|
@@ -1,33 +1,48 @@
|
|
import { useContext, useEffect, useState } from 'react';
|
|
import { useContext, useEffect, useState } from 'react';
|
|
-import { Theme, Chip } from '@mui/material';
|
|
|
|
|
|
+import { Theme } from '@mui/material';
|
|
|
|
+import { List, ListItemButton, ListItemText, Box } from '@mui/material';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { UserService } from '@/http';
|
|
import { UserService } from '@/http';
|
|
import { rootContext, dataContext } from '@/context';
|
|
import { rootContext, dataContext } from '@/context';
|
|
-import { useNavigationHook, usePaginationHook } from '@/hooks';
|
|
|
|
-import AttuGrid from '@/components/grid/Grid';
|
|
|
|
|
|
+import { useNavigationHook } from '@/hooks';
|
|
import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
|
|
import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
|
|
import UpdateRoleDialog from './dialogs/UpdateRoleDialog';
|
|
import UpdateRoleDialog from './dialogs/UpdateRoleDialog';
|
|
import { ALL_ROUTER_TYPES } from '@/router/consts';
|
|
import { ALL_ROUTER_TYPES } from '@/router/consts';
|
|
|
|
+import CustomToolBar from '@/components/grid/ToolBar';
|
|
import { makeStyles } from '@mui/styles';
|
|
import { makeStyles } from '@mui/styles';
|
|
-import type {
|
|
|
|
- ColDefinitionsType,
|
|
|
|
- ToolBarConfig,
|
|
|
|
-} from '@/components/grid/Types';
|
|
|
|
|
|
+import type { ToolBarConfig } from '@/components/grid/Types';
|
|
import Wrapper from '@/components/layout/Wrapper';
|
|
import Wrapper from '@/components/layout/Wrapper';
|
|
-import type { DeleteRoleParams } from './Types';
|
|
|
|
-import { getLabelDisplayedRows } from '@/pages/search/Utils';
|
|
|
|
-import type {
|
|
|
|
- RolesWithPrivileges,
|
|
|
|
- RBACOptions,
|
|
|
|
- DBCollectionsPrivileges,
|
|
|
|
-} from '@server/types';
|
|
|
|
|
|
+import type { DeleteRoleParams, CreateRoleParams } from './Types';
|
|
|
|
+import type { RolesWithPrivileges, RBACOptions } from '@server/types';
|
|
|
|
+import D3PrivilegeTree from './D3PrivilegeTree';
|
|
|
|
|
|
const useStyles = makeStyles((theme: Theme) => ({
|
|
const useStyles = makeStyles((theme: Theme) => ({
|
|
wrapper: {
|
|
wrapper: {
|
|
- height: `calc(100vh - 160px)`,
|
|
|
|
|
|
+ display: 'flex',
|
|
|
|
+ flexDirection: 'column',
|
|
|
|
+ overflow: 'auto',
|
|
|
|
+ },
|
|
|
|
+ list: {
|
|
|
|
+ border: `1px solid ${theme.palette.divider}`,
|
|
|
|
+ borderRadius: '8px',
|
|
|
|
+ backgroundColor: theme.palette.background.light,
|
|
|
|
+ width: '16%',
|
|
|
|
+ height: 'calc(100vh - 200px)',
|
|
|
|
+ overflow: 'auto',
|
|
|
|
+ color: theme.palette.text.primary,
|
|
|
|
+ boxShadow: theme.shadows[1],
|
|
|
|
+ minWidth: '200px',
|
|
|
|
+ },
|
|
|
|
+ tree: {
|
|
|
|
+ overflow: 'auto',
|
|
},
|
|
},
|
|
chip: {
|
|
chip: {
|
|
- marginRight: theme.spacing(0.5),
|
|
|
|
|
|
+ marginBottom: theme.spacing(0.5),
|
|
|
|
+ },
|
|
|
|
+ groupChip: {
|
|
|
|
+ marginBottom: theme.spacing(0.5),
|
|
|
|
+ backgroundColor: theme.palette.primary.dark,
|
|
|
|
+ color: theme.palette.primary.light,
|
|
},
|
|
},
|
|
}));
|
|
}));
|
|
|
|
|
|
@@ -63,10 +78,12 @@ const Roles = () => {
|
|
UserService.getRBAC(),
|
|
UserService.getRBAC(),
|
|
]);
|
|
]);
|
|
|
|
|
|
- setSelectedRole([]);
|
|
|
|
|
|
+ setSelectedRole([roles[0]]);
|
|
setRbacOptions(rbacs);
|
|
setRbacOptions(rbacs);
|
|
|
|
|
|
setRoles(roles as any);
|
|
setRoles(roles as any);
|
|
|
|
+
|
|
|
|
+ return roles;
|
|
} catch (error) {
|
|
} catch (error) {
|
|
setHasPermission(false);
|
|
setHasPermission(false);
|
|
} finally {
|
|
} finally {
|
|
@@ -74,14 +91,23 @@ const Roles = () => {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- const onUpdate = async (data: { isEditing: boolean }) => {
|
|
|
|
- fetchRoles();
|
|
|
|
|
|
+ const onUpdate = async (data: {
|
|
|
|
+ isEditing: boolean;
|
|
|
|
+ data: CreateRoleParams;
|
|
|
|
+ }) => {
|
|
|
|
+ const newRoles = await fetchRoles();
|
|
openSnackBar(
|
|
openSnackBar(
|
|
successTrans(data.isEditing ? 'update' : 'create', {
|
|
successTrans(data.isEditing ? 'update' : 'create', {
|
|
name: userTrans('role'),
|
|
name: userTrans('role'),
|
|
})
|
|
})
|
|
);
|
|
);
|
|
handleCloseDialog();
|
|
handleCloseDialog();
|
|
|
|
+
|
|
|
|
+ const roleName = data.data.roleName;
|
|
|
|
+ const role = newRoles!.find(role => role.roleName === roleName);
|
|
|
|
+ if (role) {
|
|
|
|
+ setSelectedRole([role]);
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
const handleDelete = async (force?: boolean) => {
|
|
const handleDelete = async (force?: boolean) => {
|
|
@@ -90,12 +116,18 @@ const Roles = () => {
|
|
roleName: role.roleName,
|
|
roleName: role.roleName,
|
|
force,
|
|
force,
|
|
};
|
|
};
|
|
- await UserService.deleteRole(param);
|
|
|
|
|
|
+ const d: any = await UserService.deleteRole(param);
|
|
|
|
+
|
|
|
|
+ if (d.error_code !== 'Success') {
|
|
|
|
+ openSnackBar(d.data.reason, 'error');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
openSnackBar(successTrans('delete', { name: userTrans('role') }));
|
|
openSnackBar(successTrans('delete', { name: userTrans('role') }));
|
|
- fetchRoles();
|
|
|
|
|
|
+ await fetchRoles();
|
|
handleCloseDialog();
|
|
handleCloseDialog();
|
|
|
|
+ setSelectedRole(roles[0] ? [roles[0]] : []);
|
|
};
|
|
};
|
|
|
|
|
|
const toolbarConfigs: ToolBarConfig[] = [
|
|
const toolbarConfigs: ToolBarConfig[] = [
|
|
@@ -210,141 +242,43 @@ const Roles = () => {
|
|
},
|
|
},
|
|
];
|
|
];
|
|
|
|
|
|
- const colDefinitions: ColDefinitionsType[] = [
|
|
|
|
- {
|
|
|
|
- id: 'roleName',
|
|
|
|
- align: 'left',
|
|
|
|
- disablePadding: false,
|
|
|
|
- label: userTrans('role'),
|
|
|
|
- sortType: 'string',
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- {
|
|
|
|
- id: 'privileges',
|
|
|
|
- align: 'left',
|
|
|
|
- disablePadding: false,
|
|
|
|
- formatter({ privileges, roleName }) {
|
|
|
|
- const isAdmin = roleName === 'admin';
|
|
|
|
-
|
|
|
|
- // Derive the options arrays as in DBCollectionSelector.
|
|
|
|
- const rbacEntries = Object.entries(rbacOptions) as [
|
|
|
|
- string,
|
|
|
|
- Record<string, string>
|
|
|
|
- ][];
|
|
|
|
-
|
|
|
|
- // privileges of the privilege groups
|
|
|
|
- const privilegeGroups = rbacEntries.filter(([key]) =>
|
|
|
|
- key.endsWith('PrivilegeGroups')
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- const groupPrivileges = new Set(
|
|
|
|
- privilegeGroups.reduce(
|
|
|
|
- (acc, [_, group]) => acc.concat(Object.values(group)),
|
|
|
|
- [] as string[]
|
|
|
|
- )
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- let groupCount = 0;
|
|
|
|
- let privilegeCount = 0;
|
|
|
|
-
|
|
|
|
- Object.values(privileges as DBCollectionsPrivileges).forEach(
|
|
|
|
- dbPrivileges => {
|
|
|
|
- Object.values(dbPrivileges.collections).forEach(
|
|
|
|
- collectionPrivileges => {
|
|
|
|
- Object.keys(collectionPrivileges).forEach(privilege => {
|
|
|
|
- if (groupPrivileges.has(privilege)) {
|
|
|
|
- groupCount++;
|
|
|
|
- } else {
|
|
|
|
- privilegeCount++;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- return (
|
|
|
|
- <div>
|
|
|
|
- {
|
|
|
|
- <>
|
|
|
|
- <div style={{ marginBottom: 2 }}>
|
|
|
|
- <Chip
|
|
|
|
- label={`${userTrans('Group')} (${
|
|
|
|
- isAdmin ? '*' : groupCount
|
|
|
|
- })`}
|
|
|
|
- size="small"
|
|
|
|
- style={{ marginRight: 2 }}
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
- <div style={{ marginBottom: 2 }}>
|
|
|
|
- <Chip
|
|
|
|
- label={`${userTrans('privileges')} (${
|
|
|
|
- isAdmin ? '*' : privilegeCount
|
|
|
|
- })`}
|
|
|
|
- size="small"
|
|
|
|
- style={{ marginRight: 2 }}
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
- </>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- label: userTrans('privileges'),
|
|
|
|
- getStyle: () => {
|
|
|
|
- return {
|
|
|
|
- width: '80%',
|
|
|
|
- };
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- ];
|
|
|
|
-
|
|
|
|
- const handleSelectChange = (value: any[]) => {
|
|
|
|
- setSelectedRole(value);
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
fetchRoles();
|
|
fetchRoles();
|
|
}, [database]);
|
|
}, [database]);
|
|
|
|
|
|
- const {
|
|
|
|
- pageSize,
|
|
|
|
- handlePageSize,
|
|
|
|
- currentPage,
|
|
|
|
- handleCurrentPage,
|
|
|
|
- total,
|
|
|
|
- data: result,
|
|
|
|
- order,
|
|
|
|
- orderBy,
|
|
|
|
- handleGridSort,
|
|
|
|
- } = usePaginationHook(roles || []);
|
|
|
|
-
|
|
|
|
- const handlePageChange = (e: any, page: number) => {
|
|
|
|
- handleCurrentPage(page);
|
|
|
|
|
|
+ const handleRoleClick = (role: RolesWithPrivileges) => {
|
|
|
|
+ setSelectedRole([role]);
|
|
};
|
|
};
|
|
|
|
|
|
return (
|
|
return (
|
|
<Wrapper className={classes.wrapper} hasPermission={hasPermission}>
|
|
<Wrapper className={classes.wrapper} hasPermission={hasPermission}>
|
|
- <AttuGrid
|
|
|
|
- toolbarConfigs={toolbarConfigs}
|
|
|
|
- colDefinitions={colDefinitions}
|
|
|
|
- rows={result}
|
|
|
|
- rowCount={total}
|
|
|
|
- primaryKey="roleName"
|
|
|
|
- showPagination={true}
|
|
|
|
- selected={selectedRole}
|
|
|
|
- setSelected={handleSelectChange}
|
|
|
|
- page={currentPage}
|
|
|
|
- onPageChange={handlePageChange}
|
|
|
|
- rowsPerPage={pageSize}
|
|
|
|
- rowHeight={69}
|
|
|
|
- setRowsPerPage={handlePageSize}
|
|
|
|
- isLoading={loading}
|
|
|
|
- order={order}
|
|
|
|
- orderBy={orderBy}
|
|
|
|
- handleSort={handleGridSort}
|
|
|
|
- labelDisplayedRows={getLabelDisplayedRows(userTrans('roles'))}
|
|
|
|
- />
|
|
|
|
|
|
+ <CustomToolBar toolbarConfigs={toolbarConfigs} />
|
|
|
|
+
|
|
|
|
+ <Box sx={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
|
|
+ <Box className={classes.list}>
|
|
|
|
+ <List>
|
|
|
|
+ {roles.map(role => (
|
|
|
|
+ <ListItemButton
|
|
|
|
+ key={role.roleName}
|
|
|
|
+ selected={
|
|
|
|
+ selectedRole.length > 0 &&
|
|
|
|
+ selectedRole[0].roleName === role.roleName
|
|
|
|
+ }
|
|
|
|
+ onClick={() => handleRoleClick(role)}
|
|
|
|
+ >
|
|
|
|
+ <ListItemText primary={role.roleName} />
|
|
|
|
+ </ListItemButton>
|
|
|
|
+ ))}
|
|
|
|
+ </List>
|
|
|
|
+ </Box>
|
|
|
|
+ <div className={classes.tree}>
|
|
|
|
+ <D3PrivilegeTree
|
|
|
|
+ privileges={selectedRole[0]?.privileges}
|
|
|
|
+ role={selectedRole[0]?.roleName}
|
|
|
|
+ rbacOptions={rbacOptions}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </Box>
|
|
</Wrapper>
|
|
</Wrapper>
|
|
);
|
|
);
|
|
};
|
|
};
|