TableInputCSV.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import React from 'react';
  2. import debounce from 'lodash/debounce';
  3. import { parseCSV, TableParseOptions, TableParseDetails } from '../../utils/processTableData';
  4. import { TableData } from '../../types/data';
  5. import { AutoSizer } from 'react-virtualized';
  6. interface Props {
  7. options?: TableParseOptions;
  8. text: string;
  9. onTableParsed: (table: TableData, text: string) => void;
  10. }
  11. interface State {
  12. text: string;
  13. table: TableData;
  14. details: TableParseDetails;
  15. }
  16. /**
  17. * Expects the container div to have size set and will fill it 100%
  18. */
  19. class TableInputCSV extends React.PureComponent<Props, State> {
  20. constructor(props: Props) {
  21. super(props);
  22. // Shoud this happen in onComponentMounted?
  23. const { text, options, onTableParsed } = props;
  24. const details = {};
  25. const table = parseCSV(text, options, details);
  26. this.state = {
  27. text,
  28. table,
  29. details,
  30. };
  31. onTableParsed(table, text);
  32. }
  33. readCSV = debounce(() => {
  34. const details = {};
  35. const table = parseCSV(this.state.text, this.props.options, details);
  36. this.setState({ table, details });
  37. }, 150);
  38. componentDidUpdate(prevProps: Props, prevState: State) {
  39. const { text } = this.state;
  40. if (text !== prevState.text || this.props.options !== prevProps.options) {
  41. this.readCSV();
  42. }
  43. // If the props text has changed, replace our local version
  44. if (this.props.text !== prevProps.text && this.props.text !== text) {
  45. this.setState({ text: this.props.text });
  46. }
  47. if (this.state.table !== prevState.table) {
  48. this.props.onTableParsed(this.state.table, this.state.text);
  49. }
  50. }
  51. onFooterClicked = (event: any) => {
  52. console.log('Errors', this.state);
  53. const message = this.state.details
  54. .errors!.map(err => {
  55. return err.message;
  56. })
  57. .join('\n');
  58. alert('CSV Parsing Errors:\n' + message);
  59. };
  60. onTextChange = (event: any) => {
  61. this.setState({ text: event.target.value });
  62. };
  63. render() {
  64. const { table, details } = this.state;
  65. const hasErrors = details.errors && details.errors.length > 0;
  66. const footerClassNames = hasErrors ? 'gf-table-input-csv-err' : '';
  67. return (
  68. <AutoSizer>
  69. {({ height, width }) => (
  70. <div className="gf-table-input-csv" style={{ width, height }}>
  71. <textarea placeholder="Enter CSV here..." value={this.state.text} onChange={this.onTextChange} />
  72. <footer onClick={this.onFooterClicked} className={footerClassNames}>
  73. Rows:{table.rows.length}, Columns:{table.columns.length} &nbsp;
  74. {hasErrors ? <i className="fa fa-exclamation-triangle" /> : <i className="fa fa-check-circle" />}
  75. </footer>
  76. </div>
  77. )}
  78. </AutoSizer>
  79. );
  80. }
  81. }
  82. export default TableInputCSV;