From f73be970d35f87d636f148b48ad0b0feae2817a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Tue, 27 Apr 2021 05:57:25 +0200 Subject: [PATCH] Variables: Removes experimental Tags feature (#33361) * Variables: Removes experimental Tags feature * Refactor: adds dashboard migration * Tests: fixes snapshots * Docs: removes docs for experimental feature * Refactor: dummy change * Docs: removes reference --- .../variable-types/add-query-variable.md | 1 - docs/sources/variables/variable-value-tags.md | 34 ---- .../specs/variables/new-query-variable.ts | 2 - .../__snapshots__/DashboardPage.test.tsx.snap | 14 +- .../__snapshots__/DashboardGrid.test.tsx.snap | 8 +- .../dashboard/state/DashboardMigrator.test.ts | 62 +++---- .../dashboard/state/DashboardMigrator.ts | 79 +++------ .../pickers/OptionsPicker/OptionsPicker.tsx | 33 +--- .../pickers/OptionsPicker/actions.test.ts | 66 ------- .../pickers/OptionsPicker/actions.ts | 53 +----- .../pickers/OptionsPicker/reducer.test.ts | 165 +----------------- .../pickers/OptionsPicker/reducer.ts | 53 +----- .../variables/pickers/shared/VariableLink.tsx | 35 ++-- .../pickers/shared/VariableOptions.tsx | 46 +---- .../query/QueryVariableEditor.test.tsx | 25 +-- .../variables/query/QueryVariableEditor.tsx | 71 +------- .../query/VariableQueryRunner.test.ts | 94 +--------- .../variables/query/VariableQueryRunner.ts | 10 +- .../features/variables/query/actions.test.ts | 101 +++-------- .../variables/query/operators.test.ts | 129 +------------- .../app/features/variables/query/operators.ts | 47 +---- .../features/variables/query/reducer.test.ts | 22 --- .../app/features/variables/query/reducer.ts | 19 +- .../variables/shared/formatVariable.ts | 36 +--- .../shared/testing/queryVariableBuilder.ts | 10 -- .../features/variables/state/sharedReducer.ts | 22 +-- public/app/features/variables/types.ts | 12 -- 27 files changed, 130 insertions(+), 1119 deletions(-) delete mode 100644 docs/sources/variables/variable-value-tags.md diff --git a/docs/sources/variables/variable-types/add-query-variable.md b/docs/sources/variables/variable-types/add-query-variable.md index 0bc6ac2048a..42c17705d67 100644 --- a/docs/sources/variables/variable-types/add-query-variable.md +++ b/docs/sources/variables/variable-types/add-query-variable.md @@ -39,6 +39,5 @@ Query expressions are different for each data source. For more information, refe 1. (optional) In the **Regex** field, type a regex expression to filter or capture specific parts of the names returned by your data source query. To see examples, refer to [Filter variables with regex]({{< relref "../filter-variables-with-regex.md" >}}). 1. In the **Sort** list, select the sort order for values to be displayed in the dropdown list. The default option, **Disabled**, means that the order of options returned by your data source query will be used. 1. (optional) Enter [Selection Options]({{< relref "../variable-selection-options.md" >}}). -1. (optional) Enter [Value groups/tags]({{< relref "../variable-value-tags.md" >}}). 1. In **Preview of values**, Grafana displays a list of the current variable values. Review them to ensure they match what you expect. 1. Click **Add** to add the variable to the dashboard. diff --git a/docs/sources/variables/variable-value-tags.md b/docs/sources/variables/variable-value-tags.md deleted file mode 100644 index 8030cc3e31a..00000000000 --- a/docs/sources/variables/variable-value-tags.md +++ /dev/null @@ -1,34 +0,0 @@ -+++ -title = "Variable value group tags" -weight = 500 -+++ - -# Configure variable value group tags - -> **Note:** This is an experimental feature that will be deprecated in Grafana v8. - -Value groups/tags are a feature you can use to organize variable options. If you have many options in the dropdown for a multi-value variable, then you can use this feature to group the values into selectable tags. - -{{< docs-imagebox img="/img/docs/v50/variable_dropdown_tags.png" max-width="300px" >}} - -This feature is off by default. Click **Enabled** to turn the feature on. - -To see an example, check out [Templating value groups](https://play.grafana.org/d/000000024/templating-value-groups?orgId=1). - -## Tags query - -Enter a data source query that should return a list of tags. The tags query returns a list of tags that each represents a group, and the tag values query returns a list of group members. - -For example, the tags query could be a list of regions (Europe, Asia, Americas), and then if the user selects the Europe tag, then the tag values query would return a list of countries -- Sweden, Germany, France, and so on. - -If you have a variable with a lot of values (say all the countries in the world), then this allows you to easily select a group of them. If the user selects the tag Europe, all the countries in Europe would be selected. - -In this [example dashboard](https://play.grafana.org/d/ZUPhFVGGk/graphite-with-experimental-tags?orgId=1), the server variable has tags enabled. - -## Tag values query - -Enter a data source query that should return a list of values for a specified tag key. Use `$tag` in the query to refer to the currently selected tag. - -The `$tag` variable will have the value of the tag that the user chooses. - -For example, if you have a Graphite query for tags, `regions.*`, that returns a list of regions. The values query could be `regions.$tag.*`, which if the user chooses Europe would be interpolated to `regions.Europe.*`. diff --git a/e2e/suite1/specs/variables/new-query-variable.ts b/e2e/suite1/specs/variables/new-query-variable.ts index 4da5b2ed6f0..8df5486a240 100644 --- a/e2e/suite1/specs/variables/new-query-variable.ts +++ b/e2e/suite1/specs/variables/new-query-variable.ts @@ -65,8 +65,6 @@ describe('Variables - Add variable', () => { e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch().should('not.be.checked'); e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch().should('not.be.checked'); - e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.valueGroupsTagsEnabledSwitch().should('not.be.checked'); - e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should('not.exist'); e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput().should('not.exist'); }); diff --git a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap index 391c8b99e4b..d527a15767d 100644 --- a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap +++ b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap @@ -88,7 +88,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -220,7 +220,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -322,7 +322,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -446,7 +446,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -578,7 +578,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -680,7 +680,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -786,7 +786,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], diff --git a/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap b/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap index 9a07bf1e0ec..857cff96ae8 100644 --- a/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap +++ b/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap @@ -228,7 +228,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -469,7 +469,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -710,7 +710,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], @@ -951,7 +951,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ], "refresh": undefined, "revision": undefined, - "schemaVersion": 27, + "schemaVersion": 28, "snapshot": undefined, "style": "dark", "tags": Array [], diff --git a/public/app/features/dashboard/state/DashboardMigrator.test.ts b/public/app/features/dashboard/state/DashboardMigrator.test.ts index 5b80e8b8127..d053b288a3b 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.test.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.test.ts @@ -133,7 +133,7 @@ describe('DashboardModel', () => { }); it('dashboard schema version should be set to latest', () => { - expect(model.schemaVersion).toBe(27); + expect(model.schemaVersion).toBe(28); }); it('graph thresholds should be migrated', () => { @@ -628,7 +628,7 @@ describe('DashboardModel', () => { }); }); - describe('when migrating variables with old tags format', () => { + describe('when migrating variables with tags', () => { let model: DashboardModel; beforeEach(() => { @@ -638,6 +638,9 @@ describe('DashboardModel', () => { { type: 'query', tags: ['Africa', 'America', 'Asia', 'Europe'], + tagsQuery: 'select datacenter from x', + tagValuesQuery: 'select value from x where datacenter = xyz', + useTags: true, }, { type: 'query', @@ -660,6 +663,9 @@ describe('DashboardModel', () => { value: ['server-us-east', 'server-us-central', 'server-us-west', 'server-eu-east', 'server-eu-west'], }, tags: ['Africa', 'America', 'Asia', 'Europe'], + tagsQuery: 'select datacenter from x', + tagValuesQuery: 'select value from x where datacenter = xyz', + useTags: true, }, { type: 'query', @@ -669,6 +675,9 @@ describe('DashboardModel', () => { { text: 'Asia', selected: false }, { text: 'Europe', selected: false }, ], + tagsQuery: 'select datacenter from x', + tagValuesQuery: 'select value from x where datacenter = xyz', + useTags: true, }, ], }, @@ -679,41 +688,28 @@ describe('DashboardModel', () => { expect(model.templating.list.length).toBe(3); }); - it('should be migrated with defaults if being out of sync', () => { - expect(model.templating.list[0].tags).toEqual([ - { text: 'Africa', selected: false }, - { text: 'America', selected: false }, - { text: 'Asia', selected: false }, - { text: 'Europe', selected: false }, - ]); + it('should have no tags', () => { + expect(model.templating.list[0].tags).toBeUndefined(); + expect(model.templating.list[1].tags).toBeUndefined(); + expect(model.templating.list[2].tags).toBeUndefined(); }); - it('should be migrated with current values if being out of sync', () => { - expect(model.templating.list[1].tags).toEqual([ - { text: 'Africa', selected: false }, - { - selected: true, - text: 'America', - values: ['server-us-east', 'server-us-central', 'server-us-west'], - valuesText: 'server-us-east + server-us-central + server-us-west', - }, - { text: 'Asia', selected: false }, - { - selected: true, - text: 'Europe', - values: ['server-eu-east', 'server-eu-west'], - valuesText: 'server-eu-east + server-eu-west', - }, - ]); + it('should have no tagsQuery property', () => { + expect(model.templating.list[0].tagsQuery).toBeUndefined(); + expect(model.templating.list[1].tagsQuery).toBeUndefined(); + expect(model.templating.list[2].tagsQuery).toBeUndefined(); }); - it('should not be migrated if being in sync', () => { - expect(model.templating.list[2].tags).toEqual([ - { text: 'Africa', selected: false }, - { text: 'America', selected: true }, - { text: 'Asia', selected: false }, - { text: 'Europe', selected: false }, - ]); + it('should have no tagValuesQuery property', () => { + expect(model.templating.list[0].tagValuesQuery).toBeUndefined(); + expect(model.templating.list[1].tagValuesQuery).toBeUndefined(); + expect(model.templating.list[2].tagValuesQuery).toBeUndefined(); + }); + + it('should have no useTags property', () => { + expect(model.templating.list[0].useTags).toBeUndefined(); + expect(model.templating.list[1].useTags).toBeUndefined(); + expect(model.templating.list[2].useTags).toBeUndefined(); }); }); diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts index 03d66dcf9fd..a16ffec20f1 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.ts @@ -1,18 +1,5 @@ // Libraries -import { - defaults, - each, - find, - findIndex, - flattenDeep, - isArray, - isBoolean, - isNumber, - isString, - map, - max, - some, -} from 'lodash'; +import { each, find, findIndex, flattenDeep, isArray, isBoolean, isNumber, isString, map, max, some } from 'lodash'; // Utils import getFactors from 'app/core/utils/factors'; import kbn from 'app/core/utils/kbn'; @@ -29,9 +16,9 @@ import { GRID_COLUMN_COUNT, MIN_PANEL_HEIGHT, } from 'app/core/constants'; -import { isConstant, isMulti, isQuery } from 'app/features/variables/guard'; +import { isConstant, isMulti } from 'app/features/variables/guard'; import { alignCurrentWithMulti } from 'app/features/variables/shared/multiOptions'; -import { VariableHide, VariableTag } from '../../variables/types'; +import { VariableHide } from '../../variables/types'; export class DashboardMigrator { dashboard: DashboardModel; @@ -44,7 +31,7 @@ export class DashboardMigrator { let i, j, k, n; const oldVersion = this.dashboard.schemaVersion; const panelUpgrades = []; - this.dashboard.schemaVersion = 27; + this.dashboard.schemaVersion = 28; if (oldVersion === this.dashboard.schemaVersion) { return; @@ -537,43 +524,7 @@ export class DashboardMigrator { } if (oldVersion < 25) { - for (const variable of this.dashboard.templating.list) { - if (!isQuery(variable)) { - continue; - } - - const { tags, current } = variable; - if (!Array.isArray(tags)) { - variable.tags = []; - continue; - } - - const currentTags = current?.tags ?? []; - const currents = currentTags.reduce((all, tag) => { - if (tag && tag.hasOwnProperty('text') && typeof tag['text'] === 'string') { - all[tag.text] = tag; - } - return all; - }, {} as Record); - - const newTags: VariableTag[] = []; - - for (const tag of tags) { - if (typeof tag === 'object') { - // new format let's assume it's correct - newTags.push(tag); - continue; - } - - if (typeof tag !== 'string') { - // something that we do not support - continue; - } - - newTags.push(defaults(currents[tag], { text: tag, selected: false })); - } - variable.tags = newTags; - } + // tags are removed in version 28 } if (oldVersion < 26) { @@ -603,6 +554,26 @@ export class DashboardMigrator { } } + if (oldVersion < 28) { + for (const variable of this.dashboard.templating.list) { + if (variable.tags) { + delete variable.tags; + } + + if (variable.tagsQuery) { + delete variable.tagsQuery; + } + + if (variable.tagValuesQuery) { + delete variable.tagValuesQuery; + } + + if (variable.useTags) { + delete variable.useTags; + } + } + } + if (panelUpgrades.length === 0) { return; } diff --git a/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx b/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx index e3019c7ba06..edf577eb68a 100644 --- a/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx +++ b/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx @@ -5,17 +5,11 @@ import { LoadingState } from '@grafana/data'; import { StoreState } from 'app/types'; import { VariableInput } from '../shared/VariableInput'; -import { - commitChangesToVariable, - filterOrSearchOptions, - navigateOptions, - openOptions, - toggleAndFetchTag, -} from './actions'; +import { commitChangesToVariable, filterOrSearchOptions, navigateOptions, openOptions } from './actions'; import { OptionsPickerState, toggleAllOptions, toggleOption } from './reducer'; -import { VariableOption, VariableTag, VariableWithMultiSupport, VariableWithOptions } from '../../types'; +import { VariableOption, VariableWithMultiSupport, VariableWithOptions } from '../../types'; import { VariableOptions } from '../shared/VariableOptions'; -import { isMulti, isQuery } from '../../guard'; +import { isMulti } from '../../guard'; import { VariablePickerProps } from '../types'; import { formatVariableLabel } from '../../shared/formatVariable'; import { toVariableIdentifier } from '../../state/types'; @@ -31,7 +25,6 @@ export const optionPickerFactory = - ); + return ; } onCancel = () => { @@ -110,10 +94,8 @@ export const optionPickerFactory = @@ -126,10 +108,3 @@ export const optionPickerFactory = { - if (!isQuery(variable) || !Array.isArray(variable.tags)) { - return []; - } - return variable.tags.filter((t) => t.selected); -}; diff --git a/public/app/features/variables/pickers/OptionsPicker/actions.test.ts b/public/app/features/variables/pickers/OptionsPicker/actions.test.ts index 88f059f2509..9d6b4d23e27 100644 --- a/public/app/features/variables/pickers/OptionsPicker/actions.test.ts +++ b/public/app/features/variables/pickers/OptionsPicker/actions.test.ts @@ -7,7 +7,6 @@ import { moveOptionsHighlight, showOptions, toggleOption, - toggleTag, updateOptionsAndFilter, updateSearchQuery, } from './reducer'; @@ -16,7 +15,6 @@ import { filterOrSearchOptions, navigateOptions, openOptions, - toggleAndFetchTag, toggleOptionByHighlight, } from './actions'; import { NavigationKey } from '../types'; @@ -69,7 +67,6 @@ describe('options picker actions', () => { ...createOption(['A']), selected: true, value: ['A'], - tags: [] as any[], }; tester.thenDispatchedActionsShouldEqual( @@ -191,7 +188,6 @@ describe('options picker actions', () => { ...createOption(['B']), selected: true, value: ['B'], - tags: [] as any[], }; tester.thenDispatchedActionsShouldEqual( @@ -331,7 +327,6 @@ describe('options picker actions', () => { ...createOption(['A']), selected: true, value: ['A'] as any[], - tags: [] as any[], }; tester.thenDispatchedActionsShouldEqual( @@ -360,7 +355,6 @@ describe('options picker actions', () => { ...createOption([]), selected: true, value: [], - tags: [] as any[], }; tester.thenDispatchedActionsShouldEqual( @@ -392,7 +386,6 @@ describe('options picker actions', () => { ...createOption([]), selected: true, value: [], - tags: [] as any[], }; tester.thenDispatchedActionsShouldEqual( @@ -454,53 +447,6 @@ describe('options picker actions', () => { ); }); }); - - describe('when toggleAndFetchTag is dispatched with values', () => { - it('then correct actions are dispatched', async () => { - const options = [createOption('A'), createOption('B'), createOption('C')]; - const tag = createTag('tag', []); - const variable = createMultiVariable({ - options, - current: createOption(['A'], ['A'], true), - includeAll: false, - tags: [tag], - }); - - const tester = await reduxTester() - .givenRootReducer(getRootReducer()) - .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable }))) - .whenActionIsDispatched(showOptions(variable)) - .whenAsyncActionIsDispatched(toggleAndFetchTag(tag), true); - - tester.thenDispatchedActionsShouldEqual(toggleTag(tag)); - }); - }); - - describe('when toggleAndFetchTag is dispatched without values', () => { - it('then correct actions are dispatched', async () => { - const options = [createOption('A'), createOption('B'), createOption('C')]; - const tag = createTag('tag'); - const values = [createMetric('b')]; - const variable = createMultiVariable({ - options, - current: createOption(['A'], ['A'], true), - includeAll: false, - tags: [tag], - }); - - datasource.metricFindQuery.mockReset(); - // @ts-ignore strict null error TS2345: Argument of type '() => Promise<{ value: string; text: string; }[]>' is not assignable to parameter of type '() => Promise' - datasource.metricFindQuery.mockImplementation(() => Promise.resolve(values)); - - const tester = await reduxTester() - .givenRootReducer(getRootReducer()) - .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable }))) - .whenActionIsDispatched(showOptions(variable)) - .whenAsyncActionIsDispatched(toggleAndFetchTag(tag), true); - - tester.thenDispatchedActionsShouldEqual(toggleTag({ ...tag, values: ['b'] })); - }); - }); }); function createMultiVariable(extend?: Partial): QueryVariableModel { @@ -516,10 +462,6 @@ function createMultiVariable(extend?: Partial): QueryVariabl datasource: 'datasource', definition: '', sort: VariableSort.alphabeticalAsc, - tags: [], - tagsQuery: 'tags-query', - tagValuesQuery: '', - useTags: true, refresh: VariableRefresh.never, regex: '', multi: true, @@ -543,11 +485,3 @@ function createMetric(value: string | string[]) { text: value, }; } - -function createTag(name: string, values?: any[]) { - return { - selected: false, - text: name, - values, - }; -} diff --git a/public/app/features/variables/pickers/OptionsPicker/actions.ts b/public/app/features/variables/pickers/OptionsPicker/actions.ts index c0e58ddadee..9a6a3946d33 100644 --- a/public/app/features/variables/pickers/OptionsPicker/actions.ts +++ b/public/app/features/variables/pickers/OptionsPicker/actions.ts @@ -1,13 +1,6 @@ import { debounce, trim } from 'lodash'; import { StoreState, ThunkDispatch, ThunkResult } from 'app/types'; -import { - QueryVariableModel, - VariableOption, - VariableRefresh, - VariableTag, - VariableWithMultiSupport, - VariableWithOptions, -} from '../../types'; +import { VariableOption, VariableWithMultiSupport, VariableWithOptions } from '../../types'; import { variableAdapters } from '../../adapters'; import { getVariable } from '../../state/selectors'; import { NavigationKey } from '../types'; @@ -17,13 +10,10 @@ import { OptionsPickerState, showOptions, toggleOption, - toggleTag, updateOptionsAndFilter, updateOptionsFromSearch, updateSearchQuery, } from './reducer'; -import { getDataSourceSrv } from '@grafana/runtime'; -import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { changeVariableProp, setCurrentVariableValue } from '../../state/sharedReducer'; import { toVariablePayload, VariableIdentifier } from '../../state/types'; import { containsSearchFilter, getCurrentText } from '../../utils'; @@ -124,46 +114,6 @@ export const toggleOptionByHighlight = (clearOthers: boolean, forceSelect = fals }; }; -export const toggleAndFetchTag = (tag: VariableTag): ThunkResult => { - return async (dispatch, getState) => { - if (Array.isArray(tag.values)) { - return dispatch(toggleTag(tag)); - } - - const values = await dispatch(fetchTagValues(tag.text.toString())); - return dispatch(toggleTag({ ...tag, values })); - }; -}; - -const fetchTagValues = (tagText: string): ThunkResult> => { - return async (dispatch, getState) => { - const picker = getState().templating.optionsPicker; - const variable = getVariable(picker.id, getState()); - - const datasource = await getDataSourceSrv().get(variable.datasource ?? ''); - const query = variable.tagValuesQuery.replace(/\$tag/g, tagText); - const options = { range: getTimeRange(variable), variable }; - - if (!datasource.metricFindQuery) { - return []; - } - - const results = await datasource.metricFindQuery(query, options); - - if (!Array.isArray(results)) { - return []; - } - return results.map((value) => value.text); - }; -}; - -const getTimeRange = (variable: QueryVariableModel) => { - if (variable.refresh === VariableRefresh.onTimeRangeChanged || variable.refresh === VariableRefresh.onDashboardLoad) { - return getTimeSrv().timeRange(); - } - return undefined; -}; - const searchForOptions = async (dispatch: ThunkDispatch, getState: () => StoreState, searchQuery: string) => { try { const { id } = getState().templating.optionsPicker; @@ -207,7 +157,6 @@ export function mapToCurrent(picker: OptionsPickerState): VariableOption | undef return { value: values, text: texts, - tags: picker.tags.filter((t) => t.selected), selected: true, }; } diff --git a/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts index d11e1baa1be..166e88e0afb 100644 --- a/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts +++ b/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts @@ -10,13 +10,12 @@ import { showOptions, toggleAllOptions, toggleOption, - toggleTag, updateOptionsAndFilter, updateOptionsFromSearch, updateSearchQuery, } from './reducer'; import { reducerTester } from '../../../../../test/core/redux/reducerTester'; -import { QueryVariableModel, VariableOption, VariableTag } from '../../types'; +import { QueryVariableModel, VariableOption } from '../../types'; import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from '../../state/types'; const getVariableTestContext = (extend: Partial) => { @@ -357,168 +356,6 @@ describe('optionsPickerReducer', () => { }); }); - describe('when toggleTag is dispatched', () => { - it('then state should be correct', () => { - const { initialState } = getVariableTestContext({ - tags: [ - { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - ], - options: [ - { text: 'A', selected: false, value: 'A' }, - { text: 'AA', selected: false, value: 'AA' }, - { text: 'AAA', selected: false, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - }); - const payload: VariableTag = { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }; - reducerTester() - .givenReducer(optionsPickerReducer, cloneDeep(initialState)) - .whenActionIsDispatched(toggleTag(payload)) - .thenStateShouldEqual({ - ...initialState, - options: [ - { text: 'A', selected: true, value: 'A' }, - { text: 'AA', selected: true, value: 'AA' }, - { text: 'AAA', selected: true, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - tags: [ - { text: 'All A:s', selected: true, values: ['A', 'AA', 'AAA'], valuesText: 'A + AA + AAA' }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - ], - selectedValues: [ - { text: 'A', selected: true, value: 'A' }, - { text: 'AA', selected: true, value: 'AA' }, - { text: 'AAA', selected: true, value: 'AAA' }, - ], - }); - }); - }); - - describe('when toggleTag is dispatched when tag is selected', () => { - it('then state should be correct', () => { - const { initialState } = getVariableTestContext({ - tags: [ - { text: 'All A:s', selected: true, values: ['A', 'AA', 'AAA'] }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - ], - options: [ - { text: 'A', selected: true, value: 'A' }, - { text: 'AA', selected: true, value: 'AA' }, - { text: 'AAA', selected: true, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - }); - const payload: VariableTag = { text: 'All A:s', selected: true, values: ['A', 'AA', 'AAA'] }; - reducerTester() - .givenReducer(optionsPickerReducer, cloneDeep(initialState)) - .whenActionIsDispatched(toggleTag(payload)) - .thenStateShouldEqual({ - ...initialState, - options: [ - { text: 'A', selected: false, value: 'A' }, - { text: 'AA', selected: false, value: 'AA' }, - { text: 'AAA', selected: false, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - tags: [ - { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - ], - selectedValues: [], - }); - }); - }); - - describe('when toggleTag is dispatched and ALL is previous selected', () => { - it('then state should be correct', () => { - const { initialState } = getVariableTestContext({ - tags: [ - { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - ], - options: [ - { text: ALL_VARIABLE_TEXT, selected: true, value: ALL_VARIABLE_VALUE }, - { text: 'A', selected: false, value: 'A' }, - { text: 'AA', selected: false, value: 'AA' }, - { text: 'AAA', selected: false, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - }); - const payload: VariableTag = { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }; - reducerTester() - .givenReducer(optionsPickerReducer, cloneDeep(initialState)) - .whenActionIsDispatched(toggleTag(payload)) - .thenStateShouldEqual({ - ...initialState, - options: [ - { text: ALL_VARIABLE_TEXT, selected: false, value: ALL_VARIABLE_VALUE }, - { text: 'A', selected: true, value: 'A' }, - { text: 'AA', selected: true, value: 'AA' }, - { text: 'AAA', selected: true, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - tags: [ - { text: 'All A:s', selected: true, values: ['A', 'AA', 'AAA'], valuesText: 'A + AA + AAA' }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - ], - selectedValues: [ - { text: 'A', selected: true, value: 'A' }, - { text: 'AA', selected: true, value: 'AA' }, - { text: 'AAA', selected: true, value: 'AAA' }, - ], - }); - }); - }); - - describe('when toggleTag is dispatched and only the tag is previous selected', () => { - it('then state should be correct', () => { - const { initialState } = getVariableTestContext({ - tags: [ - { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - { text: 'All D:s', selected: true, values: ['D'] }, - ], - options: [ - { text: ALL_VARIABLE_TEXT, selected: false, value: ALL_VARIABLE_VALUE }, - { text: 'A', selected: false, value: 'A' }, - { text: 'AA', selected: false, value: 'AA' }, - { text: 'AAA', selected: false, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - }); - const payload: VariableTag = { text: 'All D:s', selected: true, values: ['D'] }; - reducerTester() - .givenReducer(optionsPickerReducer, cloneDeep(initialState)) - .whenActionIsDispatched(toggleTag(payload)) - .thenStateShouldEqual({ - ...initialState, - options: [ - { text: ALL_VARIABLE_TEXT, selected: true, value: ALL_VARIABLE_VALUE }, - { text: 'A', selected: false, value: 'A' }, - { text: 'AA', selected: false, value: 'AA' }, - { text: 'AAA', selected: false, value: 'AAA' }, - { text: 'B', selected: false, value: 'B' }, - ], - tags: [ - { text: 'All A:s', selected: false, values: ['A', 'AA', 'AAA'] }, - { text: 'All B:s', selected: false, values: ['B', 'BB', 'BBB'] }, - { text: 'All C:s', selected: false, values: ['C', 'CC', 'CCC'] }, - { text: 'All D:s', selected: false, values: ['D'] }, - ], - selectedValues: [{ text: ALL_VARIABLE_TEXT, selected: true, value: ALL_VARIABLE_VALUE }], - }); - }); - }); - describe('when changeQueryVariableHighlightIndex is dispatched with -1 and highlightIndex is 0', () => { it('then state should be correct', () => { const { initialState } = getVariableTestContext({ highlightIndex: 0 }); diff --git a/public/app/features/variables/pickers/OptionsPicker/reducer.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.ts index 464fa70b6cc..cece7d60714 100644 --- a/public/app/features/variables/pickers/OptionsPicker/reducer.ts +++ b/public/app/features/variables/pickers/OptionsPicker/reducer.ts @@ -1,6 +1,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { cloneDeep, isString, trim } from 'lodash'; -import { VariableOption, VariableTag, VariableWithMultiSupport, VariableWithOptions } from '../../types'; +import { VariableOption, VariableWithOptions } from '../../types'; import { ALL_VARIABLE_VALUE } from '../../state/types'; import { isMulti, isQuery } from '../../guard'; import { applyStateChanges } from '../../../../core/utils/applyStateChanges'; @@ -15,10 +15,8 @@ export interface ToggleOption { export interface OptionsPickerState { id: string; selectedValues: VariableOption[]; - selectedTags: VariableTag[]; queryValue: string; highlightIndex: number; - tags: VariableTag[]; options: VariableOption[]; multi: boolean; } @@ -27,22 +25,13 @@ export const initialState: OptionsPickerState = { id: '', highlightIndex: -1, queryValue: '', - selectedTags: [], selectedValues: [], - tags: [], options: [], multi: false, }; export const OPTIONS_LIMIT = 1000; -const getTags = (model: VariableWithMultiSupport) => { - if (isQuery(model) && Array.isArray(model.tags)) { - return cloneDeep(model.tags); - } - return []; -}; - const optionsToRecord = (options: VariableOption[]): Record => { if (!Array.isArray(options)) { return {}; @@ -129,7 +118,6 @@ const optionsPickerSlice = createSlice({ state.multi = false; if (isMulti(action.payload)) { - state.tags = getTags(action.payload); state.multi = action.payload.multi ?? false; } @@ -172,44 +160,6 @@ const optionsPickerSlice = createSlice({ return applyStateChanges(state, updateDefaultSelection, updateAllSelection, updateOptions); }, - toggleTag: (state, action: PayloadAction): OptionsPickerState => { - const tag = action.payload; - const values = tag.values || []; - const selected = !tag.selected; - - state.tags = state.tags.map((t) => { - if (t.text !== tag.text) { - return t; - } - - t.selected = selected; - t.values = values; - - if (selected) { - t.valuesText = values.join(' + '); - } else { - delete t.valuesText; - } - - return t; - }); - - const availableOptions = optionsToRecord(state.options); - - if (!selected) { - state.selectedValues = state.selectedValues.filter( - (option) => !isString(option.value) || !availableOptions[option.value] - ); - return applyStateChanges(state, updateDefaultSelection, updateOptions); - } - - const optionsFromTag = values - .filter((value) => value !== ALL_VARIABLE_VALUE && !!availableOptions[value]) - .map((value) => ({ selected, value, text: value })); - - state.selectedValues.push.apply(state.selectedValues, optionsFromTag); - return applyStateChanges(state, updateDefaultSelection, updateOptions); - }, moveOptionsHighlight: (state, action: PayloadAction): OptionsPickerState => { let nextIndex = state.highlightIndex + action.payload; @@ -270,7 +220,6 @@ export const { toggleOption, showOptions, hideOptions, - toggleTag, moveOptionsHighlight, toggleAllOptions, updateSearchQuery, diff --git a/public/app/features/variables/pickers/shared/VariableLink.tsx b/public/app/features/variables/pickers/shared/VariableLink.tsx index e70ec4d59f6..70bb9bfb3de 100644 --- a/public/app/features/variables/pickers/shared/VariableLink.tsx +++ b/public/app/features/variables/pickers/shared/VariableLink.tsx @@ -1,20 +1,17 @@ import React, { FC, MouseEvent, useCallback } from 'react'; import { css } from '@emotion/css'; -import { getTagColorsFromName, Icon, Tooltip, useStyles } from '@grafana/ui'; +import { Icon, Tooltip, useStyles } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; import { GrafanaTheme } from '@grafana/data'; -import { VariableTag } from '../../types'; - interface Props { onClick: () => void; text: string; - tags: VariableTag[]; loading: boolean; onCancel: () => void; } -export const VariableLink: FC = ({ loading, onClick: propsOnClick, tags, text, onCancel }) => { +export const VariableLink: FC = ({ loading, onClick: propsOnClick, text, onCancel }) => { const styles = useStyles(getStyles); const onClick = useCallback( (event: MouseEvent) => { @@ -32,7 +29,7 @@ export const VariableLink: FC = ({ loading, onClick: propsOnClick, tags, aria-label={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(`${text}`)} title={text} > - + ); @@ -45,31 +42,19 @@ export const VariableLink: FC = ({ loading, onClick: propsOnClick, tags, aria-label={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(`${text}`)} title={text} > - + ); }; -const VariableLinkText: FC> = ({ tags, text }) => { +interface VariableLinkTextProps { + text: string; +} + +const VariableLinkText: FC = ({ text }) => { const styles = useStyles(getStyles); - return ( - - {text} - {tags.map((tag) => { - const { color, borderColor } = getTagColorsFromName(tag.text.toString()); - return ( - - -    - -   {tag.text} - - - ); - })} - - ); + return {text}; }; const LoadingIndicator: FC> = ({ onCancel }) => { diff --git a/public/app/features/variables/pickers/shared/VariableOptions.tsx b/public/app/features/variables/pickers/shared/VariableOptions.tsx index 5573aed39b3..4af10003d00 100644 --- a/public/app/features/variables/pickers/shared/VariableOptions.tsx +++ b/public/app/features/variables/pickers/shared/VariableOptions.tsx @@ -1,18 +1,16 @@ import React, { PureComponent } from 'react'; -import { getTagColorsFromName, Icon, Tooltip } from '@grafana/ui'; +import { Tooltip } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; -import { VariableOption, VariableTag } from '../../types'; +import { VariableOption } from '../../types'; export interface Props { multi: boolean; values: VariableOption[]; selectedValues: VariableOption[]; - tags: VariableTag[]; highlightIndex: number; onToggle: (option: VariableOption, clearOthers: boolean) => void; onToggleAll: () => void; - onToggleTag: (tag: VariableTag) => void; } export class VariableOptions extends PureComponent { @@ -27,18 +25,13 @@ export class VariableOptions extends PureComponent { this.props.onToggleAll(); }; - onToggleTag = (tag: VariableTag) => (event: React.MouseEvent) => { - this.handleEvent(event); - this.props.onToggleTag(tag); - }; - handleEvent(event: React.MouseEvent) { event.preventDefault(); event.stopPropagation(); } render() { - const { multi, values, tags } = this.props; + const { multi, values } = this.props; return (
{ {this.renderMultiToggle()} {values.map((option, index) => this.renderOption(option, index))}
- {this.renderTags(tags)} ); } - renderTags(tags: VariableTag[]) { - if (tags.length === 0) { - return null; - } - - return ( -
-
Tags
- {tags.map((tag) => this.renderTag(tag))} -
- ); - } - - renderTag(tag: VariableTag) { - const { color, borderColor } = getTagColorsFromName(tag.text.toString()); - - return ( - - - - {tag.text}   - -   - - - ); - } - renderOption(option: VariableOption, index: number) { const { highlightIndex } = this.props; const selectClass = option.selected ? 'variable-option pointer selected' : 'variable-option pointer'; diff --git a/public/app/features/variables/query/QueryVariableEditor.test.tsx b/public/app/features/variables/query/QueryVariableEditor.test.tsx index f190caad2d8..937d6e22e29 100644 --- a/public/app/features/variables/query/QueryVariableEditor.test.tsx +++ b/public/app/features/variables/query/QueryVariableEditor.test.tsx @@ -13,7 +13,7 @@ import { setDataSourceSrv } from '@grafana/runtime'; const setupTestContext = (options: Partial) => { const defaults: Props = { - variable: { ...initialQueryVariableModelState, useTags: true }, + variable: { ...initialQueryVariableModelState }, initQueryVariableEditor: jest.fn(), changeQueryVariableDataSource: jest.fn(), changeQueryVariableQuery: jest.fn(), @@ -51,11 +51,9 @@ describe('QueryVariableEditor', () => { describe('when the user changes', () => { it.each` - fieldName | propName | expectedArgs - ${'query'} | ${'changeQueryVariableQuery'} | ${[{ type: 'query', id: NEW_VARIABLE_ID }, 't', 't']} - ${'regex'} | ${'onPropChange'} | ${{ propName: 'regex', propValue: 't', updateOptions: true }} - ${'tagsQuery'} | ${'onPropChange'} | ${{ propName: 'tagsQuery', propValue: 't', updateOptions: true }} - ${'tagValuesQuery'} | ${'onPropChange'} | ${{ propName: 'tagValuesQuery', propValue: 't', updateOptions: true }} + fieldName | propName | expectedArgs + ${'query'} | ${'changeQueryVariableQuery'} | ${[{ type: 'query', id: NEW_VARIABLE_ID }, 't', 't']} + ${'regex'} | ${'onPropChange'} | ${{ propName: 'regex', propValue: 't', updateOptions: true }} `( '$fieldName field and tabs away then $propName should be called with correct args', ({ fieldName, propName, expectedArgs }) => { @@ -74,11 +72,9 @@ describe('QueryVariableEditor', () => { describe('when the user changes', () => { it.each` - fieldName | propName - ${'query'} | ${'changeQueryVariableQuery'} - ${'regex'} | ${'onPropChange'} - ${'tagsQuery'} | ${'onPropChange'} - ${'tagValuesQuery'} | ${'onPropChange'} + fieldName | propName + ${'query'} | ${'changeQueryVariableQuery'} + ${'regex'} | ${'onPropChange'} `( '$fieldName field but reverts the change and tabs away then $propName should not be called', ({ fieldName, propName }) => { @@ -101,14 +97,7 @@ const getQueryField = () => const getRegExField = () => screen.getByRole('textbox', { name: /variable editor form query regex field/i }); -const getTagsQueryField = () => screen.getByRole('textbox', { name: /variable editor form query tagsquery field/i }); - -const getTagValuesQueryField = () => - screen.getByRole('textbox', { name: /variable editor form query tagsvaluesquery field/i }); - const fieldAccessors: Record HTMLElement> = { query: getQueryField, regex: getRegExField, - tagsQuery: getTagsQueryField, - tagValuesQuery: getTagValuesQueryField, }; diff --git a/public/app/features/variables/query/QueryVariableEditor.tsx b/public/app/features/variables/query/QueryVariableEditor.tsx index 8258f140b11..1f612c7022b 100644 --- a/public/app/features/variables/query/QueryVariableEditor.tsx +++ b/public/app/features/variables/query/QueryVariableEditor.tsx @@ -1,9 +1,9 @@ -import React, { ChangeEvent, FormEvent, PureComponent } from 'react'; +import React, { FormEvent, PureComponent } from 'react'; import { css } from '@emotion/css'; import { MapDispatchToProps, MapStateToProps } from 'react-redux'; import { InlineField, InlineFieldRow, VerticalGroup } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; -import { getTemplateSrv, DataSourcePicker } from '@grafana/runtime'; +import { DataSourcePicker, getTemplateSrv } from '@grafana/runtime'; import { DataSourceInstanceSettings, LoadingState, SelectableValue } from '@grafana/data'; import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor'; @@ -20,7 +20,6 @@ import { getTimeSrv } from '../../dashboard/services/TimeSrv'; import { isLegacyQueryEditor, isQueryEditor } from '../guard'; import { VariableSectionHeader } from '../editor/VariableSectionHeader'; import { VariableTextField } from '../editor/VariableTextField'; -import { VariableSwitchField } from '../editor/VariableSwitchField'; import { QueryVariableRefreshSelect } from './QueryVariableRefreshSelect'; import { QueryVariableSortSelect } from './QueryVariableSortSelect'; @@ -102,28 +101,6 @@ export class QueryVariableEditorUnConnected extends PureComponent } }; - onTagsQueryChange = async (event: FormEvent) => { - this.setState({ tagsQuery: event.currentTarget.value }); - }; - - onTagsQueryBlur = async (event: FormEvent) => { - const tagsQuery = event.currentTarget.value; - if (this.props.variable.tagsQuery !== tagsQuery) { - this.props.onPropChange({ propName: 'tagsQuery', propValue: tagsQuery, updateOptions: true }); - } - }; - - onTagValuesQueryChange = async (event: FormEvent) => { - this.setState({ tagValuesQuery: event.currentTarget.value }); - }; - - onTagValuesQueryBlur = async (event: FormEvent) => { - const tagValuesQuery = event.currentTarget.value; - if (this.props.variable.tagValuesQuery !== tagValuesQuery) { - this.props.onPropChange({ propName: 'tagValuesQuery', propValue: tagValuesQuery, updateOptions: true }); - } - }; - onRefreshChange = (option: SelectableValue) => { this.props.onPropChange({ propName: 'refresh', propValue: option.value }); }; @@ -136,10 +113,6 @@ export class QueryVariableEditorUnConnected extends PureComponent this.props.onPropChange({ propName, propValue, updateOptions: true }); }; - onUseTagsChange = async (event: ChangeEvent) => { - this.props.onPropChange({ propName: 'useTags', propValue: event.target.checked, updateOptions: true }); - }; - renderQueryEditor = () => { const { editor, variable } = this.props; if (!editor.extended || !editor.extended.dataSource || !editor.extended.VariableQueryEditor) { @@ -236,46 +209,6 @@ export class QueryVariableEditorUnConnected extends PureComponent onPropChange={this.onSelectionOptionsChange} onMultiChanged={this.props.changeVariableMultiValue} /> - - -
Value group tags
- Experimental feature, will be deprecated in Grafana v8. - - - {this.props.variable.useTags ? ( - - - - - ) : null} -
); diff --git a/public/app/features/variables/query/VariableQueryRunner.test.ts b/public/app/features/variables/query/VariableQueryRunner.test.ts index 8ff8ebd50e4..ae8c9744d4f 100644 --- a/public/app/features/variables/query/VariableQueryRunner.test.ts +++ b/public/app/features/variables/query/VariableQueryRunner.test.ts @@ -7,7 +7,7 @@ import { queryBuilder } from '../shared/testing/builders'; import { QueryRunner, QueryRunners } from './queryRunners'; import { toVariableIdentifier, VariableIdentifier } from '../state/types'; import { QueryVariableModel } from '../types'; -import { updateVariableOptions, updateVariableTags } from './reducer'; +import { updateVariableOptions } from './reducer'; type DoneCallback = { (...args: any[]): any; @@ -146,56 +146,6 @@ describe('VariableQueryRunner', () => { }); }); - describe('tags case', () => { - it('then it should work as expected', (done) => { - const variable = queryBuilder().withId('query').withTags(true).withTagsQuery('A tags query').build(); - const { - identifier, - runner, - datasource, - getState, - getVariable, - queryRunners, - queryRunner, - dispatch, - } = getTestContext(variable); - - expectOnResults({ - identifier, - runner, - expect: (results) => { - // verify that the observable works as expected - expect(results).toEqual([ - { state: LoadingState.Loading, identifier }, - { state: LoadingState.Done, identifier }, - ]); - - // verify that mocks have been called as expected - expect(getState).toHaveBeenCalledTimes(3); - expect(getVariable).toHaveBeenCalledTimes(1); - expect(queryRunners.getRunnerForDatasource).toHaveBeenCalledTimes(1); - expect(queryRunner.getTarget).toHaveBeenCalledTimes(1); - expect(queryRunner.runRequest).toHaveBeenCalledTimes(1); - expect(datasource.metricFindQuery).toHaveBeenCalledTimes(1); - - // updateVariableOptions, updateVariableTags and validateVariableSelectionState - expect(dispatch).toHaveBeenCalledTimes(3); - expect(dispatch.mock.calls[0][0]).toEqual( - updateVariableOptions({ - id: 'query', - type: 'query', - data: { results: [], templatedRegex: 'getTemplatedRegex result' }, - }) - ); - expect(dispatch.mock.calls[1][0]).toEqual(updateVariableTags({ id: 'query', type: 'query', data: [] })); - }, - done, - }); - - runner.queueRequest({ identifier, datasource }); - }); - }); - describe('error cases', () => { describe('queryRunners.getRunnerForDatasource throws', () => { it('then it should work as expected', (done) => { @@ -280,48 +230,6 @@ describe('VariableQueryRunner', () => { runner.queueRequest({ identifier, datasource }); }); }); - - describe('metricFindQuery throws', () => { - it('then it should work as expected', (done) => { - const variable = queryBuilder().withId('query').withTags(true).withTagsQuery('A tags query').build(); - const { - identifier, - runner, - datasource, - getState, - getVariable, - queryRunners, - queryRunner, - dispatch, - } = getTestContext(variable); - - datasource.metricFindQuery = jest.fn().mockRejectedValue(new Error('metricFindQuery error')); - - expectOnResults({ - identifier, - runner, - expect: (results) => { - // verify that the observable works as expected - expect(results).toEqual([ - { state: LoadingState.Loading, identifier }, - { state: LoadingState.Error, identifier, error: new Error('metricFindQuery error') }, - ]); - - // verify that mocks have been called as expected - expect(getState).toHaveBeenCalledTimes(3); - expect(getVariable).toHaveBeenCalledTimes(1); - expect(queryRunners.getRunnerForDatasource).toHaveBeenCalledTimes(1); - expect(queryRunner.getTarget).toHaveBeenCalledTimes(1); - expect(queryRunner.runRequest).toHaveBeenCalledTimes(1); - expect(datasource.metricFindQuery).toHaveBeenCalledTimes(1); - expect(dispatch).toHaveBeenCalledTimes(1); - }, - done, - }); - - runner.queueRequest({ identifier, datasource }); - }); - }); }); describe('cancellation cases', () => { diff --git a/public/app/features/variables/query/VariableQueryRunner.ts b/public/app/features/variables/query/VariableQueryRunner.ts index e8b7daae4c2..597ff44ad04 100644 --- a/public/app/features/variables/query/VariableQueryRunner.ts +++ b/public/app/features/variables/query/VariableQueryRunner.ts @@ -20,13 +20,7 @@ import { v4 as uuidv4 } from 'uuid'; import { getTimeSrv } from '../../dashboard/services/TimeSrv'; import { QueryRunners } from './queryRunners'; import { runRequest } from '../../query/state/runRequest'; -import { - runUpdateTagsRequest, - toMetricFindValues, - updateOptionsState, - updateTagsState, - validateVariableSelection, -} from './operators'; +import { toMetricFindValues, updateOptionsState, validateVariableSelection } from './operators'; interface UpdateOptionsArgs { identifier: VariableIdentifier; @@ -133,8 +127,6 @@ export class VariableQueryRunner { }), toMetricFindValues(), updateOptionsState({ variable, dispatch, getTemplatedRegexFunc }), - runUpdateTagsRequest({ variable, datasource, searchFilter }), - updateTagsState({ variable, dispatch }), validateVariableSelection({ variable, dispatch, searchFilter }), takeUntil( merge(this.updateOptionsRequests, this.cancelRequests).pipe( diff --git a/public/app/features/variables/query/actions.test.ts b/public/app/features/variables/query/actions.test.ts index 749ef563a42..4365d0ccd86 100644 --- a/public/app/features/variables/query/actions.test.ts +++ b/public/app/features/variables/query/actions.test.ts @@ -22,7 +22,7 @@ import { initQueryVariableEditor, updateQueryVariableOptions, } from './actions'; -import { updateVariableOptions, updateVariableTags } from './reducer'; +import { updateVariableOptions } from './reducer'; import { addVariableEditorError, changeVariableEditorExtended, @@ -78,64 +78,12 @@ describe('query actions', () => { variableAdapters.setInit(() => [createQueryVariableAdapter()]); - describe('when updateQueryVariableOptions is dispatched for variable with tags and includeAll', () => { - it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true }); - const optionsMetrics = [createMetric('A'), createMetric('B')]; - const tagsMetrics = [createMetric('tagA'), createMetric('tagB')]; - - mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics); - - const tester = await reduxTester() - .givenRootReducer(getRootReducer()) - .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable }))) - .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); - - const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE); - const update = { results: optionsMetrics, templatedRegex: '' }; - - tester.thenDispatchedActionsShouldEqual( - updateVariableOptions(toVariablePayload(variable, update)), - updateVariableTags(toVariablePayload(variable, tagsMetrics)), - setCurrentVariableValue(toVariablePayload(variable, { option })) - ); - }); - }); - - describe('when updateQueryVariableOptions is dispatched for variable with tags', () => { + describe('when updateQueryVariableOptions is dispatched for variable without both tags and includeAll', () => { it('then correct actions are dispatched', async () => { const variable = createVariable({ includeAll: false }); const optionsMetrics = [createMetric('A'), createMetric('B')]; - const tagsMetrics = [createMetric('tagA'), createMetric('tagB')]; - mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics); - - const tester = await reduxTester() - .givenRootReducer(getRootReducer()) - .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable }))) - .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); - - const option = createOption('A'); - const update = { results: optionsMetrics, templatedRegex: '' }; - - tester.thenDispatchedActionsPredicateShouldEqual((actions) => { - const [updateOptions, updateTags, setCurrentAction] = actions; - const expectedNumberOfActions = 3; - - expect(updateOptions).toEqual(updateVariableOptions(toVariablePayload(variable, update))); - expect(updateTags).toEqual(updateVariableTags(toVariablePayload(variable, tagsMetrics))); - expect(setCurrentAction).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); - return actions.length === expectedNumberOfActions; - }); - }); - }); - - describe('when updateQueryVariableOptions is dispatched for variable without both tags and includeAll', () => { - it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: false, useTags: false }); - const optionsMetrics = [createMetric('A'), createMetric('B')]; - - mockDatasourceMetrics(variable, optionsMetrics, []); + mockDatasourceMetrics(variable, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -154,10 +102,10 @@ describe('query actions', () => { describe('when updateQueryVariableOptions is dispatched for variable with includeAll but without tags', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const optionsMetrics = [createMetric('A'), createMetric('B')]; - mockDatasourceMetrics(variable, optionsMetrics, []); + mockDatasourceMetrics(variable, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -180,10 +128,10 @@ describe('query actions', () => { describe('when updateQueryVariableOptions is dispatched for variable open in editor', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const optionsMetrics = [createMetric('A'), createMetric('B')]; - mockDatasourceMetrics(variable, optionsMetrics, []); + mockDatasourceMetrics(variable, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -208,10 +156,10 @@ describe('query actions', () => { describe('when updateQueryVariableOptions is dispatched for variable with searchFilter', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const optionsMetrics = [createMetric('A'), createMetric('B')]; - mockDatasourceMetrics(variable, optionsMetrics, []); + mockDatasourceMetrics(variable, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -235,7 +183,7 @@ describe('query actions', () => { describe('when updateQueryVariableOptions is dispatched and fails for variable open in editor', () => { silenceConsoleOutput(); it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const error = { message: 'failed to fetch metrics' }; mocks[variable.datasource!].metricFindQuery = jest.fn(() => Promise.reject(error)); @@ -267,7 +215,7 @@ describe('query actions', () => { describe('when initQueryVariableEditor is dispatched', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const testMetricSource = { name: 'test', value: 'test', meta: {} }; const editor = {}; @@ -296,7 +244,7 @@ describe('query actions', () => { describe('when initQueryVariableEditor is dispatched and metricsource without value is available', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const testMetricSource = { name: 'test', value: (null as unknown) as string, meta: {} }; const editor = {}; @@ -325,7 +273,7 @@ describe('query actions', () => { describe('when initQueryVariableEditor is dispatched and no metric sources was found', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ includeAll: true, useTags: false }); + const variable = createVariable({ includeAll: true }); const editor = {}; mocks.dataSourceSrv.getList = jest.fn().mockReturnValue([]); @@ -433,13 +381,12 @@ describe('query actions', () => { describe('when changeQueryVariableQuery is dispatched', () => { it('then correct actions are dispatched', async () => { const optionsMetrics = [createMetric('A'), createMetric('B')]; - const tagsMetrics = [createMetric('tagA'), createMetric('tagB')]; - const variable = createVariable({ datasource: 'datasource', useTags: true, includeAll: true }); + const variable = createVariable({ datasource: 'datasource', includeAll: true }); const query = '$datasource'; const definition = 'depends on datasource variable'; - mockDatasourceMetrics({ ...variable, query }, optionsMetrics, tagsMetrics); + mockDatasourceMetrics({ ...variable, query }, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -455,7 +402,6 @@ describe('query actions', () => { changeVariableProp(toVariablePayload(variable, { propName: 'definition', propValue: definition })), variableStateFetching(toVariablePayload(variable)), updateVariableOptions(toVariablePayload(variable, update)), - updateVariableTags(toVariablePayload(variable, tagsMetrics)), setCurrentVariableValue(toVariablePayload(variable, { option })), variableStateCompleted(toVariablePayload(variable)) ); @@ -465,12 +411,12 @@ describe('query actions', () => { describe('when changeQueryVariableQuery is dispatched for variable without tags', () => { it('then correct actions are dispatched', async () => { const optionsMetrics = [createMetric('A'), createMetric('B')]; - const variable = createVariable({ datasource: 'datasource', useTags: false, includeAll: true }); + const variable = createVariable({ datasource: 'datasource', includeAll: true }); const query = '$datasource'; const definition = 'depends on datasource variable'; - mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []); + mockDatasourceMetrics({ ...variable, query }, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -495,11 +441,11 @@ describe('query actions', () => { describe('when changeQueryVariableQuery is dispatched for variable without tags and all', () => { it('then correct actions are dispatched', async () => { const optionsMetrics = [createMetric('A'), createMetric('B')]; - const variable = createVariable({ datasource: 'datasource', useTags: false, includeAll: false }); + const variable = createVariable({ datasource: 'datasource', includeAll: false }); const query = '$datasource'; const definition = 'depends on datasource variable'; - mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []); + mockDatasourceMetrics({ ...variable, query }, optionsMetrics); const tester = await reduxTester() .givenRootReducer(getRootReducer()) @@ -523,7 +469,7 @@ describe('query actions', () => { describe('when changeQueryVariableQuery is dispatched with invalid query', () => { it('then correct actions are dispatched', async () => { - const variable = createVariable({ datasource: 'datasource', useTags: false, includeAll: false }); + const variable = createVariable({ datasource: 'datasource', includeAll: false }); const query = `$${variable.name}`; const definition = 'depends on datasource variable'; @@ -701,10 +647,9 @@ describe('query actions', () => { }); }); -function mockDatasourceMetrics(variable: QueryVariableModel, optionsMetrics: any[], tagsMetrics: any[]) { +function mockDatasourceMetrics(variable: QueryVariableModel, optionsMetrics: any[]) { const metrics: Record = { [variable.query]: optionsMetrics, - [variable.tagsQuery]: tagsMetrics, }; const { metricFindQuery } = mocks[variable.datasource!]; @@ -729,10 +674,6 @@ function createVariable(extend?: Partial): QueryVariableMode datasource: 'datasource', definition: '', sort: VariableSort.alphabeticalAsc, - tags: [], - tagsQuery: 'tags-query', - tagValuesQuery: '', - useTags: true, refresh: VariableRefresh.onDashboardLoad, regex: '', multi: true, diff --git a/public/app/features/variables/query/operators.test.ts b/public/app/features/variables/query/operators.test.ts index 91f13775402..fa7eba38e49 100644 --- a/public/app/features/variables/query/operators.test.ts +++ b/public/app/features/variables/query/operators.test.ts @@ -1,17 +1,8 @@ import { of } from 'rxjs'; import { queryBuilder } from '../shared/testing/builders'; import { FieldType, toDataFrame } from '@grafana/data'; -import { initialQueryVariableModelState, updateVariableOptions, updateVariableTags } from './reducer'; -import { toVariablePayload } from '../state/types'; -import { VariableRefresh } from '../types'; -import { - areMetricFindValues, - runUpdateTagsRequest, - toMetricFindValues, - updateOptionsState, - updateTagsState, - validateVariableSelection, -} from './operators'; +import { updateVariableOptions } from './reducer'; +import { areMetricFindValues, toMetricFindValues, updateOptionsState, validateVariableSelection } from './operators'; describe('operators', () => { beforeEach(() => { @@ -33,122 +24,6 @@ describe('operators', () => { }); }); - describe('updateTagsState', () => { - describe('when called with a variable that uses Tags', () => { - it('then the correct observable should be created', async () => { - const variable = queryBuilder().withId('query').withTags(true).build(); - const dispatch = jest.fn().mockResolvedValue({}); - const observable = of([{ text: 'A text' }]).pipe(updateTagsState({ variable, dispatch })); - - await expect(observable).toEmitValuesWith((received) => { - const value = received[0]; - expect(value).toEqual(undefined); - expect(dispatch).toHaveBeenCalledTimes(1); - expect(dispatch).toHaveBeenCalledWith(updateVariableTags(toVariablePayload(variable, [{ text: 'A text' }]))); - }); - }); - }); - - describe('when called with a variable that does not use Tags', () => { - it('then the correct observable should be created', async () => { - const variable = queryBuilder().withId('query').withTags(false).build(); - const dispatch = jest.fn().mockResolvedValue({}); - const observable = of([{ text: 'A text' }]).pipe(updateTagsState({ variable, dispatch })); - - await expect(observable).toEmitValuesWith((received) => { - const value = received[0]; - expect(value).toEqual(undefined); - expect(dispatch).not.toHaveBeenCalled(); - }); - }); - }); - }); - - describe('runUpdateTagsRequest', () => { - describe('when called with a datasource with metricFindQuery and variable that uses Tags and refreshes on time range changes', () => { - it('then the correct observable should be created', async () => { - const variable = queryBuilder() - .withId('query') - .withTags(true) - .withTagsQuery('A tags query') - .withRefresh(VariableRefresh.onTimeRangeChanged) - .build(); - const timeSrv: any = { - timeRange: jest.fn(), - }; - const datasource: any = { metricFindQuery: jest.fn().mockResolvedValue([{ text: 'A text' }]) }; - const searchFilter = 'A search filter'; - const observable = of(undefined).pipe(runUpdateTagsRequest({ variable, datasource, searchFilter }, timeSrv)); - - await expect(observable).toEmitValuesWith((received) => { - const value = received[0]; - const { index, global, ...rest } = initialQueryVariableModelState; - expect(value).toEqual([{ text: 'A text' }]); - expect(timeSrv.timeRange).toHaveBeenCalledTimes(1); - expect(datasource.metricFindQuery).toHaveBeenCalledTimes(1); - expect(datasource.metricFindQuery).toHaveBeenCalledWith('A tags query', { - range: undefined, - searchFilter: 'A search filter', - variable: { - ...rest, - id: 'query', - name: 'query', - useTags: true, - tagsQuery: 'A tags query', - refresh: VariableRefresh.onTimeRangeChanged, - }, - }); - }); - }); - }); - - describe('when called with a datasource without metricFindQuery and variable that uses Tags and refreshes on time range changes', () => { - it('then the correct observable should be created', async () => { - const variable = queryBuilder() - .withId('query') - .withTags(true) - .withTagsQuery('A tags query') - .withRefresh(VariableRefresh.onTimeRangeChanged) - .build(); - const timeSrv: any = { - timeRange: jest.fn(), - }; - const datasource: any = {}; - const searchFilter = 'A search filter'; - const observable = of(undefined).pipe(runUpdateTagsRequest({ variable, datasource, searchFilter }, timeSrv)); - - await expect(observable).toEmitValuesWith((received) => { - const value = received[0]; - expect(value).toEqual([]); - expect(timeSrv.timeRange).not.toHaveBeenCalled(); - }); - }); - }); - - describe('when called with a datasource with metricFindQuery and variable that does not use Tags but refreshes on time range changes', () => { - it('then the correct observable should be created', async () => { - const variable = queryBuilder() - .withId('query') - .withTags(false) - .withRefresh(VariableRefresh.onTimeRangeChanged) - .build(); - const timeSrv: any = { - timeRange: jest.fn(), - }; - const datasource: any = { metricFindQuery: jest.fn().mockResolvedValue([{ text: 'A text' }]) }; - const searchFilter = 'A search filter'; - const observable = of(undefined).pipe(runUpdateTagsRequest({ variable, datasource, searchFilter }, timeSrv)); - - await expect(observable).toEmitValuesWith((received) => { - const value = received[0]; - expect(value).toEqual([]); - expect(timeSrv.timeRange).not.toHaveBeenCalled(); - expect(datasource.metricFindQuery).not.toHaveBeenCalled(); - }); - }); - }); - }); - describe('updateOptionsState', () => { describe('when called', () => { it('then the correct observable should be created', async () => { diff --git a/public/app/features/variables/query/operators.ts b/public/app/features/variables/query/operators.ts index 1bb5df26302..3f57960c529 100644 --- a/public/app/features/variables/query/operators.ts +++ b/public/app/features/variables/query/operators.ts @@ -5,10 +5,9 @@ import { QueryVariableModel } from '../types'; import { ThunkDispatch } from '../../../types'; import { toVariableIdentifier, toVariablePayload } from '../state/types'; import { validateVariableSelectionState } from '../state/actions'; -import { DataSourceApi, FieldType, getFieldDisplayName, isDataFrame, MetricFindValue, PanelData } from '@grafana/data'; -import { updateVariableOptions, updateVariableTags } from './reducer'; -import { getTimeSrv, TimeSrv } from '../../dashboard/services/TimeSrv'; -import { getLegacyQueryOptions, getTemplatedRegex } from '../utils'; +import { FieldType, getFieldDisplayName, isDataFrame, MetricFindValue, PanelData } from '@grafana/data'; +import { updateVariableOptions } from './reducer'; +import { getTemplatedRegex } from '../utils'; import { getProcessedDataFrames } from 'app/features/query/state/runRequest'; export function toMetricFindValues(): OperatorFunction { @@ -110,46 +109,6 @@ export function updateOptionsState(args: { ); } -export function runUpdateTagsRequest( - args: { - variable: QueryVariableModel; - datasource: DataSourceApi; - searchFilter?: string; - }, - timeSrv: TimeSrv = getTimeSrv() -): OperatorFunction { - return (source) => - source.pipe( - mergeMap(() => { - const { datasource, searchFilter, variable } = args; - - if (variable.useTags && datasource.metricFindQuery) { - return from( - datasource.metricFindQuery(variable.tagsQuery, getLegacyQueryOptions(variable, searchFilter, timeSrv)) - ); - } - - return of([]); - }) - ); -} - -export function updateTagsState(args: { - variable: QueryVariableModel; - dispatch: ThunkDispatch; -}): OperatorFunction { - return (source) => - source.pipe( - map((tagResults) => { - const { dispatch, variable } = args; - - if (variable.useTags) { - dispatch(updateVariableTags(toVariablePayload(variable, tagResults))); - } - }) - ); -} - export function validateVariableSelection(args: { variable: QueryVariableModel; dispatch: ThunkDispatch; diff --git a/public/app/features/variables/query/reducer.test.ts b/public/app/features/variables/query/reducer.test.ts index 2721366238c..ed1e9d25473 100644 --- a/public/app/features/variables/query/reducer.test.ts +++ b/public/app/features/variables/query/reducer.test.ts @@ -4,7 +4,6 @@ import { queryVariableReducer, sortVariableValues, updateVariableOptions, - updateVariableTags, } from './reducer'; import { QueryVariableModel, VariableSort } from '../types'; import { cloneDeep } from 'lodash'; @@ -261,27 +260,6 @@ describe('queryVariableReducer', () => { }); }); }); - - describe('when updateVariableTags is dispatched', () => { - it('then state should be correct', () => { - const { initialState } = getVariableTestContext(adapter); - const tags: any[] = [{ text: 'A' }, { text: 'B' }]; - const payload = toVariablePayload({ id: '0', type: 'query' }, tags); - reducerTester() - .givenReducer(queryVariableReducer, cloneDeep(initialState)) - .whenActionIsDispatched(updateVariableTags(payload)) - .thenStateShouldEqual({ - ...initialState, - '0': ({ - ...initialState[0], - tags: [ - { text: 'A', selected: false }, - { text: 'B', selected: false }, - ], - } as unknown) as QueryVariableModel, - }); - }); - }); }); describe('sortVariableValues', () => { diff --git a/public/app/features/variables/query/reducer.ts b/public/app/features/variables/query/reducer.ts index 00c794026ba..15de292d73e 100644 --- a/public/app/features/variables/query/reducer.ts +++ b/public/app/features/variables/query/reducer.ts @@ -9,17 +9,16 @@ import { VariableQueryEditorType, VariableRefresh, VariableSort, - VariableTag, } from '../types'; import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, getInstanceState, + initialVariablesState, NONE_VARIABLE_TEXT, NONE_VARIABLE_VALUE, VariablePayload, - initialVariablesState, VariablesState, } from '../state/types'; @@ -46,10 +45,6 @@ export const initialQueryVariableModelState: QueryVariableModel = { allValue: null, options: [], current: {} as VariableOption, - tags: [], - useTags: false, - tagsQuery: '', - tagValuesQuery: '', definition: '', }; @@ -179,19 +174,9 @@ export const queryVariableSlice = createSlice({ instanceState.options = options; }, - updateVariableTags: (state: VariablesState, action: PayloadAction>) => { - const instanceState = getInstanceState(state, action.payload.id); - const results = action.payload.data; - const tags: VariableTag[] = []; - for (let i = 0; i < results.length; i++) { - tags.push({ text: results[i].text, selected: false }); - } - - instanceState.tags = tags; - }, }, }); export const queryVariableReducer = queryVariableSlice.reducer; -export const { updateVariableOptions, updateVariableTags } = queryVariableSlice.actions; +export const { updateVariableOptions } = queryVariableSlice.actions; diff --git a/public/app/features/variables/shared/formatVariable.ts b/public/app/features/variables/shared/formatVariable.ts index 162313eefe7..3cb47e741b2 100644 --- a/public/app/features/variables/shared/formatVariable.ts +++ b/public/app/features/variables/shared/formatVariable.ts @@ -6,41 +6,13 @@ export const formatVariableLabel = (variable: VariableModel) => { return variable.name; } - const { current, options = [] } = variable; + const { current } = variable; - if (!current.tags || current.tags.length === 0) { - if (Array.isArray(current.text)) { - return current.text.join(' + '); - } - return current.text; + if (Array.isArray(current.text)) { + return current.text.join(' + '); } - // filer out values that are in selected tags - const selectedAndNotInTag = options.filter((option) => { - if (!option.selected) { - return false; - } - - if (!current || !current.tags || !current.tags.length) { - return false; - } - - for (let i = 0; i < current.tags.length; i++) { - const tag = current.tags[i]; - const foundIndex = tag?.values?.findIndex((v) => v === option.value); - if (foundIndex && foundIndex !== -1) { - return false; - } - } - return true; - }); - - // convert values to text - const currentTexts = selectedAndNotInTag.map((s) => s.text); - - // join texts - const newLinkText = currentTexts.join(' + '); - return newLinkText.length > 0 ? `${newLinkText} + ` : newLinkText; + return current.text; }; const isVariableWithOptions = (variable: VariableModel): variable is VariableWithOptions => { diff --git a/public/app/features/variables/shared/testing/queryVariableBuilder.ts b/public/app/features/variables/shared/testing/queryVariableBuilder.ts index a12fb583f37..530e152a2f3 100644 --- a/public/app/features/variables/shared/testing/queryVariableBuilder.ts +++ b/public/app/features/variables/shared/testing/queryVariableBuilder.ts @@ -2,16 +2,6 @@ import { QueryVariableModel } from 'app/features/variables/types'; import { DatasourceVariableBuilder } from './datasourceVariableBuilder'; export class QueryVariableBuilder extends DatasourceVariableBuilder { - withTags(useTags: boolean) { - this.variable.useTags = useTags; - return this; - } - - withTagsQuery(tagsQuery: string) { - this.variable.tagsQuery = tagsQuery; - return this; - } - withDatasource(datasource: string) { this.variable.datasource = datasource; return this; diff --git a/public/app/features/variables/state/sharedReducer.ts b/public/app/features/variables/state/sharedReducer.ts index 7958d68128c..b6fb2a5b25a 100644 --- a/public/app/features/variables/state/sharedReducer.ts +++ b/public/app/features/variables/state/sharedReducer.ts @@ -1,11 +1,10 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { defaults as lodashDefaults, cloneDeep } from 'lodash'; +import { cloneDeep, defaults as lodashDefaults } from 'lodash'; import { LoadingState, VariableType } from '@grafana/data'; import { VariableModel, VariableOption, VariableWithOptions } from '../types'; -import { AddVariable, getInstanceState, VariablePayload, initialVariablesState, VariablesState } from './types'; +import { AddVariable, getInstanceState, initialVariablesState, VariablePayload, VariablesState } from './types'; import { variableAdapters } from '../adapters'; import { changeVariableNameSucceeded } from '../editor/reducer'; -import { isQuery } from '../guard'; import { ensureStringValues } from '../utils'; const sharedReducerSlice = createSlice({ @@ -140,19 +139,6 @@ const sharedReducerSlice = createSlice({ option.selected = selected; return option; }); - - if (hasTags(current) && isQuery(instanceState)) { - const selected = current!.tags!.reduce((all: Record, tag) => { - all[tag.text.toString()] = tag.selected; - return all; - }, {}); - - instanceState.tags = instanceState.tags.map((t) => { - const text = t.text.toString(); - t.selected = selected[text]; - return t; - }); - } }, changeVariableProp: ( state: VariablesState, @@ -184,7 +170,3 @@ export const { variableStateCompleted, variableStateFailed, } = sharedReducerSlice.actions; - -const hasTags = (option: VariableOption): boolean => { - return Array.isArray(option.tags); -}; diff --git a/public/app/features/variables/types.ts b/public/app/features/variables/types.ts index 2e3c916f62a..b75eb77eac1 100644 --- a/public/app/features/variables/types.ts +++ b/public/app/features/variables/types.ts @@ -33,19 +33,11 @@ export enum VariableSort { alphabeticalCaseInsensitiveDesc, } -export interface VariableTag { - selected: boolean; - text: string | string[]; - values?: any[]; - valuesText?: string; -} - export interface VariableOption { selected: boolean; text: string | string[]; value: string | string[]; isNone?: boolean; - tags?: VariableTag[]; } export interface AdHocVariableFilter { @@ -78,10 +70,6 @@ export interface QueryVariableModel extends DataSourceVariableModel { datasource: string | null; definition: string; sort: VariableSort; - tags: VariableTag[]; - tagsQuery: string; - tagValuesQuery: string; - useTags: boolean; queryValue?: string; query: any; }