mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
GroupBy: add new groupby
variable type and optional groupByKeys
(#81717)
* add new groupby type * rename to groupByKeys + introduce GroupByVariableModel * fix unit test * update scenes package * update interface * update fixture * update unit test * bump to scenes 2.6.2 * remove baseFilters for now
This commit is contained in:
parent
5b9b990220
commit
af8ea896d0
@ -600,24 +600,24 @@ Configured template variables
|
||||
|
||||
A variable is a placeholder for a value. You can use variables in metric queries and in panel titles.
|
||||
|
||||
| Property | Type | Required | Default | Description |
|
||||
|---------------|-------------------------------------|----------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `name` | string | **Yes** | | Name of variable |
|
||||
| `type` | string | **Yes** | | Dashboard variable type<br/>`query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.<br/>`adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).<br/>`constant`: Define a hidden constant.<br/>`datasource`: Quickly change the data source for an entire dashboard.<br/>`interval`: Interval variables represent time spans.<br/>`textbox`: Display a free text input field with an optional default value.<br/>`custom`: Define the variable options manually using a comma-separated list.<br/>`system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables<br/>Possible values are: `query`, `adhoc`, `constant`, `datasource`, `interval`, `textbox`, `custom`, `system`. |
|
||||
| `allValue` | string | No | | Custom all value |
|
||||
| `current` | [VariableOption](#variableoption) | No | | Option to be selected in a variable. |
|
||||
| `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance |
|
||||
| `description` | string | No | | Description of variable. It can be defined but `null`. |
|
||||
| `hide` | integer | No | | Determine if the variable shows on dashboard<br/>Accepted values are 0 (show label and value), 1 (show value only), 2 (show nothing).<br/>Possible values are: `0`, `1`, `2`. |
|
||||
| `includeAll` | boolean | No | `false` | Whether all value option is available or not |
|
||||
| `label` | string | No | | Optional display name |
|
||||
| `multi` | boolean | No | `false` | Whether multiple values can be selected or not from variable value list |
|
||||
| `options` | [VariableOption](#variableoption)[] | No | | Options that can be selected for a variable. |
|
||||
| `query` | | No | | Query used to fetch values for a variable |
|
||||
| `refresh` | integer | No | | Options to config when to refresh a variable<br/>`0`: Never refresh the variable<br/>`1`: Queries the data source every time the dashboard loads.<br/>`2`: Queries the data source when the dashboard time range changes.<br/>Possible values are: `0`, `1`, `2`. |
|
||||
| `regex` | string | No | | Optional field, if you want to extract part of a series name or metric node segment.<br/>Named capture groups can be used to separate the display text and value. |
|
||||
| `skipUrlSync` | boolean | No | `false` | Whether the variable value should be managed by URL query params or not |
|
||||
| `sort` | integer | No | | Sort variable options<br/>Accepted values are:<br/>`0`: No sorting<br/>`1`: Alphabetical ASC<br/>`2`: Alphabetical DESC<br/>`3`: Numerical ASC<br/>`4`: Numerical DESC<br/>`5`: Alphabetical Case Insensitive ASC<br/>`6`: Alphabetical Case Insensitive DESC<br/>`7`: Natural ASC<br/>`8`: Natural DESC<br/>Possible values are: `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`. |
|
||||
| Property | Type | Required | Default | Description |
|
||||
|---------------|-------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `name` | string | **Yes** | | Name of variable |
|
||||
| `type` | string | **Yes** | | Dashboard variable type<br/>`query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.<br/>`adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).<br/>`constant`: Define a hidden constant.<br/>`datasource`: Quickly change the data source for an entire dashboard.<br/>`interval`: Interval variables represent time spans.<br/>`textbox`: Display a free text input field with an optional default value.<br/>`custom`: Define the variable options manually using a comma-separated list.<br/>`system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables<br/>Possible values are: `query`, `adhoc`, `groupby`, `constant`, `datasource`, `interval`, `textbox`, `custom`, `system`. |
|
||||
| `allValue` | string | No | | Custom all value |
|
||||
| `current` | [VariableOption](#variableoption) | No | | Option to be selected in a variable. |
|
||||
| `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance |
|
||||
| `description` | string | No | | Description of variable. It can be defined but `null`. |
|
||||
| `hide` | integer | No | | Determine if the variable shows on dashboard<br/>Accepted values are 0 (show label and value), 1 (show value only), 2 (show nothing).<br/>Possible values are: `0`, `1`, `2`. |
|
||||
| `includeAll` | boolean | No | `false` | Whether all value option is available or not |
|
||||
| `label` | string | No | | Optional display name |
|
||||
| `multi` | boolean | No | `false` | Whether multiple values can be selected or not from variable value list |
|
||||
| `options` | [VariableOption](#variableoption)[] | No | | Options that can be selected for a variable. |
|
||||
| `query` | | No | | Query used to fetch values for a variable |
|
||||
| `refresh` | integer | No | | Options to config when to refresh a variable<br/>`0`: Never refresh the variable<br/>`1`: Queries the data source every time the dashboard loads.<br/>`2`: Queries the data source when the dashboard time range changes.<br/>Possible values are: `0`, `1`, `2`. |
|
||||
| `regex` | string | No | | Optional field, if you want to extract part of a series name or metric node segment.<br/>Named capture groups can be used to separate the display text and value. |
|
||||
| `skipUrlSync` | boolean | No | `false` | Whether the variable value should be managed by URL query params or not |
|
||||
| `sort` | integer | No | | Sort variable options<br/>Accepted values are:<br/>`0`: No sorting<br/>`1`: Alphabetical ASC<br/>`2`: Alphabetical DESC<br/>`3`: Numerical ASC<br/>`4`: Numerical DESC<br/>`5`: Alphabetical Case Insensitive ASC<br/>`6`: Alphabetical Case Insensitive DESC<br/>`7`: Natural ASC<br/>`8`: Natural DESC<br/>Possible values are: `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`. |
|
||||
|
||||
### VariableOption
|
||||
|
||||
|
@ -291,7 +291,7 @@ lineage: schemas: [{
|
||||
// `textbox`: Display a free text input field with an optional default value.
|
||||
// `custom`: Define the variable options manually using a comma-separated list.
|
||||
// `system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
|
||||
#VariableType: "query" | "adhoc" | "constant" | "datasource" | "interval" | "textbox" | "custom" | "system" @cuetsy(kind="type") @grafanamaturity(NeedsExpertReview)
|
||||
#VariableType: "query" | "adhoc" | "groupby" | "constant" | "datasource" | "interval" | "textbox" | "custom" | "system" @cuetsy(kind="type") @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.
|
||||
// Continuous color interpolates a color using the percentage of a value relative to min and max.
|
||||
|
@ -246,7 +246,7 @@
|
||||
"@grafana/o11y-ds-frontend": "workspace:*",
|
||||
"@grafana/prometheus": "workspace:*",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "^2.4.0",
|
||||
"@grafana/scenes": "2.6.3",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/sql": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
|
@ -560,6 +560,7 @@ export interface DataQueryRequest<TQuery extends DataQuery = DataQuery> {
|
||||
|
||||
/** Filters to dynamically apply to all queries */
|
||||
filters?: AdHocVariableFilter[];
|
||||
groupByKeys?: string[];
|
||||
|
||||
// Request Timing
|
||||
startTime: number;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { LoadingState } from './data';
|
||||
import { MetricFindValue } from './datasource';
|
||||
import { DataSourceRef } from './query';
|
||||
|
||||
export type VariableType = TypedVariableModel['type'];
|
||||
@ -13,6 +14,7 @@ export interface VariableModel {
|
||||
export type TypedVariableModel =
|
||||
| QueryVariableModel
|
||||
| AdHocVariableModel
|
||||
| GroupByVariableModel
|
||||
| ConstantVariableModel
|
||||
| DataSourceVariableModel
|
||||
| IntervalVariableModel
|
||||
@ -64,6 +66,14 @@ export interface AdHocVariableModel extends BaseVariableModel {
|
||||
baseFilters?: AdHocVariableFilter[];
|
||||
}
|
||||
|
||||
export interface GroupByVariableModel extends BaseVariableModel {
|
||||
type: 'groupby';
|
||||
datasource: DataSourceRef | null;
|
||||
groupByKeys: string[];
|
||||
defaultOptions?: MetricFindValue[];
|
||||
multi: true;
|
||||
}
|
||||
|
||||
export interface VariableOption {
|
||||
selected: boolean;
|
||||
text: string | string[];
|
||||
|
@ -349,7 +349,7 @@ export type DashboardLinkType = ('link' | 'dashboards');
|
||||
* `custom`: Define the variable options manually using a comma-separated list.
|
||||
* `system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
|
||||
*/
|
||||
export type VariableType = ('query' | 'adhoc' | 'constant' | 'datasource' | 'interval' | 'textbox' | 'custom' | 'system');
|
||||
export type VariableType = ('query' | 'adhoc' | 'groupby' | 'constant' | 'datasource' | 'interval' | 'textbox' | 'custom' | 'system');
|
||||
|
||||
/**
|
||||
* Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.
|
||||
|
@ -159,6 +159,7 @@ const (
|
||||
VariableTypeConstant VariableType = "constant"
|
||||
VariableTypeCustom VariableType = "custom"
|
||||
VariableTypeDatasource VariableType = "datasource"
|
||||
VariableTypeGroupby VariableType = "groupby"
|
||||
VariableTypeInterval VariableType = "interval"
|
||||
VariableTypeQuery VariableType = "query"
|
||||
VariableTypeSystem VariableType = "system"
|
||||
|
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import { GroupByVariable } from '@grafana/scenes';
|
||||
|
||||
interface GroupByVariableEditorProps {
|
||||
variable: GroupByVariable;
|
||||
onChange: (variable: GroupByVariable) => void;
|
||||
}
|
||||
|
||||
export function GroupByVariableEditor(props: GroupByVariableEditorProps) {
|
||||
return <div>GroupByVariableEditor</div>;
|
||||
}
|
@ -7,6 +7,7 @@ import {
|
||||
QueryVariable,
|
||||
DataSourceVariable,
|
||||
AdHocFiltersVariable,
|
||||
GroupByVariable,
|
||||
TextBoxVariable,
|
||||
SceneVariableSet,
|
||||
} from '@grafana/scenes';
|
||||
@ -18,6 +19,7 @@ import { AdHocFiltersVariableEditor } from './editors/AdHocFiltersVariableEditor
|
||||
import { ConstantVariableEditor } from './editors/ConstantVariableEditor';
|
||||
import { CustomVariableEditor } from './editors/CustomVariableEditor';
|
||||
import { DataSourceVariableEditor } from './editors/DataSourceVariableEditor';
|
||||
import { GroupByVariableEditor } from './editors/GroupByVariableEditor';
|
||||
import { IntervalVariableEditor } from './editors/IntervalVariableEditor';
|
||||
import { QueryVariableEditor } from './editors/QueryVariableEditor';
|
||||
import { TextBoxVariableEditor } from './editors/TextBoxVariableEditor';
|
||||
@ -73,7 +75,16 @@ jest.mock('@grafana/runtime', () => ({
|
||||
|
||||
describe('isEditableVariableType', () => {
|
||||
it('should return true for editable variable types', () => {
|
||||
const editableTypes: VariableType[] = ['custom', 'query', 'constant', 'interval', 'datasource', 'adhoc', 'textbox'];
|
||||
const editableTypes: VariableType[] = [
|
||||
'custom',
|
||||
'query',
|
||||
'constant',
|
||||
'interval',
|
||||
'datasource',
|
||||
'adhoc',
|
||||
'groupby',
|
||||
'textbox',
|
||||
];
|
||||
editableTypes.forEach((type) => {
|
||||
expect(isEditableVariableType(type)).toBe(true);
|
||||
});
|
||||
@ -99,7 +110,7 @@ describe('getVariableTypeSelectOptions', () => {
|
||||
|
||||
it('should return an array of selectable values for editable variable types', () => {
|
||||
const options = getVariableTypeSelectOptions();
|
||||
expect(options).toHaveLength(7);
|
||||
expect(options).toHaveLength(8);
|
||||
|
||||
options.forEach((option, index) => {
|
||||
const editableType = EDITABLE_VARIABLES_SELECT_ORDER[index];
|
||||
@ -132,6 +143,7 @@ describe('getVariableEditor', () => {
|
||||
['interval', IntervalVariableEditor],
|
||||
['datasource', DataSourceVariableEditor],
|
||||
['adhoc', AdHocFiltersVariableEditor],
|
||||
['groupby', GroupByVariableEditor],
|
||||
['textbox', TextBoxVariableEditor],
|
||||
])('should return the correct editor for variable type "%s"', (type, ExpectedVariableEditor) => {
|
||||
expect(getVariableEditor(type as EditableVariableType)).toBe(ExpectedVariableEditor);
|
||||
@ -158,6 +170,7 @@ describe('getVariableScene', () => {
|
||||
['interval', IntervalVariable],
|
||||
['datasource', DataSourceVariable],
|
||||
['adhoc', AdHocFiltersVariable],
|
||||
['groupby', GroupByVariable],
|
||||
['textbox', TextBoxVariable],
|
||||
])('should return the scene variable instance for the given editable variable type', () => {
|
||||
const initialState = { name: 'MyVariable' };
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
TextBoxVariable,
|
||||
QueryVariable,
|
||||
AdHocFilterSet,
|
||||
GroupByVariable,
|
||||
SceneVariable,
|
||||
MultiValueVariable,
|
||||
SceneVariableState,
|
||||
@ -22,6 +23,7 @@ import { AdHocFiltersVariableEditor } from './editors/AdHocFiltersVariableEditor
|
||||
import { ConstantVariableEditor } from './editors/ConstantVariableEditor';
|
||||
import { CustomVariableEditor } from './editors/CustomVariableEditor';
|
||||
import { DataSourceVariableEditor } from './editors/DataSourceVariableEditor';
|
||||
import { GroupByVariableEditor } from './editors/GroupByVariableEditor';
|
||||
import { IntervalVariableEditor } from './editors/IntervalVariableEditor';
|
||||
import { QueryVariableEditor } from './editors/QueryVariableEditor';
|
||||
import { TextBoxVariableEditor } from './editors/TextBoxVariableEditor';
|
||||
@ -69,6 +71,11 @@ export const EDITABLE_VARIABLES: Record<EditableVariableType, EditableVariableCo
|
||||
description: 'Add key/value filters on the fly',
|
||||
editor: AdHocFiltersVariableEditor,
|
||||
},
|
||||
groupby: {
|
||||
name: 'Group by',
|
||||
description: 'Add keys to group by on the fly',
|
||||
editor: GroupByVariableEditor,
|
||||
},
|
||||
textbox: {
|
||||
name: 'Textbox',
|
||||
description: 'Define a textbox variable, where users can enter any arbitrary string',
|
||||
@ -84,6 +91,7 @@ export const EDITABLE_VARIABLES_SELECT_ORDER: EditableVariableType[] = [
|
||||
'datasource',
|
||||
'interval',
|
||||
'adhoc',
|
||||
'groupby',
|
||||
];
|
||||
|
||||
export function getVariableTypeSelectOptions(): Array<SelectableValue<EditableVariableType>> {
|
||||
@ -118,6 +126,8 @@ export function getVariableScene(type: EditableVariableType, initialState: Commo
|
||||
case 'adhoc':
|
||||
// TODO: Initialize properly AdHocFilterSet with initialState
|
||||
return new AdHocFilterSet({ name: initialState.name });
|
||||
case 'groupby':
|
||||
return new GroupByVariable(initialState);
|
||||
case 'textbox':
|
||||
return new TextBoxVariable(initialState);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
createCustomVariable,
|
||||
createDashboardVariable,
|
||||
createDatasourceVariable,
|
||||
createGroupByVariable,
|
||||
createIntervalVariable,
|
||||
createOrgVariable,
|
||||
createQueryVariable,
|
||||
@ -164,6 +165,7 @@ describe('type guards', () => {
|
||||
const variableFactsObj: Record<VariableType | ExtraVariableTypes, VariableFacts> = {
|
||||
query: { variable: createQueryVariable(), isMulti: true, hasOptions: true, hasCurrent: true },
|
||||
adhoc: { variable: createAdhocVariable(), isMulti: false, hasOptions: false, hasCurrent: false },
|
||||
groupby: { variable: createGroupByVariable(), isMulti: true, hasOptions: false, hasCurrent: false },
|
||||
constant: { variable: createConstantVariable(), isMulti: false, hasOptions: true, hasCurrent: true },
|
||||
datasource: { variable: createDatasourceVariable(), isMulti: true, hasOptions: true, hasCurrent: true },
|
||||
interval: { variable: createIntervalVariable(), isMulti: false, hasOptions: true, hasCurrent: true },
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
CustomVariableModel,
|
||||
DashboardVariableModel,
|
||||
DataSourceVariableModel,
|
||||
GroupByVariableModel,
|
||||
IntervalVariableModel,
|
||||
LoadingState,
|
||||
OrgVariableModel,
|
||||
@ -78,6 +79,19 @@ export function createAdhocVariable(input?: Partial<AdHocVariableModel>): AdHocV
|
||||
};
|
||||
}
|
||||
|
||||
export function createGroupByVariable(input?: Partial<GroupByVariableModel>): GroupByVariableModel {
|
||||
return {
|
||||
...createBaseVariableModel('groupby'),
|
||||
datasource: {
|
||||
uid: 'abc-123',
|
||||
type: 'prometheus',
|
||||
},
|
||||
groupByKeys: [],
|
||||
multi: true,
|
||||
...input,
|
||||
};
|
||||
}
|
||||
|
||||
export function createConstantVariable(input: Partial<ConstantVariableModel> = {}): ConstantVariableModel {
|
||||
return {
|
||||
...createBaseVariableModel('constant'),
|
||||
|
22
yarn.lock
22
yarn.lock
@ -3850,7 +3850,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana/scenes@npm:^2.4.0":
|
||||
"@grafana/scenes@npm:2.6.3":
|
||||
version: 2.6.3
|
||||
resolution: "@grafana/scenes@npm:2.6.3"
|
||||
dependencies:
|
||||
@ -16834,12 +16834,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.0":
|
||||
version: 1.15.5
|
||||
resolution: "follow-redirects@npm:1.15.5"
|
||||
version: 1.15.3
|
||||
resolution: "follow-redirects@npm:1.15.3"
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
checksum: 10/d467f13c1c6aa734599b8b369cd7a625b20081af358f6204ff515f6f4116eb440de9c4e0c49f10798eeb0df26c95dd05d5e0d9ddc5786ab1a8a8abefe92929b4
|
||||
checksum: 10/60d98693f4976892f8c654b16ef6d1803887a951898857ab0cdc009570b1c06314ad499505b7a040ac5b98144939f8597766e5e6a6859c0945d157b473aa6f5f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -17772,7 +17772,7 @@ __metadata:
|
||||
"@grafana/o11y-ds-frontend": "workspace:*"
|
||||
"@grafana/prometheus": "workspace:*"
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/scenes": "npm:^2.4.0"
|
||||
"@grafana/scenes": "npm:2.6.3"
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/sql": "workspace:*"
|
||||
"@grafana/tsconfig": "npm:^1.3.0-rc1"
|
||||
@ -25579,11 +25579,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"react-hook-form@npm:^7.49.2":
|
||||
version: 7.50.1
|
||||
resolution: "react-hook-form@npm:7.50.1"
|
||||
version: 7.50.0
|
||||
resolution: "react-hook-form@npm:7.50.0"
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17 || ^18
|
||||
checksum: 10/54a9daa2143c601a9867e96a2159a0bbe98707b5bbeb5953bfdf3342d2f04bfcaa6169907ed167c5c1f3a044630860d4f43685f4ac4e15b9cd892d1b00d54dde
|
||||
checksum: 10/3b85cc179053af72a2734f2e77767de8f9b3ecbefeee282b73e81141c4b7bb97308ec00da61fdc25a28299a2defb74bff66417bb85a66357f5ceddba7b697ae7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -26243,12 +26243,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"react-zoom-pan-pinch@npm:^3.3.0":
|
||||
version: 3.4.2
|
||||
resolution: "react-zoom-pan-pinch@npm:3.4.2"
|
||||
version: 3.4.1
|
||||
resolution: "react-zoom-pan-pinch@npm:3.4.1"
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
react-dom: "*"
|
||||
checksum: 10/3014c26523d69eb6a10fb1862374e4fcfb8bcf14614b0a872ca178473634427753d5c7ed6f80233f973236fcd232dd5eec70365c6eb68703e435a9a74b75bf3f
|
||||
checksum: 10/6d46d88c869d49e511ed6899d736c8952a56ec38f7cdfa47fdd6c819c265ae4c503d4bdf6cb85557efb2e259489db6baaac9a3f3e0fa8703a534605afca6f8c2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user