123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- import { escape, isString, property } from 'lodash';
- import { deprecationWarning, ScopedVars, TimeRange } from '@grafana/data';
- import { getDataSourceSrv, setTemplateSrv, TemplateSrv as BaseTemplateSrv } from '@grafana/runtime';
- import { variableAdapters } from '../variables/adapters';
- import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from '../variables/constants';
- import { isAdHoc } from '../variables/guard';
- import { getFilteredVariables, getVariables, getVariableWithName } from '../variables/state/selectors';
- import { AdHocVariableFilter, AdHocVariableModel, VariableModel } from '../variables/types';
- import { variableRegex } from '../variables/utils';
- import { FormatOptions, formatRegistry, FormatRegistryID } from './formatRegistry';
- interface FieldAccessorCache {
- [key: string]: (obj: any) => any;
- }
- export interface TemplateSrvDependencies {
- getFilteredVariables: typeof getFilteredVariables;
- getVariables: typeof getVariables;
- getVariableWithName: typeof getVariableWithName;
- }
- const runtimeDependencies: TemplateSrvDependencies = {
- getFilteredVariables,
- getVariables,
- getVariableWithName,
- };
- export class TemplateSrv implements BaseTemplateSrv {
- private _variables: any[];
- private regex = variableRegex;
- private index: any = {};
- private grafanaVariables: any = {};
- private timeRange?: TimeRange | null = null;
- private fieldAccessorCache: FieldAccessorCache = {};
- constructor(private dependencies: TemplateSrvDependencies = runtimeDependencies) {
- this._variables = [];
- }
- init(variables: any, timeRange?: TimeRange) {
- this._variables = variables;
- this.timeRange = timeRange;
- this.updateIndex();
- }
- /**
- * @deprecated: this instance variable should not be used and will be removed in future releases
- *
- * Use getVariables function instead
- */
- get variables(): any[] {
- deprecationWarning('template_srv.ts', 'variables', 'getVariables');
- return this.getVariables();
- }
- getVariables(): VariableModel[] {
- return this.dependencies.getVariables();
- }
- updateIndex() {
- const existsOrEmpty = (value: any) => value || value === '';
- this.index = this._variables.reduce((acc, currentValue) => {
- if (currentValue.current && (currentValue.current.isNone || existsOrEmpty(currentValue.current.value))) {
- acc[currentValue.name] = currentValue;
- }
- return acc;
- }, {});
- if (this.timeRange) {
- const from = this.timeRange.from.valueOf().toString();
- const to = this.timeRange.to.valueOf().toString();
- this.index = {
- ...this.index,
- ['__from']: {
- current: { value: from, text: from },
- },
- ['__to']: {
- current: { value: to, text: to },
- },
- };
- }
- }
- updateTimeRange(timeRange: TimeRange) {
- this.timeRange = timeRange;
- this.updateIndex();
- }
- variableInitialized(variable: any) {
- this.index[variable.name] = variable;
- }
- getAdhocFilters(datasourceName: string): AdHocVariableFilter[] {
- let filters: any = [];
- let ds = getDataSourceSrv().getInstanceSettings(datasourceName);
- if (!ds) {
- return [];
- }
- for (const variable of this.getAdHocVariables()) {
- const variableUid = variable.datasource?.uid;
- if (variableUid === ds.uid) {
- filters = filters.concat(variable.filters);
- } else if (variableUid?.indexOf('$') === 0) {
- if (this.replace(variableUid) === datasourceName) {
- filters = filters.concat(variable.filters);
- }
- }
- }
- return filters;
- }
- formatValue(value: any, format: any, variable: any, text?: string): string {
- // for some scopedVars there is no variable
- variable = variable || {};
- if (value === null || value === undefined) {
- return '';
- }
- if (isAdHoc(variable) && format !== FormatRegistryID.queryParam) {
- return '';
- }
- // if it's an object transform value to string
- if (!Array.isArray(value) && typeof value === 'object') {
- value = `${value}`;
- }
- if (typeof format === 'function') {
- return format(value, variable, this.formatValue);
- }
- if (!format) {
- format = FormatRegistryID.glob;
- }
- // some formats have arguments that come after ':' character
- let args = format.split(':');
- if (args.length > 1) {
- format = args[0];
- args = args.slice(1);
- } else {
- args = [];
- }
- let formatItem = formatRegistry.getIfExists(format);
- if (!formatItem) {
- console.error(`Variable format ${format} not found. Using glob format as fallback.`);
- formatItem = formatRegistry.get(FormatRegistryID.glob);
- }
- const options: FormatOptions = { value, args, text: text ?? value };
- return formatItem.formatter(options, variable);
- }
- setGrafanaVariable(name: string, value: any) {
- this.grafanaVariables[name] = value;
- }
- /**
- * @deprecated: setGlobalVariable function should not be used and will be removed in future releases
- *
- * Use addVariable action to add variables to Redux instead
- */
- setGlobalVariable(name: string, variable: any) {
- deprecationWarning('template_srv.ts', 'setGlobalVariable', '');
- this.index = {
- ...this.index,
- [name]: {
- current: variable,
- },
- };
- }
- getVariableName(expression: string) {
- this.regex.lastIndex = 0;
- const match = this.regex.exec(expression);
- if (!match) {
- return null;
- }
- const variableName = match.slice(1).find((match) => match !== undefined);
- return variableName;
- }
- containsTemplate(target: string | undefined): boolean {
- if (!target) {
- return false;
- }
- const name = this.getVariableName(target);
- const variable = name && this.getVariableAtIndex(name);
- return variable !== null && variable !== undefined;
- }
- variableExists(expression: string): boolean {
- deprecationWarning('template_srv.ts', 'variableExists', 'containsTemplate');
- return this.containsTemplate(expression);
- }
- highlightVariablesAsHtml(str: string) {
- if (!str || !isString(str)) {
- return str;
- }
- str = escape(str);
- this.regex.lastIndex = 0;
- return str.replace(this.regex, (match, var1, var2, fmt2, var3) => {
- if (this.getVariableAtIndex(var1 || var2 || var3)) {
- return '<span class="template-variable">' + match + '</span>';
- }
- return match;
- });
- }
- getAllValue(variable: any) {
- if (variable.allValue) {
- return variable.allValue;
- }
- const values = [];
- for (let i = 1; i < variable.options.length; i++) {
- values.push(variable.options[i].value);
- }
- return values;
- }
- private getFieldAccessor(fieldPath: string) {
- const accessor = this.fieldAccessorCache[fieldPath];
- if (accessor) {
- return accessor;
- }
- return (this.fieldAccessorCache[fieldPath] = property(fieldPath));
- }
- private getVariableValue(variableName: string, fieldPath: string | undefined, scopedVars: ScopedVars) {
- const scopedVar = scopedVars[variableName];
- if (!scopedVar) {
- return null;
- }
- if (fieldPath) {
- return this.getFieldAccessor(fieldPath)(scopedVar.value);
- }
- return scopedVar.value;
- }
- private getVariableText(variableName: string, value: any, scopedVars: ScopedVars) {
- const scopedVar = scopedVars[variableName];
- if (!scopedVar) {
- return null;
- }
- if (scopedVar.value === value || typeof value !== 'string') {
- return scopedVar.text;
- }
- return value;
- }
- replace(target?: string, scopedVars?: ScopedVars, format?: string | Function): string {
- if (!target) {
- return target ?? '';
- }
- this.regex.lastIndex = 0;
- return target.replace(this.regex, (match, var1, var2, fmt2, var3, fieldPath, fmt3) => {
- const variableName = var1 || var2 || var3;
- const variable = this.getVariableAtIndex(variableName);
- const fmt = fmt2 || fmt3 || format;
- if (scopedVars) {
- const value = this.getVariableValue(variableName, fieldPath, scopedVars);
- const text = this.getVariableText(variableName, value, scopedVars);
- if (value !== null && value !== undefined) {
- return this.formatValue(value, fmt, variable, text);
- }
- }
- if (!variable) {
- return match;
- }
- if (fmt === FormatRegistryID.queryParam || isAdHoc(variable)) {
- const value = variableAdapters.get(variable.type).getValueForUrl(variable);
- const text = isAdHoc(variable) ? variable.id : variable.current.text;
- return this.formatValue(value, fmt, variable, text);
- }
- const systemValue = this.grafanaVariables[variable.current.value];
- if (systemValue) {
- return this.formatValue(systemValue, fmt, variable);
- }
- let value = variable.current.value;
- let text = variable.current.text;
- if (this.isAllValue(value)) {
- value = this.getAllValue(variable);
- text = ALL_VARIABLE_TEXT;
- // skip formatting of custom all values
- if (variable.allValue && fmt !== FormatRegistryID.text) {
- return this.replace(value);
- }
- }
- if (fieldPath) {
- const fieldValue = this.getVariableValue(variableName, fieldPath, {
- [variableName]: { value, text },
- });
- if (fieldValue !== null && fieldValue !== undefined) {
- return this.formatValue(fieldValue, fmt, variable, text);
- }
- }
- const res = this.formatValue(value, fmt, variable, text);
- return res;
- });
- }
- isAllValue(value: any) {
- return value === ALL_VARIABLE_VALUE || (Array.isArray(value) && value[0] === ALL_VARIABLE_VALUE);
- }
- replaceWithText(target: string, scopedVars?: ScopedVars) {
- deprecationWarning('template_srv.ts', 'replaceWithText()', 'replace(), and specify the :text format');
- return this.replace(target, scopedVars, 'text');
- }
- private getVariableAtIndex(name: string) {
- if (!name) {
- return;
- }
- if (!this.index[name]) {
- return this.dependencies.getVariableWithName(name);
- }
- return this.index[name];
- }
- private getAdHocVariables(): AdHocVariableModel[] {
- return this.dependencies.getFilteredVariables(isAdHoc) as AdHocVariableModel[];
- }
- }
- // Expose the template srv
- const srv = new TemplateSrv();
- setTemplateSrv(srv);
- export const getTemplateSrv = () => srv;
|