1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

Delete archived toggles from the front end (#1150)

* Grouping fix grid not showing user names

* Remove deprecated access endpoints

* Manual prettier

* Revert user role update

* Add a way to delete archived toggles from the front end

* Fix layout

* Add project to permissionbutton

* Prettier

* Minor fixes

* Run prettier
This commit is contained in:
sjaanus 2022-07-27 10:46:12 +03:00 committed by GitHub
parent 61c0d6f0a1
commit 00ab52875e
4 changed files with 141 additions and 10 deletions

View File

@ -14,7 +14,7 @@ import { FeatureTypeCell } from 'component/common/Table/cells/FeatureTypeCell/Fe
import { FeatureSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureSeenCell';
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
import { FeatureStaleCell } from 'component/feature/FeatureToggleList/FeatureStaleCell/FeatureStaleCell';
import { ReviveArchivedFeatureCell } from 'component/archive/ArchiveTable/ReviveArchivedFeatureCell/ReviveArchivedFeatureCell';
import { ArchivedFeatureActionCell } from 'component/archive/ArchiveTable/ArchivedFeatureActionCell/ArchivedFeatureActionCell';
import { featuresPlaceholder } from 'component/feature/FeatureToggleList/FeatureToggleListTable';
import theme from 'themes/theme';
import { FeatureSchema } from 'openapi';
@ -24,6 +24,8 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { useSearch } from 'hooks/useSearch';
import { FeatureArchivedCell } from './FeatureArchivedCell/FeatureArchivedCell';
import { useSearchParams } from 'react-router-dom';
import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm';
import { IFeatureToggle } from 'interfaces/featureToggle';
export interface IFeaturesArchiveTableProps {
archivedFeatures: FeatureSchema[];
@ -52,6 +54,9 @@ export const ArchiveTable = ({
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
const { setToastData, setToastApiError } = useToast();
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [deletedFeature, setDeletedFeature] = useState<IFeatureToggle>();
const [searchParams, setSearchParams] = useSearchParams();
const { reviveFeature } = useFeatureArchiveApi();
@ -153,12 +158,16 @@ export const ArchiveTable = ({
Header: 'Actions',
id: 'Actions',
align: 'center',
maxWidth: 85,
maxWidth: 120,
canSort: false,
Cell: ({ row: { original } }: any) => (
<ReviveArchivedFeatureCell
project={original.project}
onRevive={() => onRevive(original.name)}
Cell: ({ row: { original: feature } }: any) => (
<ArchivedFeatureActionCell
project={feature.project}
onRevive={() => onRevive(feature.name)}
onDelete={() => {
setDeletedFeature(feature);
setDeleteModalOpen(true);
}}
/>
),
},
@ -290,6 +299,12 @@ export const ArchiveTable = ({
/>
)}
/>
<ArchivedFeatureDeleteConfirm
deletedFeature={deletedFeature}
open={deleteModalOpen}
setOpen={setDeleteModalOpen}
refetch={refetch}
/>
</PageContent>
);
};

View File

@ -1,16 +1,21 @@
import { VFC } from 'react';
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
import { Undo } from '@mui/icons-material';
import { Delete, Undo } from '@mui/icons-material';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import {
DELETE_FEATURE,
UPDATE_FEATURE,
} from 'component/providers/AccessProvider/permissions';
interface IReviveArchivedFeatureCell {
onRevive: () => void;
onDelete: () => void;
project: string;
}
export const ReviveArchivedFeatureCell: VFC<IReviveArchivedFeatureCell> = ({
export const ArchivedFeatureActionCell: VFC<IReviveArchivedFeatureCell> = ({
onRevive,
onDelete,
project,
}) => {
return (
@ -23,6 +28,14 @@ export const ReviveArchivedFeatureCell: VFC<IReviveArchivedFeatureCell> = ({
>
<Undo />
</PermissionIconButton>
<PermissionIconButton
permission={DELETE_FEATURE}
projectId={project}
tooltipProps={{ title: 'Delete feature toggle' }}
onClick={onDelete}
>
<Delete />
</PermissionIconButton>
</ActionCell>
);
};

View File

@ -0,0 +1,97 @@
import { Alert, styled } from '@mui/material';
import React, { useState } from 'react';
import { Dialogue } from 'component/common/Dialogue/Dialogue';
import Input from 'component/common/Input/Input';
import { IFeatureToggle } from 'interfaces/featureToggle';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useFeatureArchiveApi } from 'hooks/api/actions/useFeatureArchiveApi/useReviveFeatureApi';
import useToast from 'hooks/useToast';
interface IArchivedFeatureDeleteConfirmProps {
deletedFeature?: IFeatureToggle;
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
refetch: () => void;
}
const StyledDeleteParagraph = styled('p')(({ theme }) => ({
marginTop: theme.spacing(4),
}));
const StyledFormInput = styled(Input)(({ theme }) => ({
marginTop: theme.spacing(2),
}));
export const ArchivedFeatureDeleteConfirm = ({
deletedFeature,
open,
setOpen,
refetch,
}: IArchivedFeatureDeleteConfirmProps) => {
const [confirmName, setConfirmName] = useState('');
const { setToastData, setToastApiError } = useToast();
const { deleteFeature } = useFeatureArchiveApi();
const onDeleteFeatureToggle = async () => {
try {
if (!deletedFeature) {
return;
}
await deleteFeature(deletedFeature.name);
await refetch();
setToastData({
type: 'success',
title: 'Feature deleted',
text: `You have successfully deleted the ${deletedFeature.name} feature toggle.`,
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
} finally {
clearModal();
}
};
const clearModal = () => {
setOpen(false);
setConfirmName('');
};
const formId = 'delete-feature-toggle-confirmation-form';
return (
<Dialogue
title="Are you sure you want to delete this feature toggle?"
open={open}
primaryButtonText="Delete feature toggle"
secondaryButtonText="Cancel"
onClick={onDeleteFeatureToggle}
onClose={clearModal}
disabledPrimaryButton={deletedFeature?.name !== confirmName}
formId={formId}
>
<Alert severity="warning">
Warning! To safely delete a feature toggle you might want to
delete the related code in your application first. This ensures
you avoid any errors in case you create a new feature toggle
with the same name in the future.
</Alert>
<StyledDeleteParagraph>
In order to delete this feature toggle, please enter the name of
the toggle in the textfield below:{' '}
<strong>{deletedFeature?.name}</strong>
</StyledDeleteParagraph>
<form id={formId}>
<StyledFormInput
autoFocus
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setConfirmName(e.currentTarget.value);
}}
value={confirmName}
label="Feature toggle name"
/>
</form>
</Dialogue>
);
};

View File

@ -11,5 +11,11 @@ export const useFeatureArchiveApi = () => {
return makeRequest(req.caller, req.id);
};
return { reviveFeature, errors, loading };
const deleteFeature = async (feature: string) => {
const path = `api/admin/archive/${feature}`;
const req = createRequest(path, { method: 'DELETE' });
return makeRequest(req.caller, req.id);
};
return { reviveFeature, deleteFeature, errors, loading };
};