From 9981814e801461c3d7af9d65ea552ff575d22678 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:06:55 +0000 Subject: [PATCH 01/12] Moved the iterator inside the entryrolelist component --- .../entry/overview/EntryCardRolesDialog.tsx | 37 +++++++++++++++++++ frontend/src/entry/overview/EntryRoleList.tsx | 25 +++++++++++++ frontend/src/entry/overview/FormEditPage.tsx | 6 +++ 3 files changed, 68 insertions(+) create mode 100644 frontend/src/entry/overview/EntryCardRolesDialog.tsx create mode 100644 frontend/src/entry/overview/EntryRoleList.tsx diff --git a/frontend/src/entry/overview/EntryCardRolesDialog.tsx b/frontend/src/entry/overview/EntryCardRolesDialog.tsx new file mode 100644 index 000000000..f654d8261 --- /dev/null +++ b/frontend/src/entry/overview/EntryCardRolesDialog.tsx @@ -0,0 +1,37 @@ +import { 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 EntryCardRoleDialogProps = { + entry: EntryInterface + open: boolean + setOpen: (isOpen: boolean) => void +} + +export default function EntryCardRolesDialog({ entry, open, setOpen }: EntryCardRoleDialogProps) { + // const theme = useTheme() + // const { isModelError: isEntryError, mutateModel: mutateEntry } = useGetModel(entry.id, entry.kind) + // const { + // modelRoles: entryRoles, + // isModelRolesLoading: isEntryRolesLoading, + // isModelRolesError: isEntryRolesError, + // } = useGetModelRoles(entry.id) + + return ( + <> + setOpen(false)} fullWidth maxWidth='sm' TransitionComponent={Transition}> + Roles + + {/* + {entry.collaborators.map((entryentry, index) => ( +
+ +
+ ))} +
*/} +
+ + ) +} diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx new file mode 100644 index 000000000..74380fc00 --- /dev/null +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -0,0 +1,25 @@ +import { Chip, Grid } from '@mui/material' +import { EntryInterface } from 'types/types' + +type EntryCardRoleDialogProps = { + entry: EntryInterface +} + +export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { + return ( + <> + + {entry.collaborators.map((user, index) => ( +
+ + + + + + +
+ ))} +
+ + ) +} diff --git a/frontend/src/entry/overview/FormEditPage.tsx b/frontend/src/entry/overview/FormEditPage.tsx index 2f83b59ec..c98f414ab 100644 --- a/frontend/src/entry/overview/FormEditPage.tsx +++ b/frontend/src/entry/overview/FormEditPage.tsx @@ -8,6 +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 ExportEntryCardDialog from 'src/entry/overview/ExportEntryCardDialog' import SaveAndCancelButtons from 'src/entry/overview/SaveAndCancelFormButtons' import JsonSchemaForm from 'src/Form/JsonSchemaForm' @@ -31,6 +32,7 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false const { schema, isSchemaLoading, isSchemaError } = useGetSchema(entry.card.schemaId) const { isModelError: isEntryError, mutateModel: mutateEntry } = useGetModel(entry.id, entry.kind) const { mutateModelCardRevisions: mutateEntryCardRevisions } = useGetModelCardRevisions(entry.id) + const [rolesDialogOpen, setRolesDialogOpen] = useState(false) const [historyDialogOpen, setHistoryDialogOpen] = useState(false) const [exportDialogOpen, setExportDialogOpen] = useState(false) const [jsonUploadDialogOpen, setJsonUploadDialogOpen] = useState(false) @@ -138,6 +140,9 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false {!isEdit && ( + @@ -183,6 +188,7 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false )} + setJsonUploadDialogOpen(false)} From 853a7fb77c8672256abdc9dda70519e7d1654bc4 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:40:41 +0000 Subject: [PATCH 02/12] Added grid with variable amount of rows. 1 column for collaborator's name (typography) and one for variable amount of chips representing the roles assigned to the collaborator --- .../entry/overview/EntryCardRolesDialog.tsx | 7 ------- frontend/src/entry/overview/EntryRoleList.tsx | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/frontend/src/entry/overview/EntryCardRolesDialog.tsx b/frontend/src/entry/overview/EntryCardRolesDialog.tsx index f654d8261..1fd8ecae5 100644 --- a/frontend/src/entry/overview/EntryCardRolesDialog.tsx +++ b/frontend/src/entry/overview/EntryCardRolesDialog.tsx @@ -24,13 +24,6 @@ export default function EntryCardRolesDialog({ entry, open, setOpen }: EntryCard setOpen(false)} fullWidth maxWidth='sm' TransitionComponent={Transition}> Roles - {/* - {entry.collaborators.map((entryentry, index) => ( -
- -
- ))} -
*/}
) diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx index 74380fc00..dd876b4bd 100644 --- a/frontend/src/entry/overview/EntryRoleList.tsx +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -1,4 +1,4 @@ -import { Chip, Grid } from '@mui/material' +import { Chip, Grid, Typography } from '@mui/material' import { EntryInterface } from 'types/types' type EntryCardRoleDialogProps = { @@ -8,16 +8,22 @@ type EntryCardRoleDialogProps = { export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { return ( <> - + {entry.collaborators.map((user, index) => ( -
+ <> - + + {user.entity} + - + {user.roles.map((role) => ( + <> + + + ))} -
+ ))}
From dba9f7271366bc285b5a3516b8a012cbfe799444 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:16:45 +0000 Subject: [PATCH 03/12] Cleaned up role list and displayed when a collaborator has no roles applied. --- .../entry/overview/EntryCardRolesDialog.tsx | 8 --- frontend/src/entry/overview/EntryRoleList.tsx | 55 ++++++++++++++----- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/frontend/src/entry/overview/EntryCardRolesDialog.tsx b/frontend/src/entry/overview/EntryCardRolesDialog.tsx index 1fd8ecae5..e7fbc15b2 100644 --- a/frontend/src/entry/overview/EntryCardRolesDialog.tsx +++ b/frontend/src/entry/overview/EntryCardRolesDialog.tsx @@ -11,14 +11,6 @@ type EntryCardRoleDialogProps = { } export default function EntryCardRolesDialog({ entry, open, setOpen }: EntryCardRoleDialogProps) { - // const theme = useTheme() - // const { isModelError: isEntryError, mutateModel: mutateEntry } = useGetModel(entry.id, entry.kind) - // const { - // modelRoles: entryRoles, - // isModelRolesLoading: isEntryRolesLoading, - // isModelRolesError: isEntryRolesError, - // } = useGetModelRoles(entry.id) - return ( <> setOpen(false)} fullWidth maxWidth='sm' TransitionComponent={Transition}> diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx index dd876b4bd..126d9b689 100644 --- a/frontend/src/entry/overview/EntryRoleList.tsx +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -1,5 +1,9 @@ -import { Chip, Grid, Typography } from '@mui/material' -import { EntryInterface } from 'types/types' +import GroupIcon from '@mui/icons-material/Groups' +import UserIcon from '@mui/icons-material/Person' +import { Chip, Grid, Stack, Typography } from '@mui/material' +import { Fragment, useMemo } from 'react' +import UserDisplay from 'src/common/UserDisplay' +import { CollaboratorEntry, EntryInterface } from 'types/types' type EntryCardRoleDialogProps = { entry: EntryInterface @@ -9,23 +13,44 @@ export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { return ( <> - {entry.collaborators.map((user, index) => ( - <> - - - {user.entity} - + {entry.collaborators.map((user) => ( + + + + + + - - {user.roles.map((role) => ( - <> - - - ))} + + {user.roles.length === 0 ? ( + NO ROLES + ) : ( + user.roles.map((role) => { + return + }) + )} - + ))} ) } + +type EntryCollaboratorProps = { + entity: CollaboratorEntry +} + +function EntryCollaboratorIcon({ entity }: EntryCollaboratorProps) { + const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity]) + return isUser ? : +} + +function EntryCollaboratorName({ entity }: EntryCollaboratorProps) { + const entityName = useMemo(() => entity.entity.split('/').pop()!, [entity]) + return ( + <> + + + ) +} From 43ad24a4125c454b152f0d35bb0c6cde77c4a3a9 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:41:04 +0000 Subject: [PATCH 04/12] Compartmentalised component functionality into new, relevant files --- .../entry/overview/EntryCardEntityRoleRow.tsx | 45 ++++++++++++++++ .../entry/overview/EntryCardRolesChipSet.tsx | 16 ++++++ frontend/src/entry/overview/EntryRoleList.tsx | 53 ++++--------------- 3 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 frontend/src/entry/overview/EntryCardEntityRoleRow.tsx create mode 100644 frontend/src/entry/overview/EntryCardRolesChipSet.tsx diff --git a/frontend/src/entry/overview/EntryCardEntityRoleRow.tsx b/frontend/src/entry/overview/EntryCardEntityRoleRow.tsx new file mode 100644 index 000000000..68e52d9c3 --- /dev/null +++ b/frontend/src/entry/overview/EntryCardEntityRoleRow.tsx @@ -0,0 +1,45 @@ +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 } from 'types/types' + +type EntryCardEntityRoleRowProps = { + entryCollaborators: CollaboratorEntry[] +} + +export default function EntryCardEntityRoleRow({ entryCollaborators }: EntryCardEntityRoleRowProps) { + return entryCollaborators.map((user) => ( + + + + + + + + + + + + )) +} + +type EntryCollaboratorProps = { + entity: CollaboratorEntry +} + +function EntryCollaboratorIcon({ entity }: EntryCollaboratorProps) { + const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity]) + return isUser ? : +} + +function EntryCollaboratorName({ entity }: EntryCollaboratorProps) { + const entityName = useMemo(() => entity.entity.split('/').pop()!, [entity]) + return ( + <> + + + ) +} diff --git a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx b/frontend/src/entry/overview/EntryCardRolesChipSet.tsx new file mode 100644 index 000000000..39ecb7ecb --- /dev/null +++ b/frontend/src/entry/overview/EntryCardRolesChipSet.tsx @@ -0,0 +1,16 @@ +import { Chip } from '@mui/material' +import { CollaboratorEntry } from 'types/types' + +type EntryCardChipSetProps = { + entryCollaborator: CollaboratorEntry +} + +export default function EntryCardRolesChipSet({ entryCollaborator }: EntryCardChipSetProps) { + return entryCollaborator.roles.length === 0 ? ( + + ) : ( + entryCollaborator.roles.map((role) => { + return + }) + ) +} diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx index 126d9b689..dc3c15402 100644 --- a/frontend/src/entry/overview/EntryRoleList.tsx +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -1,9 +1,6 @@ -import GroupIcon from '@mui/icons-material/Groups' -import UserIcon from '@mui/icons-material/Person' -import { Chip, Grid, Stack, Typography } from '@mui/material' -import { Fragment, useMemo } from 'react' -import UserDisplay from 'src/common/UserDisplay' -import { CollaboratorEntry, EntryInterface } from 'types/types' +import { Grid } from '@mui/material' +import EntryCardEntityRoleRowProps from 'src/entry/overview/EntryCardEntityRoleRow' +import { EntryInterface } from 'types/types' type EntryCardRoleDialogProps = { entry: EntryInterface @@ -13,44 +10,14 @@ export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { return ( <> - {entry.collaborators.map((user) => ( - - - - - - - - - {user.roles.length === 0 ? ( - NO ROLES - ) : ( - user.roles.map((role) => { - return - }) - )} - - - ))} + + Entity + + + Roles + + ) } - -type EntryCollaboratorProps = { - entity: CollaboratorEntry -} - -function EntryCollaboratorIcon({ entity }: EntryCollaboratorProps) { - const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity]) - return isUser ? : -} - -function EntryCollaboratorName({ entity }: EntryCollaboratorProps) { - const entityName = useMemo(() => entity.entity.split('/').pop()!, [entity]) - return ( - <> - - - ) -} From 631969e9169a25355802d9cd993bc8440e346b7b Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:44:11 +0000 Subject: [PATCH 05/12] Changed incorrect component name --- frontend/src/entry/overview/EntryRoleList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx index dc3c15402..c09fb5254 100644 --- a/frontend/src/entry/overview/EntryRoleList.tsx +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -1,5 +1,5 @@ import { Grid } from '@mui/material' -import EntryCardEntityRoleRowProps from 'src/entry/overview/EntryCardEntityRoleRow' +import EntryCardEntityRoleRow from 'src/entry/overview/EntryCardEntityRoleRow' import { EntryInterface } from 'types/types' type EntryCardRoleDialogProps = { @@ -16,7 +16,7 @@ export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { Roles - + ) From cdaca9b4621ab264ba077011ea49791ca643a18e Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:38:49 +0000 Subject: [PATCH 06/12] Added custom chip for when an entity has no roles on a model --- frontend/src/entry/overview/EntryCardRolesChipSet.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx b/frontend/src/entry/overview/EntryCardRolesChipSet.tsx index 39ecb7ecb..36ae4c9b3 100644 --- a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx +++ b/frontend/src/entry/overview/EntryCardRolesChipSet.tsx @@ -1,3 +1,4 @@ +import Dangerous from '@mui/icons-material/DangerousOutlined' import { Chip } from '@mui/material' import { CollaboratorEntry } from 'types/types' @@ -7,10 +8,15 @@ type EntryCardChipSetProps = { export default function EntryCardRolesChipSet({ entryCollaborator }: EntryCardChipSetProps) { return entryCollaborator.roles.length === 0 ? ( - + } + label='No Roles' + /> ) : ( entryCollaborator.roles.map((role) => { - return + return }) ) } From f54b8143035e9f2e99fc0742410a1e1384979cfb Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Tue, 6 Aug 2024 16:18:59 +0000 Subject: [PATCH 07/12] Simplified permission logic for accessing settings tab when you're not owner --- frontend/pages/data-card/[dataCardId].tsx | 15 +++- frontend/pages/model/[modelId].tsx | 15 +++- frontend/src/entry/EntryDescriptionInput.tsx | 41 +++------- frontend/src/entry/EntryNameInput.tsx | 47 +++-------- .../mirroredModels/ExportModelAgreement.tsx | 28 +++---- .../model/mirroredModels/ExportSettings.tsx | 57 +++++-------- .../model/settings/AccessRequestSettings.tsx | 50 +++++------- .../entry/model/settings/TemplateSettings.tsx | 50 +++++------- frontend/src/entry/settings/DangerZone.tsx | 24 ++---- frontend/src/entry/settings/EntityItem.tsx | 78 ++++++------------ .../src/entry/settings/EntryAccessInput.tsx | 80 +++++++------------ .../src/entry/settings/EntryAccessTab.tsx | 24 ++---- frontend/src/entry/settings/EntryDetails.tsx | 71 ++++++---------- frontend/src/entry/settings/Settings.tsx | 39 ++++----- 14 files changed, 219 insertions(+), 400 deletions(-) diff --git a/frontend/pages/data-card/[dataCardId].tsx b/frontend/pages/data-card/[dataCardId].tsx index dec8d4a67..ba0d79d38 100644 --- a/frontend/pages/data-card/[dataCardId].tsx +++ b/frontend/pages/data-card/[dataCardId].tsx @@ -3,13 +3,13 @@ import { useGetCurrentUser } from 'actions/user' import { useRouter } from 'next/router' import { useMemo } from 'react' import Loading from 'src/common/Loading' -import PageWithTabs from 'src/common/PageWithTabs' +import PageWithTabs, { PageTab } from 'src/common/PageWithTabs' import Title from 'src/common/Title' import Overview from 'src/entry/overview/Overview' import Settings from 'src/entry/settings/Settings' import MultipleErrorWrapper from 'src/errors/MultipleErrorWrapper' import { EntryKind } from 'types/types' -import { getCurrentUserRoles } from 'utils/roles' +import { getCurrentUserRoles, getRequiredRolesText, hasRole } from 'utils/roles' export default function DataCard() { const router = useRouter() @@ -23,7 +23,12 @@ export default function DataCard() { const currentUserRoles = useMemo(() => getCurrentUserRoles(dataCard, currentUser), [dataCard, currentUser]) - const tabs = useMemo( + const [isReadOnly, requiredRolesText] = useMemo(() => { + const validRoles = ['owner'] + return [!hasRole(currentUserRoles, validRoles), getRequiredRolesText(currentUserRoles, validRoles)] + }, [currentUserRoles]) + + const tabs: PageTab[] = useMemo( () => dataCard ? [ @@ -35,11 +40,13 @@ export default function DataCard() { { title: 'Settings', path: 'settings', + disabled: isReadOnly, + disabledText: requiredRolesText, view: , }, ] : [], - [currentUserRoles, dataCard], + [currentUserRoles, dataCard, isReadOnly, requiredRolesText], ) const error = MultipleErrorWrapper(`Unable to load data card page`, { diff --git a/frontend/pages/model/[modelId].tsx b/frontend/pages/model/[modelId].tsx index 7e5411de7..61e7414cd 100644 --- a/frontend/pages/model/[modelId].tsx +++ b/frontend/pages/model/[modelId].tsx @@ -4,7 +4,7 @@ import { useGetCurrentUser } from 'actions/user' import { useRouter } from 'next/router' import { useMemo } from 'react' import Loading from 'src/common/Loading' -import PageWithTabs from 'src/common/PageWithTabs' +import PageWithTabs, { PageTab } from 'src/common/PageWithTabs' import Title from 'src/common/Title' import AccessRequests from 'src/entry/model/AccessRequests' import InferenceServices from 'src/entry/model/InferenceServices' @@ -14,7 +14,7 @@ import Overview from 'src/entry/overview/Overview' import Settings from 'src/entry/settings/Settings' import MultipleErrorWrapper from 'src/errors/MultipleErrorWrapper' import { EntryKind } from 'types/types' -import { getCurrentUserRoles } from 'utils/roles' +import { getCurrentUserRoles, getRequiredRolesText, hasRole } from 'utils/roles' export default function Model() { const router = useRouter() @@ -25,7 +25,12 @@ export default function Model() { const currentUserRoles = useMemo(() => getCurrentUserRoles(model, currentUser), [model, currentUser]) - const tabs = useMemo( + const [isReadOnly, requiredRolesText] = useMemo(() => { + const validRoles = ['owner'] + return [!hasRole(currentUserRoles, validRoles), getRequiredRolesText(currentUserRoles, validRoles)] + }, [currentUserRoles]) + + const tabs: PageTab[] = useMemo( () => model && uiConfig ? [ @@ -81,11 +86,13 @@ export default function Model() { { title: 'Settings', path: 'settings', + disabled: isReadOnly, + disabledText: requiredRolesText, view: , }, ] : [], - [model, uiConfig, currentUserRoles], + [model, uiConfig, currentUserRoles, isReadOnly, requiredRolesText], ) function requestAccess() { diff --git a/frontend/src/entry/EntryDescriptionInput.tsx b/frontend/src/entry/EntryDescriptionInput.tsx index 027578c9c..a6edab017 100644 --- a/frontend/src/entry/EntryDescriptionInput.tsx +++ b/frontend/src/entry/EntryDescriptionInput.tsx @@ -1,4 +1,4 @@ -import { TextField, Tooltip } from '@mui/material' +import { TextField } from '@mui/material' import { ChangeEvent } from 'react' import LabelledInput from 'src/common/LabelledInput' @@ -7,42 +7,23 @@ const htmlId = 'entry-description-input' type EntryDescriptionInputProps = { value: string onChange: (value: string) => void -} & ( - | { - isReadOnly: boolean - requiredRolesText: string - } - | { - isReadOnly?: never - requiredRolesText?: never - } -) +} -export default function EntryDescriptionInput({ - value, - onChange, - isReadOnly = false, - requiredRolesText = '', -}: EntryDescriptionInputProps) { +export default function EntryDescriptionInput({ value, onChange }: EntryDescriptionInputProps) { const handleChange = (event: ChangeEvent) => { onChange(event.target.value) } return ( - - - - - + ) } diff --git a/frontend/src/entry/EntryNameInput.tsx b/frontend/src/entry/EntryNameInput.tsx index 7ab873b60..79b4f2cb2 100644 --- a/frontend/src/entry/EntryNameInput.tsx +++ b/frontend/src/entry/EntryNameInput.tsx @@ -1,4 +1,4 @@ -import { TextField, Tooltip } from '@mui/material' +import { TextField } from '@mui/material' import { ChangeEvent } from 'react' import LabelledInput from 'src/common/LabelledInput' import { EntryKindKeys } from 'types/types' @@ -11,46 +11,25 @@ type EntryNameInputProps = { kind: EntryKindKeys onChange: (value: string) => void autoFocus?: boolean -} & ( - | { - isReadOnly: boolean - requiredRolesText: string - } - | { - isReadOnly?: never - requiredRolesText?: never - } -) +} -export default function EntryNameInput({ - value, - kind, - onChange, - autoFocus = false, - isReadOnly = false, - requiredRolesText = '', -}: EntryNameInputProps) { +export default function EntryNameInput({ value, kind, onChange, autoFocus = false }: EntryNameInputProps) { const handleChange = (event: ChangeEvent) => { onChange(event.target.value) } return ( - - - - - + ) } diff --git a/frontend/src/entry/model/mirroredModels/ExportModelAgreement.tsx b/frontend/src/entry/model/mirroredModels/ExportModelAgreement.tsx index 112bd73e9..d5277012a 100644 --- a/frontend/src/entry/model/mirroredModels/ExportModelAgreement.tsx +++ b/frontend/src/entry/model/mirroredModels/ExportModelAgreement.tsx @@ -1,5 +1,5 @@ import { LoadingButton } from '@mui/lab' -import { Box, Card, Checkbox, Container, FormControlLabel, Stack, Tooltip, Typography } from '@mui/material' +import { Box, Card, Checkbox, Container, FormControlLabel, Stack, Typography } from '@mui/material' import { postModelExportToS3 } from 'actions/model' import { ChangeEvent, FormEvent, useState } from 'react' import ModelExportAgreementText from 'src/entry/model/mirroredModels/ModelExportAgreementText' @@ -7,13 +7,11 @@ import useNotification from 'src/hooks/useNotification' import MessageAlert from 'src/MessageAlert' import { getErrorMessage } from 'utils/fetcher' -type ExportModelProps = { +type ExportModelAgreementProps = { modelId: string - isReadOnly: boolean - requiredRolesText: string } -export default function ExportModel({ modelId, isReadOnly, requiredRolesText }: ExportModelProps) { +export default function ExportModelAgreement({ modelId }: ExportModelAgreementProps) { const [checked, setChecked] = useState(false) const [errorMessage, setErrorMessage] = useState('') const [loading, setLoading] = useState(false) @@ -55,19 +53,13 @@ export default function ExportModel({ modelId, isReadOnly, requiredRolesText }: - - } - label='I agree to the terms and conditions of this model export agreement' - /> - - - - - Submit - - - + } + label='I agree to the terms and conditions of this model export agreement' + /> + + Submit + diff --git a/frontend/src/entry/model/mirroredModels/ExportSettings.tsx b/frontend/src/entry/model/mirroredModels/ExportSettings.tsx index 8e27098d0..62f2839fc 100644 --- a/frontend/src/entry/model/mirroredModels/ExportSettings.tsx +++ b/frontend/src/entry/model/mirroredModels/ExportSettings.tsx @@ -1,15 +1,6 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import { LoadingButton } from '@mui/lab' -import { - Accordion, - AccordionDetails, - AccordionSummary, - Box, - Stack, - TextField, - Tooltip, - Typography, -} from '@mui/material' +import { Accordion, AccordionDetails, AccordionSummary, Box, Stack, TextField, Typography } from '@mui/material' import { patchModel } from 'actions/model' import { ChangeEvent, FormEvent, useState } from 'react' import LabelledInput from 'src/common/LabelledInput' @@ -21,11 +12,9 @@ import { getErrorMessage } from 'utils/fetcher' type ExportSettingsProps = { model: EntryInterface - isReadOnly: boolean - requiredRolesText: string } -export default function ExportSettings({ model, isReadOnly, requiredRolesText }: ExportSettingsProps) { +export default function ExportSettings({ model }: ExportSettingsProps) { const sendNotification = useNotification() const [destinationModelId, setDestinationModelId] = useState(model.settings.mirror?.destinationModelId || '') const [loading, setLoading] = useState(false) @@ -66,7 +55,7 @@ export default function ExportSettings({ model, isReadOnly, requiredRolesText }: return ( <> - + }> @@ -77,17 +66,12 @@ export default function ExportSettings({ model, isReadOnly, requiredRolesText }: - - - - - + {/*TODO - Add the ability to filter releases needed for export (This functionality is not available on the backend) */} - - - - Save - - - + + Save + diff --git a/frontend/src/entry/model/settings/AccessRequestSettings.tsx b/frontend/src/entry/model/settings/AccessRequestSettings.tsx index 2d4550f7f..32aff58c4 100644 --- a/frontend/src/entry/model/settings/AccessRequestSettings.tsx +++ b/frontend/src/entry/model/settings/AccessRequestSettings.tsx @@ -1,5 +1,5 @@ import { LoadingButton } from '@mui/lab' -import { Checkbox, Divider, FormControlLabel, Stack, Tooltip, Typography } from '@mui/material' +import { Checkbox, Divider, FormControlLabel, Stack, Typography } from '@mui/material' import { patchModel } from 'actions/model' import { useState } from 'react' import useNotification from 'src/hooks/useNotification' @@ -9,11 +9,9 @@ import { getErrorMessage } from 'utils/fetcher' type AccessRequestSettingsProps = { model: EntryInterface - isReadOnly: boolean - requiredRolesText: string } -export default function AccessRequestSettings({ model, isReadOnly, requiredRolesText }: AccessRequestSettingsProps) { +export default function AccessRequestSettings({ model }: AccessRequestSettingsProps) { const [allowUngoverned, setAllowUngoverned] = useState(model.settings.ungovernedAccess) const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState('') @@ -49,35 +47,27 @@ export default function AccessRequestSettings({ model, isReadOnly, requiredRoles Manage access requests
- - setAllowUngoverned(event.target.checked)} - checked={allowUngoverned} - disabled={isReadOnly} - size='small' - /> - } - /> - + setAllowUngoverned(event.target.checked)} + checked={allowUngoverned} + size='small' + /> + } + />
- - - - Save - - - + + Save +
diff --git a/frontend/src/entry/model/settings/TemplateSettings.tsx b/frontend/src/entry/model/settings/TemplateSettings.tsx index 851ec634e..6a35b5f3c 100644 --- a/frontend/src/entry/model/settings/TemplateSettings.tsx +++ b/frontend/src/entry/model/settings/TemplateSettings.tsx @@ -1,5 +1,5 @@ import { LoadingButton } from '@mui/lab' -import { Checkbox, Divider, FormControlLabel, Stack, Tooltip, Typography } from '@mui/material' +import { Checkbox, Divider, FormControlLabel, Stack, Typography } from '@mui/material' import { patchModel } from 'actions/model' import { useState } from 'react' import useNotification from 'src/hooks/useNotification' @@ -9,11 +9,9 @@ import { getErrorMessage } from 'utils/fetcher' type TemplateSettingsProps = { model: EntryInterface - isReadOnly: boolean - requiredRolesText: string } -export default function TemplateSettings({ model, isReadOnly, requiredRolesText }: TemplateSettingsProps) { +export default function TemplateSettings({ model }: TemplateSettingsProps) { const [allowTemplating, setAllowTemplating] = useState(model.settings.allowTemplating) const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState('') @@ -48,35 +46,27 @@ export default function TemplateSettings({ model, isReadOnly, requiredRolesText Manage Templating
- - setAllowTemplating(event.target.checked)} - checked={allowTemplating} - disabled={isReadOnly} - size='small' - /> - } - /> - + setAllowTemplating(event.target.checked)} + checked={allowTemplating} + size='small' + /> + } + />
- - - - Save - - - + + Save +
diff --git a/frontend/src/entry/settings/DangerZone.tsx b/frontend/src/entry/settings/DangerZone.tsx index d68595c0f..908538c48 100644 --- a/frontend/src/entry/settings/DangerZone.tsx +++ b/frontend/src/entry/settings/DangerZone.tsx @@ -1,16 +1,14 @@ import { LoadingButton } from '@mui/lab' -import { Stack, Tooltip, Typography } from '@mui/material' +import { Stack, Typography } from '@mui/material' import { useState } from 'react' import { EntryInterface } from 'types/types' import { toTitleCase } from 'utils/stringUtils' type DangerZoneProps = { entry: EntryInterface - isReadOnly: boolean - requiredRolesText: string } -export default function DangerZone({ entry, isReadOnly, requiredRolesText }: DangerZoneProps) { +export default function DangerZone({ entry }: DangerZoneProps) { const [loading, setLoading] = useState(false) const handleDeleteEntry = () => { @@ -24,20 +22,10 @@ export default function DangerZone({ entry, isReadOnly, requiredRolesText }: Dan Danger Zone! - - - {/* TODO - Set disabled to disabled={isReadOnly} when re-enabling delete functionality */} - - {`Delete ${toTitleCase(entry.kind)}`} - - - + {/* TODO - Remove disabled prop when reenabling delete functionality */} + + {`Delete ${toTitleCase(entry.kind)}`} + ) } diff --git a/frontend/src/entry/settings/EntityItem.tsx b/frontend/src/entry/settings/EntityItem.tsx index c698e6620..c82d5055c 100644 --- a/frontend/src/entry/settings/EntityItem.tsx +++ b/frontend/src/entry/settings/EntityItem.tsx @@ -1,17 +1,7 @@ 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, - Tooltip, - Typography, -} from '@mui/material' +import { Autocomplete, Chip, IconButton, Stack, TableCell, TableRow, TextField, Typography } from '@mui/material' import _ from 'lodash-es' import { SyntheticEvent, useMemo } from 'react' import UserDisplay from 'src/common/UserDisplay' @@ -24,19 +14,9 @@ type EntityItemProps = { onAccessListChange: (value: CollaboratorEntry[]) => void entryKind: string entryRoles: Role[] - isReadOnly: boolean - requiredRolesText: string } -export default function EntityItem({ - entity, - accessList, - onAccessListChange, - entryKind, - entryRoles, - isReadOnly, - requiredRolesText, -}: EntityItemProps) { +export default function EntityItem({ entity, accessList, onAccessListChange, entryKind, entryRoles }: EntityItemProps) { const entryRoleOptions = useMemo(() => entryRoles.map((role) => role.id), [entryRoles]) function onRoleChange(_event: SyntheticEvent, newValues: string[]) { @@ -67,40 +47,32 @@ export default function EntityItem({ {entryRoles.length > 0 && ( - - getRole(role).name} - onChange={onRoleChange} - renderInput={(params) => } - renderTags={(value, getTagProps) => - value.map((option, index) => ( - - )) - } - /> - + getRole(role).name} + onChange={onRoleChange} + renderInput={(params) => } + renderTags={(value, getTagProps) => + value.map((option, index) => ( + + )) + } + /> )} - - - - - - - + + + ) diff --git a/frontend/src/entry/settings/EntryAccessInput.tsx b/frontend/src/entry/settings/EntryAccessInput.tsx index 292c8c964..1e3c5f412 100644 --- a/frontend/src/entry/settings/EntryAccessInput.tsx +++ b/frontend/src/entry/settings/EntryAccessInput.tsx @@ -1,14 +1,4 @@ -import { - Autocomplete, - Stack, - Table, - TableBody, - TableCell, - TableHead, - TableRow, - TextField, - Tooltip, -} from '@mui/material' +import { Autocomplete, Stack, Table, TableBody, TableCell, TableHead, TableRow, TextField } from '@mui/material' import { useListUsers } from 'actions/user' import { debounce } from 'lodash-es' import { SyntheticEvent, useCallback, useEffect, useMemo, useState } from 'react' @@ -33,14 +23,7 @@ type EntryAccessInputProps = { } ) -export default function EntryAccessInput({ - value, - onUpdate, - entryKind, - entryRoles, - isReadOnly = false, - requiredRolesText = '', -}: EntryAccessInputProps) { +export default function EntryAccessInput({ value, onUpdate, entryKind, entryRoles }: EntryAccessInputProps) { const [open, setOpen] = useState(false) const [accessList, setAccessList] = useState(value) const [userListQuery, setUserListQuery] = useState('') @@ -57,11 +40,9 @@ export default function EntryAccessInput({ onAccessListChange={setAccessList} entryRoles={entryRoles} entryKind={entryKind} - isReadOnly={isReadOnly} - requiredRolesText={requiredRolesText} /> )), - [accessList, entryKind, entryRoles, isReadOnly, requiredRolesText], + [accessList, entryKind, entryRoles], ) useEffect(() => { @@ -106,35 +87,32 @@ export default function EntryAccessInput({ return ( - - setOpen(true)} - onClose={() => setOpen(false)} - size='small' - noOptionsText={noOptionsText} - onInputChange={debounceOnInputChange} - groupBy={(option) => option.kind.toUpperCase()} - getOptionLabel={(option) => option.id} - isOptionEqualToValue={(option, value) => option.id === value.id} - onChange={onUserChange} - options={users} - filterOptions={(options) => - options.filter( - (option) => !accessList.find((collaborator) => collaborator.entity === `${option.kind}:${option.id}`), - ) - } - loading={isUsersLoading && userListQuery.length >= 3} - renderInput={(params) => ( - - )} - /> - + setOpen(true)} + onClose={() => setOpen(false)} + size='small' + noOptionsText={noOptionsText} + onInputChange={debounceOnInputChange} + groupBy={(option) => option.kind.toUpperCase()} + getOptionLabel={(option) => option.id} + isOptionEqualToValue={(option, value) => option.id === value.id} + onChange={onUserChange} + options={users} + filterOptions={(options) => + options.filter( + (option) => !accessList.find((collaborator) => collaborator.entity === `${option.kind}:${option.id}`), + ) + } + loading={isUsersLoading && userListQuery.length >= 3} + renderInput={(params) => ( + + )} + /> diff --git a/frontend/src/entry/settings/EntryAccessTab.tsx b/frontend/src/entry/settings/EntryAccessTab.tsx index ef782eb04..5b8915c16 100644 --- a/frontend/src/entry/settings/EntryAccessTab.tsx +++ b/frontend/src/entry/settings/EntryAccessTab.tsx @@ -1,5 +1,5 @@ import { LoadingButton } from '@mui/lab' -import { Stack, Tooltip, Typography } from '@mui/material' +import { Stack, Typography } from '@mui/material' import { patchModel, useGetModel, useGetModelRoles } from 'actions/model' import { useState } from 'react' import HelpDialog from 'src/common/HelpDialog' @@ -14,11 +14,9 @@ import { toSentenceCase, toTitleCase } from 'utils/stringUtils' type EntryAccessTabProps = { entry: EntryInterface - isReadOnly: boolean - requiredRolesText: string } -export default function EntryAccessTab({ entry, isReadOnly, requiredRolesText }: EntryAccessTabProps) { +export default function EntryAccessTab({ entry }: EntryAccessTabProps) { const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState('') const [accessList, setAccessList] = useState(entry.collaborators) @@ -70,23 +68,11 @@ export default function EntryAccessTab({ entry, isReadOnly, requiredRolesText }: onUpdate={(val) => setAccessList(val)} entryKind={entry.kind} entryRoles={entryRoles} - isReadOnly={isReadOnly} - requiredRolesText={requiredRolesText} />
- - - - Save - - - + + Save +
diff --git a/frontend/src/entry/settings/EntryDetails.tsx b/frontend/src/entry/settings/EntryDetails.tsx index c458b80b3..9774418a1 100644 --- a/frontend/src/entry/settings/EntryDetails.tsx +++ b/frontend/src/entry/settings/EntryDetails.tsx @@ -15,11 +15,9 @@ import { toSentenceCase, toTitleCase } from 'utils/stringUtils' type EntryDetailsProps = { entry: EntryInterface - isReadOnly: boolean - requiredRolesText: string } -export default function EntryDetails({ entry, isReadOnly, requiredRolesText }: EntryDetailsProps) { +export default function EntryDetails({ entry }: EntryDetailsProps) { const [team, setTeam] = useState() const [name, setName] = useState(entry.name) const [description, setDescription] = useState(entry.description) @@ -37,13 +35,11 @@ export default function EntryDetails({ entry, isReadOnly, requiredRolesText }: E const isFormValid = useMemo(() => team && name && description, [team, name, description]) const saveButtonTooltip = useMemo(() => { - if (isReadOnly) { - return requiredRolesText - } else if (!isFormValid) { + if (!isFormValid) { return 'Please make sure all required fields are filled out' } return '' - }, [isFormValid, isReadOnly, requiredRolesText]) + }, [isFormValid]) async function onSubmit(event: FormEvent) { event.preventDefault() @@ -111,58 +107,39 @@ export default function EntryDetails({ entry, isReadOnly, requiredRolesText }: E setTeam(value)} /> - setName(value)} - /> + setName(value)} /> - setDescription(value)} - /> + setDescription(value)} /> <> Access control - - setVisibility(e.target.value as UpdateEntryForm['visibility'])} - > - } - label={publicLabel()} - data-test='publicButtonSelector' - /> - } - label={privateLabel()} - data-test='privateButtonSelector' - /> - - + setVisibility(e.target.value as UpdateEntryForm['visibility'])} + > + } + label={publicLabel()} + data-test='publicButtonSelector' + /> + } + label={privateLabel()} + data-test='privateButtonSelector' + /> +
- + Save diff --git a/frontend/src/entry/settings/Settings.tsx b/frontend/src/entry/settings/Settings.tsx index 1504acb53..087a4a8cc 100644 --- a/frontend/src/entry/settings/Settings.tsx +++ b/frontend/src/entry/settings/Settings.tsx @@ -1,7 +1,7 @@ import { Container, Divider, List, Stack } from '@mui/material' import { useGetUiConfig } from 'actions/uiConfig' import { useRouter } from 'next/router' -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useState } from 'react' import Loading from 'src/common/Loading' import SimpleListItemButton from 'src/common/SimpleListItemButton' import ExportSettings from 'src/entry/model/mirroredModels/ExportSettings' @@ -12,7 +12,7 @@ import EntryAccessTab from 'src/entry/settings/EntryAccessTab' import EntryDetails from 'src/entry/settings/EntryDetails' import MessageAlert from 'src/MessageAlert' import { EntryInterface, EntryKind, UiConfig } from 'types/types' -import { getRequiredRolesText, hasRole } from 'utils/roles' +import { hasRole } from 'utils/roles' import { toTitleCase } from 'utils/stringUtils' export const SettingsCategory = { @@ -64,10 +64,15 @@ export default function Settings({ entry, currentUserRoles }: SettingsProps) { const [selectedCategory, setSelectedCategory] = useState(SettingsCategory.DETAILS) - const [isReadOnly, requiredRolesText] = useMemo(() => { + useEffect(() => { const validRoles = ['owner'] - return [!hasRole(currentUserRoles, validRoles), getRequiredRolesText(currentUserRoles, validRoles)] - }, [currentUserRoles]) + if (!hasRole(currentUserRoles, validRoles)) { + const { category: _category, ...filteredQuery } = router.query + router.replace({ + query: { ...filteredQuery, tab: 'overview' }, + }) + } + }, [currentUserRoles, router]) useEffect(() => { if (isSettingsCategory(category, entry, uiConfig)) { @@ -146,24 +151,12 @@ export default function Settings({ entry, currentUserRoles }: SettingsProps) { )} - {selectedCategory === SettingsCategory.DETAILS && ( - - )} - {selectedCategory === SettingsCategory.PERMISSIONS && ( - - )} - {selectedCategory === SettingsCategory.ACCESS_REQUESTS && ( - - )} - {selectedCategory === SettingsCategory.TEMPLATING && ( - - )} - {selectedCategory === SettingsCategory.MIRRORED_MODELS && ( - - )} - {selectedCategory === SettingsCategory.DANGER && ( - - )} + {selectedCategory === SettingsCategory.DETAILS && } + {selectedCategory === SettingsCategory.PERMISSIONS && } + {selectedCategory === SettingsCategory.ACCESS_REQUESTS && } + {selectedCategory === SettingsCategory.TEMPLATING && } + {selectedCategory === SettingsCategory.MIRRORED_MODELS && } + {selectedCategory === SettingsCategory.DANGER && } ) From dec7df9fce1fc5ab5ebb688688e78aa7fb494f3c Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Thu, 8 Aug 2024 13:12:13 +0000 Subject: [PATCH 08/12] Changes per PR review --- frontend/src/entry/EntityIcon.tsx | 13 ++++ frontend/src/entry/EntityNameDisplay.tsx | 20 ++++++ .../model/settings/AccessRequestSettings.tsx | 22 +++---- .../entry/overview/EntryCardEntityRoleRow.tsx | 35 +++-------- .../entry/overview/EntryCardRolesChipSet.tsx | 18 ++---- .../entry/overview/EntryCardRolesDialog.tsx | 22 ------- frontend/src/entry/overview/EntryRoleList.tsx | 62 +++++++++++++++---- .../src/entry/overview/EntryRolesDialog.tsx | 22 +++++++ .../entry/overview/ExportEntryCardDialog.tsx | 3 +- frontend/src/entry/overview/FormEditPage.tsx | 10 +-- frontend/src/entry/settings/EntityItem.tsx | 51 +++++---------- .../src/entry/settings/EntryAccessTab.tsx | 8 +-- 12 files changed, 154 insertions(+), 132 deletions(-) create mode 100644 frontend/src/entry/EntityIcon.tsx create mode 100644 frontend/src/entry/EntityNameDisplay.tsx delete mode 100644 frontend/src/entry/overview/EntryCardRolesDialog.tsx create mode 100644 frontend/src/entry/overview/EntryRolesDialog.tsx diff --git a/frontend/src/entry/EntityIcon.tsx b/frontend/src/entry/EntityIcon.tsx new file mode 100644 index 000000000..cc5f6d118 --- /dev/null +++ b/frontend/src/entry/EntityIcon.tsx @@ -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 ? : +} diff --git a/frontend/src/entry/EntityNameDisplay.tsx b/frontend/src/entry/EntityNameDisplay.tsx new file mode 100644 index 000000000..59c1a462e --- /dev/null +++ b/frontend/src/entry/EntityNameDisplay.tsx @@ -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 ? ( + + ) : ( + {entryCollaboratorName} + ) +} diff --git a/frontend/src/entry/model/settings/AccessRequestSettings.tsx b/frontend/src/entry/model/settings/AccessRequestSettings.tsx index 32aff58c4..a68372048 100644 --- a/frontend/src/entry/model/settings/AccessRequestSettings.tsx +++ b/frontend/src/entry/model/settings/AccessRequestSettings.tsx @@ -46,18 +46,16 @@ export default function AccessRequestSettings({ model }: AccessRequestSettingsPr Manage access requests -
- setAllowUngoverned(event.target.checked)} - checked={allowUngoverned} - size='small' - /> - } - /> -
+ setAllowUngoverned(event.target.checked)} + checked={allowUngoverned} + size='small' + /> + } + />
( - + return entryCollaborators.map((collaborator) => ( + - - + + - + )) } - -type EntryCollaboratorProps = { - entity: CollaboratorEntry -} - -function EntryCollaboratorIcon({ entity }: EntryCollaboratorProps) { - const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity]) - return isUser ? : -} - -function EntryCollaboratorName({ entity }: EntryCollaboratorProps) { - const entityName = useMemo(() => entity.entity.split('/').pop()!, [entity]) - return ( - <> - - - ) -} diff --git a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx b/frontend/src/entry/overview/EntryCardRolesChipSet.tsx index 36ae4c9b3..5167532a8 100644 --- a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx +++ b/frontend/src/entry/overview/EntryCardRolesChipSet.tsx @@ -1,5 +1,5 @@ -import Dangerous from '@mui/icons-material/DangerousOutlined' import { Chip } from '@mui/material' +import { useMemo } from 'react' import { CollaboratorEntry } from 'types/types' type EntryCardChipSetProps = { @@ -7,16 +7,10 @@ type EntryCardChipSetProps = { } export default function EntryCardRolesChipSet({ entryCollaborator }: EntryCardChipSetProps) { - return entryCollaborator.roles.length === 0 ? ( - } - label='No Roles' - /> - ) : ( - entryCollaborator.roles.map((role) => { - return - }) + const roleChips = useMemo( + () => entryCollaborator.roles.map((role) => ), + [entryCollaborator.roles], ) + + return roleChips.length ? roleChips : } diff --git a/frontend/src/entry/overview/EntryCardRolesDialog.tsx b/frontend/src/entry/overview/EntryCardRolesDialog.tsx deleted file mode 100644 index e7fbc15b2..000000000 --- a/frontend/src/entry/overview/EntryCardRolesDialog.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { 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 EntryCardRoleDialogProps = { - entry: EntryInterface - open: boolean - setOpen: (isOpen: boolean) => void -} - -export default function EntryCardRolesDialog({ entry, open, setOpen }: EntryCardRoleDialogProps) { - return ( - <> - setOpen(false)} fullWidth maxWidth='sm' TransitionComponent={Transition}> - Roles - - - - ) -} diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx index c09fb5254..74ac4d122 100644 --- a/frontend/src/entry/overview/EntryRoleList.tsx +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -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) => ( + + + + + + + + + + + + )), + [entry.collaborators], + ) + return ( - <> - - - Entity - - - Roles - - + + + Entity + + + Roles + {rows} + + ) +} + +type EntryCollaboratorProps = { + entryCollaborator: CollaboratorEntry +} + +function EntryCollaboratorIcon({ entryCollaborator }: EntryCollaboratorProps) { + const isUser = useMemo(() => entryCollaborator.entity.startsWith('user:'), [entryCollaborator]) + return isUser ? : +} + +function EntryCollaboratorName({ entryCollaborator }: EntryCollaboratorProps) { + const entityName = useMemo(() => entryCollaborator.entity.split('/').pop()!, [entryCollaborator]) + return ( + <> + ) } diff --git a/frontend/src/entry/overview/EntryRolesDialog.tsx b/frontend/src/entry/overview/EntryRolesDialog.tsx new file mode 100644 index 000000000..8a0d2f32d --- /dev/null +++ b/frontend/src/entry/overview/EntryRolesDialog.tsx @@ -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 ( + + Roles + + + + + ) +} diff --git a/frontend/src/entry/overview/ExportEntryCardDialog.tsx b/frontend/src/entry/overview/ExportEntryCardDialog.tsx index 8292acbae..c8179d497 100644 --- a/frontend/src/entry/overview/ExportEntryCardDialog.tsx +++ b/frontend/src/entry/overview/ExportEntryCardDialog.tsx @@ -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' @@ -60,7 +61,7 @@ export default function ExportEntryCardDialog({ entry, splitSchema, open, setOpe }, [splitSchema.steps]) return ( - setOpen(false)} fullWidth maxWidth='md'> + setOpen(false)} fullWidth maxWidth='md' TransitionComponent={Transition}> }> diff --git a/frontend/src/entry/overview/FormEditPage.tsx b/frontend/src/entry/overview/FormEditPage.tsx index c98f414ab..6676f6644 100644 --- a/frontend/src/entry/overview/FormEditPage.tsx +++ b/frontend/src/entry/overview/FormEditPage.tsx @@ -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' @@ -140,12 +140,12 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false
{!isEdit && ( - + @@ -188,7 +188,7 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false )} - + setRolesDialogOpen(false)} /> setJsonUploadDialogOpen(false)} diff --git a/frontend/src/entry/settings/EntityItem.tsx b/frontend/src/entry/settings/EntityItem.tsx index c82d5055c..388b41f12 100644 --- a/frontend/src/entry/settings/EntityItem.tsx +++ b/frontend/src/entry/settings/EntityItem.tsx @@ -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 = { @@ -41,8 +40,8 @@ export default function EntityItem({ entity, accessList, onAccessListChange, ent - - + + @@ -66,36 +65,16 @@ export default function EntityItem({ entity, accessList, onAccessListChange, ent )} - - - + + + + + ) } - -type EntityIconProps = { - entity: CollaboratorEntry -} - -function EntityIcon({ entity }: EntityIconProps) { - const isUser = useMemo(() => entity.entity.startsWith('user:'), [entity]) - return isUser ? : -} - -type EntityNameDisplayProps = { - entity: CollaboratorEntry -} - -function EntityNameDisplay({ entity }: EntityNameDisplayProps) { - const [entityKind, entityName] = useMemo(() => entity.entity.split(':'), [entity]) - return entityKind === EntityKind.USER || entityKind === EntityKind.GROUP ? ( - - ) : ( - {entityName} - ) -} diff --git a/frontend/src/entry/settings/EntryAccessTab.tsx b/frontend/src/entry/settings/EntryAccessTab.tsx index 5b8915c16..c5c978e19 100644 --- a/frontend/src/entry/settings/EntryAccessTab.tsx +++ b/frontend/src/entry/settings/EntryAccessTab.tsx @@ -69,11 +69,9 @@ export default function EntryAccessTab({ entry }: EntryAccessTabProps) { entryKind={entry.kind} entryRoles={entryRoles} /> -
- - Save - -
+ + Save +
) From 5873cf6b9cd1c1308144ee2c5b2dd12415d34a43 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:18:47 +0000 Subject: [PATCH 09/12] Changes per PR --- .../entry/overview/EntryCardEntityRoleRow.tsx | 26 ------------- frontend/src/entry/overview/EntryRoleList.tsx | 37 +++++-------------- ...RolesChipSet.tsx => EntryRolesChipSet.tsx} | 4 +- .../src/entry/overview/EntryRolesDialog.tsx | 4 +- 4 files changed, 13 insertions(+), 58 deletions(-) delete mode 100644 frontend/src/entry/overview/EntryCardEntityRoleRow.tsx rename frontend/src/entry/overview/{EntryCardRolesChipSet.tsx => EntryRolesChipSet.tsx} (77%) diff --git a/frontend/src/entry/overview/EntryCardEntityRoleRow.tsx b/frontend/src/entry/overview/EntryCardEntityRoleRow.tsx deleted file mode 100644 index 12ebbb48f..000000000 --- a/frontend/src/entry/overview/EntryCardEntityRoleRow.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Grid, Stack } from '@mui/material' -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' - -type EntryCardEntityRoleRowProps = { - entryCollaborators: CollaboratorEntry[] -} - -export default function EntryCardEntityRoleRow({ entryCollaborators }: EntryCardEntityRoleRowProps) { - return entryCollaborators.map((collaborator) => ( - - - - - - - - - - - - )) -} diff --git a/frontend/src/entry/overview/EntryRoleList.tsx b/frontend/src/entry/overview/EntryRoleList.tsx index 74ac4d122..9489b2c5c 100644 --- a/frontend/src/entry/overview/EntryRoleList.tsx +++ b/frontend/src/entry/overview/EntryRoleList.tsx @@ -1,28 +1,27 @@ -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' +import EntityIcon from 'src/entry/EntityIcon' +import EntityNameDisplay from 'src/entry/EntityNameDisplay' +import EntryRolesChipSet from 'src/entry/overview/EntryRolesChipSet' +import { EntryInterface } from 'types/types' -type EntryCardRoleDialogProps = { +type EntryRoleListProps = { entry: EntryInterface } -export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { +export default function EntryRoleList({ entry }: EntryRoleListProps) { const rows = useMemo( () => entry.collaborators.map((collaborator) => ( - - + + - + )), @@ -41,21 +40,3 @@ export default function EntryRoleList({ entry }: EntryCardRoleDialogProps) { ) } - -type EntryCollaboratorProps = { - entryCollaborator: CollaboratorEntry -} - -function EntryCollaboratorIcon({ entryCollaborator }: EntryCollaboratorProps) { - const isUser = useMemo(() => entryCollaborator.entity.startsWith('user:'), [entryCollaborator]) - return isUser ? : -} - -function EntryCollaboratorName({ entryCollaborator }: EntryCollaboratorProps) { - const entityName = useMemo(() => entryCollaborator.entity.split('/').pop()!, [entryCollaborator]) - return ( - <> - - - ) -} diff --git a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx b/frontend/src/entry/overview/EntryRolesChipSet.tsx similarity index 77% rename from frontend/src/entry/overview/EntryCardRolesChipSet.tsx rename to frontend/src/entry/overview/EntryRolesChipSet.tsx index 5167532a8..0bac129ce 100644 --- a/frontend/src/entry/overview/EntryCardRolesChipSet.tsx +++ b/frontend/src/entry/overview/EntryRolesChipSet.tsx @@ -2,11 +2,11 @@ import { Chip } from '@mui/material' import { useMemo } from 'react' import { CollaboratorEntry } from 'types/types' -type EntryCardChipSetProps = { +type EntryRolesChipSetProps = { entryCollaborator: CollaboratorEntry } -export default function EntryCardRolesChipSet({ entryCollaborator }: EntryCardChipSetProps) { +export default function EntryRolesChipSet({ entryCollaborator }: EntryRolesChipSetProps) { const roleChips = useMemo( () => entryCollaborator.roles.map((role) => ), [entryCollaborator.roles], diff --git a/frontend/src/entry/overview/EntryRolesDialog.tsx b/frontend/src/entry/overview/EntryRolesDialog.tsx index 8a0d2f32d..e94e63390 100644 --- a/frontend/src/entry/overview/EntryRolesDialog.tsx +++ b/frontend/src/entry/overview/EntryRolesDialog.tsx @@ -4,13 +4,13 @@ import { Transition } from 'src/common/Transition' import EntryRoleList from 'src/entry/overview/EntryRoleList' import { EntryInterface } from 'types/types' -type EntryRoleDialogProps = { +type EntryRolesDialogProps = { entry: EntryInterface open: boolean onClose: () => void } -export default function EntryRolesDialog({ entry, open, onClose }: EntryRoleDialogProps) { +export default function EntryRolesDialog({ entry, open, onClose }: EntryRolesDialogProps) { return ( Roles From a9bd477c9a2760977eb2e8e3073a2f011f3fd4ba Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Mon, 12 Aug 2024 08:40:00 +0000 Subject: [PATCH 10/12] Corrected import --- frontend/src/entry/overview/FormEditPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/entry/overview/FormEditPage.tsx b/frontend/src/entry/overview/FormEditPage.tsx index 6676f6644..ffa7776b2 100644 --- a/frontend/src/entry/overview/FormEditPage.tsx +++ b/frontend/src/entry/overview/FormEditPage.tsx @@ -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/EntryRolesDialog' +import EntryRolesDialog 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' @@ -188,7 +188,7 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false )} - setRolesDialogOpen(false)} /> + setRolesDialogOpen(false)} /> setJsonUploadDialogOpen(false)} From fbffeebb1bd0bedc915cd0b28039d92806e2e130 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:35:47 +0000 Subject: [PATCH 11/12] Change per PR, forgot to commit earlier --- frontend/src/entry/overview/FormEditPage.tsx | 93 ++++++++++++++------ 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/frontend/src/entry/overview/FormEditPage.tsx b/frontend/src/entry/overview/FormEditPage.tsx index ffa7776b2..2d9c351b1 100644 --- a/frontend/src/entry/overview/FormEditPage.tsx +++ b/frontend/src/entry/overview/FormEditPage.tsx @@ -1,14 +1,17 @@ -import { Box, Button, Stack, Tooltip, Typography } from '@mui/material' +import EditIcon from '@mui/icons-material/Edit' +import HistoryIcon from '@mui/icons-material/History' +import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf' +import { Box, Button, ListItemIcon, ListItemText, Menu, MenuItem, Stack, Tooltip, Typography } from '@mui/material' import { useGetModel } from 'actions/model' import { putModelCard, useGetModelCardRevisions } from 'actions/modelCard' import { useGetSchema } from 'actions/schema' +import React from 'react' import { useContext, useEffect, useMemo, useState } from 'react' import CopyToClipboardButton from 'src/common/CopyToClipboardButton' 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 EntryRolesDialog 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' @@ -32,11 +35,20 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false const { schema, isSchemaLoading, isSchemaError } = useGetSchema(entry.card.schemaId) const { isModelError: isEntryError, mutateModel: mutateEntry } = useGetModel(entry.id, entry.kind) const { mutateModelCardRevisions: mutateEntryCardRevisions } = useGetModelCardRevisions(entry.id) - const [rolesDialogOpen, setRolesDialogOpen] = useState(false) const [historyDialogOpen, setHistoryDialogOpen] = useState(false) const [exportDialogOpen, setExportDialogOpen] = useState(false) const [jsonUploadDialogOpen, setJsonUploadDialogOpen] = useState(false) const [loading, setLoading] = useState(false) + const [anchorEl, setAnchorEl] = React.useState(null) + const open = Boolean(anchorEl) + + function handleActionButtonClick(event: React.MouseEvent) { + setAnchorEl(event.currentTarget) + } + + const handleActionButtonClose = () => { + setAnchorEl(null) + } const sendNotification = useNotification() const { setUnsavedChanges } = useContext(UnsavedChangesContext) @@ -139,31 +151,57 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false
{!isEdit && ( - - - - - {!readOnly && ( - - - - - - )} - + + + + + + { + handleActionButtonClose() + setExportDialogOpen(true) + }} + > + Export as PDF + + + + + + + { + handleActionButtonClose() + setHistoryDialogOpen(true) + }} + > + View History + + + {!readOnly && ( + + + + + + { + handleActionButtonClose() + setIsEdit(!isEdit) + }} + data-test='editEntryCardButton' + > + {`Edit ${EntryCardKindLabel[entry.kind]}`} + + + + )} + + )} {isEdit && ( - setRolesDialogOpen(false)} /> setJsonUploadDialogOpen(false)} From 7d60eb8fc2677fdbf54f0d718a0c7d14585cb5a4 Mon Sep 17 00:00:00 2001 From: IR96334 <175131971+IR96334@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:51:45 +0000 Subject: [PATCH 12/12] Revert to previous commit as 2 branches were accidentally combined --- frontend/src/entry/overview/FormEditPage.tsx | 108 +++++-------------- 1 file changed, 28 insertions(+), 80 deletions(-) diff --git a/frontend/src/entry/overview/FormEditPage.tsx b/frontend/src/entry/overview/FormEditPage.tsx index 2d9c351b1..14cb04ad9 100644 --- a/frontend/src/entry/overview/FormEditPage.tsx +++ b/frontend/src/entry/overview/FormEditPage.tsx @@ -1,17 +1,14 @@ -import EditIcon from '@mui/icons-material/Edit' -import HistoryIcon from '@mui/icons-material/History' -import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf' -import { Box, Button, ListItemIcon, ListItemText, Menu, MenuItem, Stack, Tooltip, Typography } from '@mui/material' +import { Box, Button, Stack, Tooltip, Typography } from '@mui/material' import { useGetModel } from 'actions/model' import { putModelCard, useGetModelCardRevisions } from 'actions/modelCard' import { useGetSchema } from 'actions/schema' -import React from 'react' import { useContext, useEffect, useMemo, useState } from 'react' import CopyToClipboardButton from 'src/common/CopyToClipboardButton' 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 EntryRolesDialog 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' @@ -20,44 +17,29 @@ import MessageAlert from 'src/MessageAlert' import { EntryCardKindLabel, EntryInterface, SplitSchemaNoRender } from 'types/types' import { getStepsData, getStepsFromSchema } from 'utils/formUtils' import { getRequiredRolesText, hasRole } from 'utils/roles' - type FormEditPageProps = { entry: EntryInterface readOnly?: boolean currentUserRoles: string[] } - export default function FormEditPage({ entry, currentUserRoles, readOnly = false }: FormEditPageProps) { const [isEdit, setIsEdit] = useState(false) const [splitSchema, setSplitSchema] = useState({ reference: '', steps: [] }) const [errorMessage, setErrorMessage] = useState('') - const { schema, isSchemaLoading, isSchemaError } = useGetSchema(entry.card.schemaId) const { isModelError: isEntryError, mutateModel: mutateEntry } = useGetModel(entry.id, entry.kind) const { mutateModelCardRevisions: mutateEntryCardRevisions } = useGetModelCardRevisions(entry.id) + const [rolesDialogOpen, setRolesDialogOpen] = useState(false) const [historyDialogOpen, setHistoryDialogOpen] = useState(false) const [exportDialogOpen, setExportDialogOpen] = useState(false) const [jsonUploadDialogOpen, setJsonUploadDialogOpen] = useState(false) const [loading, setLoading] = useState(false) - const [anchorEl, setAnchorEl] = React.useState(null) - const open = Boolean(anchorEl) - - function handleActionButtonClick(event: React.MouseEvent) { - setAnchorEl(event.currentTarget) - } - - const handleActionButtonClose = () => { - setAnchorEl(null) - } - const sendNotification = useNotification() const { setUnsavedChanges } = useContext(UnsavedChangesContext) - const [canEdit, requiredRolesText] = useMemo(() => { const validRoles = ['owner', 'contributor'] return [hasRole(currentUserRoles, validRoles), getRequiredRolesText(currentUserRoles, validRoles)] }, [currentUserRoles]) - async function onSubmit() { if (schema) { setErrorMessage('') @@ -73,7 +55,6 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false setLoading(false) } } - function onCancel() { if (schema) { mutateEntry() @@ -85,23 +66,18 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false setIsEdit(false) } } - useEffect(() => { if (!entry || !schema) return const metadata = entry.card.metadata const steps = getStepsFromSchema(schema, {}, ['properties.contacts'], metadata) - for (const step of steps) { step.steps = steps } - setSplitSchema({ reference: schema.id, steps }) }, [schema, entry]) - useEffect(() => { setUnsavedChanges(isEdit) }, [isEdit, setUnsavedChanges]) - function handleJsonFormOnSubmit(formData: string) { setJsonUploadDialogOpen(false) try { @@ -120,15 +96,12 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false }) } } - if (isSchemaError) { return } - if (isEntryError) { return } - return ( <> {isSchemaLoading && } @@ -151,57 +124,31 @@ export default function FormEditPage({ entry, currentUserRoles, readOnly = false {!isEdit && ( - <> - + - - - - - - { - handleActionButtonClose() - setExportDialogOpen(true) - }} - > - Export as PDF - - - - - - - { - handleActionButtonClose() - setHistoryDialogOpen(true) - }} - > - View History - - - {!readOnly && ( - - - - - - { - handleActionButtonClose() - setIsEdit(!isEdit) - }} - data-test='editEntryCardButton' - > - {`Edit ${EntryCardKindLabel[entry.kind]}`} - - - - )} - - + + {!readOnly && ( + + + + + + )} + )} {isEdit && ( + setRolesDialogOpen(false)} /> setJsonUploadDialogOpen(false)}