TemplateVariables: Introduces $__searchFilter to Query Variables (#19858)

* WIP: Initial hardcoded version

* Feature: Introduces SearchFiltering to Graphite

* Feature: Adds searchFiltering to MySql

* Tests: Adds tests to Graphite and MySql

* Feature: Adds $__searchFilter to TestData

* Refactor: Adds searchFilter to Postgres and extracts function

* Tests: Adds tests to variable

* Refactor: Adds debounce and lodash import optimization

* Docs: Adds documentation

* Refactor: Removes unused function and fixes typo

* Docs: Updates docs

* Fixed issue with UI not updating when no  was used due to async func and no .apply in the non lazy path
This commit is contained in:
Hugo Häggmark
2019-10-18 11:40:08 +02:00
committed by Torkel Ödegaard
parent c674fa1d79
commit cb0e80e7b9
18 changed files with 601 additions and 59 deletions
+13 -7
View File
@@ -1,18 +1,18 @@
import _ from 'lodash';
import {
DataSourceApi,
DataQueryRequest,
DataSourceInstanceSettings,
DataQueryResponse,
DataSourceApi,
DataSourceInstanceSettings,
MetricFindValue,
} from '@grafana/ui';
import { TableData, TimeSeries } from '@grafana/data';
import { TestDataQuery, Scenario } from './types';
import { Scenario, TestDataQuery } from './types';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { queryMetricTree } from './metricTree';
import { Observable, from, merge } from 'rxjs';
import { from, merge, Observable } from 'rxjs';
import { runStream } from './runStreams';
import templateSrv from 'app/features/templating/template_srv';
import { interpolateSearchFilter } from '../../../features/templating/variable';
type TestData = TimeSeries | TableData;
@@ -119,10 +119,16 @@ export class TestDataDataSource extends DataSourceApi<TestDataQuery> {
return getBackendSrv().get('/api/tsdb/testdata/scenarios');
}
metricFindQuery(query: string) {
metricFindQuery(query: string, options: any) {
return new Promise<MetricFindValue[]>((resolve, reject) => {
setTimeout(() => {
const children = queryMetricTree(templateSrv.replace(query));
const interpolatedQuery = interpolateSearchFilter({
query: templateSrv.replace(query),
options,
wildcardChar: '*',
quoteLiteral: false,
});
const children = queryMetricTree(interpolatedQuery);
const items = children.map(item => ({ value: item.name, text: item.name }));
resolve(items);
}, 100);
@@ -16,4 +16,9 @@ describe('MetricTree', () => {
const nodes = queryMetricTree('A.{AB,AC}.*').map(i => i.name);
expect(nodes).toEqual(['ABA', 'ABB', 'ABC', 'ACA', 'ACB', 'ACC']);
});
it('queryMetric tree supports wildcard matching', () => {
const nodes = queryMetricTree('A.AB.AB*').map(i => i.name);
expect(nodes).toEqual(['ABA', 'ABB', 'ABC']);
});
});
+11 -1
View File
@@ -35,6 +35,10 @@ function buildMetricTree(parent: string, depth: number): TreeNode[] {
}
function queryTree(children: TreeNode[], query: string[], queryIndex: number): TreeNode[] {
if (queryIndex >= query.length) {
return children;
}
if (query[queryIndex] === '*') {
return children;
}
@@ -50,7 +54,13 @@ function queryTree(children: TreeNode[], query: string[], queryIndex: number): T
for (const node of children) {
for (const nameToMatch of namesToMatch) {
if (node.name === nameToMatch) {
if (nameToMatch.indexOf('*') !== -1) {
const pattern = nameToMatch.replace('*', '');
const regex = new RegExp(`^${pattern}.*`, 'gi');
if (regex.test(node.name)) {
result = result.concat(queryTree([node], query, queryIndex + 1));
}
} else if (node.name === nameToMatch) {
result = result.concat(queryTree(node.children, query, queryIndex + 1));
}
}