From 9ca49b9ef0921e8b26768e37c215d3e05af7dc2c Mon Sep 17 00:00:00 2001 From: ysandler Date: Tue, 14 Jul 2020 23:27:26 -0500 Subject: [PATCH] feat: add table and filter nodule --- package-lock.json | 21 +++++ package.json | 3 +- src/Collections/Nodules.js | 40 +++++++++ src/Collections/Tables.js | 32 ++++++- src/Controllers/CreateNoduleController.js | 33 ++++++++ src/Controllers/CreateTableController.js | 15 +++- src/Controllers/TableListController.js | 15 ++++ src/views/App.js | 4 + .../CreateNodule/CreateFilterNoduleForm.js | 76 +++++++++++++++++ src/views/CreateNodule/CreateNodule.css | 6 ++ src/views/CreateNodule/CreateNodule.js | 84 +++++++++++++++++++ src/views/CreateNodule/TableSelect.js | 49 +++++++++++ src/views/CreateTable/CreateTableForm.js | 21 +++-- src/views/TableList/TableList.css | 0 src/views/TableList/TableList.js | 54 ++++++++++++ 15 files changed, 438 insertions(+), 15 deletions(-) create mode 100644 src/Collections/Nodules.js create mode 100644 src/Controllers/CreateNoduleController.js create mode 100644 src/Controllers/TableListController.js create mode 100644 src/views/CreateNodule/CreateFilterNoduleForm.js create mode 100644 src/views/CreateNodule/CreateNodule.css create mode 100644 src/views/CreateNodule/CreateNodule.js create mode 100644 src/views/CreateNodule/TableSelect.js create mode 100644 src/views/TableList/TableList.css create mode 100644 src/views/TableList/TableList.js diff --git a/package-lock.json b/package-lock.json index 476f333..642c38b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1852,6 +1852,11 @@ } } }, + "@types/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==" + }, "@types/yargs": { "version": "13.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", @@ -12841,6 +12846,22 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, + "uuidv4": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.1.1.tgz", + "integrity": "sha512-ZplGb1SHFMVH3l7PUQl2Uwo+FpJQV6IPOoU+MjjbqrNYQolqbGwv+/sn9F+AGMsMOgGz3r9JN3ztGUi0VzMxmw==", + "requires": { + "@types/uuid": "8.0.0", + "uuid": "8.2.0" + }, + "dependencies": { + "uuid": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" + } + } + }, "v8-compile-cache": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", diff --git a/package.json b/package.json index d0487a3..02b228c 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "react-dom": "^16.13.1", "react-scripts": "3.4.1", "semantic-ui-css": "^2.4.1", - "semantic-ui-react": "^0.88.2" + "semantic-ui-react": "^0.88.2", + "uuidv4": "^6.1.1" }, "scripts": { "start": "react-scripts start", diff --git a/src/Collections/Nodules.js b/src/Collections/Nodules.js new file mode 100644 index 0000000..24736bb --- /dev/null +++ b/src/Collections/Nodules.js @@ -0,0 +1,40 @@ +import { FilterNodule, JoinNodule, TransformNodule } from 'dmein' +import { uuid } from 'uuidv4' + +let instance = null + +class Nodules { + constructor () { + if (!instance) instance = this + this.collection = [] + return instance + } + + addNewFilterNodule = props => { + try { + const newFilterNodule = new FilterNodule({ + id: props.id || uuid(), + label: props.label, + tables: props.tables, + filterParams: props.filterParams, + filterType: props.filterType + }) + this.collection.push(newFilterNodule) + } catch (err) { + console.error(err) + } + } + + removeById = id => { + const indexToRemove = this.collection.findIndex(n => n.id === id) + if (this.collection.length === 1 && indexToRemove > -1) { + this.collection = [] + } + else { + const modifiedCollection = this.collection.splice(indexToRemove, 1) + this.collection = modifiedCollection + } + } +} + +export default Nodules \ No newline at end of file diff --git a/src/Collections/Tables.js b/src/Collections/Tables.js index 81ec32d..9e06bfc 100644 --- a/src/Collections/Tables.js +++ b/src/Collections/Tables.js @@ -1,14 +1,42 @@ import { Table } from 'dmein' +import { uuid } from 'uuidv4' let instance = null class Tables { constructor () { if (!instance) instance = this - - console.log(d) + this.collection = [] return instance } + + addNewTable = table => { + try { + const newTable = new Table({ + id: table.id || uuid(), + label: table.label, + rows: table.rows + }) + this.collection.push(newTable) + } catch (err) { + console.error(err) + } + } + + removeTableById = id => { + const indexToRemove = this.collection.findIndex(t => t.id === id) + if (this.collection.length === 1 && indexToRemove > -1) { + this.collection = [] + } + else { + const modifiedCollection = this.collection.splice(indexToRemove, 1) + this.collection = modifiedCollection + } + } + + getCollectionProps = () => this.collection.map(table => table.getProperties()) + + getTableByLabel = label => this.collection.find(t => label === t.label) } export default Tables diff --git a/src/Controllers/CreateNoduleController.js b/src/Controllers/CreateNoduleController.js new file mode 100644 index 0000000..d9373a4 --- /dev/null +++ b/src/Controllers/CreateNoduleController.js @@ -0,0 +1,33 @@ +import Tables from '../Collections/Tables' +import Nodules from '../Collections/Nodules' + +class CreateNoduleController { + constructor() { + this.nodules = new Nodules() + this.tables = new Tables() + this.updatedNodulesEvent = new Event('updateNodules') + } + + addNewFilterNodule = (props) => { + const { label, filterType, filterParams, tablesToImportByLabel } = props + const tables = tablesToImportByLabel.map(label => { + return this.tables.getTableByLabel(label) + }) + + this.nodules.addNewFilterNodule({ + label, + filterType, + filterParams, + tables + }) + console.log(this.nodules) + document.dispatchEvent(this.updatedNodulesEvent) + } + + deleteNodule = id => { + this.nodules.removeTableById(id) + document.dispatchEvent(this.updatedNodulesEvent) + } +} + +export default CreateNoduleController \ No newline at end of file diff --git a/src/Controllers/CreateTableController.js b/src/Controllers/CreateTableController.js index 2e15a24..acf6ee8 100644 --- a/src/Controllers/CreateTableController.js +++ b/src/Controllers/CreateTableController.js @@ -2,9 +2,22 @@ import Tables from '../Collections/Tables' import FileAccess from '../Services/FileAccess' class CreateTableController { - constructor(props) { + constructor() { this.tables = new Tables() this.fileAccess = new FileAccess() + this.updatedTablesEvent = new Event('updateTables') + } + + submitLocalFile = async submition => { + const { label, file } = submition + this.fileAccess.setFile(file) + const fileData = await this.fileAccess.readFile() + + this.tables.addNewTable({ + label: label, + rows: fileData + }) + document.dispatchEvent(this.updatedTablesEvent) } } diff --git a/src/Controllers/TableListController.js b/src/Controllers/TableListController.js new file mode 100644 index 0000000..a678cdb --- /dev/null +++ b/src/Controllers/TableListController.js @@ -0,0 +1,15 @@ +import Tables from '../Collections/Tables' + +class TableListController { + constructor() { + this.tables = new Tables() + this.updatedTablesEvent = new Event('updateTables') + } + + deleteTable = id => { + this.tables.removeTableById(id) + document.dispatchEvent(this.updatedTablesEvent) + } +} + +export default TableListController \ No newline at end of file diff --git a/src/views/App.js b/src/views/App.js index 9ceb4e4..b4d6f74 100644 --- a/src/views/App.js +++ b/src/views/App.js @@ -2,12 +2,16 @@ import React, { Component } from 'react' import './App.css' import 'semantic-ui-css/semantic.min.css' import CreateTableForm from './CreateTable/CreateTableForm' +import TableList from './TableList/TableList' +import CreateNodule from './CreateNodule/CreateNodule' class App extends Component { render = () => { return (
+ +
) } diff --git a/src/views/CreateNodule/CreateFilterNoduleForm.js b/src/views/CreateNodule/CreateFilterNoduleForm.js new file mode 100644 index 0000000..38c4b8d --- /dev/null +++ b/src/views/CreateNodule/CreateFilterNoduleForm.js @@ -0,0 +1,76 @@ +import React, { Component } from 'react' +import { Input, Dropdown, Grid } from 'semantic-ui-react' +import './CreateNodule.css' + +class CreateFilterNoduleForm extends Component { + constructor () { + super() + this.state = { filterType: '' } + + this.keyInput1 = React.createRef() + this.keyInput2 = React.createRef() + this.keyInput3 = React.createRef() + this.valueInput1 = React.createRef() + this.valueInput2 = React.createRef() + this.valueInput3 = React.createRef() + document.addEventListener('updateTables', this.updateTableList) + } + + handleChange = (e, value) => { + this.setState({ filterType: value.value }) + } + + getFilterProperties = () => { + let filterParams = {} + + if (this.keyInput1.current.inputRef.current.value) + filterParams[this.keyInput1.current.inputRef.current.value] = this.valueInput1.current.inputRef.current.value + + if (this.keyInput2.current.inputRef.current.value) + filterParams[this.keyInput2.current.inputRef.current.value] = this.valueInput2.current.inputRef.current.value + + if (this.keyInput3.current.inputRef.current.value) + filterParams[this.keyInput3.current.inputRef.current.value] = this.valueInput3.current.inputRef.current.value + + return { + filterType: this.state.filterType, + filterParams + } + } + + render = () => { + return ( +
+ + + + + + + + + + + + + + +
+ ) + } +} + +export default CreateFilterNoduleForm + diff --git a/src/views/CreateNodule/CreateNodule.css b/src/views/CreateNodule/CreateNodule.css new file mode 100644 index 0000000..2561bd5 --- /dev/null +++ b/src/views/CreateNodule/CreateNodule.css @@ -0,0 +1,6 @@ +.CreateNodule { + width: 380px; + padding: 40px; + border-radius: 6px; + border: solid rgb(240, 240, 240) 1px; +} \ No newline at end of file diff --git a/src/views/CreateNodule/CreateNodule.js b/src/views/CreateNodule/CreateNodule.js new file mode 100644 index 0000000..74c468a --- /dev/null +++ b/src/views/CreateNodule/CreateNodule.js @@ -0,0 +1,84 @@ +import React, { Component } from 'react' +import { Button, Input, Header, Dropdown, Table } from 'semantic-ui-react' +import CreateFilterNoduleForm from './CreateFilterNoduleForm' +import './CreateNodule.css' + +import Tables from '../../Collections/Tables' +import CreateNoduleController from '../../Controllers/CreateNoduleController' +import TableSelect from './TableSelect' + +class CreateNodule extends Component { + constructor () { + super() + + this.state = { + noduleType: '', + tablesToImportByLabel: [] + } + + this.tables = new Tables() + this.controller = new CreateNoduleController() + + this.filterNoduleForm = React.createRef() + + document.addEventListener('updateTables', this.updateTableList) + } + + handleChange = (e, value) => { + this.setState({ noduleType: value.value }) + } + + handleSubmit = () => { + if (this.state.noduleType === 'filter') + console.log(this.filterNoduleForm.current.getFilterProperties()) + } + + updateTableList = () => { + this.setState({tables: this.tables.getCollectionProps()}) + } + + renderNoduleForm = () => { + if (this.state.noduleType === 'filter') return + else return '' + } + + render = () => { + return ( +
+
Create Nodule
+ + +
+ + + + + + { this.renderNoduleForm() } + +
+
+
+ ) + } +} + +export default CreateNodule diff --git a/src/views/CreateNodule/TableSelect.js b/src/views/CreateNodule/TableSelect.js new file mode 100644 index 0000000..d03a633 --- /dev/null +++ b/src/views/CreateNodule/TableSelect.js @@ -0,0 +1,49 @@ +import React, { Component } from 'react' +import { Label, Icon } from 'semantic-ui-react' +import './CreateNodule.css' + +import Tables from '../../Collections/Tables' + +class TableSelect extends Component { + constructor () { + super() + this.tables = new Tables() + this.state = { + selectedTables: [], + tables: this.tables.getCollectionProps() + } + document.addEventListener('updateTables', this.updateTableList) + } + + toggleSelect = label => { + console.log(label) + } + + updateTableList = () => { + this.setState({tables: this.tables.getCollectionProps()}) + } + + renderTableLabels = () => { + const { selectedTables, tables } = this.state + const tableLabelElements = tables.map(t => { + const isSelected = label => selectedTables.includes(label) + return ( + + ) + }) + return tableLabelElements + } + + render = () => { + return ( +
+ { this.renderTableLabels() } +
+ ) + } +} + +export default TableSelect diff --git a/src/views/CreateTable/CreateTableForm.js b/src/views/CreateTable/CreateTableForm.js index e02b1a9..e38f0e8 100644 --- a/src/views/CreateTable/CreateTableForm.js +++ b/src/views/CreateTable/CreateTableForm.js @@ -2,30 +2,29 @@ import React, { Component } from 'react' import { Button, Input, Header } from 'semantic-ui-react' import './CreateTableForm.css' -import FileAccess from '../../Services/FileAccess' -const fileAccess = new FileAccess() - +import CreateTableController from '../../Controllers/CreateTableController' class CreateTableForm extends Component { constructor () { super() + this.controller = new CreateTableController() this.tableLabelInput = React.createRef() this.tableFileInput = React.createRef() } handleSubmit = async e => { e.preventDefault() + const label = this.tableLabelInput.current.inputRef.current.value + const file = this.tableFileInput.current.inputRef.current.files[0] - fileAccess.setFile(this.tableFileInput.current.inputRef.current.files[0]) - const fileData = await fileAccess.readFile() - console.log(fileData) + this.controller.submitLocalFile({ label, file }) } render = () => { return (
Create Table From File
-
+
-
-
-
) } diff --git a/src/views/TableList/TableList.css b/src/views/TableList/TableList.css new file mode 100644 index 0000000..e69de29 diff --git a/src/views/TableList/TableList.js b/src/views/TableList/TableList.js new file mode 100644 index 0000000..abe2008 --- /dev/null +++ b/src/views/TableList/TableList.js @@ -0,0 +1,54 @@ +import React, { Component } from 'react' +import { Card, Icon, CardContent } from 'semantic-ui-react' +import './TableList.css' + +import Tables from '../../Collections/Tables' +import TableListController from '../../Controllers/TableListController' + +class TableList extends Component { + constructor () { + super() + + this.tables = new Tables() + this.controller = new TableListController() + this.state = { tables: this.tables.getCollectionProps() } + + document.addEventListener('updateTables', this.updateTableList) + } + + updateTableList = () => { + this.setState({tables: this.tables.getCollectionProps()}) + } + + renderTableListElements = () => { + const { tables } = this.state + const tableListElements = tables.map(t => + + + { t.label } + {`${t.rows.length} rows`} + + { this.controller.deleteTable(t.id) }} + style={{ cursor: 'pointer' }} + > + Delete + + + ) + return tableListElements + } + + render = () => { + return ( +
+ + { this.renderTableListElements() } + +
+ ) + } +} + +export default TableList