// @flow import React from "react"; import _ from "lodash"; import { ListItemSecondaryAction, ListItemText, ListSubheader } from "material-ui/List"; import Switch from "material-ui/Switch"; import Input, { InputLabel } from "material-ui/Input"; import { FormControl } from "material-ui/Form"; import Select from "material-ui/Select"; import { MenuItem } from "material-ui/Menu"; import Button from "material-ui/Button"; import keyOf from "utils/keyOf"; type UiItemProps = { item: I, state: State, onChangeState: (topic: string, nextState: Actual) => void }; // eslint-disable-next-line flowtype/no-weak-types export default class UiItem extends React.Component> { constructor(props: UiItemProps) { super(props); } runPrimaryAction() { } render() { return null; } /* * TODO: The type system can't really check if the enableCondition is of * any function type or if it is a TopicDependentOption or a * StateDependentOption. This should be fixed. */ isEnabled() { if (Object.keys(this.props.item).includes("enableCondition") && typeof this.props.item.enableCondition == "function") { const enableCondition = this.props.item.enableCondition; const state = this.props.state; const internals = _.mapValues(state, (x) => x.internal); const actuals = _.mapValues(state, (x) => x.actual); return enableCondition(internals, actuals, state); } else { return true; } } } export class UiControl extends UiItem { constructor(props: UiItemProps) { super(props); } changeState(next: Actual) { if (this.props.item.topic == null) { throw new Error( `Missing topic in ${this.props.item.type} "${this.props.item.text}"` ); } this.props.onChangeState(this.props.item.topic, next); } getValue() { const control = this.props.item; const topic: string = control.topic || ""; const value = this.props.state[topic]; if (value == null) { if (topic === "") { throw new Error( `Missing topic in ${control.type} "${control.text}"` ); } throw new Error( `Unknown topic "${topic}" in ${control.type} "${control.text}"` ); } return value; } isEnabled() { if (Object.keys(this.props.item).includes("enableCondition") && typeof this.props.item.enableCondition == "function") { const enableCondition = this.props.item.enableCondition; const value = this.getValue(); return enableCondition( value.internal || value.actual, value.actual, this.props.state); } else { return true; } } } export class Toggle extends UiControl { isToggled = () => { const value = this.getValue(); const control = this.props.item; const isChecked = control.toggled || ((i, _a, _s) => i === (control.on || "on")); const checked = isChecked( value.internal || value.actual, value.actual, this.props.state); return checked; } runPrimaryAction = () => { if (this.isEnabled()) { const control = this.props.item; const toggled = this.isToggled(); const next = toggled ? (control.off || "off") : (control.on || "on"); this.changeState(next); } } render() { return [ , ]; } } export class DropDown extends UiControl { runPrimaryAction = (next?: Actual) => { if (this.isEnabled()) { const control = this.props.item; const keys = _.keys(control.options); const value = this.getValue(); const valueIndex = keyOf(keys, value); if (next == null) { this.changeState(keys[(valueIndex + 1) % keys.length]); } else { this.changeState(next); } } } render() { const control = this.props.item; const value = this.getValue(); const id = `${control.topic}-${control.text}`; const options = control.options; if (options == null) { throw new Error( `Parameter "options" missing for ${control.type} "${control.text}"` ); } return ( {control.text} } > {_.map(options, (v, k) => {v})} ); } } export class Link extends UiItem { runPrimaryAction = () => { const control = this.props.item; if (control.link == null) { throw new Error( `Parameter "link" missing for ${control.type} "${control.text}"` ); } if (this.isEnabled()) { window.open(control.link, "_blank"); } } render() { return ( ); } } export class Section extends UiItem { render() { return ( {this.props.item.text} ); } } export class Text extends UiControl { render() { return [ , ]; } }