From c4a503dbc58a16a429ba8e3098da7e480ec07e65 Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 20 Mar 2019 09:07:11 -0700 Subject: [PATCH] show all columns in singlestats --- .../grafana-ui/src/utils/processTableData.ts | 52 +++++++++++++++++++ .../panel/singlestat2/SingleStatPanel.tsx | 32 +++++++++--- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/packages/grafana-ui/src/utils/processTableData.ts b/packages/grafana-ui/src/utils/processTableData.ts index d4a91efd622..3efbbe740ae 100644 --- a/packages/grafana-ui/src/utils/processTableData.ts +++ b/packages/grafana-ui/src/utils/processTableData.ts @@ -4,6 +4,7 @@ import Papa, { ParseError, ParseMeta } from 'papaparse'; // Types import { TableData, Column, TimeSeries } from '../types'; +import { isString } from 'util'; // Subset of all parse options export interface TableParseOptions { @@ -146,6 +147,57 @@ function convertTimeSeriesToTableData(timeSeries: TimeSeries): TableData { }; } +/** + * @returns a table Returns a copy of the table with the best guess for each column type + */ +export const guessColumnTypes = (table: TableData): TableData => { + let changed = false; + const columns = table.columns.map((column, index) => { + if (!column.type) { + // 1. Use the column name to guess + if (column.text) { + const name = column.text.toLowerCase(); + if (name === 'date' || name === 'time') { + changed = true; + return { + ...column, + type: 'time', + }; + } + } + + // 2. Check the first non-null value + for (let i = 0; i < table.rows.length; i++) { + const v = table.rows[i][index]; + if (v !== null) { + let type; + if (isNumber(v)) { + type = 'number'; + } else if (isString(v)) { + type = 'string'; + } + if (type) { + changed = true; + return { + ...column, + type, + }; + } + break; + } + } + } + return column; + }); + if (changed) { + return { + ...table, + columns, + }; + } + return table; +}; + export const isTableData = (data: any): data is TableData => data && data.hasOwnProperty('columns'); export const toTableData = (results?: any[]): TableData[] => { diff --git a/public/app/plugins/panel/singlestat2/SingleStatPanel.tsx b/public/app/plugins/panel/singlestat2/SingleStatPanel.tsx index 1193a031c94..eb121f9e44a 100644 --- a/public/app/plugins/panel/singlestat2/SingleStatPanel.tsx +++ b/public/app/plugins/panel/singlestat2/SingleStatPanel.tsx @@ -4,7 +4,7 @@ import React, { PureComponent, CSSProperties } from 'react'; // Types import { SingleStatOptions, SingleStatBaseOptions } from './types'; -import { DisplayValue, PanelProps, processTimeSeries, NullValueMode } from '@grafana/ui'; +import { DisplayValue, PanelProps, processTimeSeries, NullValueMode, guessColumnTypes } from '@grafana/ui'; import { config } from 'app/core/config'; import { getDisplayProcessor } from '@grafana/ui'; import { ProcessedValuesRepeater } from './ProcessedValuesRepeater'; @@ -24,13 +24,31 @@ export const getSingleStatValues = (props: PanelProps): D theme: config.theme, }); - return processTimeSeries({ - data, - nullValueMode: NullValueMode.Null, - }).map((series, index) => { - const value = stat !== 'name' ? series.stats[stat] : series.label; - return processor(value); + const values: DisplayValue[] = []; + data.forEach(t => { + const table = guessColumnTypes(t); + for (let i = 0; i < table.columns.length; i++) { + const column = table.columns[i]; + + // Show all columns that are not 'time' + if (column.type === 'number') { + const series = processTimeSeries({ + data: [table], + xColumn: i, + yColumn: i, + nullValueMode: NullValueMode.Null, + })[0]; + + const value = stat !== 'name' ? series.stats[stat] : series.label; + values.push(processor(value)); + } + } }); + + if (values.length === 0) { + throw { message: 'Could not find numeric data' }; + } + return values; }; export class SingleStatPanel extends PureComponent> {