1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 19:34: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
type: object
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:
properties:
_program:
@@ -638,7 +656,7 @@ paths:
application/json:
schema:
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}
required:
- user
@@ -1589,10 +1607,10 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
$ref: '#/components/schemas/SessionResponse'
examples:
'Example 1':
value: {id: 123, username: johnusername, displayName: John}
value: {id: 123, username: johnusername, displayName: John, isAdmin: false}
summary: 'Get session info (username).'
tags:
- 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(() => {
return permissions.map((permission) => permission.uri)
return permissions
.map((permission) => permission.uri)
.filter((uri, index, array) => array.indexOf(uri) === index)
}, [permissions])
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 {
Box,
@@ -22,11 +22,16 @@ import DeleteForeverIcon from '@mui/icons-material/DeleteForever'
import { styled } from '@mui/material/styles'
import Modal from '../../components/modal'
import PermissionFilterModal from './permissionFilterModal'
import AddPermissionModal from './addPermissionModal'
import UpdatePermissionModal from './updatePermissionModal'
import DeleteModal from './deletePermissionModal'
import { PermissionResponse } from '../../utils/types'
import {
PermissionResponse,
RegisterPermissionPayload
} from '../../utils/types'
import { AppContext } from '../../context/appContext'
const BootstrapTableCell = styled(TableCell)({
@@ -36,10 +41,14 @@ const BootstrapTableCell = styled(TableCell)({
const Permission = () => {
const appContext = useContext(AppContext)
const [isLoading, setIsLoading] = useState(false)
const [openModal, setOpenModal] = useState(false)
const [modalTitle, setModalTitle] = useState('')
const [modalPayload, setModalPayload] = useState('')
const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false)
const [updatePermissionModalOpen, setUpdatePermissionModalOpen] =
useState(false)
const [selectedPermissionForUpdate, setSelectedPermissionForUpdate] =
const [deleteModalOpen, setDeleteModalOpen] = useState(false)
const [selectedPermission, setSelectedPermission] =
useState<PermissionResponse>()
const [filterModalOpen, setFilterModalOpen] = useState(false)
const [uriFilter, setUriFilter] = useState<string[]>([])
@@ -51,8 +60,7 @@ const Permission = () => {
>([])
const [filterApplied, setFilterApplied] = useState(false)
useEffect(() => {
setIsLoading(true)
const fetchPermissions = useCallback(() => {
axios
.get(`/SASjsApi/permission`)
.then((res: any) => {
@@ -61,13 +69,16 @@ const Permission = () => {
}
})
.catch((err) => {
console.log(err)
})
.finally(() => {
setIsLoading(false)
setModalTitle('Abort')
setModalPayload(typeof err === 'object' ? err.toSting() : err)
setOpenModal(true)
})
}, [])
useEffect(() => {
fetchPermissions()
}, [fetchPermissions])
/**
* first find the permissions w.r.t each filter type
* take intersection of resultant arrays
@@ -119,14 +130,82 @@ const Permission = () => {
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) => {
setSelectedPermissionForUpdate(permission)
setSelectedPermission(permission)
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 ? (
<CircularProgress
@@ -159,9 +238,16 @@ const Permission = () => {
<PermissionTable
permissions={filterApplied ? filteredPermissions : permissions}
handleUpdatePermissionClick={handleUpdatePermissionClick}
handleDeletePermissionClick={handleDeletePermissionClick}
/>
</Grid>
</Grid>
<Modal
open={openModal}
setOpen={setOpenModal}
title={modalTitle}
payload={modalPayload}
/>
<PermissionFilterModal
open={filterModalOpen}
handleOpen={setFilterModalOpen}
@@ -181,14 +267,17 @@ const Permission = () => {
permissions={permissions}
addPermission={addPermission}
/>
{selectedPermissionForUpdate && (
<UpdatePermissionModal
open={updatePermissionModalOpen}
handleOpen={setUpdatePermissionModalOpen}
permission={selectedPermissionForUpdate}
updatePermission={updatePermission}
/>
)}
<UpdatePermissionModal
open={updatePermissionModalOpen}
handleOpen={setUpdatePermissionModalOpen}
permission={selectedPermission}
updatePermission={updatePermission}
/>
<DeleteModal
open={deleteModalOpen}
setOpen={setDeleteModalOpen}
deletePermission={deletePermission}
/>
</Box>
)
}
@@ -198,11 +287,13 @@ export default Permission
type PermissionTableProps = {
permissions: PermissionResponse[]
handleUpdatePermissionClick: (permission: PermissionResponse) => void
handleDeletePermissionClick: (permission: PermissionResponse) => void
}
const PermissionTable = ({
permissions,
handleUpdatePermissionClick
handleUpdatePermissionClick,
handleDeletePermissionClick
}: PermissionTableProps) => {
const appContext = useContext(AppContext)
@@ -237,7 +328,10 @@ const PermissionTable = ({
</IconButton>
</Tooltip>
<Tooltip title="Delete Permission">
<IconButton color="error">
<IconButton
color="error"
onClick={() => handleDeletePermissionClick(permission)}
>
<DeleteForeverIcon />
</IconButton>
</Tooltip>

View File

@@ -48,7 +48,9 @@ const PermissionFilterModal = ({
applyFilter,
resetFilter
}: 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
let principals = permissions.map((permission) => {
@@ -62,7 +64,7 @@ const PermissionFilterModal = ({
// removes the duplicates
principals = principals.filter(
(value, index, self) => self.indexOf(value) === index
(principal, index, array) => array.indexOf(principal) === index
)
return (

View File

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