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

+ 0 - 187
packages/grafana-ui/src/components/DataTable/DataTable.tsx

@@ -1,187 +0,0 @@
-// Libraries
-import React, { Component, ReactNode } from 'react';
-import {
-  Table,
-  SortDirectionType,
-  SortIndicator,
-  Column,
-  TableHeaderProps,
-  TableCellProps,
-  Index,
-} from 'react-virtualized';
-import { Themeable } from '../../types/theme';
-
-import { sortTableData } from '../../utils/processTimeSeries';
-
-// Types
-import { TableData, InterpolateFunction } from '../../types/index';
-import { TableRenderer } from './renderer';
-
-// Made to match the existing (untyped) settings in the angular table
-export interface ColumnStyle {
-  pattern?: string;
-
-  alias?: string;
-  colorMode?: string;
-  colors?: any[];
-  decimals?: number;
-  thresholds?: any[];
-  type?: 'date' | 'number' | 'string' | 'hidden';
-  unit?: string;
-  dateFormat?: string;
-  sanitize?: boolean;
-  mappingType?: any;
-  valueMaps?: any;
-  rangeMaps?: any;
-
-  link?: any;
-  linkUrl?: any;
-  linkTooltip?: any;
-  linkTargetBlank?: boolean;
-
-  preserveFormat?: boolean;
-}
-
-interface Props extends Themeable {
-  data?: TableData;
-  showHeader: boolean;
-  styles: ColumnStyle[];
-  replaceVariables: InterpolateFunction;
-  width: number;
-  height: number;
-}
-
-interface State {
-  sortBy?: number;
-  sortDirection?: SortDirectionType;
-  data?: TableData;
-}
-
-export class DataTable extends Component<Props, State> {
-  renderer: TableRenderer;
-
-  static defaultProps = {
-    showHeader: true,
-  };
-
-  constructor(props: Props) {
-    super(props);
-
-    this.state = {
-      data: props.data,
-    };
-
-    this.renderer = this.createRenderer();
-  }
-
-  componentDidUpdate(prevProps: Props, prevState: State) {
-    const { data, styles } = this.props;
-    const { sortBy, sortDirection } = this.state;
-    const dataChanged = data !== prevProps.data;
-
-    // Update the renderer if options change
-    if (dataChanged || styles !== prevProps.styles) {
-      this.renderer = this.createRenderer();
-    }
-
-    // Update the data when data or sort changes
-    if (dataChanged || sortBy !== prevState.sortBy || sortDirection !== prevState.sortDirection) {
-      const sorted = data ? sortTableData(data, sortBy, sortDirection === 'DESC') : data;
-      this.setState({ data: sorted });
-    }
-  }
-
-  // styles: ColumnStyle[],
-  // schema: Column[],
-  // rowGetter: (info: Index) => any[], // matches the table rowGetter
-  // replaceVariables: InterpolateFunction,
-  // isUTC?: boolean, // TODO? get UTC from props?
-  // theme?: GrafanaThemeType | undefined,
-
-  createRenderer(): TableRenderer {
-    const { styles, replaceVariables, theme } = this.props;
-    const { data } = this.state;
-
-    return new TableRenderer({
-      styles,
-      schema: data ? data.columns : [],
-      rowGetter: this.rowGetter,
-      replaceVariables,
-      isUTC: false,
-      theme: theme.type,
-    });
-  }
-
-  rowGetter = ({ index }: Index) => {
-    return this.state.data!.rows[index];
-  };
-
-  doSort = (info: any) => {
-    let dir = info.sortDirection;
-    let sort = info.sortBy;
-    if (sort !== this.state.sortBy) {
-      dir = 'DESC';
-    } else if (dir === 'DESC') {
-      dir = 'ASC';
-    } else {
-      sort = null;
-    }
-    this.setState({ sortBy: sort, sortDirection: dir });
-  };
-
-  headerRenderer = (header: TableHeaderProps): ReactNode => {
-    const dataKey = header.dataKey as any; // types say string, but it is number!
-    const { data, sortBy, sortDirection } = this.state;
-    const col = data!.columns[dataKey];
-
-    return (
-      <div>
-        {col.text} {sortBy === dataKey && <SortIndicator sortDirection={sortDirection} />}
-      </div>
-    );
-  };
-
-  cellRenderer = (cell: TableCellProps) => {
-    const { columnIndex, rowIndex } = cell;
-    const row = this.state.data!.rows[rowIndex];
-    const val = row[columnIndex];
-    return this.renderer.renderCell(columnIndex, rowIndex, val);
-  };
-
-  render() {
-    const { width, height, showHeader } = this.props;
-    const { data } = this.props;
-    if (!data) {
-      return <div>NO Data</div>;
-    }
-    return (
-      <Table
-        disableHeader={!showHeader}
-        headerHeight={30}
-        height={height}
-        overscanRowCount={10}
-        rowHeight={30}
-        rowGetter={this.rowGetter}
-        rowCount={data.rows.length}
-        sort={this.doSort}
-        width={width}
-      >
-        {data.columns.map((col, index) => {
-          return (
-            <Column
-              key={index}
-              dataKey={index}
-              headerRenderer={this.headerRenderer}
-              cellRenderer={this.cellRenderer}
-              width={150}
-              minWidth={50}
-              flexGrow={1}
-            />
-          );
-        })}
-      </Table>
-    );
-  }
-}
-
-export default DataTable;

+ 8 - 7
packages/grafana-ui/src/components/DataTable/renderer.test.ts → packages/grafana-ui/src/components/Table/Table.test.ts

@@ -3,9 +3,8 @@ import TableModel from 'app/core/table_model';
 
 import { getColorDefinitionByName } from '@grafana/ui';
 import { ScopedVars } from '@grafana/ui/src/types';
-import { TableRenderer } from './renderer';
-import { Index } from 'react-virtualized';
-import { ColumnStyle } from './DataTable';
+import { getTheme } from '../../themes';
+import Table, { ColumnStyle } from './Table';
 
 // TODO: this is commented out with *x* describe!
 // Essentially all the elements need to replace the <td> with <div>
@@ -181,12 +180,14 @@ xdescribe('when rendering table', () => {
       }
       return value;
     };
-    const rowGetter = ({ index }: Index) => table.rows[index];
-    const renderer = new TableRenderer({
+    const renderer = new Table({
       styles,
-      schema: table.columns,
-      rowGetter,
+      data: table,
       replaceVariables,
+      showHeader: true,
+      width: 100,
+      height: 100,
+      theme: getTheme(),
     });
 
     it('time column should be formated', () => {

+ 182 - 25
packages/grafana-ui/src/components/DataTable/renderer.tsx → packages/grafana-ui/src/components/Table/Table.tsx

@@ -1,17 +1,55 @@
 // Libraries
 import _ from 'lodash';
-import moment from 'moment';
-import React, { CSSProperties, ReactNode } from 'react';
+import React, { Component, CSSProperties, ReactNode } from 'react';
+import {
+  Table as RVTable,
+  SortDirectionType,
+  SortIndicator,
+  Column as RVColumn,
+  TableHeaderProps,
+  TableCellProps,
+} from 'react-virtualized';
+import { Themeable } from '../../types/theme';
+
+import { sortTableData } from '../../utils/processTimeSeries';
 
 import { sanitize } from 'app/core/utils/text';
 
+import moment from 'moment';
+
+import { getValueFormat, TableData, getColorFromHexRgbOrName, InterpolateFunction, Column } from '@grafana/ui';
+import { Index } from 'react-virtualized';
+import { ColumnStyle } from './Table';
+
 // Types
 import kbn from 'app/core/utils/kbn';
-import { getValueFormat, getColorFromHexRgbOrName, GrafanaThemeType, InterpolateFunction, Column } from '@grafana/ui';
-import { Index } from 'react-virtualized';
-import { ColumnStyle } from './DataTable';
 
-type CellFormatter = (v: any, style?: ColumnStyle) => string | undefined;
+// Made to match the existing (untyped) settings in the angular table
+export interface ColumnStyle {
+  pattern?: string;
+
+  alias?: string;
+  colorMode?: string;
+  colors?: any[];
+  decimals?: number;
+  thresholds?: any[];
+  type?: 'date' | 'number' | 'string' | 'hidden';
+  unit?: string;
+  dateFormat?: string;
+  sanitize?: boolean;
+  mappingType?: any;
+  valueMaps?: any;
+  rangeMaps?: any;
+
+  link?: any;
+  linkUrl?: any;
+  linkTooltip?: any;
+  linkTargetBlank?: boolean;
+
+  preserveFormat?: boolean;
+}
+
+type CellFormatter = (v: any, style?: ColumnStyle) => ReactNode;
 
 interface ColumnInfo {
   header: string;
@@ -22,29 +60,66 @@ interface ColumnInfo {
   filterable?: boolean;
 }
 
-interface RendererOptions {
+interface Props extends Themeable {
+  data?: TableData;
+  showHeader: boolean;
   styles: ColumnStyle[];
-  schema: Column[];
-  rowGetter: (info: Index) => any[]; // matches the table rowGetter
   replaceVariables: InterpolateFunction;
-  isUTC?: boolean; // TODO? get UTC from props?
-  theme?: GrafanaThemeType | undefined;
+  width: number;
+  height: number;
+  isUTC?: boolean;
+}
+
+interface State {
+  sortBy?: number;
+  sortDirection?: SortDirectionType;
+  data?: TableData;
 }
 
-export class TableRenderer {
-  columns: ColumnInfo[];
+export class Table extends Component<Props, State> {
+  columns: ColumnInfo[] = [];
   colorState: any;
 
-  constructor(private options: RendererOptions) {
-    const { schema, styles } = options;
-    this.colorState = {};
+  static defaultProps = {
+    showHeader: true,
+  };
+
+  constructor(props: Props) {
+    super(props);
+
+    this.state = {
+      data: props.data,
+    };
+
+    this.initRenderer();
+  }
+
+  componentDidUpdate(prevProps: Props, prevState: State) {
+    const { data, styles } = this.props;
+    const { sortBy, sortDirection } = this.state;
+    const dataChanged = data !== prevProps.data;
 
-    if (!schema) {
+    // Update the renderer if options change
+    if (dataChanged || styles !== prevProps.styles) {
+      this.initRenderer();
+    }
+
+    // Update the data when data or sort changes
+    if (dataChanged || sortBy !== prevState.sortBy || sortDirection !== prevState.sortDirection) {
+      const sorted = data ? sortTableData(data, sortBy, sortDirection === 'DESC') : data;
+      this.setState({ data: sorted });
+    }
+  }
+
+  initRenderer() {
+    const { styles } = this.props;
+    const { data } = this.state;
+    this.colorState = {};
+    if (!data || !data.columns) {
       this.columns = [];
       return;
     }
-
-    this.columns = options.schema.map((col, index) => {
+    this.columns = data.columns.map((col, index) => {
       let title = col.text;
       let style; // ColumnStyle
 
@@ -70,16 +145,22 @@ export class TableRenderer {
     });
   }
 
+  //----------------------------------------------------------------------
+  // renderer.ts copy (taken from angular version!!!)
+  //----------------------------------------------------------------------
+
   getColorForValue(value: any, style: ColumnStyle) {
-    if (!style.thresholds) {
+    if (!style.thresholds || !style.colors) {
       return null;
     }
+    const { theme } = this.props;
+
     for (let i = style.thresholds.length; i > 0; i--) {
       if (value >= style.thresholds[i - 1]) {
-        return getColorFromHexRgbOrName(style.colors![i], this.options.theme);
+        return getColorFromHexRgbOrName(style.colors[i], theme.type);
       }
     }
-    return getColorFromHexRgbOrName(_.first(style.colors), this.options.theme);
+    return getColorFromHexRgbOrName(_.first(style.colors), theme.type);
   }
 
   defaultCellFormatter(v: any, style?: ColumnStyle): string {
@@ -119,7 +200,7 @@ export class TableRenderer {
           v = v[0];
         }
         let date = moment(v);
-        if (this.options.isUTC) {
+        if (this.props.isUTC) {
           date = date.utc();
         }
         return date.format(style.dateFormat);
@@ -220,7 +301,7 @@ export class TableRenderer {
 
   renderRowVariables(rowIndex: number) {
     const scopedVars: any = {};
-    const row = this.options.rowGetter({ index: rowIndex });
+    const row = this.rowGetter({ index: rowIndex });
     for (let i = 0; i < row.length; i++) {
       scopedVars[`__cell_${i}`] = { value: row[i] };
     }
@@ -260,7 +341,7 @@ export class TableRenderer {
     let columnHtml: JSX.Element;
     if (column.style && column.style.link) {
       // Render cell as link
-      const { replaceVariables } = this.options;
+      const { replaceVariables } = this.props;
       const scopedVars = this.renderRowVariables(rowIndex);
       scopedVars['__cell'] = { value: value };
 
@@ -329,4 +410,80 @@ export class TableRenderer {
     );
     return columnHtml;
   }
+
+  //----------------------------------------------------------------------
+  //----------------------------------------------------------------------
+
+  rowGetter = ({ index }: Index) => {
+    return this.state.data!.rows[index];
+  };
+
+  doSort = (info: any) => {
+    let dir = info.sortDirection;
+    let sort = info.sortBy;
+    if (sort !== this.state.sortBy) {
+      dir = 'DESC';
+    } else if (dir === 'DESC') {
+      dir = 'ASC';
+    } else {
+      sort = null;
+    }
+    this.setState({ sortBy: sort, sortDirection: dir });
+  };
+
+  headerRenderer = (header: TableHeaderProps): ReactNode => {
+    const dataKey = header.dataKey as any; // types say string, but it is number!
+    const { data, sortBy, sortDirection } = this.state;
+    const col = data!.columns[dataKey];
+
+    return (
+      <div>
+        {col.text} {sortBy === dataKey && <SortIndicator sortDirection={sortDirection} />}
+      </div>
+    );
+  };
+
+  cellRenderer = (cell: TableCellProps) => {
+    const { columnIndex, rowIndex } = cell;
+    const row = this.state.data!.rows[rowIndex];
+    const val = row[columnIndex];
+    return this.renderCell(columnIndex, rowIndex, val);
+  };
+
+  render() {
+    const { width, height, showHeader } = this.props;
+    const { data } = this.props;
+    if (!data) {
+      return <div>NO Data</div>;
+    }
+    return (
+      <RVTable
+        disableHeader={!showHeader}
+        headerHeight={30}
+        height={height}
+        overscanRowCount={10}
+        rowHeight={30}
+        rowGetter={this.rowGetter}
+        rowCount={data.rows.length}
+        sort={this.doSort}
+        width={width}
+      >
+        {data.columns.map((col, index) => {
+          return (
+            <RVColumn
+              key={index}
+              dataKey={index}
+              headerRenderer={this.headerRenderer}
+              cellRenderer={this.cellRenderer}
+              width={150}
+              minWidth={50}
+              flexGrow={1}
+            />
+          );
+        })}
+      </RVTable>
+    );
+  }
 }
+
+export default Table;

+ 0 - 0
public/sass/components/_panel_table2.scss → packages/grafana-ui/src/components/Table/_Table.scss


+ 1 - 1
public/app/plugins/panel/table/renderer.ts

@@ -2,7 +2,7 @@ import _ from 'lodash';
 import moment from 'moment';
 import kbn from 'app/core/utils/kbn';
 import { getValueFormat, getColorFromHexRgbOrName, GrafanaThemeType } from '@grafana/ui';
-import { ColumnStyle } from '@grafana/ui/src/components/DataTable/DataTable';
+import { ColumnStyle } from '@grafana/ui/src/components/Table/Table';
 
 export class TableRenderer {
   formatters: any[];

+ 2 - 3
public/app/plugins/panel/table2/TablePanel.tsx

@@ -1,11 +1,10 @@
 // Libraries
-import _ from 'lodash';
 import React, { Component } from 'react';
 
 // Types
 import { PanelProps, ThemeContext } from '@grafana/ui';
 import { Options } from './types';
-import DataTable from '@grafana/ui/src/components/DataTable/DataTable';
+import Table from '@grafana/ui/src/components/Table/Table';
 
 interface Props extends PanelProps<Options> {}
 
@@ -23,7 +22,7 @@ export class TablePanel extends Component<Props> {
 
     return (
       <ThemeContext.Consumer>
-        {theme => <DataTable {...this.props} {...options} theme={theme} data={panelData.tableData} />}
+        {theme => <Table {...this.props} {...options} theme={theme} data={panelData.tableData} />}
       </ThemeContext.Consumer>
     );
   }

+ 1 - 1
public/app/plugins/panel/table2/types.ts

@@ -1,4 +1,4 @@
-import { ColumnStyle } from '@grafana/ui/src/components/DataTable/DataTable';
+import { ColumnStyle } from '@grafana/ui/src/components/Table/Table';
 
 export interface Options {
   showHeader: boolean;