Skip to content

Commit 31c9dc9

Browse files
authored
feat: improve experiment recommendation and disable Snowflake warehouse (#7940)
1 parent 44206a2 commit 31c9dc9

6 files changed

Lines changed: 96 additions & 26 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { FC, useMemo } from 'react'
2+
import Icon from 'components/icons/Icon'
3+
import { colorTextSuccess } from 'common/theme/tokens'
4+
import { BayesianResultsSummary, Experiment } from 'common/types/responses'
5+
import { deriveSummary } from './ExperimentSummaryScorecard'
6+
import VariantName from './VariantName'
7+
8+
type ExperimentRecommendationProps = {
9+
experiment: Experiment
10+
results?: BayesianResultsSummary
11+
}
12+
13+
const ExperimentRecommendation: FC<ExperimentRecommendationProps> = ({
14+
experiment,
15+
results,
16+
}) => {
17+
const summary = useMemo(
18+
() => (results ? deriveSummary(experiment, results) : null),
19+
[experiment, results],
20+
)
21+
22+
if (!summary) return null
23+
24+
return (
25+
<div className='alert alert-success experiment-recommendation mb-3'>
26+
<div className='d-flex align-items-center gap-2 mb-2'>
27+
<Icon name='checkmark-circle' width={20} fill={colorTextSuccess} />
28+
<span className='text-success fw-semibold'>
29+
{summary.chanceToBest} Winner Probability Confirmed
30+
</span>
31+
</div>
32+
<div>
33+
<VariantName name={summary.winnerName} colour={summary.winnerColour} />{' '}
34+
is outperforming{' '}
35+
<VariantName name='Control' colour={summary.controlColour} /> by{' '}
36+
{summary.liftVsControl} with {summary.chanceToBest} probability of being
37+
the best variant.
38+
</div>
39+
<div className='mt-2'>
40+
Consider rolling out{' '}
41+
<VariantName name={summary.winnerName} colour={summary.winnerColour} />{' '}
42+
to all users.
43+
</div>
44+
</div>
45+
)
46+
}
47+
48+
export default ExperimentRecommendation

frontend/web/components/experiments/results/ExperimentSummaryScorecard.tsx

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { FC, useMemo } from 'react'
2-
import Icon from 'components/icons/Icon'
32
import InfoMessage from 'components/InfoMessage'
4-
import { colorTextSuccess } from 'common/theme/tokens'
53
import { BayesianResultsSummary, Experiment } from 'common/types/responses'
64
import { getPrimaryMetric } from 'components/experiments/constants'
75
import {
@@ -19,14 +17,16 @@ type ExperimentSummaryScorecardProps = {
1917
results?: BayesianResultsSummary
2018
}
2119

22-
type SummaryStats = {
20+
export type SummaryStats = {
2321
winnerName: string
22+
winnerColour: string
23+
controlColour: string
2424
chanceToBest: string
2525
liftVsControl: string
2626
liftFavourable: boolean
2727
}
2828

29-
const deriveSummary = (
29+
export const deriveSummary = (
3030
experiment: Experiment,
3131
results: BayesianResultsSummary,
3232
): SummaryStats | null => {
@@ -39,13 +39,18 @@ const deriveSummary = (
3939
const winner = getWinningVariant(metricResult, identities)
4040
if (!winner) return null
4141

42+
const winnerIdentity = identities.find((v) => v.key === winner.key)
43+
const controlIdentity = identities.find((v) => v.isControl)
44+
4245
return {
4346
chanceToBest: `${Math.round(winner.chanceToWin * 100)}%`,
47+
controlColour: controlIdentity?.colour ?? '',
4448
liftFavourable: isLiftFavourable(
4549
winner.inference.lift,
4650
metric.expected_direction,
4751
),
4852
liftVsControl: formatLiftPct(winner.inference.lift),
53+
winnerColour: winnerIdentity?.colour ?? '',
4954
winnerName: winner.name,
5055
}
5156
}
@@ -63,25 +68,11 @@ const ExperimentSummaryScorecard: FC<ExperimentSummaryScorecardProps> = ({
6368

6469
return (
6570
<>
66-
{summary ? (
67-
<div className='alert alert-success mb-3'>
68-
<div className='d-flex align-items-center gap-2 mb-1'>
69-
<Icon name='checkmark-circle' width={20} fill={colorTextSuccess} />
70-
<span className='text-success fw-normal'>Recommendation</span>
71-
</div>
72-
<div>
73-
<strong>{summary.winnerName}</strong> is outperforming{' '}
74-
<strong>Control</strong> with {summary.chanceToBest} probability of
75-
being the best variant.
76-
</div>
77-
</div>
78-
) : (
79-
hasResults && (
80-
<InfoMessage title='Collecting data'>
81-
The experiment is still gathering data. Results will appear once
82-
there is enough traffic for statistically meaningful analysis.
83-
</InfoMessage>
84-
)
71+
{!summary && hasResults && (
72+
<InfoMessage title='Collecting data'>
73+
The experiment is still gathering data. Results will appear once there
74+
is enough traffic for statistically meaningful analysis.
75+
</InfoMessage>
8576
)}
8677
<div className='row g-3 mb-4'>
8778
<div className='col-md-3'>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { FC } from 'react'
2+
import ColorSwatch from 'components/ColorSwatch'
3+
4+
type VariantNameProps = {
5+
name: string
6+
colour: string
7+
}
8+
9+
const VariantName: FC<VariantNameProps> = ({ colour, name }) => (
10+
<span>
11+
<ColorSwatch
12+
color={colour}
13+
shape='circle'
14+
size='sm'
15+
className='me-1 align-middle'
16+
/>
17+
<strong>{name}</strong>
18+
</span>
19+
)
20+
21+
export default VariantName

frontend/web/components/experiments/results/results.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
align-items: flex-start;
33
}
44

5+
.experiment-recommendation {
6+
font-size: 16px;
7+
}
8+
59
.experiment-results {
610
&__legend-row {
711
display: flex;

frontend/web/components/pages/ExperimentDetailPage.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { getHeadlineTotal } from 'components/experiments/results/derive'
1010
import ExperimentDetailHeader from 'components/experiments/results/ExperimentDetailHeader'
1111
import ExperimentConfiguration from 'components/experiments/results/ExperimentConfiguration'
12+
import ExperimentRecommendation from 'components/experiments/results/ExperimentRecommendation'
1213
import ExperimentSummaryScorecard from 'components/experiments/results/ExperimentSummaryScorecard'
1314
import ExperimentMetricScorecard from 'components/experiments/results/ExperimentMetricScorecard'
1415
import ExperimentExposuresPanel from 'components/experiments/results/ExperimentExposuresPanel'
@@ -85,6 +86,9 @@ const ExperimentDetailPage: FC = () => {
8586
environmentId={environmentId}
8687
experiment={experiment}
8788
/>
89+
{experiment.status !== 'created' && (
90+
<ExperimentRecommendation experiment={experiment} results={results} />
91+
)}
8892
<ExperimentConfiguration
8993
experiment={experiment}
9094
environmentId={environmentId}

frontend/web/components/pages/environment-settings/tabs/warehouse-tab/WarehouseSetup.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type WarehouseSetupProps = {
1515

1616
type WarehouseTypeOption = WarehouseType | 'bigquery' | 'databricks'
1717

18-
const CONFIGURABLE_TYPES: WarehouseTypeOption[] = ['flagsmith', 'snowflake']
18+
const CONFIGURABLE_TYPES: WarehouseTypeOption[] = ['flagsmith']
1919

2020
const WarehouseSetup: FC<WarehouseSetupProps> = ({
2121
isCreating,
@@ -51,9 +51,11 @@ const WarehouseSetup: FC<WarehouseSetupProps> = ({
5151
icon={<Icon name='flash' width={20} />}
5252
title='Snowflake'
5353
description='Cloud data warehouse'
54-
selected={selectedType === 'snowflake'}
55-
onClick={() => setSelectedType('snowflake')}
54+
selected={false}
55+
onClick={() => {}}
56+
disabled
5657
/>
58+
<span className='warehouse-setup__coming-soon'>Coming Soon</span>
5759
</div>
5860
<div className='warehouse-setup__type-card'>
5961
<SelectableCard

0 commit comments

Comments
 (0)