From f4ae4abb5715b1efeaee3131e7773503a1dcbaf2 Mon Sep 17 00:00:00 2001 From: SteveGT96 Date: Tue, 29 Oct 2024 16:06:00 +0100 Subject: [PATCH] Add a 'select all' option for columns and rows in the group permissions edit page --- .../admin/users/editGroup/EditGroup.tsx | 24 ++--- .../editPermissions/AclPermissionCheckbox.tsx | 42 +++----- .../admin/users/editPermissions/AclTable.tsx | 99 ++++++++++++++++++- .../users/editPermissions/AreaAccess.tsx | 5 +- .../GroupPermissionsEditor.tsx | 4 +- .../editPermissions/PermissionCheckbox.tsx | 7 +- .../users/editPermissions/permission.utils.ts | 4 +- src/resources/i18n/en.json | 5 +- 8 files changed, 137 insertions(+), 53 deletions(-) diff --git a/src/components/accessories/admin/users/editGroup/EditGroup.tsx b/src/components/accessories/admin/users/editGroup/EditGroup.tsx index c9ac20d9a..a5b77b261 100644 --- a/src/components/accessories/admin/users/editGroup/EditGroup.tsx +++ b/src/components/accessories/admin/users/editGroup/EditGroup.tsx @@ -22,13 +22,13 @@ import { updateUserGroup, updateUserGroupReset, } from "../../../../../state/usergroups"; +import { TabOptions } from "../Users"; import { GroupPermissionsEditor } from "../editPermissions/GroupPermissionsEditor"; import { PermissionActionEnum, PermissionActionType, comparePermissions, } from "../editPermissions/permission.utils"; -import { TabOptions } from "../Users"; import "./styles.scss"; import { userGroupSchema } from "./validation"; @@ -58,18 +58,18 @@ export const EditGroup = () => { >([]); const handleUpdatePermissions = ({ - permission, + permissions: perms, action, }: PermissionActionType) => { const otherPermissions = groupPermissions.filter( - (p) => p.id !== permission.id + (p) => !perms.some((item) => item.id === p.id) ); if (action === PermissionActionEnum.REVOKE) { setGroupPermissions(otherPermissions); } if (action === PermissionActionEnum.ASSIGN) { - setGroupPermissions([...otherPermissions, permission]); + setGroupPermissions([...otherPermissions, ...perms]); } }; @@ -197,13 +197,15 @@ export const EditGroup = () => { Editing permissions:{" "} {updatedPermissionsStack - .map( - (p) => - `${p.permission.name}: ${ - p.action === PermissionActionEnum.ASSIGN - ? "assign" - : "revoked" - }` + .flatMap((p) => + p.permissions.map( + (item) => + `${item.name}: ${ + p.action === PermissionActionEnum.ASSIGN + ? "assign" + : "revoked" + }` + ) ) .join(",")} diff --git a/src/components/accessories/admin/users/editPermissions/AclPermissionCheckbox.tsx b/src/components/accessories/admin/users/editPermissions/AclPermissionCheckbox.tsx index 6c38dd86f..eb9e0d812 100644 --- a/src/components/accessories/admin/users/editPermissions/AclPermissionCheckbox.tsx +++ b/src/components/accessories/admin/users/editPermissions/AclPermissionCheckbox.tsx @@ -1,12 +1,16 @@ -import { Checkbox, Popper } from "@mui/material"; +import { Checkbox, Tooltip } from "@mui/material"; import React from "react"; +import { useTranslation } from "react-i18next"; import { PermissionDTO } from "../../../../../generated"; import { PermissionActionEnum } from "./permission.utils"; interface IProps { permission: PermissionDTO; groupPermissions: Array; - onChange: (permission: PermissionDTO, action: PermissionActionEnum) => void; + onChange: ( + permissions: [PermissionDTO], + action: PermissionActionEnum + ) => void; } export const AclPermissionCheckbox = ({ @@ -14,46 +18,22 @@ export const AclPermissionCheckbox = ({ groupPermissions, onChange, }: IProps) => { - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - const id = open ? "simple-popper" : undefined; + const { t } = useTranslation(); const checked = groupPermissions?.some((p) => p.id === permission.id) || false; return ( - <> + onChange( - permission, + [permission], checked ? PermissionActionEnum.REVOKE : PermissionActionEnum.ASSIGN ) } name={permission.id.toString()} - onMouseEnter={(event: React.MouseEvent) => { - setAnchorEl(anchorEl ? null : event.currentTarget); - }} - onMouseLeave={() => setAnchorEl(null)} /> - - - {permission.name || "unknown"} - - - + ); }; diff --git a/src/components/accessories/admin/users/editPermissions/AclTable.tsx b/src/components/accessories/admin/users/editPermissions/AclTable.tsx index 42eb72d3b..7f972681b 100644 --- a/src/components/accessories/admin/users/editPermissions/AclTable.tsx +++ b/src/components/accessories/admin/users/editPermissions/AclTable.tsx @@ -1,5 +1,6 @@ -import React, { useMemo } from "react"; +import React, { ChangeEvent, useCallback, useMemo } from "react"; +import { Checkbox, Tooltip } from "@mui/material"; import { useTranslation } from "react-i18next"; import { PermissionDTO } from "../../../../../generated"; import { AclPermissionCheckbox } from "./AclPermissionCheckbox"; @@ -13,7 +14,10 @@ import { interface IProps { permissions: PermissionDTO[]; groupPermissions: PermissionDTO[]; - onChange: (permission: PermissionDTO, action: PermissionActionEnum) => void; + onChange: ( + permissions: PermissionDTO[], + action: PermissionActionEnum + ) => void; } export const AclTable = ({ @@ -29,22 +33,111 @@ export const AclTable = ({ const crudKeys = Array.from(crudPermissions.keys()); + const allColumnsChecked = useCallback( + (crudKey: string) => { + return ( + [Crud.CREATE, Crud.READ, Crud.UPDATE, Crud.DELETE].filter((item) => + groupPermissions.some((p) => p.name === `${crudKey}.${item}`) + ).length === + [Crud.CREATE, Crud.READ, Crud.UPDATE, Crud.DELETE].filter((item) => + permissions.some((p) => p.name === `${crudKey}.${item}`) + ).length + ); + }, + [groupPermissions, permissions] + ); + + const allRowsChecked = useCallback(() => { + return ( + crudKeys.filter((crudKey) => allColumnsChecked(crudKey)).length === + crudKeys.length + ); + }, [groupPermissions, permissions, allColumnsChecked]); + + const toggleCheckAllColumns = useCallback( + (crudKey: string) => (event: ChangeEvent) => { + const crudPermNames = [ + Crud.CREATE, + Crud.READ, + Crud.UPDATE, + Crud.DELETE, + ].map((item) => `${crudKey}.${item}`); + const crudPerms = permissions.filter((p) => + crudPermNames.includes(p.name!) + ); + if (event.target.checked) { + onChange( + crudPerms.filter( + (item) => !groupPermissions.some((p) => p.id === item.id) + ), + PermissionActionEnum.ASSIGN + ); + } else { + onChange(crudPerms, PermissionActionEnum.REVOKE); + } + }, + [groupPermissions, permissions, onChange] + ); + + const toggleCheckAllRows = useCallback( + (event: ChangeEvent) => { + const crudPermNames = [ + Crud.CREATE, + Crud.READ, + Crud.UPDATE, + Crud.DELETE, + ].flatMap((item) => crudKeys.map((crudKey) => `${crudKey}.${item}`)); + const crudPerms = permissions.filter((p) => + crudPermNames.includes(p.name!) + ); + if (event.target.checked) { + onChange( + crudPerms.filter( + (item) => !groupPermissions.some((p) => p.id === item.id) + ), + PermissionActionEnum.ASSIGN + ); + } else { + onChange(crudPerms, PermissionActionEnum.REVOKE); + } + }, + [groupPermissions, permissions] + ); + return (
+ - + {Array.from(crudPermissions.values()).map((crudPermission, index) => { return ( + {[Crud.CREATE, Crud.READ, Crud.UPDATE, Crud.DELETE].map( (access: Crud, index: number) => { diff --git a/src/components/accessories/admin/users/editPermissions/AreaAccess.tsx b/src/components/accessories/admin/users/editPermissions/AreaAccess.tsx index ec90d1dbc..cdf822740 100644 --- a/src/components/accessories/admin/users/editPermissions/AreaAccess.tsx +++ b/src/components/accessories/admin/users/editPermissions/AreaAccess.tsx @@ -7,7 +7,10 @@ import { PermissionActionEnum } from "./permission.utils"; interface IProps { permissions: PermissionDTO[]; groupPermissions: PermissionDTO[]; - onChange: (permission: PermissionDTO, action: PermissionActionEnum) => void; + onChange: ( + permissions: PermissionDTO[], + action: PermissionActionEnum + ) => void; } export const AreaAccess = ({ permissions, diff --git a/src/components/accessories/admin/users/editPermissions/GroupPermissionsEditor.tsx b/src/components/accessories/admin/users/editPermissions/GroupPermissionsEditor.tsx index ee15e53f9..f73a5aa0d 100644 --- a/src/components/accessories/admin/users/editPermissions/GroupPermissionsEditor.tsx +++ b/src/components/accessories/admin/users/editPermissions/GroupPermissionsEditor.tsx @@ -19,11 +19,11 @@ export const GroupPermissionsEditor = ({ update, }: IProps) => { const handleChange = ( - newPermission: PermissionDTO, + newPermissions: PermissionDTO[], action: PermissionActionEnum ) => { setDirty(true); - update({ permission: newPermission, action }); + update({ permissions: newPermissions, action }); }; const { t } = useTranslation(); diff --git a/src/components/accessories/admin/users/editPermissions/PermissionCheckbox.tsx b/src/components/accessories/admin/users/editPermissions/PermissionCheckbox.tsx index 3ac90792c..b5547d822 100644 --- a/src/components/accessories/admin/users/editPermissions/PermissionCheckbox.tsx +++ b/src/components/accessories/admin/users/editPermissions/PermissionCheckbox.tsx @@ -6,7 +6,10 @@ import { PermissionActionEnum } from "./permission.utils"; interface IProps { permission: PermissionDTO; groupPermissions: Array; - onChange: (permission: PermissionDTO, action: PermissionActionEnum) => void; + onChange: ( + permissions: PermissionDTO[], + action: PermissionActionEnum + ) => void; } export const PermissionCheckbox = ({ @@ -23,7 +26,7 @@ export const PermissionCheckbox = ({ checked={checked} onChange={(_ev, val) => onChange( - permission, + [permission], checked ? PermissionActionEnum.REVOKE : PermissionActionEnum.ASSIGN diff --git a/src/components/accessories/admin/users/editPermissions/permission.utils.ts b/src/components/accessories/admin/users/editPermissions/permission.utils.ts index efd8d53ac..da29cdc52 100644 --- a/src/components/accessories/admin/users/editPermissions/permission.utils.ts +++ b/src/components/accessories/admin/users/editPermissions/permission.utils.ts @@ -7,7 +7,7 @@ export enum PermissionActionEnum { export type PermissionActionType = { action: PermissionActionEnum; - permission: PermissionDTO; + permissions: PermissionDTO[]; }; export enum Crud { @@ -79,7 +79,7 @@ export const comparePermissions = ( action: stackedPermission ? PermissionActionEnum.ASSIGN : PermissionActionEnum.REVOKE, - permission, + permissions: [permission], }, ]; } diff --git a/src/resources/i18n/en.json b/src/resources/i18n/en.json index 1ca6ac69d..972077f64 100644 --- a/src/resources/i18n/en.json +++ b/src/resources/i18n/en.json @@ -574,8 +574,11 @@ "read": "Read", "update": "Update", "deleted": "Deleted", + "delete": "Delete", "accessarea": "Access area", - "accesscontrollist": "Access control list" + "accesscontrollist": "Access control list", + "toggle-check-all": "Toggle check all", + "all": "All" }, "therapy": { "newtherapy": "New Therapy",
+ + + + {t("permission.name")} {t("permission.create")} {t("permission.read")} {t("permission.update")}{t("permission.deleted")}{t("permission.delete")}
+ + + + {crudKeys[index]}