1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: delete features FE (#3350)

This commit is contained in:
Jaanus Sellin 2023-03-21 10:45:02 +02:00 committed by GitHub
parent 8a03e5526c
commit 076768215e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 19 deletions

View File

@ -1,12 +1,16 @@
import { FC } from 'react'; import { FC, useState } from 'react';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import { Undo } from '@mui/icons-material'; import { Undo } from '@mui/icons-material';
import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions'; import {
DELETE_FEATURE,
UPDATE_FEATURE,
} from 'component/providers/AccessProvider/permissions';
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
import { formatUnknownError } from 'utils/formatUnknownError'; import { formatUnknownError } from 'utils/formatUnknownError';
import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive'; import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm';
interface IArchiveBatchActionsProps { interface IArchiveBatchActionsProps {
selectedIds: string[]; selectedIds: string[];
@ -20,6 +24,7 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
const { reviveFeatures } = useProjectApi(); const { reviveFeatures } = useProjectApi();
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const { refetchArchived } = useFeaturesArchive(projectId); const { refetchArchived } = useFeaturesArchive(projectId);
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const onRevive = async () => { const onRevive = async () => {
try { try {
@ -34,6 +39,10 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
} }
}; };
const onDelete = async () => {
setDeleteModalOpen(true);
};
return ( return (
<> <>
<PermissionHOC projectId={projectId} permission={UPDATE_FEATURE}> <PermissionHOC projectId={projectId} permission={UPDATE_FEATURE}>
@ -49,6 +58,26 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
</Button> </Button>
)} )}
</PermissionHOC> </PermissionHOC>
<PermissionHOC projectId={projectId} permission={DELETE_FEATURE}>
{({ hasAccess }) => (
<Button
disabled={!hasAccess}
startIcon={<Undo />}
variant="outlined"
size="small"
onClick={onDelete}
>
Delete
</Button>
)}
</PermissionHOC>
<ArchivedFeatureDeleteConfirm
deletedFeatures={selectedIds}
projectId={projectId}
open={deleteModalOpen}
setOpen={setDeleteModalOpen}
refetch={refetchArchived}
/>
</> </>
); );
}; };

View File

@ -341,7 +341,8 @@ export const ArchiveTable = ({
)} )}
/> />
<ArchivedFeatureDeleteConfirm <ArchivedFeatureDeleteConfirm
deletedFeature={deletedFeature} deletedFeatures={[deletedFeature?.name!]}
projectId={projectId!}
open={deleteModalOpen} open={deleteModalOpen}
setOpen={setDeleteModalOpen} setOpen={setDeleteModalOpen}
refetch={refetch} refetch={refetch}

View File

@ -2,13 +2,13 @@ import { Alert, styled } from '@mui/material';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Dialogue } from 'component/common/Dialogue/Dialogue'; import { Dialogue } from 'component/common/Dialogue/Dialogue';
import Input from 'component/common/Input/Input'; import Input from 'component/common/Input/Input';
import { IFeatureToggle } from 'interfaces/featureToggle';
import { formatUnknownError } from 'utils/formatUnknownError'; import { formatUnknownError } from 'utils/formatUnknownError';
import { useFeatureArchiveApi } from 'hooks/api/actions/useFeatureArchiveApi/useReviveFeatureApi';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
interface IArchivedFeatureDeleteConfirmProps { interface IArchivedFeatureDeleteConfirmProps {
deletedFeature?: IFeatureToggle; deletedFeatures: string[];
projectId: string;
open: boolean; open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>; setOpen: React.Dispatch<React.SetStateAction<boolean>>;
refetch: () => void; refetch: () => void;
@ -23,27 +23,32 @@ const StyledFormInput = styled(Input)(({ theme }) => ({
width: '100%', width: '100%',
})); }));
const confirmationText = 'I want to delete';
export const ArchivedFeatureDeleteConfirm = ({ export const ArchivedFeatureDeleteConfirm = ({
deletedFeature, deletedFeatures,
projectId,
open, open,
setOpen, setOpen,
refetch, refetch,
}: IArchivedFeatureDeleteConfirmProps) => { }: IArchivedFeatureDeleteConfirmProps) => {
const [confirmName, setConfirmName] = useState(''); const [confirmName, setConfirmName] = useState('');
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const { deleteFeature } = useFeatureArchiveApi(); const { deleteFeatures } = useProjectApi();
const onDeleteFeatureToggle = async () => { const onDeleteFeatureToggle = async () => {
try { try {
if (!deletedFeature) { if (deletedFeatures.length === 0) {
return; return;
} }
await deleteFeature(deletedFeature.name); await deleteFeatures(projectId, deletedFeatures);
await refetch(); await refetch();
setToastData({ setToastData({
type: 'success', type: 'success',
title: 'Feature toggle deleted', title: 'Feature toggles deleted',
text: `You have successfully deleted the ${deletedFeature.name} feature toggle.`, text: `You have successfully deleted following features toggles: ${deletedFeatures.join(
', '
)}.`,
}); });
} catch (error: unknown) { } catch (error: unknown) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
@ -61,13 +66,13 @@ export const ArchivedFeatureDeleteConfirm = ({
return ( return (
<Dialogue <Dialogue
title="Delete feature toggle?" title="Delete feature toggles?"
open={open} open={open}
primaryButtonText="Delete feature toggle" primaryButtonText="Delete feature toggles"
secondaryButtonText="Cancel" secondaryButtonText="Cancel"
onClick={onDeleteFeatureToggle} onClick={onDeleteFeatureToggle}
onClose={clearModal} onClose={clearModal}
disabledPrimaryButton={deletedFeature?.name !== confirmName} disabledPrimaryButton={confirmationText !== confirmName}
formId={formId} formId={formId}
> >
<Alert severity="warning"> <Alert severity="warning">
@ -78,8 +83,9 @@ export const ArchivedFeatureDeleteConfirm = ({
</Alert> </Alert>
<StyledDeleteParagraph> <StyledDeleteParagraph>
In order to delete this feature toggle, please enter its name in In order to delete feature toggles, please enter the following
the text field below: <strong>{deletedFeature?.name}</strong> confirmation text in the text field below:{' '}
<strong>I want to delete</strong>
</StyledDeleteParagraph> </StyledDeleteParagraph>
<form id={formId}> <form id={formId}>
@ -89,8 +95,8 @@ export const ArchivedFeatureDeleteConfirm = ({
setConfirmName(e.currentTarget.value); setConfirmName(e.currentTarget.value);
}} }}
value={confirmName} value={confirmName}
placeholder="<feature toggle name>" placeholder="<deletion confirmation>"
label="Feature toggle name" label="Deletetion confirmation"
/> />
</form> </form>
</Dialogue> </Dialogue>

View File

@ -223,6 +223,16 @@ const useProjectApi = () => {
return makeRequest(req.caller, req.id); return makeRequest(req.caller, req.id);
}; };
const deleteFeatures = async (projectId: string, featureIds: string[]) => {
const path = `api/admin/projects/${projectId}/delete`;
const req = createRequest(path, {
method: 'POST',
body: JSON.stringify({ features: featureIds }),
});
return makeRequest(req.caller, req.id);
};
const staleFeatures = async ( const staleFeatures = async (
projectId: string, projectId: string,
featureIds: string[], featureIds: string[],
@ -257,6 +267,7 @@ const useProjectApi = () => {
archiveFeatures, archiveFeatures,
reviveFeatures, reviveFeatures,
staleFeatures, staleFeatures,
deleteFeatures,
searchProjectUser, searchProjectUser,
errors, errors,
loading, loading,