diff --git a/frontend/src/component/impact-metrics/ChartConfigModal/ImpactMetricsControls/ModeSelector/ModeSelector.tsx b/frontend/src/component/impact-metrics/ChartConfigModal/ImpactMetricsControls/ModeSelector/ModeSelector.tsx index 0feb45bf2f..fa06d18f12 100644 --- a/frontend/src/component/impact-metrics/ChartConfigModal/ImpactMetricsControls/ModeSelector/ModeSelector.tsx +++ b/frontend/src/component/impact-metrics/ChartConfigModal/ImpactMetricsControls/ModeSelector/ModeSelector.tsx @@ -5,7 +5,7 @@ import type { AggregationMode } from '../../../types.ts'; export type ModeSelectorProps = { value: AggregationMode; onChange: (mode: AggregationMode) => void; - seriesType: 'counter' | 'gauge' | 'unknown'; + seriesType: 'counter' | 'gauge' | 'histogram' | 'unknown'; }; export const ModeSelector: FC = ({ @@ -32,14 +32,28 @@ export const ModeSelector: FC = ({ Count , ] - : [ - - Average - , - - Sum - , - ]} + : seriesType === 'gauge' + ? [ + + Average + , + + Sum + , + ] + : seriesType === 'histogram' + ? [ + + 50th percentile + , + + 95th percentile + , + + 99th percentile + , + ] + : []} ); diff --git a/frontend/src/component/impact-metrics/hooks/useChartFormState.ts b/frontend/src/component/impact-metrics/hooks/useChartFormState.ts index ab9c4045cb..ee2fdf1718 100644 --- a/frontend/src/component/impact-metrics/hooks/useChartFormState.ts +++ b/frontend/src/component/impact-metrics/hooks/useChartFormState.ts @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; import { useImpactMetricsData } from 'hooks/api/getters/useImpactMetricsData/useImpactMetricsData'; import type { AggregationMode, ChartConfig } from '../types.ts'; import type { ImpactMetricsLabels } from 'hooks/api/getters/useImpactMetricsData/useImpactMetricsData'; -import { getMetricType } from '../utils.ts'; +import { getDefaultAggregation, getMetricType } from '../utils.ts'; type UseChartConfigParams = { open: boolean; @@ -48,10 +48,12 @@ export const useChartFormState = ({ Record >(initialConfig?.labelSelectors || {}); const [aggregationMode, setAggregationMode] = useState( - (initialConfig?.aggregationMode || getMetricType(metricName)) === - 'counter' - ? 'count' - : 'avg', + initialConfig?.aggregationMode || + (getMetricType(metricName) === 'counter' + ? 'count' + : getMetricType(metricName) === 'histogram' + ? 'p50' + : 'avg'), ); const { @@ -75,9 +77,7 @@ export const useChartFormState = ({ setLabelSelectors(initialConfig.labelSelectors); setAggregationMode( initialConfig.aggregationMode || - (getMetricType(initialConfig.metricName) === 'counter' - ? 'count' - : 'avg'), + getDefaultAggregation(initialConfig.metricName), ); } else if (open && !initialConfig) { setTitle(''); @@ -97,6 +97,8 @@ export const useChartFormState = ({ setAggregationMode('count'); } else if (metric === 'gauge') { setAggregationMode('avg'); + } else if (metric === 'histogram') { + setAggregationMode('p50'); } }; diff --git a/frontend/src/component/impact-metrics/types.ts b/frontend/src/component/impact-metrics/types.ts index e9ece23f30..932b666467 100644 --- a/frontend/src/component/impact-metrics/types.ts +++ b/frontend/src/component/impact-metrics/types.ts @@ -8,10 +8,17 @@ export type ChartConfig = { title?: string; }; -export type AggregationMode = 'rps' | 'count' | 'avg' | 'sum'; +export type AggregationMode = + | 'rps' + | 'count' + | 'avg' + | 'sum' + | 'p50' + | 'p95' + | 'p99'; export type DisplayChartConfig = ChartConfig & { - type: 'counter' | 'gauge' | 'unknown'; + type: 'counter' | 'gauge' | 'histogram' | 'unknown'; displayName: string; // e.g. my_metric with unleash_counter stripped }; diff --git a/frontend/src/component/impact-metrics/utils.ts b/frontend/src/component/impact-metrics/utils.ts index 28ad0a8585..09570739e6 100644 --- a/frontend/src/component/impact-metrics/utils.ts +++ b/frontend/src/component/impact-metrics/utils.ts @@ -64,5 +64,18 @@ export const formatLargeNumbers = (value: number): string => { export const getMetricType = (seriesName: string) => { if (seriesName.startsWith('unleash_counter_')) return 'counter'; if (seriesName.startsWith('unleash_gauge_')) return 'gauge'; + if (seriesName.startsWith('unleash_histogram_')) return 'histogram'; return 'unknown'; }; + +export const getDefaultAggregation = (seriesName: string) => { + const metricType = getMetricType(seriesName); + + if (metricType === 'counter') { + return 'count'; + } + if (metricType === 'histogram') { + return 'p50'; + } + return 'avg'; +}; diff --git a/frontend/src/hooks/api/getters/useImpactMetricsData/useImpactMetricsData.ts b/frontend/src/hooks/api/getters/useImpactMetricsData/useImpactMetricsData.ts index 4863d82069..0fd1ca5adf 100644 --- a/frontend/src/hooks/api/getters/useImpactMetricsData/useImpactMetricsData.ts +++ b/frontend/src/hooks/api/getters/useImpactMetricsData/useImpactMetricsData.ts @@ -27,7 +27,7 @@ export type ImpactMetricsQuery = { series: string; range: 'hour' | 'day' | 'week' | 'month'; labels?: Record; - aggregationMode?: 'rps' | 'count' | 'avg' | 'sum'; + aggregationMode?: 'rps' | 'count' | 'avg' | 'sum' | 'p50' | 'p95' | 'p99'; }; export const useImpactMetricsData = (query?: ImpactMetricsQuery) => { diff --git a/frontend/src/openapi/models/createImpactMetricsConfigSchemaAggregationMode.ts b/frontend/src/openapi/models/createImpactMetricsConfigSchemaAggregationMode.ts index 6bdcafad19..c6e8903ced 100644 --- a/frontend/src/openapi/models/createImpactMetricsConfigSchemaAggregationMode.ts +++ b/frontend/src/openapi/models/createImpactMetricsConfigSchemaAggregationMode.ts @@ -16,4 +16,7 @@ export const CreateImpactMetricsConfigSchemaAggregationMode = { count: 'count', avg: 'avg', sum: 'sum', + p50: 'p50', + p95: 'p95', + p99: 'p99', } as const;