mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-28 17:55:15 +02:00
feat: UI for archiving release templates (#9415)
This commit is contained in:
parent
065fd4b469
commit
f6bb94addf
@ -16,11 +16,13 @@ import { useReleasePlanTemplatesApi } from 'hooks/api/actions/useReleasePlanTemp
|
|||||||
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
|
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { TemplateDeleteDialog } from '../TemplateDeleteDialog';
|
import { TemplateArchiveDialog } from '../TemplateArchiveDialog';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||||
|
import { RELEASE_PLAN_TEMPLATE_DELETE } from '@server/types/permissions';
|
||||||
|
import { useHasRootAccess } from 'hooks/useHasAccess';
|
||||||
|
|
||||||
const StyledActions = styled('div')(({ theme }) => ({
|
const StyledActions = styled('div')(({ theme }) => ({
|
||||||
margin: theme.spacing(-1),
|
margin: theme.spacing(-1),
|
||||||
@ -39,30 +41,31 @@ export const ReleasePlanTemplateCardActions = ({
|
|||||||
template,
|
template,
|
||||||
}: { template: IReleasePlanTemplate }) => {
|
}: { template: IReleasePlanTemplate }) => {
|
||||||
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
|
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
|
||||||
const { deleteReleasePlanTemplate } = useReleasePlanTemplatesApi();
|
const { archiveReleasePlanTemplate } = useReleasePlanTemplatesApi();
|
||||||
const { refetch } = useReleasePlanTemplates();
|
const { refetch } = useReleasePlanTemplates();
|
||||||
const { setToastData, setToastApiError } = useToast();
|
const { setToastData, setToastApiError } = useToast();
|
||||||
const { trackEvent } = usePlausibleTracker();
|
const { trackEvent } = usePlausibleTracker();
|
||||||
const [deleteOpen, setDeleteOpen] = useState(false);
|
const [archiveOpen, setArchiveOpen] = useState(false);
|
||||||
const deleteReleasePlan = useCallback(async () => {
|
const hasArchivePermission = useHasRootAccess(RELEASE_PLAN_TEMPLATE_DELETE);
|
||||||
|
const archiveReleasePlan = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await deleteReleasePlanTemplate(template.id);
|
await archiveReleasePlanTemplate(template.id);
|
||||||
refetch();
|
refetch();
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
text: 'Release plan template deleted',
|
text: 'Release plan template archived',
|
||||||
});
|
});
|
||||||
|
|
||||||
trackEvent('release-management', {
|
trackEvent('release-management', {
|
||||||
props: {
|
props: {
|
||||||
eventType: 'delete-template',
|
eventType: 'archive-template',
|
||||||
template: template.name,
|
template: template.name,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
setToastApiError(formatUnknownError(error));
|
setToastApiError(formatUnknownError(error));
|
||||||
}
|
}
|
||||||
}, [setToastApiError, refetch, setToastData, deleteReleasePlanTemplate]);
|
}, [setToastApiError, refetch, setToastData, archiveReleasePlanTemplate]);
|
||||||
|
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
@ -121,26 +124,27 @@ export const ReleasePlanTemplateCardActions = ({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteOpen(true);
|
setArchiveOpen(true);
|
||||||
handleClose();
|
handleClose();
|
||||||
}}
|
}}
|
||||||
|
disabled={!hasArchivePermission}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<Typography variant='body2'>
|
<Typography variant='body2'>
|
||||||
Delete template
|
Archive template
|
||||||
</Typography>
|
</Typography>
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</StyledPopover>
|
</StyledPopover>
|
||||||
<TemplateDeleteDialog
|
<TemplateArchiveDialog
|
||||||
template={template}
|
template={template}
|
||||||
open={deleteOpen}
|
open={archiveOpen}
|
||||||
setOpen={setDeleteOpen}
|
setOpen={setArchiveOpen}
|
||||||
onConfirm={deleteReleasePlan}
|
onConfirm={archiveReleasePlan}
|
||||||
/>
|
/>
|
||||||
</StyledActions>
|
</StyledActions>
|
||||||
);
|
);
|
||||||
|
@ -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<React.SetStateAction<boolean>>;
|
||||||
|
onConfirm: (template: IReleasePlanTemplate) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TemplateArchiveDialog: React.FC<ITemplateArchiveDialogProps> = ({
|
||||||
|
template,
|
||||||
|
open,
|
||||||
|
setOpen,
|
||||||
|
onConfirm,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Dialogue
|
||||||
|
title='Archive release plan template?'
|
||||||
|
open={open}
|
||||||
|
secondaryButtonText='Cancel'
|
||||||
|
onClose={() => {
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
permissionButton={
|
||||||
|
<PermissionButton
|
||||||
|
variant='contained'
|
||||||
|
onClick={() => onConfirm(template!)}
|
||||||
|
permission={RELEASE_PLAN_TEMPLATE_DELETE}
|
||||||
|
>
|
||||||
|
Archive template
|
||||||
|
</PermissionButton>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
You are about to archive release plan template:{' '}
|
||||||
|
<strong>{template?.name}</strong>
|
||||||
|
</p>
|
||||||
|
</Dialogue>
|
||||||
|
);
|
||||||
|
};
|
@ -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<React.SetStateAction<boolean>>;
|
|
||||||
onConfirm: (template: IReleasePlanTemplate) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TemplateDeleteDialog: React.FC<ITemplateDeleteDialogProps> = ({
|
|
||||||
template,
|
|
||||||
open,
|
|
||||||
setOpen,
|
|
||||||
onConfirm,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Dialogue
|
|
||||||
title='Delete release plan template?'
|
|
||||||
open={open}
|
|
||||||
primaryButtonText='Delete template'
|
|
||||||
secondaryButtonText='Cancel'
|
|
||||||
onClick={() => onConfirm(template!)}
|
|
||||||
onClose={() => {
|
|
||||||
setOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
You are about to delete release plan template:{' '}
|
|
||||||
<strong>{template?.name}</strong>
|
|
||||||
</p>
|
|
||||||
</Dialogue>
|
|
||||||
);
|
|
||||||
};
|
|
@ -60,10 +60,25 @@ export const useReleasePlanTemplatesApi = () => {
|
|||||||
return makeRequest(req.caller, req.id);
|
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 {
|
return {
|
||||||
deleteReleasePlanTemplate,
|
deleteReleasePlanTemplate,
|
||||||
updateReleasePlanTemplate,
|
updateReleasePlanTemplate,
|
||||||
createReleasePlanTemplate,
|
createReleasePlanTemplate,
|
||||||
|
archiveReleasePlanTemplate,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user