Browse Source

use TableData for timeseries in react

ryan 6 years ago
parent
commit
abf015ace2

+ 3 - 7
packages/grafana-ui/src/types/data.ts

@@ -53,12 +53,9 @@ export interface TimeSeriesVMs {
   length: number;
 }
 
-interface Column {
-  text: string;
-  title?: string;
-  type?: string;
-  sort?: boolean;
-  desc?: boolean;
+export interface Column {
+  text: string; // name
+  type?: 'time' | 'number' | 'string' | 'object';
   filterable?: boolean;
   unit?: string;
 }
@@ -67,5 +64,4 @@ export interface TableData {
   columns: Column[];
   rows: any[];
   type: string;
-  columnMap: any;
 }

+ 2 - 7
packages/grafana-ui/src/types/panel.ts

@@ -1,12 +1,12 @@
 import { ComponentClass } from 'react';
-import { TimeSeries, LoadingState, TableData } from './data';
+import { LoadingState, TableData } from './data';
 import { TimeRange } from './time';
 import { ScopedVars } from './datasource';
 
 export type InterpolateFunction = (value: string, scopedVars?: ScopedVars, format?: string | Function) => string;
 
 export interface PanelProps<T = any> {
-  panelData: PanelData;
+  data?: TableData[];
   timeRange: TimeRange;
   loading: LoadingState;
   options: T;
@@ -16,11 +16,6 @@ export interface PanelProps<T = any> {
   replaceVariables: InterpolateFunction;
 }
 
-export interface PanelData {
-  timeSeries?: TimeSeries[];
-  tableData?: TableData;
-}
-
 export interface PanelEditorProps<T = any> {
   options: T;
   onOptionsChange: (options: T) => void;

+ 11 - 9
packages/grafana-ui/src/utils/processTimeSeries.ts

@@ -4,17 +4,19 @@ import isNumber from 'lodash/isNumber';
 import { colors } from './colors';
 
 // Types
-import { TimeSeries, TimeSeriesVMs, NullValueMode, TimeSeriesValue } from '../types';
+import { TimeSeriesVMs, NullValueMode, TimeSeriesValue, TableData } from '../types';
 
 interface Options {
-  timeSeries: TimeSeries[];
+  data: TableData[];
+  xColumn: number; // Time
+  yColumn: number; // Value
   nullValueMode: NullValueMode;
 }
 
-export function processTimeSeries({ timeSeries, nullValueMode }: Options): TimeSeriesVMs {
-  const vmSeries = timeSeries.map((item, index) => {
+export function processTimeSeries({ data, xColumn, yColumn, nullValueMode }: Options): TimeSeriesVMs {
+  const vmSeries = data.map((item, index) => {
     const colorIndex = index % colors.length;
-    const label = item.target;
+    const label = item.columns[yColumn].text;
     const result = [];
 
     // stat defaults
@@ -42,9 +44,9 @@ export function processTimeSeries({ timeSeries, nullValueMode }: Options): TimeS
     let previousValue = 0;
     let previousDeltaUp = true;
 
-    for (let i = 0; i < item.datapoints.length; i++) {
-      currentValue = item.datapoints[i][0];
-      currentTime = item.datapoints[i][1];
+    for (let i = 0; i < item.rows.length; i++) {
+      currentValue = item.rows[i][yColumn];
+      currentTime = item.rows[i][xColumn];
 
       if (typeof currentTime !== 'number') {
         continue;
@@ -95,7 +97,7 @@ export function processTimeSeries({ timeSeries, nullValueMode }: Options): TimeS
           if (previousValue > currentValue) {
             // counter reset
             previousDeltaUp = false;
-            if (i === item.datapoints.length - 1) {
+            if (i === item.rows.length - 1) {
               // reset on last
               delta += currentValue;
             }

+ 5 - 7
public/app/core/table_model.ts

@@ -1,17 +1,15 @@
 import _ from 'lodash';
+import { Column, TableData } from '@grafana/ui';
 
-interface Column {
-  text: string;
+// This class mutates and uses the extra column fields
+interface ColumnEX extends Column {
   title?: string;
-  type?: string;
   sort?: boolean;
   desc?: boolean;
-  filterable?: boolean;
-  unit?: string;
 }
 
-export default class TableModel {
-  columns: Column[];
+export default class TableModel implements TableData {
+  columns: ColumnEX[];
   rows: any[];
   type: string;
   columnMap: any;

+ 11 - 22
public/app/features/dashboard/dashgrid/DataPanel.tsx

@@ -11,16 +11,16 @@ import {
   DataQueryResponse,
   DataQueryError,
   LoadingState,
-  PanelData,
   TableData,
   TimeRange,
-  TimeSeries,
   ScopedVars,
 } from '@grafana/ui';
 
+import { toTableData } from '../utils/panel';
+
 interface RenderProps {
   loading: LoadingState;
-  panelData: PanelData;
+  data: TableData[];
 }
 
 export interface Props {
@@ -44,7 +44,7 @@ export interface State {
   isFirstLoad: boolean;
   loading: LoadingState;
   response: DataQueryResponse;
-  panelData: PanelData;
+  data?: TableData[];
 }
 
 export class DataPanel extends Component<Props, State> {
@@ -64,7 +64,6 @@ export class DataPanel extends Component<Props, State> {
       response: {
         data: [],
       },
-      panelData: {},
       isFirstLoad: true,
     };
   }
@@ -146,10 +145,12 @@ export class DataPanel extends Component<Props, State> {
         onDataResponse(resp);
       }
 
+      const data = toTableData(resp.data);
+      console.log('Converted:', data);
       this.setState({
         loading: LoadingState.Done,
         response: resp,
-        panelData: this.getPanelData(resp),
+        data,
         isFirstLoad: false,
       });
     } catch (err) {
@@ -172,23 +173,9 @@ export class DataPanel extends Component<Props, State> {
     }
   };
 
-  getPanelData(response: DataQueryResponse) {
-    if (response.data.length > 0 && (response.data[0] as TableData).type === 'table') {
-      return {
-        tableData: response.data[0] as TableData,
-        timeSeries: null,
-      };
-    }
-
-    return {
-      timeSeries: response.data as TimeSeries[],
-      tableData: null,
-    };
-  }
-
   render() {
     const { queries } = this.props;
-    const { loading, isFirstLoad, panelData } = this.state;
+    const { loading, isFirstLoad, data } = this.state;
 
     // do not render component until we have first data
     if (isFirstLoad && (loading === LoadingState.Loading || loading === LoadingState.NotStarted)) {
@@ -203,10 +190,12 @@ export class DataPanel extends Component<Props, State> {
       );
     }
 
+    console.log('RENDER', data);
+
     return (
       <>
         {loading === LoadingState.Loading && this.renderLoadingState()}
-        {this.props.children({ loading, panelData })}
+        {this.props.children({ loading, data })}
       </>
     );
   }

+ 5 - 5
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -18,7 +18,7 @@ import { profiler } from 'app/core/profiler';
 // Types
 import { DashboardModel, PanelModel } from '../state';
 import { PanelPlugin } from 'app/types';
-import { DataQueryResponse, TimeRange, LoadingState, PanelData, DataQueryError } from '@grafana/ui';
+import { DataQueryResponse, TimeRange, LoadingState, TableData, DataQueryError } from '@grafana/ui';
 import { ScopedVars } from '@grafana/ui';
 
 import variables from 'sass/_variables.generated.scss';
@@ -142,7 +142,7 @@ export class PanelChrome extends PureComponent<Props, State> {
     return this.hasPanelSnapshot ? snapshotDataToPanelData(this.props.panel) : null;
   }
 
-  renderPanelPlugin(loading: LoadingState, panelData: PanelData, width: number, height: number): JSX.Element {
+  renderPanelPlugin(loading: LoadingState, data: TableData[], width: number, height: number): JSX.Element {
     const { panel, plugin } = this.props;
     const { timeRange, renderCounter } = this.state;
     const PanelComponent = plugin.exports.reactPanel.panel;
@@ -157,7 +157,7 @@ export class PanelChrome extends PureComponent<Props, State> {
       <div className="panel-content">
         <PanelComponent
           loading={loading}
-          panelData={panelData}
+          data={data}
           timeRange={timeRange}
           options={panel.getOptions(plugin.exports.reactPanel.defaults)}
           width={width - 2 * variables.panelhorizontalpadding}
@@ -188,8 +188,8 @@ export class PanelChrome extends PureComponent<Props, State> {
             onDataResponse={this.onDataResponse}
             onError={this.onDataError}
           >
-            {({ loading, panelData }) => {
-              return this.renderPanelPlugin(loading, panelData, width, height);
+            {({ loading, data }) => {
+              return this.renderPanelPlugin(loading, data, width, height);
             }}
           </DataPanel>
         ) : (

+ 33 - 13
public/app/features/dashboard/utils/panel.ts

@@ -4,8 +4,7 @@ import store from 'app/core/store';
 // Models
 import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
 import { PanelModel } from 'app/features/dashboard/state/PanelModel';
-import { PanelData, TimeRange, TimeSeries } from '@grafana/ui';
-import { TableData } from '@grafana/ui/src';
+import { TableData, TimeRange, TimeSeries } from '@grafana/ui';
 
 // Utils
 import { isString as _isString } from 'lodash';
@@ -173,16 +172,37 @@ export function getResolution(panel: PanelModel): number {
 
 const isTimeSeries = (data: any): data is TimeSeries => data && data.hasOwnProperty('datapoints');
 const isTableData = (data: any): data is TableData => data && data.hasOwnProperty('columns');
-export const snapshotDataToPanelData = (panel: PanelModel): PanelData => {
-  const snapshotData = panel.snapshotData;
-  if (isTimeSeries(snapshotData[0])) {
-    return {
-      timeSeries: snapshotData,
-    } as PanelData;
-  } else if (isTableData(snapshotData[0])) {
-    return {
-      tableData: snapshotData[0],
-    } as PanelData;
+export const snapshotDataToPanelData = (panel: PanelModel): TableData[] => {
+  return toTableData(panel.snapshotData);
+};
+
+export const toTableData = (results: any[]): TableData[] => {
+  if (!results) {
+    return [];
   }
-  throw new Error('snapshotData is invalid:' + snapshotData.toString());
+  return results.map(data => {
+    if (isTableData(data)) {
+      return data as TableData;
+    }
+    if (isTimeSeries(data)) {
+      const ts = data as TimeSeries;
+      return {
+        type: 'timeseries',
+        columns: [
+          {
+            text: ts.target,
+            unit: ts.unit,
+            type: 'number', // Is this really true?
+          },
+          {
+            text: 'time',
+            type: 'time',
+          },
+        ],
+        rows: ts.datapoints,
+      } as TableData;
+    }
+    console.warn('Can not convert', data);
+    throw new Error('Unsupported data format');
+  });
 };

+ 16 - 6
public/app/plugins/panel/gauge/GaugePanel.tsx

@@ -22,29 +22,39 @@ export class GaugePanel extends Component<Props, State> {
     this.state = {
       value: this.findValue(props),
     };
+    console.log('CONSTRUCTOR!', this.props.data);
   }
 
   componentDidUpdate(prevProps: Props) {
-    if (this.props.panelData !== prevProps.panelData) {
+    console.log('UPDATE', this.props.data);
+
+    if (this.props.data !== prevProps.data) {
       this.setState({ value: this.findValue(this.props) });
     }
   }
 
   findValue(props: Props): number | null {
-    const { panelData, options } = props;
+    const { data, options } = props;
     const { valueOptions } = options;
 
-    if (panelData.timeSeries) {
+    console.log('FIND VALUE', data);
+
+    if (data) {
+      // For now, assume timeseries defaults
+      const xColumn = 1; // time
+      const yColumn = 0; // value
       const vmSeries = processTimeSeries({
-        timeSeries: panelData.timeSeries,
+        data,
+        xColumn,
+        yColumn,
         nullValueMode: NullValueMode.Null,
       });
 
+      console.log('GOT', vmSeries);
+
       if (vmSeries[0]) {
         return vmSeries[0].stats[valueOptions.stat];
       }
-    } else if (panelData.tableData) {
-      return panelData.tableData.rows[0].find(prop => prop > 0);
     }
     return null;
   }

+ 8 - 3
public/app/plugins/panel/graph2/GraphPanel.tsx

@@ -16,13 +16,18 @@ interface Props extends PanelProps<Options> {}
 
 export class GraphPanel extends PureComponent<Props> {
   render() {
-    const { panelData, timeRange, width, height } = this.props;
+    const { data, timeRange, width, height } = this.props;
     const { showLines, showBars, showPoints } = this.props.options;
 
     let vmSeries: TimeSeriesVMs;
-    if (panelData.timeSeries) {
+    if (data) {
+      // For now, assume timeseries defaults
+      const xColumn = 1; // time
+      const yColumn = 0; // value
       vmSeries = processTimeSeries({
-        timeSeries: panelData.timeSeries,
+        data,
+        xColumn,
+        yColumn,
         nullValueMode: NullValueMode.Ignore,
       });
     }