mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboards: Add template variables to selectable options (#75870)
This commit is contained in:
parent
c5914d92d4
commit
b2ba28ab40
@ -1,8 +1,9 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { initTemplateSrv } from 'test/helpers/initTemplateSrv';
|
||||||
|
|
||||||
import { FetchError } from '@grafana/runtime';
|
import { FetchError, setTemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
|
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
|
||||||
import { TempoDatasource } from '../datasource';
|
import { TempoDatasource } from '../datasource';
|
||||||
@ -35,9 +36,11 @@ jest.mock('../language_provider', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('SearchField', () => {
|
describe('SearchField', () => {
|
||||||
|
let templateSrv = initTemplateSrv('key', [{ name: 'templateVariable1' }, { name: 'templateVariable2' }]);
|
||||||
let user: ReturnType<typeof userEvent.setup>;
|
let user: ReturnType<typeof userEvent.setup>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
setTemplateSrv(templateSrv);
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
// Need to use delay: null here to work with fakeTimers
|
// Need to use delay: null here to work with fakeTimers
|
||||||
// see https://github.com/testing-library/user-event/issues/833
|
// see https://github.com/testing-library/user-event/issues/833
|
||||||
@ -172,6 +175,8 @@ describe('SearchField', () => {
|
|||||||
expect(await screen.findByText('span')).toBeInTheDocument();
|
expect(await screen.findByText('span')).toBeInTheDocument();
|
||||||
expect(await screen.findByText('unscoped')).toBeInTheDocument();
|
expect(await screen.findByText('unscoped')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('intrinsic')).not.toBeInTheDocument();
|
expect(screen.queryByText('intrinsic')).not.toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('$templateVariable1')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('$templateVariable2')).toBeInTheDocument();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,8 +3,9 @@ import { uniq } from 'lodash';
|
|||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
import useAsync from 'react-use/lib/useAsync';
|
import useAsync from 'react-use/lib/useAsync';
|
||||||
|
|
||||||
|
import { SelectableValue } from '@grafana/data';
|
||||||
import { AccessoryButton } from '@grafana/experimental';
|
import { AccessoryButton } from '@grafana/experimental';
|
||||||
import { FetchError, isFetchError } from '@grafana/runtime';
|
import { FetchError, getTemplateSrv, isFetchError } from '@grafana/runtime';
|
||||||
import { Select, HorizontalGroup, useStyles2 } from '@grafana/ui';
|
import { Select, HorizontalGroup, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { createErrorNotification } from '../../../../core/copy/appNotification';
|
import { createErrorNotification } from '../../../../core/copy/appNotification';
|
||||||
@ -112,13 +113,24 @@ const SearchField = ({
|
|||||||
operatorList = numberOperators;
|
operatorList = numberOperators;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add to a list of options the current template variables.
|
||||||
|
*
|
||||||
|
* @param options a list of options
|
||||||
|
* @returns the list of given options plus the template variables
|
||||||
|
*/
|
||||||
|
const withTemplateVariableOptions = (options: SelectableValue[] | undefined) => {
|
||||||
|
const templateVariables = getTemplateSrv().getVariables();
|
||||||
|
return [...(options || []), ...templateVariables.map((v) => ({ label: `$${v.name}`, value: `$${v.name}` }))];
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HorizontalGroup spacing={'none'} width={'auto'}>
|
<HorizontalGroup spacing={'none'} width={'auto'}>
|
||||||
{!hideScope && (
|
{!hideScope && (
|
||||||
<Select
|
<Select
|
||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
inputId={`${filter.id}-scope`}
|
inputId={`${filter.id}-scope`}
|
||||||
options={scopeOptions}
|
options={withTemplateVariableOptions(scopeOptions)}
|
||||||
value={filter.scope}
|
value={filter.scope}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
updateFilter({ ...filter, scope: v?.value });
|
updateFilter({ ...filter, scope: v?.value });
|
||||||
@ -133,10 +145,12 @@ const SearchField = ({
|
|||||||
inputId={`${filter.id}-tag`}
|
inputId={`${filter.id}-tag`}
|
||||||
isLoading={isTagsLoading}
|
isLoading={isTagsLoading}
|
||||||
// Add the current tag to the list if it doesn't exist in the tags prop, otherwise the field will be empty even though the state has a value
|
// Add the current tag to the list if it doesn't exist in the tags prop, otherwise the field will be empty even though the state has a value
|
||||||
options={(filter.tag !== undefined ? uniq([filter.tag, ...tags]) : tags).map((t) => ({
|
options={withTemplateVariableOptions(
|
||||||
|
(filter.tag !== undefined ? uniq([filter.tag, ...tags]) : tags).map((t) => ({
|
||||||
label: t,
|
label: t,
|
||||||
value: t,
|
value: t,
|
||||||
}))}
|
}))
|
||||||
|
)}
|
||||||
value={filter.tag}
|
value={filter.tag}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
updateFilter({ ...filter, tag: v?.value });
|
updateFilter({ ...filter, tag: v?.value });
|
||||||
@ -150,7 +164,7 @@ const SearchField = ({
|
|||||||
<Select
|
<Select
|
||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
inputId={`${filter.id}-operator`}
|
inputId={`${filter.id}-operator`}
|
||||||
options={operatorList.map(operatorSelectableValue)}
|
options={withTemplateVariableOptions(operatorList.map(operatorSelectableValue))}
|
||||||
value={filter.operator}
|
value={filter.operator}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
updateFilter({ ...filter, operator: v?.value });
|
updateFilter({ ...filter, operator: v?.value });
|
||||||
@ -165,7 +179,7 @@ const SearchField = ({
|
|||||||
className={styles.dropdown}
|
className={styles.dropdown}
|
||||||
inputId={`${filter.id}-value`}
|
inputId={`${filter.id}-value`}
|
||||||
isLoading={isLoadingValues}
|
isLoading={isLoadingValues}
|
||||||
options={options}
|
options={withTemplateVariableOptions(options)}
|
||||||
value={filter.value}
|
value={filter.value}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
if (Array.isArray(val)) {
|
if (Array.isArray(val)) {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { render, screen, waitFor } from '@testing-library/react';
|
import { render, screen, waitFor } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { initTemplateSrv } from 'test/helpers/initTemplateSrv';
|
||||||
|
|
||||||
import { FetchError } from '@grafana/runtime';
|
import { FetchError, setTemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
|
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
|
||||||
import { TempoDatasource } from '../datasource';
|
import { TempoDatasource } from '../datasource';
|
||||||
@ -13,9 +14,11 @@ import TagsInput from './TagsInput';
|
|||||||
import { v1Tags, v2Tags } from './utils.test';
|
import { v1Tags, v2Tags } from './utils.test';
|
||||||
|
|
||||||
describe('TagsInput', () => {
|
describe('TagsInput', () => {
|
||||||
|
let templateSrv = initTemplateSrv('key', [{ name: 'templateVariable1' }, { name: 'templateVariable2' }]);
|
||||||
let user: ReturnType<typeof userEvent.setup>;
|
let user: ReturnType<typeof userEvent.setup>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
setTemplateSrv(templateSrv);
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
// Need to use delay: null here to work with fakeTimers
|
// Need to use delay: null here to work with fakeTimers
|
||||||
// see https://github.com/testing-library/user-event/issues/833
|
// see https://github.com/testing-library/user-event/issues/833
|
||||||
@ -37,6 +40,8 @@ describe('TagsInput', () => {
|
|||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByText('foo')).toBeInTheDocument();
|
expect(screen.getByText('foo')).toBeInTheDocument();
|
||||||
expect(screen.getByText('bar')).toBeInTheDocument();
|
expect(screen.getByText('bar')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable2')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,6 +55,8 @@ describe('TagsInput', () => {
|
|||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByText('cluster')).toBeInTheDocument();
|
expect(screen.getByText('cluster')).toBeInTheDocument();
|
||||||
expect(screen.getByText('container')).toBeInTheDocument();
|
expect(screen.getByText('container')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable2')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -62,6 +69,8 @@ describe('TagsInput', () => {
|
|||||||
jest.advanceTimersByTime(1000);
|
jest.advanceTimersByTime(1000);
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByText('db')).toBeInTheDocument();
|
expect(screen.getByText('db')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable2')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,6 +85,8 @@ describe('TagsInput', () => {
|
|||||||
expect(screen.getByText('cluster')).toBeInTheDocument();
|
expect(screen.getByText('cluster')).toBeInTheDocument();
|
||||||
expect(screen.getByText('container')).toBeInTheDocument();
|
expect(screen.getByText('container')).toBeInTheDocument();
|
||||||
expect(screen.getByText('db')).toBeInTheDocument();
|
expect(screen.getByText('db')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('$templateVariable2')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user