Quellcode durchsuchen

Started demo_module

Tomi Cvetic vor 8 Jahren
Ursprung
Commit
f8e53d8706

+ 5 - 0
README.md

@@ -0,0 +1,5 @@
+# AutoMate - Lab Automation
+
+AutoMate is a lab automation software.
+
+It is implemented with React.

+ 2 - 0
package.json

@@ -13,6 +13,8 @@
     "redux": "3.6.0",
     "redux-saga": "0.14.3",
     "reselect": "2.5.4",
+    "style-loader": "0.13.2",
+    "stylus-loader": "3.0.1",
     "stylus-normalize": "3.0.3"
   },
   "devDependencies": {

+ 11 - 0
src/demo_module/components/EditRegister.js

@@ -0,0 +1,11 @@
+import React from 'react'
+
+class EditRegisters extends React.Component {
+  render () {
+    return (
+      <p>bit</p>
+    )
+  }
+}
+
+export default EditRegisters

+ 47 - 0
src/demo_module/components/EditRegistermap.js

@@ -0,0 +1,47 @@
+import React from 'react'
+
+class EditRegistermap extends React.Component {
+  constructor () {
+    super()
+    this.update = this.update.bind(this)
+  }
+
+  update () {
+    const { registermap, actions } = this.props
+    actions.updateRegistermap(registermap.id, {
+      id: registermap.id,
+      name: this.regmapName.value,
+      description: this.regmapDescription.value,
+      nrOfRegisters: this.regmapNrOfRegisters.value,
+      bitsPerRegister: this.regmapBitsPerRegister.value,
+      modes: this.regmapModes.value
+    })
+  }
+
+  render () {
+    const { registermap } = this.props
+    console.log('Edit registermap', registermap)
+
+    return (
+      <form className='app-form'>
+        <fieldset className='create-registermap-form-basic'>
+          <button onClick={this.toggleExtended}>+</button>
+          <input type='text' ref={input => { this.regmapName = input }} value={registermap.name} onChange={this.update} placeholder='Registermap Name' />
+          <input type='text' ref={input => { this.regmapDescription = input }} value={registermap.description} onChange={this.update} placeholder='Description' />
+        </fieldset>
+        <fieldset className='create-registermap-form-extended'>
+          <input type='text' ref={input => { this.regmapNrOfRegisters = input }} value={registermap.nrOfRegisters} onChange={this.update} placeholder='Number of registers' />
+          <input type='text' ref={input => { this.regmapBitsPerRegister = input }} value={registermap.bitsPerRegister} onChange={this.update} placeholder='Bits per register' />
+          <input type='text' ref={input => { this.regmapModes = input }} list='modes' value={registermap.modes} onChange={this.update} placeholder='modes' />
+          <datalist id='modes'>
+            <option value='GPS only'>GPS only</option>
+            <option value='Multi GNSS'>Multi GNSS</option>
+          </datalist>
+          <button type='submit'>Save</button>
+        </fieldset>
+      </form>
+    )
+  }
+}
+
+export default EditRegistermap

+ 70 - 0
src/demo_module/components/EditSetting.js

@@ -0,0 +1,70 @@
+import React from 'react'
+
+class EditSetting extends React.Component {
+  constructor () {
+    super()
+    this.saveSetting = this.saveSetting.bind(this)
+    this.updateSetting = this.updateSetting.bind(this)
+  }
+
+  saveSetting (event) {
+    event.preventDefault()
+    this.props.actions.updateSetting(12, {
+      name: this.name.value,
+      description: this.description.value,
+      nrOfBits: this.nrOfBits.value,
+      comment: this.comment.value,
+      format: this.format.value,
+      formatOverride: this.formatOverride.value
+    })
+    console.log('Saving ')
+  }
+
+  updateSetting (event) {
+    event.preventDefault()
+    this.props.actions.updateSetting(this.id.value, {
+      name: this.name.value,
+      description: this.description.value,
+      nrOfBits: this.nrOfBits.value,
+      comment: this.comment.value,
+      format: this.format.value,
+      formatOverride: this.formatOverride.value
+    })
+    console.log('Updating')
+  }
+
+  checkSetting (event) {
+
+  }
+
+  render () {
+    const { setting } = this.props
+    if (typeof setting.id === 'undefined') {
+      setting.id = null
+      setting.name = ''
+      setting.description = ''
+      setting.nrOfBits = 1
+      setting.range = {
+        lower: 0,
+        upper: 1
+      }
+      setting.comment = ''
+      setting.format = ''
+      setting.formatOverride = {}
+    }
+    return (
+      <form className='app-form' onSubmit={this.saveSetting}>
+        <input type='text' ref={input => { this.name = input }} value={setting.name} placeholder='Setting name' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <input type='text' ref={input => { this.description = input }} value={setting.description} placeholder='Description' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <input type='text' ref={input => { this.id = input }} value={setting.id} placeholder='Description' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <input type='text' ref={input => { this.nrOfBits = input }} value={setting.nrOfBits} placeholder='Number of bits' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <input type='text' ref={input => { this.comment = input }} value={setting.comment} placeholder='Comment' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <input type='text' ref={input => { this.format = input }} value={setting.format} placeholder='Format' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <input type='text' ref={input => { this.formatOverride = input }} value={setting.formatOverride} placeholder='Format Override' onChange={this.updateSetting} onBlur={this.checkSetting} />
+        <button type='submit'>Save</button>
+      </form>
+    )
+  }
+}
+
+export default EditSetting

+ 38 - 0
src/demo_module/components/Registermap.js

@@ -0,0 +1,38 @@
+import React from 'react'
+import ShowRegistermap from './ShowRegistermap'
+import RegistermapList from './RegistermapList'
+
+class Registermap extends React.Component {
+  render () {
+    // Retrieve the registermapId from the URL
+    const { registermapId } = this.props.params
+    const { registermapActions } = this.props
+    const { registermap, settings } = this.props.registermap
+
+    let registerMap
+    if (typeof registermapId !== 'undefined' && registermap && registermap.length > 0) {
+      // It the registermapId is defined, check whether there's such a registermap
+      registerMap = registermap.find(registermap => { return (registermap.id === registermapId) })
+    } else if (registermap && registermap.length > 0) {
+      registerMap = registermap[0]
+      this.props.router.transitionTo(`/registermap/${registerMap}`)
+    }
+    console.log('Registermap', registerMap, registermap, settings)
+
+    return (
+      <div className='app-main'>
+        <div className='app-content'>
+          <button onClick={registermapActions.loadSamples}>Load sample data</button>
+          {(typeof registerMap !== 'undefined') ? <ShowRegistermap registermap={registerMap} settingList={settings} actions={registermapActions} /> : <p>Please select a registermap.</p>}
+        </div>
+        <div className='app-aside-left'>
+          <p>New Registermap Button</p>
+          <p>Registermap List</p>
+          {<RegistermapList registermapList={registermap} />}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default Registermap

+ 23 - 0
src/demo_module/components/RegistermapList.js

@@ -0,0 +1,23 @@
+import React from 'react'
+import { Link } from 'react-router'
+
+class RegistermapList extends React.Component {
+  render () {
+    const { registermapList } = this.props
+    if (typeof registermapList !== 'undefined' && registermapList.length > 0) {
+      return (
+        <ul className='registermap-list scrollable'>
+          {registermapList.map((registermap, key) =>
+            <li key={key}><Link to={`/registermap/${registermap.id}`}>{registermap.name}</Link></li>
+          )}
+        </ul>
+      )
+    } else {
+      return (
+        <p>No registermaps found.</p>
+      )
+    }
+  }
+}
+
+export default RegistermapList

+ 84 - 0
src/demo_module/components/ShowRegistermap.js

@@ -0,0 +1,84 @@
+import React from 'react'
+import EditRegistermap from './EditRegistermap'
+import EditSetting from './EditSetting'
+import './registermap.css'
+
+class ShowRegistermap extends React.Component {
+  constructor () {
+    super()
+    this.sayMyName = this.sayMyName.bind(this)
+    this.table = this.table.bind(this)
+
+    this.bitmap = {}
+  }
+
+  sayMyName (event) {
+    event.preventDefault()
+    console.log('Hi, my name is', event)
+  }
+
+  table (registermap, settings) {
+    // Generate a table with rows for registers and columns for bits
+    let trow = []
+    let idx
+
+    const thead = []
+    const tbody = []
+
+    for (let idxCol = 0; idxCol < registermap.bitsPerRegister; idxCol += 1) {
+      trow.push(<th key={idxCol}>{idxCol}</th>)
+    }
+    trow.push(<th key={registermap.bitsPerRegister}>Register Name</th>)
+    thead.push(<tr key={-1}>{trow}</tr>)
+
+    for (let idxRow = 0; idxRow < registermap.nrOfRegisters; idxRow += 1) {
+      trow = []
+      for (let idxCol = 0; idxCol < registermap.bitsPerRegister; idxCol += 1) {
+        idx = idxRow * registermap.bitsPerRegister + idxCol
+        this.bitmap[idx] = ''
+        trow.push(<td key={idx} onClick={this.sayMyName}>{this.bitmap[idx]}</td>)
+      }
+      trow.push(<td key={`inp${idxRow}`}><input ref={input => { this.bitmap[idxRow] = input }} type='text' placeholder={`register${idxRow}`} onChange={this.updateRegister} /></td>)
+      tbody.push(<tr key={idxRow}>{trow}</tr>)
+    }
+    return (
+      <table>
+        <thead>{thead}</thead>
+        <tbody>{tbody}</tbody>
+      </table>
+    )
+  }
+
+  render () {
+    const { registermap, settingList, actions } = this.props
+    console.log('Show registermap', registermap, settingList, actions)
+    if (typeof settingList === 'undefined') {
+      return (
+        <p>Please select a registermap</p>
+      )
+    }
+
+    return (
+      <div className='content-flex'>
+        <div className='content-main'>
+          <h2>Registermap {registermap.name}</h2>
+          <EditRegistermap registermap={registermap} actions={actions} />
+          <h2>Registers</h2>
+          {this.table(registermap, settingList)}
+          <div>Warning: Not all settings fit in the registers!</div>
+        </div>
+        <div className='content-aside-right'>
+          <h2>Settings</h2>
+          {settingList.map((value, idx) => {
+            return (
+              <EditSetting key={idx} setting={value} actions={actions} />
+            )
+          }
+          )}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default ShowRegistermap

+ 7 - 0
src/demo_module/components/index.js

@@ -0,0 +1,7 @@
+import EditRegistermap from './EditRegistermap'
+import EditSetting from './EditSetting'
+import EditRegister from './EditRegister'
+import Registermap from './Registermap'
+import ShowRegistermap from './ShowRegistermap'
+
+export default { Registermap, EditRegistermap, EditSetting, EditRegister, ShowRegistermap }

+ 17 - 0
src/demo_module/components/registermap.css

@@ -0,0 +1,17 @@
+table,
+tbody,
+thead {
+  border-collapse: collapse;
+}
+table tr,
+tbody tr,
+thead tr,
+table th,
+tbody th,
+thead th,
+table td,
+tbody td,
+thead td {
+  border-collapse: collapse;
+  border: 1px solid #dcdef2;
+}

+ 5 - 0
src/demo_module/components/registermap.styl

@@ -0,0 +1,5 @@
+table, tbody, thead
+	border-collapse collapse
+	tr, th, td
+		border-collapse collapse
+		border 1px solid #DCDEF2

+ 14 - 0
src/demo_module/constants.js

@@ -0,0 +1,14 @@
+/*
+ * constants.js
+ *
+ * Collection of all constants used in the component.
+ * Also define 'name' which is used to identify the component.
+ **/
+
+/** NAME is used to identify the module and to specify actions and reducers. */
+export const NAME = 'registermap'
+console.log('Constants NAME', NAME)
+
+/** DATA contains a list with the state variable names used in the module */
+export const DATA = ['primary', 'secondary1', 'secondary2']
+console.log('Constants DATA', DATA)

+ 0 - 0
src/demo_module/helpers.js


+ 49 - 0
src/demo_module/index.js

@@ -0,0 +1,49 @@
+/**
+ * index.js
+ *
+ * If you need this component, import the default exports
+ * in this file. It gives you a reference for everything
+ * needed to interact with it.
+ **/
+
+import * as constants from './constants'
+import { actions, reducer, state } from './state'
+import components from './components'
+// import { createSelector } from 'reselect'
+// import { NAME } from './constants'
+// import _ from 'lodash'
+
+const filters = {
+  all: registermap => registermap.filter(p => registermap.active)
+}
+
+const selectors = {
+  getAll: state => state[constants.NAME],
+  getActive: () => []
+}
+
+function registermapFactory () {
+  return {
+
+  }
+}
+
+function settingFactory () {
+  return {
+
+  }
+}
+
+/* export const getAll = state => state[NAME]
+export const getActive = _.compose(filterActive, getAll)
+export const getCounts = createSelector(
+    getAll,
+    getActive,
+    (allProjects, activeProjects) => ({
+      all: allProjects.length,
+      active: activeProjects.length
+    })
+) */
+
+console.log('Exporting registermap:', { actions, constants, components, filters, selectors, reducer, state, registermapFactory, settingFactory })
+export default { actions, constants, components, filters, selectors, reducer, state, registermapFactory, settingFactory }

+ 62 - 0
src/demo_module/initialData.js

@@ -0,0 +1,62 @@
+/**
+  * initial data for the demo module
+  **/
+
+/**
+  * primary contains the primary data for the module.
+  * It could come from a database, file or any other asynchronous source.
+  * It can have joins from other databases directly in a field (e.g. joins)
+  **/
+export const primary = [{
+  id: 'primary-1',
+  name: 'String1',
+  active: true,
+  items: [
+    { id: 'item1-1' },
+    { id: 'item1-2' }
+  ],
+  joins: [{
+    id: 'id2',
+    primaryId: 'primary-1',
+    name: 'secondary1-2'
+  }]
+}, {
+  id: 'primary-2',
+  name: 'String2',
+  active: false,
+  items: [
+    { id: 'item2-1' },
+    { id: 'item2-2' },
+    { id: 'item2-3' },
+    { id: 'item2-4' }
+  ],
+  joins: [{
+    id: 'id1',
+    primaryId: 'primary-2',
+    name: 'secondary1-1'
+  }, {
+    id: 'id3',
+    primaryId: 'primary-2',
+    name: 'secondary1-3'
+  }]
+}]
+
+/**
+  * secondary contains the secondary data for the module.
+  * It could come from a database, file or any other asynchronous source.
+  * It is collected from the source and placed as reference in the primary data.
+  * It should have a reference to the primary item it belongs to.
+  **/
+export const secondary2 = [{
+  id: 'id1',
+  primaryId: 'primary-1',
+  name: 'secondary2-1'
+}, {
+  id: 'id2',
+  primaryId: 'primary-2',
+  name: 'secondary2-2'
+}, {
+  id: 'id3',
+  primaryId: 'primary-1',
+  name: 'secondary2-3'
+}]

+ 140 - 0
src/demo_module/state.js

@@ -0,0 +1,140 @@
+/**
+ * state.js
+ *
+ * Collection of everything which has to do with state changes.
+ * - actionTypes
+ * - actions
+ * - reducers
+ **/
+
+import { NAME, DATA } from './constants'
+import { primary, secondary2 } from './initialData'
+// import { call, put, takeEvery } from 'redux-saga/effects'
+
+/** actionTypes define what actions are handeled by the reducer. */
+export const actionTypes = {}
+export const actions = {}
+
+// Generate default actionsTypes CREATE, UPDATE, DELETE for every data type
+DATA.forEach(data => {
+  ['create', 'update', 'delete'].forEach(action => {
+    const actionType = `${action.toUpperCase()}_${data.toUpperCase()}`
+    const actionName = `${action}${data[0].toUpperCase()}${data.substring(1)}`
+    actionTypes[actionType] = `${NAME}/${actionType}`
+    actions[actionName] = (id, data) => { return { type: actionType, id, data } }
+  })
+})
+
+// Add specific actionTypes/actions
+actionTypes['LOAD_SAMPLES'] = `${NAME}/LOAD_SAMPLES`
+actions['loadSamples'] = () => { return { type: `${NAME}/LOAD_SAMPLES` } }
+console.log('State actionTypes, actions', actionTypes, actions)
+
+/** state definition */
+/** It is generally easier to not have another object here. If you can combine everything into
+  * the primary data, do it. */
+export const state = {
+  primary: [],
+  secondary2: []
+}
+console.log('State state', state)
+
+/** reducer is called by the redux dispatcher and handles all component actions */
+function secondaryReducer (state = {}, action) {
+  console.log(`Entering registermap setting reducer.`, state, action)
+  switch (action.type) {
+    case actionTypes.CREATE_SETTING:
+      console.log(`Creating setting.`, state, action)
+      return {
+        ...state,
+        [action.project.projectId]: action.project
+      }
+    case actionTypes.UPDATE_SETTING:
+      console.log(`Update setting.`, state, action)
+      return {
+        ...state,
+        [action.projectId]: action.project
+      }
+    case actionTypes.DELETE_SETTING:
+      console.log(`Delete setting.`, state, action)
+      return {
+        ...state,
+        [action.projectId]: null
+      }
+    default:
+      return state
+  }
+}
+
+function primaryReducer (state = {}, action) {
+  console.log(`Entering registermap reducer.`, state, action)
+  switch (action.type) {
+    case actionTypes.CREATE_REGISTERMAP:
+      console.log(`Creating registermap.`, state, action)
+      return {
+        ...state,
+        [action.project.projectId]: action.project
+      }
+    case actionTypes.UPDATE_REGISTERMAP:
+      console.log(`Update registermap.`, state, action)
+      const idx = state.findIndex(elem => { return (elem.id === action.registermapId) })
+      console.log(`Update registermap.`, idx)
+      const next = [
+        ...state.slice(0, idx),
+        action.registermap,
+        ...state.slice(idx + 1)
+      ]
+      console.log(`Update registermap.`, next)
+      return next
+    case actionTypes.DELETE_REGISTERMAP:
+      console.log(`Delete registermap.`, state, action)
+      return {
+        ...state,
+        [action.projectId]: null
+      }
+    default:
+      return state
+  }
+}
+
+export function reducer (state = {}, action) {
+  console.log(`Entering registermap root reducer.`, state, action)
+  if (typeof action.settingId !== 'undefined') {
+    return {
+      ...state,
+      registermap: secondaryReducer(state.registermap, action)
+    }
+  }
+  if (typeof action.registermapId !== 'undefined') {
+    return {
+      ...state,
+      registermap: primaryReducer(state.registermap, action)
+    }
+  }
+  return state
+}
+console.log('State reducer', reducer)
+
+/** sagas are asynchronous workers (JS generators) to handle the state.
+// Worker
+export function * incrementAsync () {
+  try {
+    const data = yield call(Api.isIncrementOk)
+    yield put({ type: 'INCREMENT_SUCCESS', data })
+  } catch (error) {
+    yield put({ type: 'INCREMENT_FAIL', error})
+  }
+}
+
+// Watcher (intercepts INCREMENT_REQUEST, dispatches INCREMENT_SUCCESS or INCREMENT_FAIL in return.)
+export function * watchIncrementAsync () {
+  yield takeEvery('INCREMENT_REQUEST', incrementAsync)
+}
+
+// export all sagas in parallel
+function * sagas () {
+  yield takeEvery('INCREMENT_REQUEST')
+  yield takeEvery('DECREMENT_REQUEST')
+} */
+export const sagas = null
+console.log('State sagas', sagas)

+ 1 - 0
src/registermap/components/ShowRegistermap.js

@@ -1,6 +1,7 @@
 import React from 'react'
 import EditRegistermap from './EditRegistermap'
 import EditSetting from './EditSetting'
+import './registermap.css'
 
 class ShowRegistermap extends React.Component {
   constructor () {

+ 17 - 0
src/registermap/components/registermap.css

@@ -0,0 +1,17 @@
+table,
+tbody,
+thead {
+  border-collapse: collapse;
+}
+table tr,
+tbody tr,
+thead tr,
+table th,
+tbody th,
+thead th,
+table td,
+tbody td,
+thead td {
+  border-collapse: collapse;
+  border: 1px solid #dcdef2;
+}

+ 5 - 0
src/registermap/components/registermap.styl

@@ -0,0 +1,5 @@
+table, tbody, thead
+	border-collapse collapse
+	tr, th, td
+		border-collapse collapse
+		border 1px solid #DCDEF2