From f6bb94addfcea4edf534ad9f17978e4bdd153897 Mon Sep 17 00:00:00 2001 From: David Leek Date: Wed, 5 Mar 2025 08:08:57 +0100 Subject: [PATCH] feat: UI for archiving release templates (#9415) --- .../ReleasePlanTemplateCardActions.tsx | 32 ++++++++------ .../TemplateArchiveDialog.tsx | 43 +++++++++++++++++++ .../TemplateDeleteDialog.tsx | 34 --------------- .../useReleasePlanTemplatesApi.ts | 15 +++++++ 4 files changed, 76 insertions(+), 48 deletions(-) create mode 100644 frontend/src/component/releases/ReleaseManagement/TemplateArchiveDialog.tsx delete mode 100644 frontend/src/component/releases/ReleaseManagement/TemplateDeleteDialog.tsx diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx index b056a66269..e182528ab2 100644 --- a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx +++ b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx @@ -16,11 +16,13 @@ import { useReleasePlanTemplatesApi } from 'hooks/api/actions/useReleasePlanTemp import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates'; import useToast from 'hooks/useToast'; import { formatUnknownError } from 'utils/formatUnknownError'; -import { TemplateDeleteDialog } from '../TemplateDeleteDialog'; +import { TemplateArchiveDialog } from '../TemplateArchiveDialog'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import { Link } from 'react-router-dom'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; +import { RELEASE_PLAN_TEMPLATE_DELETE } from '@server/types/permissions'; +import { useHasRootAccess } from 'hooks/useHasAccess'; const StyledActions = styled('div')(({ theme }) => ({ margin: theme.spacing(-1), @@ -39,30 +41,31 @@ export const ReleasePlanTemplateCardActions = ({ template, }: { template: IReleasePlanTemplate }) => { const [anchorEl, setAnchorEl] = useState(null); - const { deleteReleasePlanTemplate } = useReleasePlanTemplatesApi(); + const { archiveReleasePlanTemplate } = useReleasePlanTemplatesApi(); const { refetch } = useReleasePlanTemplates(); const { setToastData, setToastApiError } = useToast(); const { trackEvent } = usePlausibleTracker(); - const [deleteOpen, setDeleteOpen] = useState(false); - const deleteReleasePlan = useCallback(async () => { + const [archiveOpen, setArchiveOpen] = useState(false); + const hasArchivePermission = useHasRootAccess(RELEASE_PLAN_TEMPLATE_DELETE); + const archiveReleasePlan = useCallback(async () => { try { - await deleteReleasePlanTemplate(template.id); + await archiveReleasePlanTemplate(template.id); refetch(); setToastData({ type: 'success', - text: 'Release plan template deleted', + text: 'Release plan template archived', }); trackEvent('release-management', { props: { - eventType: 'delete-template', + eventType: 'archive-template', template: template.name, }, }); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } - }, [setToastApiError, refetch, setToastData, deleteReleasePlanTemplate]); + }, [setToastApiError, refetch, setToastData, archiveReleasePlanTemplate]); const open = Boolean(anchorEl); const handleClick = (event: React.MouseEvent) => { @@ -121,26 +124,27 @@ export const ReleasePlanTemplateCardActions = ({ { - setDeleteOpen(true); + setArchiveOpen(true); handleClose(); }} + disabled={!hasArchivePermission} > - Delete template + Archive template - ); diff --git a/frontend/src/component/releases/ReleaseManagement/TemplateArchiveDialog.tsx b/frontend/src/component/releases/ReleaseManagement/TemplateArchiveDialog.tsx new file mode 100644 index 0000000000..7fe4bec522 --- /dev/null +++ b/frontend/src/component/releases/ReleaseManagement/TemplateArchiveDialog.tsx @@ -0,0 +1,43 @@ +import { RELEASE_PLAN_TEMPLATE_DELETE } from '@server/types/permissions'; +import { Dialogue } from 'component/common/Dialogue/Dialogue'; +import PermissionButton from 'component/common/PermissionButton/PermissionButton'; +import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; + +interface ITemplateArchiveDialogProps { + template?: IReleasePlanTemplate; + open: boolean; + setOpen: React.Dispatch>; + onConfirm: (template: IReleasePlanTemplate) => void; +} + +export const TemplateArchiveDialog: React.FC = ({ + template, + open, + setOpen, + onConfirm, +}) => { + return ( + { + setOpen(false); + }} + permissionButton={ + onConfirm(template!)} + permission={RELEASE_PLAN_TEMPLATE_DELETE} + > + Archive template + + } + > +

+ You are about to archive release plan template:{' '} + {template?.name} +

+
+ ); +}; diff --git a/frontend/src/component/releases/ReleaseManagement/TemplateDeleteDialog.tsx b/frontend/src/component/releases/ReleaseManagement/TemplateDeleteDialog.tsx deleted file mode 100644 index b08a14bf85..0000000000 --- a/frontend/src/component/releases/ReleaseManagement/TemplateDeleteDialog.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Dialogue } from 'component/common/Dialogue/Dialogue'; -import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; - -interface ITemplateDeleteDialogProps { - template?: IReleasePlanTemplate; - open: boolean; - setOpen: React.Dispatch>; - onConfirm: (template: IReleasePlanTemplate) => void; -} - -export const TemplateDeleteDialog: React.FC = ({ - template, - open, - setOpen, - onConfirm, -}) => { - return ( - onConfirm(template!)} - onClose={() => { - setOpen(false); - }} - > -

- You are about to delete release plan template:{' '} - {template?.name} -

-
- ); -}; diff --git a/frontend/src/hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi.ts b/frontend/src/hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi.ts index 7d85091268..329ca46d6a 100644 --- a/frontend/src/hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi.ts +++ b/frontend/src/hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi.ts @@ -60,10 +60,25 @@ export const useReleasePlanTemplatesApi = () => { return makeRequest(req.caller, req.id); }; + const archiveReleasePlanTemplate = async (templateId: string) => { + const requestId = 'updateReleasePlanTemplate'; + const path = `api/admin/release-plan-templates/archive/${templateId}`; + const req = createRequest( + path, + { + method: 'POST', + }, + requestId, + ); + + return makeRequest(req.caller, req.id); + }; + return { deleteReleasePlanTemplate, updateReleasePlanTemplate, createReleasePlanTemplate, + archiveReleasePlanTemplate, }; };