mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-24 20:06:55 +01:00
feat: delete safeguard button (#10974)
This commit is contained in:
parent
684a0ff48c
commit
71099247e7
@ -132,7 +132,7 @@ export const ReleasePlan = ({
|
||||
const { removeReleasePlanFromFeature, startReleasePlanMilestone } =
|
||||
useReleasePlansApi();
|
||||
const { deleteMilestoneProgression } = useMilestoneProgressionsApi();
|
||||
const { createOrUpdateSafeguard } = useSafeguardsApi();
|
||||
const { createOrUpdateSafeguard, deleteSafeguard } = useSafeguardsApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { trackEvent } = usePlausibleTracker();
|
||||
|
||||
@ -400,6 +400,24 @@ export const ReleasePlan = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleSafeguardDelete = async () => {
|
||||
try {
|
||||
await deleteSafeguard({
|
||||
projectId,
|
||||
featureName,
|
||||
environment,
|
||||
planId: id,
|
||||
});
|
||||
setToastData({
|
||||
type: 'success',
|
||||
text: 'Safeguard deleted successfully',
|
||||
});
|
||||
refetch();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledHeader>
|
||||
@ -436,6 +454,7 @@ export const ReleasePlan = ({
|
||||
safeguard={safeguards[0]}
|
||||
onSubmit={handleSafeguardSubmit}
|
||||
onCancel={() => setSafeguardFormOpen(false)}
|
||||
onDelete={handleSafeguardDelete}
|
||||
/>
|
||||
) : safeguardFormOpen ? (
|
||||
<SafeguardForm
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Button, FormControl, TextField } from '@mui/material';
|
||||
import { Button, FormControl, IconButton, TextField } from '@mui/material';
|
||||
import ShieldIcon from '@mui/icons-material/Shield';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
import type { FormEvent } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useImpactMetricsOptions } from 'hooks/api/getters/useImpactMetricsMetadata/useImpactMetricsMetadata';
|
||||
@ -27,6 +28,7 @@ const StyledIcon = createStyledIcon(ShieldIcon);
|
||||
interface ISafeguardFormProps {
|
||||
onSubmit: (data: CreateSafeguardSchema) => void;
|
||||
onCancel: () => void;
|
||||
onDelete?: () => void;
|
||||
safeguard?: ISafeguard;
|
||||
}
|
||||
|
||||
@ -63,6 +65,7 @@ const getDefaultAggregationMode = (
|
||||
export const SafeguardForm = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
onDelete,
|
||||
safeguard,
|
||||
}: ISafeguardFormProps) => {
|
||||
const { metricOptions, loading } = useImpactMetricsOptions();
|
||||
@ -208,11 +211,27 @@ export const SafeguardForm = ({
|
||||
|
||||
const showButtons = mode === 'create' || mode === 'edit';
|
||||
|
||||
const handleDelete = () => {
|
||||
if (onDelete) {
|
||||
onDelete();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledFormContainer onSubmit={handleSubmit}>
|
||||
<StyledTopRow>
|
||||
<StyledTopRow sx={{ mb: 1 }}>
|
||||
<StyledIcon />
|
||||
<StyledLabel>Pause automation when</StyledLabel>
|
||||
{mode !== 'create' && (
|
||||
<IconButton
|
||||
onClick={handleDelete}
|
||||
size='small'
|
||||
aria-label='Delete safeguard'
|
||||
sx={{ padding: 0.5, marginLeft: 'auto' }}
|
||||
>
|
||||
<DeleteOutlineIcon fontSize='small' />
|
||||
</IconButton>
|
||||
)}
|
||||
</StyledTopRow>
|
||||
<StyledTopRow>
|
||||
<MetricSelector
|
||||
|
||||
@ -88,7 +88,7 @@ test('filters by flag type', async () => {
|
||||
|
||||
await screen.findByText('Flag type');
|
||||
await screen.findByText('Operational');
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('selects project features', async () => {
|
||||
setupApi();
|
||||
@ -130,7 +130,7 @@ test('selects project features', async () => {
|
||||
// deselect a single item
|
||||
fireEvent.click(selectFeatureA);
|
||||
expect(screen.queryByTestId(BATCH_SELECTED_COUNT)).not.toBeInTheDocument();
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('filters by tag', async () => {
|
||||
setupApi();
|
||||
@ -155,7 +155,7 @@ test('filters by tag', async () => {
|
||||
|
||||
await screen.findByText('include');
|
||||
expect(await screen.findAllByText('backend:sdk')).toHaveLength(2);
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('filters by flag author', async () => {
|
||||
setupApi();
|
||||
@ -184,7 +184,7 @@ test('filters by flag author', async () => {
|
||||
fireEvent.click(authorA);
|
||||
|
||||
expect(window.location.href).toContain('createdBy=IS%3A1');
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('Project is onboarded', async () => {
|
||||
const projectId = 'default';
|
||||
@ -208,7 +208,7 @@ test('Project is onboarded', async () => {
|
||||
expect(
|
||||
screen.queryByText('Welcome to your project'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('Project is not onboarded', async () => {
|
||||
const projectId = 'default';
|
||||
@ -230,7 +230,7 @@ test('Project is not onboarded', async () => {
|
||||
},
|
||||
);
|
||||
await screen.findByText('Welcome to your project');
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('renders lifecycle quick filters', async () => {
|
||||
setupApi();
|
||||
@ -255,7 +255,7 @@ test('renders lifecycle quick filters', async () => {
|
||||
await screen.findByText(/Develop/);
|
||||
await screen.findByText(/Rollout production/);
|
||||
await screen.findByText(/Cleanup/);
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
test('clears lifecycle filter when switching to archived view', async () => {
|
||||
setupApi();
|
||||
@ -291,4 +291,4 @@ test('clears lifecycle filter when switching to archived view', async () => {
|
||||
|
||||
expect(window.location.href).not.toContain('lifecycle=IS%3Alive');
|
||||
expect(window.location.href).toContain('archived=IS%3Atrue');
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
@ -9,6 +9,13 @@ export interface CreateSafeguardParams {
|
||||
body: CreateSafeguardSchema;
|
||||
}
|
||||
|
||||
export interface DeleteSafeguardParams {
|
||||
projectId: string;
|
||||
featureName: string;
|
||||
environment: string;
|
||||
planId: string;
|
||||
}
|
||||
|
||||
export const useSafeguardsApi = () => {
|
||||
const { makeRequest, createRequest, errors, loading } = useAPI({
|
||||
propagateErrors: true,
|
||||
@ -35,8 +42,28 @@ export const useSafeguardsApi = () => {
|
||||
await makeRequest(req.caller, req.id);
|
||||
};
|
||||
|
||||
const deleteSafeguard = async ({
|
||||
projectId,
|
||||
featureName,
|
||||
environment,
|
||||
planId,
|
||||
}: DeleteSafeguardParams): Promise<void> => {
|
||||
const requestId = 'deleteSafeguard';
|
||||
const path = `api/admin/projects/${projectId}/features/${featureName}/environments/${environment}/release_plans/${planId}/safeguards`;
|
||||
const req = createRequest(
|
||||
path,
|
||||
{
|
||||
method: 'DELETE',
|
||||
},
|
||||
requestId,
|
||||
);
|
||||
|
||||
await makeRequest(req.caller, req.id);
|
||||
};
|
||||
|
||||
return {
|
||||
createOrUpdateSafeguard,
|
||||
deleteSafeguard,
|
||||
errors,
|
||||
loading,
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user