Commit 9134620c by ryan

return table directly, not the debug info

parent c7f35f2d
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import TableInputCSV from './TableInputCSV'; import TableInputCSV from './TableInputCSV';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { ParseResults } from '../../utils/processTableData'; import { TableData } from '../../types/data';
const TableInputStories = storiesOf('UI/Table/Input', module); const TableInputStories = storiesOf('UI/Table/Input', module);
...@@ -11,11 +11,12 @@ TableInputStories.add('default', () => { ...@@ -11,11 +11,12 @@ TableInputStories.add('default', () => {
return ( return (
<div> <div>
<TableInputCSV <TableInputCSV
text="a,b,c\n1,2,3"
width={'90%'} width={'90%'}
height={'90vh'} height={'90vh'}
onTableParsed={(results: ParseResults) => { onTableParsed={(table: TableData, text: string) => {
console.log('Table Results', results); console.log('Table', table, text);
action('Parsed')(results); action('Table')(table, text);
}} }}
/> />
</div> </div>
......
...@@ -2,17 +2,18 @@ import React from 'react'; ...@@ -2,17 +2,18 @@ import React from 'react';
import renderer from 'react-test-renderer'; import renderer from 'react-test-renderer';
import TableInputCSV from './TableInputCSV'; import TableInputCSV from './TableInputCSV';
import { ParseResults } from '../../utils/processTableData'; import { TableData } from '../../types/data';
describe('TableInputCSV', () => { describe('TableInputCSV', () => {
it('renders correctly', () => { it('renders correctly', () => {
const tree = renderer const tree = renderer
.create( .create(
<TableInputCSV <TableInputCSV
text="a,b,c\n1,2,3"
width={100} width={100}
height={100} height={100}
onTableParsed={(results: ParseResults) => { onTableParsed={(table: TableData, text: string) => {
console.log('GOT', results); console.log('Table:', table, 'from:', text);
}} }}
/> />
) )
......
import React from 'react'; import React from 'react';
import debounce from 'lodash/debounce'; 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 { interface Props {
config?: ParseConfig; config?: ParseConfig;
width: number | string; width: number | string;
height: number | string; height: number | string;
onTableParsed: (results: ParseResults) => void; text: string;
onTableParsed: (table: TableData, text: string) => void;
} }
interface State { interface State {
text: string; text: string;
results: ParseResults; table: TableData;
details: ParseDetails;
} }
class TableInputCSV extends React.PureComponent<Props, State> { class TableInputCSV extends React.PureComponent<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
// Shoud this happen in onComponentMounted?
const { text, config, onTableParsed } = props;
const details = {};
const table = parseCSV(text, config, details);
this.state = { this.state = {
text: '', text,
results: parseCSV('', this.props.config), table,
details,
}; };
onTableParsed(table, text);
} }
readCSV = debounce(() => { readCSV = debounce(() => {
const results = parseCSV(this.state.text, this.props.config); const details = {};
this.setState({ results }); const table = parseCSV(this.state.text, this.props.config, details);
this.setState({ table, details });
}, 150); }, 150);
componentDidUpdate(prevProps: Props, prevState: State) { 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(); this.readCSV();
} }
if (this.state.results !== prevState.results) { // If the props text has changed, replace our local version
this.props.onTableParsed(this.state.results); 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<Props, State> { ...@@ -43,9 +60,9 @@ class TableInputCSV extends React.PureComponent<Props, State> {
render() { render() {
const { width, height } = this.props; 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 ( return (
<div className="gf-table-input-csv" style={{ width, height }}> <div className="gf-table-input-csv" style={{ width, height }}>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP // 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`] = ` exports[`processTableData basic processing should read header and two rows 1`] = `
Object { Object {
"errors": Array [], "columnMap": Object {},
"meta": Object { "columns": Array [
"aborted": false, Object {
"cursor": 17, "text": "a",
"delimiter": ",", },
"linebreak": " Object {
", "text": "b",
"truncated": false, },
}, Object {
"table": Object { "text": "c",
"columnMap": Object {}, },
"columns": Array [ ],
Object { "rows": Array [
"text": "a", Array [
}, 1,
Object { 2,
"text": "b", 3,
},
Object {
"text": "c",
},
], ],
"rows": Array [ Array [
Array [ 4,
1, 5,
2, 6,
3,
],
Array [
4,
5,
6,
],
], ],
"type": "table", ],
}, "type": "table",
} }
`; `;
...@@ -3,8 +3,18 @@ import { parseCSV } from './processTableData'; ...@@ -3,8 +3,18 @@ import { parseCSV } from './processTableData';
describe('processTableData', () => { describe('processTableData', () => {
describe('basic processing', () => { describe('basic processing', () => {
it('should read header and two rows', () => { it('should read header and two rows', () => {
const simpleCSV = 'a,b,c\n1,2,3\n4,5,6'; const text = 'a,b,c\n1,2,3\n4,5,6';
expect(parseCSV(simpleCSV)).toMatchSnapshot(); 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();
}); });
}); });
}); });
...@@ -12,10 +12,9 @@ export interface ParseConfig { ...@@ -12,10 +12,9 @@ export interface ParseConfig {
comments?: boolean | string; // default: false comments?: boolean | string; // default: false
} }
export interface ParseResults { export interface ParseDetails {
table: TableData; meta?: ParseMeta;
meta: ParseMeta; errors?: ParseError[];
errors: ParseError[];
} }
/** /**
...@@ -84,12 +83,26 @@ function makeColumns(values: any[]): Column[] { ...@@ -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 results = Papa.parse(text, { ...config, dynamicTyping: true, skipEmptyLines: true });
const { data, meta, errors } = results; 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 (!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.length = 0;
errors.push({ errors.push({
code: 'empty', code: 'empty',
...@@ -97,16 +110,13 @@ export function parseCSV(text: string, config?: ParseConfig): ParseResults { ...@@ -97,16 +110,13 @@ export function parseCSV(text: string, config?: ParseConfig): ParseResults {
type: 'warning', type: 'warning',
row: 0, row: 0,
}); });
details.errors = errors;
} }
return { return {
table: { columns: [],
columns: [], rows: [],
rows: [], type: 'table',
type: 'table', columnMap: {},
columnMap: {},
},
meta,
errors,
}; };
} }
...@@ -114,14 +124,10 @@ export function parseCSV(text: string, config?: ParseConfig): ParseResults { ...@@ -114,14 +124,10 @@ export function parseCSV(text: string, config?: ParseConfig): ParseResults {
const headerIsNotFirstLine = config && config.headerIsFirstLine === false; const headerIsNotFirstLine = config && config.headerIsFirstLine === false;
const header = headerIsNotFirstLine ? [] : results.data.shift(); const header = headerIsNotFirstLine ? [] : results.data.shift();
return { return matchRowSizes({
table: matchRowSizes({ columns: makeColumns(header),
columns: makeColumns(header), rows: results.data,
rows: results.data, type: 'table',
type: 'table', columnMap: {},
columnMap: {}, });
}),
meta,
errors,
};
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment