diff --git a/web/src/components/dialogTitle.tsx b/web/src/components/dialogTitle.tsx index 8c78033..5084809 100644 --- a/web/src/components/dialogTitle.tsx +++ b/web/src/components/dialogTitle.tsx @@ -7,19 +7,19 @@ import CloseIcon from '@mui/icons-material/Close' export interface DialogTitleProps { id: string children?: React.ReactNode - onClose: Dispatch> + handleOpen: Dispatch> } export const BootstrapDialogTitle = (props: DialogTitleProps) => { - const { children, onClose, ...other } = props + const { children, handleOpen, ...other } = props return ( {children} - {onClose ? ( + {handleOpen ? ( onClose(false)} + onClick={() => handleOpen(false)} sx={{ position: 'absolute', right: 8, diff --git a/web/src/containers/Settings/addPermissionModal.tsx b/web/src/containers/Settings/addPermissionModal.tsx new file mode 100644 index 0000000..0d413b8 --- /dev/null +++ b/web/src/containers/Settings/addPermissionModal.tsx @@ -0,0 +1,217 @@ +import React, { + useState, + useEffect, + useMemo, + Dispatch, + SetStateAction +} from 'react' +import axios from 'axios' +import { + Button, + Grid, + Dialog, + DialogContent, + DialogActions, + TextField, + CircularProgress +} from '@mui/material' +import { styled } from '@mui/material/styles' +import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete' + +import { BootstrapDialogTitle } from '../../components/dialogTitle' + +import { + PermissionResponse, + UserResponse, + GroupResponse, + RegisterPermissionPayload +} from '../../utils/types' + +const BootstrapDialog = styled(Dialog)(({ theme }) => ({ + '& .MuiDialogContent-root': { + padding: theme.spacing(2) + }, + '& .MuiDialogActions-root': { + padding: theme.spacing(1) + } +})) + +type AddPermissionModalProps = { + open: boolean + handleOpen: Dispatch> + permissions: PermissionResponse[] + addPermission: (addPermissionPayload: RegisterPermissionPayload) => void +} + +const filter = createFilterOptions() + +const AddPermissionModal = ({ + open, + handleOpen, + permissions, + addPermission +}: AddPermissionModalProps) => { + const [uri, setUri] = useState() + const [principalType, setPrincipalType] = useState('user') + const [userPrincipal, setUserPrincipal] = useState() + const [groupPrincipal, setGroupPrincipal] = useState() + const [permissionSetting, setPermissionSetting] = useState('Grant') + const [loadingPrincipals, setLoadingPrincipals] = useState(false) + const [userPrincipals, setUserPrincipals] = useState([]) + const [groupPrincipals, setGroupPrincipals] = useState([]) + + useEffect(() => { + setLoadingPrincipals(true) + axios + .get(`/SASjsApi/${principalType}`) + .then((res: any) => { + if (res.data) { + if (principalType === 'user') setUserPrincipals(res.data) + else setGroupPrincipals(res.data) + } + }) + .catch((err) => { + console.log(err) + }) + .finally(() => { + setLoadingPrincipals(false) + }) + }, [principalType]) + + const handleAddPermission = () => { + const addPermissionPayload: any = { + uri, + setting: permissionSetting, + principalType + } + if (principalType === 'user' && userPrincipal) { + addPermissionPayload.principalId = userPrincipal.id + } else if (principalType === 'group' && groupPrincipal) { + addPermissionPayload.principalId = groupPrincipal.groupId + } + addPermission(addPermissionPayload) + } + + const URIs = useMemo(() => { + return permissions.map((permission) => permission.uri) + }, [permissions]) + + const addButtonDisabled = + !uri || (principalType === 'user' ? !userPrincipal : !groupPrincipal) + + return ( + handleOpen(false)} open={open}> + + Add Permission + + + + + setUri(newValue)} + filterOptions={(options, params) => { + const filtered = filter(options, params) + + const { inputValue } = params + + const isExisting = options.some( + (option) => inputValue === option + ) + if (inputValue !== '' && !isExisting) { + filtered.push(inputValue) + } + return filtered + }} + selectOnFocus + clearOnBlur + handleHomeEndKeys + options={URIs} + renderOption={(props, option) =>
  • {option}
  • } + freeSolo + renderInput={(params) => } + /> +
    + + + setPrincipalType(newValue) + } + renderInput={(params) => ( + + )} + /> + + + {principalType === 'user' ? ( + option.displayName} + disableClearable + value={userPrincipal} + onChange={(event: any, newValue: UserResponse) => + setUserPrincipal(newValue) + } + renderInput={(params) => + loadingPrincipals ? ( + + ) : ( + + ) + } + /> + ) : ( + option.name} + disableClearable + value={groupPrincipal} + onChange={(event: any, newValue: GroupResponse) => + setGroupPrincipal(newValue) + } + renderInput={(params) => + loadingPrincipals ? ( + + ) : ( + + ) + } + /> + )} + + + + setPermissionSetting(newValue) + } + renderInput={(params) => ( + + )} + /> + +
    +
    + + + +
    + ) +} + +export default AddPermissionModal diff --git a/web/src/containers/Settings/permission.tsx b/web/src/containers/Settings/permission.tsx index 42e2854..ae4c17f 100644 --- a/web/src/containers/Settings/permission.tsx +++ b/web/src/containers/Settings/permission.tsx @@ -23,26 +23,9 @@ import DeleteForeverIcon from '@mui/icons-material/DeleteForever' import { styled } from '@mui/material/styles' import PermissionFilterModal from './permissionFilterModal' +import AddPermissionModal from './addPermissionModal' -interface UserResponse { - id: number - username: string - displayName: string -} - -interface GroupResponse { - groupId: number - name: string - description: string -} - -export interface PermissionResponse { - permissionId: number - uri: string - setting: string - user?: UserResponse - group?: GroupResponse -} +import { PermissionResponse } from '../../utils/types' const BootstrapTableCell = styled(TableCell)({ textAlign: 'left' @@ -50,6 +33,7 @@ const BootstrapTableCell = styled(TableCell)({ const Permission = () => { const [isLoading, setIsLoading] = useState(false) + const [addPermissionModalOpen, setAddPermissionModalOpen] = useState(false) const [filterModalOpen, setFilterModalOpen] = useState(false) const [uriFilter, setUriFilter] = useState([]) const [principalFilter, setPrincipalFilter] = useState([]) @@ -128,6 +112,8 @@ const Permission = () => { setFilterApplied(false) } + const addPermission = () => {} + return isLoading ? ( { setFilterModalOpen(true)} />
    - - + + setAddPermissionModalOpen(true)}> @@ -157,7 +147,7 @@ const Permission = () => { { applyFilter={applyFilter} resetFilter={resetFilter} /> + ) } @@ -192,7 +188,7 @@ const PermissionTable = ({ permissions }: PermissionTableProps) => { {permissions.map((permission) => ( - + {permission.uri} {displayPrincipal(permission)} diff --git a/web/src/containers/Settings/permissionFilterModal.tsx b/web/src/containers/Settings/permissionFilterModal.tsx index f7d67e1..7f7faab 100644 --- a/web/src/containers/Settings/permissionFilterModal.tsx +++ b/web/src/containers/Settings/permissionFilterModal.tsx @@ -10,7 +10,7 @@ import { import { styled } from '@mui/material/styles' import Autocomplete from '@mui/material/Autocomplete' -import { PermissionResponse } from './permission' +import { PermissionResponse } from '../../utils/types' import { BootstrapDialogTitle } from '../../components/dialogTitle' const BootstrapDialog = styled(Dialog)(({ theme }) => ({ '& .MuiDialogContent-root': { @@ -23,7 +23,7 @@ const BootstrapDialog = styled(Dialog)(({ theme }) => ({ type FilterModalProps = { open: boolean - handleClose: Dispatch> + handleOpen: Dispatch> permissions: PermissionResponse[] uriFilter: string[] setUriFilter: Dispatch> @@ -37,7 +37,7 @@ type FilterModalProps = { const PermissionFilterModal = ({ open, - handleClose, + handleOpen, permissions, uriFilter, setUriFilter, @@ -58,10 +58,10 @@ const PermissionFilterModal = ({ .filter((principal) => principal !== '') return ( - + handleOpen(false)} open={open}> Permission Filter