From 94801c9c757b7feb2f83c2b3e3c8e28a03a10587 Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Wed, 17 May 2023 08:09:06 +0300 Subject: [PATCH] Sparkline: Sort dataframe (#68007) * Sort sparkline dataframe * Sort frame only if needed * add utils test --- .../grafana-data/src/transformations/index.ts | 2 +- .../src/components/Sparkline/utils.test.ts | 93 +++++++++++++++++++ .../src/components/Sparkline/utils.ts | 51 ++++++---- 3 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 packages/grafana-ui/src/components/Sparkline/utils.test.ts diff --git a/packages/grafana-data/src/transformations/index.ts b/packages/grafana-data/src/transformations/index.ts index f689933c0bd..8b3ee1b7250 100644 --- a/packages/grafana-data/src/transformations/index.ts +++ b/packages/grafana-data/src/transformations/index.ts @@ -16,6 +16,6 @@ export { } from './matchers/nameMatcher'; export type { RenameByRegexTransformerOptions } from './transformers/renameByRegex'; /** @deprecated -- will be removed in future versions */ -export { joinDataFrames as outerJoinDataFrames } from './transformers/joinDataFrames'; +export { joinDataFrames as outerJoinDataFrames, isLikelyAscendingVector } from './transformers/joinDataFrames'; export * from './transformers/histogram'; export { ensureTimeField } from './transformers/convertFieldType'; diff --git a/packages/grafana-ui/src/components/Sparkline/utils.test.ts b/packages/grafana-ui/src/components/Sparkline/utils.test.ts new file mode 100644 index 00000000000..d563d83f334 --- /dev/null +++ b/packages/grafana-ui/src/components/Sparkline/utils.test.ts @@ -0,0 +1,93 @@ +import { FieldSparkline, FieldType } from '@grafana/data'; + +import { preparePlotFrame } from './utils'; + +describe('Prepare Sparkline plot frame', () => { + it('should return sorted array if x-axis numeric', () => { + const sparkline: FieldSparkline = { + x: { + name: 'x', + values: [5, 4, 3, 2, 1], + type: FieldType.number, + config: {}, + }, + y: { + name: 'y', + values: [1, 2, 3, 4, 5], + type: FieldType.number, + config: {}, + }, + }; + + const frame = preparePlotFrame(sparkline); + + expect(frame.fields[0].values).toEqual([1, 2, 3, 4, 5]); + expect(frame.fields[1].values).toEqual([5, 4, 3, 2, 1]); + }); + + it('should return a dataframe with unmodified fields', () => { + const sparkline: FieldSparkline = { + x: { + name: 'x', + values: [1679839200000, 1680444000000, 1681048800000, 1681653600000, 1682258400000], + type: FieldType.time, + config: {}, + }, + y: { + name: 'y', + values: [1, 2, 3, 4, 5], + type: FieldType.number, + config: {}, + }, + }; + + const frame = preparePlotFrame(sparkline); + + expect(frame.fields[0].values).toEqual([1679839200000, 1680444000000, 1681048800000, 1681653600000, 1682258400000]); + expect(frame.fields[1].values).toEqual([1, 2, 3, 4, 5]); + }); + + it('should return a dataframe with sorted fields', () => { + const sparkline: FieldSparkline = { + x: { + name: 'x', + values: [1682258400000, 1681653600000, 1681048800000, 1680444000000, 1679839200000], + type: FieldType.time, + config: {}, + }, + y: { + name: 'y', + values: [1, 2, 3, 4, 5], + type: FieldType.number, + config: {}, + }, + }; + + const frame = preparePlotFrame(sparkline); + + expect(frame.fields[0].values).toEqual([1679839200000, 1680444000000, 1681048800000, 1681653600000, 1682258400000]); + expect(frame.fields[1].values).toEqual([5, 4, 3, 2, 1]); + }); + + it('should return a dataframe with null thresholds applied to sorted fields', () => { + const sparkline: FieldSparkline = { + x: { + name: 'x', + values: [7, 2, 4], + type: FieldType.time, + config: { interval: 1 }, + }, + y: { + name: 'y', + values: [1, 2, 3], + type: FieldType.number, + config: {}, + }, + }; + + const frame = preparePlotFrame(sparkline); + + expect(frame.fields[0].values).toEqual([2, 3, 4, 5, 6, 7]); + expect(frame.fields[1].values).toEqual([2, null, 3, null, null, 1]); + }); +}); diff --git a/packages/grafana-ui/src/components/Sparkline/utils.ts b/packages/grafana-ui/src/components/Sparkline/utils.ts index ff7c0471759..ebe72c90b51 100644 --- a/packages/grafana-ui/src/components/Sparkline/utils.ts +++ b/packages/grafana-ui/src/components/Sparkline/utils.ts @@ -1,4 +1,11 @@ -import { DataFrame, FieldConfig, FieldSparkline, FieldType } from '@grafana/data'; +import { + DataFrame, + FieldConfig, + FieldSparkline, + FieldType, + isLikelyAscendingVector, + sortDataFrame, +} from '@grafana/data'; import { GraphFieldConfig } from '@grafana/schema'; import { applyNullInsertThreshold } from '../GraphNG/nullInsertThreshold'; @@ -13,22 +20,28 @@ export function preparePlotFrame(sparkline: FieldSparkline, config?: FieldConfig ...config, }; - return applyNullInsertThreshold({ - frame: { - refId: 'sparkline', - fields: [ - sparkline.x ?? { - name: '', - values: [...Array(length).keys()], - type: FieldType.number, - config: {}, - }, - { - ...sparkline.y, - config: yFieldConfig, - }, - ], - length, - }, - }); + const xField = sparkline.x ?? { + name: '', + values: [...Array(length).keys()], + type: FieldType.number, + config: {}, + }; + + let frame: DataFrame = { + refId: 'sparkline', + fields: [ + xField, + { + ...sparkline.y, + config: yFieldConfig, + }, + ], + length, + }; + + if (!isLikelyAscendingVector(xField.values)) { + frame = sortDataFrame(frame, 0); + } + + return applyNullInsertThreshold({ frame }); }