diff --git a/frontend/src/scenes/appScenes.ts b/frontend/src/scenes/appScenes.ts index 6954d228d1879..29d9d8848fbb6 100644 --- a/frontend/src/scenes/appScenes.ts +++ b/frontend/src/scenes/appScenes.ts @@ -29,8 +29,8 @@ export const appScenes: Record any> = { [Scene.Group]: () => import('./groups/Group'), [Scene.Action]: () => import('./actions/Action'), [Scene.Experiments]: () => import('./experiments/Experiments'), - [Scene.ExperimentsSavedMetrics]: () => import('./experiments/SavedMetrics/SavedMetrics'), - [Scene.ExperimentsSavedMetric]: () => import('./experiments/SavedMetrics/SavedMetric'), + [Scene.ExperimentsSharedMetrics]: () => import('./experiments/SharedMetrics/SharedMetrics'), + [Scene.ExperimentsSharedMetric]: () => import('./experiments/SharedMetrics/SharedMetric'), [Scene.Experiment]: () => import('./experiments/Experiment'), [Scene.FeatureFlags]: () => import('./feature-flags/FeatureFlags'), [Scene.FeatureManagement]: () => import('./feature-flags/FeatureManagement'), diff --git a/frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx b/frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx index 06c1ba1707b22..ea78b929c536f 100644 --- a/frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx +++ b/frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx @@ -8,7 +8,7 @@ import { ExperimentImplementationDetails } from '../ExperimentImplementationDeta import { experimentLogic } from '../experimentLogic' import { MetricModal } from '../Metrics/MetricModal' import { MetricSourceModal } from '../Metrics/MetricSourceModal' -import { SavedMetricModal } from '../Metrics/SavedMetricModal' +import { SharedMetricModal } from '../Metrics/SharedMetricModal' import { MetricsView } from '../MetricsView/MetricsView' import { ExperimentLoadingAnimation, @@ -194,8 +194,8 @@ export function ExperimentView(): JSX.Element { - - + + diff --git a/frontend/src/scenes/experiments/Experiments.tsx b/frontend/src/scenes/experiments/Experiments.tsx index e31d1958000cd..385c04f77632f 100644 --- a/frontend/src/scenes/experiments/Experiments.tsx +++ b/frontend/src/scenes/experiments/Experiments.tsx @@ -24,7 +24,7 @@ import { Experiment, ExperimentsTabs, ProductKey, ProgressStatus } from '~/types import { experimentsLogic, getExperimentStatus } from './experimentsLogic' import { StatusTag } from './ExperimentView/components' import { Holdouts } from './Holdouts' -import { SavedMetrics } from './SavedMetrics/SavedMetrics' +import { SharedMetrics } from './SharedMetrics/SharedMetrics' export const scene: SceneExport = { component: Experiments, @@ -222,15 +222,15 @@ export function Experiments(): JSX.Element { { key: ExperimentsTabs.Archived, label: 'Archived experiments' }, { key: ExperimentsTabs.Holdouts, label: 'Holdout groups' }, ...(featureFlags[FEATURE_FLAGS.EXPERIMENTS_MULTIPLE_METRICS] - ? [{ key: ExperimentsTabs.SavedMetrics, label: 'Shared metrics' }] + ? [{ key: ExperimentsTabs.SharedMetrics, label: 'Shared metrics' }] : []), ]} /> {tab === ExperimentsTabs.Holdouts ? ( - ) : tab === ExperimentsTabs.SavedMetrics && featureFlags[FEATURE_FLAGS.EXPERIMENTS_MULTIPLE_METRICS] ? ( - + ) : tab === ExperimentsTabs.SharedMetrics && featureFlags[FEATURE_FLAGS.EXPERIMENTS_MULTIPLE_METRICS] ? ( + ) : ( <> {tab === ExperimentsTabs.Archived ? ( diff --git a/frontend/src/scenes/experiments/Metrics/MetricSourceModal.tsx b/frontend/src/scenes/experiments/Metrics/MetricSourceModal.tsx index ae277b0d18126..3819bcc52f627 100644 --- a/frontend/src/scenes/experiments/Metrics/MetricSourceModal.tsx +++ b/frontend/src/scenes/experiments/Metrics/MetricSourceModal.tsx @@ -20,16 +20,16 @@ export function MetricSourceModal({ closePrimaryMetricSourceModal, closeSecondaryMetricSourceModal, openPrimaryMetricModal, - openPrimarySavedMetricModal, + openPrimarySharedMetricModal, openSecondaryMetricModal, - openSecondarySavedMetricModal, + openSecondarySharedMetricModal, } = useActions(experimentLogic({ experimentId })) const metricsField = isSecondary ? 'metrics_secondary' : 'metrics' const isOpen = isSecondary ? isSecondaryMetricSourceModalOpen : isPrimaryMetricSourceModalOpen const closeCurrentModal = isSecondary ? closeSecondaryMetricSourceModal : closePrimaryMetricSourceModal const openMetricModal = isSecondary ? openSecondaryMetricModal : openPrimaryMetricModal - const openSavedMetricModal = isSecondary ? openSecondarySavedMetricModal : openPrimarySavedMetricModal + const openSharedMetricModal = isSecondary ? openSecondarySharedMetricModal : openPrimarySharedMetricModal return ( @@ -57,7 +57,7 @@ export function MetricSourceModal({ className="flex-1 cursor-pointer p-4 rounded border hover:border-primary-3000" onClick={() => { closeCurrentModal() - openSavedMetricModal(null) + openSharedMetricModal(null) }} >
diff --git a/frontend/src/scenes/experiments/Metrics/SavedMetricModal.tsx b/frontend/src/scenes/experiments/Metrics/SharedMetricModal.tsx similarity index 78% rename from frontend/src/scenes/experiments/Metrics/SavedMetricModal.tsx rename to frontend/src/scenes/experiments/Metrics/SharedMetricModal.tsx index 0380910ecaa0c..d59bb109a3fd5 100644 --- a/frontend/src/scenes/experiments/Metrics/SavedMetricModal.tsx +++ b/frontend/src/scenes/experiments/Metrics/SharedMetricModal.tsx @@ -8,40 +8,40 @@ import { Experiment } from '~/types' import { experimentLogic } from '../experimentLogic' import { MetricDisplayFunnels, MetricDisplayTrends } from '../ExperimentView/Goal' -import { SavedMetric } from '../SavedMetrics/savedMetricLogic' +import { SharedMetric } from '../SharedMetrics/sharedMetricLogic' -export function SavedMetricModal({ +export function SharedMetricModal({ experimentId, isSecondary, }: { experimentId: Experiment['id'] isSecondary?: boolean }): JSX.Element { - const { savedMetrics, isPrimarySavedMetricModalOpen, isSecondarySavedMetricModalOpen, editingSavedMetricId } = + const { sharedMetrics, isPrimarySharedMetricModalOpen, isSecondarySharedMetricModalOpen, editingSharedMetricId } = useValues(experimentLogic({ experimentId })) const { - closePrimarySavedMetricModal, - closeSecondarySavedMetricModal, - addSavedMetricToExperiment, - removeSavedMetricFromExperiment, + closePrimarySharedMetricModal, + closeSecondarySharedMetricModal, + addSharedMetricToExperiment, + removeSharedMetricFromExperiment, } = useActions(experimentLogic({ experimentId })) - const [selectedMetricId, setSelectedMetricId] = useState(null) + const [selectedMetricId, setSelectedMetricId] = useState(null) const [mode, setMode] = useState<'create' | 'edit'>('create') useEffect(() => { - if (editingSavedMetricId) { - setSelectedMetricId(editingSavedMetricId) + if (editingSharedMetricId) { + setSelectedMetricId(editingSharedMetricId) setMode('edit') } - }, [editingSavedMetricId]) + }, [editingSharedMetricId]) - if (!savedMetrics) { + if (!sharedMetrics) { return <> } - const isOpen = isSecondary ? isSecondarySavedMetricModalOpen : isPrimarySavedMetricModalOpen - const closeModal = isSecondary ? closeSecondarySavedMetricModal : closePrimarySavedMetricModal + const isOpen = isSecondary ? isSecondarySharedMetricModalOpen : isPrimarySharedMetricModalOpen + const closeModal = isSecondary ? closeSecondarySharedMetricModal : closePrimarySharedMetricModal return (
- {editingSavedMetricId && ( + {editingSharedMetricId && ( { - removeSavedMetricFromExperiment(editingSavedMetricId) + removeSharedMetricFromExperiment(editingSharedMetricId) }} type="secondary" > @@ -74,7 +74,7 @@ export function SavedMetricModal({ { if (selectedMetricId) { - addSavedMetricToExperiment(selectedMetricId, { + addSharedMetricToExperiment(selectedMetricId, { type: isSecondary ? 'secondary' : 'primary', }) } @@ -91,9 +91,9 @@ export function SavedMetricModal({ > {mode === 'create' && (
- {savedMetrics.length > 0 ? ( + {sharedMetrics.length > 0 ? ( ({ + options={sharedMetrics.map((metric: SharedMetric) => ({ label: metric.name, value: metric.id, }))} @@ -110,7 +110,7 @@ export function SavedMetricModal({ type="info" action={{ children: 'New shared metric', - to: urls.experimentsSavedMetric('new'), + to: urls.experimentsSharedMetric('new'), }} > You don't have any shared metrics yet. Shared metrics let you create reusable metrics that @@ -123,7 +123,7 @@ export function SavedMetricModal({ {selectedMetricId && (
{(() => { - const metric = savedMetrics.find((m: SavedMetric) => m.id === selectedMetricId) + const metric = sharedMetrics.find((m: SharedMetric) => m.id === selectedMetricId) if (!metric) { return <> } @@ -135,7 +135,7 @@ export function SavedMetricModal({ diff --git a/frontend/src/scenes/experiments/MetricsView/DeltaChart.tsx b/frontend/src/scenes/experiments/MetricsView/DeltaChart.tsx index dc110cf051464..b8100b803d180 100644 --- a/frontend/src/scenes/experiments/MetricsView/DeltaChart.tsx +++ b/frontend/src/scenes/experiments/MetricsView/DeltaChart.tsx @@ -108,8 +108,8 @@ export function DeltaChart({ const { openPrimaryMetricModal, openSecondaryMetricModal, - openPrimarySavedMetricModal, - openSecondarySavedMetricModal, + openPrimarySharedMetricModal, + openSecondarySharedMetricModal, } = useActions(experimentLogic) const [tooltipData, setTooltipData] = useState<{ x: number; y: number; variant: string } | null>(null) const [emptyStateTooltipVisible, setEmptyStateTooltipVisible] = useState(true) @@ -229,11 +229,11 @@ export function DeltaChart({ size="xsmall" icon={} onClick={() => { - if (metric.isSavedMetric) { + if (metric.isSharedMetric) { if (isSecondary) { - openSecondarySavedMetricModal(metric.savedMetricId) + openSecondarySharedMetricModal(metric.sharedMetricId) } else { - openPrimarySavedMetricModal(metric.savedMetricId) + openPrimarySharedMetricModal(metric.sharedMetricId) } return } @@ -247,7 +247,7 @@ export function DeltaChart({ {metric.kind === 'ExperimentFunnelsQuery' ? 'Funnel' : 'Trend'} - {metric.isSavedMetric && ( + {metric.isSharedMetric && ( Shared diff --git a/frontend/src/scenes/experiments/MetricsView/MetricsView.tsx b/frontend/src/scenes/experiments/MetricsView/MetricsView.tsx index 2b5735778e1c3..dc62d1d4e52c2 100644 --- a/frontend/src/scenes/experiments/MetricsView/MetricsView.tsx +++ b/frontend/src/scenes/experiments/MetricsView/MetricsView.tsx @@ -104,17 +104,17 @@ export function MetricsView({ isSecondary }: { isSecondary?: boolean }): JSX.Ele const hasSomeResults = results?.some((result) => result?.insight) let metrics = isSecondary ? experiment.metrics_secondary : experiment.metrics - const savedMetrics = experiment.saved_metrics - .filter((savedMetric) => savedMetric.metadata.type === (isSecondary ? 'secondary' : 'primary')) - .map((savedMetric) => ({ - ...savedMetric.query, - name: savedMetric.name, - savedMetricId: savedMetric.saved_metric, - isSavedMetric: true, + const sharedMetrics = experiment.saved_metrics + .filter((sharedMetric) => sharedMetric.metadata.type === (isSecondary ? 'secondary' : 'primary')) + .map((sharedMetric) => ({ + ...sharedMetric.query, + name: sharedMetric.name, + sharedMetricId: sharedMetric.saved_metric, + isSharedMetric: true, })) - if (savedMetrics) { - metrics = [...metrics, ...savedMetrics] + if (sharedMetrics) { + metrics = [...metrics, ...sharedMetrics] } // Calculate the maximum absolute value across ALL metrics diff --git a/frontend/src/scenes/experiments/SavedMetrics/savedMetricsLogic.tsx b/frontend/src/scenes/experiments/SavedMetrics/savedMetricsLogic.tsx deleted file mode 100644 index 795ca52060d9d..0000000000000 --- a/frontend/src/scenes/experiments/SavedMetrics/savedMetricsLogic.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { actions, events, kea, listeners, path, reducers } from 'kea' -import { loaders } from 'kea-loaders' -import { router } from 'kea-router' -import api from 'lib/api' - -import { SavedMetric } from './savedMetricLogic' -import type { savedMetricsLogicType } from './savedMetricsLogicType' - -export enum SavedMetricsTabs { - All = 'all', - Yours = 'yours', - Archived = 'archived', -} - -export const savedMetricsLogic = kea([ - path(['scenes', 'experiments', 'savedMetricsLogic']), - actions({ - setSavedMetricsTab: (tabKey: SavedMetricsTabs) => ({ tabKey }), - }), - - loaders({ - savedMetrics: { - loadSavedMetrics: async () => { - const response = await api.get('api/projects/@current/experiment_saved_metrics') - return response.results as SavedMetric[] - }, - }, - }), - - reducers({ - tab: [ - SavedMetricsTabs.All as SavedMetricsTabs, - { - setSavedMetricsTab: (_, { tabKey }) => tabKey, - }, - ], - }), - listeners(() => ({ - setSavedMetricsTab: () => { - router.actions.push('/experiments/shared-metrics') - }, - })), - events(({ actions }) => ({ - afterMount: () => { - actions.loadSavedMetrics() - }, - })), -]) diff --git a/frontend/src/scenes/experiments/SavedMetrics/SavedFunnelsMetricForm.tsx b/frontend/src/scenes/experiments/SharedMetrics/SharedFunnelsMetricForm.tsx similarity index 72% rename from frontend/src/scenes/experiments/SavedMetrics/SavedFunnelsMetricForm.tsx rename to frontend/src/scenes/experiments/SharedMetrics/SharedFunnelsMetricForm.tsx index 6a69c279f7286..a22b1f17d32f1 100644 --- a/frontend/src/scenes/experiments/SavedMetrics/SavedFunnelsMetricForm.tsx +++ b/frontend/src/scenes/experiments/SharedMetrics/SharedFunnelsMetricForm.tsx @@ -20,11 +20,11 @@ import { FunnelAttributionSelect, FunnelConversionWindowFilter, } from '../Metrics/Selectors' -import { savedMetricLogic } from './savedMetricLogic' +import { sharedMetricLogic } from './sharedMetricLogic' -export function SavedFunnelsMetricForm(): JSX.Element { - const { savedMetric } = useValues(savedMetricLogic) - const { setSavedMetric } = useActions(savedMetricLogic) +export function SharedFunnelsMetricForm(): JSX.Element { + const { sharedMetric } = useValues(sharedMetricLogic) + const { setSharedMetric } = useActions(sharedMetricLogic) const { currentTeam } = useValues(teamLogic) const hasFilters = (currentTeam?.test_account_filters || []).length > 0 @@ -34,19 +34,19 @@ export function SavedFunnelsMetricForm(): JSX.Element { actionsTaxonomicGroupTypes: [TaxonomicFilterGroupType.Events, TaxonomicFilterGroupType.Actions], } - if (!savedMetric?.query) { + if (!sharedMetric?.query) { return <> } - const savedMetricQuery = savedMetric.query as ExperimentFunnelsQuery + const sharedMetricQuery = sharedMetric.query as ExperimentFunnelsQuery return ( <> ): void => { - if (!savedMetric?.query) { + if (!sharedMetric?.query) { return } @@ -55,11 +55,11 @@ export function SavedFunnelsMetricForm(): JSX.Element { true, MathAvailability.None ) - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, funnels_query: { - ...savedMetricQuery.funnels_query, + ...sharedMetricQuery.funnels_query, series, }, }, @@ -77,15 +77,15 @@ export function SavedFunnelsMetricForm(): JSX.Element {
{ - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, funnels_query: { - ...savedMetricQuery.funnels_query, + ...sharedMetricQuery.funnels_query, aggregation_group_type_index: value, }, }, @@ -93,17 +93,17 @@ export function SavedFunnelsMetricForm(): JSX.Element { }} /> { - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, funnels_query: { - ...savedMetricQuery.funnels_query, + ...sharedMetricQuery.funnels_query, // funnelWindowInterval: funnelWindowInterval, funnelsFilter: { - ...savedMetricQuery.funnels_query.funnelsFilter, + ...sharedMetricQuery.funnels_query.funnelsFilter, funnelWindowInterval: funnelWindowInterval, }, }, @@ -111,13 +111,13 @@ export function SavedFunnelsMetricForm(): JSX.Element { }) }} onFunnelWindowIntervalUnitChange={(funnelWindowIntervalUnit) => { - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, funnels_query: { - ...savedMetricQuery.funnels_query, + ...sharedMetricQuery.funnels_query, funnelsFilter: { - ...savedMetricQuery.funnels_query.funnelsFilter, + ...sharedMetricQuery.funnels_query.funnelsFilter, funnelWindowIntervalUnit: funnelWindowIntervalUnit || undefined, }, }, @@ -128,9 +128,9 @@ export function SavedFunnelsMetricForm(): JSX.Element { { const breakdownAttributionType = - savedMetricQuery.funnels_query?.funnelsFilter?.breakdownAttributionType + sharedMetricQuery.funnels_query?.funnelsFilter?.breakdownAttributionType const breakdownAttributionValue = - savedMetricQuery.funnels_query?.funnelsFilter?.breakdownAttributionValue + sharedMetricQuery.funnels_query?.funnelsFilter?.breakdownAttributionValue const currentValue: BreakdownAttributionType | `${BreakdownAttributionType.Step}/${number}` = !breakdownAttributionType @@ -143,13 +143,13 @@ export function SavedFunnelsMetricForm(): JSX.Element { })()} onChange={(value) => { const [breakdownAttributionType, breakdownAttributionValue] = (value || '').split('/') - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, funnels_query: { - ...savedMetricQuery.funnels_query, + ...sharedMetricQuery.funnels_query, funnelsFilter: { - ...savedMetricQuery.funnels_query.funnelsFilter, + ...sharedMetricQuery.funnels_query.funnelsFilter, breakdownAttributionType: breakdownAttributionType as BreakdownAttributionType, breakdownAttributionValue: breakdownAttributionValue ? parseInt(breakdownAttributionValue) @@ -159,19 +159,19 @@ export function SavedFunnelsMetricForm(): JSX.Element { }, }) }} - stepsLength={savedMetricQuery.funnels_query?.series?.length} + stepsLength={sharedMetricQuery.funnels_query?.series?.length} /> { - const val = savedMetricQuery.funnels_query?.filterTestAccounts + const val = sharedMetricQuery.funnels_query?.filterTestAccounts return hasFilters ? !!val : false })()} onChange={(checked: boolean) => { - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, funnels_query: { - ...savedMetricQuery.funnels_query, + ...sharedMetricQuery.funnels_query, filterTestAccounts: checked, }, }, @@ -190,7 +190,7 @@ export function SavedFunnelsMetricForm(): JSX.Element { ({ - savedMetricId: id === 'new' ? 'new' : parseInt(id), + sharedMetricId: id === 'new' ? 'new' : parseInt(id), }), } -export function SavedMetric(): JSX.Element { - const { savedMetricId, savedMetric } = useValues(savedMetricLogic) - const { setSavedMetric, createSavedMetric, updateSavedMetric, deleteSavedMetric } = useActions(savedMetricLogic) +export function SharedMetric(): JSX.Element { + const { sharedMetricId, sharedMetric } = useValues(sharedMetricLogic) + const { setSharedMetric, createSharedMetric, updateSharedMetric, deleteSharedMetric } = + useActions(sharedMetricLogic) const { isDarkModeOn } = useValues(themeLogic) - if (!savedMetric || !savedMetric.query) { + if (!sharedMetric || !sharedMetric.query) { return (
@@ -37,19 +37,19 @@ export function SavedMetric(): JSX.Element {
{ - setSavedMetric({ + setSharedMetric({ query: getDefaultTrendsMetric(), }) }} >
Trend - {savedMetric.query.kind === NodeKind.ExperimentTrendsQuery && ( + {sharedMetric.query.kind === NodeKind.ExperimentTrendsQuery && ( )}
@@ -59,19 +59,19 @@ export function SavedMetric(): JSX.Element {
{ - setSavedMetric({ + setSharedMetric({ query: getDefaultFunnelsMetric(), }) }} >
Funnel - {savedMetric.query.kind === NodeKind.ExperimentFunnelsQuery && ( + {sharedMetric.query.kind === NodeKind.ExperimentFunnelsQuery && ( )}
@@ -84,9 +84,9 @@ export function SavedMetric(): JSX.Element {
Name { - setSavedMetric({ + setSharedMetric({ name: newName, }) }} @@ -95,18 +95,18 @@ export function SavedMetric(): JSX.Element {
Description (optional) { - setSavedMetric({ + setSharedMetric({ description: newDescription, }) }} />
- {savedMetric.query.kind === NodeKind.ExperimentTrendsQuery ? ( - + {sharedMetric.query.kind === NodeKind.ExperimentTrendsQuery ? ( + ) : ( - + )}
@@ -121,7 +121,7 @@ export function SavedMetric(): JSX.Element { primaryButton: { children: 'Delete', type: 'primary', - onClick: () => deleteSavedMetric(), + onClick: () => deleteSharedMetric(), size: 'small', }, secondaryButton: { @@ -135,14 +135,14 @@ export function SavedMetric(): JSX.Element { Delete { - if (savedMetricId === 'new') { - createSavedMetric() + if (sharedMetricId === 'new') { + createSharedMetric() } else { - updateSavedMetric() + updateSharedMetric() } }} > diff --git a/frontend/src/scenes/experiments/SavedMetrics/SavedMetrics.tsx b/frontend/src/scenes/experiments/SharedMetrics/SharedMetrics.tsx similarity index 69% rename from frontend/src/scenes/experiments/SavedMetrics/SavedMetrics.tsx rename to frontend/src/scenes/experiments/SharedMetrics/SharedMetrics.tsx index fab8705189275..4ec8f7fa26ac2 100644 --- a/frontend/src/scenes/experiments/SavedMetrics/SavedMetrics.tsx +++ b/frontend/src/scenes/experiments/SharedMetrics/SharedMetrics.tsx @@ -7,20 +7,20 @@ import { createdAtColumn } from 'lib/lemon-ui/LemonTable/columnUtils' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { SavedMetric } from './savedMetricLogic' -import { savedMetricsLogic } from './savedMetricsLogic' +import { SharedMetric } from './sharedMetricLogic' +import { sharedMetricsLogic } from './sharedMetricsLogic' export const scene: SceneExport = { - component: SavedMetrics, - logic: savedMetricsLogic, + component: SharedMetrics, + logic: sharedMetricsLogic, } -const columns: LemonTableColumns = [ +const columns: LemonTableColumns = [ { key: 'name', title: 'Name', - render: (_, savedMetric) => { - return
{savedMetric.name}
+ render: (_, sharedMetric) => { + return
{sharedMetric.name}
}, }, { @@ -28,12 +28,12 @@ const columns: LemonTableColumns = [ title: 'Description', dataIndex: 'description', }, - createdByColumn() as LemonTableColumn, - createdAtColumn() as LemonTableColumn, + createdByColumn() as LemonTableColumn, + createdAtColumn() as LemonTableColumn, { key: 'actions', title: 'Actions', - render: (_, savedMetric) => { + render: (_, sharedMetric) => { return ( = [ size="xsmall" icon={} onClick={() => { - router.actions.push(urls.experimentsSavedMetric(savedMetric.id)) + router.actions.push(urls.experimentsSharedMetric(sharedMetric.id)) }} /> ) @@ -49,8 +49,8 @@ const columns: LemonTableColumns = [ }, ] -export function SavedMetrics(): JSX.Element { - const { savedMetrics, savedMetricsLoading } = useValues(savedMetricsLogic) +export function SharedMetrics(): JSX.Element { + const { sharedMetrics, sharedMetricsLoading } = useValues(sharedMetricsLogic) return (
@@ -69,14 +69,14 @@ export function SavedMetrics(): JSX.Element { having to set them up each time.
- + New shared metric
You haven't created any shared metrics yet.
} />
diff --git a/frontend/src/scenes/experiments/SavedMetrics/SavedTrendsMetricForm.tsx b/frontend/src/scenes/experiments/SharedMetrics/SharedTrendsMetricForm.tsx similarity index 87% rename from frontend/src/scenes/experiments/SavedMetrics/SavedTrendsMetricForm.tsx rename to frontend/src/scenes/experiments/SharedMetrics/SharedTrendsMetricForm.tsx index 7b8068f945bbd..b1f712f3c3aa1 100644 --- a/frontend/src/scenes/experiments/SavedMetrics/SavedTrendsMetricForm.tsx +++ b/frontend/src/scenes/experiments/SharedMetrics/SharedTrendsMetricForm.tsx @@ -16,20 +16,20 @@ import { ExperimentTrendsQuery, InsightQueryNode, NodeKind } from '~/queries/sch import { BaseMathType, ChartDisplayType, FilterType, PropertyMathType } from '~/types' import { commonActionFilterProps } from '../Metrics/Selectors' -import { savedMetricLogic } from './savedMetricLogic' +import { sharedMetricLogic } from './sharedMetricLogic' -export function SavedTrendsMetricForm(): JSX.Element { - const { savedMetric } = useValues(savedMetricLogic) - const { setSavedMetric } = useActions(savedMetricLogic) +export function SharedTrendsMetricForm(): JSX.Element { + const { sharedMetric } = useValues(sharedMetricLogic) + const { setSharedMetric } = useActions(sharedMetricLogic) const { currentTeam } = useValues(teamLogic) const hasFilters = (currentTeam?.test_account_filters || []).length > 0 const [activeTab, setActiveTab] = useState('main') - if (!savedMetric?.query) { + if (!sharedMetric?.query) { return <> } - const savedMetricQuery = savedMetric.query as ExperimentTrendsQuery + const sharedMetricQuery = sharedMetric.query as ExperimentTrendsQuery return ( <> @@ -44,18 +44,18 @@ export function SavedTrendsMetricForm(): JSX.Element { <> ): void => { const series = actionsAndEventsToSeries( { actions, events, data_warehouse } as any, true, MathAvailability.All ) - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, count_query: { - ...savedMetricQuery.count_query, + ...sharedMetricQuery.count_query, series, }, }, @@ -72,15 +72,15 @@ export function SavedTrendsMetricForm(): JSX.Element {
{ - const val = savedMetricQuery.count_query?.filterTestAccounts + const val = sharedMetricQuery.count_query?.filterTestAccounts return hasFilters ? !!val : false })()} onChange={(checked: boolean) => { - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, count_query: { - ...savedMetricQuery.count_query, + ...sharedMetricQuery.count_query, filterTestAccounts: checked, }, }, @@ -97,7 +97,7 @@ export function SavedTrendsMetricForm(): JSX.Element {
{ - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, exposure_query: undefined, }, }) @@ -131,7 +131,7 @@ export function SavedTrendsMetricForm(): JSX.Element { >
Default - {!savedMetricQuery.exposure_query && ( + {!sharedMetricQuery.exposure_query && ( )}
@@ -144,14 +144,14 @@ export function SavedTrendsMetricForm(): JSX.Element {
{ - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, exposure_query: { kind: NodeKind.TrendsQuery, series: [ @@ -181,7 +181,7 @@ export function SavedTrendsMetricForm(): JSX.Element { >
Custom - {savedMetricQuery.exposure_query && ( + {sharedMetricQuery.exposure_query && ( )}
@@ -192,12 +192,12 @@ export function SavedTrendsMetricForm(): JSX.Element {
- {savedMetricQuery.exposure_query && ( + {sharedMetricQuery.exposure_query && ( <> { - const val = savedMetricQuery.exposure_query?.filterTestAccounts + const val = sharedMetricQuery.exposure_query?.filterTestAccounts return hasFilters ? !!val : false })()} onChange={(checked: boolean) => { - setSavedMetric({ + setSharedMetric({ query: { - ...savedMetricQuery, + ...sharedMetricQuery, exposure_query: { - ...savedMetricQuery.exposure_query, + ...sharedMetricQuery.exposure_query, filterTestAccounts: checked, }, }, @@ -255,7 +255,7 @@ export function SavedTrendsMetricForm(): JSX.Element { = { +export const NEW_SHARED_METRIC: Partial = { name: '', description: '', query: getDefaultTrendsMetric(), } -export const savedMetricLogic = kea([ - props({} as SavedMetricLogicProps), - path((key) => ['scenes', 'experiments', 'savedMetricLogic', key]), - key((props) => props.savedMetricId || 'new'), +export const sharedMetricLogic = kea([ + props({} as SharedMetricLogicProps), + path((key) => ['scenes', 'experiments', 'sharedMetricLogic', key]), + key((props) => props.sharedMetricId || 'new'), connect(() => ({ - actions: [savedMetricsLogic, ['loadSavedMetrics']], + actions: [sharedMetricsLogic, ['loadSharedMetrics']], })), actions({ - setSavedMetric: (metric: Partial) => ({ metric }), - createSavedMetric: true, - updateSavedMetric: true, - deleteSavedMetric: true, + setSharedMetric: (metric: Partial) => ({ metric }), + createSharedMetric: true, + updateSharedMetric: true, + deleteSharedMetric: true, }), loaders(({ props }) => ({ - savedMetric: { - loadSavedMetric: async () => { - if (props.savedMetricId && props.savedMetricId !== 'new') { + sharedMetric: { + loadSharedMetric: async () => { + if (props.sharedMetricId && props.sharedMetricId !== 'new') { const response = await api.get( - `api/projects/@current/experiment_saved_metrics/${props.savedMetricId}` + `api/projects/@current/experiment_saved_metrics/${props.sharedMetricId}` ) - return response as SavedMetric + return response as SharedMetric } - return { ...NEW_SAVED_METRIC } + return { ...NEW_SHARED_METRIC } }, }, })), listeners(({ actions, values }) => ({ - createSavedMetric: async () => { - const response = await api.create(`api/projects/@current/experiment_saved_metrics/`, values.savedMetric) + createSharedMetric: async () => { + const response = await api.create(`api/projects/@current/experiment_saved_metrics/`, values.sharedMetric) if (response.id) { lemonToast.success('Shared metric created successfully') - actions.loadSavedMetrics() + actions.loadSharedMetrics() router.actions.push('/experiments/shared-metrics') } }, - updateSavedMetric: async () => { + updateSharedMetric: async () => { const response = await api.update( - `api/projects/@current/experiment_saved_metrics/${values.savedMetricId}`, - values.savedMetric + `api/projects/@current/experiment_saved_metrics/${values.sharedMetricId}`, + values.sharedMetric ) if (response.id) { lemonToast.success('Shared metric updated successfully') - actions.loadSavedMetrics() + actions.loadSharedMetrics() router.actions.push('/experiments/shared-metrics') } }, - deleteSavedMetric: async () => { + deleteSharedMetric: async () => { try { - await api.delete(`api/projects/@current/experiment_saved_metrics/${values.savedMetricId}`) + await api.delete(`api/projects/@current/experiment_saved_metrics/${values.sharedMetricId}`) lemonToast.success('Shared metric deleted successfully') - actions.loadSavedMetrics() + actions.loadSharedMetrics() router.actions.push('/experiments/shared-metrics') } catch (error) { lemonToast.error('Failed to delete shared metric') @@ -92,20 +92,20 @@ export const savedMetricLogic = kea([ })), reducers({ - savedMetric: [ - { ...NEW_SAVED_METRIC } as Partial, + sharedMetric: [ + { ...NEW_SHARED_METRIC } as Partial, { - setSavedMetric: (state, { metric }) => ({ ...state, ...metric }), + setSharedMetric: (state, { metric }) => ({ ...state, ...metric }), }, ], }), selectors({ - savedMetricId: [ - () => [(_, props) => props.savedMetricId ?? 'new'], - (savedMetricId): string | number => savedMetricId, + sharedMetricId: [ + () => [(_, props) => props.sharedMetricId ?? 'new'], + (sharedMetricId): string | number => sharedMetricId, ], - isNew: [(s) => [s.savedMetricId], (savedMetricId) => savedMetricId === 'new'], + isNew: [(s) => [s.sharedMetricId], (sharedMetricId) => sharedMetricId === 'new'], }), urlToAction(({ actions, values }) => ({ @@ -115,11 +115,11 @@ export const savedMetricLogic = kea([ if (id && didPathChange) { const parsedId = id === 'new' ? 'new' : parseInt(id) if (parsedId === 'new') { - actions.setSavedMetric({ ...NEW_SAVED_METRIC }) + actions.setSharedMetric({ ...NEW_SHARED_METRIC }) } - if (parsedId !== 'new' && parsedId === values.savedMetricId) { - actions.loadSavedMetric() + if (parsedId !== 'new' && parsedId === values.sharedMetricId) { + actions.loadSharedMetric() } } }, diff --git a/frontend/src/scenes/experiments/SharedMetrics/sharedMetricsLogic.tsx b/frontend/src/scenes/experiments/SharedMetrics/sharedMetricsLogic.tsx new file mode 100644 index 0000000000000..bbf460c21510f --- /dev/null +++ b/frontend/src/scenes/experiments/SharedMetrics/sharedMetricsLogic.tsx @@ -0,0 +1,48 @@ +import { actions, events, kea, listeners, path, reducers } from 'kea' +import { loaders } from 'kea-loaders' +import { router } from 'kea-router' +import api from 'lib/api' + +import { SharedMetric } from './sharedMetricLogic' +import type { sharedMetricsLogicType } from './sharedMetricsLogicType' + +export enum SharedMetricsTabs { + All = 'all', + Yours = 'yours', + Archived = 'archived', +} + +export const sharedMetricsLogic = kea([ + path(['scenes', 'experiments', 'sharedMetricsLogic']), + actions({ + setSharedMetricsTab: (tabKey: SharedMetricsTabs) => ({ tabKey }), + }), + + loaders({ + sharedMetrics: { + loadSharedMetrics: async () => { + const response = await api.get('api/projects/@current/experiment_saved_metrics') + return response.results as SharedMetric[] + }, + }, + }), + + reducers({ + tab: [ + SharedMetricsTabs.All as SharedMetricsTabs, + { + setSharedMetricsTab: (_, { tabKey }) => tabKey, + }, + ], + }), + listeners(() => ({ + setSharedMetricsTab: () => { + router.actions.push('/experiments/shared-metrics') + }, + })), + events(({ actions }) => ({ + afterMount: () => { + actions.loadSharedMetrics() + }, + })), +]) diff --git a/frontend/src/scenes/experiments/experimentLogic.tsx b/frontend/src/scenes/experiments/experimentLogic.tsx index d44f9ba7ea7ea..a67614429c6ec 100644 --- a/frontend/src/scenes/experiments/experimentLogic.tsx +++ b/frontend/src/scenes/experiments/experimentLogic.tsx @@ -64,8 +64,8 @@ import { MetricInsightId } from './constants' import type { experimentLogicType } from './experimentLogicType' import { experimentsLogic } from './experimentsLogic' import { holdoutsLogic } from './holdoutsLogic' -import { SavedMetric } from './SavedMetrics/savedMetricLogic' -import { savedMetricsLogic } from './SavedMetrics/savedMetricsLogic' +import { SharedMetric } from './SharedMetrics/sharedMetricLogic' +import { sharedMetricsLogic } from './SharedMetrics/sharedMetricsLogic' import { getMinimumDetectableEffect, transformFiltersForWinningVariant } from './utils' const NEW_EXPERIMENT: Experiment = { @@ -136,8 +136,8 @@ export const experimentLogic = kea([ ['insightDataLoading as trendMetricInsightLoading'], insightDataLogic({ dashboardItemId: MetricInsightId.Funnels }), ['insightDataLoading as funnelMetricInsightLoading'], - savedMetricsLogic, - ['savedMetrics'], + sharedMetricsLogic, + ['sharedMetrics'], ], actions: [ experimentsLogic, @@ -269,18 +269,18 @@ export const experimentLogic = kea([ closePrimaryMetricSourceModal: true, openSecondaryMetricSourceModal: true, closeSecondaryMetricSourceModal: true, - openPrimarySavedMetricModal: (savedMetricId: SavedMetric['id'] | null) => ({ savedMetricId }), - closePrimarySavedMetricModal: true, - openSecondarySavedMetricModal: (savedMetricId: SavedMetric['id'] | null) => ({ savedMetricId }), - closeSecondarySavedMetricModal: true, - addSavedMetricToExperiment: ( - savedMetricId: SavedMetric['id'], + openPrimarySharedMetricModal: (sharedMetricId: SharedMetric['id'] | null) => ({ sharedMetricId }), + closePrimarySharedMetricModal: true, + openSecondarySharedMetricModal: (sharedMetricId: SharedMetric['id'] | null) => ({ sharedMetricId }), + closeSecondarySharedMetricModal: true, + addSharedMetricToExperiment: ( + sharedMetricId: SharedMetric['id'], metadata: { type: 'primary' | 'secondary' } ) => ({ - savedMetricId, + sharedMetricId, metadata, }), - removeSavedMetricFromExperiment: (savedMetricId: SavedMetric['id']) => ({ savedMetricId }), + removeSharedMetricFromExperiment: (sharedMetricId: SharedMetric['id']) => ({ sharedMetricId }), }), reducers({ experiment: [ @@ -523,13 +523,13 @@ export const experimentLogic = kea([ updateExperimentGoal: () => null, }, ], - editingSavedMetricId: [ - null as SavedMetric['id'] | null, + editingSharedMetricId: [ + null as SharedMetric['id'] | null, { - openPrimarySavedMetricModal: (_, { savedMetricId }) => savedMetricId, - openSecondarySavedMetricModal: (_, { savedMetricId }) => savedMetricId, - closePrimarySavedMetricModal: () => null, - closeSecondarySavedMetricModal: () => null, + openPrimarySharedMetricModal: (_, { sharedMetricId }) => sharedMetricId, + openSecondarySharedMetricModal: (_, { sharedMetricId }) => sharedMetricId, + closePrimarySharedMetricModal: () => null, + closeSecondarySharedMetricModal: () => null, updateExperimentGoal: () => null, }, ], @@ -555,18 +555,18 @@ export const experimentLogic = kea([ closeSecondaryMetricSourceModal: () => false, }, ], - isPrimarySavedMetricModalOpen: [ + isPrimarySharedMetricModalOpen: [ false, { - openPrimarySavedMetricModal: () => true, - closePrimarySavedMetricModal: () => false, + openPrimarySharedMetricModal: () => true, + closePrimarySharedMetricModal: () => false, }, ], - isSecondarySavedMetricModalOpen: [ + isSecondarySharedMetricModalOpen: [ false, { - openSecondarySavedMetricModal: () => true, - closeSecondarySavedMetricModal: () => false, + openSecondarySharedMetricModal: () => true, + closeSecondarySharedMetricModal: () => false, }, ], }), @@ -750,10 +750,10 @@ export const experimentLogic = kea([ closeSecondaryMetricModal: () => { actions.loadExperiment() }, - closePrimarySavedMetricModal: () => { + closePrimarySharedMetricModal: () => { actions.loadExperiment() }, - closeSecondarySavedMetricModal: () => { + closeSecondarySharedMetricModal: () => { actions.loadExperiment() }, resetRunningExperiment: async () => { @@ -901,34 +901,34 @@ export const experimentLogic = kea([ holdout_id: values.experiment.holdout_id, }) }, - addSavedMetricToExperiment: async ({ savedMetricId, metadata }) => { - const savedMetricsIds = values.experiment.saved_metrics.map((savedMetric) => ({ - id: savedMetric.saved_metric, + addSharedMetricToExperiment: async ({ sharedMetricId, metadata }) => { + const sharedMetricsIds = values.experiment.saved_metrics.map((sharedMetric) => ({ + id: sharedMetric.saved_metric, metadata, })) - savedMetricsIds.push({ id: savedMetricId, metadata }) + sharedMetricsIds.push({ id: sharedMetricId, metadata }) await api.update(`api/projects/${values.currentProjectId}/experiments/${values.experimentId}`, { - saved_metrics_ids: savedMetricsIds, + saved_metrics_ids: sharedMetricsIds, }) - actions.closePrimarySavedMetricModal() - actions.closeSecondarySavedMetricModal() + actions.closePrimarySharedMetricModal() + actions.closeSecondarySharedMetricModal() actions.loadExperiment() }, - removeSavedMetricFromExperiment: async ({ savedMetricId }) => { - const savedMetricsIds = values.experiment.saved_metrics - .filter((savedMetric) => savedMetric.saved_metric !== savedMetricId) - .map((savedMetric) => ({ - id: savedMetric.saved_metric, - metadata: savedMetric.metadata, + removeSharedMetricFromExperiment: async ({ sharedMetricId }) => { + const sharedMetricsIds = values.experiment.saved_metrics + .filter((sharedMetric) => sharedMetric.saved_metric !== sharedMetricId) + .map((sharedMetric) => ({ + id: sharedMetric.saved_metric, + metadata: sharedMetric.metadata, })) await api.update(`api/projects/${values.currentProjectId}/experiments/${values.experimentId}`, { - saved_metrics_ids: savedMetricsIds, + saved_metrics_ids: sharedMetricsIds, }) - actions.closePrimarySavedMetricModal() - actions.closeSecondarySavedMetricModal() + actions.closePrimarySharedMetricModal() + actions.closeSecondarySharedMetricModal() actions.loadExperiment() }, })), @@ -966,11 +966,11 @@ export const experimentLogic = kea([ refresh?: boolean ): Promise<(CachedExperimentTrendsQueryResponse | CachedExperimentFunnelsQueryResponse | null)[]> => { let metrics = values.experiment?.metrics - const savedMetrics = values.experiment?.saved_metrics - .filter((savedMetric) => savedMetric.metadata.type === 'primary') - .map((savedMetric) => savedMetric.query) - if (savedMetrics) { - metrics = [...metrics, ...savedMetrics] + const sharedMetrics = values.experiment?.saved_metrics + .filter((sharedMetric) => sharedMetric.metadata.type === 'primary') + .map((sharedMetric) => sharedMetric.query) + if (sharedMetrics) { + metrics = [...metrics, ...sharedMetrics] } return (await Promise.all( @@ -1011,11 +1011,11 @@ export const experimentLogic = kea([ refresh?: boolean ): Promise<(CachedExperimentTrendsQueryResponse | CachedExperimentFunnelsQueryResponse | null)[]> => { let metrics = values.experiment?.metrics_secondary - const savedMetrics = values.experiment?.saved_metrics - .filter((savedMetric) => savedMetric.metadata.type === 'secondary') - .map((savedMetric) => savedMetric.query) - if (savedMetrics) { - metrics = [...metrics, ...savedMetrics] + const sharedMetrics = values.experiment?.saved_metrics + .filter((sharedMetric) => sharedMetric.metadata.type === 'secondary') + .map((sharedMetric) => sharedMetric.query) + if (sharedMetrics) { + metrics = [...metrics, ...sharedMetrics] } return (await Promise.all( diff --git a/frontend/src/scenes/experiments/experimentsLogic.ts b/frontend/src/scenes/experiments/experimentsLogic.ts index 811beec33145e..f7d71502a80cf 100644 --- a/frontend/src/scenes/experiments/experimentsLogic.ts +++ b/frontend/src/scenes/experiments/experimentsLogic.ts @@ -76,8 +76,8 @@ export const experimentsLogic = kea([ }), listeners(({ actions }) => ({ setExperimentsTab: ({ tabKey }) => { - if (tabKey === ExperimentsTabs.SavedMetrics) { - // Saved Metrics is a fake tab that we use to redirect to the saved metrics page + if (tabKey === ExperimentsTabs.SharedMetrics) { + // Saved Metrics is a fake tab that we use to redirect to the shared metrics page actions.setExperimentsTab(ExperimentsTabs.All) router.actions.push('/experiments/shared-metrics') } else { diff --git a/frontend/src/scenes/sceneTypes.ts b/frontend/src/scenes/sceneTypes.ts index f4ae177e0d461..c3dd4b17bb3ad 100644 --- a/frontend/src/scenes/sceneTypes.ts +++ b/frontend/src/scenes/sceneTypes.ts @@ -37,8 +37,8 @@ export enum Scene { Group = 'Group', Action = 'Action', Experiments = 'Experiments', - ExperimentsSavedMetrics = 'ExperimentsSavedMetrics', - ExperimentsSavedMetric = 'ExperimentsSavedMetric', + ExperimentsSharedMetrics = 'ExperimentsSharedMetrics', + ExperimentsSharedMetric = 'ExperimentsSharedMetric', Experiment = 'Experiment', FeatureManagement = 'FeatureManagement', FeatureFlags = 'FeatureFlags', diff --git a/frontend/src/scenes/scenes.ts b/frontend/src/scenes/scenes.ts index b7b3dba72025a..0cf02f1d81ba8 100644 --- a/frontend/src/scenes/scenes.ts +++ b/frontend/src/scenes/scenes.ts @@ -211,13 +211,13 @@ export const sceneConfigurations: Record = { defaultDocsPath: '/docs/experiments/creating-an-experiment', activityScope: ActivityScope.EXPERIMENT, }, - [Scene.ExperimentsSavedMetric]: { + [Scene.ExperimentsSharedMetric]: { projectBased: true, name: 'Shared metric', defaultDocsPath: '/docs/experiments/creating-an-experiment', activityScope: ActivityScope.EXPERIMENT, }, - [Scene.ExperimentsSavedMetrics]: { + [Scene.ExperimentsSharedMetrics]: { projectBased: true, name: 'Shared metrics', defaultDocsPath: '/docs/experiments/creating-an-experiment', @@ -581,8 +581,8 @@ export const routes: Record = { [urls.cohort(':id')]: Scene.Cohort, [urls.cohorts()]: Scene.PersonsManagement, [urls.experiments()]: Scene.Experiments, - [urls.experimentsSavedMetrics()]: Scene.ExperimentsSavedMetrics, - [urls.experimentsSavedMetric(':id')]: Scene.ExperimentsSavedMetric, + [urls.experimentsSharedMetrics()]: Scene.ExperimentsSharedMetrics, + [urls.experimentsSharedMetric(':id')]: Scene.ExperimentsSharedMetric, [urls.experiment(':id')]: Scene.Experiment, [urls.earlyAccessFeatures()]: Scene.EarlyAccessFeatures, [urls.earlyAccessFeature(':id')]: Scene.EarlyAccessFeature, diff --git a/frontend/src/scenes/urls.ts b/frontend/src/scenes/urls.ts index 43ce620de0d80..cace92f08b5fb 100644 --- a/frontend/src/scenes/urls.ts +++ b/frontend/src/scenes/urls.ts @@ -159,8 +159,8 @@ export const urls = { cohorts: (): string => '/cohorts', experiment: (id: string | number): string => `/experiments/${id}`, experiments: (): string => '/experiments', - experimentsSavedMetrics: (): string => '/experiments/shared-metrics', - experimentsSavedMetric: (id: string | number): string => `/experiments/shared-metrics/${id}`, + experimentsSharedMetrics: (): string => '/experiments/shared-metrics', + experimentsSharedMetric: (id: string | number): string => `/experiments/shared-metrics/${id}`, featureFlags: (tab?: string): string => `/feature_flags${tab ? `?tab=${tab}` : ''}`, featureFlag: (id: string | number): string => `/feature_flags/${id}`, featureManagement: (id?: string | number): string => `/features${id ? `/${id}` : ''}`, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 2209996a3871b..e638db249c396 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -709,7 +709,7 @@ export enum ExperimentsTabs { Yours = 'yours', Archived = 'archived', Holdouts = 'holdouts', - SavedMetrics = 'shared-metrics', + SharedMetrics = 'shared-metrics', } export enum ActivityTab {