import { map } from 'rxjs/operators'; import { ArrayVector, DataFrame, DataTransformerID, DataTransformerInfo, FieldMatcherID, getFieldDisplayName, getFieldMatcher, MatcherConfig, reduceField, } from '@grafana/data'; import { getFieldConfigFromFrame, FieldToConfigMapping, evaluteFieldMappings, } from '../fieldToConfigMapping/fieldToConfigMapping'; export interface ConfigFromQueryTransformOptions { configRefId?: string; mappings: FieldToConfigMapping[]; applyTo?: MatcherConfig; } export function extractConfigFromQuery(options: ConfigFromQueryTransformOptions, data: DataFrame[]) { let configFrame: DataFrame | null = null; for (const frame of data) { if (frame.refId === options.configRefId) { configFrame = frame; break; } } if (!configFrame) { return data; } const reducedConfigFrame: DataFrame = { fields: [], length: 1, }; const mappingResult = evaluteFieldMappings(configFrame, options.mappings ?? [], false); // reduce config frame for (const field of configFrame.fields) { const newField = { ...field }; const fieldName = getFieldDisplayName(field, configFrame); const fieldMapping = mappingResult.index[fieldName]; const result = reduceField({ field, reducers: [fieldMapping.reducerId] }); newField.values = new ArrayVector([result[fieldMapping.reducerId]]); reducedConfigFrame.fields.push(newField); } const output: DataFrame[] = []; const matcher = getFieldMatcher(options.applyTo || { id: FieldMatcherID.numeric }); for (const frame of data) { // Skip config frame in output if (frame === configFrame && data.length > 1) { continue; } const outputFrame: DataFrame = { fields: [], length: frame.length, }; for (const field of frame.fields) { if (matcher(field, frame, data)) { const dataConfig = getFieldConfigFromFrame(reducedConfigFrame, 0, mappingResult); outputFrame.fields.push({ ...field, config: { ...field.config, ...dataConfig, }, }); } else { outputFrame.fields.push(field); } } output.push(outputFrame); } return output; } export const configFromDataTransformer: DataTransformerInfo = { id: DataTransformerID.configFromData, name: 'Config from query results', description: 'Set unit, min, max and more from data', defaultOptions: { configRefId: 'config', mappings: [], }, /** * Return a modified copy of the series. If the transform is not or should not * be applied, just return the input series */ operator: (options) => (source) => source.pipe(map((data) => extractConfigFromQuery(options, data))), };