diff --git a/docs/sources/developers/kinds/core/dashboard/schema-reference.md b/docs/sources/developers/kinds/core/dashboard/schema-reference.md index b1e7fb7ea9d..eb287875f5c 100644 --- a/docs/sources/developers/kinds/core/dashboard/schema-reference.md +++ b/docs/sources/developers/kinds/core/dashboard/schema-reference.md @@ -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
`query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.
`adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).
`constant`: Define a hidden constant.
`datasource`: Quickly change the data source for an entire dashboard.
`interval`: Interval variables represent time spans.
`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
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
Accepted values are 0 (show label and value), 1 (show value only), 2 (show nothing).
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
`0`: Never refresh the variable
`1`: Queries the data source every time the dashboard loads.
`2`: Queries the data source when the dashboard time range changes.
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.
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
Accepted values are:
`0`: No sorting
`1`: Alphabetical ASC
`2`: Alphabetical DESC
`3`: Numerical ASC
`4`: Numerical DESC
`5`: Alphabetical Case Insensitive ASC
`6`: Alphabetical Case Insensitive DESC
`7`: Natural ASC
`8`: Natural DESC
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
`query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.
`adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).
`constant`: Define a hidden constant.
`datasource`: Quickly change the data source for an entire dashboard.
`interval`: Interval variables represent time spans.
`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
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
Accepted values are 0 (show label and value), 1 (show value only), 2 (show nothing).
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
`0`: Never refresh the variable
`1`: Queries the data source every time the dashboard loads.
`2`: Queries the data source when the dashboard time range changes.
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.
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
Accepted values are:
`0`: No sorting
`1`: Alphabetical ASC
`2`: Alphabetical DESC
`3`: Numerical ASC
`4`: Numerical DESC
`5`: Alphabetical Case Insensitive ASC
`6`: Alphabetical Case Insensitive DESC
`7`: Natural ASC
`8`: Natural DESC
Possible values are: `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`. | ### VariableOption diff --git a/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue index ac0fddf3212..6cace8d26ff 100644 --- a/kinds/dashboard/dashboard_kind.cue +++ b/kinds/dashboard/dashboard_kind.cue @@ -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. diff --git a/package.json b/package.json index 964c78a49db..d6fa8af44b4 100644 --- a/package.json +++ b/package.json @@ -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:*", diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index 782462d146e..82232b4991d 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -560,6 +560,7 @@ export interface DataQueryRequest { /** Filters to dynamically apply to all queries */ filters?: AdHocVariableFilter[]; + groupByKeys?: string[]; // Request Timing startTime: number; diff --git a/packages/grafana-data/src/types/templateVars.ts b/packages/grafana-data/src/types/templateVars.ts index 8594bbb20e7..49dfe218bc9 100644 --- a/packages/grafana-data/src/types/templateVars.ts +++ b/packages/grafana-data/src/types/templateVars.ts @@ -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[]; diff --git a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts index 6e42cab8111..c34707a521c 100644 --- a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts +++ b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts @@ -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. diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go index eb45c900be2..dfd9bf19629 100644 --- a/pkg/kinds/dashboard/dashboard_spec_gen.go +++ b/pkg/kinds/dashboard/dashboard_spec_gen.go @@ -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" diff --git a/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx new file mode 100644 index 00000000000..8637fb23e5c --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx @@ -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
GroupByVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/utils.test.ts b/public/app/features/dashboard-scene/settings/variables/utils.test.ts index 9725ee5fe5c..f34dcdc3ec1 100644 --- a/public/app/features/dashboard-scene/settings/variables/utils.test.ts +++ b/public/app/features/dashboard-scene/settings/variables/utils.test.ts @@ -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' }; diff --git a/public/app/features/dashboard-scene/settings/variables/utils.ts b/public/app/features/dashboard-scene/settings/variables/utils.ts index 8b6480b6c9e..f1ed0380100 100644 --- a/public/app/features/dashboard-scene/settings/variables/utils.ts +++ b/public/app/features/dashboard-scene/settings/variables/utils.ts @@ -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> { @@ -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); } diff --git a/public/app/features/variables/guard.test.ts b/public/app/features/variables/guard.test.ts index 1afcf66bbef..17e22c9ccce 100644 --- a/public/app/features/variables/guard.test.ts +++ b/public/app/features/variables/guard.test.ts @@ -19,6 +19,7 @@ import { createCustomVariable, createDashboardVariable, createDatasourceVariable, + createGroupByVariable, createIntervalVariable, createOrgVariable, createQueryVariable, @@ -164,6 +165,7 @@ describe('type guards', () => { const variableFactsObj: Record = { 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 }, diff --git a/public/app/features/variables/state/__tests__/fixtures.ts b/public/app/features/variables/state/__tests__/fixtures.ts index 8f7ae7cc9f2..6014a6a33ce 100644 --- a/public/app/features/variables/state/__tests__/fixtures.ts +++ b/public/app/features/variables/state/__tests__/fixtures.ts @@ -5,6 +5,7 @@ import { CustomVariableModel, DashboardVariableModel, DataSourceVariableModel, + GroupByVariableModel, IntervalVariableModel, LoadingState, OrgVariableModel, @@ -78,6 +79,19 @@ export function createAdhocVariable(input?: Partial): AdHocV }; } +export function createGroupByVariable(input?: Partial): GroupByVariableModel { + return { + ...createBaseVariableModel('groupby'), + datasource: { + uid: 'abc-123', + type: 'prometheus', + }, + groupByKeys: [], + multi: true, + ...input, + }; +} + export function createConstantVariable(input: Partial = {}): ConstantVariableModel { return { ...createBaseVariableModel('constant'), diff --git a/yarn.lock b/yarn.lock index de827c749d4..14c16499f6b 100644 --- a/yarn.lock +++ b/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