diff --git a/cypress/e2e/cohorts.cy.ts b/cypress/e2e/cohorts.cy.ts index 29bdcae4d4c47..267b579e79021 100644 --- a/cypress/e2e/cohorts.cy.ts +++ b/cypress/e2e/cohorts.cy.ts @@ -52,5 +52,24 @@ describe('Cohorts', () => { cy.url().should('include', '/cohorts/') cy.get('[data-attr="cohort-name"]').should('have.value', 'Test Cohort') }) + + // back into cohort + cy.get('tbody').contains('Test Cohort').click() + + // duplicate cohort (dynamic) + cy.get('[data-attr="more-button"]').click() + cy.get('.Popover__content').contains('Duplicate as dynamic cohort').click() + cy.get('.Toastify__toast-body').contains('View cohort').click() + + // duplicate cohort (static) + cy.get('[data-attr="more-button"]').click() + cy.get('.Popover__content').contains('Duplicate as static cohort').click() + cy.get('.Toastify__toast-body').contains('View cohort').click() + + // delete cohort + cy.get('[data-attr="more-button"]').click() + cy.get('.Popover__content').contains('Delete cohort').click() + cy.clickNavMenu('cohorts') + cy.get('tbody').should('not.have.text', 'Test Cohort (dynamic copy) (static copy)') }) }) diff --git a/frontend/src/scenes/cohorts/CohortEdit.tsx b/frontend/src/scenes/cohorts/CohortEdit.tsx index 9fafa06e5f105..878104df2349d 100644 --- a/frontend/src/scenes/cohorts/CohortEdit.tsx +++ b/frontend/src/scenes/cohorts/CohortEdit.tsx @@ -26,12 +26,13 @@ import { Query } from '~/queries/Query/Query' import { pluralize } from 'lib/utils' import { LemonDivider } from '@posthog/lemon-ui' import { AndOrFilterSelect } from '~/queries/nodes/InsightViz/PropertyGroupFilters/AndOrFilterSelect' +import { More } from 'lib/lemon-ui/LemonButton/More' export function CohortEdit({ id }: CohortLogicProps): JSX.Element { const logicProps = { id } const logic = cohortEditLogic(logicProps) - const { deleteCohort, setOuterGroupsType, setQuery, duplicateToStaticCohort } = useActions(logic) - const { cohort, cohortLoading, cohortMissing, query, duplicatedStaticCohortLoading } = useValues(logic) + const { deleteCohort, setOuterGroupsType, setQuery, duplicateCohort } = useActions(logic) + const { cohort, cohortLoading, cohortMissing, query, duplicatedCohortLoading } = useValues(logic) const { hasAvailableFeature } = useValues(userLogic) const isNewCohort = cohort.id === 'new' || cohort.id === undefined @@ -57,33 +58,53 @@ export function CohortEdit({ id }: CohortLogicProps): JSX.Element { Cancel ) : ( - { - deleteCohort() - }} - disabled={cohortLoading} - > - Delete - - )} - {!isNewCohort && !cohort.is_static && ( - <> - - - Duplicate as static cohort - - + + {!cohort.is_static && ( + <> + duplicateCohort(false)} + fullWidth + disabledReason={ + cohort.is_calculating + ? 'Cohort is still calculating' + : undefined + } + loading={duplicatedCohortLoading} + > + Duplicate as dynamic cohort + + duplicateCohort(true)} + fullWidth + disabledReason={ + cohort.is_calculating + ? 'Cohort is still calculating' + : undefined + } + loading={duplicatedCohortLoading} + > + Duplicate as static cohort + + + + )} + { + deleteCohort() + }} + > + Delete cohort + + + } + /> )} + ([ criteriaIndex, }), setQuery: (query: Node) => ({ query }), - duplicateToStaticCohort: true, + duplicateCohort: (asStatic: boolean) => ({ asStatic }), }), reducers(({ props }) => ({ @@ -253,17 +253,24 @@ export const cohortEditLogic = kea([ }, }, ], - duplicatedStaticCohort: [ + duplicatedCohort: [ null as CohortType | null, { - duplicateToStaticCohort: async (_, breakpoint) => { + duplicateCohort: async ({ asStatic }: { asStatic: boolean }, breakpoint) => { + let cohort: CohortType try { await breakpoint(200) - const cohort = await api.cohorts.duplicate(values.cohort.id) + if (asStatic) { + cohort = await api.cohorts.duplicate(values.cohort.id) + } else { + const data = { ...values.cohort } + data.name += ' (dynamic copy)' + cohort = await api.cohorts.create(data) + } lemonToast.success( 'Cohort duplicated. Please wait up to a few minutes for it to be calculated', { - toastId: `cohort-duplicated-${values.cohort.id}`, + toastId: `cohort-duplicated-${cohort.id}`, button: { label: 'View cohort', action: () => {