Fixed tslint things and worked more on the ui
This commit is contained in:
parent
55207a2821
commit
15bd1ebebb
@ -2,7 +2,7 @@ import * as React from "react";
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import DevTools from "mobx-react-devtools";
|
import DevTools from "mobx-react-devtools";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { SprinklersDevice, Section, Program } from "./sprinklers";
|
import { SprinklersDevice, Section, Program, Duration } from "./sprinklers";
|
||||||
import { Item, Table, Header, Segment, Form, Input, DropdownItemProps } from "semantic-ui-react";
|
import { Item, Table, Header, Segment, Form, Input, DropdownItemProps } from "semantic-ui-react";
|
||||||
import FontAwesome = require("react-fontawesome");
|
import FontAwesome = require("react-fontawesome");
|
||||||
import * as classNames from "classnames";
|
import * as classNames from "classnames";
|
||||||
@ -16,6 +16,9 @@ import "app/style/app.css";
|
|||||||
@observer
|
@observer
|
||||||
class SectionTable extends React.PureComponent<{ sections: Section[] }, void> {
|
class SectionTable extends React.PureComponent<{ sections: Section[] }, void> {
|
||||||
private static renderRow(section: Section, index: number) {
|
private static renderRow(section: Section, index: number) {
|
||||||
|
if (!section) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const { name, state } = section;
|
const { name, state } = section;
|
||||||
return (
|
return (
|
||||||
<Table.Row key={index}>
|
<Table.Row key={index}>
|
||||||
@ -55,6 +58,25 @@ class SectionTable extends React.PureComponent<{ sections: Section[] }, void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DurationInput extends React.Component<{
|
||||||
|
duration: Duration,
|
||||||
|
onDurationChange?: (newDuration: Duration) => void;
|
||||||
|
}, void> {
|
||||||
|
public render() {
|
||||||
|
const duration = this.props.duration;
|
||||||
|
return <div className="field durationInput">
|
||||||
|
<label>Duration</label>
|
||||||
|
<div className="fields">
|
||||||
|
<Form.Field control={Input} className="durationInput--minutes" placeholder="Minutes"
|
||||||
|
value={duration.minutes} />
|
||||||
|
<Form.Field className="durationInput--colon"><span>:</span></Form.Field>
|
||||||
|
<Form.Field control={Input} className="durationInput--seconds" placeholder="Seconds"
|
||||||
|
value={duration.seconds} />
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class RunSectionForm extends React.Component<{ sections: Section[] }, void> {
|
class RunSectionForm extends React.Component<{ sections: Section[] }, void> {
|
||||||
public render() {
|
public render() {
|
||||||
@ -63,26 +85,27 @@ class RunSectionForm extends React.Component<{ sections: Section[] }, void> {
|
|||||||
<Form>
|
<Form>
|
||||||
<Form.Group>
|
<Form.Group>
|
||||||
<Form.Select label="Section" placeholder="Section" options={this.sectionOptions} />
|
<Form.Select label="Section" placeholder="Section" options={this.sectionOptions} />
|
||||||
<Form.Input control={Input} label="Duration" placeholder="Duration" />
|
<DurationInput duration={new Duration(1, 1)} />
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
</Form>
|
</Form>
|
||||||
</Segment>;
|
</Segment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
private get sectionOptions(): DropdownItemProps[] {
|
private get sectionOptions(): DropdownItemProps[] {
|
||||||
// return this.props.sections.map((s, i) => ({
|
return this.props.sections.map((s, i) => ({
|
||||||
// text: s.name,
|
text: s ? s.name : null,
|
||||||
// value: i,
|
value: i,
|
||||||
// }));
|
}));
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class ProgramTable extends React.PureComponent<{ programs: Program[] }, void> {
|
class ProgramTable extends React.PureComponent<{ programs: Program[] }, void> {
|
||||||
private static renderRow(program: Program, i: number) {
|
private static renderRow(program: Program, i: number) {
|
||||||
|
if (!program) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const { name, running } = program;
|
const { name, running } = program;
|
||||||
return (
|
return (
|
||||||
<Table.Row key={i}>
|
<Table.Row key={i}>
|
||||||
@ -155,8 +178,8 @@ class DeviceView extends React.PureComponent<{ device: SprinklersDevice }, void>
|
|||||||
export default class App extends React.PureComponent<{ device: SprinklersDevice }, any> {
|
export default class App extends React.PureComponent<{ device: SprinklersDevice }, any> {
|
||||||
public render() {
|
public render() {
|
||||||
return <Item.Group divided>
|
return <Item.Group divided>
|
||||||
<DeviceView device={this.props.device} />
|
<DeviceView device={this.props.device} />
|
||||||
<DevTools />
|
<DevTools />
|
||||||
</Item.Group>;
|
</Item.Group>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import MQTT = Paho.MQTT;
|
|||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import * as objectAssign from "object-assign";
|
import * as objectAssign from "object-assign";
|
||||||
import {
|
import {
|
||||||
SprinklersDevice, ISprinklersApi, Section, Program, IProgramItem, Schedule, ITimeOfDay, Weekday,
|
SprinklersDevice, ISprinklersApi, Section, Program, IProgramItem, Schedule, ITimeOfDay, Weekday, Duration,
|
||||||
} from "./sprinklers";
|
} from "./sprinklers";
|
||||||
|
|
||||||
export class MqttApiClient extends EventEmitter implements ISprinklersApi {
|
export class MqttApiClient extends EventEmitter implements ISprinklersApi {
|
||||||
@ -23,6 +23,7 @@ export class MqttApiClient extends EventEmitter implements ISprinklersApi {
|
|||||||
this.client = new MQTT.Client(location.hostname, 1884, MqttApiClient.newClientId());
|
this.client = new MQTT.Client(location.hostname, 1884, MqttApiClient.newClientId());
|
||||||
this.client.onMessageArrived = (m) => this.onMessageArrived(m);
|
this.client.onMessageArrived = (m) => this.onMessageArrived(m);
|
||||||
this.client.onConnectionLost = (e) => this.onConnectionLost(e);
|
this.client.onConnectionLost = (e) => this.onConnectionLost(e);
|
||||||
|
// (this.client as any).trace = (m => console.log(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
public start() {
|
public start() {
|
||||||
@ -65,7 +66,15 @@ export class MqttApiClient extends EventEmitter implements ISprinklersApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onMessageArrived(m: MQTT.Message) {
|
private onMessageArrived(m: MQTT.Message) {
|
||||||
console.log("message arrived: ", m);
|
try {
|
||||||
|
this.processMessage(m);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("error while processing mqtt message", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private processMessage(m: MQTT.Message) {
|
||||||
|
// console.log("message arrived: ", m);
|
||||||
const topicIdx = m.destinationName.indexOf("/"); // find the first /
|
const topicIdx = m.destinationName.indexOf("/"); // find the first /
|
||||||
const prefix = m.destinationName.substr(0, topicIdx); // assume prefix does not contain a /
|
const prefix = m.destinationName.substr(0, topicIdx); // assume prefix does not contain a /
|
||||||
const topic = m.destinationName.substr(topicIdx + 1);
|
const topic = m.destinationName.substr(topicIdx + 1);
|
||||||
@ -197,10 +206,15 @@ function scheduleFromJSON(json: IScheduleJSON): Schedule {
|
|||||||
return sched;
|
return sched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IProgramItemJSON {
|
||||||
|
section: number;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface IProgramJSON {
|
interface IProgramJSON {
|
||||||
name: string;
|
name: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
sequence: IProgramItem[];
|
sequence: IProgramItemJSON[];
|
||||||
sched: IScheduleJSON;
|
sched: IScheduleJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,18 +224,26 @@ class MqttProgram extends Program {
|
|||||||
this.running = (payload === "true");
|
this.running = (payload === "true");
|
||||||
} else if (topic == null) {
|
} else if (topic == null) {
|
||||||
const json = JSON.parse(payload) as Partial<IProgramJSON>;
|
const json = JSON.parse(payload) as Partial<IProgramJSON>;
|
||||||
if (json.name != null) {
|
this.updateFromJSON(json);
|
||||||
this.name = json.name;
|
}
|
||||||
}
|
}
|
||||||
if (json.enabled != null) {
|
|
||||||
this.enabled = json.enabled;
|
public updateFromJSON(json: Partial<IProgramJSON>) {
|
||||||
}
|
if (json.name != null) {
|
||||||
if (json.sequence != null) {
|
this.name = json.name;
|
||||||
this.sequence = json.sequence;
|
}
|
||||||
}
|
if (json.enabled != null) {
|
||||||
if (json.sched != null) {
|
this.enabled = json.enabled;
|
||||||
this.schedule = scheduleFromJSON(json.sched);
|
}
|
||||||
}
|
if (json.sequence != null) {
|
||||||
|
// tslint:disable:object-literal-sort-keys
|
||||||
|
this.sequence = json.sequence.map((item) => ({
|
||||||
|
section: item.section,
|
||||||
|
duration: Duration.fromSeconds(item.duration),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (json.sched != null) {
|
||||||
|
this.schedule = scheduleFromJSON(json.sched);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,29 @@ export class Schedule {
|
|||||||
public to?: Date = null;
|
public to?: Date = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Duration {
|
||||||
|
public static fromSeconds(seconds: number): Duration {
|
||||||
|
return new Duration(Math.floor(seconds / 60), seconds % 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
public minutes: number = 0;
|
||||||
|
public seconds: number = 0;
|
||||||
|
|
||||||
|
constructor(minutes: number, seconds: number) {
|
||||||
|
this.minutes = minutes;
|
||||||
|
this.seconds = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toSeconds(): number {
|
||||||
|
return this.minutes * 60 + this.seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface IProgramItem {
|
export interface IProgramItem {
|
||||||
// the section number
|
// the section number
|
||||||
section: number;
|
section: number;
|
||||||
// duration in seconds
|
// duration of the run
|
||||||
duration: number;
|
duration: Duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Program {
|
export class Program {
|
||||||
|
@ -33,4 +33,13 @@
|
|||||||
|
|
||||||
.section--state-false {
|
.section--state-false {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.durationInput--minutes,
|
||||||
|
.durationInput--seconds {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.durationInput--colon {
|
||||||
|
line-height: 38px;
|
||||||
}
|
}
|
@ -51,6 +51,7 @@
|
|||||||
"source-map-loader": "^0.2.1",
|
"source-map-loader": "^0.2.1",
|
||||||
"style-loader": "^0.17.0",
|
"style-loader": "^0.17.0",
|
||||||
"ts-loader": "^2.0.3",
|
"ts-loader": "^2.0.3",
|
||||||
|
"tslint": "^5.2.0",
|
||||||
"typescript": "^2.3.1",
|
"typescript": "^2.3.1",
|
||||||
"webpack": "^2.4.1",
|
"webpack": "^2.4.1",
|
||||||
"webpack-dev-server": "^2.4.4"
|
"webpack-dev-server": "^2.4.4"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user