GroupByVariable: Separate DS API method (#118270)

* create new GroupBy DS API method

* cleanup

* add canary scenes

* add method to loki

* add proper scenes version
This commit is contained in:
Victor Marin
2026-02-20 13:36:33 +02:00
committed by GitHub
parent 2513c67e0d
commit 386a8e316a
9 changed files with 64 additions and 40 deletions
+2 -2
View File
@@ -301,8 +301,8 @@
"@grafana/plugin-ui": "^0.13.1",
"@grafana/prometheus": "workspace:*",
"@grafana/runtime": "workspace:*",
"@grafana/scenes": "6.52.13",
"@grafana/scenes-react": "6.52.13",
"@grafana/scenes": "6.55.0",
"@grafana/scenes-react": "6.55.0",
"@grafana/schema": "workspace:*",
"@grafana/sql": "workspace:*",
"@grafana/ui": "workspace:*",
@@ -336,6 +336,13 @@ abstract class DataSourceApi<
*/
getTagKeys?(options?: DataSourceGetTagKeysOptions<TQuery>): Promise<GetTagResponse> | Promise<MetricFindValue[]>;
/**
* Get tag keys for group by variables. Implementing this method independently from getTagKeys
* allows a datasource to support group by variables without necessarily supporting adhoc filters,
* and vice versa.
*/
getGroupByKeys?(options?: DataSourceGetTagKeysOptions<TQuery>): Promise<GetTagResponse> | Promise<MetricFindValue[]>;
/**
* Get tag values for adhoc filters
*/
@@ -565,6 +565,12 @@ export class PrometheusDatasource
.map((k) => ({ value: k, text: k }));
}
// By implementing getGroupByKeys we add group by variable support independently from adhoc filters.
// It delegates to getTagKeys
async getGroupByKeys(options: DataSourceGetTagKeysOptions<PromQuery>): Promise<MetricFindValue[]> {
return this.getTagKeys(options);
}
// By implementing getTagKeys and getTagValues we add ad-hoc filters functionality
async getTagValues(options: DataSourceGetTagValuesOptions<PromQuery>): Promise<MetricFindValue[]> {
if (!options.timeRange) {
@@ -34,6 +34,7 @@ const fakeDsMock: DataSourceApi = {
toDataQuery: (q) => ({ ...q, refId: 'FakeDataSource-refId' }),
},
getTagKeys: jest.fn(),
getGroupByKeys: jest.fn(),
uid: 'fake-std',
};
@@ -24,12 +24,12 @@ export async function buildNewDashboardSaveModel(urlFolderUid?: string): Promise
// Add filter and group by variables if the datasource supports it
const defaultDs = await getDatasourceSrv().get();
if (defaultDs.getTagKeys) {
const datasourceRef = {
type: defaultDs.meta.id,
uid: defaultDs.uid,
};
const datasourceRef = {
type: defaultDs.meta.id,
uid: defaultDs.uid,
};
if (defaultDs.getTagKeys) {
const filterVariable = {
datasource: datasourceRef,
filters: [],
@@ -37,13 +37,17 @@ export async function buildNewDashboardSaveModel(urlFolderUid?: string): Promise
type: 'adhoc',
};
variablesList = (variablesList || []).concat([filterVariable as VariableModel]);
}
if (defaultDs.getGroupByKeys) {
const groupByVariable: VariableModel = {
datasource: datasourceRef,
name: 'Group by',
type: 'groupby',
};
variablesList = (variablesList || []).concat([filterVariable as VariableModel, groupByVariable]);
variablesList = (variablesList || []).concat([groupByVariable]);
}
}
@@ -86,12 +90,12 @@ export async function buildNewDashboardSaveModelV2(
// Add filter and group by variables if the datasource supports it
const defaultDs = await getDatasourceSrv().get();
if (defaultDs.getTagKeys) {
const datasourceRef = {
type: defaultDs.meta.id,
uid: defaultDs.uid,
};
const datasourceRef = {
type: defaultDs.meta.id,
uid: defaultDs.uid,
};
if (defaultDs.getTagKeys) {
const filterVariable: AdhocVariableKind = {
kind: 'AdhocVariable',
group: datasourceRef.type,
@@ -101,6 +105,10 @@ export async function buildNewDashboardSaveModelV2(
spec: { ...defaultAdhocVariableSpec(), name: 'Filter' },
};
variablesList = (variablesList || []).concat([filterVariable]);
}
if (defaultDs.getGroupByKeys) {
const groupByVariable: GroupByVariableKind = {
kind: 'GroupByVariable',
group: datasourceRef.type,
@@ -113,7 +121,7 @@ export async function buildNewDashboardSaveModelV2(
},
};
variablesList = (variablesList || []).concat([filterVariable, groupByVariable]);
variablesList = (variablesList || []).concat([groupByVariable]);
}
}
@@ -32,11 +32,10 @@ jest.mock('@grafana/runtime', () => ({
query: jest.fn(),
editor: jest.fn().mockImplementation(LegacyVariableQueryEditor),
},
getTagKeys: () => [],
getGroupByKeys: () => [],
}),
getList: () => [defaultDatasource, promDatasource],
getInstanceSettings: () => ({ ...defaultDatasource }),
getTagKeys: () => [],
}),
}));
@@ -23,8 +23,7 @@ export function GroupByVariableEditor(props: GroupByVariableEditorProps) {
return await getDataSourceSrv().get(datasourceRef);
}, [variable.state]);
const supported = datasource?.getTagKeys !== undefined;
const message = supported
const message = datasource?.getGroupByKeys
? 'Group by dimensions are applied automatically to all queries that target this data source'
: 'This data source does not support group by variable yet.';
@@ -54,7 +53,7 @@ export function GroupByVariableEditor(props: GroupByVariableEditorProps) {
allowCustomValue={allowCustomValue}
onAllowCustomValueChange={onAllowCustomValueChange}
inline={inline}
datasourceSupported={supported}
datasourceSupported={datasource?.getGroupByKeys ? true : false}
/>
);
}
@@ -806,6 +806,10 @@ export class LokiDatasource
return result.map((value: string) => ({ text: value }));
}
async getGroupByKeys(options?: DataSourceGetTagKeysOptions<LokiQuery>): Promise<MetricFindValue[]> {
return this.getTagKeys(options);
}
/**
* Implemented as part of the DataSourceAPI. Retrieves tag values that can be used for ad-hoc filtering.
* @returns A Promise that resolves to an array of label values represented as MetricFindValue objects
+21 -21
View File
@@ -3884,23 +3884,23 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/scenes-react@npm:6.52.13":
version: 6.52.13
resolution: "@grafana/scenes-react@npm:6.52.13"
"@grafana/scenes-react@npm:6.55.0":
version: 6.55.0
resolution: "@grafana/scenes-react@npm:6.55.0"
dependencies:
"@grafana/scenes": "npm:6.52.13"
"@grafana/scenes": "npm:6.55.0"
lru-cache: "npm:^10.2.2"
react-use: "npm:^17.4.0"
peerDependencies:
"@grafana/data": ^11.0.0
"@grafana/e2e-selectors": ^11.0.0
"@grafana/runtime": ^11.0.0
"@grafana/schema": ^11.0.0
"@grafana/ui": ^11.0.0
"@grafana/data": ">=11.6"
"@grafana/e2e-selectors": ">=11.6"
"@grafana/runtime": ">=11.6"
"@grafana/schema": ">=11.6"
"@grafana/ui": ">=11.6"
react: ^18.0.0
react-dom: ^18.0.0
react-router-dom: ^6.28.0
checksum: 10/796e4735584d733f539f946b4daf5b104433c903aef12a04b7d7289c5a174d9cc6ba0ab2edf28b2ba52e061f1b8180d268f0c3762871a7a806a09144195d3d16
checksum: 10/edc3b7c0f9116f3718ef9b23e8e897beef0265ce53c9236cb8485e4f4c2a1c217c3f914059e0db1035d31bb64e19e16a66dded8d59de5c396568fdcb9ae92edc
languageName: node
linkType: hard
@@ -3930,9 +3930,9 @@ __metadata:
languageName: node
linkType: hard
"@grafana/scenes@npm:6.52.13":
version: 6.52.13
resolution: "@grafana/scenes@npm:6.52.13"
"@grafana/scenes@npm:6.55.0":
version: 6.55.0
resolution: "@grafana/scenes@npm:6.55.0"
dependencies:
"@floating-ui/react": "npm:^0.26.16"
"@leeoniya/ufuzzy": "npm:^1.0.16"
@@ -3943,16 +3943,16 @@ __metadata:
react-virtualized-auto-sizer: "npm:1.0.24"
uuid: "npm:^9.0.0"
peerDependencies:
"@grafana/data": ">=10.4"
"@grafana/e2e-selectors": ">=10.4"
"@grafana/data": ">=11.6"
"@grafana/e2e-selectors": ">=11.6"
"@grafana/i18n": "*"
"@grafana/runtime": ">=10.4"
"@grafana/schema": ">=10.4"
"@grafana/ui": ">=10.4"
"@grafana/runtime": ">=11.6"
"@grafana/schema": ">=11.6"
"@grafana/ui": ">=11.6"
react: ^18.0.0
react-dom: ^18.0.0
react-router-dom: ^6.28.0
checksum: 10/d49894f9fc4e4cf4af0ab4a308b282457b3602c4a421e8335300252124dd72f1bc418bafb0af16bf103844200df47037cd238b9f82e92aef7fe568bd3d4dec98
checksum: 10/8600080d76e785219329201a29362006fd71e45fdca35ac97989b60a250d3cc2d34cb8adc95e1d84e62aaf049e9f814ec1e27b752ba3c42fe9f48cb269bae57d
languageName: node
linkType: hard
@@ -20555,8 +20555,8 @@ __metadata:
"@grafana/plugin-ui": "npm:^0.13.1"
"@grafana/prometheus": "workspace:*"
"@grafana/runtime": "workspace:*"
"@grafana/scenes": "npm:6.52.13"
"@grafana/scenes-react": "npm:6.52.13"
"@grafana/scenes": "npm:6.55.0"
"@grafana/scenes-react": "npm:6.55.0"
"@grafana/schema": "workspace:*"
"@grafana/sql": "workspace:*"
"@grafana/test-utils": "workspace:*"