Alerting: Add instances with no label value to an ungrouped group (#113170)
add instances with no label value to an ungrouped group in alerting triage – these will be collapsed by default
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { isString } from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
@@ -27,7 +28,7 @@ export const FolderGroupRow = ({ row, leftColumnWidth, rowKey, depth = 0, childr
|
||||
title={
|
||||
<Stack direction="row" gap={0.5} alignItems="center">
|
||||
<MetaText icon="folder" />
|
||||
<Text color="primary">{row.metadata.value}</Text>
|
||||
{isString(row.metadata.value) && <Text color="primary">{row.metadata.value}</Text>}
|
||||
</Stack>
|
||||
}
|
||||
isOpenByDefault={true}
|
||||
|
||||
@@ -5,9 +5,10 @@ import { AlertLabel } from '@grafana/alerting/unstable';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { GenericGroupedRow } from '../types';
|
||||
import { EmptyLabelValue, GenericGroupedRow } from '../types';
|
||||
|
||||
import { GenericRow } from './GenericRow';
|
||||
import { formatLabelValue } from './utils';
|
||||
|
||||
interface GroupRowProps {
|
||||
row: GenericGroupedRow;
|
||||
@@ -19,13 +20,21 @@ interface GroupRowProps {
|
||||
|
||||
export const GroupRow = ({ row, leftColumnWidth, rowKey, depth = 0, children }: GroupRowProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const isEmptyValue = row.metadata.value === EmptyLabelValue;
|
||||
|
||||
return (
|
||||
<GenericRow
|
||||
key={rowKey}
|
||||
width={leftColumnWidth}
|
||||
title={<AlertLabel size="sm" labelKey={row.metadata.label} value={row.metadata.value} colorBy="key" />}
|
||||
isOpenByDefault={true}
|
||||
title={
|
||||
<AlertLabel
|
||||
size="sm"
|
||||
labelKey={row.metadata.label}
|
||||
value={formatLabelValue(row.metadata.value)}
|
||||
colorBy="key"
|
||||
/>
|
||||
}
|
||||
isOpenByDefault={!isEmptyValue}
|
||||
leftColumnClassName={styles.groupRow}
|
||||
rightColumnClassName={styles.groupRow}
|
||||
depth={depth}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkbenchRow } from '../types';
|
||||
import { EmptyLabelValue, LabelValue, WorkbenchRow } from '../types';
|
||||
|
||||
// Generate unique keys for WorkbenchRow items
|
||||
export function generateRowKey(row: WorkbenchRow, fallbackIndex: number): string {
|
||||
@@ -8,6 +8,8 @@ export function generateRowKey(row: WorkbenchRow, fallbackIndex: number): string
|
||||
} else {
|
||||
// For GenericGroupedRow, create key from label and value
|
||||
const groupedRow = row;
|
||||
return `group-${groupedRow.metadata.label}-${groupedRow.metadata.value}`;
|
||||
return `group-${groupedRow.metadata.label}-${formatLabelValue(groupedRow.metadata.value)}`;
|
||||
}
|
||||
}
|
||||
|
||||
export const formatLabelValue = (value: LabelValue): string => (value === EmptyLabelValue ? '<no value>' : value);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isEmpty } from 'lodash';
|
||||
import { ArrayValues } from 'type-fest';
|
||||
|
||||
import { DataFrame, PanelData } from '@grafana/data';
|
||||
@@ -6,7 +7,7 @@ import { useQueryRunner, useTimeRange, useVariableValues } from '@grafana/scenes
|
||||
|
||||
import { Workbench } from '../Workbench';
|
||||
import { DEFAULT_FIELDS, METRIC_NAME, VARIABLES } from '../constants';
|
||||
import { AlertRuleRow, GenericGroupedRow, WorkbenchRow } from '../types';
|
||||
import { AlertRuleRow, EmptyLabelValue, GenericGroupedRow, WorkbenchRow } from '../types';
|
||||
|
||||
import { convertTimeRangeToDomain, getDataQuery, useQueryFilter } from './utils';
|
||||
|
||||
@@ -79,29 +80,40 @@ function groupData(dataPoints: DataPoint[], groupBy: string[], depth: number): W
|
||||
}
|
||||
|
||||
const groupByKey = groupBy[depth];
|
||||
const grouped = new Map<string, DataPoint[]>();
|
||||
const grouped = new Map<string | typeof EmptyLabelValue, DataPoint[]>();
|
||||
|
||||
for (const dp of dataPoints) {
|
||||
const key = String(dp[groupByKey] ?? 'undefined');
|
||||
if (!grouped.has(key)) {
|
||||
grouped.set(key, []);
|
||||
const mapKey = dp[groupByKey] ?? EmptyLabelValue;
|
||||
if (!grouped.has(mapKey)) {
|
||||
grouped.set(mapKey, []);
|
||||
}
|
||||
grouped.get(key)?.push(dp);
|
||||
grouped.get(mapKey)?.push(dp);
|
||||
}
|
||||
|
||||
const result: GenericGroupedRow[] = [];
|
||||
const emptyGroups: GenericGroupedRow[] = [];
|
||||
|
||||
for (const [value, rows] of grouped.entries()) {
|
||||
result.push({
|
||||
const labelValue = isEmpty(value) ? EmptyLabelValue : value;
|
||||
|
||||
const group: GenericGroupedRow = {
|
||||
type: 'group',
|
||||
metadata: {
|
||||
label: groupByKey,
|
||||
value: value,
|
||||
value: labelValue,
|
||||
},
|
||||
rows: groupData(rows, groupBy, depth + 1),
|
||||
});
|
||||
};
|
||||
|
||||
// Separate empty label groups to append at the end
|
||||
if (group.metadata.value === EmptyLabelValue) {
|
||||
emptyGroups.push(group);
|
||||
} else {
|
||||
result.push(group);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return [...result, ...emptyGroups];
|
||||
}
|
||||
|
||||
// @TODO narrower types for PanelData! (if possible)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TimeRange } from '@grafana/data';
|
||||
import { SceneDataQuery } from '@grafana/scenes';
|
||||
import { useVariableValue, useVariableValues } from '@grafana/scenes-react';
|
||||
import { useVariableValue } from '@grafana/scenes-react';
|
||||
import { DataSourceRef } from '@grafana/schema';
|
||||
|
||||
import { DATASOURCE_UID, VARIABLES } from '../constants';
|
||||
@@ -44,11 +44,6 @@ export function convertTimeRangeToDomain(timeRange: TimeRange): Domain {
|
||||
* This hook will create a Prometheus label matcher string from the "groupBy" and "filters" variables
|
||||
*/
|
||||
export function useQueryFilter(): string {
|
||||
const [groupBy = []] = useVariableValues<string>(VARIABLES.groupBy);
|
||||
const [filters = ''] = useVariableValue<string>(VARIABLES.filters);
|
||||
|
||||
const groupByFilter = stringifyGroupFilter(groupBy);
|
||||
const queryFilter = [groupByFilter, filters].filter((s) => Boolean(s)).join(',');
|
||||
|
||||
return queryFilter;
|
||||
return filters;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ export interface GenericGroupedRow {
|
||||
type: 'group';
|
||||
metadata: {
|
||||
label: string;
|
||||
value: string;
|
||||
value: LabelValue;
|
||||
};
|
||||
rows: WorkbenchRow[];
|
||||
}
|
||||
|
||||
export type LabelValue = string | typeof EmptyLabelValue;
|
||||
export const EmptyLabelValue = Symbol('empty label value');
|
||||
|
||||
Reference in New Issue
Block a user