Tempo: Group by template vars (#86022)

* Add template variables to group by field

* Add test for interpolation

* Add test to allow selecting template vars

* Show custom value
This commit is contained in:
Joey 2024-04-18 08:52:51 +01:00 committed by GitHub
parent 9614126cb7
commit 306cea7350
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 66 additions and 15 deletions

View File

@ -5,6 +5,7 @@ import React, { useState } from 'react';
import { TraceqlSearchScope } from '../dataquery.gen'; import { TraceqlSearchScope } from '../dataquery.gen';
import { TempoDatasource } from '../datasource'; import { TempoDatasource } from '../datasource';
import TempoLanguageProvider from '../language_provider'; import TempoLanguageProvider from '../language_provider';
import { initTemplateSrv } from '../test_utils';
import { TempoQuery } from '../types'; import { TempoQuery } from '../types';
import { GroupByField } from './GroupByField'; import { GroupByField } from './GroupByField';
@ -40,6 +41,8 @@ describe('GroupByField', () => {
// 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
user = userEvent.setup({ delay: null }); user = userEvent.setup({ delay: null });
initTemplateSrv([{ name: 'templateVariable1' }, { name: 'templateVariable2' }], {});
}); });
afterEach(() => { afterEach(() => {
@ -132,4 +135,21 @@ describe('GroupByField', () => {
expect(groupByFilter?.tag).toBe('http.method'); expect(groupByFilter?.tag).toBe('http.method');
} }
}); });
it('should allow selecting template variables', async () => {
const { container } = render(
<GroupByField datasource={datasource} query={query} onChange={onChange} isTagsLoading={false} />
);
const tagSelect = container.querySelector(`input[aria-label="Select tag for filter 1"]`);
expect(tagSelect).not.toBeNull();
expect(tagSelect).toBeInTheDocument();
if (tagSelect) {
await user.click(tagSelect);
jest.advanceTimersByTime(1000);
expect(await screen.findByText('$templateVariable1')).toBeInTheDocument();
expect(await screen.findByText('$templateVariable2')).toBeInTheDocument();
}
});
}); });

View File

@ -11,6 +11,7 @@ import { TempoDatasource } from '../datasource';
import { TempoQuery } from '../types'; import { TempoQuery } from '../types';
import InlineSearchField from './InlineSearchField'; import InlineSearchField from './InlineSearchField';
import { withTemplateVariableOptions } from './SearchField';
import { replaceAt } from './utils'; import { replaceAt } from './utils';
interface Props { interface Props {
@ -89,15 +90,20 @@ export const GroupByField = (props: Props) => {
<Select <Select
aria-label={`Select tag for filter ${i + 1}`} aria-label={`Select tag for filter ${i + 1}`}
isClearable isClearable
allowCustomValue
isLoading={isTagsLoading} isLoading={isTagsLoading}
key={f.tag} key={f.tag}
onChange={(v) => { onChange={(v) => {
updateFilter({ ...f, tag: v?.value }); updateFilter({ ...f, tag: v?.value });
}} }}
options={getTags(f)?.map((t) => ({ options={withTemplateVariableOptions(
label: t, getTags(f)
value: t, ?.concat(f.tag !== undefined && !getTags(f)?.includes(f.tag) ? [f.tag] : [])
}))} .map((t) => ({
label: t,
value: t,
}))
)}
placeholder="Select tag" placeholder="Select tag"
value={f.tag || ''} value={f.tag || ''}
/> />

View File

@ -126,17 +126,6 @@ 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'}>
@ -220,4 +209,15 @@ const SearchField = ({
); );
}; };
/**
* 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
*/
export const withTemplateVariableOptions = (options: SelectableValue[] | undefined) => {
const templateVariables = getTemplateSrv().getVariables();
return [...(options || []), ...templateVariables.map((v) => ({ label: `$${v.name}`, value: `$${v.name}` }))];
};
export default SearchField; export default SearchField;

View File

@ -170,6 +170,16 @@ describe('Tempo data source', () => {
valueType: 'string', valueType: 'string',
}, },
], ],
groupBy: [
{
id: 'groupBy1',
tag: '$interpolationVar',
},
{
id: 'groupBy2',
tag: '$interpolationVar',
},
],
}; };
} }
let templateSrv: TemplateSrv; let templateSrv: TemplateSrv;
@ -202,6 +212,8 @@ describe('Tempo data source', () => {
expect(queries[0].filters[0].value).toBe(textWithPipe); expect(queries[0].filters[0].value).toBe(textWithPipe);
expect(queries[0].filters[1].value).toBe(text); expect(queries[0].filters[1].value).toBe(text);
expect(queries[0].filters[1].tag).toBe(text); expect(queries[0].filters[1].tag).toBe(text);
expect(queries[0].groupBy?.[0].tag).toBe(text);
expect(queries[0].groupBy?.[1].tag).toBe(text);
}); });
it('when applying template variables', async () => { it('when applying template variables', async () => {
@ -214,6 +226,8 @@ describe('Tempo data source', () => {
expect(resp.filters[0].value).toBe(textWithPipe); expect(resp.filters[0].value).toBe(textWithPipe);
expect(resp.filters[1].value).toBe(scopedText); expect(resp.filters[1].value).toBe(scopedText);
expect(resp.filters[1].tag).toBe(scopedText); expect(resp.filters[1].tag).toBe(scopedText);
expect(resp.groupBy?.[0].tag).toBe(scopedText);
expect(resp.groupBy?.[1].tag).toBe(scopedText);
}); });
it('when serviceMapQuery is an array', async () => { it('when serviceMapQuery is an array', async () => {

View File

@ -486,6 +486,17 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
}); });
} }
if (query.groupBy) {
expandedQuery.groupBy = query.groupBy.map((filter) => {
const updatedFilter = {
...filter,
tag: this.templateSrv.replace(filter.tag ?? '', scopedVars),
};
return updatedFilter;
});
}
return { return {
...expandedQuery, ...expandedQuery,
query: this.templateSrv.replace(query.query ?? '', scopedVars, VariableFormatID.Pipe), query: this.templateSrv.replace(query.query ?? '', scopedVars, VariableFormatID.Pipe),