Commit 03951c00 by Ryan McKinley Committed by Torkel Ödegaard

Feat: Angular panels & SeriesData to Table/TimeSeries (#16266)

Similar to how the react panels make sure all data is SeriesData before passing it to the react panels, this makes sure SeriesData is converted to TableData|TimeSeries before passing it to the angular panels.

It also changes the typing to encourage using SeriesData for future development
parent 236074ea
...@@ -2,7 +2,12 @@ import { TimeRange, RawTimeRange } from './time'; ...@@ -2,7 +2,12 @@ import { TimeRange, RawTimeRange } from './time';
import { PluginMeta } from './plugin'; import { PluginMeta } from './plugin';
import { TableData, TimeSeries, SeriesData } from './data'; import { TableData, TimeSeries, SeriesData } from './data';
export type DataQueryResponseData = TimeSeries | TableData | SeriesData | any; /**
* Starting in v6.2 SeriesData can represent both TimeSeries and TableData
*/
export type LegacyResponseData = TimeSeries | TableData | any;
export type DataQueryResponseData = SeriesData | LegacyResponseData;
export interface DataQueryResponse { export interface DataQueryResponse {
data: DataQueryResponseData[]; data: DataQueryResponseData[];
......
import { toSeriesData, guessFieldTypes, guessFieldTypeFromValue } from './processSeriesData'; import {
import { FieldType } from '../types/data'; isSeriesData,
toLegacyResponseData,
isTableData,
toSeriesData,
guessFieldTypes,
guessFieldTypeFromValue,
} from './processSeriesData';
import { FieldType, TimeSeries } from '../types/data';
import moment from 'moment'; import moment from 'moment';
describe('toSeriesData', () => { describe('toSeriesData', () => {
...@@ -63,3 +70,33 @@ describe('toSeriesData', () => { ...@@ -63,3 +70,33 @@ describe('toSeriesData', () => {
expect(norm.fields[3].type).toBe(FieldType.time); // based on name expect(norm.fields[3].type).toBe(FieldType.time); // based on name
}); });
}); });
describe('SerisData backwards compatibility', () => {
it('converts TimeSeries to series and back again', () => {
const timeseries = {
target: 'Field Name',
datapoints: [[100, 1], [200, 2]],
};
const series = toSeriesData(timeseries);
expect(isSeriesData(timeseries)).toBeFalsy();
expect(isSeriesData(series)).toBeTruthy();
const roundtrip = toLegacyResponseData(series) as TimeSeries;
expect(isSeriesData(roundtrip)).toBeFalsy();
expect(roundtrip.target).toBe(timeseries.target);
});
it('converts TableData to series and back again', () => {
const table = {
columns: [{ text: 'a', unit: 'ms' }, { text: 'b', unit: 'zz' }, { text: 'c', unit: 'yy' }],
rows: [[100, 1, 'a'], [200, 2, 'a']],
};
const series = toSeriesData(table);
expect(isTableData(table)).toBeTruthy();
expect(isSeriesData(series)).toBeTruthy();
const roundtrip = toLegacyResponseData(series) as TimeSeries;
expect(isTableData(roundtrip)).toBeTruthy();
expect(roundtrip).toMatchObject(table);
});
});
...@@ -157,6 +157,32 @@ export const toSeriesData = (data: any): SeriesData => { ...@@ -157,6 +157,32 @@ export const toSeriesData = (data: any): SeriesData => {
throw new Error('Unsupported data format'); throw new Error('Unsupported data format');
}; };
export const toLegacyResponseData = (series: SeriesData): TimeSeries | TableData => {
const { fields, rows } = series;
if (fields.length === 2) {
const type = guessFieldTypeFromTable(series, 1);
if (type === FieldType.time) {
return {
target: fields[0].name || series.name,
datapoints: rows,
unit: fields[0].unit,
} as TimeSeries;
}
}
return {
columns: fields.map(f => {
return {
text: f.name,
filterable: f.filterable,
unit: f.unit,
};
}),
rows,
};
};
export function sortSeriesData(data: SeriesData, sortIndex?: number, reverse = false): SeriesData { export function sortSeriesData(data: SeriesData, sortIndex?: number, reverse = false): SeriesData {
if (isNumber(sortIndex)) { if (isNumber(sortIndex)) {
const copy = { const copy = {
......
...@@ -6,6 +6,7 @@ import { PanelCtrl } from 'app/features/panel/panel_ctrl'; ...@@ -6,6 +6,7 @@ import { PanelCtrl } from 'app/features/panel/panel_ctrl';
import { getExploreUrl } from 'app/core/utils/explore'; import { getExploreUrl } from 'app/core/utils/explore';
import { applyPanelTimeOverrides, getResolution } from 'app/features/dashboard/utils/panel'; import { applyPanelTimeOverrides, getResolution } from 'app/features/dashboard/utils/panel';
import { ContextSrv } from 'app/core/services/context_srv'; import { ContextSrv } from 'app/core/services/context_srv';
import { toLegacyResponseData, isSeriesData } from '@grafana/ui';
class MetricsPanelCtrl extends PanelCtrl { class MetricsPanelCtrl extends PanelCtrl {
scope: any; scope: any;
...@@ -188,7 +189,14 @@ class MetricsPanelCtrl extends PanelCtrl { ...@@ -188,7 +189,14 @@ class MetricsPanelCtrl extends PanelCtrl {
result = { data: [] }; result = { data: [] };
} }
this.events.emit('data-received', result.data); // Make sure the data is TableData | TimeSeries
const data = result.data.map(v => {
if (isSeriesData(v)) {
return toLegacyResponseData(v);
}
return v;
});
this.events.emit('data-received', data);
} }
handleDataStream(stream) { handleDataStream(stream) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment