diff --git a/client/components/ProgramSequenceView.tsx b/client/components/ProgramSequenceView.tsx
index 28bd9d0..aed3727 100644
--- a/client/components/ProgramSequenceView.tsx
+++ b/client/components/ProgramSequenceView.tsx
@@ -105,16 +105,17 @@ class ProgramSequenceItem extends React.Component<{
const ProgramSequenceItemD = SortableElement(ProgramSequenceItem);
+// tslint:disable: no-shadowed-variable
const ProgramSequenceList = SortableContainer(
observer(
- (props: {
+ function ProgramSequenceList(props: {
className: string;
list: ProgramItem[];
sections: Section[];
editing: boolean;
onChange: ItemChangeHandler;
onRemove: ItemRemoveHandler;
- }) => {
+ }) {
const { className, list, sections, ...rest } = props;
const listItems = list.map((item, index) => {
const key = `item-${index}`;
@@ -132,7 +133,6 @@ const ProgramSequenceList = SortableContainer(
return
;
}
),
- { withRef: true }
);
@observer
diff --git a/client/components/ProgramTable.tsx b/client/components/ProgramTable.tsx
index 4acac9e..a4869f9 100644
--- a/client/components/ProgramTable.tsx
+++ b/client/components/ProgramTable.tsx
@@ -8,6 +8,7 @@ import { ProgramSequenceView, ScheduleView } from "@client/components";
import * as route from "@client/routePaths";
import { ISprinklersDevice } from "@common/httpApi";
import { Program, SprinklersDevice } from "@common/sprinklersRpc";
+import moment = require("moment");
@observer
class ProgramRows extends React.Component<{
@@ -69,6 +70,12 @@ class ProgramRows extends React.Component<{
Sequence:
{" "}
Schedule: } />
+ Next run:
+ {
+ program.nextRun
+ ?
+ :
+ }
diff --git a/client/pages/ProgramPage.tsx b/client/pages/ProgramPage.tsx
index b93e59c..1caee46 100644
--- a/client/pages/ProgramPage.tsx
+++ b/client/pages/ProgramPage.tsx
@@ -20,8 +20,9 @@ import { AppState, injectState } from "@client/state";
import { ISprinklersDevice } from "@common/httpApi";
import log from "@common/logger";
import { Program, SprinklersDevice } from "@common/sprinklersRpc";
-import { action } from "mobx";
import classNames = require("classnames");
+import { action } from "mobx";
+import * as moment from "moment";
interface ProgramPageProps
extends RouteComponentProps<{ deviceId: string; programId: string }> {
@@ -186,7 +187,6 @@ class ProgramPage extends React.Component {
toggle
label="Enabled"
checked={enabled}
- readOnly={!editing}
onChange={this.onEnabledChange}
/>
{
editing={editing}
label={Schedule
}
/>
+ { !editing && (
+ Next run:
)
+ }
+ {
+ !editing && (
+ program.nextRun
+ ?
+ :
+ )
+ }
{this.renderActions(program)}
@@ -243,6 +253,10 @@ class ProgramPage extends React.Component {
},
err => {
log.error({ err }, "error updating Program");
+ this.props.appState.uiStore.addMessage({
+ error: true,
+ content: `Error updating program: ${err}`,
+ });
}
);
this.stopEditing();
@@ -268,11 +282,28 @@ class ProgramPage extends React.Component {
@action.bound
private onEnabledChange(e: any, p: CheckboxProps) {
- if (this.programView) {
- this.programView.enabled = p.checked!;
+ if (p.checked !== undefined && this.program) {
+ this.program.enabled = p.checked;
+ this.program.update().then(
+ data => {
+ log.info({ data }, "Program updated");
+ this.props.appState.uiStore.addMessage({
+ success: true,
+ content: `Program ${this.program!.name} ${this.program!.enabled ? "enabled" : "disabled"}`,
+ timeout: 2000,
+ });
+ },
+ err => {
+ log.error({ err }, "error updating Program");
+ this.props.appState.uiStore.addMessage({
+ error: true,
+ content: `Error updating program: ${err}`,
+ });
+ }
+ );
}
}
}
-const DecoratedProgramPage = injectState(withRouter(observer(ProgramPage)));
+const DecoratedProgramPage = injectState(withRouter(ProgramPage));
export default DecoratedProgramPage;
diff --git a/client/styles/DeviceView.scss b/client/styles/DeviceView.scss
index 3698043..fb9f6bf 100644
--- a/client/styles/DeviceView.scss
+++ b/client/styles/DeviceView.scss
@@ -78,6 +78,11 @@ $connected-color: #13d213;
color: green;
}
+.program--nextRun {
+ display: inline-block;
+ padding-right: 0.5em;
+}
+
.ui.modal.programEditor {
&.editing > .content {
min-height: 80vh;
diff --git a/common/sprinklersRpc/Program.ts b/common/sprinklersRpc/Program.ts
index 7ab916d..0c176df 100644
--- a/common/sprinklersRpc/Program.ts
+++ b/common/sprinklersRpc/Program.ts
@@ -32,6 +32,8 @@ export class Program {
sequence: ProgramItem[] = [];
@observable
running: boolean = false;
+ @observable
+ nextRun: Date | null = null;
constructor(device: SprinklersDevice, id: number, data?: Partial) {
this.device = device;
@@ -60,7 +62,8 @@ export class Program {
enabled: this.enabled,
running: this.running,
schedule: this.schedule.clone(),
- sequence: this.sequence.slice()
+ sequence: this.sequence.slice(),
+ nextRun: this.nextRun,
});
}
@@ -68,7 +71,7 @@ export class Program {
return (
`Program{name="${this.name}", enabled=${this.enabled}, schedule=${
this.schedule
- }, ` + `sequence=${this.sequence}, running=${this.running}}`
+ }, ` + `sequence=${this.sequence}, running=${this.running}, nextRun=${this.nextRun}}`
);
}
}
diff --git a/common/sprinklersRpc/mqtt/MqttProgram.ts b/common/sprinklersRpc/mqtt/MqttProgram.ts
index 330f34e..59b1b0c 100644
--- a/common/sprinklersRpc/mqtt/MqttProgram.ts
+++ b/common/sprinklersRpc/mqtt/MqttProgram.ts
@@ -7,6 +7,8 @@ export class MqttProgram extends s.Program {
onMessage(payload: string, topic: string | undefined) {
if (topic === "running") {
this.running = payload === "true";
+ } else if (topic === "nextRun") {
+ this.nextRun = (payload.length > 0) ? new Date(Number(payload) * 1000.0) : null;
} else if (topic == null) {
this.updateFromJSON(JSON.parse(payload));
}
diff --git a/common/sprinklersRpc/schema/index.ts b/common/sprinklersRpc/schema/index.ts
index 86fd9c3..ac767b8 100644
--- a/common/sprinklersRpc/schema/index.ts
+++ b/common/sprinklersRpc/schema/index.ts
@@ -1,4 +1,4 @@
-import { createSimpleSchema, ModelSchema, object, primitive } from "serializr";
+import { createSimpleSchema, ModelSchema, object, primitive, date } from "serializr";
import * as s from "..";
import list from "./list";
@@ -85,7 +85,8 @@ export const program: ModelSchema = {
enabled: primitive(),
schedule: object(schedule),
sequence: list(object(programItem)),
- running: primitive()
+ running: primitive(),
+ nextRun: date(),
}
};