feat: add table and filter nodule
This commit is contained in:
parent
62502b3b46
commit
9ca49b9ef0
21
package-lock.json
generated
21
package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
40
src/Collections/Nodules.js
Normal file
40
src/Collections/Nodules.js
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
33
src/Controllers/CreateNoduleController.js
Normal file
33
src/Controllers/CreateNoduleController.js
Normal file
@ -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
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
src/Controllers/TableListController.js
Normal file
15
src/Controllers/TableListController.js
Normal file
@ -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
|
||||
@ -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 (
|
||||
<div className='App'>
|
||||
<CreateTableForm />
|
||||
<CreateNodule />
|
||||
<TableList />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
76
src/views/CreateNodule/CreateFilterNoduleForm.js
Normal file
76
src/views/CreateNodule/CreateFilterNoduleForm.js
Normal file
@ -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 (
|
||||
<div className='CreateFiltrerNoduleForm'>
|
||||
<Dropdown
|
||||
placeholder='Select a Comparison Type'
|
||||
fluid
|
||||
selection
|
||||
options={[
|
||||
{key: 'EQUAL', text: 'EQUAL', value: 'EQUAL'},
|
||||
{key: 'GREATER', text: 'GREATER THAN', value: 'GREATER'},
|
||||
{key: 'GREATEREQUAL', text: 'GREATER THEN EQUAL TO', value: 'GREATEREQUAL'},
|
||||
{key: 'LESSER', text: 'LESSER THAN', value: 'LESSER'},
|
||||
{key: 'LESSEREQUAL', text: 'LESSER THEN EQUAL TO', value: 'LESSEREQUAL'}
|
||||
]}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
<Grid columns={2} relaxed='very' stackable>
|
||||
<Grid.Column>
|
||||
<Input placeholder='Key' ref={this.keyInput1} style={{ width: '115px' }} />
|
||||
<Input placeholder='Key' ref={this.keyInput2} style={{ width: '115px' }} />
|
||||
<Input placeholder='Key' ref={this.keyInput3} style={{ width: '115px' }} />
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Input placeholder='Value' ref={this.valueInput1} style={{ width: '115px' }} />
|
||||
<Input placeholder='Value' ref={this.valueInput2} style={{ width: '115px' }} />
|
||||
<Input placeholder='Value' ref={this.valueInput3} style={{ width: '115px' }} />
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CreateFilterNoduleForm
|
||||
|
||||
6
src/views/CreateNodule/CreateNodule.css
Normal file
6
src/views/CreateNodule/CreateNodule.css
Normal file
@ -0,0 +1,6 @@
|
||||
.CreateNodule {
|
||||
width: 380px;
|
||||
padding: 40px;
|
||||
border-radius: 6px;
|
||||
border: solid rgb(240, 240, 240) 1px;
|
||||
}
|
||||
84
src/views/CreateNodule/CreateNodule.js
Normal file
84
src/views/CreateNodule/CreateNodule.js
Normal file
@ -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 <CreateFilterNoduleForm ref={this.filterNoduleForm} />
|
||||
else return ''
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div className='CreateNodule'>
|
||||
<Header as='h3'>Create Nodule</Header>
|
||||
|
||||
<Input
|
||||
placeholder='Nodule Label'
|
||||
ref={this.tableLabelInput}
|
||||
icon='tags'
|
||||
style={{ width: '300px' }}
|
||||
/>
|
||||
<br />
|
||||
|
||||
<Dropdown
|
||||
placeholder='Select a Nodule Type'
|
||||
options={[
|
||||
{key: 'Join Nodule', text: 'Join Nodule', value: 'join', icon: 'sitemap'},
|
||||
{key: 'Filter Nodule', text: 'Filter Nodule', value: 'filter', icon: 'filter'},
|
||||
{key: 'Transform Nodule', text: 'Transform Nodule', value: 'transform', icon: 'sliders horizontal'},
|
||||
]}
|
||||
fluid
|
||||
selection
|
||||
style={{ width: '300px' }}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
<TableSelect />
|
||||
|
||||
{ this.renderNoduleForm() }
|
||||
|
||||
<div className='creatTableFormSubmitButtons'>
|
||||
<Button content='Cancel' secondary />
|
||||
<Button content='Confirm' primary onClick={this.handleSubmit} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CreateNodule
|
||||
49
src/views/CreateNodule/TableSelect.js
Normal file
49
src/views/CreateNodule/TableSelect.js
Normal file
@ -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 (
|
||||
<Label onClick={() => this.toggleSelect(t.label)}>
|
||||
{t.label}
|
||||
{ isSelected ? <Icon name='delete' /> : '' }
|
||||
</Label>
|
||||
)
|
||||
})
|
||||
return tableLabelElements
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div className='TableSelect'>
|
||||
{ this.renderTableLabels() }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TableSelect
|
||||
@ -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 (
|
||||
<div className='CreateTableForm'>
|
||||
<Header as='h3'>Create Table From File</Header>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div>
|
||||
<Input
|
||||
placeholder='Table Label'
|
||||
ref={this.tableLabelInput}
|
||||
@ -43,10 +42,10 @@ class CreateTableForm extends Component {
|
||||
/>
|
||||
|
||||
<div className='creatTableFormSubmitButtons'>
|
||||
<Button content='Confirm' primary />
|
||||
<Button content='Confirm' secondary />
|
||||
<Button content='Cancel' secondary />
|
||||
<Button content='Confirm' primary onClick={this.handleSubmit} />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
0
src/views/TableList/TableList.css
Normal file
0
src/views/TableList/TableList.css
Normal file
54
src/views/TableList/TableList.js
Normal file
54
src/views/TableList/TableList.js
Normal file
@ -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 =>
|
||||
<Card key={t.id} id={t.id}>
|
||||
<Card.Content>
|
||||
<Card.Header>{ t.label }</Card.Header>
|
||||
<Card.Meta>{`${t.rows.length} rows`}</Card.Meta>
|
||||
</Card.Content>
|
||||
<CardContent
|
||||
extra
|
||||
onClick={() => { this.controller.deleteTable(t.id) }}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
Delete <Icon name='trash' />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
return tableListElements
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div className='TableList'>
|
||||
<Card.Group>
|
||||
{ this.renderTableListElements() }
|
||||
</Card.Group>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TableList
|
||||
Loading…
x
Reference in New Issue
Block a user