Просмотр исходного кода

add stat picker to single stat

ryan 6 лет назад
Родитель
Сommit
658f419cab

+ 1 - 1
packages/grafana-ui/src/components/StatsPicker/StatsPicker.tsx

@@ -69,7 +69,7 @@ export class StatsPicker extends PureComponent<Props> {
       return {
       return {
         value: s.id,
         value: s.id,
         label: s.name,
         label: s.name,
-        desctipiton: s.description,
+        description: s.description,
       };
       };
     });
     });
 
 

+ 1 - 0
packages/grafana-ui/src/components/index.ts

@@ -27,6 +27,7 @@ export { Switch } from './Switch/Switch';
 export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
 export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
 export { PieChart, PieChartDataPoint, PieChartType } from './PieChart/PieChart';
 export { PieChart, PieChartDataPoint, PieChartType } from './PieChart/PieChart';
 export { UnitPicker } from './UnitPicker/UnitPicker';
 export { UnitPicker } from './UnitPicker/UnitPicker';
+export { StatsPicker } from './StatsPicker/StatsPicker';
 export { Input, InputStatus } from './Input/Input';
 export { Input, InputStatus } from './Input/Input';
 
 
 // Visualizations
 // Visualizations

+ 1 - 0
packages/grafana-ui/src/utils/index.ts

@@ -5,6 +5,7 @@ export * from './colors';
 export * from './namedColorsPalette';
 export * from './namedColorsPalette';
 export * from './thresholds';
 export * from './thresholds';
 export * from './string';
 export * from './string';
+export * from './statsCalculator';
 export * from './displayValue';
 export * from './displayValue';
 export * from './deprecationWarning';
 export * from './deprecationWarning';
 export { getMappedValue } from './valueMappings';
 export { getMappedValue } from './valueMappings';

+ 14 - 3
packages/grafana-ui/src/utils/statsCalculator.test.ts

@@ -41,7 +41,7 @@ describe('Stats Calculators', () => {
 
 
   it('should calculate basic stats', () => {
   it('should calculate basic stats', () => {
     const stats = calculateStats({
     const stats = calculateStats({
-      data: basicTable,
+      table: basicTable,
       columnIndex: 0,
       columnIndex: 0,
       stats: ['first', 'last', 'mean'],
       stats: ['first', 'last', 'mean'],
     });
     });
@@ -58,7 +58,7 @@ describe('Stats Calculators', () => {
 
 
   it('should support a single stat also', () => {
   it('should support a single stat also', () => {
     const stats = calculateStats({
     const stats = calculateStats({
-      data: basicTable,
+      table: basicTable,
       columnIndex: 0,
       columnIndex: 0,
       stats: ['first'],
       stats: ['first'],
     });
     });
@@ -70,7 +70,7 @@ describe('Stats Calculators', () => {
 
 
   it('should get non standard stats', () => {
   it('should get non standard stats', () => {
     const stats = calculateStats({
     const stats = calculateStats({
-      data: basicTable,
+      table: basicTable,
       columnIndex: 0,
       columnIndex: 0,
       stats: [StatID.distinctCount, StatID.changeCount],
       stats: [StatID.distinctCount, StatID.changeCount],
     });
     });
@@ -78,4 +78,15 @@ describe('Stats Calculators', () => {
     expect(stats.distinctCount).toEqual(2);
     expect(stats.distinctCount).toEqual(2);
     expect(stats.changeCount).toEqual(1);
     expect(stats.changeCount).toEqual(1);
   });
   });
+
+  it('should calculate step', () => {
+    const stats = calculateStats({
+      table: { columns: [{ text: 'A' }], rows: [[100], [200], [300], [400]] },
+      columnIndex: 0,
+      stats: [StatID.step, StatID.delta],
+    });
+
+    expect(stats.step).toEqual(100);
+    expect(stats.delta).toEqual(300);
+  });
 });
 });

+ 15 - 14
packages/grafana-ui/src/utils/statsCalculator.ts

@@ -29,7 +29,7 @@ export interface ColumnStats {
 }
 }
 
 
 // Internal function
 // Internal function
-type StatCalculator = (data: TableData, columnIndex: number, ignoreNulls: boolean, nullAsZero: boolean) => ColumnStats;
+type StatCalculator = (table: TableData, columnIndex: number, ignoreNulls: boolean, nullAsZero: boolean) => ColumnStats;
 
 
 export interface StatCalculatorInfo {
 export interface StatCalculatorInfo {
   id: string;
   id: string;
@@ -64,7 +64,7 @@ export function getStatsCalculators(ids?: string[]): StatCalculatorInfo[] {
 }
 }
 
 
 export interface CalculateStatsOptions {
 export interface CalculateStatsOptions {
-  data: TableData;
+  table: TableData;
   columnIndex: number;
   columnIndex: number;
   stats: string[]; // The stats to calculate
   stats: string[]; // The stats to calculate
   nullValueMode?: NullValueMode;
   nullValueMode?: NullValueMode;
@@ -74,7 +74,7 @@ export interface CalculateStatsOptions {
  * @returns an object with a key for each selected stat
  * @returns an object with a key for each selected stat
  */
  */
 export function calculateStats(options: CalculateStatsOptions): ColumnStats {
 export function calculateStats(options: CalculateStatsOptions): ColumnStats {
-  const { data, columnIndex, stats, nullValueMode } = options;
+  const { table, columnIndex, stats, nullValueMode } = options;
 
 
   if (!stats || stats.length < 1) {
   if (!stats || stats.length < 1) {
     return {};
     return {};
@@ -84,7 +84,7 @@ export function calculateStats(options: CalculateStatsOptions): ColumnStats {
 
 
   // Return early for empty tables
   // Return early for empty tables
   // This lets the concrete implementations assume at least one row
   // This lets the concrete implementations assume at least one row
-  if (!data.rows || data.rows.length < 1) {
+  if (!table.rows || table.rows.length < 1) {
     const stats = {} as ColumnStats;
     const stats = {} as ColumnStats;
     queue.forEach(stat => {
     queue.forEach(stat => {
       stats[stat.id] = stat.emptyInputResult !== null ? stat.emptyInputResult : null;
       stats[stat.id] = stat.emptyInputResult !== null ? stat.emptyInputResult : null;
@@ -97,19 +97,19 @@ export function calculateStats(options: CalculateStatsOptions): ColumnStats {
 
 
   // Avoid calculating all the standard stats if possible
   // Avoid calculating all the standard stats if possible
   if (queue.length === 1 && queue[0].calculator) {
   if (queue.length === 1 && queue[0].calculator) {
-    return queue[0].calculator(data, columnIndex, ignoreNulls, nullAsZero);
+    return queue[0].calculator(table, columnIndex, ignoreNulls, nullAsZero);
   }
   }
 
 
   // For now everything can use the standard stats
   // For now everything can use the standard stats
-  let values = standardStatsStat(data, columnIndex, ignoreNulls, nullAsZero);
-  queue.forEach(calc => {
+  let values = standardStatsStat(table, columnIndex, ignoreNulls, nullAsZero);
+  for (const calc of queue) {
     if (!values.hasOwnProperty(calc.id) && calc.calculator) {
     if (!values.hasOwnProperty(calc.id) && calc.calculator) {
       values = {
       values = {
         ...values,
         ...values,
-        ...calc.calculator(data, columnIndex, ignoreNulls, nullAsZero),
+        ...calc.calculator(table, columnIndex, ignoreNulls, nullAsZero),
       };
       };
     }
     }
-  });
+  }
   return values;
   return values;
 }
 }
 
 
@@ -141,7 +141,7 @@ function getById(id: string): StatCalculatorInfo | undefined {
       { id: StatID.first, name: 'First', description: 'First Value', standard: true, calculator: calculateFirst },
       { id: StatID.first, name: 'First', description: 'First Value', standard: true, calculator: calculateFirst },
       { id: StatID.min, name: 'Min', description: 'Minimum Value', standard: true },
       { id: StatID.min, name: 'Min', description: 'Minimum Value', standard: true },
       { id: StatID.max, name: 'Max', description: 'Maximum Value', standard: true },
       { id: StatID.max, name: 'Max', description: 'Maximum Value', standard: true },
-      { id: StatID.mean, name: 'Mean', description: 'Average Value', standard: true },
+      { id: StatID.mean, name: 'Mean', description: 'Average Value', standard: true, alias: 'avg' },
       {
       {
         id: StatID.sum,
         id: StatID.sum,
         name: 'Total',
         name: 'Total',
@@ -241,7 +241,7 @@ function standardStatsStat(
     range: null,
     range: null,
     diff: null,
     diff: null,
     delta: 0,
     delta: 0,
-    step: 0,
+    step: Number.MAX_VALUE,
 
 
     // Just used for calcutations -- not exposed as a stat
     // Just used for calcutations -- not exposed as a stat
     previousDeltaUp: true,
     previousDeltaUp: true,
@@ -260,8 +260,6 @@ function standardStatsStat(
     }
     }
 
 
     if (currentValue !== null) {
     if (currentValue !== null) {
-      stats.last = currentValue;
-
       const isFirst = stats.first === null;
       const isFirst = stats.first === null;
       if (isFirst) {
       if (isFirst) {
         stats.first = currentValue;
         stats.first = currentValue;
@@ -324,6 +322,10 @@ function standardStatsStat(
     stats.min = null;
     stats.min = null;
   }
   }
 
 
+  if (stats.step === Number.MAX_VALUE) {
+    stats.step = null;
+  }
+
   if (stats.nonNullCount > 0) {
   if (stats.nonNullCount > 0) {
     stats.mean = stats.sum! / stats.nonNullCount;
     stats.mean = stats.sum! / stats.nonNullCount;
   }
   }
@@ -342,7 +344,6 @@ function standardStatsStat(
 }
 }
 
 
 function calculateFirst(data: TableData, columnIndex: number, ignoreNulls: boolean, nullAsZero: boolean): ColumnStats {
 function calculateFirst(data: TableData, columnIndex: number, ignoreNulls: boolean, nullAsZero: boolean): ColumnStats {
-  console.log('FIRST', data);
   return { first: data.rows[0][columnIndex] };
   return { first: data.rows[0][columnIndex] };
 }
 }
 
 

+ 6 - 0
public/app/features/dashboard/dashgrid/DashboardPanel.tsx

@@ -98,6 +98,12 @@ export class DashboardPanel extends PureComponent<Props, State> {
           }
           }
           panel.changeType(pluginId, hook);
           panel.changeType(pluginId, hook);
         }
         }
+      } else if (plugin.exports && plugin.exports.reactPanel) {
+        const hook = plugin.exports.reactPanel.panelTypeChangedHook;
+        if (hook) {
+          panel.options = hook(panel.options || {}, null, null);
+          console.log('OPITONS', pluginId, panel);
+        }
       }
       }
 
 
       this.setState({ plugin, angularPanel: null });
       this.setState({ plugin, angularPanel: null });

+ 2 - 2
public/app/plugins/panel/bargauge/types.ts

@@ -1,4 +1,4 @@
-import { VizOrientation, SelectOptionItem } from '@grafana/ui';
+import { VizOrientation, SelectOptionItem, StatID } from '@grafana/ui';
 import { SingleStatBaseOptions } from '../singlestat2/types';
 import { SingleStatBaseOptions } from '../singlestat2/types';
 
 
 export interface BarGaugeOptions extends SingleStatBaseOptions {
 export interface BarGaugeOptions extends SingleStatBaseOptions {
@@ -25,7 +25,7 @@ export const defaults: BarGaugeOptions = {
   orientation: VizOrientation.Horizontal,
   orientation: VizOrientation.Horizontal,
   valueOptions: {
   valueOptions: {
     unit: 'none',
     unit: 'none',
-    stat: 'avg',
+    stat: StatID.mean,
     prefix: '',
     prefix: '',
     suffix: '',
     suffix: '',
     decimals: null,
     decimals: null,

+ 2 - 2
public/app/plugins/panel/gauge/types.ts

@@ -1,5 +1,5 @@
 import { SingleStatBaseOptions } from '../singlestat2/types';
 import { SingleStatBaseOptions } from '../singlestat2/types';
-import { VizOrientation } from '@grafana/ui';
+import { VizOrientation, StatID } from '@grafana/ui';
 
 
 export interface GaugeOptions extends SingleStatBaseOptions {
 export interface GaugeOptions extends SingleStatBaseOptions {
   maxValue: number;
   maxValue: number;
@@ -17,7 +17,7 @@ export const defaults: GaugeOptions = {
     prefix: '',
     prefix: '',
     suffix: '',
     suffix: '',
     decimals: null,
     decimals: null,
-    stat: 'avg',
+    stat: StatID.mean,
     unit: 'none',
     unit: 'none',
   },
   },
   valueMappings: [],
   valueMappings: [],

+ 16 - 8
public/app/plugins/panel/singlestat2/SingleStatPanel.tsx

@@ -4,7 +4,7 @@ import React, { PureComponent, CSSProperties } from 'react';
 // Types
 // Types
 import { SingleStatOptions, SingleStatBaseOptions } from './types';
 import { SingleStatOptions, SingleStatBaseOptions } from './types';
 
 
-import { DisplayValue, PanelProps, processTimeSeries, NullValueMode } from '@grafana/ui';
+import { DisplayValue, PanelProps, NullValueMode, calculateStats } from '@grafana/ui';
 import { config } from 'app/core/config';
 import { config } from 'app/core/config';
 import { getDisplayProcessor } from '@grafana/ui';
 import { getDisplayProcessor } from '@grafana/ui';
 import { ProcessedValuesRepeater } from './ProcessedValuesRepeater';
 import { ProcessedValuesRepeater } from './ProcessedValuesRepeater';
@@ -14,7 +14,7 @@ export const getSingleStatValues = (props: PanelProps<SingleStatBaseOptions>): D
   const { valueOptions, valueMappings } = options;
   const { valueOptions, valueMappings } = options;
   const { unit, decimals, stat } = valueOptions;
   const { unit, decimals, stat } = valueOptions;
 
 
-  const processor = getDisplayProcessor({
+  const display = getDisplayProcessor({
     unit,
     unit,
     decimals,
     decimals,
     mappings: valueMappings,
     mappings: valueMappings,
@@ -24,12 +24,20 @@ export const getSingleStatValues = (props: PanelProps<SingleStatBaseOptions>): D
     theme: config.theme,
     theme: config.theme,
   });
   });
 
 
-  return processTimeSeries({
-    data,
-    nullValueMode: NullValueMode.Null,
-  }).map((series, index) => {
-    const value = stat !== 'name' ? series.stats[stat] : series.label;
-    return processor(value);
+  return data.map(table => {
+    // Support last_time?  Add that to the migration?  last, but differnt column
+    if (stat === 'name') {
+      // Should not really be possible anymore?
+      return display(table.name);
+    }
+    return display(
+      calculateStats({
+        table,
+        columnIndex: 0, // Hardcoded for now!
+        stats: [stat], // The stats to calculate
+        nullValueMode: NullValueMode.Null,
+      })[stat]
+    );
   });
   });
 };
 };
 
 

+ 15 - 20
public/app/plugins/panel/singlestat2/SingleStatValueEditor.tsx

@@ -2,25 +2,11 @@
 import React, { PureComponent } from 'react';
 import React, { PureComponent } from 'react';
 
 
 // Components
 // Components
-import { FormField, FormLabel, PanelOptionsGroup, Select, UnitPicker } from '@grafana/ui';
+import { FormField, FormLabel, PanelOptionsGroup, StatsPicker, UnitPicker, StatID } from '@grafana/ui';
 
 
 // Types
 // Types
 import { SingleStatValueOptions } from './types';
 import { SingleStatValueOptions } from './types';
 
 
-const statOptions = [
-  { value: 'min', label: 'Min' },
-  { value: 'max', label: 'Max' },
-  { value: 'avg', label: 'Average' },
-  { value: 'current', label: 'Current' },
-  { value: 'total', label: 'Total' },
-  { value: 'name', label: 'Name' },
-  { value: 'first', label: 'First' },
-  { value: 'delta', label: 'Delta' },
-  { value: 'diff', label: 'Difference' },
-  { value: 'range', label: 'Range' },
-  { value: 'last_time', label: 'Time of last point' },
-];
-
 const labelWidth = 6;
 const labelWidth = 6;
 
 
 export interface Props {
 export interface Props {
@@ -30,7 +16,12 @@ export interface Props {
 
 
 export class SingleStatValueEditor extends PureComponent<Props> {
 export class SingleStatValueEditor extends PureComponent<Props> {
   onUnitChange = unit => this.props.onChange({ ...this.props.options, unit: unit.value });
   onUnitChange = unit => this.props.onChange({ ...this.props.options, unit: unit.value });
-  onStatChange = stat => this.props.onChange({ ...this.props.options, stat: stat.value });
+
+  onStatsChange = stats => {
+    console.log('SELECTED', stats);
+    const stat = stats[0] || StatID.mean;
+    this.props.onChange({ ...this.props.options, stat });
+  };
 
 
   onDecimalChange = event => {
   onDecimalChange = event => {
     if (!isNaN(event.target.value)) {
     if (!isNaN(event.target.value)) {
@@ -57,15 +48,19 @@ export class SingleStatValueEditor extends PureComponent<Props> {
       decimalsString = decimals.toString();
       decimalsString = decimals.toString();
     }
     }
 
 
+    console.log('xxx', stat);
+
     return (
     return (
       <PanelOptionsGroup title="Value">
       <PanelOptionsGroup title="Value">
         <div className="gf-form">
         <div className="gf-form">
           <FormLabel width={labelWidth}>Stat</FormLabel>
           <FormLabel width={labelWidth}>Stat</FormLabel>
-          <Select
+          <StatsPicker
             width={12}
             width={12}
-            options={statOptions}
-            onChange={this.onStatChange}
-            value={statOptions.find(option => option.value === stat)}
+            placeholder="Choose Stat"
+            defaultStat={StatID.mean}
+            allowMultiple={false}
+            stats={[stat]}
+            onChange={this.onStatsChange}
           />
           />
         </div>
         </div>
         <div className="gf-form">
         <div className="gf-form">

+ 8 - 1
public/app/plugins/panel/singlestat2/module.tsx

@@ -1,4 +1,4 @@
-import { ReactPanelPlugin } from '@grafana/ui';
+import { ReactPanelPlugin, getStatsCalculators } from '@grafana/ui';
 import { SingleStatOptions, defaults, SingleStatBaseOptions } from './types';
 import { SingleStatOptions, defaults, SingleStatBaseOptions } from './types';
 import { SingleStatPanel } from './SingleStatPanel';
 import { SingleStatPanel } from './SingleStatPanel';
 import cloneDeep from 'lodash/cloneDeep';
 import cloneDeep from 'lodash/cloneDeep';
@@ -21,6 +21,13 @@ export const singleStatBaseOptionsCheck = (
     });
     });
   }
   }
 
 
+  // 6.1 renamed some stats, This makes sure they are up to date
+  // avg -> mean, current -> last, total -> sum
+  const { valueOptions } = options;
+  if (valueOptions && valueOptions.stat) {
+    valueOptions.stat = getStatsCalculators([valueOptions.stat]).map(s => s.id)[0];
+    console.log('CHANGED', valueOptions);
+  }
   return options;
   return options;
 };
 };
 
 

+ 2 - 2
public/app/plugins/panel/singlestat2/types.ts

@@ -1,4 +1,4 @@
-import { VizOrientation, ValueMapping, Threshold } from '@grafana/ui';
+import { VizOrientation, ValueMapping, Threshold, StatID } from '@grafana/ui';
 
 
 export interface SingleStatBaseOptions {
 export interface SingleStatBaseOptions {
   valueMappings: ValueMapping[];
   valueMappings: ValueMapping[];
@@ -24,7 +24,7 @@ export const defaults: SingleStatOptions = {
     prefix: '',
     prefix: '',
     suffix: '',
     suffix: '',
     decimals: null,
     decimals: null,
-    stat: 'avg',
+    stat: StatID.mean,
     unit: 'none',
     unit: 'none',
   },
   },
   valueMappings: [],
   valueMappings: [],