@@ -78,42 +110,29 @@ export default class ProgramTable extends React.Component<{
if (!program) {
return null;
}
- const { name, running, enabled, schedule, sequence } = program;
- const sequenceItems = flatMap(sequence, (item, index) => {
- const section = this.props.sections[item.section];
- const duration = Duration.fromSeconds(item.duration);
- return [
- "{section.name}", ` for ${duration.toString()}, `,
- ];
- });
- const cancelOrRun = () => running ? program.cancel() : program.run();
- const mainRow = (
-
- {"" + (i + 1)}
- {name}
- {enabled ? "Enabled" : "Not enabled"}
-
- {running ? "Running" : "Not running"}
-
-
-
-
- );
- const detailRow = false && (
-
-
- Sequence:
{sequenceItems}
- Schedule:
-
-
- );
+ const expanded = this.state.expandedPrograms.indexOf(program) !== -1;
return (
-
- {mainRow}
- {detailRow}
-
+
);
}
+
+ private toggleExpanded = (program: Program) => {
+ const { expandedPrograms } = this.state;
+ const idx = expandedPrograms.indexOf(program);
+ if (idx !== -1) {
+ expandedPrograms.splice(idx, 1);
+ } else {
+ expandedPrograms.push(program);
+ }
+ this.setState({
+ expandedPrograms,
+ });
+ }
}
diff --git a/app/components/ScheduleView.tsx b/app/components/ScheduleView.tsx
new file mode 100644
index 0000000..5447074
--- /dev/null
+++ b/app/components/ScheduleView.tsx
@@ -0,0 +1,38 @@
+import { observer } from "mobx-react";
+import * as moment from "moment";
+import * as React from "react";
+
+import { DateOfYear, Schedule, TimeOfDay, Weekday } from "@common/sprinklersRpc";
+
+function timeToString(time: TimeOfDay) {
+ return moment(time).format("LTS");
+}
+
+function formatDateOfYear(day: DateOfYear | null, prefix: React.ReactNode) {
+ if (day == null) {
+ return null;
+ }
+ const format = (day.year === 0) ? "M/D" : "l";
+ return {prefix}{moment(day).format(format)};
+}
+
+@observer
+export default class ScheduleView extends React.Component<{ schedule: Schedule }> {
+ render() {
+ const { schedule } = this.props;
+ const times = schedule.times.map((time, i) => timeToString(time))
+ .join(", ");
+ const weekdays = schedule.weekdays.map((weekday) =>
+ Weekday[weekday]).join(", ");
+ const from = formatDateOfYear(schedule.from, From );
+ const to = formatDateOfYear(schedule.to, To );
+ return (
+
+ At {times}
+ On {weekdays}
+ {from}
+ {to}
+
+ );
+ }
+}
diff --git a/app/components/index.ts b/app/components/index.ts
index 7d4f5f2..fe3f345 100644
--- a/app/components/index.ts
+++ b/app/components/index.ts
@@ -5,7 +5,9 @@ export { default as DurationInput } from "./DurationInput";
export { default as MessagesView } from "./MessagesView";
export { default as ProgramTable } from "./ProgramTable";
export { default as RunSectionForm } from "./RunSectionForm";
+export { default as ScheduleView } from "./ScheduleView";
export { default as SectionRunnerView } from "./SectionRunnerView";
export { default as SectionTable } from "./SectionTable";
export { default as NavBar } from "./NavBar";
export { default as MessageTest } from "./MessageTest";
+export { default as ProgramSequenceView } from "./ProgramSequenceView";
diff --git a/app/pages/ProgramPage.tsx b/app/pages/ProgramPage.tsx
new file mode 100644
index 0000000..4dbfe30
--- /dev/null
+++ b/app/pages/ProgramPage.tsx
@@ -0,0 +1,69 @@
+import { observer } from "mobx-react";
+import * as React from "react";
+import { Button, Menu, Segment} from "semantic-ui-react";
+
+import { ProgramSequenceView, ScheduleView } from "@app/components";
+import { AppState, injectState } from "@app/state";
+import { Program, SprinklersDevice } from "@common/sprinklersRpc";
+import { RouteComponentProps } from "react-router";
+import { Link } from "react-router-dom";
+
+@observer
+class ProgramDetailView extends React.Component {
+
+}
+
+@observer
+class ProgramPage extends React.Component<{
+ appState: AppState,
+} & RouteComponentProps<{ deviceId: string, programId: number }>> {
+ device!: SprinklersDevice;
+
+ render() {
+ const { deviceId, programId } = this.props.match.params;
+ const device = this.device = this.props.appState.sprinklersRpc.getDevice(deviceId);
+ // TODO: check programId
+ if (device.programs.length <= programId || !device.programs[programId]) {
+ return null;
+ }
+ const program = device.programs[programId];
+
+ const programRows = this.renderRows(program, programId);
+ return (
+
+
+
+ {programRows}
+
+
+ );
+ }
+
+ private renderRows = (program: Program, i: number): JSX.Element | null => {
+ const { name, running, enabled, schedule, sequence } = program;
+ const cancelOrRun = () => running ? program.cancel() : program.run();
+ return (
+
+ Enabled: {enabled ? "Enabled" : "Not enabled"}
+ Running: {running ? "Running" : "Not running"}
+
+ Sequence:
+ Schedule:
+
+ );
+ }
+}
+
+const DecoratedProgramPage = injectState(observer(ProgramPage));
+export default DecoratedProgramPage;
diff --git a/app/pages/index.tsx b/app/pages/index.tsx
index c530c26..48d1c2c 100644
--- a/app/pages/index.tsx
+++ b/app/pages/index.tsx
@@ -5,6 +5,7 @@ import { DevicesView, MessageTest} from "@app/components";
export { LoginPage } from "./LoginPage";
export { LogoutPage } from "./LogoutPage";
+export { default as ProgramPage } from "./ProgramPage";
export function DevicePage({ match }: RouteComponentProps<{ deviceId: string }>) {
return (
diff --git a/app/routePaths.ts b/app/routePaths.ts
new file mode 100644
index 0000000..ee50b39
--- /dev/null
+++ b/app/routePaths.ts
@@ -0,0 +1,23 @@
+export interface RouteParams {
+ deviceId: string;
+ programId: string;
+}
+
+export const routerRouteParams: RouteParams = {
+ deviceId: ":deviceId",
+ programId: ":programId",
+};
+
+export const home = "/";
+export const messagesTest = "/messagesTest";
+
+export const login = "/login";
+export const logout = "/logout";
+
+export function device(deviceId?: string | number): string {
+ return `/devices/${deviceId || ""}`;
+}
+
+export function program(deviceId: string | number, programId?: string | number): string {
+ return `${device(deviceId)}/programs/${programId}`;
+}
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 39fd218..b6b461a 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -47,13 +47,8 @@
}
-.ui.table {
- tr > td.program--running {
- display: flex !important;
- @media only screen and (min-width: 768px) {
- //line-height: 36px;
- }
- }
+.flex {
+ display: flex !important;
}
.section--state-true {