From 3afba102b017c39316e8cad82a7abd70c8b4068c Mon Sep 17 00:00:00 2001 From: uwap Date: Fri, 10 Nov 2017 22:07:07 +0100 Subject: [PATCH] Implement every UI type except slider --- .eslintrc.js | 2 +- src/UiItems.js | 4 +- src/components/App.js | 9 ++- src/components/UiItemList.js | 112 ++++++++++++++++++++++++++++------- src/map.js | 6 +- src/mqtt.js | 2 +- src/state.js | 6 +- src/util.js | 2 +- src/utils/parseIconName.js | 2 +- 9 files changed, 110 insertions(+), 35 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 83cca54..76f7bca 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -128,7 +128,7 @@ module.exports = { // ES6 "arrow-spacing": "error", - "arrow-parens": "warning", + "arrow-parens": "warn", "no-confusing-arrow": ["error", {"allowParens": true}], // react diff --git a/src/UiItems.js b/src/UiItems.js index 10552f8..fb54a15 100644 --- a/src/UiItems.js +++ b/src/UiItems.js @@ -25,8 +25,8 @@ const enabled = (props: ControlUI, state: State) => { const val = state.values[props.topic]; return props.enableCondition( val.internal == null ? val.actual : val.internal, val.actual, - R.map(x => x.internal == null ? x.actual - : x.internal, state.values == null ? {} : state.values)); + R.map((x) => (x.internal == null ? x.actual + : x.internal), state.values == null ? {} : state.values)); } }; diff --git a/src/components/App.js b/src/components/App.js index 4865bd8..5ea6c7a 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -12,6 +12,8 @@ import ControlMap from "components/ControlMap"; import TopBar from "components/TopBar"; import UiItemList from "components/UiItemList"; +import { keyOf } from "../util"; + export type AppProps = { config: Config }; @@ -28,9 +30,9 @@ class App extends React.Component { this.state = { selectedControl: null, drawerOpened: false, - mqttState: _.map(props.topics, topic => ({ + mqttState: _.mapValues(props.config.topics, (topic) => ({ actual: topic.defaultValue, - internal: topic.values[topic.defaultValue] + internal: keyOf(topic.values, topic.defaultValue) })) }; } @@ -71,7 +73,8 @@ class App extends React.Component { onCloseRequest={this.closeDrawer.bind(this)} > {this.state.selectedControl == null - || } + || } diff --git a/src/components/UiItemList.js b/src/components/UiItemList.js index 9b722b9..c8605fd 100644 --- a/src/components/UiItemList.js +++ b/src/components/UiItemList.js @@ -10,6 +10,11 @@ import { } from "material-ui/List"; import Switch from "material-ui/Switch"; import { renderIcon } from "utils/parseIconName"; +import Input, { InputLabel } from "material-ui/Input"; +import { FormControl } from "material-ui/Form"; +import Select from "material-ui/Select"; +import { MenuItem } from "material-ui/Menu"; +import Button from "material-ui/Button"; export type UiItemListProps = { controls: Array, @@ -22,25 +27,44 @@ export default class UiItemList extends React.Component { } render() { - return this.props.controls.map((control, key) => ( - - {control.icon == null || {renderIcon(control.icon, "mdi-24px")}} - {this.renderControl(control)} - - )); + return this.props.controls.map((control, key) => { + if (control.type == null) { + throw new Error( + "A control is missing the \"type\" parameter" + ); + } + if (control.type === "section") { + return this.renderControl(control); + } + return ( + + {control.icon == null || + {renderIcon(control.icon, "mdi-24px")}} + {this.renderControl(control)} + + ); + }); } renderControl(control: ControlUI) { switch (control.type) { - case "toggle": { - return this.renderToggle(control); - } - default: { - console.error( - `Unknown UI type "${control.type}" for "${control.text}" component` - ); - return "unknown ui type"; - } + case "toggle": { + return this.renderToggle(control); + } + case "dropDown": { + return this.renderDropDown(control); + } + case "section": { + return this.renderSection(control); + } + case "link": { + return this.renderLink(control); + } + default: { + throw new Error( + `Unknown UI type "${control.type}" for "${control.text}" component` + ); + } } } @@ -58,21 +82,20 @@ export default class UiItemList extends React.Component { getValue(control: ControlUI) { const value = this.props.state[control.topic]; if (value == null) { - console.error( + throw new Error( `Unknown topic "${control.topic}" in ${control.type} "${control.text}"` ); - return { internal: "error", actual: "error" }; } return value; } - toggleSwitch(control: ControlUI, newState: boolean) { + toggleSwitch(_control: ControlUI, _newState: boolean) { } renderToggle(control: ControlUI) { const value = this.getValue(control); - const isToggled = control.isToggled || (i => i === (control.on || "on")); + const isToggled = control.isToggled || ((i) => i === (control.on || "on")); const checked = isToggled( value.internal || value.actual, value.actual, this.props.state); return [ @@ -80,9 +103,58 @@ export default class UiItemList extends React.Component { this.toggleSwitch(control, state)} + onChange={(state) => this.toggleSwitch(control, state)} disabled={!this.isEnabled(control)} /> ]; } + + changeDropDown(_control: ControlUI, _newState: string) { + + } + + renderDropDown(control: ControlUI) { + const value = this.getValue(control); + const id = `${control.topic}-${control.name}`; + const options = control.options; + if (options == null) { + throw new Error( + `Parameter "options" missing for ${control.type} "${control.text}"` + ); + } + return ( + + {control.text} + } + > + {_.map(options, (v, k) => {v})} + + + ); + } + + renderSection(control: ControlUI) { + return ( + {control.text} + ); + } + + renderLink(control: ControlUI) { + if (control.link == null) { + throw new Error( + `Parameter "link" missing for ${control.type} "${control.text}"` + ); + } + return ( + + ); + } } diff --git a/src/map.js b/src/map.js index a4471ab..ebed3e5 100644 --- a/src/map.js +++ b/src/map.js @@ -14,8 +14,8 @@ const color = (iconColor, state: State) => { // TODO: give iconColor not only internal but also actual values return iconColor == null ? "#000000" : iconColor( - R.map(x => x.internal == null ? - x.actual : x.internal, state.values == null ? {} : state.values) + R.map((x) => (x.internal == null ? + x.actual : x.internal), state.values == null ? {} : state.values) ); }; const iconHtml = (el, state: State) => @@ -59,7 +59,7 @@ class SpaceMap extends React.Component { crs={Leaflet.CRS.Simple}> {Markers(props)} - {Config.layers.map(x => + {Config.layers.map((x) => this.renderLayer(x, [c([0, 0]), c([props.width, props.height])]))} diff --git a/src/mqtt.js b/src/mqtt.js index 7e60fca..6ec04e4 100644 --- a/src/mqtt.js +++ b/src/mqtt.js @@ -11,7 +11,7 @@ export default function connectMqtt(url: string, store: Store<*, *>) { store.dispatch({ type: Actions.MQTT_CONNECT, payload: client }); - R.forEachObjIndexed(v => + R.forEachObjIndexed((v) => client.subscribe(v.state), Config.topics); }); client.on("message", (topic, message) => { diff --git a/src/state.js b/src/state.js index c50fc90..e64b31d 100644 --- a/src/state.js +++ b/src/state.js @@ -15,7 +15,7 @@ const initState : State = { mqtt: null, uiOpened: null, values: R.map( - topic => { + (topic) => { return { internal: keyOf(topic.values, topic.defaultValue), actual: topic.defaultValue @@ -37,7 +37,7 @@ const onMessage = (state: State, action: StateAction) => { const payload = action.payload == null ? { topic: "", message: {} } : action.payload; // thx flow val.state === payload.topic, Config.topics)); + (val) => val.state === payload.topic, Config.topics)); const message = payload.message; const parsedMessage = (topic: string) => { let parseFunction = Config.topics[topic].parseState; @@ -54,7 +54,7 @@ const onMessage = (state: State, action: StateAction) => { }; }; return R.mergeDeepRight(state, R.objOf("values", R.mergeAll( - R.map(topic => R.objOf(topic, newValue(topic)), topics) + R.map((topic) => R.objOf(topic, newValue(topic)), topics) ))); }; diff --git a/src/util.js b/src/util.js index aebc15b..75cb598 100644 --- a/src/util.js +++ b/src/util.js @@ -2,4 +2,4 @@ import R from "ramda"; export const keyOf = (map: Map, value: a): ?b => - ((keys) => keys[R.findIndex(k => map[k] === value, keys)])(R.keys(map)); + ((keys) => keys[R.findIndex((k) => map[k] === value, keys)])(R.keys(map)); diff --git a/src/utils/parseIconName.js b/src/utils/parseIconName.js index a07dede..9aa5285 100644 --- a/src/utils/parseIconName.js +++ b/src/utils/parseIconName.js @@ -2,7 +2,7 @@ import React from "react"; export default function parseIconName(name: string): string { - return `mdi ${name.split(" ").map(icon => "mdi-".concat(icon)).join(" ")}`; + return `mdi ${name.split(" ").map((icon) => "mdi-".concat(icon)).join(" ")}`; } export const renderIcon = (name: string, extraClass?: string) => {