From 7a162eda8fc60383ff647d93e6611799e2e6af7a Mon Sep 17 00:00:00 2001 From: Sabir Hassan Date: Thu, 4 Aug 2022 02:51:59 +0500 Subject: [PATCH] fix: improve user experience for adding permissions --- .../Settings/addPermissionResponseModal.tsx | 157 ++++++++++++------ web/src/containers/Settings/index.tsx | 2 +- web/src/containers/Settings/permission.tsx | 83 +++++++-- web/src/utils/helper.ts | 59 +++++++ 4 files changed, 233 insertions(+), 68 deletions(-) create mode 100644 web/src/utils/helper.ts diff --git a/web/src/containers/Settings/addPermissionResponseModal.tsx b/web/src/containers/Settings/addPermissionResponseModal.tsx index 181778c..5bb6696 100644 --- a/web/src/containers/Settings/addPermissionResponseModal.tsx +++ b/web/src/containers/Settings/addPermissionResponseModal.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useMemo } from 'react' import { Paper, @@ -16,19 +16,92 @@ import { BootstrapDialog } from '../../components/modal' import { BootstrapDialogTitle } from '../../components/dialogTitle' import { PermissionResponse } from '../../utils/types' +export interface PermissionResponsePayload { + existingPermissions: PermissionResponse[] + newAddedPermissions: PermissionResponse[] + updatedPermissions: PermissionResponse[] + errorPaths: string[] +} + type Props = { open: boolean setOpen: React.Dispatch> - permissionResponses: PermissionResponse[] - errorResponses: any[] + payload: PermissionResponsePayload } -const PermissionResponseModal = ({ - open, - setOpen, - permissionResponses, - errorResponses -}: Props) => { +const PermissionResponseModal = ({ open, setOpen, payload }: Props) => { + const rows = useMemo(() => { + const paths: any = [] + + const existingPermissionsLength = payload.existingPermissions.length + const newAddedPermissionsLength = payload.newAddedPermissions.length + const updatedPermissionsLength = payload.updatedPermissions.length + if ( + existingPermissionsLength >= newAddedPermissionsLength && + existingPermissionsLength >= updatedPermissionsLength + ) { + payload.existingPermissions.forEach((permission, index) => { + const obj = { + existing: permission.path, + newAdded: + index < newAddedPermissionsLength + ? payload.newAddedPermissions[index].path + : '-', + updated: + index < updatedPermissionsLength + ? payload.updatedPermissions[index].path + : '-' + } + paths.push(obj) + }) + return paths + } + + if ( + newAddedPermissionsLength >= existingPermissionsLength && + newAddedPermissionsLength >= updatedPermissionsLength + ) { + payload.newAddedPermissions.forEach((permission, index) => { + const obj = { + newAdded: permission.path, + existing: + index < existingPermissionsLength + ? payload.existingPermissions[index].path + : '-', + updated: + index < updatedPermissionsLength + ? payload.updatedPermissions[index].path + : '-' + } + paths.push(obj) + }) + return paths + } + + if ( + updatedPermissionsLength >= existingPermissionsLength && + updatedPermissionsLength >= newAddedPermissionsLength + ) { + payload.updatedPermissions.forEach((permission, index) => { + const obj = { + updated: permission.path, + existing: + index < existingPermissionsLength + ? payload.existingPermissions[index].path + : '-', + newAdded: + index < newAddedPermissionsLength + ? payload.newAddedPermissions[index].path + : '-' + } + paths.push(obj) + }) + return paths + } + + return paths + }, [payload]) + return (
setOpen(false)} open={open}> @@ -39,52 +112,38 @@ const PermissionResponseModal = ({ Permission Response - {permissionResponses.length > 0 && ( - <> - Added Permissions - {permissionResponses.length > 0 && ( - - - - - Path - Type - Setting - - - - {permissionResponses.map((permission, index) => { - return ( - - {permission.path} - {permission.type} - {permission.setting} - - ) - })} - -
-
- )} - - )} + + + + + New + Updated + Unchanged + + + + {rows.map((obj: any, index: number) => { + return ( + + {obj.newAdded} + {obj.updated} + {obj.existing} + + ) + })} + +
+
- {errorResponses.length > 0 && ( + {payload.errorPaths.length > 0 && ( <> - Errors + Errors occurred for following paths:
    - {errorResponses.map((err, index) => ( + {payload.errorPaths.map((path, index) => (
  • - - Error occurred for Path: {err.permission.path} - - - {typeof err.error.response.data === 'object' - ? JSON.stringify(err.error.response.data) - : err.error.response.data} - + {path}
  • ))}
diff --git a/web/src/containers/Settings/index.tsx b/web/src/containers/Settings/index.tsx index a93d400..9abe7bf 100644 --- a/web/src/containers/Settings/index.tsx +++ b/web/src/containers/Settings/index.tsx @@ -47,7 +47,7 @@ const Settings = () => { > {appContext.mode === ModeType.Server && ( - + )} diff --git a/web/src/containers/Settings/permission.tsx b/web/src/containers/Settings/permission.tsx index 32223f1..086f13e 100644 --- a/web/src/containers/Settings/permission.tsx +++ b/web/src/containers/Settings/permission.tsx @@ -27,7 +27,9 @@ import { styled } from '@mui/material/styles' import Modal from '../../components/modal' import PermissionFilterModal from './permissionFilterModal' import AddPermissionModal from './addPermissionModal' -import PermissionResponseModal from './addPermissionResponseModal' +import PermissionResponseModal, { + PermissionResponsePayload +} from './addPermissionResponseModal' import UpdatePermissionModal from './updatePermissionModal' import DeleteConfirmationModal from '../../components/deleteConfirmationModal' import BootstrapSnackbar, { AlertSeverityType } from '../../components/snackbar' @@ -37,6 +39,11 @@ import { PermissionResponse, RegisterPermissionPayload } from '../../utils/types' +import { + findExistingPermission, + findUpdatingPermission +} from '../../utils/helper' + import { AppContext } from '../../context/appContext' const BootstrapTableCell = styled(TableCell)({ @@ -62,10 +69,13 @@ const Permission = () => { const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false) const [openPermissionResponseModal, setOpenPermissionResponseModal] = useState(false) - const [addedPermissions, setAddedPermission] = useState( - [] - ) - const [errorResponses, setErrorResponses] = useState([]) + const [permissionResponsePayload, setPermissionResponsePayload] = + useState({ + existingPermissions: [], + newAddedPermissions: [], + updatedPermissions: [], + errorPaths: [] + }) const [updatePermissionModalOpen, setUpdatePermissionModalOpen] = useState(false) @@ -189,31 +199,69 @@ const Permission = () => { setFilterApplied(false) } - const addPermission = (permissions: RegisterPermissionPayload[]) => { + const addPermission = async ( + permissionsToAdd: RegisterPermissionPayload[] + ) => { setAddPermissionModalOpen(false) - setAddedPermission([]) - setErrorResponses([]) setIsLoading(true) - const permissionResponses: PermissionResponse[] = [] - const errors: any = [] + const newAddedPermissions: PermissionResponse[] = [] + const updatedPermissions: PermissionResponse[] = [] + const errorPaths: string[] = [] - permissions.forEach(async (permission) => { + const existingPermissions: PermissionResponse[] = [] + const updatingPermissions: PermissionResponse[] = [] + const newPermissions: RegisterPermissionPayload[] = [] + + permissionsToAdd.forEach((permission) => { + const existingPermission = findExistingPermission(permissions, permission) + if (existingPermission) { + existingPermissions.push(existingPermission) + return + } + + const updatingPermission = findUpdatingPermission(permissions, permission) + if (updatingPermission) { + updatingPermissions.push(updatingPermission) + return + } + + newPermissions.push(permission) + }) + + for (const permission of newPermissions) { await axios .post('/SASjsApi/permission', permission) .then((res) => { - permissionResponses.push(res.data) + newAddedPermissions.push(res.data) }) .catch((error) => { - errors.push({ error, permission }) + errorPaths.push(permission.path) }) - }) + } + + for (const permission of updatingPermissions) { + await axios + .patch(`/SASjsApi/permission/${permission.permissionId}`, { + setting: permission.setting === 'Grant' ? 'Deny' : 'Grant' + }) + .then((res) => { + updatedPermissions.push(res.data) + }) + .catch((error) => { + errorPaths.push(permission.path) + }) + } fetchPermissions() setIsLoading(false) + setPermissionResponsePayload({ + existingPermissions, + updatedPermissions, + newAddedPermissions, + errorPaths + }) setOpenPermissionResponseModal(true) - setAddedPermission(permissionResponses) - setErrorResponses(errors) } const handleUpdatePermissionClick = (permission: PermissionResponse) => { @@ -353,8 +401,7 @@ const Permission = () => { { + for (const permission of existingPermissions) { + if ( + permission.user?.id === newPermission.principalId && + hasSameCombination(permission, newPermission) + ) + return permission + + if ( + permission.group?.groupId === newPermission.principalId && + hasSameCombination(permission, newPermission) + ) + return permission + } + + return null +} + +export const findUpdatingPermission = ( + existingPermissions: PermissionResponse[], + newPermission: RegisterPermissionPayload +) => { + for (const permission of existingPermissions) { + if ( + permission.user?.id === newPermission.principalId && + hasDifferentSetting(permission, newPermission) + ) + return permission + + if ( + permission.group?.groupId === newPermission.principalId && + hasDifferentSetting(permission, newPermission) + ) + return permission + } + + return null +} + +const hasSameCombination = ( + existingPermission: PermissionResponse, + newPermission: RegisterPermissionPayload +) => + existingPermission.path === newPermission.path && + existingPermission.type === newPermission.type && + existingPermission.setting === newPermission.setting + +const hasDifferentSetting = ( + existingPermission: PermissionResponse, + newPermission: RegisterPermissionPayload +) => + existingPermission.path === newPermission.path && + existingPermission.type === newPermission.type && + existingPermission.setting !== newPermission.setting