Skip to content

Commit

Permalink
chore(experiments): refactor metric modals (#27129)
Browse files Browse the repository at this point in the history
  • Loading branch information
jurajmajerik authored Dec 23, 2024
1 parent c2b4798 commit 584eae0
Show file tree
Hide file tree
Showing 8 changed files with 374 additions and 687 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { WebExperimentImplementationDetails } from 'scenes/experiments/WebExperi

import { ExperimentImplementationDetails } from '../ExperimentImplementationDetails'
import { experimentLogic } from '../experimentLogic'
import { PrimaryMetricModal } from '../Metrics/PrimaryMetricModal'
import { SecondaryMetricModal } from '../Metrics/SecondaryMetricModal'
import { MetricModal } from '../Metrics/MetricModal'
import { MetricsView } from '../MetricsView/MetricsView'
import {
ExperimentLoadingAnimation,
Expand Down Expand Up @@ -142,8 +141,9 @@ export function ExperimentView(): JSX.Element {
/>
</>
)}
<PrimaryMetricModal experimentId={experimentId} />
<SecondaryMetricModal experimentId={experimentId} />
<MetricModal experimentId={experimentId} isSecondary={true} />
<MetricModal experimentId={experimentId} isSecondary={false} />

<DistributionModal experimentId={experimentId} />
<ReleaseConditionsModal experimentId={experimentId} />
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LemonLabel } from '@posthog/lemon-ui'
import { LemonInput } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types'
import { TestAccountFilterSwitch } from 'lib/components/TestAccountFiltersSwitch'
import { EXPERIMENT_DEFAULT_DURATION } from 'lib/constants'
import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
Expand All @@ -22,13 +23,26 @@ import {
FunnelAttributionSelect,
FunnelConversionWindowFilter,
} from './Selectors'

export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.Element {
export function FunnelsMetricForm({ isSecondary = false }: { isSecondary?: boolean }): JSX.Element {
const { currentTeam } = useValues(teamLogic)
const { experiment, isExperimentRunning } = useValues(experimentLogic)
const { experiment, isExperimentRunning, editingPrimaryMetricIndex, editingSecondaryMetricIndex } =
useValues(experimentLogic)
const { setFunnelsMetric } = useActions(experimentLogic)
const hasFilters = (currentTeam?.test_account_filters || []).length > 0
const currentMetric = experiment.metrics_secondary[metricIdx] as ExperimentFunnelsQuery

const metrics = isSecondary ? experiment.metrics_secondary : experiment.metrics
const metricIdx = isSecondary ? editingSecondaryMetricIndex : editingPrimaryMetricIndex

if (!metricIdx && metricIdx !== 0) {
return <></>
}

const currentMetric = metrics[metricIdx] as ExperimentFunnelsQuery

const actionFilterProps = {
...commonActionFilterProps,
actionsTaxonomicGroupTypes: [TaxonomicFilterGroupType.Events, TaxonomicFilterGroupType.Actions],
}

return (
<>
Expand All @@ -40,7 +54,7 @@ export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.
setFunnelsMetric({
metricIdx,
name: newName,
isSecondary: true,
isSecondary,
})
}}
/>
Expand All @@ -58,7 +72,7 @@ export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.
setFunnelsMetric({
metricIdx,
series,
isSecondary: true,
isSecondary,
})
}}
typeKey="experiment-metric"
Expand All @@ -68,7 +82,7 @@ export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.
seriesIndicatorType="numeric"
sortable={true}
showNestedArrow={true}
{...commonActionFilterProps}
{...actionFilterProps}
/>
<div className="mt-4 space-y-4">
<FunnelAggregationSelect
Expand All @@ -80,7 +94,7 @@ export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.
setFunnelsMetric({
metricIdx,
funnelAggregateByHogQL: value,
isSecondary: true,
isSecondary,
})
}}
/>
Expand All @@ -91,14 +105,14 @@ export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.
setFunnelsMetric({
metricIdx,
funnelWindowInterval: funnelWindowInterval,
isSecondary: true,
isSecondary,
})
}}
onFunnelWindowIntervalUnitChange={(funnelWindowIntervalUnit) => {
setFunnelsMetric({
metricIdx,
funnelWindowIntervalUnit: funnelWindowIntervalUnit || undefined,
isSecondary: true,
isSecondary,
})
}}
/>
Expand Down Expand Up @@ -126,18 +140,21 @@ export function SecondaryGoalFunnels({ metricIdx }: { metricIdx: number }): JSX.
breakdownAttributionValue: breakdownAttributionValue
? parseInt(breakdownAttributionValue)
: undefined,
isSecondary: true,
isSecondary,
})
}}
stepsLength={currentMetric.funnels_query?.series?.length}
/>
<TestAccountFilterSwitch
checked={hasFilters ? !!currentMetric.funnels_query?.filterTestAccounts : false}
checked={(() => {
const val = currentMetric.funnels_query?.filterTestAccounts
return hasFilters ? !!val : false
})()}
onChange={(checked: boolean) => {
setFunnelsMetric({
metricIdx,
filterTestAccounts: checked,
isSecondary: true,
isSecondary,
})
}}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,82 @@
import { LemonButton, LemonModal, LemonSelect } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'

import { ExperimentFunnelsQuery } from '~/queries/schema'
import { Experiment, InsightType } from '~/types'

import { experimentLogic, getDefaultFunnelsMetric, getDefaultTrendsMetric } from '../experimentLogic'
import { SecondaryGoalFunnels } from './SecondaryGoalFunnels'
import { SecondaryGoalTrends } from './SecondaryGoalTrends'
import { FunnelsMetricForm } from './FunnelsMetricForm'
import { TrendsMetricForm } from './TrendsMetricForm'

export function SecondaryMetricModal({ experimentId }: { experimentId: Experiment['id'] }): JSX.Element {
export function MetricModal({
experimentId,
isSecondary,
}: {
experimentId: Experiment['id']
isSecondary?: boolean
}): JSX.Element {
const {
experiment,
experimentLoading,
getMetricType,
getSecondaryMetricType,
isPrimaryMetricModalOpen,
isSecondaryMetricModalOpen,
editingPrimaryMetricIndex,
editingSecondaryMetricIndex,
} = useValues(experimentLogic({ experimentId }))
const { setExperiment, updateExperimentGoal, closeSecondaryMetricModal } = useActions(
const { updateExperimentGoal, setExperiment, closePrimaryMetricModal, closeSecondaryMetricModal } = useActions(
experimentLogic({ experimentId })
)

if (!editingSecondaryMetricIndex && editingSecondaryMetricIndex !== 0) {
const metricIdx = isSecondary ? editingSecondaryMetricIndex : editingPrimaryMetricIndex
const metricsField = isSecondary ? 'metrics_secondary' : 'metrics'

if (!metricIdx && metricIdx !== 0) {
return <></>
}

const metricIdx = editingSecondaryMetricIndex
const metricType = getSecondaryMetricType(metricIdx)
const metricType = isSecondary ? getSecondaryMetricType(metricIdx) : getMetricType(metricIdx)
const metrics = experiment[metricsField]
const metric = metrics[metricIdx]
const funnelStepsLength = (metric as ExperimentFunnelsQuery)?.funnels_query?.series?.length || 0

return (
<LemonModal
isOpen={isSecondaryMetricModalOpen}
onClose={closeSecondaryMetricModal}
isOpen={isSecondary ? isSecondaryMetricModalOpen : isPrimaryMetricModalOpen}
onClose={isSecondary ? closeSecondaryMetricModal : closePrimaryMetricModal}
width={1000}
title="Change secondary metric"
title="Edit experiment metric"
footer={
<div className="flex items-center w-full">
<LemonButton
type="secondary"
status="danger"
onClick={() => {
const newMetricsSecondary = experiment.metrics_secondary.filter(
(_, idx) => idx !== metricIdx
)
const newMetrics = metrics.filter((_, idx) => idx !== metricIdx)
setExperiment({
metrics_secondary: newMetricsSecondary,
[metricsField]: newMetrics,
})
updateExperimentGoal()
}}
>
Delete
</LemonButton>
<div className="flex items-center gap-2 ml-auto">
<LemonButton type="secondary" onClick={closeSecondaryMetricModal}>
<LemonButton
form="edit-experiment-goal-form"
type="secondary"
onClick={isSecondary ? closeSecondaryMetricModal : closePrimaryMetricModal}
>
Cancel
</LemonButton>
<LemonButton
disabledReason={
metricType === InsightType.FUNNELS &&
funnelStepsLength < 2 &&
'The experiment needs at least two funnel steps.'
}
form="edit-experiment-goal-form"
onClick={() => {
updateExperimentGoal()
}}
Expand All @@ -75,12 +98,12 @@ export function SecondaryMetricModal({ experimentId }: { experimentId: Experimen
onChange={(newMetricType) => {
setExperiment({
...experiment,
metrics_secondary: [
...experiment.metrics_secondary.slice(0, metricIdx),
[metricsField]: [
...metrics.slice(0, metricIdx),
newMetricType === InsightType.TRENDS
? getDefaultTrendsMetric()
: getDefaultFunnelsMetric(),
...experiment.metrics_secondary.slice(metricIdx + 1),
...metrics.slice(metricIdx + 1),
],
})
}}
Expand All @@ -91,9 +114,9 @@ export function SecondaryMetricModal({ experimentId }: { experimentId: Experimen
/>
</div>
{metricType === InsightType.TRENDS ? (
<SecondaryGoalTrends metricIdx={metricIdx} />
<TrendsMetricForm isSecondary={isSecondary} />
) : (
<SecondaryGoalFunnels metricIdx={metricIdx} />
<FunnelsMetricForm isSecondary={isSecondary} />
)}
</LemonModal>
)
Expand Down
Loading

0 comments on commit 584eae0

Please sign in to comment.