From 9134620c1a89f5c1f3f6f0592441c19a78da8900 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 9 Mar 2019 14:15:41 -0800 Subject: [PATCH] return table directly, not the debug info --- .../components/Table/TableInputCSV.story.tsx | 9 +- .../components/Table/TableInputCSV.test.tsx | 7 +- .../src/components/Table/TableInputCSV.tsx | 41 ++++++--- .../processTableData.test.ts.snap | 92 ++++++++++++------- .../src/utils/processTableData.test.ts | 14 ++- .../grafana-ui/src/utils/processTableData.ts | 56 ++++++----- 6 files changed, 139 insertions(+), 80 deletions(-) diff --git a/packages/grafana-ui/src/components/Table/TableInputCSV.story.tsx b/packages/grafana-ui/src/components/Table/TableInputCSV.story.tsx index c100e59effc..4ff4a00a4fa 100644 --- a/packages/grafana-ui/src/components/Table/TableInputCSV.story.tsx +++ b/packages/grafana-ui/src/components/Table/TableInputCSV.story.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; import TableInputCSV from './TableInputCSV'; import { action } from '@storybook/addon-actions'; -import { ParseResults } from '../../utils/processTableData'; +import { TableData } from '../../types/data'; const TableInputStories = storiesOf('UI/Table/Input', module); @@ -11,11 +11,12 @@ TableInputStories.add('default', () => { return (
{ - console.log('Table Results', results); - action('Parsed')(results); + onTableParsed={(table: TableData, text: string) => { + console.log('Table', table, text); + action('Table')(table, text); }} />
diff --git a/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx b/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx index 26923dcb1aa..e99061f2c5b 100644 --- a/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx +++ b/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx @@ -2,17 +2,18 @@ import React from 'react'; import renderer from 'react-test-renderer'; import TableInputCSV from './TableInputCSV'; -import { ParseResults } from '../../utils/processTableData'; +import { TableData } from '../../types/data'; describe('TableInputCSV', () => { it('renders correctly', () => { const tree = renderer .create( { - console.log('GOT', results); + onTableParsed={(table: TableData, text: string) => { + console.log('Table:', table, 'from:', text); }} /> ) diff --git a/packages/grafana-ui/src/components/Table/TableInputCSV.tsx b/packages/grafana-ui/src/components/Table/TableInputCSV.tsx index b576a520de7..5828c97228b 100644 --- a/packages/grafana-ui/src/components/Table/TableInputCSV.tsx +++ b/packages/grafana-ui/src/components/Table/TableInputCSV.tsx @@ -1,39 +1,56 @@ import React from 'react'; import debounce from 'lodash/debounce'; -import { ParseConfig, ParseResults, parseCSV } from '../../utils/processTableData'; +import { ParseConfig, parseCSV, ParseDetails } from '../../utils/processTableData'; +import { TableData } from '../../types/data'; interface Props { config?: ParseConfig; width: number | string; height: number | string; - onTableParsed: (results: ParseResults) => void; + text: string; + onTableParsed: (table: TableData, text: string) => void; } interface State { text: string; - results: ParseResults; + table: TableData; + details: ParseDetails; } class TableInputCSV extends React.PureComponent { constructor(props: Props) { super(props); + + // Shoud this happen in onComponentMounted? + const { text, config, onTableParsed } = props; + const details = {}; + const table = parseCSV(text, config, details); this.state = { - text: '', - results: parseCSV('', this.props.config), + text, + table, + details, }; + onTableParsed(table, text); } readCSV = debounce(() => { - const results = parseCSV(this.state.text, this.props.config); - this.setState({ results }); + const details = {}; + const table = parseCSV(this.state.text, this.props.config, details); + this.setState({ table, details }); }, 150); componentDidUpdate(prevProps: Props, prevState: State) { - if (this.state.text !== prevState.text || this.props.config !== prevProps.config) { + const { text } = this.state; + if (text !== prevState.text || this.props.config !== prevProps.config) { this.readCSV(); } - if (this.state.results !== prevState.results) { - this.props.onTableParsed(this.state.results); + // If the props text has changed, replace our local version + if (this.props.text !== prevProps.text && this.props.text !== text) { + this.setState({ text: this.props.text }); + } + + if (this.state.table !== prevState.table) { + this.props.onTableParsed(this.state.table, this.state.text); } } @@ -43,9 +60,9 @@ class TableInputCSV extends React.PureComponent { render() { const { width, height } = this.props; - const { table, errors } = this.state.results; + const { table, details } = this.state; - const hasErrors = errors.length > 0; + const hasErrors = details.errors && details.errors.length > 0; return (
diff --git a/packages/grafana-ui/src/utils/__snapshots__/processTableData.test.ts.snap b/packages/grafana-ui/src/utils/__snapshots__/processTableData.test.ts.snap index 299f56288c1..42e25cb38e4 100644 --- a/packages/grafana-ui/src/utils/__snapshots__/processTableData.test.ts.snap +++ b/packages/grafana-ui/src/utils/__snapshots__/processTableData.test.ts.snap @@ -1,42 +1,66 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`processTableData basic processing should generate a header and fix widths 1`] = ` +Object { + "columnMap": Object {}, + "columns": Array [ + Object { + "text": "Column 1", + }, + Object { + "text": "Column 2", + }, + Object { + "text": "Column 3", + }, + ], + "rows": Array [ + Array [ + 1, + null, + null, + ], + Array [ + 2, + 3, + 4, + ], + Array [ + 5, + 6, + null, + ], + ], + "type": "table", +} +`; + exports[`processTableData basic processing should read header and two rows 1`] = ` Object { - "errors": Array [], - "meta": Object { - "aborted": false, - "cursor": 17, - "delimiter": ",", - "linebreak": " -", - "truncated": false, - }, - "table": Object { - "columnMap": Object {}, - "columns": Array [ - Object { - "text": "a", - }, - Object { - "text": "b", - }, - Object { - "text": "c", - }, + "columnMap": Object {}, + "columns": Array [ + Object { + "text": "a", + }, + Object { + "text": "b", + }, + Object { + "text": "c", + }, + ], + "rows": Array [ + Array [ + 1, + 2, + 3, ], - "rows": Array [ - Array [ - 1, - 2, - 3, - ], - Array [ - 4, - 5, - 6, - ], + Array [ + 4, + 5, + 6, ], - "type": "table", - }, + ], + "type": "table", } `; diff --git a/packages/grafana-ui/src/utils/processTableData.test.ts b/packages/grafana-ui/src/utils/processTableData.test.ts index 191ddd61cb3..fc2545b1706 100644 --- a/packages/grafana-ui/src/utils/processTableData.test.ts +++ b/packages/grafana-ui/src/utils/processTableData.test.ts @@ -3,8 +3,18 @@ import { parseCSV } from './processTableData'; describe('processTableData', () => { describe('basic processing', () => { it('should read header and two rows', () => { - const simpleCSV = 'a,b,c\n1,2,3\n4,5,6'; - expect(parseCSV(simpleCSV)).toMatchSnapshot(); + const text = 'a,b,c\n1,2,3\n4,5,6'; + expect(parseCSV(text)).toMatchSnapshot(); + }); + + it('should generate a header and fix widths', () => { + const text = '1\n2,3,4\n5,6'; + const table = parseCSV(text, { + headerIsFirstLine: false, + }); + expect(table.rows.length).toBe(3); + + expect(table).toMatchSnapshot(); }); }); }); diff --git a/packages/grafana-ui/src/utils/processTableData.ts b/packages/grafana-ui/src/utils/processTableData.ts index 5919930064a..da539f18052 100644 --- a/packages/grafana-ui/src/utils/processTableData.ts +++ b/packages/grafana-ui/src/utils/processTableData.ts @@ -12,10 +12,9 @@ export interface ParseConfig { comments?: boolean | string; // default: false } -export interface ParseResults { - table: TableData; - meta: ParseMeta; - errors: ParseError[]; +export interface ParseDetails { + meta?: ParseMeta; + errors?: ParseError[]; } /** @@ -84,12 +83,26 @@ function makeColumns(values: any[]): Column[] { }); } -export function parseCSV(text: string, config?: ParseConfig): ParseResults { +/** + * Convert text into a valid TableData object + * + * @param text + * @param config + * @param details, if exists the result will be filled with parse details + */ +export function parseCSV(text: string, config?: ParseConfig, details?: ParseDetails): TableData { const results = Papa.parse(text, { ...config, dynamicTyping: true, skipEmptyLines: true }); const { data, meta, errors } = results; + + // Fill the parse details fro debugging + if (details) { + details.errors = errors; + details.meta = meta; + } + if (!data || data.length < 1) { - if (!text) { - // Show a more reasonable warning on empty input text + // Show a more reasonable warning on empty input text + if (details && !text) { errors.length = 0; errors.push({ code: 'empty', @@ -97,16 +110,13 @@ export function parseCSV(text: string, config?: ParseConfig): ParseResults { type: 'warning', row: 0, }); + details.errors = errors; } return { - table: { - columns: [], - rows: [], - type: 'table', - columnMap: {}, - }, - meta, - errors, + columns: [], + rows: [], + type: 'table', + columnMap: {}, }; } @@ -114,14 +124,10 @@ export function parseCSV(text: string, config?: ParseConfig): ParseResults { const headerIsNotFirstLine = config && config.headerIsFirstLine === false; const header = headerIsNotFirstLine ? [] : results.data.shift(); - return { - table: matchRowSizes({ - columns: makeColumns(header), - rows: results.data, - type: 'table', - columnMap: {}, - }), - meta, - errors, - }; + return matchRowSizes({ + columns: makeColumns(header), + rows: results.data, + type: 'table', + columnMap: {}, + }); }