mirror of
https://github.com/grafana/grafana.git
synced 2024-11-24 09:50:29 -06:00
TimeseriesPanel: Preserve string fields for data link interpolation (#58424)
* TimeseriesPanel: Preserve string fields for data link interpolation * clean code * Modify tests so that string fields are allowed only when a valid time/number dataframe exists * performance mods * fix wrong length * remove console.log * Check if aligned dataframe has links
This commit is contained in:
parent
1ee52e14d2
commit
0da77201bf
@ -23,4 +23,8 @@ export class SortedVector<T = any> implements Vector<T> {
|
||||
toJSON(): T[] {
|
||||
return vectorToArray(this);
|
||||
}
|
||||
|
||||
getOrderArray(): number[] {
|
||||
return this.order;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Field, PanelProps, getLinksSupplier } from '@grafana/data';
|
||||
import { Field, PanelProps } from '@grafana/data';
|
||||
import { PanelDataErrorView } from '@grafana/runtime';
|
||||
import { TooltipDisplayMode } from '@grafana/schema';
|
||||
import { usePanelContext, TimeSeries, TooltipPlugin, ZoomPlugin, KeyboardPlugin } from '@grafana/ui';
|
||||
@ -14,7 +14,7 @@ import { ExemplarsPlugin } from './plugins/ExemplarsPlugin';
|
||||
import { OutsideRangePlugin } from './plugins/OutsideRangePlugin';
|
||||
import { ThresholdControlsPlugin } from './plugins/ThresholdControlsPlugin';
|
||||
import { TimeSeriesOptions } from './types';
|
||||
import { getTimezones, prepareGraphableFields } from './utils';
|
||||
import { getTimezones, prepareGraphableFields, regenerateLinksSupplier } from './utils';
|
||||
|
||||
interface TimeSeriesPanelProps extends PanelProps<TimeSeriesOptions> {}
|
||||
|
||||
@ -65,15 +65,11 @@ export const TimeSeriesPanel: React.FC<TimeSeriesPanelProps> = ({
|
||||
options={options}
|
||||
>
|
||||
{(config, alignedDataFrame) => {
|
||||
alignedDataFrame.fields.forEach((field) => {
|
||||
field.getLinks = getLinksSupplier(
|
||||
alignedDataFrame,
|
||||
field,
|
||||
field.state!.scopedVars!,
|
||||
replaceVariables,
|
||||
timeZone
|
||||
);
|
||||
});
|
||||
if (
|
||||
alignedDataFrame.fields.filter((f) => f.config.links !== undefined && f.config.links.length > 0).length > 0
|
||||
) {
|
||||
alignedDataFrame = regenerateLinksSupplier(alignedDataFrame, frames, replaceVariables, timeZone);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -43,7 +43,7 @@ describe('prepare timeseries graph', () => {
|
||||
const frames = prepareGraphableFields(input, createTheme());
|
||||
const out = frames![0];
|
||||
|
||||
expect(out.fields.map((f) => f.name)).toEqual(['a', 'c', 'd']);
|
||||
expect(out.fields.map((f) => f.name)).toEqual(['a', 'b', 'c', 'd']);
|
||||
|
||||
const field = out.fields.find((f) => f.name === 'c');
|
||||
expect(field?.display).toBeDefined();
|
||||
|
@ -4,8 +4,11 @@ import {
|
||||
Field,
|
||||
FieldType,
|
||||
getDisplayProcessor,
|
||||
getLinksSupplier,
|
||||
GrafanaTheme2,
|
||||
InterpolateFunction,
|
||||
isBooleanUnit,
|
||||
SortedVector,
|
||||
TimeRange,
|
||||
} from '@grafana/data';
|
||||
import { GraphFieldConfig, LineInterpolation } from '@grafana/schema';
|
||||
@ -60,6 +63,14 @@ export function prepareGraphableFields(
|
||||
),
|
||||
};
|
||||
|
||||
fields.push(copy);
|
||||
break; // ok
|
||||
case FieldType.string:
|
||||
copy = {
|
||||
...field,
|
||||
values: new ArrayVector(field.values.toArray()),
|
||||
};
|
||||
|
||||
fields.push(copy);
|
||||
break; // ok
|
||||
case FieldType.boolean:
|
||||
@ -123,3 +134,46 @@ export function getTimezones(timezones: string[] | undefined, defaultTimezone: s
|
||||
}
|
||||
return timezones.map((v) => (v?.length ? v : defaultTimezone));
|
||||
}
|
||||
|
||||
export function regenerateLinksSupplier(
|
||||
alignedDataFrame: DataFrame,
|
||||
frames: DataFrame[],
|
||||
replaceVariables: InterpolateFunction,
|
||||
timeZone: string
|
||||
): DataFrame {
|
||||
alignedDataFrame.fields.forEach((field) => {
|
||||
const frameIndex = field.state?.origin?.frameIndex;
|
||||
|
||||
if (frameIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const frame = frames[frameIndex];
|
||||
const tempFields: Field[] = [];
|
||||
|
||||
/* check if field has sortedVector values
|
||||
if it does, sort all string fields in the original frame by the order array already used for the field
|
||||
otherwise just attach the fields to the temporary frame used to get the links
|
||||
*/
|
||||
for (const frameField of frame.fields) {
|
||||
if (frameField.type === FieldType.string) {
|
||||
if (field.values instanceof SortedVector) {
|
||||
const copiedField = { ...frameField };
|
||||
copiedField.values = new SortedVector(frameField.values, field.values.getOrderArray());
|
||||
tempFields.push(copiedField);
|
||||
} else {
|
||||
tempFields.push(frameField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tempFrame: DataFrame = {
|
||||
fields: [...alignedDataFrame.fields, ...tempFields],
|
||||
length: alignedDataFrame.fields.length + tempFields.length,
|
||||
};
|
||||
|
||||
field.getLinks = getLinksSupplier(tempFrame, field, field.state!.scopedVars!, replaceVariables, timeZone);
|
||||
});
|
||||
|
||||
return alignedDataFrame;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user