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:
parent
8a03e5526c
commit
076768215e
@ -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}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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}
|
||||||
|
@ -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>
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user