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

feat: add, remove and update permissions from web component

This commit is contained in:
2022-06-24 14:48:57 +05:00
parent 5b319f9ad1
commit 97ecfdc955
7 changed files with 233 additions and 30 deletions

View File

@@ -535,6 +535,24 @@ components:
- setting - setting
type: object type: object
additionalProperties: false additionalProperties: false
SessionResponse:
properties:
id:
type: number
format: double
username:
type: string
displayName:
type: string
isAdmin:
type: boolean
required:
- id
- username
- displayName
- isAdmin
type: object
additionalProperties: false
ExecuteReturnJsonPayload: ExecuteReturnJsonPayload:
properties: properties:
_program: _program:
@@ -638,7 +656,7 @@ paths:
application/json: application/json:
schema: schema:
properties: properties:
user: {properties: {displayName: {type: string}, username: {type: string}, id: {type: number, format: double}}, required: [displayName, username, id], type: object} user: {properties: {isAdmin: {type: boolean}, displayName: {type: string}, username: {type: string}, id: {type: number, format: double}}, required: [isAdmin, displayName, username, id], type: object}
loggedIn: {type: boolean} loggedIn: {type: boolean}
required: required:
- user - user
@@ -1589,10 +1607,10 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/UserResponse' $ref: '#/components/schemas/SessionResponse'
examples: examples:
'Example 1': 'Example 1':
value: {id: 123, username: johnusername, displayName: John} value: {id: 123, username: johnusername, displayName: John, isAdmin: false}
summary: 'Get session info (username).' summary: 'Get session info (username).'
tags: tags:
- Session - Session

View File

@@ -0,0 +1,43 @@
import React from 'react'
import { Typography, Dialog, DialogContent } from '@mui/material'
import { styled } from '@mui/material/styles'
import { BootstrapDialogTitle } from './dialogTitle'
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2)
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1)
}
}))
export interface ModalProps {
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
title: string
payload: string
}
const Modal = (props: ModalProps) => {
const { open, setOpen, title, payload } = props
return (
<div>
<BootstrapDialog onClose={() => setOpen(false)} open={open}>
<BootstrapDialogTitle id="abort-modal" handleOpen={setOpen}>
{title}
</BootstrapDialogTitle>
<DialogContent dividers>
<Typography gutterBottom>
<span style={{ fontFamily: 'monospace' }}>{payload}</span>
</Typography>
</DialogContent>
</BootstrapDialog>
</div>
)
}
export default Modal

View File

@@ -93,7 +93,9 @@ const AddPermissionModal = ({
} }
const URIs = useMemo(() => { const URIs = useMemo(() => {
return permissions.map((permission) => permission.uri) return permissions
.map((permission) => permission.uri)
.filter((uri, index, array) => array.indexOf(uri) === index)
}, [permissions]) }, [permissions])
const addButtonDisabled = const addButtonDisabled =

View File

@@ -0,0 +1,44 @@
import React from 'react'
import {
Button,
Dialog,
DialogContent,
DialogActions,
Typography
} from '@mui/material'
import { styled } from '@mui/material/styles'
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2)
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1)
}
}))
type DeleteModalProps = {
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
deletePermission: () => void
}
const DeleteModal = ({ open, setOpen, deletePermission }: DeleteModalProps) => {
return (
<BootstrapDialog onClose={() => setOpen(false)} open={open}>
<DialogContent dividers>
<Typography gutterBottom>
Are you sure to delete this permission?
</Typography>
</DialogContent>
<DialogActions>
<Button color="error" onClick={() => deletePermission()}>
Delete
</Button>
</DialogActions>
</BootstrapDialog>
)
}
export default DeleteModal

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useContext } from 'react' import React, { useState, useEffect, useContext, useCallback } from 'react'
import axios from 'axios' import axios from 'axios'
import { import {
Box, Box,
@@ -22,11 +22,16 @@ import DeleteForeverIcon from '@mui/icons-material/DeleteForever'
import { styled } from '@mui/material/styles' import { styled } from '@mui/material/styles'
import Modal from '../../components/modal'
import PermissionFilterModal from './permissionFilterModal' import PermissionFilterModal from './permissionFilterModal'
import AddPermissionModal from './addPermissionModal' import AddPermissionModal from './addPermissionModal'
import UpdatePermissionModal from './updatePermissionModal' import UpdatePermissionModal from './updatePermissionModal'
import DeleteModal from './deletePermissionModal'
import { PermissionResponse } from '../../utils/types' import {
PermissionResponse,
RegisterPermissionPayload
} from '../../utils/types'
import { AppContext } from '../../context/appContext' import { AppContext } from '../../context/appContext'
const BootstrapTableCell = styled(TableCell)({ const BootstrapTableCell = styled(TableCell)({
@@ -36,10 +41,14 @@ const BootstrapTableCell = styled(TableCell)({
const Permission = () => { const Permission = () => {
const appContext = useContext(AppContext) const appContext = useContext(AppContext)
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [openModal, setOpenModal] = useState(false)
const [modalTitle, setModalTitle] = useState('')
const [modalPayload, setModalPayload] = useState('')
const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false) const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false)
const [updatePermissionModalOpen, setUpdatePermissionModalOpen] = const [updatePermissionModalOpen, setUpdatePermissionModalOpen] =
useState(false) useState(false)
const [selectedPermissionForUpdate, setSelectedPermissionForUpdate] = const [deleteModalOpen, setDeleteModalOpen] = useState(false)
const [selectedPermission, setSelectedPermission] =
useState<PermissionResponse>() useState<PermissionResponse>()
const [filterModalOpen, setFilterModalOpen] = useState(false) const [filterModalOpen, setFilterModalOpen] = useState(false)
const [uriFilter, setUriFilter] = useState<string[]>([]) const [uriFilter, setUriFilter] = useState<string[]>([])
@@ -51,8 +60,7 @@ const Permission = () => {
>([]) >([])
const [filterApplied, setFilterApplied] = useState(false) const [filterApplied, setFilterApplied] = useState(false)
useEffect(() => { const fetchPermissions = useCallback(() => {
setIsLoading(true)
axios axios
.get(`/SASjsApi/permission`) .get(`/SASjsApi/permission`)
.then((res: any) => { .then((res: any) => {
@@ -61,13 +69,16 @@ const Permission = () => {
} }
}) })
.catch((err) => { .catch((err) => {
console.log(err) setModalTitle('Abort')
}) setModalPayload(typeof err === 'object' ? err.toSting() : err)
.finally(() => { setOpenModal(true)
setIsLoading(false)
}) })
}, []) }, [])
useEffect(() => {
fetchPermissions()
}, [fetchPermissions])
/** /**
* first find the permissions w.r.t each filter type * first find the permissions w.r.t each filter type
* take intersection of resultant arrays * take intersection of resultant arrays
@@ -119,14 +130,82 @@ const Permission = () => {
setFilterApplied(false) setFilterApplied(false)
} }
const addPermission = () => {} const addPermission = (addPermissionPayload: RegisterPermissionPayload) => {
setAddPermissionModalOpen(false)
setIsLoading(true)
axios
.post('/SASjsApi/permission', addPermissionPayload)
.then((res: any) => {
fetchPermissions()
setModalTitle('Success')
setModalPayload('Permission added Successfully.')
setOpenModal(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(typeof err === 'object' ? err.toSting() : err)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
})
}
const handleUpdatePermissionClick = (permission: PermissionResponse) => { const handleUpdatePermissionClick = (permission: PermissionResponse) => {
setSelectedPermissionForUpdate(permission) setSelectedPermission(permission)
setUpdatePermissionModalOpen(true) setUpdatePermissionModalOpen(true)
} }
const updatePermission = () => {} const updatePermission = (setting: string) => {
setUpdatePermissionModalOpen(false)
setIsLoading(true)
axios
.patch(`/SASjsApi/permission/${selectedPermission?.permissionId}`, {
setting
})
.then((res: any) => {
fetchPermissions()
setModalTitle('Success')
setModalPayload('Permission updated Successfully.')
setOpenModal(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(typeof err === 'object' ? err.toSting() : err)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
setSelectedPermission(undefined)
})
}
const handleDeletePermissionClick = (permission: PermissionResponse) => {
setSelectedPermission(permission)
setDeleteModalOpen(true)
}
const deletePermission = () => {
setDeleteModalOpen(false)
setIsLoading(true)
axios
.delete(`/SASjsApi/permission/${selectedPermission?.permissionId}`)
.then((res: any) => {
fetchPermissions()
setModalTitle('Success')
setModalPayload('Permission deleted Successfully.')
setOpenModal(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(typeof err === 'object' ? err.toSting() : err)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
setSelectedPermission(undefined)
})
}
return isLoading ? ( return isLoading ? (
<CircularProgress <CircularProgress
@@ -159,9 +238,16 @@ const Permission = () => {
<PermissionTable <PermissionTable
permissions={filterApplied ? filteredPermissions : permissions} permissions={filterApplied ? filteredPermissions : permissions}
handleUpdatePermissionClick={handleUpdatePermissionClick} handleUpdatePermissionClick={handleUpdatePermissionClick}
handleDeletePermissionClick={handleDeletePermissionClick}
/> />
</Grid> </Grid>
</Grid> </Grid>
<Modal
open={openModal}
setOpen={setOpenModal}
title={modalTitle}
payload={modalPayload}
/>
<PermissionFilterModal <PermissionFilterModal
open={filterModalOpen} open={filterModalOpen}
handleOpen={setFilterModalOpen} handleOpen={setFilterModalOpen}
@@ -181,14 +267,17 @@ const Permission = () => {
permissions={permissions} permissions={permissions}
addPermission={addPermission} addPermission={addPermission}
/> />
{selectedPermissionForUpdate && ( <UpdatePermissionModal
<UpdatePermissionModal open={updatePermissionModalOpen}
open={updatePermissionModalOpen} handleOpen={setUpdatePermissionModalOpen}
handleOpen={setUpdatePermissionModalOpen} permission={selectedPermission}
permission={selectedPermissionForUpdate} updatePermission={updatePermission}
updatePermission={updatePermission} />
/> <DeleteModal
)} open={deleteModalOpen}
setOpen={setDeleteModalOpen}
deletePermission={deletePermission}
/>
</Box> </Box>
) )
} }
@@ -198,11 +287,13 @@ export default Permission
type PermissionTableProps = { type PermissionTableProps = {
permissions: PermissionResponse[] permissions: PermissionResponse[]
handleUpdatePermissionClick: (permission: PermissionResponse) => void handleUpdatePermissionClick: (permission: PermissionResponse) => void
handleDeletePermissionClick: (permission: PermissionResponse) => void
} }
const PermissionTable = ({ const PermissionTable = ({
permissions, permissions,
handleUpdatePermissionClick handleUpdatePermissionClick,
handleDeletePermissionClick
}: PermissionTableProps) => { }: PermissionTableProps) => {
const appContext = useContext(AppContext) const appContext = useContext(AppContext)
@@ -237,7 +328,10 @@ const PermissionTable = ({
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Delete Permission"> <Tooltip title="Delete Permission">
<IconButton color="error"> <IconButton
color="error"
onClick={() => handleDeletePermissionClick(permission)}
>
<DeleteForeverIcon /> <DeleteForeverIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>

View File

@@ -48,7 +48,9 @@ const PermissionFilterModal = ({
applyFilter, applyFilter,
resetFilter resetFilter
}: FilterModalProps) => { }: FilterModalProps) => {
const URIs = permissions.map((permission) => permission.uri) const URIs = permissions
.map((permission) => permission.uri)
.filter((uri, index, array) => array.indexOf(uri) === index)
// fetch all the principals from permissions array // fetch all the principals from permissions array
let principals = permissions.map((permission) => { let principals = permissions.map((permission) => {
@@ -62,7 +64,7 @@ const PermissionFilterModal = ({
// removes the duplicates // removes the duplicates
principals = principals.filter( principals = principals.filter(
(value, index, self) => self.indexOf(value) === index (principal, index, array) => array.indexOf(principal) === index
) )
return ( return (

View File

@@ -26,7 +26,7 @@ const BootstrapDialog = styled(Dialog)(({ theme }) => ({
type UpdatePermissionModalProps = { type UpdatePermissionModalProps = {
open: boolean open: boolean
handleOpen: Dispatch<SetStateAction<boolean>> handleOpen: Dispatch<SetStateAction<boolean>>
permission: PermissionResponse permission: PermissionResponse | undefined
updatePermission: (setting: string) => void updatePermission: (setting: string) => void
} }
@@ -68,7 +68,7 @@ const UpdatePermissionModal = ({
<Button <Button
variant="outlined" variant="outlined"
onClick={() => updatePermission(permissionSetting)} onClick={() => updatePermission(permissionSetting)}
disabled={permission.setting === permissionSetting} disabled={permission?.setting === permissionSetting}
> >
Update Update
</Button> </Button>