grafana/public/app/features/templating/dataMacros.ts
Leon Sorokin b24ba7b7ae
FieldValues: Use plain arrays instead of Vector (part 3 of 2) (#66612)
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2023-04-20 17:59:18 +03:00

172 lines
4.0 KiB
TypeScript

import {
DisplayProcessor,
FieldType,
formattedValueToString,
getDisplayProcessor,
getFieldDisplayValuesProxy,
getFrameDisplayName,
ScopedVars,
} from '@grafana/data';
import { VariableCustomFormatterFn } from '@grafana/scenes';
import { getFieldAccessor } from './fieldAccessorCache';
import { formatVariableValue } from './formatVariableValue';
import { getTemplateProxyForField } from './templateProxies';
/**
* ${__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);
return timeField ? timeField.values[rowIndex] : undefined;
}
const value = field.values[rowIndex];
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);
}
}
/**
* 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);
}
let fallbackDisplayProcessor: DisplayProcessor | undefined;
function getFallbackDisplayProcessor() {
if (!fallbackDisplayProcessor) {
fallbackDisplayProcessor = getDisplayProcessor();
}
return fallbackDisplayProcessor;
}
/**
* ${__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);
}