TablePanel.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Libraries
  2. import _ from 'lodash';
  3. import React, { Component, ReactNode } from 'react';
  4. // Types
  5. import { PanelProps, ThemeContext } from '@grafana/ui';
  6. import { Options } from './types';
  7. import { Table, SortDirectionType, SortIndicator, Column, TableHeaderProps, TableCellProps } from 'react-virtualized';
  8. import { TableRenderer } from './renderer';
  9. import { SortedTableData } from './sortable';
  10. interface Props extends PanelProps<Options> {}
  11. interface State {
  12. sortBy?: number; // but really is a number!
  13. sortDirection?: SortDirectionType;
  14. data: SortedTableData;
  15. }
  16. export class TablePanel extends Component<Props, State> {
  17. renderer: TableRenderer;
  18. constructor(props: Props) {
  19. super(props);
  20. const { panelData, options, replaceVariables } = this.props;
  21. this.state = {
  22. data: new SortedTableData(panelData.tableData),
  23. };
  24. this.renderer = new TableRenderer(options.styles, this.state.data, this._rowGetter, replaceVariables);
  25. }
  26. componentDidUpdate(prevProps: Props, prevState: State) {
  27. const { panelData, options } = this.props;
  28. const { sortBy, sortDirection } = this.state;
  29. console.log('componentDidUpdate', this.props);
  30. // Update the renderer if options change
  31. if (options !== prevProps.options) {
  32. console.log('Options Changed, update renderer', options);
  33. this.renderer = new TableRenderer(options.styles, this.state.data, this._rowGetter, this.props.replaceVariables);
  34. }
  35. // Update the data when data or sort changes
  36. if (panelData !== prevProps.panelData || sortBy !== prevState.sortBy || sortDirection !== prevState.sortDirection) {
  37. const data = new SortedTableData(panelData.tableData, sortBy, sortDirection === 'DESC');
  38. this.setState({ data });
  39. console.log('Data Changed, update', data);
  40. }
  41. }
  42. _rowGetter = ({ index }) => {
  43. return this.state.data.getRow(index);
  44. };
  45. _sort = ({ sortBy }) => {
  46. let sortDirection = this.state.sortDirection;
  47. if (sortBy !== this.state.sortBy) {
  48. sortDirection = 'DESC';
  49. } else if (sortDirection === 'DESC') {
  50. sortDirection = 'ASC';
  51. } else {
  52. sortBy = null;
  53. }
  54. // This will trigger sort via properties
  55. console.log('SORT', sortBy, typeof sortBy, sortDirection);
  56. this.setState({ sortBy, sortDirection });
  57. };
  58. _headerRenderer = (header: TableHeaderProps): ReactNode => {
  59. const dataKey = header.dataKey as any; // types say string, but it is number?
  60. const { data, sortBy, sortDirection } = this.state;
  61. const col = data.getInfo()[dataKey];
  62. if (!col) {
  63. return <div>??{dataKey}??</div>;
  64. }
  65. const isSorted = sortBy === dataKey;
  66. console.log('header SORT', sortBy, isSorted);
  67. return (
  68. <div>
  69. {col.text} {isSorted && <SortIndicator sortDirection={sortDirection} />}
  70. </div>
  71. );
  72. };
  73. _cellRenderer = (cell: TableCellProps) => {
  74. const { columnIndex, rowIndex } = cell;
  75. const row = this.state.data.getRow(rowIndex);
  76. const val = row[columnIndex];
  77. return this.renderer.renderCell(columnIndex, rowIndex, val);
  78. };
  79. render() {
  80. const { panelData, width, height, options } = this.props;
  81. const { showHeader } = options;
  82. // const { sortBy, sortDirection } = this.state;
  83. const { tableData } = panelData;
  84. if (!tableData || tableData.rows.length < 1) {
  85. return <div>No Table Data...</div>;
  86. }
  87. return (
  88. <ThemeContext.Consumer>
  89. {(
  90. theme // ??? { this.renderer.setTheme(theme) }
  91. ) => (
  92. <Table
  93. disableHeader={!showHeader}
  94. headerHeight={30}
  95. height={height}
  96. overscanRowCount={10}
  97. rowHeight={30}
  98. rowGetter={this._rowGetter}
  99. rowCount={tableData.rows.length}
  100. sort={this._sort}
  101. width={width}
  102. >
  103. {tableData.columns.map((col, index) => {
  104. return (
  105. <Column
  106. key={index}
  107. dataKey={index}
  108. headerRenderer={this._headerRenderer}
  109. cellRenderer={this._cellRenderer}
  110. width={300}
  111. />
  112. );
  113. })}
  114. </Table>
  115. )}
  116. </ThemeContext.Consumer>
  117. );
  118. }
  119. }