From bfbd18eb97c29e835eaccf478f6174c388a5fc0d Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg Date: Tue, 12 Mar 2024 15:03:53 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20allow=20deletion=20of=20segments=20refer?= =?UTF-8?q?encing=20strategies=20in=20archived=20f=E2=80=A6=20(#6406)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Subset of #6392, allowing you to delete segments that are referenced in strategies on archived features. --- .../SegmentDeleteConfirm.tsx | 7 ++++- .../feature-toggle-strategies-store.ts | 9 +++++- .../segment/admin-segment.e2e.test.ts | 30 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/segments/SegmentDelete/SegmentDeleteConfirm/SegmentDeleteConfirm.tsx b/frontend/src/component/segments/SegmentDelete/SegmentDeleteConfirm/SegmentDeleteConfirm.tsx index edef0e309c..f6b457c97a 100644 --- a/frontend/src/component/segments/SegmentDelete/SegmentDeleteConfirm/SegmentDeleteConfirm.tsx +++ b/frontend/src/component/segments/SegmentDelete/SegmentDeleteConfirm/SegmentDeleteConfirm.tsx @@ -3,7 +3,7 @@ import { Dialogue } from 'component/common/Dialogue/Dialogue'; import Input from 'component/common/Input/Input'; import { ISegment } from 'interfaces/segment'; import { SEGMENT_DIALOG_NAME_ID } from 'utils/testIds'; -import { styled } from '@mui/material'; +import { Alert, styled } from '@mui/material'; const StyledInput = styled(Input)(({ theme }) => ({ marginTop: theme.spacing(2), @@ -46,6 +46,11 @@ export const SegmentDeleteConfirm = ({ onClose={handleCancel} formId={formId} > + + Deleted segments may be referenced in strategies if the feature + flag is archived. Removing the segment will also remove the + segments from strategies of archived flags. +

In order to delete this segment, please enter the name of the segment in the field below: {segment?.name} diff --git a/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts b/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts index 421ca95da0..cd81e3b6f0 100644 --- a/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts +++ b/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts @@ -814,7 +814,14 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { `${T.featureStrategySegment}.feature_strategy_id`, `${T.featureStrategies}.id`, ) - .where(`${T.featureStrategySegment}.segment_id`, '=', segmentId); + .join( + T.features, + `${T.features}.name`, + `${T.featureStrategies}.feature_name`, + ) + .where(`${T.featureStrategySegment}.segment_id`, '=', segmentId) + .andWhere(`${T.features}.archived_at`, 'IS', null); + stopTimer(); return rows.map(mapRow); } diff --git a/src/lib/features/segment/admin-segment.e2e.test.ts b/src/lib/features/segment/admin-segment.e2e.test.ts index eaef38cf95..5eecae2ef3 100644 --- a/src/lib/features/segment/admin-segment.e2e.test.ts +++ b/src/lib/features/segment/admin-segment.e2e.test.ts @@ -290,6 +290,36 @@ test('should not delete segments used by strategies', async () => { expect((await fetchSegments()).length).toEqual(1); }); +test('should delete segments used by strategies in archived feature toggles', async () => { + await app.createSegment({ + name: 'a', + constraints: [], + }); + const toggle = mockFeatureToggle(); + await createFeatureToggle(app, toggle); + const [segment] = await fetchSegments(); + + await addStrategyToFeatureEnv( + app, + { ...toggle.strategies[0] }, + 'default', + toggle.name, + ); + const [feature] = await fetchFeatures(); + //@ts-ignore + await addSegmentsToStrategy([segment.id], feature.strategies[0].id); + const segments = await fetchSegments(); + expect(segments.length).toEqual(1); + + await app.archiveFeature(feature.name); + + await app.request + .delete(`${SEGMENTS_BASE_PATH}/${segments[0].id}`) + .expect(204); + + expect((await fetchSegments()).length).toEqual(0); +}); + test('should list strategies by segment', async () => { await app.createSegment({ name: 'S1',