mirror of
https://github.com/grafana/grafana.git
synced 2025-02-15 10:03:33 -06:00
128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
|
import { map } from 'rxjs/operators';
|
||
|
|
||
|
import {
|
||
|
ArrayVector,
|
||
|
DataFrame,
|
||
|
DataTransformerID,
|
||
|
DataTransformerInfo,
|
||
|
Field,
|
||
|
FieldType,
|
||
|
MutableDataFrame,
|
||
|
isTimeSeriesFrame,
|
||
|
} from '@grafana/data';
|
||
|
|
||
|
export interface TimeSeriesTableTransformerOptions {}
|
||
|
|
||
|
export const timeSeriesTableTransformer: DataTransformerInfo<TimeSeriesTableTransformerOptions> = {
|
||
|
id: DataTransformerID.timeSeriesTable,
|
||
|
name: 'Time series to table transform',
|
||
|
description: 'Time series to table rows',
|
||
|
defaultOptions: {},
|
||
|
|
||
|
operator: (options) => (source) =>
|
||
|
source.pipe(
|
||
|
map((data) => {
|
||
|
return timeSeriesToTableTransform(options, data);
|
||
|
})
|
||
|
),
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Converts time series frames to table frames for use with sparkline chart type.
|
||
|
*
|
||
|
* @remarks
|
||
|
* For each refId (queryName) convert all time series frames into a single table frame, adding each series
|
||
|
* as values of a "Trend" frame field. This allows "Trend" to be rendered as area chart type.
|
||
|
* Any non time series frames are returned as is.
|
||
|
*
|
||
|
* @param options - Transform options, currently not used
|
||
|
* @param data - Array of data frames to transform
|
||
|
* @returns Array of transformed data frames
|
||
|
*
|
||
|
* @alpha
|
||
|
*/
|
||
|
export function timeSeriesToTableTransform(options: TimeSeriesTableTransformerOptions, data: DataFrame[]): DataFrame[] {
|
||
|
// initialize fields from labels for each refId
|
||
|
const refId2LabelFields = getLabelFields(data);
|
||
|
|
||
|
const refId2frameField: Record<string, Field<DataFrame, ArrayVector>> = {};
|
||
|
|
||
|
const result: DataFrame[] = [];
|
||
|
|
||
|
for (const frame of data) {
|
||
|
if (!isTimeSeriesFrame(frame)) {
|
||
|
result.push(frame);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const refId = frame.refId ?? '';
|
||
|
|
||
|
const labelFields = refId2LabelFields[refId] ?? {};
|
||
|
// initialize a new frame for this refId with fields per label and a Trend frame field, if it doesn't exist yet
|
||
|
let frameField = refId2frameField[refId];
|
||
|
if (!frameField) {
|
||
|
frameField = {
|
||
|
name: 'Trend' + (refId && Object.keys(refId2LabelFields).length > 1 ? ` #${refId}` : ''),
|
||
|
type: FieldType.frame,
|
||
|
config: {},
|
||
|
values: new ArrayVector(),
|
||
|
};
|
||
|
refId2frameField[refId] = frameField;
|
||
|
const table = new MutableDataFrame();
|
||
|
for (const label of Object.values(labelFields)) {
|
||
|
table.addField(label);
|
||
|
}
|
||
|
table.addField(frameField);
|
||
|
table.refId = refId;
|
||
|
result.push(table);
|
||
|
}
|
||
|
|
||
|
// add values to each label based field of this frame
|
||
|
const labels = frame.fields[1].labels;
|
||
|
for (const labelKey of Object.keys(labelFields)) {
|
||
|
const labelValue = labels?.[labelKey] ?? null;
|
||
|
labelFields[labelKey].values.add(labelValue);
|
||
|
}
|
||
|
|
||
|
frameField.values.add(frame);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// For each refId, initialize a field for each label name
|
||
|
function getLabelFields(frames: DataFrame[]): Record<string, Record<string, Field<string, ArrayVector>>> {
|
||
|
// refId -> label name -> field
|
||
|
const labelFields: Record<string, Record<string, Field<string, ArrayVector>>> = {};
|
||
|
|
||
|
for (const frame of frames) {
|
||
|
if (!isTimeSeriesFrame(frame)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const refId = frame.refId ?? '';
|
||
|
|
||
|
if (!labelFields[refId]) {
|
||
|
labelFields[refId] = {};
|
||
|
}
|
||
|
|
||
|
for (const field of frame.fields) {
|
||
|
if (!field.labels) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
for (const labelName of Object.keys(field.labels)) {
|
||
|
if (!labelFields[refId][labelName]) {
|
||
|
labelFields[refId][labelName] = {
|
||
|
name: labelName,
|
||
|
type: FieldType.string,
|
||
|
config: {},
|
||
|
values: new ArrayVector(),
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return labelFields;
|
||
|
}
|