mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-09-26 13:04:13 +00:00
Merge branch 'origin/ui/TRA-4204_user_managment' of github.com:up9inc/mizu into feature/ui/TRA-4192_workspace_management
# Conflicts: # ui/src/components/Modals/AddUserModal/AddUserModal.tsx # ui/src/helpers/api.js
This commit is contained in:
@@ -55,4 +55,7 @@
|
|||||||
.search-workspace
|
.search-workspace
|
||||||
width: 186px
|
width: 186px
|
||||||
|
|
||||||
|
.u-margin-left
|
||||||
|
margin-left : 20px
|
||||||
|
|
||||||
|
|
||||||
|
@@ -74,15 +74,6 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
setEditMode(isEditMode)
|
setEditMode(isEditMode)
|
||||||
if (isEditMode) {
|
|
||||||
|
|
||||||
//const userDetails = await api.getUserDetails(userData)
|
|
||||||
//const data = {...userData,...userDetails}
|
|
||||||
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
|
|
||||||
}
|
|
||||||
setUserData(userData as UserData)
|
setUserData(userData as UserData)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error("Error getting user details")
|
toast.error("Error getting user details")
|
||||||
@@ -98,6 +89,18 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
onCloseModal()
|
onCloseModal()
|
||||||
setUserData({} as UserData)
|
setUserData({} as UserData)
|
||||||
setInvite({sent:false,isSuceeded:false,link:""})
|
setInvite({sent:false,isSuceeded:false,link:""})
|
||||||
|
setEditMode(false)
|
||||||
|
setDisable(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateUser = async() =>{
|
||||||
|
try {
|
||||||
|
const res = await api.updateUser(userDataModel)
|
||||||
|
onClose()
|
||||||
|
toast.success("User has been modified")
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("Error accured modifing user")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspaceChange = (workspaces) => {
|
const workspaceChange = (workspaces) => {
|
||||||
@@ -125,8 +128,7 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isFormValid = () : boolean => {
|
const isFormValid = () : boolean => {
|
||||||
return true;
|
return (Object.values(userDataModel).length >= 3) && Object.values(userDataModel).every(val => val !== null)
|
||||||
//return (Object.values(userDataModel).length === 3) && Object.values(userDataModel).every(val => val !== null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setGenarateDisabledState = () => {
|
const setGenarateDisabledState = () => {
|
||||||
@@ -134,39 +136,59 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
setDisable(!isValid)
|
setDisable(!isValid)
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateLink = () => {
|
const mapTokenToLink = (token) => {
|
||||||
try {
|
return`${window.location.origin}/${token}`
|
||||||
if (editMode) {
|
}
|
||||||
//await api.updateUser(userDataModel)
|
|
||||||
setInvite({...invite,isSuceeded:true,sent:true,link:"asdasdasdasdasdasdasdasdads"})
|
const generateLink = async() => {
|
||||||
toast.success("User has been modified")
|
try {
|
||||||
}
|
const res = await api.genareteInviteLink(userDataModel)
|
||||||
else{
|
setInvite({...invite,isSuceeded:true,sent:true, link: mapTokenToLink(res.inviteToken)})
|
||||||
//const res = await api.genareteInviteLink(userDataModel)
|
|
||||||
setInvite({...invite,isSuceeded:true,sent:true, link:"asdasdasdasdasdasdasdasdads"})
|
|
||||||
toast.success("User has been added")
|
toast.success("User has been added")
|
||||||
}
|
onUserChange(userDataModel)
|
||||||
|
} catch (e) {
|
||||||
|
toast.error("Error accrued generating link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const inviteExistingUser = async() => {
|
||||||
|
try {
|
||||||
|
const res = await api.inviteExistingUser(userDataModel.userId)
|
||||||
|
setInvite({...invite,isSuceeded:true,sent:true, link: mapTokenToLink(res.inviteToken)})
|
||||||
|
toast.success("Invite link created")
|
||||||
onUserChange(userDataModel)
|
onUserChange(userDataModel)
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error("Error accrued generating link")
|
toast.error("Error accrued generating link")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isShowInviteLink = () => {
|
||||||
|
return ((invite.isSuceeded && invite.link));
|
||||||
|
}
|
||||||
|
|
||||||
|
const showGenerateButton = () => {
|
||||||
|
return (!invite.isSuceeded || !(invite.link && invite.sent))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCopyinviteLink = (e) => {navigator.clipboard.writeText(invite.link)}
|
const handleCopyinviteLink = (e) => {navigator.clipboard.writeText(invite.link)}
|
||||||
|
|
||||||
const modalCustomActions = <>
|
const addUsermodalCustomActions = <>
|
||||||
{(!invite.isSuceeded || !(invite.link && invite.sent)) && <Button
|
{showGenerateButton() && <Button
|
||||||
className={classes.button + " generate-link-button"} size={"small"} onClick={generateLink}
|
className={classes.button + " generate-link-button"} size={"small"}
|
||||||
|
onClick={!isEditMode ? generateLink : inviteExistingUser}
|
||||||
disabled={disable}
|
disabled={disable}
|
||||||
endIcon={isLoading && <img src={spinner} alt="spinner"/>}>
|
endIcon={isLoading && <img src={spinner} alt="spinner"/>}>
|
||||||
<span className='generate-link-button__icon'></span>
|
<span className='generate-link-button__icon'></span>
|
||||||
{"Generate Invite Link"}
|
{"Generate Invite Link"}
|
||||||
</Button>}
|
</Button>}
|
||||||
{invite.isSuceeded && invite.link && <div className="invite-link-row">
|
{
|
||||||
<FormControl variant="outlined" size={"small"} className='invite-link-field'>
|
isEditMode && <Button style={{height: '100%'}} disabled={disable} className={classes.button + " u-margin-left"} size={"small"} onClick={updateUser}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="invite-link-row">
|
||||||
|
{isShowInviteLink() && <FormControl variant="outlined" size={"small"} className='invite-link-field'>
|
||||||
<InputLabel htmlFor="outlined-adornment-password">Invite link</InputLabel>
|
<InputLabel htmlFor="outlined-adornment-password">Invite link</InputLabel>
|
||||||
<OutlinedInput
|
<OutlinedInput
|
||||||
type={'text'}
|
type={'text'}
|
||||||
@@ -178,20 +200,20 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
{<span className='generate-link-button__icon'></span>}
|
{<span className='generate-link-button__icon'></span>}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
} label="Invite link"/>
|
||||||
label="Invite link"
|
</FormControl>}
|
||||||
/>
|
{!isEditMode && isShowInviteLink() && <Button style={{height: '100%'}} className={classes.button + " u-margin-left"} size={"small"} onClick={onClose}>
|
||||||
</FormControl>
|
|
||||||
<Button style={{height: '100%'}} className={classes.button} size={"small"} onClick={onClose}>
|
|
||||||
Done
|
Done
|
||||||
</Button>
|
</Button>}
|
||||||
</div>}
|
|
||||||
</>;
|
</div>
|
||||||
|
|
||||||
|
</>;
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
|
|
||||||
<ConfirmationModal isOpen={isOpen} onClose={onClose} onConfirm={onClose}
|
<ConfirmationModal isOpen={isOpen} onClose={onClose} onConfirm={onClose}
|
||||||
title={`${editMode ? "Edit" : "Add"} User`} customActions={modalCustomActions}>
|
title={`${editMode ? "Edit" : "Add"} User`} customActions={addUsermodalCustomActions}>
|
||||||
|
|
||||||
<h3 className='comfirmation-modal__sub-section-header'>DETAILS</h3>
|
<h3 className='comfirmation-modal__sub-section-header'>DETAILS</h3>
|
||||||
<div className='comfirmation-modal__sub-section'>
|
<div className='comfirmation-modal__sub-section'>
|
||||||
|
@@ -1,14 +1,17 @@
|
|||||||
@import "../../../variables.module"
|
@import "../../../variables.module"
|
||||||
|
|
||||||
|
@mixin tab-container
|
||||||
|
max-width: 513px
|
||||||
|
margin: 0 auto
|
||||||
|
|
||||||
.settings-page
|
.settings-page
|
||||||
max-width: 513px
|
background: #F7F9FC;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
justify-content: center;
|
/* justify-content: center; */
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
|
||||||
& .tabs-nav
|
& .tabs-nav
|
||||||
padding-top: 0px;
|
padding-top: 0px;
|
||||||
@@ -16,8 +19,10 @@
|
|||||||
|
|
||||||
|
|
||||||
.header-section
|
.header-section
|
||||||
margin-bottom: 30px;
|
|
||||||
background: #F7F9FC;
|
|
||||||
|
&__container
|
||||||
|
@include tab-container
|
||||||
|
|
||||||
|
|
||||||
&__title
|
&__title
|
||||||
@@ -27,3 +32,8 @@
|
|||||||
margin-bottom: 60px;
|
margin-bottom: 60px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.tab-content
|
||||||
|
padding-top: 30px;
|
||||||
|
&__container
|
||||||
|
@include tab-container
|
||||||
|
|
@@ -13,19 +13,22 @@ const AdminSettings: React.FC<any> = ({color}) => {
|
|||||||
const [currentTab, setCurrentTab] = useState(TABS[0].tab);
|
const [currentTab, setCurrentTab] = useState(TABS[0].tab);
|
||||||
return (<>
|
return (<>
|
||||||
<div className="settings-page">
|
<div className="settings-page">
|
||||||
<div className="header-section">
|
<div className="header-section">
|
||||||
<div className="header-section__title">Settings</div>
|
<div className="header-section__container">
|
||||||
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned classes={{root:"tabs-nav"}}/>
|
<div className="header-section__title">Settings</div>
|
||||||
</div>
|
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned classes={{root:"tabs-nav"}}/>
|
||||||
<div>
|
</div>
|
||||||
|
</div>
|
||||||
{currentTab === TABS[0].tab && <React.Fragment>
|
<div className="tab-content">
|
||||||
<UserSettings/>
|
<div className="tab-content__container">
|
||||||
</React.Fragment>}
|
{currentTab === TABS[0].tab && <React.Fragment>
|
||||||
{currentTab === TABS[1].tab && <React.Fragment>
|
<UserSettings/>
|
||||||
<WorkspaceSettings/>
|
</React.Fragment>}
|
||||||
</React.Fragment>}
|
{currentTab === TABS[1].tab && <React.Fragment>
|
||||||
</div>
|
<WorkspaceSettings/>
|
||||||
|
</React.Fragment>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@@ -13,6 +13,11 @@ interface Props {
|
|||||||
|
|
||||||
const api = Api.getInstance();
|
const api = Api.getInstance();
|
||||||
|
|
||||||
|
enum InviteStatus{
|
||||||
|
active = "Active",
|
||||||
|
pending = "Pending"
|
||||||
|
}
|
||||||
|
|
||||||
export const UserSettings : React.FC<Props> = ({}) => {
|
export const UserSettings : React.FC<Props> = ({}) => {
|
||||||
|
|
||||||
const [usersRows, setUserRows] = useState([]);
|
const [usersRows, setUserRows] = useState([]);
|
||||||
@@ -20,7 +25,7 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
const cols : ColsType[] = [{field : "username",header:"User"},
|
const cols : ColsType[] = [{field : "username",header:"User"},
|
||||||
{field : "role",header:"Role"},
|
{field : "role",header:"Role"},
|
||||||
{field : "status",header:"Status",getCellClassName : (field, val) =>{
|
{field : "status",header:"Status",getCellClassName : (field, val) =>{
|
||||||
return val === "Active" ? "status--active" : "status--pending"
|
return val === InviteStatus.active ? "status--active" : "status--pending"
|
||||||
}}]
|
}}]
|
||||||
const [isOpenModal,setIsOpen] = useState(false)
|
const [isOpenModal,setIsOpen] = useState(false)
|
||||||
const [editMode, setEditMode] = useState(false);
|
const [editMode, setEditMode] = useState(false);
|
||||||
@@ -28,9 +33,13 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
|
|
||||||
const getUserList = (async () => {
|
const getUserList = (async () => {
|
||||||
try {
|
try {
|
||||||
let users = [{username:"asd",role:"Admin",status:"Active",userId : "1"},
|
// let users = [{username:"asd",role:"Admin",status:"Active",userId : "1"},
|
||||||
{username:"aaaaaaa",role:"User",status:"Active",userId : "2"}]//await api.getUsers()
|
// {username:"asdasdasdasdasdasd",role:"User",status:"Active",userId : "2"}]
|
||||||
setUserRows(users)
|
let users = await api.getUsers()
|
||||||
|
const mappedUsers = users.map((user) => {
|
||||||
|
return {...user,status: capitalizeFirstLetter(user.status), role: capitalizeFirstLetter(user.role)}
|
||||||
|
})
|
||||||
|
setUserRows(mappedUsers)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@@ -41,6 +50,10 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
getUserList();
|
getUserList();
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
|
function capitalizeFirstLetter(string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
const filterFuncFactory = (searchQuery: string) => {
|
const filterFuncFactory = (searchQuery: string) => {
|
||||||
return (row) => {
|
return (row) => {
|
||||||
return row.username.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
return row.username.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
@@ -64,7 +77,7 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
const onConfirmDelete = () => {
|
const onConfirmDelete = () => {
|
||||||
(async() => {
|
(async() => {
|
||||||
try {
|
try {
|
||||||
//await api.deleteUser(user)
|
await api.deleteUser(userData)
|
||||||
const findFunc = filterFuncFactory(userData.userId);
|
const findFunc = filterFuncFactory(userData.userId);
|
||||||
const usersLeft = usersRows.filter(e => !findFunc(e))
|
const usersLeft = usersRows.filter(e => !findFunc(e))
|
||||||
setUserRows(usersLeft)
|
setUserRows(usersLeft)
|
||||||
@@ -72,6 +85,7 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error("User want not deleted")
|
toast.error("User want not deleted")
|
||||||
}
|
}
|
||||||
|
setConfirmModalOpen(false);
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +99,7 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
getUserList()
|
getUserList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const buttonConfig = {onClick: () => {setIsOpen(true)}, text:"Add User"}
|
const buttonConfig = {onClick: () => {setIsOpen(true);setEditMode(false);}, text:"Add User"}
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<FilterableTableAction onRowEdit={onRowEdit} onRowDelete={onRowDelete} searchConfig={searchConfig}
|
<FilterableTableAction onRowEdit={onRowEdit} onRowDelete={onRowDelete} searchConfig={searchConfig}
|
||||||
|
@@ -68,7 +68,12 @@ export default class Api {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
genareteInviteLink = async(userData) =>{
|
inviteExistingUser = async(userId) =>{
|
||||||
|
const response = await this.client.post(`/user/${userId}/invite`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
genareteInviteLink = async(userData) =>{
|
||||||
const response = await this.client.post(`/user/createUserAndInvite`,userData);
|
const response = await this.client.post(`/user/createUserAndInvite`,userData);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
@@ -224,6 +229,7 @@ export default class Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
login = async (username, password) => {
|
login = async (username, password) => {
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('username', username);
|
form.append('username', username);
|
||||||
|
Reference in New Issue
Block a user