Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bai 1376 display entry collaborators outside of the settings tab #1455

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions frontend/src/entry/EntityIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import GroupsIcon from '@mui/icons-material/Groups'
import PersonIcon from '@mui/icons-material/Person'
import { useMemo } from 'react'
import { CollaboratorEntry } from 'types/types'

type EntityIconProps = {
entryCollaborator: CollaboratorEntry
}

export default function EntityIcon({ entryCollaborator }: EntityIconProps) {
const isUser = useMemo(() => entryCollaborator.entity.startsWith('user:'), [entryCollaborator])
return isUser ? <PersonIcon color='primary' /> : <GroupsIcon color='secondary' />
}
20 changes: 20 additions & 0 deletions frontend/src/entry/EntityNameDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Typography } from '@mui/material'
import { useMemo } from 'react'
import UserDisplay from 'src/common/UserDisplay'
import { CollaboratorEntry, EntityKind } from 'types/types'

type EntityNameDisplayProps = {
entryCollaborator: CollaboratorEntry
}

export default function EntityNameDisplay({ entryCollaborator }: EntityNameDisplayProps) {
const [entryCollaboratorKind, entryCollaboratorName] = useMemo(
() => entryCollaborator.entity.split(':'),
[entryCollaborator],
)
return entryCollaboratorKind === EntityKind.USER || entryCollaboratorKind === EntityKind.GROUP ? (
<UserDisplay dn={entryCollaboratorName} />
) : (
<Typography fontWeight='bold'>{entryCollaboratorName}</Typography>
)
}
22 changes: 10 additions & 12 deletions frontend/src/entry/model/settings/AccessRequestSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,16 @@ export default function AccessRequestSettings({ model }: AccessRequestSettingsPr
<Typography variant='h6' component='h2'>
Manage access requests
</Typography>
<div>
<FormControlLabel
label='Allow users to make ungoverned access requests'
control={
<Checkbox
onChange={(event) => setAllowUngoverned(event.target.checked)}
checked={allowUngoverned}
size='small'
/>
}
/>
</div>
<FormControlLabel
label='Allow users to make ungoverned access requests'
control={
<Checkbox
onChange={(event) => setAllowUngoverned(event.target.checked)}
checked={allowUngoverned}
size='small'
/>
}
/>
<Divider />
<div>
<LoadingButton
Expand Down
35 changes: 8 additions & 27 deletions frontend/src/entry/overview/EntryCardEntityRoleRow.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import GroupIcon from '@mui/icons-material/Groups'
import UserIcon from '@mui/icons-material/Person'
import { Grid, Stack } from '@mui/material'
import { Fragment, useMemo } from 'react'
import UserDisplay from 'src/common/UserDisplay'
import { Fragment } from 'react'
import EntityIcon from 'src/entry/EntityIcon'
import EntityNameDisplay from 'src/entry/EntityNameDisplay'
import EntryCardRolesChipSet from 'src/entry/overview/EntryCardRolesChipSet'
import { CollaboratorEntry } from 'types/types'

Expand All @@ -11,35 +10,17 @@ type EntryCardEntityRoleRowProps = {
}

export default function EntryCardEntityRoleRow({ entryCollaborators }: EntryCardEntityRoleRowProps) {
return entryCollaborators.map((user) => (
<Fragment key={user.entity}>
return entryCollaborators.map((collaborator) => (
<Fragment key={collaborator.entity}>
<Grid item xs={6}>
<Stack direction='row' alignItems='center' spacing={1}>
<EntryCollaboratorIcon entity={user} />
<EntryCollaboratorName entity={user} />
<EntityIcon entryCollaborator={collaborator} />
<EntityNameDisplay entryCollaborator={collaborator} />
</Stack>
</Grid>
<Grid item xs={6}>
<EntryCardRolesChipSet entryCollaborator={user} />
<EntryCardRolesChipSet entryCollaborator={collaborator} />
</Grid>
</Fragment>
))
}

type EntryCollaboratorProps = {
entity: CollaboratorEntry
}

function EntryCollaboratorIcon({ entity }: EntryCollaboratorProps) {
const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity])
return isUser ? <UserIcon color='primary' /> : <GroupIcon color='secondary' />
}

function EntryCollaboratorName({ entity }: EntryCollaboratorProps) {
const entityName = useMemo(() => entity.entity.split('/').pop()!, [entity])
return (
<>
<UserDisplay dn={entityName} />
</>
)
}
18 changes: 6 additions & 12 deletions frontend/src/entry/overview/EntryCardRolesChipSet.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import Dangerous from '@mui/icons-material/DangerousOutlined'
import { Chip } from '@mui/material'
import { useMemo } from 'react'
import { CollaboratorEntry } from 'types/types'

type EntryCardChipSetProps = {
entryCollaborator: CollaboratorEntry
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad for not noticing this the first time around. Should be EntryCardRolesChipSetProps

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

}

export default function EntryCardRolesChipSet({ entryCollaborator }: EntryCardChipSetProps) {
return entryCollaborator.roles.length === 0 ? (
<Chip
variant='outlined'
style={{ marginRight: 2, marginBottom: 2, backgroundColor: '#B00020', color: 'white', alignContent: 'center' }}
icon={<Dangerous style={{ color: 'white' }} />}
label='No Roles'
/>
) : (
entryCollaborator.roles.map((role) => {
return <Chip key={role} variant='outlined' style={{ marginRight: 2, marginBottom: 2 }} label={role} />
})
const roleChips = useMemo(
() => entryCollaborator.roles.map((role) => <Chip key={role} label={role} color='primary' sx={{ mr: 1 }} />),
[entryCollaborator.roles],
)

return roleChips.length ? roleChips : <Chip label='No roles' color='warning' />
}
22 changes: 0 additions & 22 deletions frontend/src/entry/overview/EntryCardRolesDialog.tsx

This file was deleted.

62 changes: 50 additions & 12 deletions frontend/src/entry/overview/EntryRoleList.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,61 @@
import { Grid } from '@mui/material'
import EntryCardEntityRoleRow from 'src/entry/overview/EntryCardEntityRoleRow'
import { EntryInterface } from 'types/types'
import GroupIcon from '@mui/icons-material/Groups'
import UserIcon from '@mui/icons-material/Person'
import { Grid, Stack } from '@mui/material'
import { Fragment, useMemo } from 'react'
import UserDisplay from 'src/common/UserDisplay'
import EntryCardRolesChipSet from 'src/entry/overview/EntryCardRolesChipSet'
import { CollaboratorEntry, EntryInterface } from 'types/types'

type EntryCardRoleDialogProps = {
entry: EntryInterface
}

export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) {
const rows = useMemo(
() =>
entry.collaborators.map((collaborator) => (
<Fragment key={collaborator.entity}>
<Grid item xs={6}>
<Stack direction='row' alignItems='center' spacing={1}>
<EntryCollaboratorIcon entryCollaborator={collaborator} />
<EntryCollaboratorName entryCollaborator={collaborator} />
</Stack>
</Grid>
<Grid item xs={6}>
<EntryCardRolesChipSet entryCollaborator={collaborator} />
</Grid>
</Fragment>
)),
[entry.collaborators],
)

return (
<>
<Grid container spacing={2} paddingX={5} paddingBottom={2}>
<Grid item xs={6}>
Entity
</Grid>
<Grid item xs={6}>
Roles
</Grid>
<EntryCardEntityRoleRow entryCollaborators={entry.collaborators} />
<Grid container spacing={2}>
<Grid item xs={6}>
Entity
</Grid>
<Grid item xs={6}>
Roles
</Grid>
{rows}
</Grid>
)
}

type EntryCollaboratorProps = {
entryCollaborator: CollaboratorEntry
}

function EntryCollaboratorIcon({ entryCollaborator }: EntryCollaboratorProps) {
const isUser = useMemo(() => entryCollaborator.entity.startsWith('user:'), [entryCollaborator])
return isUser ? <UserIcon color='primary' /> : <GroupIcon color='secondary' />
}

function EntryCollaboratorName({ entryCollaborator }: EntryCollaboratorProps) {
const entityName = useMemo(() => entryCollaborator.entity.split('/').pop()!, [entryCollaborator])
return (
<>
<UserDisplay dn={entityName} />
</>
)
}
22 changes: 22 additions & 0 deletions frontend/src/entry/overview/EntryRolesDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { DialogContent, DialogTitle } from '@mui/material'
import Dialog from '@mui/material/Dialog'
import { Transition } from 'src/common/Transition'
import EntryRoleList from 'src/entry/overview/EntryRoleList'
import { EntryInterface } from 'types/types'

type EntryRoleDialogProps = {
entry: EntryInterface
open: boolean
onClose: () => void
}

export default function EntryRolesDialog({ entry, open, onClose }: EntryRoleDialogProps) {
return (
<Dialog open={open} onClose={onClose} fullWidth maxWidth='md' TransitionComponent={Transition}>
<DialogTitle>Roles</DialogTitle>
<DialogContent>
<EntryRoleList entry={entry} />
</DialogContent>
</Dialog>
)
}
3 changes: 2 additions & 1 deletion frontend/src/entry/overview/ExportEntryCardDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Image from 'next/image'
import logo from 'public/horizontal-dark.png'
import { useMemo, useRef } from 'react'
import { useReactToPrint } from 'react-to-print'
import { Transition } from 'src/common/Transition'
import { ArrayFieldTemplate, DescriptionFieldTemplate, ObjectFieldTemplate } from 'src/Form/FormTemplates'
import { EntryInterface, SplitSchemaNoRender } from 'types/types'
import { widgets } from 'utils/formUtils'
Expand Down Expand Up @@ -60,7 +61,7 @@ export default function ExportEntryCardDialog({ entry, splitSchema, open, setOpe
}, [splitSchema.steps])

return (
<Dialog open={open} onClose={() => setOpen(false)} fullWidth maxWidth='md'>
<Dialog open={open} onClose={() => setOpen(false)} fullWidth maxWidth='md' TransitionComponent={Transition}>
<DialogContent ref={modelCardContentRef}>
<Stack spacing={2} divider={<Divider />}>
<Stack direction='row' alignItems='center'>
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/entry/overview/FormEditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Loading from 'src/common/Loading'
import TextInputDialog from 'src/common/TextInputDialog'
import UnsavedChangesContext from 'src/contexts/unsavedChangesContext'
import EntryCardHistoryDialog from 'src/entry/overview/EntryCardHistoryDialog'
import EntryCardRolesDialog from 'src/entry/overview/EntryCardRolesDialog'
import EntryCardRolesDialog from 'src/entry/overview/EntryRolesDialog'
import ExportEntryCardDialog from 'src/entry/overview/ExportEntryCardDialog'
import SaveAndCancelButtons from 'src/entry/overview/SaveAndCancelFormButtons'
import JsonSchemaForm from 'src/Form/JsonSchemaForm'
Expand Down Expand Up @@ -140,12 +140,12 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false
</div>
{!isEdit && (
<Stack direction='row' spacing={1} justifyContent='flex-end' sx={{ mb: { xs: 2 } }}>
<Button variant='outlined' onClick={() => setRolesDialogOpen(true)}>
View Roles
</Button>
<Button variant='outlined' onClick={() => setExportDialogOpen(true)}>
Export as PDF
</Button>
<Button variant='outlined' onClick={() => setRolesDialogOpen(true)}>
View Roles
</Button>
<Button variant='outlined' onClick={() => setHistoryDialogOpen(true)}>
View History
</Button>
Expand Down Expand Up @@ -188,7 +188,7 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false
)}
</Box>
<EntryCardHistoryDialog entry={entry} open={historyDialogOpen} setOpen={setHistoryDialogOpen} />
<EntryCardRolesDialog entry={entry} open={rolesDialogOpen} setOpen={setRolesDialogOpen} />
<EntryCardRolesDialog entry={entry} open={rolesDialogOpen} onClose={() => setRolesDialogOpen(false)} />
<TextInputDialog
open={jsonUploadDialogOpen}
onClose={() => setJsonUploadDialogOpen(false)}
Expand Down
51 changes: 15 additions & 36 deletions frontend/src/entry/settings/EntityItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import ClearIcon from '@mui/icons-material/Clear'
import GroupsIcon from '@mui/icons-material/Groups'
import PersonIcon from '@mui/icons-material/Person'
import { Autocomplete, Chip, IconButton, Stack, TableCell, TableRow, TextField, Typography } from '@mui/material'
import { Autocomplete, Chip, IconButton, Stack, TableCell, TableRow, TextField, Tooltip } from '@mui/material'
import _ from 'lodash-es'
import { SyntheticEvent, useMemo } from 'react'
import UserDisplay from 'src/common/UserDisplay'
import { CollaboratorEntry, EntityKind, Role } from 'types/types'
import EntityIcon from 'src/entry/EntityIcon'
import EntityNameDisplay from 'src/entry/EntityNameDisplay'
import { CollaboratorEntry, Role } from 'types/types'
import { toSentenceCase } from 'utils/stringUtils'

type EntityItemProps = {
Expand Down Expand Up @@ -41,8 +40,8 @@ export default function EntityItem({ entity, accessList, onAccessListChange, ent
<TableRow>
<TableCell>
<Stack direction='row' alignItems='center' spacing={1}>
<EntityIcon entity={entity} />
<EntityNameDisplay entity={entity} />
<EntityIcon entryCollaborator={entity} />
<EntityNameDisplay entryCollaborator={entity} />
</Stack>
</TableCell>
<TableCell>
Expand All @@ -66,36 +65,16 @@ export default function EntityItem({ entity, accessList, onAccessListChange, ent
)}
</TableCell>
<TableCell align='right'>
<IconButton
aria-label={`Remove user ${entity.entity} from ${toSentenceCase(entryKind)} access list`}
onClick={removeEntity}
data-test='accessListRemoveUser'
>
<ClearIcon color='secondary' fontSize='inherit' />
</IconButton>
<Tooltip title='Remove user'>
<IconButton
aria-label={`Remove user ${entity.entity} from ${toSentenceCase(entryKind)} access list`}
onClick={removeEntity}
data-test='accessListRemoveUser'
>
<ClearIcon color='secondary' fontSize='inherit' />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
)
}

type EntityIconProps = {
entity: CollaboratorEntry
}

function EntityIcon({ entity }: EntityIconProps) {
const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity])
return isUser ? <PersonIcon color='primary' /> : <GroupsIcon color='secondary' />
}

type EntityNameDisplayProps = {
entity: CollaboratorEntry
}

function EntityNameDisplay({ entity }: EntityNameDisplayProps) {
const [entityKind, entityName] = useMemo(() => entity.entity.split(':'), [entity])
return entityKind === EntityKind.USER || entityKind === EntityKind.GROUP ? (
<UserDisplay dn={entityName} />
) : (
<Typography fontWeight='bold'>{entityName}</Typography>
)
}
Loading
Loading