Merge branch 'origin/ui/TRA-4204_user_managment' of github.com:up9inc/mizu into feature/ui/TRA-4192_workspace_management

# Conflicts:
#	ui/src/components/UI/SelectList.tsx
This commit is contained in:
Amit Fainholts
2022-01-30 11:40:34 +02:00
7 changed files with 133 additions and 50 deletions

View File

@@ -45,11 +45,14 @@
& .user__email & .user__email
width : 40% width : 300px
height: 30px; height: 30px;
box-sizing: border-box; box-sizing: border-box;
& .user__role & .user__role
width : 40% width : 186px
.search-workspace
width: 186px

View File

@@ -1,4 +1,5 @@
import { Button, FormControl, IconButton, InputAdornment, InputLabel, MenuItem, OutlinedInput, 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';
@@ -18,21 +19,23 @@ export type UserData = {
interface AddUserModalProps { interface AddUserModalProps {
isOpen : boolean, isOpen : boolean,
onCloseModal : () => void onCloseModal : () => void,
userData : UserData; userData : UserData,
setShowAlert : ({open:boolean,sevirity: Color}) => void; isEditMode : boolean,
onUserChange: (UserData) => void,
} }
const api = Api.getInstance(); const api = Api.getInstance();
export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userData = {}, setShowAlert}) => { export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userData, isEditMode,onUserChange}) => {
//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 { control, handleSubmit,register } = useForm<UserData>(); //const { control, handleSubmit,register } = useForm<UserData>();
const [disable, setDisable] = useState(true); const [disable, setDisable] = useState(true);
const [editMode, setEditMode] = useState(isEditMode);
const [invite, setInvite] = useState({sent:false,isSuceeded:false,link : null}); const [invite, setInvite] = useState({sent:false,isSuceeded:false,link : null});
const roles = [{key:"1",value:"Admin"},{key:"2",value:"User"}] const roles = [{key:"1",value:"Admin"},{key:"2",value:"User"}]
const classes = useCommonStyles() const classes = useCommonStyles()
@@ -69,15 +72,22 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
useEffect(()=> { useEffect(()=> {
(async () => { (async () => {
try { try {
//if edit setEditMode(isEditMode)
// const userDetails = await api.getUserDetails(userData) if (isEditMode) {
// setUserData(userDetails)
setUserData(userData as UserData) //const userDetails = await api.getUserDetails(userData)
//const data = {...userData,...userDetails}
}
else{
}
setUserData(userData as UserData)
} catch (e) { } catch (e) {
toast.error("Error getting user details") toast.error("Error getting user details")
} }
})(); })();
},[userData]) },[isEditMode, userData])
// const onClose = () => { // const onClose = () => {
// setIsOpen(false) // setIsOpen(false)
@@ -86,12 +96,13 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
const onClose = () => { const onClose = () => {
onCloseModal() onCloseModal()
setUserData({} as UserData) setUserData({} as UserData)
setInvite({sent:false,isSuceeded:false,link:""})
} }
const workspaceChange = (newVal) => { const workspaceChange = (workspaces) => {
//setWorkspaces(newVal); //setWorkspaces(newVal);
const data = {...userDataModel, workspace : newVal} const selectedWorksapce = workspaces.find(x=> x.isChecked)
const data = {...userDataModel, workspace : selectedWorksapce.key}
setUserData(data) setUserData(data)
setGenarateDisabledState() setGenarateDisabledState()
} }
@@ -113,7 +124,8 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
}; };
const isFormValid = () : boolean => { const isFormValid = () : boolean => {
return (Object.values(userDataModel).length === 3) && Object.values(userDataModel).every(val => val !== null) return true;
//return (Object.values(userDataModel).length === 3) && Object.values(userDataModel).every(val => val !== null)
} }
const setGenarateDisabledState = () => { const setGenarateDisabledState = () => {
@@ -123,14 +135,19 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
const generateLink = () => { const generateLink = () => {
try { try {
//const res = await api.genareteInviteLink(userDataModel) if (editMode) {
//setInvite({...invite,isSuceeded:true,sent:true,link:res}) //await api.updateUser(userDataModel)
//toast.success("User has been added") setInvite({...invite,isSuceeded:true,sent:true,link:"asdasdasdasdasdasdasdasdads"})
toast.success("User has been modified")
}
else{
//const res = await api.genareteInviteLink(userDataModel)
setInvite({...invite,isSuceeded:true,sent:true, link:"asdasdasdasdasdasdasdasdads"})
toast.success("User has been added")
}
onUserChange(userDataModel)
//if edit
api.updateUser(userDataModel)
setInvite({...invite,isSuceeded:true,sent:true,link:"asdasdasdasdasdasdasdasdads"})
toast.success("User has been modified")
} catch (e) { } catch (e) {
toast.error("Error accrued generating link") toast.error("Error accrued generating link")
} }
@@ -172,13 +189,14 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
return (<> return (<>
<ConfirmationModal isOpen={isOpen} onClose={onClose} onConfirm={onClose} title='Add User' customActions={modalCustomActions}> <ConfirmationModal isOpen={isOpen} onClose={onClose} onConfirm={onClose}
title={`${editMode ? "Edit" : "Add"} User`} customActions={modalCustomActions}>
<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?.username ?? ""} className={classes.textField + " user__email"} <input type="text" value={userDataModel?.username ?? ""} className={classes.textField + " user__email"}
placeholder={"User Email"} onChange={userNameChange}> placeholder={"User Email"} onChange={userNameChange} disabled={editMode}>
</input> </input>
{/* <Controller name="role" control={control} rules={{ required: true }} {/* <Controller name="role" control={control} rules={{ required: true }}
@@ -187,7 +205,7 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
<FormControl size='small' variant="outlined" className='user__role'> <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} classes={{ root : 'my-class-name' }} >
<MenuItem value="0"> <MenuItem value="0">
<em>None</em> <em>None</em>
</MenuItem> </MenuItem>
@@ -203,7 +221,7 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
<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 + " search-workspace"} 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} <SelectList valuesListInput={workspaces} tableName={''} multiSelect={false} searchValue={searchValue}

View File

@@ -0,0 +1,29 @@
@import "../../../variables.module"
.settings-page
max-width: 513px
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
margin: 0 auto;
& .tabs-nav
padding-top: 0px;
.header-section
margin-bottom: 30px;
background: #F7F9FC;
&__title
font-size: 28px
color: $blue-gray
font-weight: 600
margin-bottom: 60px;
margin-top: 20px;

View File

@@ -3,6 +3,7 @@ import { useState } from "react";
import Tabs from "../../UI/Tabs" import Tabs from "../../UI/Tabs"
import { UserSettings } from "../../UserSettings/UserSettings"; import { UserSettings } from "../../UserSettings/UserSettings";
import { WorkspaceSettings } from "../../WorkspaceSettings/WorkspaceSettings"; import { WorkspaceSettings } from "../../WorkspaceSettings/WorkspaceSettings";
import "./SettingsPage.sass"
const AdminSettings: React.FC<any> = ({color}) => { const AdminSettings: React.FC<any> = ({color}) => {
var TABS = [ var TABS = [
@@ -10,9 +11,14 @@ const AdminSettings: React.FC<any> = ({color}) => {
]; ];
const [currentTab, setCurrentTab] = useState(TABS[0].tab); const [currentTab, setCurrentTab] = useState(TABS[0].tab);
return ( return (<>
<div style={{padding:" 0 24px"}}> <div className="settings-page">
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned/> <div className="header-section">
<div className="header-section__title">Settings</div>
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned classes={{root:"tabs-nav"}}/>
</div>
<div>
{currentTab === TABS[0].tab && <React.Fragment> {currentTab === TABS[0].tab && <React.Fragment>
<UserSettings/> <UserSettings/>
</React.Fragment>} </React.Fragment>}
@@ -20,6 +26,8 @@ const AdminSettings: React.FC<any> = ({color}) => {
<WorkspaceSettings/> <WorkspaceSettings/>
</React.Fragment>} </React.Fragment>}
</div> </div>
</div>
</>
) )
} }

View File

@@ -30,7 +30,7 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = observer(({title, is
confirmButtonColor, titleColor, img, isLoading,children, confirmButtonColor, titleColor, img, isLoading,children,
className, customActions}) => { className, customActions}) => {
const classes = useCommonStyles(); const classes = useCommonStyles();
const confirmStyle = {width: 100, marginLeft: 20} const confirmStyle = {minWidth: 100, marginLeft: 20}
const defualtActions = <><Button disabled={isLoading} style={{width: 100}} className={classes.outlinedButton} size={"small"} const defualtActions = <><Button disabled={isLoading} style={{width: 100}} className={classes.outlinedButton} size={"small"}
variant='outlined' onClick={onClose}>{closeButtonText ?? "CANCEL"} variant='outlined' onClick={onClose}>{closeButtonText ?? "CANCEL"}

View File

@@ -22,6 +22,10 @@ export type ValuesListInput = {
const SelectList: React.FC<Props> = ({valuesListInput ,tableName,checkedValues=[],multiSelect=true,searchValue="",setValues,tabelClassName}) => { const SelectList: React.FC<Props> = ({valuesListInput ,tableName,checkedValues=[],multiSelect=true,searchValue="",setValues,tabelClassName}) => {
const [valuesList, setValuesList] = useState(valuesListInput as ValuesListInput); const [valuesList, setValuesList] = useState(valuesListInput as ValuesListInput);
const filteredValues = useMemo(() => {
return valuesList.filter((listValue) => listValue?.value?.includes(searchValue));
},[valuesList, searchValue])
useEffect(() => { useEffect(() => {
const list = valuesList.map(obj => { const list = valuesList.map(obj => {
const isValueChecked = checkedValues.some(checkedValueKey => obj.key === checkedValueKey) const isValueChecked = checkedValues.some(checkedValueKey => obj.key === checkedValueKey)
@@ -70,9 +74,7 @@ const SelectList: React.FC<Props> = ({valuesListInput ,tableName,checkedValues=[
<th>{tableName}</th> <th>{tableName}</th>
</tr> </tr>
const filteredValues = useMemo(() => {
return valuesList.filter((listValue) => listValue?.value?.includes(searchValue));
},[valuesList, searchValue])
return <div className={tabelClassName + " select-list-table"}> return <div className={tabelClassName + " select-list-table"}>
<table cellPadding={5} style={{borderCollapse: "collapse"}}> <table cellPadding={5} style={{borderCollapse: "collapse"}}>

View File

@@ -14,6 +14,7 @@ import { SettingsModal } from "../SettingsModal/SettingModal";
import OasModal from "../Modals/OasModal/OasModal"; import OasModal from "../Modals/OasModal/OasModal";
import { apiDefineProperty } from "mobx/dist/internal"; import { apiDefineProperty } from "mobx/dist/internal";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import ConfirmationModal from "../UI/Modals/ConfirmationModal";
interface Props { interface Props {
@@ -31,19 +32,22 @@ 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"}) const [editMode, setEditMode] = useState(false);
const [confirmModalOpen,setConfirmModalOpen] = useState(false)
const getUserList = (async () => {
try {
let users = [{username:"asd",role:"Admin",status:"Active",userId : "1"},
{username:"aaaaaaa",role:"User",status:"Active",userId : "2"}]//await api.getUsers()
setUserRows(users)
} catch (e) {
console.error(e);
}
})
useEffect(() => { useEffect(() => {
(async () => { getUserList();
try {
const users = [{username:"asd",role:"Admin",status:"Active",userId : "1"},
{username:"aaaaaaa",role:"User",status:"Active",userId : "2"}]//await api.getUsers()
setUserRows(users)
} catch (e) {
console.error(e);
}
})();
},[]) },[])
const filterFuncFactory = (searchQuery: string) => { const filterFuncFactory = (searchQuery: string) => {
@@ -55,12 +59,22 @@ export const UserSettings : React.FC<Props> = ({}) => {
const searchConfig = { searchPlaceholder: "Search User",filterRows: filterFuncFactory} const searchConfig = { searchPlaceholder: "Search User",filterRows: filterFuncFactory}
const findUser = (userId) => {
const findFunc = filterFuncFactory(userId);
return usersRows.find(findFunc);
}
const onRowDelete = (user) => { const onRowDelete = (user) => {
const findFunc = filterFuncFactory(user.userId); setConfirmModalOpen(true);
const userToDelete = usersRows.find(findFunc); const userForDel = findUser(user.userId);
userUserData(userForDel)
}
const onConfirmDelete = () => {
(async() => { (async() => {
try { try {
//await api.deleteUser(user) //await api.deleteUser(user)
const findFunc = filterFuncFactory(userData.userId);
const usersLeft = usersRows.filter(e => !findFunc(e)) const usersLeft = usersRows.filter(e => !findFunc(e))
setUserRows(usersLeft) setUserRows(usersLeft)
toast.success("User Deleted succesesfully") toast.success("User Deleted succesesfully")
@@ -68,15 +82,17 @@ export const UserSettings : React.FC<Props> = ({}) => {
toast.error("User want not deleted") toast.error("User want not deleted")
} }
})() })()
} }
const onRowEdit = (row) => { const onRowEdit = (row) => {
userUserData(row) userUserData(row)
setEditMode(true)
setIsOpen(true) setIsOpen(true)
} }
const onUserChange = (user) =>{
getUserList()
}
const buttonConfig = {onClick: () => {setIsOpen(true)}, text:"Add User"} const buttonConfig = {onClick: () => {setIsOpen(true)}, text:"Add User"}
@@ -84,8 +100,15 @@ 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);userUserData({} as UserData) } } userData={userData} setShowAlert={setAlert}> <AddUserModal isOpen={isOpenModal} onCloseModal={() => {
setIsOpen(false);userUserData({} as UserData) } }
userData={userData} isEditMode={editMode} onUserChange={onUserChange}>
</AddUserModal> </AddUserModal>
<ConfirmationModal isOpen={confirmModalOpen} onClose={() => setConfirmModalOpen(false)}
onConfirm={onConfirmDelete} confirmButtonText="Delete user" title="Delete User"
confirmButtonColor="#DB2156">
<p>Are you sure you want to delete this user?</p>
</ConfirmationModal>
{/* <Snackbar open={alert.open} classes={{root: "alert--right"}}> {/* <Snackbar open={alert.open} classes={{root: "alert--right"}}>
<MuiAlert classes={{filledWarning: 'customWarningStyle'}} elevation={6} variant="filled" <MuiAlert classes={{filledWarning: 'customWarningStyle'}} elevation={6} variant="filled"
onClose={() => setAlert({...alert,open:false})} severity={"success"}> onClose={() => setAlert({...alert,open:false})} severity={"success"}>