From 06102dae2725df0ac0f5f82f1a22736872a3574e Mon Sep 17 00:00:00 2001 From: Yazan Amer Abu Obaideh Date: Wed, 15 Oct 2025 01:16:32 +0300 Subject: [PATCH] fix: deleted cohort navigation experience (#38753) Co-authored-by: yazan-amer --- frontend/src/scenes/cohorts/CohortEdit.tsx | 22 ++++++++++++++++++- .../scenes/cohorts/cohortEditLogic.test.ts | 18 +++++++++++++++ .../src/scenes/cohorts/cohortEditLogic.ts | 14 ++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/frontend/src/scenes/cohorts/CohortEdit.tsx b/frontend/src/scenes/cohorts/CohortEdit.tsx index d8bead96ae..493f6f97a0 100644 --- a/frontend/src/scenes/cohorts/CohortEdit.tsx +++ b/frontend/src/scenes/cohorts/CohortEdit.tsx @@ -14,7 +14,7 @@ import { LemonButton } from 'lib/lemon-ui/LemonButton' import { LemonField } from 'lib/lemon-ui/LemonField' import { LemonSelect } from 'lib/lemon-ui/LemonSelect' import { Spinner } from 'lib/lemon-ui/Spinner/Spinner' -import { IconErrorOutline, IconUploadFile } from 'lib/lemon-ui/icons' +import { IconErrorOutline, IconRefresh, IconUploadFile } from 'lib/lemon-ui/icons' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { useAttachedLogic } from 'lib/logic/scenes/useAttachedLogic' import { ButtonPrimitive } from 'lib/ui/Button/ButtonPrimitives' @@ -71,6 +71,7 @@ export function CohortEdit({ id, attachTo, tabId }: CohortEditProps): JSX.Elemen useAttachedLogic(logic, attachTo) const { deleteCohort, + restoreCohort, setOuterGroupsType, setQuery, duplicateCohort, @@ -131,6 +132,25 @@ export function CohortEdit({ id, attachTo, tabId }: CohortEditProps): JSX.Elemen return } + if (cohort.deleted) { + return ( +
+ The cohort '{cohort.name}' has been soft deleted. + + { + restoreCohort() + }} + menuItem + > + Restore + + +
+ ) + } + return (
diff --git a/frontend/src/scenes/cohorts/cohortEditLogic.test.ts b/frontend/src/scenes/cohorts/cohortEditLogic.test.ts index 2e49933f46..8a814d17b7 100644 --- a/frontend/src/scenes/cohorts/cohortEditLogic.test.ts +++ b/frontend/src/scenes/cohorts/cohortEditLogic.test.ts @@ -105,6 +105,24 @@ describe('cohortEditLogic', () => { expect(api.update).toHaveBeenCalledTimes(1) }) + it('restore cohort', async () => { + await initCohortLogic({ id: 1 }) + await expectLogic(logic, async () => { + logic.actions.setCohort({ ...mockCohort, deleted: true }) + logic.actions.restoreCohort() + }) + .toFinishAllListeners() + .toDispatchActions(['setCohort', 'restoreCohort']) + expect(api.update).toHaveBeenCalledTimes(1) + expect(api.update).toHaveBeenCalledWith( + expect.anything(), + { + deleted: false, + }, + expect.anything() + ) + }) + describe('form validation', () => { it('save with valid cohort', async () => { await initCohortLogic({ id: 1 }) diff --git a/frontend/src/scenes/cohorts/cohortEditLogic.ts b/frontend/src/scenes/cohorts/cohortEditLogic.ts index 0cccd57cef..0562a7b06a 100644 --- a/frontend/src/scenes/cohorts/cohortEditLogic.ts +++ b/frontend/src/scenes/cohorts/cohortEditLogic.ts @@ -69,6 +69,7 @@ export const cohortEditLogic = kea([ saveCohort: (cohortParams = {}) => ({ cohortParams }), setCohort: (cohort: CohortType) => ({ cohort }), deleteCohort: true, + restoreCohort: true, fetchCohort: (id: CohortType['id']) => ({ id }), setCohortMissing: true, onCriteriaChange: (newGroup: Partial, id: string) => ({ newGroup, id }), @@ -319,6 +320,19 @@ export const cohortEditLogic = kea([ return values.cohort } }, + restoreCohort: async () => { + try { + const restoredCohort = await api.cohorts.update(values.cohort.id, { + deleted: false, + }) + actions.setCohort(restoredCohort) + lemonToast.success('Cohort restored successfully.') + return restoredCohort + } catch (error) { + lemonToast.error(`Failed to restore cohort: '${error}'`) + return values.cohort + } + }, saveCohort: async ({ cohortParams }, breakpoint) => { const existingCohort = values.cohort let cohort = { ...existingCohort, ...cohortParams }