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:
@@ -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
|
||||||
|
|||||||
43
web/src/components/modal.tsx
Normal file
43
web/src/components/modal.tsx
Normal 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
|
||||||
@@ -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 =
|
||||||
|
|||||||
44
web/src/containers/Settings/deletePermissionModal.tsx
Normal file
44
web/src/containers/Settings/deletePermissionModal.tsx
Normal 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
|
||||||
@@ -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={selectedPermissionForUpdate}
|
permission={selectedPermission}
|
||||||
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>
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user