import React, { useState, useEffect, useContext, useCallback } from 'react' import axios from 'axios' import { Box, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Grid, CircularProgress, IconButton, Tooltip, Typography, Popover } from '@mui/material' import FilterListIcon from '@mui/icons-material/FilterList' import AddIcon from '@mui/icons-material/Add' import EditIcon from '@mui/icons-material/Edit' 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 DeleteConfirmationModal from '../../components/deleteConfirmationModal' import BootstrapSnackbar, { AlertSeverityType } from '../../components/snackbar' import { GroupDetailsResponse, PermissionResponse, RegisterPermissionPayload } from '../../utils/types' import { AppContext } from '../../context/appContext' const BootstrapTableCell = styled(TableCell)({ textAlign: 'left' }) export enum PrincipalType { User = 'User', Group = 'Group' } 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 [openSnackbar, setOpenSnackbar] = useState(false) const [snackbarMessage, setSnackbarMessage] = useState('') const [snackbarSeverity, setSnackbarSeverity] = useState( AlertSeverityType.Success ) const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false) const [updatePermissionModalOpen, setUpdatePermissionModalOpen] = useState(false) const [deleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false) const [deleteConfirmationModalMessage, setDeleteConfirmationModalMessage] = useState('') const [selectedPermission, setSelectedPermission] = useState() const [filterModalOpen, setFilterModalOpen] = useState(false) const [uriFilter, setUriFilter] = useState([]) const [principalFilter, setPrincipalFilter] = useState([]) const [principalTypeFilter, setPrincipalTypeFilter] = useState< PrincipalType[] >([]) const [settingFilter, setSettingFilter] = useState([]) const [permissions, setPermissions] = useState([]) const [filteredPermissions, setFilteredPermissions] = useState< PermissionResponse[] >([]) const [filterApplied, setFilterApplied] = useState(false) const fetchPermissions = useCallback(() => { axios .get(`/SASjsApi/permission`) .then((res: any) => { if (res.data?.length > 0) { setPermissions(res.data) } }) .catch((err) => { setModalTitle('Abort') setModalPayload( typeof err.response.data === 'object' ? JSON.stringify(err.response.data) : err.response.data ) setOpenModal(true) }) }, []) useEffect(() => { fetchPermissions() }, [fetchPermissions]) /** * first find the permissions w.r.t each filter type * take intersection of resultant arrays */ const applyFilter = () => { setFilterModalOpen(false) const uriFilteredPermissions = uriFilter.length > 0 ? permissions.filter((permission) => uriFilter.includes(permission.uri)) : 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) setUriFilter([]) setPrincipalFilter([]) setSettingFilter([]) setFilteredPermissions([]) setFilterApplied(false) } const addPermission = (addPermissionPayload: RegisterPermissionPayload) => { setAddPermissionModalOpen(false) setIsLoading(true) axios .post('/SASjsApi/permission', addPermissionPayload) .then((res: any) => { fetchPermissions() setSnackbarMessage('Permission added!') 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) }) } const handleUpdatePermissionClick = (permission: PermissionResponse) => { setSelectedPermission(permission) setUpdatePermissionModalOpen(true) } 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 handleDeletePermissionClick = (permission: PermissionResponse) => { setSelectedPermission(permission) setDeleteConfirmationModalOpen(true) setDeleteConfirmationModalMessage( 'Are you sure you want to delete this permission?' ) } 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) }) } return isLoading ? ( ) : ( setFilterModalOpen(true)} /> {appContext.isAdmin && ( setAddPermissionModalOpen(true)}> )} ) } export default Permission type PermissionTableProps = { permissions: PermissionResponse[] handleUpdatePermissionClick: (permission: PermissionResponse) => void handleDeletePermissionClick: (permission: PermissionResponse) => void } const PermissionTable = ({ permissions, handleUpdatePermissionClick, handleDeletePermissionClick }: PermissionTableProps) => { const appContext = useContext(AppContext) return ( Uri Principal Type Setting {appContext.isAdmin && ( Action )} {permissions.map((permission) => ( {permission.uri} {displayPrincipal(permission)} {displayPrincipalType(permission)} {permission.setting} {appContext.isAdmin && ( handleUpdatePermissionClick(permission)} > handleDeletePermissionClick(permission)} > )} ))}
) } const displayPrincipal = (permission: PermissionResponse) => { if (permission.user) return permission.user.username if (permission.group) return } type DisplayGroupProps = { group: GroupDetailsResponse } const DisplayGroup = ({ group }: DisplayGroupProps) => { const [anchorEl, setAnchorEl] = useState(null) const handlePopoverOpen = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget) } const handlePopoverClose = () => { setAnchorEl(null) } const open = Boolean(anchorEl) return (
{group.name} Group Members {group.users.map((user) => ( {user.username} ))}
) } const displayPrincipalType = (permission: PermissionResponse) => { if (permission.user) return PrincipalType.User if (permission.group) return PrincipalType.Group }