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/components/UserSettings/UserSettings.tsx
This commit is contained in:
@@ -9,6 +9,21 @@
|
|||||||
background-size: 26px
|
background-size: 26px
|
||||||
margin-right: 10px
|
margin-right: 10px
|
||||||
|
|
||||||
|
.invite-link
|
||||||
|
&-row
|
||||||
|
display: flex
|
||||||
|
justify-content: space-between
|
||||||
|
align-items: center
|
||||||
|
align-content: center
|
||||||
|
|
||||||
|
& .done-btn
|
||||||
|
box-sizing: border-box
|
||||||
|
height: 30px
|
||||||
|
width: 78px
|
||||||
|
|
||||||
|
&-field
|
||||||
|
width: 80%
|
||||||
|
max-width: 435px
|
||||||
|
|
||||||
.generate-link-button
|
.generate-link-button
|
||||||
&:disabled
|
&:disabled
|
||||||
@@ -20,11 +35,7 @@
|
|||||||
&__icon
|
&__icon
|
||||||
@include generate-icon
|
@include generate-icon
|
||||||
background-image: url('../../assets/copy-enabled.svg')
|
background-image: url('../../assets/copy-enabled.svg')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.user
|
.user
|
||||||
&__details
|
&__details
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -35,6 +46,10 @@
|
|||||||
|
|
||||||
& .user__email
|
& .user__email
|
||||||
width : 40%
|
width : 40%
|
||||||
|
height: 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
& .user__role
|
& .user__role
|
||||||
width : 40%
|
width : 40%
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Button, FormControl, InputLabel, MenuItem, Select } from '@material-ui/core';
|
import { Button, FormControl, IconButton, InputAdornment, InputLabel, MenuItem, OutlinedInput, Select } from '@material-ui/core';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import Api from '../../../helpers/api';
|
import Api from '../../../helpers/api';
|
||||||
import { useCommonStyles } from '../../../helpers/commonStyle';
|
import { useCommonStyles } from '../../../helpers/commonStyle';
|
||||||
@@ -6,10 +6,11 @@ import ConfirmationModal from '../../UI/Modals/ConfirmationModal';
|
|||||||
import SelectList from '../../UI/SelectList';
|
import SelectList from '../../UI/SelectList';
|
||||||
import './AddUserModal.sass';
|
import './AddUserModal.sass';
|
||||||
import spinner from "../../assets/spinner.svg";
|
import spinner from "../../assets/spinner.svg";
|
||||||
|
import { useForm,Controller } from "react-hook-form";
|
||||||
|
|
||||||
export type UserData = {
|
export type UserData = {
|
||||||
role:string;
|
role:string;
|
||||||
email : string;
|
username : string;
|
||||||
workspace : string;
|
workspace : string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,16 +18,21 @@ interface AddUserModalProps {
|
|||||||
isOpen : boolean,
|
isOpen : boolean,
|
||||||
onCloseModal : () => void
|
onCloseModal : () => void
|
||||||
userData : UserData;
|
userData : UserData;
|
||||||
|
setShowAlert : ({open:boolean,sevirity: Color}) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = Api.getInstance();
|
const api = Api.getInstance();
|
||||||
|
|
||||||
export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userData = {}}) => {
|
export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userData = {}, setShowAlert}) => {
|
||||||
|
|
||||||
//const [editUserData, setEditUserData] = useState(userData)
|
//const [editUserData, setEditUserData] = useState(userData)
|
||||||
const [searchValue, setSearchValue] = useState("");
|
const [searchValue, setSearchValue] = useState("");
|
||||||
const [workspaces, setWorkspaces] = useState({})
|
const [workspaces, setWorkspaces] = useState([])
|
||||||
const roles = [{key:"1",value:"Admin"}]
|
//const { control, handleSubmit,register } = useForm<UserData>();
|
||||||
|
const [disable, setDisable] = useState(true);
|
||||||
|
|
||||||
|
const [invite, setInvite] = useState({sent:false,isSuceeded:false,link : null});
|
||||||
|
const roles = [{key:"1",value:"Admin"},{key:"2",value:"User"}]
|
||||||
const classes = useCommonStyles()
|
const classes = useCommonStyles()
|
||||||
|
|
||||||
const [userDataModel, setUserData] = useState(userData as UserData)
|
const [userDataModel, setUserData] = useState(userData as UserData)
|
||||||
@@ -39,7 +45,16 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const workspacesList = [{"default":true}] //await api.getWorkspaces()
|
const workspacesList = [
|
||||||
|
{
|
||||||
|
"id": "f54b18ec-aa15-4b2c-a4d5-8eda17e44c93",
|
||||||
|
"name": "sock-shop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c7ad9158-d840-46c0-b5ce-2487c013723f",
|
||||||
|
"name": "test"
|
||||||
|
}
|
||||||
|
]//{"default":true} //await api.getWorkspaces()
|
||||||
setWorkspaces(workspacesList)
|
setWorkspaces(workspacesList)
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -56,57 +71,109 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
// setIsOpen(false)
|
// setIsOpen(false)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const onConfirm = () => {}
|
const onConfirm = () => {
|
||||||
|
setUserData({} as UserData)
|
||||||
|
onCloseModal()
|
||||||
|
}
|
||||||
|
|
||||||
const workspaceChange = (newVal) => {
|
const workspaceChange = (newVal) => {
|
||||||
setWorkspaces(newVal);
|
//setWorkspaces(newVal);
|
||||||
const data = {...userDataModel, workspace : newVal}
|
const data = {...userDataModel, workspace : newVal}
|
||||||
setUserData(data)
|
setUserData(data)
|
||||||
|
setGenarateDisabledState()
|
||||||
}
|
}
|
||||||
|
|
||||||
const userRoleChange = (e) => {
|
const userRoleChange = (e) => {
|
||||||
const data = {...userDataModel, role : e.currentTarget.value}
|
const data = {...userDataModel, role : e.target.value}
|
||||||
setUserData(data)
|
setUserData(data)
|
||||||
|
setGenarateDisabledState()
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFormValid(): boolean {
|
const userNameChange = (e) => {
|
||||||
return true;
|
const data = {...userDataModel, username : e.currentTarget.value}
|
||||||
|
setUserData(data)
|
||||||
|
setGenarateDisabledState()
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateLink = () => {
|
const handleChange = (prop) => (event) => {
|
||||||
|
//setValues({ ...values, [prop]: event.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFormValid = () : boolean => {
|
||||||
|
return (Object.values(userDataModel).length === 3) && Object.values(userDataModel).every(val => val !== null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setGenarateDisabledState = () => {
|
||||||
|
const isValid = isFormValid()
|
||||||
|
setDisable(!isValid)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateLink = () => {
|
||||||
try {
|
try {
|
||||||
api.genareteInviteLink(userDataModel)
|
//const res = await api.genareteInviteLink(userDataModel)
|
||||||
console.log(workspaces);
|
//setInvite({...invite,isSuceeded:true,sent:true,link:res})
|
||||||
|
|
||||||
|
setInvite({...invite,isSuceeded:true,sent:true,link:"asdasdasdasdasdasdasdasdads"})
|
||||||
|
setShowAlert({open:true,sevirity:"error"})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
setShowAlert({open:true,sevirity:"error"})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const modalCustomActions = <>
|
const handleCopyinviteLink = (e) => {navigator.clipboard.writeText(invite.link)}
|
||||||
|
|
||||||
|
const modalCustomActions = <>
|
||||||
|
{(!invite.isSuceeded || !(invite.link && invite.sent)) && <Button
|
||||||
|
className={classes.button + " generate-link-button"} size={"small"} onClick={generateLink}
|
||||||
|
disabled={disable}
|
||||||
|
endIcon={isLoading && <img src={spinner} alt="spinner"/>}>
|
||||||
|
<span className='generate-link-button__icon'></span>
|
||||||
|
{"Generate Invite Link"}
|
||||||
|
</Button>}
|
||||||
|
{invite.isSuceeded && invite.link && <div className="invite-link-row">
|
||||||
|
<FormControl variant="outlined" size={"small"} className='invite-link-field'>
|
||||||
|
<InputLabel htmlFor="outlined-adornment-password">Invite link</InputLabel>
|
||||||
|
<OutlinedInput
|
||||||
|
type={'text'}
|
||||||
|
value={invite.link}
|
||||||
|
onChange={handleChange('password')}
|
||||||
|
endAdornment={
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton aria-label="cpoy invite link" onClick={handleCopyinviteLink} edge="end">
|
||||||
|
{<span className='generate-link-button__icon'></span>}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
}
|
||||||
|
label="Invite link"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<Button style={{height: '100%'}} className={classes.button} size={"small"} onClick={onConfirm}>
|
||||||
|
Done
|
||||||
|
</Button>
|
||||||
|
</div>}
|
||||||
</>;
|
</>;
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
|
|
||||||
<ConfirmationModal isOpen={isOpen} onClose={onCloseModal} onConfirm={onConfirm} title='Add User'>
|
<ConfirmationModal isOpen={isOpen} onClose={onCloseModal} onConfirm={onConfirm} title='Add User' customActions={modalCustomActions}>
|
||||||
<Button
|
|
||||||
className={classes.button + " generate-link-button"} size={"small"} onClick={generateLink}
|
|
||||||
//disabled={isFormValid()}
|
|
||||||
endIcon={isLoading && <img src={spinner} alt="spinner"/>}>
|
|
||||||
<span className='generate-link-button__icon'></span>
|
|
||||||
|
|
||||||
{"Generate Invite Link"}
|
|
||||||
</Button>
|
|
||||||
<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'>
|
||||||
<div className='user__details'>
|
<div className='user__details'>
|
||||||
<input type="text" value={userDataModel?.email ?? ""} className={classes.textField + " user__email"} placeholder={"User Email"}
|
<input type="text" value={userDataModel?.username ?? ""} className={classes.textField + " user__email"}
|
||||||
onChange={(e) => {}}></input>
|
placeholder={"User Email"} onChange={userNameChange}>
|
||||||
<FormControl size='small' variant="outlined" className='user__role'>
|
</input>
|
||||||
|
|
||||||
|
{/* <Controller name="role" control={control} rules={{ required: true }}
|
||||||
|
render={({ field }) => }
|
||||||
|
/> */}
|
||||||
|
|
||||||
|
<FormControl size='small' variant="outlined" className='user__role'>
|
||||||
<InputLabel>User Role</InputLabel>
|
<InputLabel>User Role</InputLabel>
|
||||||
<Select value={userDataModel.role} onChange={userRoleChange} >
|
<Select value={userDataModel.role ?? ""} onChange={userRoleChange} >
|
||||||
<MenuItem value="">
|
<MenuItem value="0">
|
||||||
<em>None</em>
|
<em>None</em>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{roles.map((role) => (
|
{roles.map((role) => (
|
||||||
@@ -118,16 +185,17 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 className='comfirmation-modal__sub-section-header'>WORKSPACE ACCESS </h3>
|
<h3 className='comfirmation-modal__sub-section-header'>WORKSPACE ACCESS </h3>
|
||||||
<div className="namespacesSettingsContainer">
|
<div className="namespacesSettingsContainer">
|
||||||
<div style={{margin: "10px 0"}}>
|
<div style={{margin: "10px 0"}}>
|
||||||
<input className={classes.textField + " searchNamespace"} placeholder="Search" value={searchValue}
|
<input className={classes.textField + " searchNamespace"} placeholder="Search" value={searchValue}
|
||||||
onChange={(event) => setSearchValue(event.target.value)}/>
|
onChange={(event) => setSearchValue(event.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<SelectList valuesListInput={workspaces} tableName={''} multiSelect={false} searchValue={searchValue} setValues={workspaceChange} tabelClassName={''} ></SelectList>
|
<SelectList valuesListInput={workspaces} tableName={''} multiSelect={false} searchValue={searchValue}
|
||||||
|
setValues= {workspaceChange} tabelClassName={''} >
|
||||||
|
</SelectList>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
</>);
|
</>);
|
||||||
};
|
};
|
||||||
|
|
@@ -62,7 +62,7 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = observer(({title, is
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="confirmationActions">
|
<div className="confirmationActions">
|
||||||
{customActions}
|
{customActions ?? defualtActions}
|
||||||
</div>
|
</div>
|
||||||
</CustomModal>
|
</CustomModal>
|
||||||
)
|
)
|
||||||
|
@@ -18,4 +18,11 @@
|
|||||||
@include status-base(rgba(111, 207, 151, 0.5), #247E4B, 1px solid #219653)
|
@include status-base(rgba(111, 207, 151, 0.5), #247E4B, 1px solid #219653)
|
||||||
|
|
||||||
&--pending
|
&--pending
|
||||||
@include status-base(rgba(242, 201, 76, 0.5), #8C7325, 1px solid #F2994A)
|
@include status-base(rgba(242, 201, 76, 0.5), #8C7325, 1px solid #F2994A)
|
||||||
|
|
||||||
|
.alert--right.MuiSnackbar-root
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
left: auto;
|
||||||
|
right: 1vw;
|
||||||
|
transform: unset;
|
@@ -3,6 +3,13 @@ import {ColsType, FilterableTableAction} from "../UI/FilterableTableAction"
|
|||||||
// import Api from "../../helpers/api"
|
// import Api from "../../helpers/api"
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { UserData,AddUserModal } from "../Modals/AddUserModal/AddUserModal";
|
import { UserData,AddUserModal } from "../Modals/AddUserModal/AddUserModal";
|
||||||
|
import {Snackbar} from "@material-ui/core";
|
||||||
|
import MuiAlert from "@material-ui/lab/Alert";
|
||||||
|
import { Select } from "../UI/Select";
|
||||||
|
import { MenuItem } from "@material-ui/core";
|
||||||
|
import { settings } from "cluster";
|
||||||
|
import { SettingsModal } from "../SettingsModal/SettingModal";
|
||||||
|
import OasModal from "../Modals/OasModal/OasModal";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
||||||
@@ -20,14 +27,14 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
return val === "Active" ? "status--active" : "status--pending"
|
return val === "Active" ? "status--active" : "status--pending"
|
||||||
}}]
|
}}]
|
||||||
const [isOpenModal,setIsOpen] = useState(false)
|
const [isOpenModal,setIsOpen] = useState(false)
|
||||||
|
const [alert,setAlert] = useState({open:false,sevirity:"success"})
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const users = [{userName:"asd",role:"Admin",status:"Active"}]//await api.getUsers()
|
const users = [{userName:"asd",role:"Admin",status:"Active"}]//await api.getUsers()
|
||||||
setUserRows(users)
|
setUserRows(users)
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@@ -49,7 +56,8 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onRowEdit = (row) => {
|
const onRowEdit = (row) => {
|
||||||
// open Edit user Modal
|
SetUsetData(row)
|
||||||
|
setIsOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -60,7 +68,14 @@ export const UserSettings : React.FC<Props> = ({}) => {
|
|||||||
<FilterableTableAction onRowEdit={onRowEdit} onRowDelete={onRowDelete} searchConfig={searchConfig}
|
<FilterableTableAction onRowEdit={onRowEdit} onRowDelete={onRowDelete} searchConfig={searchConfig}
|
||||||
buttonConfig={buttonConfig} rows={usersRows} cols={cols}>
|
buttonConfig={buttonConfig} rows={usersRows} cols={cols}>
|
||||||
</FilterableTableAction>
|
</FilterableTableAction>
|
||||||
<AddUserModal isOpen={isOpenModal} onCloseModal={() => { setIsOpen(false); } } userData={userData}></AddUserModal>
|
<AddUserModal isOpen={isOpenModal} onCloseModal={() => { setIsOpen(false); } } userData={userData} setShowAlert={setAlert}>
|
||||||
|
</AddUserModal>
|
||||||
|
<Snackbar open={alert.open} classes={{root: "alert--right"}}>
|
||||||
|
<MuiAlert classes={{filledWarning: 'customWarningStyle'}} elevation={6} variant="filled"
|
||||||
|
onClose={() => setAlert({...alert,open:false})} severity={"success"}>
|
||||||
|
User has been added
|
||||||
|
</MuiAlert>
|
||||||
|
</Snackbar>
|
||||||
{/* <SettingsModal isOpen={false} onClose={function (): void {
|
{/* <SettingsModal isOpen={false} onClose={function (): void {
|
||||||
throw new Error("Function not implemented.");
|
throw new Error("Function not implemented.");
|
||||||
} } isFirstLogin={false}></SettingsModal> */}
|
} } isFirstLogin={false}></SettingsModal> */}
|
||||||
|
@@ -7,7 +7,7 @@ export const useCommonStyles = makeStyles(() => ({
|
|||||||
color: "white",
|
color: "white",
|
||||||
fontWeight: "600 !important",
|
fontWeight: "600 !important",
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
padding: "8px 12px",
|
padding: "9px 12px",
|
||||||
borderRadius: "6px ! important",
|
borderRadius: "6px ! important",
|
||||||
|
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
@@ -34,7 +34,9 @@ export const useCommonStyles = makeStyles(() => ({
|
|||||||
padding: "8px 10px",
|
padding: "8px 10px",
|
||||||
border: "1px #9D9D9D solid",
|
border: "1px #9D9D9D solid",
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
color: "#494677"
|
color: "#494677",
|
||||||
|
height: "30px",
|
||||||
|
boxSizing: "border-box"
|
||||||
},
|
},
|
||||||
modal :{
|
modal :{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
Reference in New Issue
Block a user