2023-04-05 04:10:33 -05:00
|
|
|
import {
|
|
|
|
DisplayProcessor,
|
|
|
|
FieldType,
|
|
|
|
formattedValueToString,
|
|
|
|
getDisplayProcessor,
|
|
|
|
getFieldDisplayValuesProxy,
|
|
|
|
getFrameDisplayName,
|
|
|
|
ScopedVars,
|
|
|
|
} from '@grafana/data';
|
2023-03-28 12:22:34 -05:00
|
|
|
import { VariableCustomFormatterFn } from '@grafana/scenes';
|
|
|
|
|
2023-04-05 04:10:33 -05:00
|
|
|
import { getFieldAccessor } from './fieldAccessorCache';
|
2023-03-28 12:22:34 -05:00
|
|
|
import { formatVariableValue } from './formatVariableValue';
|
2023-04-05 04:10:33 -05:00
|
|
|
import { getTemplateProxyForField } from './templateProxies';
|
2023-03-28 12:22:34 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ${__value.raw/nummeric/text/time} macro
|
|
|
|
*/
|
|
|
|
export function valueMacro(
|
|
|
|
match: string,
|
|
|
|
fieldPath?: string,
|
|
|
|
scopedVars?: ScopedVars,
|
|
|
|
format?: string | VariableCustomFormatterFn
|
|
|
|
) {
|
|
|
|
const value = getValueForValueMacro(match, fieldPath, scopedVars);
|
|
|
|
return formatVariableValue(value, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getValueForValueMacro(match: string, fieldPath?: string, scopedVars?: ScopedVars) {
|
|
|
|
const dataContext = scopedVars?.__dataContext;
|
|
|
|
if (!dataContext) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { frame, rowIndex, field, calculatedValue } = dataContext.value;
|
|
|
|
|
|
|
|
if (calculatedValue) {
|
|
|
|
switch (fieldPath) {
|
|
|
|
case 'numeric':
|
|
|
|
return calculatedValue.numeric.toString();
|
|
|
|
case 'raw':
|
|
|
|
return calculatedValue.numeric;
|
|
|
|
case 'time':
|
|
|
|
return '';
|
|
|
|
case 'text':
|
|
|
|
default:
|
|
|
|
return formattedValueToString(calculatedValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rowIndex === undefined) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fieldPath === 'time') {
|
|
|
|
const timeField = frame.fields.find((f) => f.type === FieldType.time);
|
2023-04-20 09:59:18 -05:00
|
|
|
return timeField ? timeField.values[rowIndex] : undefined;
|
2023-03-28 12:22:34 -05:00
|
|
|
}
|
|
|
|
|
2023-04-20 09:59:18 -05:00
|
|
|
const value = field.values[rowIndex];
|
2023-03-28 12:22:34 -05:00
|
|
|
if (fieldPath === 'raw') {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
const displayProcessor = field.display ?? getFallbackDisplayProcessor();
|
|
|
|
const result = displayProcessor(value);
|
|
|
|
|
|
|
|
switch (fieldPath) {
|
|
|
|
case 'numeric':
|
|
|
|
return result.numeric;
|
|
|
|
case 'text':
|
|
|
|
return result.text;
|
|
|
|
default:
|
|
|
|
return formattedValueToString(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-05 04:10:33 -05:00
|
|
|
/**
|
|
|
|
* Macro support doing things like.
|
|
|
|
* ${__data.name}
|
|
|
|
* ${__data.fields[0].name}
|
|
|
|
* ${__data.fields["Value"].labels.cluster}
|
|
|
|
*
|
|
|
|
* Requires rowIndex on dataContext
|
|
|
|
*/
|
|
|
|
export function dataMacro(
|
|
|
|
match: string,
|
|
|
|
fieldPath?: string,
|
|
|
|
scopedVars?: ScopedVars,
|
|
|
|
format?: string | VariableCustomFormatterFn
|
|
|
|
) {
|
|
|
|
const dataContext = scopedVars?.__dataContext;
|
|
|
|
if (!dataContext || !fieldPath) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { frame, rowIndex } = dataContext.value;
|
|
|
|
|
|
|
|
if (rowIndex === undefined || fieldPath === undefined) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
const obj = {
|
|
|
|
name: frame.name,
|
|
|
|
refId: frame.refId,
|
|
|
|
fields: getFieldDisplayValuesProxy({ frame, rowIndex }),
|
|
|
|
};
|
|
|
|
|
|
|
|
const value = getFieldAccessor(fieldPath)(obj) ?? '';
|
|
|
|
return formatVariableValue(value, format);
|
|
|
|
}
|
|
|
|
|
2023-03-28 12:22:34 -05:00
|
|
|
let fallbackDisplayProcessor: DisplayProcessor | undefined;
|
|
|
|
|
|
|
|
function getFallbackDisplayProcessor() {
|
|
|
|
if (!fallbackDisplayProcessor) {
|
|
|
|
fallbackDisplayProcessor = getDisplayProcessor();
|
|
|
|
}
|
|
|
|
|
|
|
|
return fallbackDisplayProcessor;
|
|
|
|
}
|
2023-04-05 04:10:33 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ${__series} = frame display name
|
|
|
|
*/
|
|
|
|
export function seriesNameMacro(
|
|
|
|
match: string,
|
|
|
|
fieldPath?: string,
|
|
|
|
scopedVars?: ScopedVars,
|
|
|
|
format?: string | VariableCustomFormatterFn
|
|
|
|
) {
|
|
|
|
const dataContext = scopedVars?.__dataContext;
|
|
|
|
if (!dataContext) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fieldPath !== 'name') {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { frame, frameIndex } = dataContext.value;
|
|
|
|
const value = getFrameDisplayName(frame, frameIndex);
|
|
|
|
return formatVariableValue(value, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles expressions like
|
|
|
|
* ${__field.name}
|
|
|
|
* ${__field.labels.cluster}
|
|
|
|
*/
|
|
|
|
export function fieldMacro(
|
|
|
|
match: string,
|
|
|
|
fieldPath?: string,
|
|
|
|
scopedVars?: ScopedVars,
|
|
|
|
format?: string | VariableCustomFormatterFn
|
|
|
|
) {
|
|
|
|
const dataContext = scopedVars?.__dataContext;
|
|
|
|
if (!dataContext) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fieldPath === undefined || fieldPath === '') {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { frame, field, data } = dataContext.value;
|
|
|
|
const obj = getTemplateProxyForField(field, frame, data);
|
|
|
|
|
|
|
|
const value = getFieldAccessor(fieldPath)(obj) ?? '';
|
|
|
|
return formatVariableValue(value, format);
|
|
|
|
}
|