1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-10 17:53:36 +02:00

bulk archive feature toggles

This commit is contained in:
Tymoteusz Czech 2023-03-13 16:57:38 +01:00 committed by Tymoteusz Czech
parent 30a753b93f
commit abe19d3040
No known key found for this signature in database
GPG Key ID: 133555230D88D75F
5 changed files with 120 additions and 18 deletions

View File

@ -3,13 +3,14 @@ import { Dialogue } from 'component/common/Dialogue/Dialogue';
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
interface IFeatureArchiveDialogProps {
isOpen: boolean;
onConfirm: () => void;
onClose: () => void;
projectId: string;
featureId: string;
featureIds: string[];
}
export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
@ -17,14 +18,15 @@ export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
onClose,
onConfirm,
projectId,
featureId,
featureIds,
}) => {
const { archiveFeatureToggle } = useFeatureApi();
const { setToastData, setToastApiError } = useToast();
const isBulkArchive = featureIds?.length > 1;
const archiveToggle = async () => {
try {
await archiveFeatureToggle(projectId, featureId);
await archiveFeatureToggle(projectId, featureIds[0]);
setToastData({
text: 'Your feature toggle has been archived',
type: 'success',
@ -38,16 +40,69 @@ export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
}
};
const archiveToggles = async () => {
try {
// TODO: bulk archive
await Promise.allSettled(
featureIds.map(id => {
archiveFeatureToggle(projectId, id);
})
);
setToastData({
text: 'Selected feature toggles have been archived',
type: 'success',
title: 'Feature toggles archived',
});
onConfirm();
onClose();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
onClose();
}
};
return (
<Dialogue
onClick={() => archiveToggle()}
onClick={isBulkArchive ? archiveToggles : archiveToggle}
open={isOpen}
onClose={onClose}
primaryButtonText="Archive toggle"
primaryButtonText={
isBulkArchive ? 'Archive toggles' : 'Archive toggle'
}
secondaryButtonText="Cancel"
title="Archive feature toggle"
title={
isBulkArchive
? 'Archive feature toggles'
: 'Archive feature toggle'
}
>
Are you sure you want to archive this feature toggle?
<ConditionallyRender
condition={isBulkArchive}
show={
<>
<p>
Are you sure you want to archive{' '}
<strong>{featureIds?.length}</strong> feature
toggles?
</p>
<ConditionallyRender
condition={featureIds?.length <= 5}
show={
<ul>
{featureIds?.map(id => (
<li key={id}>{id}</li>
))}
</ul>
}
/>
</>
}
elseShow={
<p>
Are you sure you want to archive these feature toggles?
</p>
}
/>
</Dialogue>
);
};

View File

@ -248,7 +248,7 @@ export const FeatureView = () => {
}}
onClose={() => setShowDelDialog(false)}
projectId={projectId}
featureId={featureId}
featureIds={[featureId]}
/>
<FeatureStaleDialog
isStale={feature.stale}

View File

@ -685,7 +685,7 @@ export const ProjectFeatureToggles = ({
onClose={() => {
setFeatureArchiveState(undefined);
}}
featureId={featureArchiveState || ''}
featureIds={[featureArchiveState || '']}
projectId={projectId}
/>{' '}
<ChangeRequestDialogue
@ -717,6 +717,7 @@ export const ProjectFeatureToggles = ({
<SelectionActionsBar
selectedIds={Object.keys(selectedRowIds)}
data={features}
projectId={projectId}
/>
</PageContent>
);

View File

@ -0,0 +1,50 @@
import { useState, VFC } from 'react';
import { Button } from '@mui/material';
import { Archive } from '@mui/icons-material';
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
import { DELETE_FEATURE } from 'component/providers/AccessProvider/permissions';
import useProject from 'hooks/api/getters/useProject/useProject';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
interface IArchiveButtonProps {
projectId: string;
features: string[];
}
export const ArchiveButton: VFC<IArchiveButtonProps> = ({
projectId,
features,
}) => {
const { refetch } = useProject(projectId);
const [isDialogOpen, setIsDialogOpen] = useState(false);
const onConfirm = async () => {
setIsDialogOpen(false);
await refetch();
};
return (
<>
<PermissionHOC projectId={projectId} permission={DELETE_FEATURE}>
{({ hasAccess }) => (
<Button
disabled={!hasAccess || isDialogOpen}
startIcon={<Archive />}
variant="outlined"
size="small"
onClick={() => setIsDialogOpen(true)}
>
Archive
</Button>
)}
</PermissionHOC>
<FeatureArchiveDialog
projectId={projectId}
featureIds={features}
onConfirm={onConfirm}
isOpen={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
/>
</>
);
};

View File

@ -1,14 +1,16 @@
import { useMemo, useState, VFC } from 'react';
import { Box, Button, Paper, styled, Typography } from '@mui/material';
import { Archive, FileDownload, Label, WatchLater } from '@mui/icons-material';
import { FileDownload, Label, WatchLater } from '@mui/icons-material';
import type { FeatureSchema } from 'openapi';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ArchiveButton } from './ArchiveButton/ArchiveButton';
interface ISelectionActionsBarProps {
selectedIds: string[];
data: FeatureSchema[];
projectId: string;
}
const StyledContainer = styled(Box)(() => ({
@ -45,6 +47,7 @@ const StyledText = styled(Typography)(({ theme }) => ({
export const SelectionActionsBar: VFC<ISelectionActionsBarProps> = ({
selectedIds,
data,
projectId,
}) => {
const { uiConfig } = useUiConfig();
const [showExportDialog, setShowExportDialog] = useState(false);
@ -71,14 +74,7 @@ export const SelectionActionsBar: VFC<ISelectionActionsBarProps> = ({
<StyledCount>{selectedIds.length}</StyledCount>
&ensp;selected
</StyledText>
<Button
disabled
startIcon={<Archive />}
variant="outlined"
size="small"
>
Archive
</Button>
<ArchiveButton projectId={projectId} features={selectedIds} />
<Button
disabled
startIcon={<WatchLater />}