diff --git a/packages/grafana-ui/src/components/DataTable/DataTable.tsx b/packages/grafana-ui/src/components/DataTable/DataTable.tsx deleted file mode 100644 index 322b3847c7b..00000000000 --- a/packages/grafana-ui/src/components/DataTable/DataTable.tsx +++ /dev/null @@ -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 { - 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 ( -
- {col.text} {sortBy === dataKey && } -
- ); - }; - - 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
NO Data
; - } - return ( - - {data.columns.map((col, index) => { - return ( - - ); - })} -
- ); - } -} - -export default DataTable; diff --git a/packages/grafana-ui/src/components/DataTable/renderer.test.ts b/packages/grafana-ui/src/components/Table/Table.test.ts similarity index 97% rename from packages/grafana-ui/src/components/DataTable/renderer.test.ts rename to packages/grafana-ui/src/components/Table/Table.test.ts index 28f217b11f0..deb34385b1a 100644 --- a/packages/grafana-ui/src/components/DataTable/renderer.test.ts +++ b/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 with
@@ -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', () => { diff --git a/packages/grafana-ui/src/components/DataTable/renderer.tsx b/packages/grafana-ui/src/components/Table/Table.tsx similarity index 60% rename from packages/grafana-ui/src/components/DataTable/renderer.tsx rename to packages/grafana-ui/src/components/Table/Table.tsx index 11977dc2e6f..294be5ec321 100644 --- a/packages/grafana-ui/src/components/DataTable/renderer.tsx +++ b/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; } -export class TableRenderer { - columns: ColumnInfo[]; +interface State { + sortBy?: number; + sortDirection?: SortDirectionType; + data?: TableData; +} + +export class Table extends Component { + columns: ColumnInfo[] = []; colorState: any; - constructor(private options: RendererOptions) { - const { schema, styles } = options; - this.colorState = {}; + static defaultProps = { + showHeader: true, + }; - if (!schema) { + 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; + + // 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 ( +
+ {col.text} {sortBy === dataKey && } +
+ ); + }; + + 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
NO Data
; + } + return ( + + {data.columns.map((col, index) => { + return ( + + ); + })} + + ); + } } + +export default Table; diff --git a/public/sass/components/_panel_table2.scss b/packages/grafana-ui/src/components/Table/_Table.scss similarity index 100% rename from public/sass/components/_panel_table2.scss rename to packages/grafana-ui/src/components/Table/_Table.scss diff --git a/public/app/plugins/panel/table/renderer.ts b/public/app/plugins/panel/table/renderer.ts index ffb8f89b972..db6f87cfc74 100644 --- a/public/app/plugins/panel/table/renderer.ts +++ b/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[]; diff --git a/public/app/plugins/panel/table2/TablePanel.tsx b/public/app/plugins/panel/table2/TablePanel.tsx index de4648f2c8b..a7cd84f8ecb 100644 --- a/public/app/plugins/panel/table2/TablePanel.tsx +++ b/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 {} @@ -23,7 +22,7 @@ export class TablePanel extends Component { return ( - {theme => } + {theme => } ); } diff --git a/public/app/plugins/panel/table2/types.ts b/public/app/plugins/panel/table2/types.ts index 0935a0878c9..87643648f91 100644 --- a/public/app/plugins/panel/table2/types.ts +++ b/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;