D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
templating
/
Filename :
template_srv.ts
back
Copy
import { escape, isString } from 'lodash'; import { deprecationWarning, ScopedVars, TimeRange, AdHocVariableFilter, AdHocVariableModel, TypedVariableModel, ScopedVar, } from '@grafana/data'; import { getDataSourceSrv, setTemplateSrv, TemplateSrv as BaseTemplateSrv, VariableInterpolation, } from '@grafana/runtime'; import { sceneGraph, VariableCustomFormatterFn } from '@grafana/scenes'; import { VariableFormatID } from '@grafana/schema'; 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 { variableRegex } from '../variables/utils'; import { getFieldAccessor } from './fieldAccessorCache'; import { formatVariableValue } from './formatVariableValue'; import { macroRegistry } from './macroRegistry'; /** * Internal regex replace function */ type ReplaceFunction = (fullMatch: string, variableName: string, fieldPath: string, format: string) => string; 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 = new Map<string, any>(); private timeRange?: TimeRange | null = null; 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(): TypedVariableModel[] { 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) === ds.uid) { filters = filters.concat(variable.filters); } } } return filters; } setGrafanaVariable(name: string, value: any) { this.grafanaVariables.set(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); return this._replaceWithVariableRegex(str, undefined, (match, variableName) => { if (this.getVariableAtIndex(variableName)) { 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 getVariableValue(scopedVar: ScopedVar, fieldPath: string | undefined) { if (fieldPath) { return getFieldAccessor(fieldPath)(scopedVar.value); } return scopedVar.value; } private getVariableText(scopedVar: ScopedVar, value: any) { if (scopedVar.value === value || typeof value !== 'string') { return scopedVar.text; } return value; } replace( target?: string, scopedVars?: ScopedVars, format?: string | Function | undefined, interpolations?: VariableInterpolation[] ): string { if (scopedVars && scopedVars.__sceneObject) { return sceneGraph.interpolate( scopedVars.__sceneObject.value, target, scopedVars, format as string | VariableCustomFormatterFn | undefined ); } if (!target) { return target ?? ''; } this.regex.lastIndex = 0; return this._replaceWithVariableRegex(target, format, (match, variableName, fieldPath, fmt) => { const value = this._evaluateVariableExpression(match, variableName, fieldPath, fmt, scopedVars); // If we get passed this interpolations map we will also record all the expressions that were replaced if (interpolations) { interpolations.push({ match, variableName, fieldPath, format: fmt, value, found: value !== match }); } return value; }); } private _evaluateVariableExpression( match: string, variableName: string, fieldPath: string, format: string | VariableCustomFormatterFn | undefined, scopedVars: ScopedVars | undefined ) { const variable = this.getVariableAtIndex(variableName); const scopedVar = scopedVars?.[variableName]; if (scopedVar) { const value = this.getVariableValue(scopedVar, fieldPath); const text = this.getVariableText(scopedVar, value); if (value !== null && value !== undefined) { return formatVariableValue(value, format, variable, text); } } if (!variable) { const macro = macroRegistry[variableName]; if (macro) { return macro(match, fieldPath, scopedVars, format); } return match; } if (format === VariableFormatID.QueryParam || isAdHoc(variable)) { const value = variableAdapters.get(variable.type).getValueForUrl(variable); const text = isAdHoc(variable) ? variable.id : variable.current.text; return formatVariableValue(value, format, variable, text); } const systemValue = this.grafanaVariables.get(variable.current.value); if (systemValue) { return formatVariableValue(systemValue, format, 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 unless format set to text or percentencode if (variable.allValue && format !== VariableFormatID.Text && format !== VariableFormatID.PercentEncode) { return this.replace(value); } } if (fieldPath) { const fieldValue = this.getVariableValue({ value, text }, fieldPath); if (fieldValue !== null && fieldValue !== undefined) { return formatVariableValue(fieldValue, format, variable, text); } } return formatVariableValue(value, format, variable, text); } /** * Tries to unify the different variable format capture groups into a simpler replacer function */ private _replaceWithVariableRegex(text: string, format: string | Function | undefined, replace: ReplaceFunction) { this.regex.lastIndex = 0; return text.replace(this.regex, (match, var1, var2, fmt2, var3, fieldPath, fmt3) => { const variableName = var1 || var2 || var3; const fmt = fmt2 || fmt3 || format; return replace(match, variableName, fieldPath, fmt); }); } 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;