1
0
mirror of https://github.com/sasjs/server.git synced 2026-01-13 00:50:06 +00:00

chore(web): refactor react code

This commit is contained in:
2022-09-08 21:49:35 +05:00
parent d6651bbdbe
commit 4560ef942f
26 changed files with 1534 additions and 1127 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,13 @@
import { PermissionResponse } from '../../../utils/types'
import { PrincipalType } from './hooks/usePermission'
import DisplayGroup from './components/displayGroup'
export const displayPrincipal = (permission: PermissionResponse) => {
if (permission.user) return permission.user.username
if (permission.group) return <DisplayGroup group={permission.group} />
}
export const displayPrincipalType = (permission: PermissionResponse) => {
if (permission.user) return PrincipalType.User
if (permission.group) return PrincipalType.Group
}

View File

@@ -0,0 +1,109 @@
import axios from 'axios'
import { useState, useContext } from 'react'
import {
PermissionResponse,
RegisterPermissionPayload
} from '../../../../utils/types'
import AddPermission from '../components/addPermission'
import { PermissionsContext } from '../../../../context/permissionsContext'
import {
findExistingPermission,
findUpdatingPermission
} from '../../../../utils/helper'
const useAddPermission = () => {
const {
permissions,
fetchPermissions,
setIsLoading,
setPermissionResponsePayload,
setOpenPermissionResponseModal
} = useContext(PermissionsContext)
const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false)
const addPermission = async (
permissionsToAdd: RegisterPermissionPayload[],
permissionType: string,
principalType: string,
principal: string,
permissionSetting: string
) => {
setAddPermissionModalOpen(false)
setIsLoading(true)
const newAddedPermissions: PermissionResponse[] = []
const updatedPermissions: PermissionResponse[] = []
const errorPaths: string[] = []
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) => {
newAddedPermissions.push(res.data)
})
.catch((error) => {
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({
permissionType,
principalType,
principal,
permissionSetting,
existingPermissions,
updatedPermissions,
newAddedPermissions,
errorPaths
})
setOpenPermissionResponseModal(true)
}
const AddPermissionButton = () => (
<AddPermission
openModal={addPermissionModalOpen}
setOpenModal={setAddPermissionModalOpen}
addPermission={addPermission}
/>
)
return { AddPermissionButton, setAddPermissionModalOpen }
}
export default useAddPermission

View File

@@ -0,0 +1,61 @@
import axios from 'axios'
import { useState, useContext } from 'react'
import { PermissionsContext } from '../../../../context/permissionsContext'
import { AlertSeverityType } from '../../../../components/snackbar'
import DeleteConfirmationModal from '../../../../components/deleteConfirmationModal'
const useDeletePermissionModal = () => {
const {
selectedPermission,
setSelectedPermission,
fetchPermissions,
setIsLoading,
setSnackbarMessage,
setSnackbarSeverity,
setOpenSnackbar,
setModalTitle,
setModalPayload,
setOpenModal
} = useContext(PermissionsContext)
const [deleteConfirmationModalOpen, setDeleteConfirmationModalOpen] =
useState(false)
const deletePermission = () => {
setDeleteConfirmationModalOpen(false)
setIsLoading(true)
axios
.delete(`/SASjsApi/permission/${selectedPermission?.permissionId}`)
.then((res: any) => {
fetchPermissions()
setSnackbarMessage('Permission deleted!')
setSnackbarSeverity(AlertSeverityType.Success)
setOpenSnackbar(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(
typeof err.response.data === 'object'
? JSON.stringify(err.response.data)
: err.response.data
)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
setSelectedPermission(undefined)
})
}
const DeletePermissionDialog = () => (
<DeleteConfirmationModal
open={deleteConfirmationModalOpen}
setOpen={setDeleteConfirmationModalOpen}
message="Are you sure you want to delete this permission?"
_delete={deletePermission}
/>
)
return { DeletePermissionDialog, setDeleteConfirmationModalOpen }
}
export default useDeletePermissionModal

View File

@@ -0,0 +1,105 @@
import { useState, useContext } from 'react'
import { PermissionsContext } from '../../../../context/permissionsContext'
import { PrincipalType } from './usePermission'
import FilterPermissions from '../components/filterPermissions'
const useFilterPermissions = () => {
const { permissions, setFilteredPermissions, setFilterApplied } =
useContext(PermissionsContext)
const [filterModalOpen, setFilterModalOpen] = useState(false)
/**
* first find the permissions w.r.t each filter type
* take intersection of resultant arrays
*/
const applyFilter = (
pathFilter: string[],
principalFilter: string[],
principalTypeFilter: PrincipalType[],
settingFilter: string[]
) => {
setFilterModalOpen(false)
const uriFilteredPermissions =
pathFilter.length > 0
? permissions.filter((permission) =>
pathFilter.includes(permission.path)
)
: permissions
const principalFilteredPermissions =
principalFilter.length > 0
? permissions.filter((permission) => {
if (permission.user) {
return principalFilter.includes(permission.user.username)
}
if (permission.group) {
return principalFilter.includes(permission.group.name)
}
return false
})
: permissions
const principalTypeFilteredPermissions =
principalTypeFilter.length > 0
? permissions.filter((permission) => {
if (permission.user) {
return principalTypeFilter.includes(PrincipalType.User)
}
if (permission.group) {
return principalTypeFilter.includes(PrincipalType.Group)
}
return false
})
: permissions
const settingFilteredPermissions =
settingFilter.length > 0
? permissions.filter((permission) =>
settingFilter.includes(permission.setting)
)
: permissions
let filteredArray = uriFilteredPermissions.filter((permission) =>
principalFilteredPermissions.some(
(item) => item.permissionId === permission.permissionId
)
)
filteredArray = filteredArray.filter((permission) =>
principalTypeFilteredPermissions.some(
(item) => item.permissionId === permission.permissionId
)
)
filteredArray = filteredArray.filter((permission) =>
settingFilteredPermissions.some(
(item) => item.permissionId === permission.permissionId
)
)
setFilteredPermissions(filteredArray)
setFilterApplied(true)
}
const resetFilter = () => {
setFilterModalOpen(false)
setFilterApplied(false)
setFilteredPermissions([])
}
const FilterPermissionsButton = () => (
<FilterPermissions
open={filterModalOpen}
handleOpen={setFilterModalOpen}
permissions={permissions}
applyFilter={applyFilter}
resetFilter={resetFilter}
/>
)
return { FilterPermissionsButton }
}
export default useFilterPermissions

View File

@@ -0,0 +1,71 @@
import { useContext, useEffect } from 'react'
import { AppContext } from '../../../../context/appContext'
import { PermissionsContext } from '../../../../context/permissionsContext'
import { PermissionResponse } from '../../../../utils/types'
import useAddPermission from './useAddPermission'
import useUpdatePermissionModal from './useUpdatePermissionModal'
import useDeletePermissionModal from './useDeletePermissionModal'
import useFilterPermissions from './useFilterPermissions'
export enum PrincipalType {
User = 'User',
Group = 'Group'
}
const usePermission = () => {
const { isAdmin } = useContext(AppContext)
const {
filterApplied,
filteredPermissions,
isLoading,
permissions,
Dialog,
Snackbar,
PermissionResponseDialog,
fetchPermissions,
setSelectedPermission
} = useContext(PermissionsContext)
const { AddPermissionButton } = useAddPermission()
const { UpdatePermissionDialog, setUpdatePermissionModalOpen } =
useUpdatePermissionModal()
const { DeletePermissionDialog, setDeleteConfirmationModalOpen } =
useDeletePermissionModal()
const { FilterPermissionsButton } = useFilterPermissions()
useEffect(() => {
if (fetchPermissions) fetchPermissions()
}, [fetchPermissions])
const handleUpdatePermissionClick = (permission: PermissionResponse) => {
setSelectedPermission(permission)
setUpdatePermissionModalOpen(true)
}
const handleDeletePermissionClick = (permission: PermissionResponse) => {
setSelectedPermission(permission)
setDeleteConfirmationModalOpen(true)
}
return {
filterApplied,
filteredPermissions,
isAdmin,
isLoading,
permissions,
AddPermissionButton,
UpdatePermissionDialog,
DeletePermissionDialog,
FilterPermissionsButton,
handleDeletePermissionClick,
handleUpdatePermissionClick,
PermissionResponseDialog,
Dialog,
Snackbar
}
}
export default usePermission

View File

@@ -0,0 +1,36 @@
import { useState } from 'react'
import PermissionResponseModal, {
PermissionResponsePayload
} from '../components/permissionResponseModal'
const usePermissionResponseModal = () => {
const [openPermissionResponseModal, setOpenPermissionResponseModal] =
useState(false)
const [permissionResponsePayload, setPermissionResponsePayload] =
useState<PermissionResponsePayload>({
permissionType: '',
principalType: '',
principal: '',
permissionSetting: '',
existingPermissions: [],
newAddedPermissions: [],
updatedPermissions: [],
errorPaths: []
})
const PermissionResponseDialog = () => (
<PermissionResponseModal
open={openPermissionResponseModal}
setOpen={setOpenPermissionResponseModal}
payload={permissionResponsePayload}
/>
)
return {
PermissionResponseDialog,
setOpenPermissionResponseModal,
setPermissionResponsePayload
}
}
export default usePermissionResponseModal

View File

@@ -0,0 +1,63 @@
import axios from 'axios'
import { useState, useContext } from 'react'
import UpdatePermissionModal from '../components/updatePermissionModal'
import { PermissionsContext } from '../../../../context/permissionsContext'
import { AlertSeverityType } from '../../../../components/snackbar'
const useUpdatePermissionModal = () => {
const {
selectedPermission,
setSelectedPermission,
fetchPermissions,
setIsLoading,
setSnackbarMessage,
setSnackbarSeverity,
setOpenSnackbar,
setModalTitle,
setModalPayload,
setOpenModal
} = useContext(PermissionsContext)
const [updatePermissionModalOpen, setUpdatePermissionModalOpen] =
useState(false)
const updatePermission = (setting: string) => {
setUpdatePermissionModalOpen(false)
setIsLoading(true)
axios
.patch(`/SASjsApi/permission/${selectedPermission?.permissionId}`, {
setting
})
.then((res: any) => {
fetchPermissions()
setSnackbarMessage('Permission updated!')
setSnackbarSeverity(AlertSeverityType.Success)
setOpenSnackbar(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(
typeof err.response.data === 'object'
? JSON.stringify(err.response.data)
: err.response.data
)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
setSelectedPermission(undefined)
})
}
const UpdatePermissionDialog = () => (
<UpdatePermissionModal
open={updatePermissionModalOpen}
handleOpen={setUpdatePermissionModalOpen}
permission={selectedPermission}
updatePermission={updatePermission}
/>
)
return { UpdatePermissionDialog, setUpdatePermissionModalOpen }
}
export default useUpdatePermissionModal