From adffea950af0b4911f3fe56ca6d7d5c1ff4fa89c Mon Sep 17 00:00:00 2001 From: Alex Mikhalev Date: Fri, 13 Oct 2017 16:11:37 -0600 Subject: [PATCH] Lots of good improvements --- .vscode/tasks.json | 5 ++++ app/components/App.tsx | 2 +- app/components/DeviceView.tsx | 24 +++++++++++-------- app/components/DurationInput.tsx | 7 ++++-- app/components/RunSectionForm.tsx | 9 +++++--- app/components/SectionTable.tsx | 2 +- app/state/StateBase.ts | 11 +++++++++ app/state/index.ts | 33 ++------------------------- app/state/web.ts | 14 ++++++++++++ app/styles/app.css | 4 ++++ common/sprinklers/SprinklersDevice.ts | 14 ++++-------- common/sprinklers/mqtt/index.ts | 7 +++--- 12 files changed, 71 insertions(+), 61 deletions(-) create mode 100644 app/state/StateBase.ts create mode 100644 app/state/web.ts diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f461b63..f480298 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -48,6 +48,11 @@ "type": "npm", "script": "start:dev-server", "problemMatcher": [] + }, + { + "type": "npm", + "script": "start:nodemon", + "problemMatcher": [] } ] } \ No newline at end of file diff --git a/app/components/App.tsx b/app/components/App.tsx index 36adbb9..90a601f 100644 --- a/app/components/App.tsx +++ b/app/components/App.tsx @@ -13,7 +13,7 @@ import "semantic-ui-css/semantic.css"; class App extends React.Component { render() { return ( - + {/* */} diff --git a/app/components/DeviceView.tsx b/app/components/DeviceView.tsx index 6211bf9..0dff0f2 100644 --- a/app/components/DeviceView.tsx +++ b/app/components/DeviceView.tsx @@ -1,25 +1,25 @@ import * as classNames from "classnames"; import { observer } from "mobx-react"; import * as React from "react"; -import { Header, Icon, Item } from "semantic-ui-react"; +import { Grid, Header, Icon, Item } from "semantic-ui-react"; import { injectState, MqttApiState } from "@app/state"; import { SprinklersDevice } from "@common/sprinklers"; import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from "."; -const ConnectionState = ({ connected }: { connected: boolean }) => { +function ConnectionState({ connected, className }: { connected: boolean, className?: string }) { const classes = classNames({ "device--connectionState": true, "device--connectionState-connected": connected, "device--connectionState-disconnected": !connected, - }); + }, className); return ( - +
  {connected ? "Connected" : "Disconnected"} - +
); -}; +} interface DeviceViewProps { deviceId: string; @@ -44,14 +44,20 @@ class DeviceView extends React.Component {
- Device {id} +
Device {id}
Raspberry Pi Grinklers Instance - - + + + + + + + +
diff --git a/app/components/DurationInput.tsx b/app/components/DurationInput.tsx index 83db646..4d08a49 100644 --- a/app/components/DurationInput.tsx +++ b/app/components/DurationInput.tsx @@ -1,3 +1,4 @@ +import * as classNames from "classnames"; import * as React from "react"; import { Input, InputProps } from "semantic-ui-react"; @@ -5,13 +6,15 @@ import { Duration } from "@common/Duration"; export default class DurationInput extends React.Component<{ duration: Duration, - onDurationChange: (newDuration: Duration) => void; + onDurationChange: (newDuration: Duration) => void, + className?: string, }> { render() { const duration = this.props.duration; + const className = classNames("field", "durationInput", this.props.className); // const editing = this.props.onDurationChange != null; return ( -
+
Run Section
- + - + {/*Label must be   to align it properly*/} + Sections diff --git a/app/state/StateBase.ts b/app/state/StateBase.ts new file mode 100644 index 0000000..f42d394 --- /dev/null +++ b/app/state/StateBase.ts @@ -0,0 +1,11 @@ +import { ISprinklersApi } from "@common/sprinklers"; +import { UiMessage, UiStore } from "./ui"; + +export default abstract class StateBase { + abstract readonly sprinklersApi: ISprinklersApi; + uiStore = new UiStore(); + + start() { + this.sprinklersApi.start(); + } +} diff --git a/app/state/index.ts b/app/state/index.ts index c9b8328..613c3de 100644 --- a/app/state/index.ts +++ b/app/state/index.ts @@ -1,32 +1,3 @@ -import { ISprinklersApi } from "@common/sprinklers"; -import { MqttApiClient } from "@common/sprinklers/mqtt"; -import { WebApiClient } from "./websocket"; - -import { UiMessage, UiStore } from "./ui"; -export { UiMessage, UiStore }; +export { UiMessage, UiStore } from "./ui"; export * from "./inject"; - -export abstract class StateBase { - abstract readonly sprinklersApi: ISprinklersApi; - uiStore = new UiStore(); - - constructor() { - this.uiStore.addMessage({ header: "asdf", content: "boo!", error: true }); - } - - start() { - this.sprinklersApi.start(); - } -} - -const isDev = process.env.NODE_ENV === "development"; - -export class MqttApiState extends StateBase { - sprinklersApi = new MqttApiClient(`ws://${location.hostname}:1884`); -} - -export class WebApiState extends StateBase { - sprinklersApi = new WebApiClient(isDev ? - `ws://${location.hostname}:8080` : - `ws://${location.host}`); -} +export { default as StateBase } from "./StateBase"; diff --git a/app/state/web.ts b/app/state/web.ts new file mode 100644 index 0000000..7d8d234 --- /dev/null +++ b/app/state/web.ts @@ -0,0 +1,14 @@ +import { MqttApiClient } from "@common/sprinklers/mqtt"; +import StateBase from "./StateBase"; +import { WebApiClient } from "./websocket"; + +const isDev = process.env.NODE_ENV === "development"; +const websocketPort = isDev ? 8080 : location.port; + +export class MqttApiState extends StateBase { + sprinklersApi = new MqttApiClient(`ws://${location.hostname}:1884`); +} + +export class WebApiState extends StateBase { + sprinklersApi = new WebApiClient(`ws://${location.hostname}:${websocketPort}`); +} diff --git a/app/styles/app.css b/app/styles/app.css index a503e78..1c3902c 100644 --- a/app/styles/app.css +++ b/app/styles/app.css @@ -1,3 +1,7 @@ +.app { + margin-top: 1em; +} + .device--connectionState { margin-left: .75em; font-size: .75em; diff --git a/common/sprinklers/SprinklersDevice.ts b/common/sprinklers/SprinklersDevice.ts index 556674c..47cf139 100644 --- a/common/sprinklers/SprinklersDevice.ts +++ b/common/sprinklers/SprinklersDevice.ts @@ -10,6 +10,10 @@ export abstract class SprinklersDevice { @observable programs: Program[] = []; @observable sectionRunner: SectionRunner; + sectionConstructor: typeof Section = Section; + sectionRunnerConstructor: typeof SectionRunner = SectionRunner; + programConstructor: typeof Program = Program; + constructor() { this.sectionRunner = new (this.sectionRunnerConstructor)(this); } @@ -45,16 +49,6 @@ export abstract class SprinklersDevice { return this.makeRequest({ ...opts, type: "pauseSectionRunner" }); } - get sectionConstructor(): typeof Section { - return Section; - } - get sectionRunnerConstructor(): typeof SectionRunner { - return SectionRunner; - } - get programConstructor(): typeof Program { - return Program; - } - toString(): string { return `SprinklersDevice{id="${this.id}", connected=${this.connected}, ` + `sections=[${this.sections}], ` + diff --git a/common/sprinklers/mqtt/index.ts b/common/sprinklers/mqtt/index.ts index b93b707..dd561ac 100644 --- a/common/sprinklers/mqtt/index.ts +++ b/common/sprinklers/mqtt/index.ts @@ -132,6 +132,9 @@ class MqttSprinklersDevice extends s.SprinklersDevice { constructor(apiClient: MqttApiClient, prefix: string) { super(); + this.sectionConstructor = MqttSection; + this.sectionRunnerConstructor = MqttSectionRunner; + this.programConstructor = MqttProgram; this.apiClient = apiClient; this.prefix = prefix; this.sectionRunner = new MqttSectionRunner(this); @@ -141,10 +144,6 @@ class MqttSprinklersDevice extends s.SprinklersDevice { return this.prefix; } - get sectionConstructor() { return MqttSection; } - get sectionRunnerConstructor() { return MqttSectionRunner; } - get programConstructor() { return MqttProgram; } - doSubscribe() { const topics = subscriptions.map((filter) => this.prefix + filter); this.apiClient.client.subscribe(topics, { qos: 1 });