diff --git a/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--dark.png b/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--dark.png index 1cfa54e4bfb80..4fe845177fd6b 100644 Binary files a/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--dark.png and b/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--light.png b/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--light.png index ca494887f274e..d4cf49f5c030a 100644 Binary files a/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--light.png and b/frontend/__snapshots__/scenes-app-sidepanels--side-panel-docs--light.png differ diff --git a/frontend/src/lib/components/Alerts/insightAlertsLogic.ts b/frontend/src/lib/components/Alerts/insightAlertsLogic.ts index 5ef92b84b8de2..f95c941eb3896 100644 --- a/frontend/src/lib/components/Alerts/insightAlertsLogic.ts +++ b/frontend/src/lib/components/Alerts/insightAlertsLogic.ts @@ -35,6 +35,7 @@ export const insightAlertsLogic = kea([ connect((props: InsightAlertsLogicProps) => ({ actions: [insightVizDataLogic(props.insightLogicProps), ['setQuery']], + values: [insightVizDataLogic(props.insightLogicProps), ['showAlertThresholdLines']], })), loaders(({ props }) => ({ @@ -62,10 +63,11 @@ export const insightAlertsLogic = kea([ selectors({ alertThresholdLines: [ - (s) => [s.alerts], - (alerts: AlertType[]): GoalLine[] => + (s) => [s.alerts, s.showAlertThresholdLines], + (alerts: AlertType[], showAlertThresholdLines: boolean): GoalLine[] => alerts.flatMap((alert) => { if ( + !showAlertThresholdLines || alert.threshold.configuration.type !== InsightThresholdType.ABSOLUTE || alert.condition.type !== AlertConditionType.ABSOLUTE_VALUE || !alert.threshold.configuration.bounds @@ -76,14 +78,14 @@ export const insightAlertsLogic = kea([ const bounds = alert.threshold.configuration.bounds const thresholds = [] - if (bounds?.upper !== undefined) { + if (bounds?.upper != null) { thresholds.push({ label: `${alert.name} Upper Threshold`, value: bounds?.upper, }) } - if (bounds?.lower !== undefined) { + if (bounds?.lower != null) { thresholds.push({ label: `${alert.name} Lower Threshold`, value: bounds?.lower, diff --git a/frontend/src/lib/components/Alerts/views/Alerts.tsx b/frontend/src/lib/components/Alerts/views/Alerts.tsx index 004a848377edb..4bb1129fd1146 100644 --- a/frontend/src/lib/components/Alerts/views/Alerts.tsx +++ b/frontend/src/lib/components/Alerts/views/Alerts.tsx @@ -3,6 +3,7 @@ import { IconCheck } from '@posthog/icons' import { Tooltip } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { router } from 'kea-router' +import { FeedbackNotice } from 'lib/components/FeedbackNotice' import { DetectiveHog } from 'lib/components/hedgehogs' import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction' import { LemonTable, LemonTableColumn, LemonTableColumns } from 'lib/lemon-ui/LemonTable' @@ -104,6 +105,8 @@ export function Alerts({ alertId }: AlertsProps): JSX.Element { // TODO: add info here to sign up for alerts early access return ( <> + + {alertsSortedByState.length === 0 && !alertsLoading && ( ): TrendsF return objectCleanWithEmpty({ smoothingIntervals: filters.smoothing_intervals, showLegend: filters.show_legend, + showAlertThresholdLines: filters.show_alert_threshold_lines, hiddenLegendIndexes: hiddenLegendKeysToIndexes(filters.hidden_legend_keys), aggregationAxisFormat: filters.aggregation_axis_format, aggregationAxisPrefix: filters.aggregation_axis_prefix, diff --git a/frontend/src/queries/nodes/InsightViz/InsightDisplayConfig.tsx b/frontend/src/queries/nodes/InsightViz/InsightDisplayConfig.tsx index 1e72d999b1dfe..d75685def2228 100644 --- a/frontend/src/queries/nodes/InsightViz/InsightDisplayConfig.tsx +++ b/frontend/src/queries/nodes/InsightViz/InsightDisplayConfig.tsx @@ -14,6 +14,7 @@ import { funnelDataLogic } from 'scenes/funnels/funnelDataLogic' import { axisLabel } from 'scenes/insights/aggregationAxisFormat' import { PercentStackViewFilter } from 'scenes/insights/EditorFilters/PercentStackViewFilter' import { ScalePicker } from 'scenes/insights/EditorFilters/ScalePicker' +import { ShowAlertThresholdLinesFilter } from 'scenes/insights/EditorFilters/ShowAlertThresholdLinesFilter' import { ShowLegendFilter } from 'scenes/insights/EditorFilters/ShowLegendFilter' import { ValueOnSeriesFilter } from 'scenes/insights/EditorFilters/ValueOnSeriesFilter' import { InsightDateFilter } from 'scenes/insights/filters/InsightDateFilter' @@ -77,6 +78,7 @@ export function InsightDisplayConfig(): JSX.Element { ...(supportsValueOnSeries ? [{ label: () => }] : []), ...(supportsPercentStackView ? [{ label: () => }] : []), ...(hasLegend ? [{ label: () => }] : []), + { label: () => }, ], }, ] diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index a9dc7be1bf476..7df99c3f651ad 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -11468,6 +11468,10 @@ }, "type": "array" }, + "showAlertThresholdLines": { + "default": false, + "type": "boolean" + }, "showLabelsOnSeries": { "type": "boolean" }, @@ -11538,6 +11542,9 @@ }, "type": "object" }, + "show_alert_threshold_lines": { + "type": "boolean" + }, "show_labels_on_series": { "type": "boolean" }, diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 1887f57ee0f96..5b8412cc48bb8 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -834,6 +834,8 @@ export type TrendsFilter = { display?: TrendsFilterLegacy['display'] /** @default false */ showLegend?: TrendsFilterLegacy['show_legend'] + /** @default false */ + showAlertThresholdLines?: boolean breakdown_histogram_bin_count?: TrendsFilterLegacy['breakdown_histogram_bin_count'] // TODO: fully move into BreakdownFilter /** @default numeric */ aggregationAxisFormat?: TrendsFilterLegacy['aggregation_axis_format'] diff --git a/frontend/src/queries/utils.ts b/frontend/src/queries/utils.ts index ed9cfc8d2fcf1..f2828675a643d 100644 --- a/frontend/src/queries/utils.ts +++ b/frontend/src/queries/utils.ts @@ -301,6 +301,13 @@ export const getShowLegend = (query: InsightQueryNode): boolean | undefined => { return undefined } +export const getShowAlertThresholdLines = (query: InsightQueryNode): boolean | undefined => { + if (isTrendsQuery(query)) { + return query.trendsFilter?.showAlertThresholdLines + } + return undefined +} + export const getShowLabelsOnSeries = (query: InsightQueryNode): boolean | undefined => { if (isTrendsQuery(query)) { return query.trendsFilter?.showLabelsOnSeries diff --git a/frontend/src/scenes/insights/EditorFilters/ShowAlertThresholdLinesFilter.tsx b/frontend/src/scenes/insights/EditorFilters/ShowAlertThresholdLinesFilter.tsx new file mode 100644 index 0000000000000..17948bec59b00 --- /dev/null +++ b/frontend/src/scenes/insights/EditorFilters/ShowAlertThresholdLinesFilter.tsx @@ -0,0 +1,25 @@ +import { LemonCheckbox } from '@posthog/lemon-ui' +import { useActions, useValues } from 'kea' +import { insightLogic } from 'scenes/insights/insightLogic' + +import { insightVizDataLogic } from '../insightVizDataLogic' + +export function ShowAlertThresholdLinesFilter(): JSX.Element | null { + const { insightProps } = useValues(insightLogic) + const { showAlertThresholdLines } = useValues(insightVizDataLogic(insightProps)) + const { updateInsightFilter } = useActions(insightVizDataLogic(insightProps)) + + const toggleShowAlertThresholdLines = (): void => { + updateInsightFilter({ showAlertThresholdLines: !showAlertThresholdLines }) + } + + return ( + Show alert threshold lines} + size="small" + /> + ) +} diff --git a/frontend/src/scenes/insights/insightVizDataLogic.ts b/frontend/src/scenes/insights/insightVizDataLogic.ts index f80f24e4f74fb..aec4a1eb32ed8 100644 --- a/frontend/src/scenes/insights/insightVizDataLogic.ts +++ b/frontend/src/scenes/insights/insightVizDataLogic.ts @@ -44,6 +44,7 @@ import { getFormula, getInterval, getSeries, + getShowAlertThresholdLines, getShowLabelsOnSeries, getShowLegend, getShowPercentStackView, @@ -158,6 +159,7 @@ export const insightVizDataLogic = kea([ interval: [(s) => [s.querySource], (q) => (q ? getInterval(q) : null)], properties: [(s) => [s.querySource], (q) => (q ? q.properties : null)], samplingFactor: [(s) => [s.querySource], (q) => (q ? q.samplingFactor : null)], + showAlertThresholdLines: [(s) => [s.querySource], (q) => (q ? getShowAlertThresholdLines(q) : null)], showLegend: [(s) => [s.querySource], (q) => (q ? getShowLegend(q) : null)], showValuesOnSeries: [(s) => [s.querySource], (q) => (q ? getShowValuesOnSeries(q) : null)], showLabelOnSeries: [(s) => [s.querySource], (q) => (q ? getShowLabelsOnSeries(q) : null)], diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 0a28032ade19e..79fe3bb2ecf28 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -2242,6 +2242,7 @@ export interface TrendsFilterType extends FilterType { breakdown_histogram_bin_count?: number // trends breakdown histogram bin count // frontend only + show_alert_threshold_lines?: boolean // used to show/hide horizontal lines on insight representing alert thresholds set on the insight show_legend?: boolean // used to show/hide legend next to insights graph hidden_legend_keys?: Record // used to toggle visibilities in table and legend aggregation_axis_format?: AggregationAxisFormat // a fixed format like duration that needs calculation diff --git a/posthog/hogql_queries/legacy_compatibility/filter_to_query.py b/posthog/hogql_queries/legacy_compatibility/filter_to_query.py index 585f37f387755..a8cc01a0b89fb 100644 --- a/posthog/hogql_queries/legacy_compatibility/filter_to_query.py +++ b/posthog/hogql_queries/legacy_compatibility/filter_to_query.py @@ -400,6 +400,7 @@ def _insight_filter(filter: dict): "trendsFilter": TrendsFilter( smoothingIntervals=filter.get("smoothing_intervals"), showLegend=filter.get("show_legend"), + showAlertThresholdLines=filter.get("show_alert_threshold_lines"), hiddenLegendIndexes=hidden_legend_keys_to_indexes(filter.get("hidden_legend_keys")), aggregationAxisFormat=filter.get("aggregation_axis_format"), aggregationAxisPrefix=filter.get("aggregation_axis_prefix"), diff --git a/posthog/schema.py b/posthog/schema.py index 1ba777cd25b26..1a43a435cd4dc 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -1387,6 +1387,7 @@ class TrendsFilter(BaseModel): display: Optional[ChartDisplayType] = ChartDisplayType.ACTIONS_LINE_GRAPH formula: Optional[str] = None hiddenLegendIndexes: Optional[list[int]] = None + showAlertThresholdLines: Optional[bool] = False showLabelsOnSeries: Optional[bool] = None showLegend: Optional[bool] = False showPercentStackView: Optional[bool] = False @@ -1409,6 +1410,7 @@ class TrendsFilterLegacy(BaseModel): display: Optional[ChartDisplayType] = None formula: Optional[str] = None hidden_legend_keys: Optional[dict[str, Union[bool, Any]]] = None + show_alert_threshold_lines: Optional[bool] = None show_labels_on_series: Optional[bool] = None show_legend: Optional[bool] = None show_percent_stack_view: Optional[bool] = None