diff --git a/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx b/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx
index 4809a44573a..1e5e1156452 100644
--- a/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx
+++ b/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx
@@ -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={
- {row.metadata.value}
+ {isString(row.metadata.value) && {row.metadata.value}}
}
isOpenByDefault={true}
diff --git a/public/app/features/alerting/unified/triage/rows/GroupRow.tsx b/public/app/features/alerting/unified/triage/rows/GroupRow.tsx
index 4499672dd6e..1bb73674165 100644
--- a/public/app/features/alerting/unified/triage/rows/GroupRow.tsx
+++ b/public/app/features/alerting/unified/triage/rows/GroupRow.tsx
@@ -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 (
}
- isOpenByDefault={true}
+ title={
+
+ }
+ isOpenByDefault={!isEmptyValue}
leftColumnClassName={styles.groupRow}
rightColumnClassName={styles.groupRow}
depth={depth}
diff --git a/public/app/features/alerting/unified/triage/rows/utils.ts b/public/app/features/alerting/unified/triage/rows/utils.ts
index 6a4d0731643..d5b193ee755 100644
--- a/public/app/features/alerting/unified/triage/rows/utils.ts
+++ b/public/app/features/alerting/unified/triage/rows/utils.ts
@@ -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 ? '' : value);
diff --git a/public/app/features/alerting/unified/triage/scene/Workbench.tsx b/public/app/features/alerting/unified/triage/scene/Workbench.tsx
index 356a2924461..f202a5cd0a0 100644
--- a/public/app/features/alerting/unified/triage/scene/Workbench.tsx
+++ b/public/app/features/alerting/unified/triage/scene/Workbench.tsx
@@ -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();
+ const grouped = new Map();
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)
diff --git a/public/app/features/alerting/unified/triage/scene/utils.ts b/public/app/features/alerting/unified/triage/scene/utils.ts
index 19886a760e0..456e3f3c7bf 100644
--- a/public/app/features/alerting/unified/triage/scene/utils.ts
+++ b/public/app/features/alerting/unified/triage/scene/utils.ts
@@ -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(VARIABLES.groupBy);
const [filters = ''] = useVariableValue(VARIABLES.filters);
-
- const groupByFilter = stringifyGroupFilter(groupBy);
- const queryFilter = [groupByFilter, filters].filter((s) => Boolean(s)).join(',');
-
- return queryFilter;
+ return filters;
}
diff --git a/public/app/features/alerting/unified/triage/types.ts b/public/app/features/alerting/unified/triage/types.ts
index b599f46cb33..c878f8f303c 100644
--- a/public/app/features/alerting/unified/triage/types.ts
+++ b/public/app/features/alerting/unified/triage/types.ts
@@ -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');