1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-12 11:54:35 +00:00

feat: add multiple permission for same combination of type and principal at once

This commit is contained in:
2022-08-03 23:26:31 +05:00
parent 78bea7c154
commit 754704bca8
4 changed files with 171 additions and 53 deletions

View File

@@ -32,7 +32,7 @@ const BootstrapDialog = styled(Dialog)(({ theme }) => ({
type AddPermissionModalProps = { type AddPermissionModalProps = {
open: boolean open: boolean
handleOpen: Dispatch<SetStateAction<boolean>> handleOpen: Dispatch<SetStateAction<boolean>>
addPermission: (addPermissionPayload: RegisterPermissionPayload) => void addPermission: (permissions: RegisterPermissionPayload[]) => void
} }
const AddPermissionModal = ({ const AddPermissionModal = ({
@@ -42,9 +42,9 @@ const AddPermissionModal = ({
}: AddPermissionModalProps) => { }: AddPermissionModalProps) => {
const [paths, setPaths] = useState<string[]>([]) const [paths, setPaths] = useState<string[]>([])
const [loadingPaths, setLoadingPaths] = useState(false) const [loadingPaths, setLoadingPaths] = useState(false)
const [path, setPath] = useState<string>() const [selectedPaths, setSelectedPaths] = useState<string[]>([])
const [permissionType, setPermissionType] = useState('Route') const [permissionType, setPermissionType] = useState('Route')
const [principalType, setPrincipalType] = useState('group') const [principalType, setPrincipalType] = useState('Group')
const [userPrincipal, setUserPrincipal] = useState<UserResponse>() const [userPrincipal, setUserPrincipal] = useState<UserResponse>()
const [groupPrincipal, setGroupPrincipal] = useState<GroupResponse>() const [groupPrincipal, setGroupPrincipal] = useState<GroupResponse>()
const [permissionSetting, setPermissionSetting] = useState('Grant') const [permissionSetting, setPermissionSetting] = useState('Grant')
@@ -72,10 +72,10 @@ const AddPermissionModal = ({
useEffect(() => { useEffect(() => {
setLoadingPrincipals(true) setLoadingPrincipals(true)
axios axios
.get(`/SASjsApi/${principalType}`) .get(`/SASjsApi/${principalType.toLowerCase()}`)
.then((res: any) => { .then((res: any) => {
if (res.data) { if (res.data) {
if (principalType === 'user') { if (principalType.toLowerCase() === 'user') {
const users: UserResponse[] = res.data const users: UserResponse[] = res.data
const nonAdminUsers = users.filter((user) => !user.isAdmin) const nonAdminUsers = users.filter((user) => !user.isAdmin)
setUserPrincipals(nonAdminUsers) setUserPrincipals(nonAdminUsers)
@@ -93,22 +93,29 @@ const AddPermissionModal = ({
}, [principalType]) }, [principalType])
const handleAddPermission = () => { const handleAddPermission = () => {
const addPermissionPayload: any = { const permissions: RegisterPermissionPayload[] = []
path,
type: permissionType, selectedPaths.forEach((path) => {
setting: permissionSetting, const addPermissionPayload: any = {
principalType path,
} type: permissionType,
if (principalType === 'user' && userPrincipal) { setting: permissionSetting,
addPermissionPayload.principalId = userPrincipal.id principalType: principalType.toLowerCase(),
} else if (principalType === 'group' && groupPrincipal) { principalId:
addPermissionPayload.principalId = groupPrincipal.groupId principalType.toLowerCase() === 'user'
} ? userPrincipal?.id
addPermission(addPermissionPayload) : groupPrincipal?.groupId
}
permissions.push(addPermissionPayload)
})
addPermission(permissions)
} }
const addButtonDisabled = const addButtonDisabled =
!path || (principalType === 'user' ? !userPrincipal : !groupPrincipal) !selectedPaths.length ||
(principalType.toLowerCase() === 'user' ? !userPrincipal : !groupPrincipal)
return ( return (
<BootstrapDialog onClose={() => handleOpen(false)} open={open}> <BootstrapDialog onClose={() => handleOpen(false)} open={open}>
@@ -122,17 +129,14 @@ const AddPermissionModal = ({
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={12}> <Grid item xs={12}>
<Autocomplete <Autocomplete
multiple
options={paths} options={paths}
disableClearable filterSelectedOptions
value={path} value={selectedPaths}
onChange={(event: any, newValue: string) => setPath(newValue)} onChange={(event: any, newValue: string[]) => {
renderInput={(params) => setSelectedPaths(newValue)
loadingPaths ? ( }}
<CircularProgress /> renderInput={(params) => <TextField {...params} label="Paths" />}
) : (
<TextField {...params} autoFocus label="Path" />
)
}
/> />
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
@@ -154,8 +158,7 @@ const AddPermissionModal = ({
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<Autocomplete <Autocomplete
options={['group', 'user']} options={['Group', 'User']}
getOptionLabel={(option) => option.toUpperCase()}
disableClearable disableClearable
value={principalType} value={principalType}
onChange={(event: any, newValue: string) => onChange={(event: any, newValue: string) =>
@@ -167,7 +170,7 @@ const AddPermissionModal = ({
/> />
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
{principalType === 'user' ? ( {principalType.toLowerCase() === 'user' ? (
<Autocomplete <Autocomplete
options={userPrincipals} options={userPrincipals}
getOptionLabel={(option) => option.displayName} getOptionLabel={(option) => option.displayName}

View File

@@ -0,0 +1,99 @@
import React from 'react'
import {
Paper,
Typography,
DialogContent,
TableContainer,
Table,
TableHead,
TableBody,
TableRow,
TableCell
} from '@mui/material'
import { BootstrapDialog } from '../../components/modal'
import { BootstrapDialogTitle } from '../../components/dialogTitle'
import { PermissionResponse } from '../../utils/types'
type Props = {
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
permissionResponses: PermissionResponse[]
errorResponses: any[]
}
const PermissionResponseModal = ({
open,
setOpen,
permissionResponses,
errorResponses
}: Props) => {
return (
<div>
<BootstrapDialog onClose={() => setOpen(false)} open={open}>
<BootstrapDialogTitle
id="permission-response-modal"
handleOpen={setOpen}
>
Permission Response
</BootstrapDialogTitle>
<DialogContent dividers>
{permissionResponses.length > 0 && (
<>
<Typography gutterBottom>Added Permissions</Typography>
{permissionResponses.length > 0 && (
<TableContainer component={Paper}>
<Table size="small">
<TableHead>
<TableRow>
<TableCell>Path</TableCell>
<TableCell>Type</TableCell>
<TableCell>Setting</TableCell>
</TableRow>
</TableHead>
<TableBody>
{permissionResponses.map((permission, index) => {
return (
<TableRow key={index}>
<TableCell>{permission.path}</TableCell>
<TableCell>{permission.type}</TableCell>
<TableCell>{permission.setting}</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</TableContainer>
)}
</>
)}
{errorResponses.length > 0 && (
<>
<Typography style={{ color: 'red', marginTop: '10px' }}>
Errors
</Typography>
<ul>
{errorResponses.map((err, index) => (
<li key={index}>
<Typography>
Error occurred for Path: {err.permission.path}
</Typography>
<Typography>
{typeof err.error.response.data === 'object'
? JSON.stringify(err.error.response.data)
: err.error.response.data}
</Typography>
</li>
))}
</ul>
</>
)}
</DialogContent>
</BootstrapDialog>
</div>
)
}
export default PermissionResponseModal

View File

@@ -27,6 +27,7 @@ import { styled } from '@mui/material/styles'
import Modal from '../../components/modal' import Modal from '../../components/modal'
import PermissionFilterModal from './permissionFilterModal' import PermissionFilterModal from './permissionFilterModal'
import AddPermissionModal from './addPermissionModal' import AddPermissionModal from './addPermissionModal'
import PermissionResponseModal from './addPermissionResponseModal'
import UpdatePermissionModal from './updatePermissionModal' import UpdatePermissionModal from './updatePermissionModal'
import DeleteConfirmationModal from '../../components/deleteConfirmationModal' import DeleteConfirmationModal from '../../components/deleteConfirmationModal'
import BootstrapSnackbar, { AlertSeverityType } from '../../components/snackbar' import BootstrapSnackbar, { AlertSeverityType } from '../../components/snackbar'
@@ -59,6 +60,13 @@ const Permission = () => {
AlertSeverityType.Success AlertSeverityType.Success
) )
const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false) const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false)
const [openPermissionResponseModal, setOpenPermissionResponseModal] =
useState(false)
const [addedPermissions, setAddedPermission] = useState<PermissionResponse[]>(
[]
)
const [errorResponses, setErrorResponses] = useState<any[]>([])
const [updatePermissionModalOpen, setUpdatePermissionModalOpen] = const [updatePermissionModalOpen, setUpdatePermissionModalOpen] =
useState(false) useState(false)
const [deleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = const [deleteConfirmationModalOpen, setDeleteConfirmationModalOpen] =
@@ -181,29 +189,31 @@ const Permission = () => {
setFilterApplied(false) setFilterApplied(false)
} }
const addPermission = (addPermissionPayload: RegisterPermissionPayload) => { const addPermission = (permissions: RegisterPermissionPayload[]) => {
setAddPermissionModalOpen(false) setAddPermissionModalOpen(false)
setAddedPermission([])
setErrorResponses([])
setIsLoading(true) setIsLoading(true)
axios
.post('/SASjsApi/permission', addPermissionPayload) const permissionResponses: PermissionResponse[] = []
.then((res: any) => { const errors: any = []
fetchPermissions()
setSnackbarMessage('Permission added!') permissions.forEach(async (permission) => {
setSnackbarSeverity(AlertSeverityType.Success) await axios
setOpenSnackbar(true) .post('/SASjsApi/permission', permission)
}) .then((res) => {
.catch((err) => { permissionResponses.push(res.data)
setModalTitle('Abort') })
setModalPayload( .catch((error) => {
typeof err.response.data === 'object' errors.push({ error, permission })
? JSON.stringify(err.response.data) })
: err.response.data })
)
setOpenModal(true) fetchPermissions()
}) setIsLoading(false)
.finally(() => { setOpenPermissionResponseModal(true)
setIsLoading(false) setAddedPermission(permissionResponses)
}) setErrorResponses(errors)
} }
const handleUpdatePermissionClick = (permission: PermissionResponse) => { const handleUpdatePermissionClick = (permission: PermissionResponse) => {
@@ -340,6 +350,12 @@ const Permission = () => {
handleOpen={setAddPermissionModalOpen} handleOpen={setAddPermissionModalOpen}
addPermission={addPermission} addPermission={addPermission}
/> />
<PermissionResponseModal
open={openPermissionResponseModal}
setOpen={setOpenPermissionResponseModal}
permissionResponses={addedPermissions}
errorResponses={errorResponses}
/>
<UpdatePermissionModal <UpdatePermissionModal
open={updatePermissionModalOpen} open={updatePermissionModalOpen}
handleOpen={setUpdatePermissionModalOpen} handleOpen={setUpdatePermissionModalOpen}

View File

@@ -92,7 +92,7 @@ const PermissionFilterModal = ({
onChange={(event: any, newValue: string[]) => { onChange={(event: any, newValue: string[]) => {
setPathFilter(newValue) setPathFilter(newValue)
}} }}
renderInput={(params) => <TextField {...params} label="URIs" />} renderInput={(params) => <TextField {...params} label="Paths" />}
/> />
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>