mirror of
https://github.com/sasjs/server.git
synced 2026-01-09 23:40:06 +00:00
chore(web): refactor react code
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
import { IconButton, Tooltip } from '@mui/material'
|
||||
import { Add } from '@mui/icons-material'
|
||||
import { RegisterPermissionPayload } from '../../../../utils/types'
|
||||
import AddPermissionModal from './addPermissionModal'
|
||||
|
||||
type Props = {
|
||||
openModal: boolean
|
||||
setOpenModal: React.Dispatch<React.SetStateAction<boolean>>
|
||||
addPermission: (
|
||||
permissionsToAdd: RegisterPermissionPayload[],
|
||||
permissionType: string,
|
||||
principalType: string,
|
||||
principal: string,
|
||||
permissionSetting: string
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
const AddPermission = ({ openModal, setOpenModal, addPermission }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<Tooltip
|
||||
sx={{ marginLeft: 'auto' }}
|
||||
title="Add Permission"
|
||||
placement="bottom-end"
|
||||
>
|
||||
<IconButton onClick={() => setOpenModal(true)}>
|
||||
<Add />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<AddPermissionModal
|
||||
open={openModal}
|
||||
handleOpen={setOpenModal}
|
||||
addPermission={addPermission}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AddPermission
|
||||
@@ -0,0 +1,245 @@
|
||||
import React, { useState, useEffect, Dispatch, SetStateAction } from 'react'
|
||||
import axios from 'axios'
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
TextField,
|
||||
CircularProgress,
|
||||
Autocomplete
|
||||
} from '@mui/material'
|
||||
|
||||
import { BootstrapDialog } from '../../../../components/modal'
|
||||
import { BootstrapDialogTitle } from '../../../../components/dialogTitle'
|
||||
|
||||
import {
|
||||
UserResponse,
|
||||
GroupResponse,
|
||||
RegisterPermissionPayload
|
||||
} from '../../../../utils/types'
|
||||
|
||||
type AddPermissionModalProps = {
|
||||
open: boolean
|
||||
handleOpen: Dispatch<SetStateAction<boolean>>
|
||||
addPermission: (
|
||||
permissions: RegisterPermissionPayload[],
|
||||
permissionType: string,
|
||||
principalType: string,
|
||||
principal: string,
|
||||
permissionSetting: string
|
||||
) => void
|
||||
}
|
||||
|
||||
const AddPermissionModal = ({
|
||||
open,
|
||||
handleOpen,
|
||||
addPermission
|
||||
}: AddPermissionModalProps) => {
|
||||
const [paths, setPaths] = useState<string[]>([])
|
||||
const [loadingPaths, setLoadingPaths] = useState(false)
|
||||
const [selectedPaths, setSelectedPaths] = useState<string[]>([])
|
||||
const [permissionType, setPermissionType] = useState('Route')
|
||||
const [principalType, setPrincipalType] = useState('Group')
|
||||
const [userPrincipal, setUserPrincipal] = useState<UserResponse>()
|
||||
const [groupPrincipal, setGroupPrincipal] = useState<GroupResponse>()
|
||||
const [permissionSetting, setPermissionSetting] = useState('Grant')
|
||||
const [loadingPrincipals, setLoadingPrincipals] = useState(false)
|
||||
const [userPrincipals, setUserPrincipals] = useState<UserResponse[]>([])
|
||||
const [groupPrincipals, setGroupPrincipals] = useState<GroupResponse[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
setLoadingPaths(true)
|
||||
axios
|
||||
.get('/SASjsApi/info/authorizedRoutes')
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
setPaths(res.data.paths)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoadingPaths(false)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
setLoadingPrincipals(true)
|
||||
axios
|
||||
.get(`/SASjsApi/${principalType.toLowerCase()}`)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
if (principalType.toLowerCase() === 'user') {
|
||||
const users: UserResponse[] = res.data
|
||||
const nonAdminUsers = users.filter((user) => !user.isAdmin)
|
||||
setUserPrincipals(nonAdminUsers)
|
||||
} else {
|
||||
setGroupPrincipals(res.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoadingPrincipals(false)
|
||||
})
|
||||
}, [principalType])
|
||||
|
||||
const handleAddPermission = () => {
|
||||
const permissions: RegisterPermissionPayload[] = []
|
||||
|
||||
selectedPaths.forEach((path) => {
|
||||
const addPermissionPayload: any = {
|
||||
path,
|
||||
type: permissionType,
|
||||
setting: permissionSetting,
|
||||
principalType: principalType.toLowerCase(),
|
||||
principalId:
|
||||
principalType.toLowerCase() === 'user'
|
||||
? userPrincipal?.id
|
||||
: groupPrincipal?.groupId
|
||||
}
|
||||
|
||||
permissions.push(addPermissionPayload)
|
||||
})
|
||||
|
||||
const principal =
|
||||
principalType.toLowerCase() === 'user'
|
||||
? userPrincipal?.username
|
||||
: groupPrincipal?.name
|
||||
|
||||
addPermission(
|
||||
permissions,
|
||||
permissionType,
|
||||
principalType,
|
||||
principal!,
|
||||
permissionSetting
|
||||
)
|
||||
}
|
||||
|
||||
const addButtonDisabled =
|
||||
!selectedPaths.length ||
|
||||
(principalType.toLowerCase() === 'user' ? !userPrincipal : !groupPrincipal)
|
||||
|
||||
return (
|
||||
<BootstrapDialog onClose={() => handleOpen(false)} open={open}>
|
||||
<BootstrapDialogTitle
|
||||
id="add-permission-dialog-title"
|
||||
handleOpen={handleOpen}
|
||||
>
|
||||
Add Permission
|
||||
</BootstrapDialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
multiple
|
||||
disableClearable
|
||||
options={paths}
|
||||
filterSelectedOptions
|
||||
value={selectedPaths}
|
||||
onChange={(event: any, newValue: string[]) => {
|
||||
setSelectedPaths(newValue)
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} label="Paths" />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
options={['Route']}
|
||||
disableClearable
|
||||
value={permissionType}
|
||||
onChange={(event: any, newValue: string) =>
|
||||
setPermissionType(newValue)
|
||||
}
|
||||
renderInput={(params) =>
|
||||
loadingPaths ? (
|
||||
<CircularProgress />
|
||||
) : (
|
||||
<TextField {...params} label="Permission Type" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
options={['Group', 'User']}
|
||||
disableClearable
|
||||
value={principalType}
|
||||
onChange={(event: any, newValue: string) =>
|
||||
setPrincipalType(newValue)
|
||||
}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Principal Type" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{principalType.toLowerCase() === 'user' ? (
|
||||
<Autocomplete
|
||||
options={userPrincipals}
|
||||
getOptionLabel={(option) => option.displayName}
|
||||
disableClearable
|
||||
value={userPrincipal}
|
||||
onChange={(event: any, newValue: UserResponse) =>
|
||||
setUserPrincipal(newValue)
|
||||
}
|
||||
renderInput={(params) =>
|
||||
loadingPrincipals ? (
|
||||
<CircularProgress />
|
||||
) : (
|
||||
<TextField {...params} label="Principal" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Autocomplete
|
||||
options={groupPrincipals}
|
||||
getOptionLabel={(option) => option.name}
|
||||
disableClearable
|
||||
value={groupPrincipal}
|
||||
onChange={(event: any, newValue: GroupResponse) =>
|
||||
setGroupPrincipal(newValue)
|
||||
}
|
||||
renderInput={(params) =>
|
||||
loadingPrincipals ? (
|
||||
<CircularProgress />
|
||||
) : (
|
||||
<TextField {...params} label="Principal" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
options={['Grant', 'Deny']}
|
||||
disableClearable
|
||||
value={permissionSetting}
|
||||
onChange={(event: any, newValue: string) =>
|
||||
setPermissionSetting(newValue)
|
||||
}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Settings" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleAddPermission}
|
||||
disabled={addButtonDisabled}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</BootstrapDialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default AddPermissionModal
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useState } from 'react'
|
||||
import { Typography, Popover } from '@mui/material'
|
||||
import { GroupDetailsResponse } from '../../../../utils/types'
|
||||
|
||||
type DisplayGroupProps = {
|
||||
group: GroupDetailsResponse
|
||||
}
|
||||
|
||||
const DisplayGroup = ({ group }: DisplayGroupProps) => {
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)
|
||||
|
||||
const handlePopoverOpen = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
}
|
||||
|
||||
const handlePopoverClose = () => {
|
||||
setAnchorEl(null)
|
||||
}
|
||||
|
||||
const open = Boolean(anchorEl)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography
|
||||
aria-owns={open ? 'mouse-over-popover' : undefined}
|
||||
aria-haspopup="true"
|
||||
onMouseEnter={handlePopoverOpen}
|
||||
onMouseLeave={handlePopoverClose}
|
||||
>
|
||||
{group.name}
|
||||
</Typography>
|
||||
<Popover
|
||||
id="mouse-over-popover"
|
||||
sx={{
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'left'
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'left'
|
||||
}}
|
||||
onClose={handlePopoverClose}
|
||||
disableRestoreFocus
|
||||
>
|
||||
<Typography sx={{ p: 1 }} variant="h6" component="div">
|
||||
Group Members
|
||||
</Typography>
|
||||
{group.users.map((user, index) => (
|
||||
<Typography key={index} sx={{ p: 1 }} component="li">
|
||||
{user.username}
|
||||
</Typography>
|
||||
))}
|
||||
</Popover>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DisplayGroup
|
||||
@@ -0,0 +1,72 @@
|
||||
import React, { Dispatch, SetStateAction, useState } from 'react'
|
||||
import { IconButton, Tooltip } from '@mui/material'
|
||||
import { FilterList } from '@mui/icons-material'
|
||||
import { PermissionResponse } from '../../../../utils/types'
|
||||
import PermissionFilterModal from './permissionFilterModal'
|
||||
import { PrincipalType } from '../hooks/usePermission'
|
||||
|
||||
type Props = {
|
||||
open: boolean
|
||||
handleOpen: Dispatch<SetStateAction<boolean>>
|
||||
permissions: PermissionResponse[]
|
||||
applyFilter: (
|
||||
pathFilter: string[],
|
||||
principalFilter: string[],
|
||||
principalTypeFilter: PrincipalType[],
|
||||
settingFilter: string[]
|
||||
) => void
|
||||
resetFilter: () => void
|
||||
}
|
||||
|
||||
const FilterPermissions = ({
|
||||
open,
|
||||
handleOpen,
|
||||
permissions,
|
||||
applyFilter,
|
||||
resetFilter
|
||||
}: Props) => {
|
||||
const [pathFilter, setPathFilter] = useState<string[]>([])
|
||||
const [principalFilter, setPrincipalFilter] = useState<string[]>([])
|
||||
const [principalTypeFilter, setPrincipalTypeFilter] = useState<
|
||||
PrincipalType[]
|
||||
>([])
|
||||
const [settingFilter, setSettingFilter] = useState<string[]>([])
|
||||
const handleApplyFilter = () => {
|
||||
applyFilter(pathFilter, principalFilter, principalTypeFilter, settingFilter)
|
||||
}
|
||||
|
||||
const handleResetFilter = () => {
|
||||
setPathFilter([])
|
||||
setPrincipalFilter([])
|
||||
setPrincipalFilter([])
|
||||
setSettingFilter([])
|
||||
resetFilter()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="Filter Permissions">
|
||||
<IconButton onClick={() => handleOpen(true)}>
|
||||
<FilterList />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<PermissionFilterModal
|
||||
open={open}
|
||||
handleOpen={handleOpen}
|
||||
permissions={permissions}
|
||||
pathFilter={pathFilter}
|
||||
setPathFilter={setPathFilter}
|
||||
principalFilter={principalFilter}
|
||||
setPrincipalFilter={setPrincipalFilter}
|
||||
principalTypeFilter={principalTypeFilter}
|
||||
setPrincipalTypeFilter={setPrincipalTypeFilter}
|
||||
settingFilter={settingFilter}
|
||||
setSettingFilter={setSettingFilter}
|
||||
applyFilter={handleApplyFilter}
|
||||
resetFilter={handleResetFilter}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FilterPermissions
|
||||
@@ -0,0 +1,154 @@
|
||||
import React, { Dispatch, SetStateAction } from 'react'
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
TextField
|
||||
} from '@mui/material'
|
||||
import { styled } from '@mui/material/styles'
|
||||
import Autocomplete from '@mui/material/Autocomplete'
|
||||
|
||||
import { PermissionResponse } from '../../../../utils/types'
|
||||
import { BootstrapDialogTitle } from '../../../../components/dialogTitle'
|
||||
import { PrincipalType } from '../hooks/usePermission'
|
||||
|
||||
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
|
||||
'& .MuiDialogContent-root': {
|
||||
padding: theme.spacing(2)
|
||||
},
|
||||
'& .MuiDialogActions-root': {
|
||||
padding: theme.spacing(1)
|
||||
}
|
||||
}))
|
||||
|
||||
type FilterModalProps = {
|
||||
open: boolean
|
||||
handleOpen: Dispatch<SetStateAction<boolean>>
|
||||
permissions: PermissionResponse[]
|
||||
pathFilter: string[]
|
||||
setPathFilter: Dispatch<SetStateAction<string[]>>
|
||||
principalFilter: string[]
|
||||
setPrincipalFilter: Dispatch<SetStateAction<string[]>>
|
||||
principalTypeFilter: PrincipalType[]
|
||||
setPrincipalTypeFilter: Dispatch<SetStateAction<PrincipalType[]>>
|
||||
settingFilter: string[]
|
||||
setSettingFilter: Dispatch<SetStateAction<string[]>>
|
||||
applyFilter: () => void
|
||||
resetFilter: () => void
|
||||
}
|
||||
|
||||
const PermissionFilterModal = ({
|
||||
open,
|
||||
handleOpen,
|
||||
permissions,
|
||||
pathFilter,
|
||||
setPathFilter,
|
||||
principalFilter,
|
||||
setPrincipalFilter,
|
||||
principalTypeFilter,
|
||||
setPrincipalTypeFilter,
|
||||
settingFilter,
|
||||
setSettingFilter,
|
||||
applyFilter,
|
||||
resetFilter
|
||||
}: FilterModalProps) => {
|
||||
const paths = permissions
|
||||
.map((permission) => permission.path)
|
||||
.filter((uri, index, array) => array.indexOf(uri) === index)
|
||||
|
||||
// fetch all the principals from permissions array
|
||||
let principals = permissions.map((permission) => {
|
||||
if (permission.user) return permission.user.username
|
||||
if (permission.group) return permission.group.name
|
||||
return ''
|
||||
})
|
||||
|
||||
// removes empty strings
|
||||
principals = principals.filter((principal) => principal !== '')
|
||||
|
||||
// removes the duplicates
|
||||
principals = principals.filter(
|
||||
(principal, index, array) => array.indexOf(principal) === index
|
||||
)
|
||||
|
||||
return (
|
||||
<BootstrapDialog onClose={() => handleOpen(false)} open={open}>
|
||||
<BootstrapDialogTitle
|
||||
id="permission-filter-dialog-title"
|
||||
handleOpen={handleOpen}
|
||||
>
|
||||
Permission Filter
|
||||
</BootstrapDialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={paths}
|
||||
filterSelectedOptions
|
||||
value={pathFilter}
|
||||
onChange={(event: any, newValue: string[]) => {
|
||||
setPathFilter(newValue)
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} label="Paths" />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={principals}
|
||||
filterSelectedOptions
|
||||
value={principalFilter}
|
||||
onChange={(event: any, newValue: string[]) => {
|
||||
setPrincipalFilter(newValue)
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Principals" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={Object.values(PrincipalType)}
|
||||
filterSelectedOptions
|
||||
value={principalTypeFilter}
|
||||
onChange={(event: any, newValue: PrincipalType[]) => {
|
||||
setPrincipalTypeFilter(newValue)
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Principal Type" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={['Grant', 'Deny']}
|
||||
filterSelectedOptions
|
||||
value={settingFilter}
|
||||
onChange={(event: any, newValue: string[]) => {
|
||||
setSettingFilter(newValue)
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Settings" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="outlined" color="error" onClick={resetFilter}>
|
||||
Reset
|
||||
</Button>
|
||||
<Button variant="outlined" onClick={applyFilter}>
|
||||
Apply
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</BootstrapDialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default PermissionFilterModal
|
||||
@@ -0,0 +1,120 @@
|
||||
import React from 'react'
|
||||
|
||||
import { Typography, DialogContent } from '@mui/material'
|
||||
|
||||
import { BootstrapDialog } from '../../../../components/modal'
|
||||
import { BootstrapDialogTitle } from '../../../../components/dialogTitle'
|
||||
import { PermissionResponse } from '../../../../utils/types'
|
||||
|
||||
export interface PermissionResponsePayload {
|
||||
permissionType: string
|
||||
principalType: string
|
||||
principal: string
|
||||
permissionSetting: string
|
||||
existingPermissions: PermissionResponse[]
|
||||
newAddedPermissions: PermissionResponse[]
|
||||
updatedPermissions: PermissionResponse[]
|
||||
errorPaths: string[]
|
||||
}
|
||||
|
||||
type Props = {
|
||||
open: boolean
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||
payload: PermissionResponsePayload
|
||||
}
|
||||
|
||||
const PermissionResponseModal = ({ open, setOpen, payload }: Props) => {
|
||||
const newAddedPermissionsLength = payload.newAddedPermissions.length
|
||||
const updatedPermissionsLength = payload.updatedPermissions.length
|
||||
const existingPermissionsLength = payload.existingPermissions.length
|
||||
const appliedPermissionsLength =
|
||||
newAddedPermissionsLength + updatedPermissionsLength
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapDialog onClose={() => setOpen(false)} open={open}>
|
||||
<BootstrapDialogTitle
|
||||
id="permission-response-modal"
|
||||
handleOpen={setOpen}
|
||||
>
|
||||
Permission Response
|
||||
</BootstrapDialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography sx={{ fontWeight: 'bold', marginBottom: '15px' }}>
|
||||
{`${appliedPermissionsLength} "${payload.permissionSetting}", "${
|
||||
payload.permissionType
|
||||
}", "${payload.principalType}", "${payload.principal}" ${
|
||||
appliedPermissionsLength > 1 ? 'Rules' : 'Rule'
|
||||
}`}{' '}
|
||||
Applied:
|
||||
</Typography>
|
||||
|
||||
{newAddedPermissionsLength > 0 && (
|
||||
<>
|
||||
<Typography>
|
||||
{`${newAddedPermissionsLength} ${
|
||||
newAddedPermissionsLength > 1 ? 'Rules' : 'Rule'
|
||||
}`}{' '}
|
||||
Added:
|
||||
</Typography>
|
||||
<ul>
|
||||
{payload.newAddedPermissions.map((permission, index) => (
|
||||
<li key={index}>{permission.path}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
|
||||
{updatedPermissionsLength > 0 && (
|
||||
<>
|
||||
<Typography>
|
||||
{` ${updatedPermissionsLength} ${
|
||||
updatedPermissionsLength > 1 ? 'Rules' : 'Rule'
|
||||
}`}{' '}
|
||||
Updated:
|
||||
</Typography>
|
||||
<ul>
|
||||
{payload.updatedPermissions.map((permission, index) => (
|
||||
<li key={index}>{permission.path}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
|
||||
{existingPermissionsLength > 0 && (
|
||||
<>
|
||||
<Typography>
|
||||
{`${existingPermissionsLength} ${
|
||||
existingPermissionsLength > 1 ? 'Rules' : 'Rule'
|
||||
}`}{' '}
|
||||
Unchanged:
|
||||
</Typography>
|
||||
<ul>
|
||||
{payload.existingPermissions.map((permission, index) => (
|
||||
<li key={index}>{permission.path}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
|
||||
{payload.errorPaths.length > 0 && (
|
||||
<>
|
||||
<Typography style={{ color: 'red', marginTop: '10px' }}>
|
||||
Errors occurred for following paths:
|
||||
</Typography>
|
||||
<ul>
|
||||
{payload.errorPaths.map((path, index) => (
|
||||
<li key={index}>
|
||||
<Typography>{path}</Typography>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</DialogContent>
|
||||
</BootstrapDialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PermissionResponseModal
|
||||
@@ -0,0 +1,101 @@
|
||||
import { useContext } from 'react'
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Paper,
|
||||
IconButton,
|
||||
Tooltip
|
||||
} from '@mui/material'
|
||||
|
||||
import EditIcon from '@mui/icons-material/Edit'
|
||||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'
|
||||
|
||||
import { styled } from '@mui/material/styles'
|
||||
|
||||
import { PermissionResponse } from '../../../../utils/types'
|
||||
|
||||
import { AppContext } from '../../../../context/appContext'
|
||||
import { displayPrincipal, displayPrincipalType } from '../helper'
|
||||
|
||||
const BootstrapTableCell = styled(TableCell)({
|
||||
textAlign: 'left'
|
||||
})
|
||||
|
||||
export enum PrincipalType {
|
||||
User = 'User',
|
||||
Group = 'Group'
|
||||
}
|
||||
|
||||
type PermissionTableProps = {
|
||||
permissions: PermissionResponse[]
|
||||
handleUpdatePermissionClick: (permission: PermissionResponse) => void
|
||||
handleDeletePermissionClick: (permission: PermissionResponse) => void
|
||||
}
|
||||
|
||||
const PermissionTable = ({
|
||||
permissions,
|
||||
handleUpdatePermissionClick,
|
||||
handleDeletePermissionClick
|
||||
}: PermissionTableProps) => {
|
||||
const appContext = useContext(AppContext)
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table sx={{ minWidth: 650 }}>
|
||||
<TableHead sx={{ background: 'rgb(0,0,0, 0.3)' }}>
|
||||
<TableRow>
|
||||
<BootstrapTableCell>Path</BootstrapTableCell>
|
||||
<BootstrapTableCell>Permission Type</BootstrapTableCell>
|
||||
<BootstrapTableCell>Principal</BootstrapTableCell>
|
||||
<BootstrapTableCell>Principal Type</BootstrapTableCell>
|
||||
<BootstrapTableCell>Setting</BootstrapTableCell>
|
||||
{appContext.isAdmin && (
|
||||
<BootstrapTableCell>Action</BootstrapTableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{permissions.map((permission) => (
|
||||
<TableRow key={permission.permissionId}>
|
||||
<BootstrapTableCell>{permission.path}</BootstrapTableCell>
|
||||
<BootstrapTableCell>{permission.type}</BootstrapTableCell>
|
||||
<BootstrapTableCell>
|
||||
{displayPrincipal(permission)}
|
||||
</BootstrapTableCell>
|
||||
<BootstrapTableCell>
|
||||
{displayPrincipalType(permission)}
|
||||
</BootstrapTableCell>
|
||||
<BootstrapTableCell>{permission.setting}</BootstrapTableCell>
|
||||
{appContext.isAdmin && (
|
||||
<BootstrapTableCell>
|
||||
<Tooltip title="Edit Permission">
|
||||
<IconButton
|
||||
onClick={() => handleUpdatePermissionClick(permission)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete Permission">
|
||||
<IconButton
|
||||
color="error"
|
||||
onClick={() => handleDeletePermissionClick(permission)}
|
||||
>
|
||||
<DeleteForeverIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</BootstrapTableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default PermissionTable
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { useState, Dispatch, SetStateAction, useEffect } from 'react'
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
TextField
|
||||
} from '@mui/material'
|
||||
|
||||
import Autocomplete from '@mui/material/Autocomplete'
|
||||
|
||||
import { BootstrapDialog } from '../../../../components/modal'
|
||||
import { BootstrapDialogTitle } from '../../../../components/dialogTitle'
|
||||
|
||||
import { PermissionResponse } from '../../../../utils/types'
|
||||
|
||||
type UpdatePermissionModalProps = {
|
||||
open: boolean
|
||||
handleOpen: Dispatch<SetStateAction<boolean>>
|
||||
permission: PermissionResponse | undefined
|
||||
updatePermission: (setting: string) => void
|
||||
}
|
||||
|
||||
const UpdatePermissionModal = ({
|
||||
open,
|
||||
handleOpen,
|
||||
permission,
|
||||
updatePermission
|
||||
}: UpdatePermissionModalProps) => {
|
||||
const [permissionSetting, setPermissionSetting] = useState('Grant')
|
||||
|
||||
useEffect(() => {
|
||||
if (permission) setPermissionSetting(permission.setting)
|
||||
}, [permission])
|
||||
|
||||
return (
|
||||
<BootstrapDialog onClose={() => handleOpen(false)} open={open}>
|
||||
<BootstrapDialogTitle
|
||||
id="add-permission-dialog-title"
|
||||
handleOpen={handleOpen}
|
||||
>
|
||||
Update Permission
|
||||
</BootstrapDialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Autocomplete
|
||||
sx={{ width: 300 }}
|
||||
options={['Grant', 'Deny']}
|
||||
disableClearable
|
||||
value={permissionSetting}
|
||||
onChange={(event: any, newValue: string) =>
|
||||
setPermissionSetting(newValue)
|
||||
}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Settings" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => updatePermission(permissionSetting)}
|
||||
disabled={permission?.setting === permissionSetting}
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</BootstrapDialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default UpdatePermissionModal
|
||||
Reference in New Issue
Block a user