Tempo: Add support for ad-hoc filters (#102448)
* Add support for ad-hoc filters * Handle enum tags when using ad hoc filters
This commit is contained in:
@@ -64,7 +64,9 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app, addVa
|
||||
|
||||
const templateVariables = getTemplateSrv().getVariables();
|
||||
useEffect(() => {
|
||||
setTraceQlQuery(datasource.languageProvider.generateQueryFromFilters(interpolateFilters(query.filters || [])));
|
||||
setTraceQlQuery(
|
||||
datasource.languageProvider.generateQueryFromFilters({ traceqlFilters: interpolateFilters(query.filters || []) })
|
||||
);
|
||||
}, [datasource.languageProvider, query, templateVariables]);
|
||||
|
||||
const findFilter = useCallback((id: string) => query.filters?.find((f) => f.id === id), [query.filters]);
|
||||
@@ -123,7 +125,9 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app, addVa
|
||||
return traceQlQuery;
|
||||
}
|
||||
const filtersAfterRemoval = query.filters?.filter((f) => f.id !== filter.id) || [];
|
||||
return datasource.languageProvider.generateQueryFromFilters(interpolateFilters(filtersAfterRemoval || []));
|
||||
return datasource.languageProvider.generateQueryFromFilters({
|
||||
traceqlFilters: interpolateFilters(filtersAfterRemoval || []),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -260,7 +264,9 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app, addVa
|
||||
});
|
||||
|
||||
onClearResults();
|
||||
const traceQlQuery = datasource.languageProvider.generateQueryFromFilters(query.filters || []);
|
||||
const traceQlQuery = datasource.languageProvider.generateQueryFromFilters({
|
||||
traceqlFilters: query.filters || [],
|
||||
});
|
||||
onChange({
|
||||
...query,
|
||||
query: traceQlQuery,
|
||||
|
||||
@@ -7,7 +7,6 @@ import { intrinsics } from '../traceql/traceql';
|
||||
|
||||
import {
|
||||
filterToQuerySection,
|
||||
generateQueryFromAdHocFilters,
|
||||
getAllTags,
|
||||
getFilteredTags,
|
||||
getIntrinsicTags,
|
||||
@@ -22,34 +21,6 @@ const datasource: TempoDatasource = {
|
||||
} as unknown as TempoDatasource;
|
||||
const lp = new TempoLanguageProvider(datasource);
|
||||
|
||||
describe('generateQueryFromAdHocFilters generates the correct query for', () => {
|
||||
it('an empty array', () => {
|
||||
expect(generateQueryFromAdHocFilters([], lp)).toBe('{}');
|
||||
});
|
||||
|
||||
it('a filter with values', () => {
|
||||
expect(generateQueryFromAdHocFilters([{ key: 'footag', operator: '=', value: 'foovalue' }], lp)).toBe(
|
||||
'{footag="foovalue"}'
|
||||
);
|
||||
});
|
||||
|
||||
it('two filters with values', () => {
|
||||
expect(
|
||||
generateQueryFromAdHocFilters(
|
||||
[
|
||||
{ key: 'footag', operator: '=', value: 'foovalue' },
|
||||
{ key: 'bartag', operator: '=', value: '0' },
|
||||
],
|
||||
lp
|
||||
)
|
||||
).toBe('{footag="foovalue" && bartag=0}');
|
||||
});
|
||||
|
||||
it('a filter with intrinsic values', () => {
|
||||
expect(generateQueryFromAdHocFilters([{ key: 'kind', operator: '=', value: 'server' }], lp)).toBe('{kind=server}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('gets correct tags', () => {
|
||||
const datasource: TempoDatasource = {
|
||||
search: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { startCase, uniq } from 'lodash';
|
||||
|
||||
import { AdHocVariableFilter, ScopedVars, SelectableValue } from '@grafana/data';
|
||||
import { ScopedVars, SelectableValue } from '@grafana/data';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { VariableFormatID } from '@grafana/schema';
|
||||
|
||||
@@ -81,23 +81,6 @@ export const filterToQuerySection = (f: TraceqlFilter, filters: TraceqlFilter[],
|
||||
return `${scopeHelper(f, lp)}${tagHelper(f, filters)}${f.operator}${valueHelper(f)}`;
|
||||
};
|
||||
|
||||
export const generateQueryFromAdHocFilters = (filters: AdHocVariableFilter[], lp: TempoLanguageProvider) => {
|
||||
return `{${filters
|
||||
.filter((f) => f.key && f.operator && f.value)
|
||||
.map((f) => `${f.key}${f.operator}${adHocValueHelper(f, lp)}`)
|
||||
.join(' && ')}}`;
|
||||
};
|
||||
|
||||
const adHocValueHelper = (f: AdHocVariableFilter, lp: TempoLanguageProvider) => {
|
||||
if (lp.getIntrinsics().find((t) => t === f.key)) {
|
||||
return f.value;
|
||||
}
|
||||
if (parseInt(f.value, 10).toString() === f.value) {
|
||||
return f.value;
|
||||
}
|
||||
return `"${f.value}"`;
|
||||
};
|
||||
|
||||
export const getTagWithoutScope = (tag: string) => {
|
||||
return tag.replace(/^(event|instrumentation|link|resource|span)\./, '');
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
} from '@grafana/runtime';
|
||||
import { BarGaugeDisplayMode, TableCellDisplayMode, VariableFormatID } from '@grafana/schema';
|
||||
|
||||
import { generateQueryFromAdHocFilters, getTagWithoutScope, interpolateFilters } from './SearchTraceQLEditor/utils';
|
||||
import { getTagWithoutScope, interpolateFilters } from './SearchTraceQLEditor/utils';
|
||||
import { TempoVariableQuery, TempoVariableQueryType } from './VariableQueryEditor';
|
||||
import { PrometheusDatasource, PromQuery } from './_importedDependencies/datasources/prometheus/types';
|
||||
import { TagLimitOptions } from './configuration/TagLimitSettings';
|
||||
@@ -239,7 +239,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
||||
|
||||
// Allows to retrieve the list of tag values for ad-hoc filters
|
||||
getTagValues(options: DataSourceGetTagValuesOptions<TempoQuery>): Promise<Array<{ text: string }>> {
|
||||
const query = generateQueryFromAdHocFilters(options.filters, this.languageProvider);
|
||||
const query = this.languageProvider.generateQueryFromFilters({ adhocFilters: options.filters });
|
||||
return this.tagValuesQuery(options.key, query);
|
||||
}
|
||||
|
||||
@@ -418,7 +418,10 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
||||
const traceqlSearchTargets = targets.traceqlSearch;
|
||||
if (traceqlSearchTargets.length > 0) {
|
||||
const appliedQuery = this.applyVariables(traceqlSearchTargets[0], options.scopedVars);
|
||||
const queryFromFilters = this.languageProvider.generateQueryFromFilters(appliedQuery.filters);
|
||||
const queryFromFilters = this.languageProvider.generateQueryFromFilters({
|
||||
traceqlFilters: appliedQuery.filters,
|
||||
adhocFilters: options.filters,
|
||||
});
|
||||
|
||||
reportInteraction('grafana_traces_traceql_search_queried', {
|
||||
datasourceType: 'tempo',
|
||||
@@ -918,7 +921,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
|
||||
}
|
||||
|
||||
const appliedQuery = this.applyVariables(query, {});
|
||||
return this.languageProvider.generateQueryFromFilters(appliedQuery.filters);
|
||||
return this.languageProvider.generateQueryFromFilters({ traceqlFilters: appliedQuery.filters });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,143 +89,228 @@ describe('Language_provider', () => {
|
||||
});
|
||||
|
||||
it('an empty array', () => {
|
||||
expect(lp.generateQueryFromFilters([])).toBe('{}');
|
||||
expect(lp.generateQueryFromFilters({ traceqlFilters: [] })).toBe('{}');
|
||||
});
|
||||
|
||||
it('a field without value', () => {
|
||||
expect(lp.generateQueryFromFilters([{ id: 'foo', tag: 'footag', operator: '=' }])).toBe('{}');
|
||||
expect(lp.generateQueryFromFilters({ traceqlFilters: [{ id: 'foo', tag: 'footag', operator: '=' }] })).toBe('{}');
|
||||
});
|
||||
|
||||
it('a field with value but without tag', () => {
|
||||
expect(lp.generateQueryFromFilters([{ id: 'foo', value: 'foovalue', operator: '=' }])).toBe('{}');
|
||||
expect(lp.generateQueryFromFilters({ traceqlFilters: [{ id: 'foo', value: 'foovalue', operator: '=' }] })).toBe(
|
||||
'{}'
|
||||
);
|
||||
});
|
||||
|
||||
it('a field with value and tag but without operator', () => {
|
||||
expect(lp.generateQueryFromFilters([{ id: 'foo', tag: 'footag', value: 'foovalue' }])).toBe('{}');
|
||||
expect(lp.generateQueryFromFilters({ traceqlFilters: [{ id: 'foo', tag: 'footag', value: 'foovalue' }] })).toBe(
|
||||
'{}'
|
||||
);
|
||||
});
|
||||
|
||||
describe('generates correct query for duration when duration type', () => {
|
||||
it('not set', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'min-duration', operator: '>', valueType: 'duration', tag: 'duration', value: '100ms' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{ id: 'min-duration', operator: '>', valueType: 'duration', tag: 'duration', value: '100ms' },
|
||||
],
|
||||
})
|
||||
).toBe('{duration>100ms}');
|
||||
});
|
||||
it('set to span', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'min-duration', operator: '>', valueType: 'duration', tag: 'duration', value: '100ms' },
|
||||
{ id: 'duration-type', value: 'span' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{ id: 'min-duration', operator: '>', valueType: 'duration', tag: 'duration', value: '100ms' },
|
||||
{ id: 'duration-type', value: 'span' },
|
||||
],
|
||||
})
|
||||
).toBe('{duration>100ms}');
|
||||
});
|
||||
it('set to trace', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'min-duration', operator: '>', valueType: 'duration', tag: 'duration', value: '100ms' },
|
||||
{ id: 'duration-type', value: 'trace' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{ id: 'min-duration', operator: '>', valueType: 'duration', tag: 'duration', value: '100ms' },
|
||||
{ id: 'duration-type', value: 'trace' },
|
||||
],
|
||||
})
|
||||
).toBe('{traceDuration>100ms}');
|
||||
});
|
||||
});
|
||||
|
||||
it('a field with tag, operator and tag', () => {
|
||||
expect(lp.generateQueryFromFilters([{ id: 'foo', tag: 'footag', value: 'foovalue', operator: '=' }])).toBe(
|
||||
'{.footag=foovalue}'
|
||||
);
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'foo', tag: 'footag', value: 'foovalue', operator: '=', valueType: 'string' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [{ id: 'foo', tag: 'footag', value: 'foovalue', operator: '=' }],
|
||||
})
|
||||
).toBe('{.footag=foovalue}');
|
||||
expect(
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [{ id: 'foo', tag: 'footag', value: 'foovalue', operator: '=', valueType: 'string' }],
|
||||
})
|
||||
).toBe('{.footag="foovalue"}');
|
||||
});
|
||||
|
||||
it('a field with valueType as integer', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([{ id: 'foo', tag: 'footag', value: '1234', operator: '>', valueType: 'integer' }])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [{ id: 'foo', tag: 'footag', value: '1234', operator: '>', valueType: 'integer' }],
|
||||
})
|
||||
).toBe('{.footag>1234}');
|
||||
});
|
||||
it.each([['=~'], ['!~']])('a field with a regexp operator (%s)', (operator) => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{
|
||||
id: 'span-name',
|
||||
tag: 'name',
|
||||
operator,
|
||||
scope: TraceqlSearchScope.Span,
|
||||
value: ['api/v2/variants/by-upc/(?P<upc>[\\s\\S]*)/$'],
|
||||
valueType: 'string',
|
||||
},
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{
|
||||
id: 'span-name',
|
||||
tag: 'name',
|
||||
operator,
|
||||
scope: TraceqlSearchScope.Span,
|
||||
value: ['api/v2/variants/by-upc/(?P<upc>[\\s\\S]*)/$'],
|
||||
valueType: 'string',
|
||||
},
|
||||
],
|
||||
})
|
||||
).toBe(`{name${operator}"api/v2/variants/by-upc/\\\\(\\\\?P<upc>\\\\[\\\\\\\\s\\\\\\\\S\\\\]\\\\*\\\\)/\\\\$"}`);
|
||||
});
|
||||
it('two fields with everything filled in', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'foo', tag: 'footag', value: '1234', operator: '>=', valueType: 'integer' },
|
||||
{ id: 'bar', tag: 'bartag', value: 'barvalue', operator: '=', valueType: 'string' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{ id: 'foo', tag: 'footag', value: '1234', operator: '>=', valueType: 'integer' },
|
||||
{ id: 'bar', tag: 'bartag', value: 'barvalue', operator: '=', valueType: 'string' },
|
||||
],
|
||||
})
|
||||
).toBe('{.footag>=1234 && .bartag="barvalue"}');
|
||||
});
|
||||
it('two fields but one is missing a value', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'foo', tag: 'footag', value: '1234', operator: '>=', valueType: 'integer' },
|
||||
{ id: 'bar', tag: 'bartag', operator: '=', valueType: 'string' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{ id: 'foo', tag: 'footag', value: '1234', operator: '>=', valueType: 'integer' },
|
||||
{ id: 'bar', tag: 'bartag', operator: '=', valueType: 'string' },
|
||||
],
|
||||
})
|
||||
).toBe('{.footag>=1234}');
|
||||
});
|
||||
it('two fields but one is missing a value and the other a tag', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{ id: 'foo', value: '1234', operator: '>=', valueType: 'integer' },
|
||||
{ id: 'bar', tag: 'bartag', operator: '=', valueType: 'string' },
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{ id: 'foo', value: '1234', operator: '>=', valueType: 'integer' },
|
||||
{ id: 'bar', tag: 'bartag', operator: '=', valueType: 'string' },
|
||||
],
|
||||
})
|
||||
).toBe('{}');
|
||||
});
|
||||
it('scope is unscoped', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Unscoped,
|
||||
valueType: 'integer',
|
||||
},
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Unscoped,
|
||||
valueType: 'integer',
|
||||
},
|
||||
],
|
||||
})
|
||||
).toBe('{.footag>=1234}');
|
||||
});
|
||||
it('scope is span', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Span,
|
||||
valueType: 'integer',
|
||||
},
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Span,
|
||||
valueType: 'integer',
|
||||
},
|
||||
],
|
||||
})
|
||||
).toBe('{span.footag>=1234}');
|
||||
});
|
||||
it('scope is resource', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters([
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Resource,
|
||||
valueType: 'integer',
|
||||
},
|
||||
])
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Resource,
|
||||
valueType: 'integer',
|
||||
},
|
||||
],
|
||||
})
|
||||
).toBe('{resource.footag>=1234}');
|
||||
});
|
||||
describe('adhoc filters', () => {
|
||||
it('mixes adhoc filters with trace ql', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters({
|
||||
traceqlFilters: [
|
||||
{
|
||||
id: 'foo',
|
||||
tag: 'footag',
|
||||
value: '1234',
|
||||
operator: '>=',
|
||||
scope: TraceqlSearchScope.Resource,
|
||||
valueType: 'integer',
|
||||
},
|
||||
],
|
||||
adhocFilters: [
|
||||
{
|
||||
key: 'resource.name',
|
||||
operator: '=',
|
||||
value: 'foo',
|
||||
},
|
||||
],
|
||||
})
|
||||
).toBe('{resource.footag>=1234 && resource.name="foo"}');
|
||||
});
|
||||
it('an empty array', () => {
|
||||
expect(lp.generateQueryFromFilters({ adhocFilters: [] })).toBe('{}');
|
||||
});
|
||||
|
||||
it('a filter with values', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters({ adhocFilters: [{ key: 'footag', operator: '=', value: 'foovalue' }] })
|
||||
).toBe('{footag="foovalue"}');
|
||||
});
|
||||
|
||||
it('two filters with values', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters({
|
||||
adhocFilters: [
|
||||
{ key: 'footag', operator: '=', value: 'foovalue' },
|
||||
{ key: 'bartag', operator: '=', value: '0' },
|
||||
],
|
||||
})
|
||||
).toBe('{footag="foovalue" && bartag=0}');
|
||||
});
|
||||
|
||||
it('a filter with enum intrinsic values', () => {
|
||||
expect(lp.generateQueryFromFilters({ adhocFilters: [{ key: 'kind', operator: '=', value: 'server' }] })).toBe(
|
||||
'{kind=server}'
|
||||
);
|
||||
});
|
||||
|
||||
it('a filter with non-enum intrinsic values', () => {
|
||||
expect(
|
||||
lp.generateQueryFromFilters({ adhocFilters: [{ key: 'name', operator: '=', value: 'my-server' }] })
|
||||
).toBe('{name="my-server"}');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const setup = (tagsV1?: string[], tagsV2?: Scope[]) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LanguageProvider, SelectableValue } from '@grafana/data';
|
||||
import { AdHocVariableFilter, LanguageProvider, SelectableValue } from '@grafana/data';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { VariableFormatID } from '@grafana/schema';
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from './SearchTraceQLEditor/utils';
|
||||
import { TraceqlFilter, TraceqlSearchScope } from './dataquery.gen';
|
||||
import { TempoDatasource } from './datasource';
|
||||
import { intrinsicsV1 } from './traceql/traceql';
|
||||
import { enumIntrinsics, intrinsicsV1 } from './traceql/traceql';
|
||||
import { Scope } from './types';
|
||||
|
||||
// Limit maximum tags retrieved from the backend
|
||||
@@ -179,14 +179,48 @@ export default class TempoLanguageProvider extends LanguageProvider {
|
||||
return encodeURIComponent(encodeURIComponent(tag));
|
||||
};
|
||||
|
||||
generateQueryFromFilters(filters: TraceqlFilter[]) {
|
||||
generateQueryFromFilters({
|
||||
traceqlFilters,
|
||||
adhocFilters,
|
||||
}: {
|
||||
traceqlFilters?: TraceqlFilter[];
|
||||
adhocFilters?: AdHocVariableFilter[];
|
||||
}) {
|
||||
if (!traceqlFilters && !adhocFilters) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const allFilters = [
|
||||
...this.generateQueryFromTraceQlFilters(traceqlFilters || []),
|
||||
...this.generateQueryFromAdHocFilters(adhocFilters || []),
|
||||
];
|
||||
|
||||
return `{${allFilters.join(' && ')}}`;
|
||||
}
|
||||
|
||||
private generateQueryFromTraceQlFilters(filters: TraceqlFilter[]) {
|
||||
if (!filters) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `{${filters
|
||||
return filters
|
||||
.filter((f) => f.tag && f.operator && f.value?.length)
|
||||
.map((f) => filterToQuerySection(f, filters, this))
|
||||
.join(' && ')}}`;
|
||||
.map((f) => filterToQuerySection(f, filters, this));
|
||||
}
|
||||
|
||||
private generateQueryFromAdHocFilters = (filters: AdHocVariableFilter[]) => {
|
||||
return filters
|
||||
.filter((f) => f.key && f.operator && f.value)
|
||||
.map((f) => `${f.key}${f.operator}${this.adHocValueHelper(f)}`);
|
||||
};
|
||||
|
||||
adHocValueHelper = (f: AdHocVariableFilter) => {
|
||||
if (this.getIntrinsics().find((t) => t === f.key) && enumIntrinsics.includes(f.key)) {
|
||||
return f.value;
|
||||
}
|
||||
if (parseInt(f.value, 10).toString() === f.value) {
|
||||
return f.value;
|
||||
}
|
||||
return `"${f.value}"`;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ export function QueryEditor(props: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const query = defaults(props.query, defaultQuery);
|
||||
const [showCopyFromSearchButton, setShowCopyFromSearchButton] = useState(() => {
|
||||
const genQuery = props.datasource.languageProvider.generateQueryFromFilters(query.filters || []);
|
||||
const genQuery = props.datasource.languageProvider.generateQueryFromFilters({
|
||||
traceqlFilters: query.filters || [],
|
||||
});
|
||||
return genQuery === query.query || genQuery === '{}';
|
||||
});
|
||||
|
||||
@@ -50,7 +52,9 @@ export function QueryEditor(props: Props) {
|
||||
props.onClearResults();
|
||||
props.onChange({
|
||||
...query,
|
||||
query: props.datasource.languageProvider.generateQueryFromFilters(query.filters || []),
|
||||
query: props.datasource.languageProvider.generateQueryFromFilters({
|
||||
traceqlFilters: query.filters || [],
|
||||
}),
|
||||
});
|
||||
setShowCopyFromSearchButton(true);
|
||||
}}
|
||||
|
||||
@@ -58,6 +58,8 @@ export const intrinsics = intrinsicsV1.concat([
|
||||
]);
|
||||
export const scopes: string[] = ['event', 'instrumentation', 'link', 'resource', 'span'];
|
||||
|
||||
export const enumIntrinsics = ['kind', 'span:kind', 'status', 'span:status'];
|
||||
|
||||
const aggregatorFunctions = ['avg', 'count', 'max', 'min', 'sum'];
|
||||
const functions = aggregatorFunctions.concat([
|
||||
'by',
|
||||
|
||||
Reference in New Issue
Block a user