Skip to content

Commit

Permalink
Merge branch 'master' into feat/cdp-error-events
Browse files Browse the repository at this point in the history
# Conflicts:
#	frontend/src/layout/navigation-3000/sidepanel/panels/activity/SidePanelActivitySubscriptions.tsx
#	frontend/src/scenes/pipeline/hogfunctions/filters/HogFunctionFiltersInternal.tsx
#	frontend/src/types.ts
  • Loading branch information
benjackwhite committed Dec 27, 2024
2 parents 0e0a080 + dd74b2c commit 227bc8a
Show file tree
Hide file tree
Showing 87 changed files with 1,591 additions and 1,815 deletions.
85 changes: 0 additions & 85 deletions cypress/e2e/experiments.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,89 +43,4 @@ describe('Experiments', () => {
// Save experiment
cy.get('[data-attr="save-experiment"]').first().click()
})

const createExperimentInNewUi = (): void => {
cy.visit('/experiments')

// Name, flag key, description
cy.get('[data-attr=create-experiment]').first().click()
cy.get('[data-attr=experiment-name]').click().type(`${experimentName}`).should('have.value', experimentName)
cy.get('[data-attr=experiment-feature-flag-key]')
.click()
.type(`${featureFlagKey}`)
.should('have.value', featureFlagKey)
cy.get('[data-attr=experiment-description]')
.click()
.type('This is the description of the experiment')
.should('have.value', 'This is the description of the experiment')

// Edit variants
cy.get('[data-attr="add-test-variant"]').click()
cy.get('input[data-attr="experiment-variant-key"][data-key-index="1"]')
.clear()
.type('test-variant-1')
.should('have.value', 'test-variant-1')
cy.get('input[data-attr="experiment-variant-key"][data-key-index="2"]')
.clear()
.type('test-variant-2')
.should('have.value', 'test-variant-2')

// Save experiment
cy.get('[data-attr="save-experiment"]').first().click()

// Set the experiment goal once the experiment is drafted
cy.get('[data-attr="add-experiment-goal"]').click()

// Wait for the goal modal to open and click the confirmation button
cy.get('.LemonModal__layout').should('be.visible')
cy.contains('Change experiment goal').should('be.visible')
cy.get('.LemonModal__content').contains('button', 'Add funnel step').click()
cy.get('.LemonModal__footer').contains('button', 'Save').click()
}

it('create, launch and stop experiment with new ui', () => {
createExperimentInNewUi()
cy.get('[data-attr="experiment-status"]').contains('draft').should('be.visible')

cy.get('[data-attr="experiment-creation-date"]').contains('a few seconds ago').should('be.visible')
cy.get('[data-attr="experiment-start-date"]').should('not.exist')

cy.wait(1000)
cy.get('[data-attr="launch-experiment"]').first().click()
cy.get('[data-attr="experiment-creation-date"]').should('not.exist')
cy.get('[data-attr="experiment-start-date"]').contains('a few seconds ago').should('be.visible')

cy.get('[data-attr="stop-experiment"]').first().click()
// Wait for the dialog to appear and click the confirmation button
cy.get('.LemonModal__layout').should('be.visible')
cy.contains('Stop this experiment?').should('be.visible')
cy.get('.LemonModal__footer').contains('button', 'Stop').click()
// Wait for the dialog to disappear
cy.get('[data-attr="experiment-creation-date"]').should('not.exist')
cy.get('[data-attr="experiment-start-date"]').contains('a few seconds ago').should('be.visible')
cy.get('[data-attr="experiment-end-date"]').contains('a few seconds ago').should('be.visible')
})

it('move start date', () => {
createExperimentInNewUi()

cy.wait(1000)
cy.get('[data-attr="launch-experiment"]').first().click()

cy.get('[data-attr="move-experiment-start-date"]').first().click()
cy.get('[data-attr="experiment-start-date-picker"]').should('exist')
cy.get('[data-attr="lemon-calendar-month-previous"]').first().click()
cy.get('[data-attr="lemon-calendar-day"]').first().click()
cy.get('[data-attr="lemon-calendar-select-apply"]').first().click()
cy.get('[data-attr="experiment-start-date"]')
.contains(/months? ago/)
.should('be.visible')

cy.reload()

// Check that the start date persists
cy.get('[data-attr="experiment-start-date"]')
.contains(/months? ago/)
.should('be.visible')
})
})
Binary file modified frontend/__snapshots__/lemon-ui-lemon-input--search--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-lemon-input--search--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 26 additions & 1 deletion frontend/src/lib/components/Alerts/alertFormLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ import { AlertType, AlertTypeWrite } from './types'

export type AlertFormType = Pick<
AlertType,
'name' | 'enabled' | 'created_at' | 'threshold' | 'condition' | 'subscribed_users' | 'checks' | 'config'
| 'name'
| 'enabled'
| 'created_at'
| 'calculation_interval'
| 'threshold'
| 'condition'
| 'subscribed_users'
| 'checks'
| 'config'
| 'skip_weekend'
> & {
id?: AlertType['id']
created_by?: AlertType['created_by'] | null
Expand Down Expand Up @@ -48,6 +57,7 @@ export const alertFormLogic = kea<alertFormLogicType>([
config: {
type: 'TrendsAlertConfig',
series_index: 0,
check_ongoing_interval: false,
},
threshold: { configuration: { type: InsightThresholdType.ABSOLUTE, bounds: {} } },
condition: {
Expand All @@ -56,6 +66,7 @@ export const alertFormLogic = kea<alertFormLogicType>([
subscribed_users: [],
checks: [],
calculation_interval: AlertCalculationInterval.DAILY,
skip_weekend: false,
insight: props.insightId,
} as AlertFormType),
errors: ({ name }) => ({
Expand All @@ -66,6 +77,20 @@ export const alertFormLogic = kea<alertFormLogicType>([
...alert,
subscribed_users: alert.subscribed_users?.map(({ id }) => id),
insight: props.insightId,
// can only skip weekends for hourly/daily alerts
skip_weekend:
(alert.calculation_interval === AlertCalculationInterval.DAILY ||
alert.calculation_interval === AlertCalculationInterval.HOURLY) &&
alert.skip_weekend,
// can only check ongoing interval for absolute value/increase alerts with upper threshold
config: {
...alert.config,
check_ongoing_interval:
(alert.condition.type === AlertConditionType.ABSOLUTE_VALUE ||
alert.condition.type === AlertConditionType.RELATIVE_INCREASE) &&
alert.threshold.configuration.bounds?.upper != null &&
alert.config.check_ongoing_interval,
},
}

// absolute value alert can only have absolute threshold
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/components/Alerts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface AlertTypeBase {
enabled: boolean
insight: QueryBasedInsightModel
config: AlertConfig
skip_weekend?: boolean
}

export interface AlertTypeWrite extends Omit<AlertTypeBase, 'insight'> {
Expand Down
55 changes: 55 additions & 0 deletions frontend/src/lib/components/Alerts/views/EditAlertModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { IconInfo } from '@posthog/icons'
import {
LemonBanner,
LemonCheckbox,
LemonInput,
LemonSegmentedButton,
LemonSelect,
SpinnerOverlay,
Tooltip,
} from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { Form, Group } from 'kea-forms'
Expand Down Expand Up @@ -97,6 +99,11 @@ export function EditAlertModal({
const { alertSeries, isNonTimeSeriesDisplay, isBreakdownValid, formula } = useValues(trendsLogic)

const creatingNewAlert = alertForm.id === undefined
// can only check ongoing interval for absolute value/increase alerts with upper threshold
const can_check_ongoing_interval =
(alertForm?.condition.type === AlertConditionType.ABSOLUTE_VALUE ||
alertForm?.condition.type === AlertConditionType.RELATIVE_INCREASE) &&
alertForm.threshold.configuration.bounds?.upper != null

return (
<LemonModal onClose={onClose} isOpen={isOpen} width={600} simple title="">
Expand Down Expand Up @@ -320,7 +327,55 @@ export function EditAlertModal({
</div>
</div>
</div>

<div className="space-y-2">
<h3 className="text-muted-alt">Advanced</h3>
<Group name={['config']}>
<div className="flex gap-1">
<LemonField name="check_ongoing_interval">
<LemonCheckbox
checked={
can_check_ongoing_interval &&
alertForm?.config.check_ongoing_interval
}
data-attr="alertForm-check-ongoing-interval"
fullWidth
label="Check ongoing period"
disabledReason={
!can_check_ongoing_interval &&
'Can only alert for ongoing period when checking for absolute value/increase above threshold'
}
/>
</LemonField>
<Tooltip
title={`Checks the insight value for the on going period (current week/month) that hasn't yet completed. Use this if you want to be alerted right away when the insight value rises/increases above threshold`}
placement="right"
delayMs={0}
>
<IconInfo />
</Tooltip>
</div>
</Group>
<LemonField name="skip_weekend">
<LemonCheckbox
checked={
(alertForm?.calculation_interval === AlertCalculationInterval.DAILY ||
alertForm?.calculation_interval === AlertCalculationInterval.HOURLY) &&
alertForm?.skip_weekend
}
data-attr="alertForm-skip-weekend"
fullWidth
label="Skip checking on weekends"
disabledReason={
alertForm?.calculation_interval !== AlertCalculationInterval.DAILY &&
alertForm?.calculation_interval !== AlertCalculationInterval.HOURLY &&
'Can only skip weekend checking for hourly/daily alerts'
}
/>
</LemonField>
</div>
</div>

{alert && <AlertStateTable alert={alert} />}
</LemonModal.Content>

Expand Down
1 change: 0 additions & 1 deletion frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ export const WEBHOOK_SERVICES: Record<string, string> = {
export const FEATURE_FLAGS = {
// Experiments / beta features
FUNNELS_CUE_OPT_OUT: 'funnels-cue-opt-out-7301', // owner: @neilkakkar
KAFKA_INSPECTOR: 'kafka-inspector', // owner: @yakkomajuri
HISTORICAL_EXPORTS_V2: 'historical-exports-v2', // owner @macobo
INGESTION_WARNINGS_ENABLED: 'ingestion-warnings-enabled', // owner: @tiina303
SESSION_RESET_ON_LOAD: 'session-reset-on-load', // owner: @benjackwhite
Expand Down
1 change: 0 additions & 1 deletion frontend/src/lib/lemon-ui/LemonInput/LemonInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
&.LemonInput--type-search {
// NOTE Design: Search inputs are given a specific small width
max-width: 240px;
border-radius: 0;
}

&.LemonInput--type-number {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7359,6 +7359,9 @@
"additionalProperties": false,
"description": "HogQL Query Options are automatically set per team. However, they can be overridden in the query.",
"properties": {
"bounceRateDurationSeconds": {
"type": "number"
},
"bounceRatePageViewMode": {
"enum": ["count_pageviews", "uniq_urls", "uniq_page_screen_autocaptures"],
"type": "string"
Expand Down Expand Up @@ -12519,6 +12522,9 @@
"TrendsAlertConfig": {
"additionalProperties": false,
"properties": {
"check_ongoing_interval": {
"type": "boolean"
},
"series_index": {
"type": "integer"
},
Expand Down Expand Up @@ -13264,6 +13270,7 @@
"InitialUTMSourceMediumCampaign",
"Browser",
"OS",
"Viewport",
"DeviceType",
"Country",
"Region",
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export interface HogQLQueryModifiers {
s3TableUseInvalidColumns?: boolean
personsJoinMode?: 'inner' | 'left'
bounceRatePageViewMode?: 'count_pageviews' | 'uniq_urls' | 'uniq_page_screen_autocaptures'
bounceRateDurationSeconds?: number
sessionTableVersion?: 'auto' | 'v1' | 'v2'
propertyGroupsMode?: 'enabled' | 'disabled' | 'optimized'
useMaterializedViews?: boolean
Expand Down Expand Up @@ -1822,6 +1823,7 @@ export enum WebStatsBreakdown {
InitialUTMSourceMediumCampaign = 'InitialUTMSourceMediumCampaign',
Browser = 'Browser',
OS = 'OS',
Viewport = 'Viewport',
DeviceType = 'DeviceType',
Country = 'Country',
Region = 'Region',
Expand Down Expand Up @@ -2379,6 +2381,7 @@ export enum AlertCalculationInterval {
export interface TrendsAlertConfig {
type: 'TrendsAlertConfig'
series_index: integer
check_ongoing_interval?: boolean
}

export interface HogCompileResponse {
Expand Down
25 changes: 19 additions & 6 deletions frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { WebExperimentImplementationDetails } from 'scenes/experiments/WebExperi

import { ExperimentImplementationDetails } from '../ExperimentImplementationDetails'
import { experimentLogic } from '../experimentLogic'
import { PrimaryMetricModal } from '../Metrics/PrimaryMetricModal'
import { MetricModal } from '../Metrics/MetricModal'
import { MetricsView } from '../MetricsView/MetricsView'
import {
ExperimentLoadingAnimation,
Expand Down Expand Up @@ -52,7 +52,11 @@ const ResultsTab = (): JSX.Element => {
)}
</>
)}
<SecondaryMetricsTable experimentId={experiment.id} />
{featureFlags[FEATURE_FLAGS.EXPERIMENTS_MULTIPLE_METRICS] ? (
<MetricsView isSecondary={true} />
) : (
<SecondaryMetricsTable experimentId={experiment.id} />
)}
</div>
)
}
Expand All @@ -70,8 +74,15 @@ const VariantsTab = (): JSX.Element => {
}

export function ExperimentView(): JSX.Element {
const { experimentLoading, metricResultsLoading, experimentId, metricResults, tabKey, featureFlags } =
useValues(experimentLogic)
const {
experimentLoading,
metricResultsLoading,
secondaryMetricResultsLoading,
experimentId,
metricResults,
tabKey,
featureFlags,
} = useValues(experimentLogic)

const { setTabKey } = useActions(experimentLogic)
const result = metricResults?.[0]
Expand All @@ -86,7 +97,7 @@ export function ExperimentView(): JSX.Element {
) : (
<>
<Info />
{metricResultsLoading ? (
{metricResultsLoading || secondaryMetricResultsLoading ? (
<ExperimentLoadingAnimation />
) : (
<>
Expand Down Expand Up @@ -130,7 +141,9 @@ export function ExperimentView(): JSX.Element {
/>
</>
)}
<PrimaryMetricModal experimentId={experimentId} />
<MetricModal experimentId={experimentId} isSecondary={true} />
<MetricModal experimentId={experimentId} isSecondary={false} />

<DistributionModal experimentId={experimentId} />
<ReleaseConditionsModal experimentId={experimentId} />
</>
Expand Down
19 changes: 8 additions & 11 deletions frontend/src/scenes/experiments/ExperimentView/Goal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export function MetricDisplayOld({ filters }: { filters?: FilterType }): JSX.Ele

export function ExposureMetric({ experimentId }: { experimentId: Experiment['id'] }): JSX.Element {
const { experiment, featureFlags } = useValues(experimentLogic({ experimentId }))
const { updateExperimentExposure, loadExperiment, setExperiment } = useActions(experimentLogic({ experimentId }))
const { updateExperimentGoal, loadExperiment, setExperiment } = useActions(experimentLogic({ experimentId }))
const [isModalOpen, setIsModalOpen] = useState(false)

const metricIdx = 0
Expand Down Expand Up @@ -213,16 +213,13 @@ export function ExposureMetric({ experimentId }: { experimentId: Experiment['id'
status="danger"
size="xsmall"
onClick={() => {
// :FLAG: CLEAN UP AFTER MIGRATION
if (featureFlags[FEATURE_FLAGS.EXPERIMENTS_HOGQL]) {
setExperiment({
...experiment,
metrics: experiment.metrics.map((metric, idx) =>
idx === metricIdx ? { ...metric, exposure_query: undefined } : metric
),
})
}
updateExperimentExposure(null)
setExperiment({
...experiment,
metrics: experiment.metrics.map((metric, idx) =>
idx === metricIdx ? { ...metric, exposure_query: undefined } : metric
),
})
updateExperimentGoal()
}}
>
Reset
Expand Down
Loading

0 comments on commit 227bc8a

Please sign in to comment.