mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
adding stub table input CSV
This commit is contained in:
parent
0ae9c1c5cc
commit
9df47391ea
@ -24,6 +24,7 @@
|
||||
"jquery": "^3.2.1",
|
||||
"lodash": "^4.17.10",
|
||||
"moment": "^2.22.2",
|
||||
"papaparse": "^4.6.3",
|
||||
"react": "^16.6.3",
|
||||
"react-color": "^2.17.0",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
@ -46,6 +47,7 @@
|
||||
"@types/jquery": "^1.10.35",
|
||||
"@types/lodash": "^4.14.119",
|
||||
"@types/node": "^10.12.18",
|
||||
"@types/papaparse": "^4.5.9",
|
||||
"@types/react": "^16.7.6",
|
||||
"@types/react-custom-scrollbars": "^4.0.5",
|
||||
"@types/react-test-renderer": "^16.0.3",
|
||||
|
@ -0,0 +1,12 @@
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
|
||||
import TableInputCSV from './TableInputCSV';
|
||||
|
||||
const TableInputStories = storiesOf('UI/Table/Input', module);
|
||||
|
||||
TableInputStories.addDecorator(withCenteredStory);
|
||||
|
||||
TableInputStories.add('default', () => {
|
||||
return renderComponentWithTheme(TableInputCSV, {});
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import renderer from 'react-test-renderer';
|
||||
import TableInputCSV from './TableInputCSV';
|
||||
|
||||
describe('TableInputCSV', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer.create(<TableInputCSV />).toJSON();
|
||||
//expect(tree).toMatchSnapshot();
|
||||
expect(tree).toBeDefined();
|
||||
});
|
||||
});
|
144
packages/grafana-ui/src/components/Table/TableInputCSV.tsx
Normal file
144
packages/grafana-ui/src/components/Table/TableInputCSV.tsx
Normal file
@ -0,0 +1,144 @@
|
||||
import React from 'react';
|
||||
import debounce from 'lodash/debounce';
|
||||
import Papa, { ParseError, ParseMeta } from 'papaparse';
|
||||
import { TableData, Column } from '../../types/data';
|
||||
|
||||
// Subset of all parse configs
|
||||
export interface ParseConfig {
|
||||
delimiter?: string; // default: ","
|
||||
newline?: string; // default: "\r\n"
|
||||
quoteChar?: string; // default: '"'
|
||||
encoding?: string; // default: ""
|
||||
comments?: boolean | string; // default: false
|
||||
}
|
||||
|
||||
interface ParseResults {
|
||||
table: TableData;
|
||||
meta: ParseMeta;
|
||||
errors: ParseError[];
|
||||
}
|
||||
|
||||
export function parseCSV(text: string, config?: ParseConfig): ParseResults {
|
||||
const results = Papa.parse(text, { ...config, dynamicTyping: true, skipEmptyLines: true });
|
||||
|
||||
const { data, meta, errors } = results;
|
||||
if (!data || data.length < 1) {
|
||||
if (!text) {
|
||||
errors.length = 0; // clear other errors
|
||||
}
|
||||
errors.push({
|
||||
type: 'warning', // A generalization of the error
|
||||
message: 'Empty Data',
|
||||
code: 'empty',
|
||||
row: 0,
|
||||
});
|
||||
return {
|
||||
table: {
|
||||
columns: [],
|
||||
rows: [],
|
||||
type: 'table',
|
||||
columnMap: {},
|
||||
} as TableData,
|
||||
meta,
|
||||
errors,
|
||||
};
|
||||
}
|
||||
|
||||
let same = true;
|
||||
let cols = data[0].length;
|
||||
data.forEach(row => {
|
||||
if (cols !== row.length) {
|
||||
same = false;
|
||||
cols = Math.max(cols, row.length);
|
||||
}
|
||||
});
|
||||
|
||||
// Use a second pass to update the sizes
|
||||
if (!same) {
|
||||
errors.push({
|
||||
type: 'warning', // A generalization of the error
|
||||
message: 'not all rows have the same width',
|
||||
code: 'width',
|
||||
row: 0,
|
||||
});
|
||||
// Add null values to the end of all short arrays
|
||||
data.forEach(row => {
|
||||
const diff = cols - row.length;
|
||||
for (let i = 0; i < diff; i++) {
|
||||
row.push(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const first = results.data.shift();
|
||||
return {
|
||||
table: {
|
||||
columns: first.map((v: any, index: number) => {
|
||||
if (!v) {
|
||||
v = 'Column ' + (index + 1);
|
||||
}
|
||||
return {
|
||||
text: v.toString().trim(),
|
||||
} as Column;
|
||||
}),
|
||||
rows: results.data,
|
||||
type: 'table',
|
||||
columnMap: {},
|
||||
} as TableData,
|
||||
meta,
|
||||
errors,
|
||||
};
|
||||
}
|
||||
|
||||
interface Props {
|
||||
config?: ParseConfig;
|
||||
}
|
||||
|
||||
interface State {
|
||||
text: string;
|
||||
results: ParseResults;
|
||||
}
|
||||
|
||||
class TableInputCSV extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
text: '',
|
||||
results: parseCSV('', this.props.config),
|
||||
};
|
||||
}
|
||||
|
||||
readCSV = debounce(() => {
|
||||
const results = parseCSV(this.state.text, this.props.config);
|
||||
this.setState({ results });
|
||||
console.log('GOT:', results);
|
||||
}, 150);
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||
if (this.state.text !== prevState.text || this.props.config !== prevProps.config) {
|
||||
this.readCSV();
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (event: any) => {
|
||||
this.setState({ text: event.target.value });
|
||||
};
|
||||
handleBlur = (event: React.SyntheticEvent<HTMLTextAreaElement>) => {
|
||||
// console.log('BLUR', event);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { table, errors } = this.state.results;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<textarea value={this.state.text} onChange={this.handleChange} onBlur={this.handleBlur} />
|
||||
<div>
|
||||
BAR: / ROWS:{table.rows.length} / COLS:{table.columns.length} / {JSON.stringify(errors)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TableInputCSV;
|
@ -0,0 +1,11 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TableInputCSV renders correctly 1`] = `
|
||||
<div>
|
||||
<textarea
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
`;
|
@ -53,7 +53,7 @@ export interface TimeSeriesVMs {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface Column {
|
||||
export interface Column {
|
||||
text: string;
|
||||
title?: string;
|
||||
type?: string;
|
||||
|
12
yarn.lock
12
yarn.lock
@ -1801,6 +1801,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.40.tgz#4314888d5cd537945d73e9ce165c04cc550144a4"
|
||||
integrity sha512-RRSjdwz63kS4u7edIwJUn8NqKLLQ6LyqF/X4+4jp38MBT3Vwetewi2N4dgJEshLbDwNgOJXNYoOwzVZUSSLhkQ==
|
||||
|
||||
"@types/papaparse@^4.5.9":
|
||||
version "4.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-4.5.9.tgz#ff887bd362f57cd0c87320d2de38ac232bb55e81"
|
||||
integrity sha512-8Pmxp2IEd/y58tOIsiZkCbAkcKI7InYVpwZFVKJyweCVnqnVahKXVjfSo6gvxUVykQsJvtWB+s6Kc60znVfQVw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce"
|
||||
@ -12993,6 +13000,11 @@ pako@~1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4"
|
||||
integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==
|
||||
|
||||
papaparse@^4.6.3:
|
||||
version "4.6.3"
|
||||
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.6.3.tgz#742e5eaaa97fa6c7e1358d2934d8f18f44aee781"
|
||||
integrity sha512-LRq7BrHC2kHPBYSD50aKuw/B/dGcg29omyJbKWY3KsYUZU69RKwaBHu13jGmCYBtOc4odsLCrFyk6imfyNubJQ==
|
||||
|
||||
parallel-transform@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
||||
|
Loading…
Reference in New Issue
Block a user