grafana/public/app/features/templating/query_variable.ts
Hugo Häggmark 8b672c8aed
Templating: Adds typings to Variables (#20117)
* Refactor: Adds typings and changes AdHocVariable to conform to new typings

* Refactor: Adds typings to ConstantVariable

* Refactor: Adds typings to IntervalVariable

* Refactor: Adds typings to QueryVariable

* Refactor: Adds typings to TextBoxVariable

* Refactor: Adds typings to CustomVariable
2019-10-31 10:59:30 +01:00

254 lines
6.3 KiB
TypeScript

import _ from 'lodash';
import {
assignModelProperties,
containsVariable,
QueryVariableModel,
VariableActions,
VariableHide,
VariableOption,
VariableRefresh,
VariableSort,
VariableTag,
VariableType,
variableTypes,
} from './variable';
import { stringToJsRegex } from '@grafana/data';
import DatasourceSrv from '../plugins/datasource_srv';
import { TemplateSrv } from './template_srv';
import { VariableSrv } from './variable_srv';
import { TimeSrv } from '../dashboard/services/TimeSrv';
function getNoneOption(): VariableOption {
return { text: 'None', value: '', isNone: true, selected: false };
}
export class QueryVariable implements QueryVariableModel, VariableActions {
type: VariableType;
name: string;
label: string;
hide: VariableHide;
skipUrlSync: boolean;
datasource: string;
query: string;
regex: string;
sort: VariableSort;
options: VariableOption[];
current: VariableOption;
refresh: VariableRefresh;
multi: boolean;
includeAll: boolean;
useTags: boolean;
tagsQuery: string;
tagValuesQuery: string;
tags: VariableTag[];
definition: string;
allValue: string;
defaults: QueryVariableModel = {
type: 'query',
name: '',
label: null,
hide: VariableHide.dontHide,
skipUrlSync: false,
datasource: null,
query: '',
regex: '',
sort: VariableSort.disabled,
refresh: VariableRefresh.never,
multi: false,
includeAll: false,
allValue: null,
options: [],
current: {} as VariableOption,
tags: [],
useTags: false,
tagsQuery: '',
tagValuesQuery: '',
definition: '',
};
/** @ngInject */
constructor(
private model: any,
private datasourceSrv: DatasourceSrv,
private templateSrv: TemplateSrv,
private variableSrv: VariableSrv,
private timeSrv: TimeSrv
) {
// copy model properties to this instance
assignModelProperties(this, model, this.defaults);
this.updateOptionsFromMetricFindQuery.bind(this);
}
getSaveModel() {
// copy back model properties to model
assignModelProperties(this.model, this, this.defaults);
// remove options
if (this.refresh !== 0) {
this.model.options = [];
}
return this.model;
}
setValue(option: any) {
return this.variableSrv.setOptionAsCurrent(this, option);
}
setValueFromUrl(urlValue: any) {
return this.variableSrv.setOptionFromUrl(this, urlValue);
}
getValueForUrl() {
if (this.current.text === 'All') {
return 'All';
}
return this.current.value;
}
updateOptions(searchFilter?: string) {
return this.datasourceSrv
.get(this.datasource)
.then(ds => this.updateOptionsFromMetricFindQuery(ds, searchFilter))
.then(this.updateTags.bind(this))
.then(this.variableSrv.validateVariableSelectionState.bind(this.variableSrv, this));
}
updateTags(datasource: any) {
if (this.useTags) {
return this.metricFindQuery(datasource, this.tagsQuery).then((results: any[]) => {
this.tags = [];
for (let i = 0; i < results.length; i++) {
this.tags.push(results[i].text);
}
return datasource;
});
} else {
delete this.tags;
}
return datasource;
}
getValuesForTag(tagKey: string) {
return this.datasourceSrv.get(this.datasource).then(datasource => {
const query = this.tagValuesQuery.replace('$tag', tagKey);
return this.metricFindQuery(datasource, query).then((results: any) => {
return _.map(results, value => {
return value.text;
});
});
});
}
updateOptionsFromMetricFindQuery(datasource: any, searchFilter?: string) {
return this.metricFindQuery(datasource, this.query, searchFilter).then((results: any) => {
this.options = this.metricNamesToVariableValues(results);
if (this.includeAll) {
this.addAllOption();
}
if (!this.options.length) {
this.options.push(getNoneOption());
}
return datasource;
});
}
metricFindQuery(datasource: any, query: string, searchFilter?: string) {
const options: any = { range: undefined, variable: this, searchFilter };
if (this.refresh === 2) {
options.range = this.timeSrv.timeRange();
}
return datasource.metricFindQuery(query, options);
}
addAllOption() {
this.options.unshift({ text: 'All', value: '$__all', selected: false });
}
metricNamesToVariableValues(metricNames: any[]) {
let regex, options, i, matches;
options = [];
if (this.regex) {
regex = stringToJsRegex(this.templateSrv.replace(this.regex, {}, 'regex'));
}
for (i = 0; i < metricNames.length; i++) {
const item = metricNames[i];
let text = item.text === undefined || item.text === null ? item.value : item.text;
let value = item.value === undefined || item.value === null ? item.text : item.value;
if (_.isNumber(value)) {
value = value.toString();
}
if (_.isNumber(text)) {
text = text.toString();
}
if (regex) {
matches = regex.exec(value);
if (!matches) {
continue;
}
if (matches.length > 1) {
value = matches[1];
text = matches[1];
}
}
options.push({ text: text, value: value });
}
options = _.uniqBy(options, 'value');
return this.sortVariableValues(options, this.sort);
}
sortVariableValues(options: any[], sortOrder: number) {
if (sortOrder === 0) {
return options;
}
const sortType = Math.ceil(sortOrder / 2);
const reverseSort = sortOrder % 2 === 0;
if (sortType === 1) {
options = _.sortBy(options, 'text');
} else if (sortType === 2) {
options = _.sortBy(options, opt => {
const matches = opt.text.match(/.*?(\d+).*/);
if (!matches || matches.length < 2) {
return -1;
} else {
return parseInt(matches[1], 10);
}
});
} else if (sortType === 3) {
options = _.sortBy(options, opt => {
return _.toLower(opt.text);
});
}
if (reverseSort) {
options = options.reverse();
}
return options;
}
dependsOn(variable: any) {
return containsVariable(this.query, this.datasource, this.regex, variable.name);
}
}
// @ts-ignore
variableTypes['query'] = {
name: 'Query',
ctor: QueryVariable,
description: 'Variable values are fetched from a datasource query',
supportsMulti: true,
};