You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
6.7 KiB
201 lines
6.7 KiB
import { observer } from "mobx-react"; |
|
import { createViewModel, IViewModel } from "mobx-utils"; |
|
import * as React from "react"; |
|
import { RouteComponentProps } from "react-router"; |
|
import { Button, CheckboxProps, Form, Input, InputOnChangeData, Menu, Modal, Segment } from "semantic-ui-react"; |
|
|
|
import { ProgramSequenceView, ScheduleView } from "@app/components"; |
|
import * as rp from "@app/routePaths"; |
|
import { AppState, injectState } from "@app/state"; |
|
import log from "@common/logger"; |
|
import { Program, SprinklersDevice } from "@common/sprinklersRpc"; |
|
|
|
@observer |
|
class ProgramPage extends React.Component<{ |
|
appState: AppState, |
|
} & RouteComponentProps<{ deviceId: string, programId: number }>, { |
|
programView: Program & IViewModel<Program> | undefined, |
|
}> { |
|
private device!: SprinklersDevice; |
|
private program!: Program; |
|
|
|
constructor(p: any) { |
|
super(p); |
|
this.state = { |
|
programView: undefined, |
|
}; |
|
} |
|
|
|
get isEditing(): boolean { |
|
return this.state.programView != null; |
|
} |
|
|
|
renderName(program: Program) { |
|
const { name } = program; |
|
if (this.isEditing) { |
|
return ( |
|
<Menu.Item header> |
|
<Form> |
|
<Form.Group inline> |
|
<Form.Field inline> |
|
<label><h4>Program</h4></label> |
|
<Input |
|
placeholder="Program Name" |
|
type="text" |
|
value={name} |
|
onChange={this.onNameChange} |
|
/> |
|
</Form.Field> |
|
({program.id}) |
|
</Form.Group> |
|
</Form> |
|
</Menu.Item> |
|
); |
|
} else { |
|
return <Menu.Item header as="h4">Program {name} ({program.id})</Menu.Item>; |
|
} |
|
} |
|
|
|
renderActions(program: Program) { |
|
const { running } = program; |
|
const editing = this.isEditing; |
|
let editButtons; |
|
if (editing) { |
|
editButtons = ( |
|
<React.Fragment> |
|
<Button primary onClick={this.save}> |
|
Save |
|
</Button> |
|
<Button negative onClick={this.cancelEditing}> |
|
Cancel |
|
</Button> |
|
</React.Fragment> |
|
); |
|
} else { |
|
editButtons = ( |
|
<Button primary onClick={this.startEditing}> |
|
Edit |
|
</Button> |
|
); |
|
} |
|
return ( |
|
<Modal.Actions> |
|
<Button positive={!running} negative={running} onClick={this.cancelOrRun}> |
|
{running ? "Stop" : "Run"} |
|
</Button> |
|
{editButtons} |
|
<Button onClick={this.close}> |
|
Close |
|
</Button> |
|
</Modal.Actions> |
|
); |
|
} |
|
|
|
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; |
|
} |
|
this.program = device.programs[programId]; |
|
|
|
const { programView } = this.state; |
|
const program = programView || this.program; |
|
const editing = programView != null; |
|
|
|
const { running, enabled, schedule, sequence } = program; |
|
|
|
return ( |
|
<Modal open onClose={this.close} className="programEditor"> |
|
<Modal.Header>{this.renderName(program)}</Modal.Header> |
|
<Modal.Content> |
|
<Form> |
|
<Form.Group> |
|
<Form.Checkbox |
|
toggle |
|
label="Enabled" |
|
checked={enabled} |
|
readOnly={!editing} |
|
onChange={this.onEnabledChange} |
|
/> |
|
<Form.Checkbox toggle label="Running" checked={running} readOnly={!editing}/> |
|
</Form.Group> |
|
<Form.Field> |
|
<label><h4>Sequence</h4></label> |
|
<ProgramSequenceView sequence={sequence} sections={this.device.sections} editing={editing}/> |
|
</Form.Field> |
|
<Form.Field> |
|
<label><h4>Schedule</h4></label> |
|
<ScheduleView schedule={schedule}/> |
|
</Form.Field> |
|
</Form> |
|
</Modal.Content> |
|
{this.renderActions(program)} |
|
</Modal> |
|
); |
|
} |
|
|
|
private cancelOrRun = () => { |
|
if (!this.program) { |
|
return; |
|
} |
|
this.program.running ? this.program.cancel() : this.program.run(); |
|
} |
|
|
|
private startEditing = () => { |
|
let { programView } = this.state; |
|
if (programView) { // stop editing, so save |
|
programView.submit(); |
|
programView = undefined; |
|
} else { // start editing |
|
programView = createViewModel(this.program); |
|
} |
|
this.setState({ programView }); |
|
} |
|
|
|
private save = () => { |
|
let { programView } = this.state; |
|
if (programView) { // stop editing, so save |
|
programView.submit(); |
|
programView = undefined; |
|
} |
|
this.setState({ programView }); |
|
this.program.update() |
|
.then((data) => { |
|
log.info({ data }, "Program updated"); |
|
}, (err) => { |
|
log.error({ err }, "error updating Program"); |
|
}); |
|
} |
|
|
|
private cancelEditing = () => { |
|
let { programView } = this.state; |
|
if (programView) { |
|
programView = undefined; // stop editing |
|
} |
|
this.setState({ programView }); |
|
} |
|
|
|
private close = () => { |
|
const { deviceId } = this.props.match.params; |
|
this.props.history.push({ pathname: rp.device(deviceId) }); |
|
} |
|
|
|
private onNameChange = (e: any, p: InputOnChangeData) => { |
|
const { programView } = this.state; |
|
if (programView) { |
|
programView.name = p.value; |
|
} |
|
} |
|
|
|
private onEnabledChange = (e: any, p: CheckboxProps) => { |
|
const { programView } = this.state; |
|
if (programView) { |
|
programView.enabled = p.checked!; |
|
} |
|
} |
|
} |
|
|
|
const DecoratedProgramPage = injectState(observer(ProgramPage)); |
|
export default DecoratedProgramPage;
|
|
|