Merge remote-tracking branch 'upstream/master' into patch-16

This commit is contained in:
Ranlvor 2018-07-01 16:47:49 +02:00
commit 454619974d
Signed by untrusted user who does not match committer: Ranlvor
GPG key ID: 5E12D04750EF6F8E
19 changed files with 857 additions and 538 deletions

View file

@ -1,6 +1,8 @@
// @flow // @flow
import type { Config } from "config/flowtypes"; import type { Config } from "config/flowtypes";
import { hex, rgb, rgba, rainbow } from "config/colors"; import { hex, rgb, rgba, rainbow } from "config/colors";
import * as types from "config/types";
import { mdi } from "config/icon";
import { esper_topics, esper_statistics } from "./utils"; import { esper_topics, esper_statistics } from "./utils";
const config : Config = { const config : Config = {
@ -12,16 +14,18 @@ const config : Config = {
topics: [ topics: [
{ {
hauptraum_table_light: { hauptraum_table_light: {
command: "/public/sensoren/TPH/leinwand/control", command: {
state: "test", name: "/public/sensoren/TPH/leinwand/control",
defaultValue: "A1 ON", type: types.option({ "A1 ON": "on", "A1 OFF": "off" })
values: { on: "A1 ON", off: "A1 OFF" } },
defaultValue: "off"
}, },
hauptraum_table_light_on_hack: { hauptraum_table_light_on_hack: {
command: "/public/sensoren/TPH/leinwand/control", command: {
state: "test", name: "/public/sensoren/TPH/leinwand/control",
defaultValue: "A1 OFF", type: types.option({ "A1 ON": "on", "A1 OFF": "off" })
values: { on: "A1 ON", off: "A1 OFF" } },
defaultValue: "on"
} }
} }
], ],
@ -29,20 +33,20 @@ const config : Config = {
hauptraum_table_light: { hauptraum_table_light: {
name: "Hauptraum Tisch", name: "Hauptraum Tisch",
position: [450, 450], position: [450, 450],
icon: "white-balance-iridescent", icon: mdi("white-balance-iridescent"),
iconColor: () => hex("#000000"), iconColor: () => hex("#000000"),
ui: [ ui: [
{ {
type: "toggle", type: "toggle",
text: "Licht", text: "Licht",
topic: "hauptraum_table_light", topic: "hauptraum_table_light",
icon: "power" icon: mdi("power")
}, },
{ {
type: "toggle", type: "toggle",
text: "Licht", text: "Licht",
topic: "hauptraum_table_light_on_hack", topic: "hauptraum_table_light_on_hack",
icon: "power" icon: mdi("power")
} }
] ]
} }

File diff suppressed because it is too large Load diff

View file

@ -1,42 +1,44 @@
// @flow // @flow
import type { ControlUI } from "config/flowtypes"; import type { ControlUI } from "config/flowtypes";
import { mdi } from "config/icon";
import * as types from "config/types";
export const esper_topics = (chip_id: string, name: string) => ({ export const esper_topics = (chip_id: string, name: string) => ({
[ `esper_${name}_version` ]: { [ `esper_${name}_version` ]: {
state: `/service/esper/${chip_id}/info`, state: {
command: "", name: `/service/esper/${chip_id}/info`,
defaultValue: "UNKNOWN", type: types.json("version.esper")
values: {}, },
type: msg => JSON.parse(msg.toString()).version.esper defaultValue: "UNKNOWN"
}, },
[ `esper_${name}_ip` ]: { [ `esper_${name}_ip` ]: {
state: `/service/esper/${chip_id}/info`, state: {
command: "", name: `/service/esper/${chip_id}/info`,
defaultValue: "UNKNOWN", type: types.json("network.ip")
values: {}, },
type: msg => JSON.parse(msg.toString()).network.ip defaultValue: "UNKNOWN"
}, },
[ `esper_${name}_rssi` ]: { [ `esper_${name}_rssi` ]: {
state: `/service/esper/${chip_id}/info`, state: {
command: "", name: `/service/esper/${chip_id}/info`,
defaultValue: "UNKNOWN", type: types.json("wifi.rssi")
values: {}, },
type: msg => JSON.parse(msg.toString()).wifi.rssi defaultValue: "UNKNOWN"
}, },
[ `esper_${name}_uptime` ]: { [ `esper_${name}_uptime` ]: {
state: `/service/esper/${chip_id}/info`, state: {
command: "", name: `/service/esper/${chip_id}/info`,
defaultValue: "UNKNOWN", type: msg => new Date(JSON.parse(msg.toString()).time.startup * 1000)
values: {},
type: msg => new Date(JSON.parse(msg.toString()).time.startup * 1000)
.toLocaleString() .toLocaleString()
},
defaultValue: "UNKNOWN",
}, },
[ `esper_${name}_device` ]: { [ `esper_${name}_device` ]: {
state: `/service/esper/${chip_id}/info`, state: {
command: "", name: `/service/esper/${chip_id}/info`,
defaultValue: "UNKNOWN", type: types.json("device")
values: {}, },
type: msg => JSON.parse(msg.toString()).device defaultValue: "UNKNOWN"
} }
}); });
@ -45,16 +47,47 @@ export const floalt = {
brightness: (light_id: string) => `floalt_${light_id}_brightness`, brightness: (light_id: string) => `floalt_${light_id}_brightness`,
topics: (light_id: string) => ({ topics: (light_id: string) => ({
[ `floalt_${light_id}_color` ]: { [ `floalt_${light_id}_color` ]: {
state: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/state`, state: {
command: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/command`, name: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/state`,
defaultValue: "0", type: types.string
values: {} },
command: {
name: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/command`,
type: types.string
},
defaultValue: "0"
}, },
[ `floalt_${light_id}_brightness` ]: { [ `floalt_${light_id}_brightness` ]: {
state: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/state`, state: {
command: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/command`, name: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/state`,
defaultValue: "0", type: types.string
values: {} },
command: {
name: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/command`,
type: types.string
},
defaultValue: "0"
}
})
}
export const tradfri_remote = {
level: (remote_id: string) => `tradfri_remote_${remote_id}_level`,
low: (remote_id: string) => `tradfri_remote_${remote_id}_low`,
topics: (remote_id: string) => ({
[ `tradfri_remote_${remote_id}_level` ]: {
state: {
name: `/service/openhab/out/tradfri_0830_gwb8d7af2b448f_${remote_id}_battery_level/state`,
type: types.string
},
defaultValue: "0"
},
[ `tradfri_remote_${remote_id}_low` ]: {
state: {
name: `/service/openhab/out/tradfri_0830_gwb8d7af2b448f_${remote_id}_battery_low/state`,
type: types.option({ ON: "true", OFF: "false" })
},
defaultValue: "false",
} }
}) })
} }
@ -69,31 +102,31 @@ export const esper_statistics = (name: string,
{ {
type: "text", type: "text",
text: "Device Variant", text: "Device Variant",
icon: "chart-donut", icon: mdi("chart-donut"),
topic: `esper_${name}_device` topic: `esper_${name}_device`
}, },
{ {
type: "text", type: "text",
text: "Version", text: "Version",
icon: "source-branch", icon: mdi("source-branch"),
topic: `esper_${name}_version` topic: `esper_${name}_version`
}, },
{ {
type: "text", type: "text",
text: "IP", text: "IP",
icon: "access-point-network", icon: mdi("access-point-network"),
topic: `esper_${name}_ip` topic: `esper_${name}_ip`
}, },
{ {
type: "text", type: "text",
text: "RSSI", text: "RSSI",
icon: "wifi", icon: mdi("wifi"),
topic: `esper_${name}_rssi` topic: `esper_${name}_rssi`
}, },
{ {
type: "text", type: "text",
text: "Running since…", text: "Running since…",
icon: "av-timer", icon: mdi("av-timer"),
topic: `esper_${name}_uptime` topic: `esper_${name}_uptime`
} }
]) ])

View file

@ -6,9 +6,9 @@
"scripts": { "scripts": {
"build": "webpack --bail --config webpack.config.js -p --env", "build": "webpack --bail --config webpack.config.js -p --env",
"dev": "webpack --bail --config webpack.config.js --mode development --env", "dev": "webpack --bail --config webpack.config.js --mode development --env",
"watch": "webpack-dev-server --open --config webpack.dev.js --mode development --env", "watch": "webpack-dev-server --open --config webpack.config.js --mode development --env",
"travis": "./travis.sh", "travis": "./travis.sh",
"lint": "eslint -- --ext js --ext jsx src/", "lint": "eslint --ext js --ext jsx src/",
"precommit": "yarn lint" "precommit": "yarn lint"
}, },
"dependencies": { "dependencies": {
@ -30,16 +30,16 @@
"babel-eslint": "^8.0.1", "babel-eslint": "^8.0.1",
"babel-loader": "^7.1.1", "babel-loader": "^7.1.1",
"babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-env": "^1.6.0", "babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.18", "clean-webpack-plugin": "^0.1.18",
"css-loader": "^0.28.9", "css-loader": "^0.28.9",
"eslint": "^4.16.0", "eslint": "^5.0.1",
"eslint-plugin-flowtype": "^2.42.0", "eslint-plugin-flowtype": "^2.42.0",
"eslint-plugin-react": "^7.6.1", "eslint-plugin-react": "^7.6.1",
"file-loader": "^1.1.5", "file-loader": "^1.1.5",
"flow": "^0.2.3", "flow": "^0.2.3",
"flow-bin": "^0.70.0", "flow-bin": "^0.75.0",
"flow-typed": "^2.3.0", "flow-typed": "^2.3.0",
"html-webpack-plugin": "^3.1.0", "html-webpack-plugin": "^3.1.0",
"husky": "^0.14.3", "husky": "^0.14.3",

View file

@ -18,9 +18,6 @@ import ControlMap from "components/ControlMap";
import TopBar from "components/TopBar"; import TopBar from "components/TopBar";
import UiItemList from "components/UiItemList"; import UiItemList from "components/UiItemList";
import keyOf from "utils/keyOf";
import { controlGetIcon } from "utils/parseIconName";
import connectMqtt from "../connectMqtt"; import connectMqtt from "../connectMqtt";
export type AppProps = { export type AppProps = {
@ -31,7 +28,7 @@ export type AppState = {
selectedControl: ?Control, selectedControl: ?Control,
drawerOpened: boolean, drawerOpened: boolean,
mqttState: State, mqttState: State,
mqttSend: (topic: string, value: Actual) => void, mqttSend: (topic: string, value: Buffer) => void,
mqttConnected: boolean, mqttConnected: boolean,
}; };
@ -41,16 +38,15 @@ class App extends React.PureComponent<AppProps & Classes, AppState> {
this.state = { this.state = {
selectedControl: null, selectedControl: null,
drawerOpened: false, drawerOpened: false,
mqttState: mapValues(this.topics, (topic) => ({ mqttState: mapValues(this.topics, (topic) => topic.defaultValue),
actual: topic.defaultValue,
internal: keyOf(topic.values, topic.defaultValue)
})),
mqttSend: connectMqtt(props.config.space.mqtt, { mqttSend: connectMqtt(props.config.space.mqtt, {
onMessage: this.receiveMessage.bind(this), onMessage: this.receiveMessage.bind(this),
onConnect: () => this.setState({ mqttConnected: true }), onConnect: () => this.setState({ mqttConnected: true }),
onReconnect: () => this.setState({ mqttConnected: false }), onReconnect: () => this.setState({ mqttConnected: false }),
onDisconnect: () => this.setState({ mqttConnected: false }), onDisconnect: () => this.setState({ mqttConnected: false }),
subscribe: map(this.topics, (x) => x.state) subscribe: map(
filter(keys(this.topics), (x) => this.topics[x].state != null),
(x) => this.topics[x].state.name)
}), }),
mqttConnected: false mqttConnected: false
}; };
@ -77,23 +73,23 @@ class App extends React.PureComponent<AppProps & Classes, AppState> {
}); });
} }
receiveMessage(rawTopic: string, message: Object) { receiveMessage(rawTopic: string, message: Buffer) {
const topics = filter( const topics = filter(
keys(this.topics), keys(this.topics),
(k) => this.topics[k].state === rawTopic (k) => this.topics[k].state != null &&
this.topics[k].state.name === rawTopic
); );
if (topics.length === 0) { if (topics.length === 0) {
return; return;
} }
for (let i in topics) { for (let i in topics) {
// TODO: Remove FlowFixMe
const topic = topics[i]; const topic = topics[i];
const parseValue = this.topics[topic].type; // $FlowFixMe
const parseValue = this.topics[topic].state.type;
const val = parseValue == null ? message.toString() : parseValue(message); const val = parseValue == null ? message.toString() : parseValue(message);
this.setState({mqttState: Object.assign({}, merge(this.state.mqttState, this.setState({mqttState: Object.assign({}, merge(this.state.mqttState,
{ [topic]: { { [topic]: val}))});
actual: val,
internal: keyOf(this.topics[topic].values, val) || val
}}))});
} }
} }
@ -105,15 +101,15 @@ class App extends React.PureComponent<AppProps & Classes, AppState> {
this.setState({drawerOpened: false}); this.setState({drawerOpened: false});
} }
changeState(topic: string, value: Actual) { changeState(topic: string, value: string) {
const rawTopic = this.topics[topic].command; if (this.topics[topic].command == null) {
if (rawTopic == null) {
return; return;
} }
this.state.mqttSend( const rawTopic = this.topics[topic].command.name;
rawTopic, const transformValue = this.topics[topic].command.type;
String(this.topics[topic].values[value] || value) const val =
); transformValue == null ? value : transformValue(Buffer.from(value));
this.state.mqttSend(rawTopic, Buffer.from(val));
} }
render() { render() {
@ -127,8 +123,7 @@ class App extends React.PureComponent<AppProps & Classes, AppState> {
control={this.state.selectedControl} control={this.state.selectedControl}
onCloseRequest={this.closeDrawer.bind(this)} onCloseRequest={this.closeDrawer.bind(this)}
icon={this.state.selectedControl == null ? null : icon={this.state.selectedControl == null ? null :
controlGetIcon(this.state.selectedControl, this.state.selectedControl.icon(this.state.mqttState)}
this.state.mqttState)}
> >
{this.state.selectedControl == null {this.state.selectedControl == null
|| <UiItemList state={this.state.mqttState} || <UiItemList state={this.state.mqttState}

View file

@ -3,8 +3,6 @@ import React from "react";
import { Map, ImageOverlay, Marker, LayersControl } from "react-leaflet"; import { Map, ImageOverlay, Marker, LayersControl } from "react-leaflet";
import { CRS, point, divIcon } from "leaflet"; import { CRS, point, divIcon } from "leaflet";
import map from "lodash/map"; import map from "lodash/map";
import mapValues from "lodash/mapValues";
import parseIconName, { controlGetIcon } from "utils/parseIconName";
import type { Controls, Control } from "config/flowtypes"; import type { Controls, Control } from "config/flowtypes";
@ -50,8 +48,8 @@ export default class ControlMap extends React.PureComponent<ControlMapProps> {
} }
createLeafletIcon(control: Control) { createLeafletIcon(control: Control) {
const icon = controlGetIcon(control, this.props.state); const icon = control.icon(this.props.state);
const iconClass = parseIconName(`${icon} 36px`); const iconClass = `${icon} mdi-36px`;
return divIcon({ return divIcon({
iconSize: point(36, 36), iconSize: point(36, 36),
iconAnchor: point(18, 18), iconAnchor: point(18, 18),
@ -61,10 +59,8 @@ export default class ControlMap extends React.PureComponent<ControlMapProps> {
} }
iconColor(control: Control): string { iconColor(control: Control): string {
const ints = mapValues(this.props.state, (x) => x.internal || x.actual);
const acts = mapValues(this.props.state, (x) => x.actual);
if (control.iconColor != null) { if (control.iconColor != null) {
return control.iconColor(ints, acts, this.props.state); return control.iconColor(this.props.state);
} }
return "#000"; return "#000";
} }

View file

@ -8,24 +8,26 @@ import IconButton from "@material-ui/core/IconButton";
import AppBar from "@material-ui/core/AppBar"; import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar"; import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List"; import List from "@material-ui/core/List";
import { renderIcon } from "utils/parseIconName"; import { renderIcon } from "config/icon";
import type { RawIcon } from "config/icon";
import type { Control } from "config/flowtypes"; import type { Control } from "config/flowtypes";
export type SideBarProps = { export type SideBarProps = {
control: ?Control, control: ?Control,
open: boolean, open: boolean,
onCloseRequest: () => void, onCloseRequest: () => void,
icon?: ?string, icon?: ?RawIcon,
children?: React.Node children?: React.Node
}; };
export type SideBarState = { export type SideBarState = {
}; };
class SideBar extends React.PureComponent<SideBarProps & Classes, SideBarState> type Props = SideBarProps & Classes;
{
constructor(props: SideBarProps & Classes) { class SideBar extends React.PureComponent<Props, SideBarState> {
constructor(props: Props) {
super(props); super(props);
} }

View file

@ -16,7 +16,7 @@ export type TopBarState = {
}; };
export default class TopBar export default class TopBar
extends React.PureComponent<TopBarProps, TopBarState> { extends React.PureComponent<TopBarProps, TopBarState> {
constructor(props: TopBarProps) { constructor(props: TopBarProps) {
super(props); super(props);
} }

View file

@ -21,17 +21,16 @@ import type {
} from "config/flowtypes"; } from "config/flowtypes";
import keyOf from "utils/keyOf"; import keyOf from "utils/keyOf";
import { getInternals, getActuals } from "utils/state";
type UiItemProps<I> = { type UiItemProps<I> = {
item: I, item: I,
state: State, state: State,
onChangeState: (topic: string, nextState: Actual) => void onChangeState: (topic: string, nextState: string) => void
}; };
// eslint-disable-next-line flowtype/no-weak-types // eslint-disable-next-line flowtype/no-weak-types
export default class UiItem<I:Object> export default class UiItem<I:Object>
extends React.PureComponent<UiItemProps<I>> { extends React.PureComponent<UiItemProps<I>> {
constructor(props: UiItemProps<I>) { constructor(props: UiItemProps<I>) {
super(props); super(props);
} }
@ -54,9 +53,7 @@ export default class UiItem<I:Object>
typeof this.props.item.enableCondition == "function") { typeof this.props.item.enableCondition == "function") {
const enableCondition = this.props.item.enableCondition; const enableCondition = this.props.item.enableCondition;
const state = this.props.state; const state = this.props.state;
const internals = getInternals(state); return enableCondition(state);
const actuals = getActuals(state);
return enableCondition(internals, actuals, state);
} else { } else {
return true; return true;
} }
@ -68,7 +65,7 @@ export class UiControl<I: UIControl> extends UiItem<I> {
super(props); super(props);
} }
changeState(next: Actual) { changeState(next: string) {
if (this.props.item.topic == null) { if (this.props.item.topic == null) {
throw new Error( throw new Error(
`Missing topic in ${this.props.item.type} "${this.props.item.text}"` `Missing topic in ${this.props.item.type} "${this.props.item.text}"`
@ -93,19 +90,6 @@ export class UiControl<I: UIControl> extends UiItem<I> {
} }
return value; return value;
} }
isEnabled() {
if (Object.keys(this.props.item).includes("enableCondition") &&
// $FlowFixMe
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<UIToggle> { export class Toggle extends UiControl<UIToggle> {
@ -113,9 +97,8 @@ export class Toggle extends UiControl<UIToggle> {
const value = this.getValue(); const value = this.getValue();
const control = this.props.item; const control = this.props.item;
const isChecked = control.toggled || const isChecked = control.toggled ||
((i, _a, _s) => i === (control.on || "on")); ((i, _s) => i === (control.on || "on"));
const checked = isChecked( const checked = isChecked(value, this.props.state);
value.internal || value.actual, value.actual, this.props.state);
return checked; return checked;
} }
@ -145,7 +128,7 @@ export class Toggle extends UiControl<UIToggle> {
} }
export class DropDown extends UiControl<UIDropDown> { export class DropDown extends UiControl<UIDropDown> {
runPrimaryAction = (next?: Actual) => { runPrimaryAction = (next?: string) => {
if (this.isEnabled()) { if (this.isEnabled()) {
const control = this.props.item; const control = this.props.item;
const optionKeys = keys(control.options); const optionKeys = keys(control.options);
@ -172,7 +155,7 @@ export class DropDown extends UiControl<UIDropDown> {
return ( return (
<FormControl> <FormControl>
<InputLabel htmlFor={id}>{control.text}</InputLabel> <InputLabel htmlFor={id}>{control.text}</InputLabel>
<Select value={value.internal || value.actual} <Select value={value}
onChange={(event) => this.runPrimaryAction(event.target.value)} onChange={(event) => this.runPrimaryAction(event.target.value)}
disabled={!this.isEnabled()} disabled={!this.isEnabled()}
input={<Input id={id} />} input={<Input id={id} />}
@ -185,9 +168,9 @@ export class DropDown extends UiControl<UIDropDown> {
} }
export class Slider extends UiControl<UISlider> { export class Slider extends UiControl<UISlider> {
runPrimaryAction = (_e: ?any, v: ?number) => { runPrimaryAction = (e: ?Event, v: ?number) => {
if (v != null) { if (v != null) {
this.changeState(v); this.changeState(v.toString());
} }
} }
@ -195,10 +178,11 @@ export class Slider extends UiControl<UISlider> {
return [ return [
<ListItemText key="label" primary={this.props.item.text} />, <ListItemText key="label" primary={this.props.item.text} />,
<SliderComponent key="slidercomponent" <SliderComponent key="slidercomponent"
value={this.getValue().internal || this.getValue().actual} value={parseFloat(this.getValue())}
min={this.props.item.min || 0} max={this.props.item.max || 0} min={this.props.item.min || 0} max={this.props.item.max || 0}
step={this.props.item.step || 0} step={this.props.item.step || 1}
onChange={() => this.props.item.delayedApply || this.runPrimaryAction()} onChange={(e, v) =>
this.props.item.delayedApply || this.runPrimaryAction(e, v)}
onDragEnd={this.runPrimaryAction} onDragEnd={this.runPrimaryAction}
disabled={!this.isEnabled()} /> disabled={!this.isEnabled()} />
]; ];
@ -244,7 +228,7 @@ export class Text extends UiControl<UIText> {
render() { render() {
return [ return [
<ListItemText key="label" secondary={this.props.item.text} />, <ListItemText key="label" secondary={this.props.item.text} />,
<ListItemText key="vr" primary={this.getValue().internal} align="right" /> <ListItemText key="vr" primary={this.getValue()} align="right" />
]; ];
} }
} }
@ -253,7 +237,7 @@ export class Progress extends UiControl<UIProgress> {
render() { render() {
const min = this.props.item.min || 0; const min = this.props.item.min || 0;
const max = this.props.item.max || 100; const max = this.props.item.max || 100;
const val = parseFloat(this.getValue().internal || this.getValue().actual); const val = parseFloat(this.getValue());
const value = val * 100 / max - min; const value = val * 100 / max - min;
return [ return [
<ListItemText key="label" secondary={this.props.item.text} />, <ListItemText key="label" secondary={this.props.item.text} />,

View file

@ -2,17 +2,17 @@
import React from "react"; import React from "react";
import ListItem from "@material-ui/core/ListItem"; import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon"; import ListItemIcon from "@material-ui/core/ListItemIcon";
import { renderIcon } from "utils/parseIconName"; import { renderIcon } from "config/icon";
import type { ControlUI } from "config/flowtypes"; import type { ControlUI } from "config/flowtypes";
import { Toggle, DropDown, Link, import { Toggle, DropDown, Link,
Section, Text, Progress, Slider } from "./UiItem"; Section, Text, Progress, Slider } from "./UiItem";
export type UiItemListProps = { export type UiItemListProps = {
controls: Array<ControlUI>, controls: Array<ControlUI>,
state: State, state: State,
onChangeState: (topic: string, nextState: Actual) => void onChangeState: (topic: string, nextState: string) => void
}; };
export default class UiItemList extends React.PureComponent<UiItemListProps> { export default class UiItemList extends React.PureComponent<UiItemListProps> {
@ -33,7 +33,9 @@ export default class UiItemList extends React.PureComponent<UiItemListProps> {
return ( return (
<ListItem key={key}> <ListItem key={key}>
{control.icon == null || {control.icon == null ||
<ListItemIcon>{renderIcon(control.icon, "mdi-24px")}</ListItemIcon>} <ListItemIcon>
{renderIcon(control.icon(this.props.state), "mdi-24px")}
</ListItemIcon>}
{this.renderControl(control)} {this.renderControl(control)}
</ListItem> </ListItem>
); );

View file

@ -1,24 +1,21 @@
// @flow // @flow
import type { Color } from "config/colors"; import type { Color } from "config/colors";
import type { Icon } from "config/icon";
export type TopicType = (msg: Buffer) => any; export type TopicType = (msg: Buffer) => string;
export type StateCommand = {
name: string,
type: TopicType
}
export type Topic = { export type Topic = {
state: string, state?: StateCommand,
command: string, command?: StateCommand,
defaultValue: Actual, defaultValue: string
values: Map<Internal, Actual>,
type?: TopicType
}; };
export type Topics = Map<string, Topic>; export type Topics = Map<string, Topic>;
export type TopicDependentOption<T> = (
internal: Internal, actual: Actual, state: State
) => T;
export type StateDependentOption<T> = (
internals: Map<string, Internal>, actuals: Map<string, Actual>, state: State
) => T;
export interface UIControl { export interface UIControl {
+type: string, +type: string,
+text: string, +text: string,
@ -26,27 +23,27 @@ export interface UIControl {
} }
export interface Enableable { export interface Enableable {
enableCondition?: TopicDependentOption<boolean> enableCondition?: (s: State) => boolean
} }
export type UIToggle = $ReadOnly<{| export type UIToggle = $ReadOnly<{|
type: "toggle", type: "toggle",
text: string, text: string,
topic: string, topic: string,
icon?: string, icon?: Icon,
enableCondition?: TopicDependentOption<boolean>, enableCondition?: (s: State) => boolean,
on?: Actual, on?: string,
off?: Actual, off?: string,
toggled?: TopicDependentOption<boolean> toggled?: (v: string, s: State) => boolean
|}>; |}>;
export type UIDropDown = $ReadOnly<{| export type UIDropDown = $ReadOnly<{|
type: "dropDown", type: "dropDown",
text: string, text: string,
topic: string, topic: string,
icon?: string, icon?: Icon,
enableCondition?: TopicDependentOption<boolean>, enableCondition?: (s: State) => boolean,
options: Map<string, any>, options: Map<string, string>,
renderValue?: (value: string) => string renderValue?: (value: string) => string
|}>; |}>;
@ -54,8 +51,8 @@ export type UISlider = $ReadOnly<{|
type: "slider", type: "slider",
text: string, text: string,
topic: string, topic: string,
icon?: string, icon?: Icon,
enableCondition?: TopicDependentOption<boolean>, enableCondition?: (s: State) => boolean,
min?: number, min?: number,
max?: number, max?: number,
step?: number, step?: number,
@ -71,24 +68,24 @@ export type UILink = $ReadOnly<{|
type: "link", type: "link",
text: string, text: string,
link: string, link: string,
enableCondition?: StateDependentOption<boolean>, enableCondition?: (s: State) => boolean,
// TODO: check if both the following options are implemented // TODO: check if both the following options are implemented
icon?: string icon?: Icon
|}>; |}>;
export type UIText = $ReadOnly<{| export type UIText = $ReadOnly<{|
type: "text", type: "text",
text: string, text: string,
topic: string, topic: string,
icon?: string icon?: Icon
|}>; |}>;
export type UIProgress = $ReadOnly<{| export type UIProgress = $ReadOnly<{|
type: "progress", type: "progress",
text: string, text: string,
topic: string, topic: string,
icon?: string, icon?: Icon,
min?: number, min?: number,
max?: number max?: number
|}>; |}>;
@ -105,16 +102,8 @@ export type ControlUI =
export type Control = { export type Control = {
name: string, name: string,
position: [number, number], position: [number, number],
icon: string | ( icon: Icon,
internals: Map<string, Internal>, iconColor?: (state: State) => Color,
actuals: Map<string, Actual>,
state: State
) => string,
iconColor?: (
internals: Map<string, Internal>,
actuals: Map<string, Actual>,
state: State
) => Color,
ui: Array<ControlUI> ui: Array<ControlUI>
}; };
export type Controls = Map<string, Control>; export type Controls = Map<string, Control>;

45
src/config/icon.js Normal file
View file

@ -0,0 +1,45 @@
// @flow
import * as React from "react";
export opaque type RawIcon: string = string;
export type Icon = (State) => RawIcon;
export const raw_mdi = (name: string): RawIcon => {
return `mdi ${name.split(" ").map((icon) => "mdi-".concat(icon)).join(" ")}`;
};
export const mdi = (icon: string) => () => raw_mdi(icon);
export const mdi_battery = (topic: string) => (state: State) => {
const rawval = state[topic];
const val = parseInt(rawval);
if (isNaN(val)) {
return raw_mdi("battery-unknown");
} else if (val > 95) {
return raw_mdi("battery");
} else if (val > 85) {
return raw_mdi("battery-90");
} else if (val > 75) {
return raw_mdi("battery-80");
} else if (val > 65) {
return raw_mdi("battery-70");
} else if (val > 55) {
return raw_mdi("battery-60");
} else if (val > 45) {
return raw_mdi("battery-50");
} else if (val > 35) {
return raw_mdi("battery-40");
} else if (val > 25) {
return raw_mdi("battery-30");
} else if (val > 15) {
return raw_mdi("battery-20");
} else {
return raw_mdi("battery-10");
}
};
export const renderIcon =
(icon: RawIcon, extraClass?: string): React.Node => {
return <i className={`${extraClass || ""} ${icon}`}></i>;
};

View file

@ -1,8 +1,21 @@
// @flow // @flow
import type { TopicType } from "config/flowtypes"; import type { TopicType } from "config/flowtypes";
import at from "lodash/at";
export const string: TopicType = (msg: Buffer) => msg.toString();
export const string: TopicType = msg => msg.toString();
export const json = (path: string, innerType?: TopicType): TopicType => { export const json = (path: string, innerType?: TopicType): TopicType => {
const parseAgain = innerType == null ? x => x : innerType; const parseAgain = innerType == null ? (x) => x.toString() : innerType;
return msg => parseAgain(JSON.parse(msg.toString())[path]); return (msg) => parseAgain(Buffer.from(
at(JSON.parse(msg.toString()), path)[0].toString()));
}; };
export type TypeOptionParam = { otherwise?: string, [string]: string };
export const option = (values: TypeOptionParam): TopicType => {
// TODO: error
const defaultValue = values.otherwise != null ? values.otherwise : "";
const mapVal = (x) => (values[x] != null ? values[x] : defaultValue);
return (x) => mapVal(x.toString());
};
export const jsonArray = (msg: Buffer) => JSON.parse(msg.toString()).join(", ");

View file

@ -8,11 +8,13 @@ import App from "components/App";
import "../node_modules/@mdi/font/css/materialdesignicons.min.css"; import "../node_modules/@mdi/font/css/materialdesignicons.min.css";
import "../css/styles.css"; import "../css/styles.css";
const Config : Config = window.config; import type { Config } from "config/flowtypes";
const config : Config = window.config;
injectTapEventPlugin(); injectTapEventPlugin();
document.title = `${Config.space.name} Map`; document.title = `${config.space.name} Map`;
// $FlowFixMe // $FlowFixMe
const contentElement: Element = document.getElementById("content"); const contentElement: Element = document.getElementById("content");
ReactDOM.render(<App config={Config} />, contentElement); ReactDOM.render(<App config={config} />, contentElement);

View file

@ -1,25 +0,0 @@
// @flow
import * as React from "react";
import { getInternals, getActuals } from "utils/state";
import type { Control } from "config/flowtypes";
export default function parseIconName(name: string): string {
return `mdi ${name.split(" ").map((icon) => "mdi-".concat(icon)).join(" ")}`;
}
export const renderIcon = (name: string, extraClass?: string): React.Node => {
return <i className={`${extraClass || ""} ${parseIconName(name)}`}></i>;
};
export const controlGetIcon = (control: Control, state: State): string => {
const internals: Map<string, Internal> = getInternals(state);
const actuals: Map<string, Actual> = getActuals(state);
return typeof control.icon !== "function" ? control.icon
: control.icon(internals, actuals, state);
};
export const renderControlIcon = (control: Control,
state: State, extraClass?: string): React.Node => {
return renderIcon(controlGetIcon(control, state), extraClass);
};

View file

@ -1,8 +0,0 @@
// @flow
import mapValues from "lodash/mapValues";
export const getInternals = (state: State): Map<string, Internal> =>
mapValues(state, (x) => x.internal || x.actual);
export const getActuals = (state: State): Map<string, Actual> =>
mapValues(state, (x) => x.actual);

View file

@ -7,26 +7,7 @@ declare type Classes = {
classes: Map<string, string> classes: Map<string, string>
}; };
declare type Internal = string; declare type State = Map<string,string>;
declare type Actual = any;
declare type StateValue = {
internal: string,
actual: any
};
declare type State = Map<string,StateValue>;
//declare type State = {
// mqtt: ?any,
// uiOpened: ?string,
// A map of the actual state values for each topic.
// internal is the internal term for the value,
// that is equal to the key in the values section of that
// topic, for example given by:
// values: { off: "OFF", on: "ON" }
// and actual is the value of that or whatever is given by mqtt.
// values: Map<string, { internal: ?string, actual: any }>,
// visibleLayers: Array<string>
//};
declare type Point = [number, number]; declare type Point = [number, number];

View file

@ -3,7 +3,6 @@ const webpack = require('webpack');
const WebpackShellPlugin = require('webpack-shell-plugin'); const WebpackShellPlugin = require('webpack-shell-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin');
const preBuildScripts = process.env.NO_FLOW == undefined ? const preBuildScripts = process.env.NO_FLOW == undefined ?
process.env.FLOW_PATH != undefined ? [process.env.FLOW_PATH] : ['flow'] process.env.FLOW_PATH != undefined ? [process.env.FLOW_PATH] : ['flow']
: []; : [];

217
yarn.lock
View file

@ -161,23 +161,19 @@ acorn-dynamic-import@^3.0.0:
dependencies: dependencies:
acorn "^5.0.0" acorn "^5.0.0"
acorn-jsx@^3.0.0: acorn-jsx@^4.1.1:
version "3.0.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e"
dependencies: dependencies:
acorn "^3.0.4" acorn "^5.0.3"
acorn@^3.0.4: acorn@^5.0.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
acorn@^5.0.0, acorn@^5.5.0:
version "5.5.3" version "5.5.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9"
ajv-keywords@^2.1.0: acorn@^5.0.3, acorn@^5.6.0:
version "2.1.1" version "5.7.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
ajv-keywords@^3.0.0, ajv-keywords@^3.1.0: ajv-keywords@^3.0.0, ajv-keywords@^3.1.0:
version "3.1.0" version "3.1.0"
@ -190,15 +186,6 @@ ajv@^4.9.1:
co "^4.6.0" co "^4.6.0"
json-stable-stringify "^1.0.1" json-stable-stringify "^1.0.1"
ajv@^5.2.3, ajv@^5.3.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
ajv@^6.0.1, ajv@^6.1.0: ajv@^6.0.1, ajv@^6.1.0:
version "6.4.0" version "6.4.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6"
@ -208,6 +195,15 @@ ajv@^6.0.1, ajv@^6.1.0:
json-schema-traverse "^0.3.0" json-schema-traverse "^0.3.0"
uri-js "^3.0.2" uri-js "^3.0.2"
ajv@^6.5.0:
version "6.5.1"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.1.tgz#88ebc1263c7133937d108b80c5572e64e1d9322d"
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.1"
alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
@ -422,7 +418,7 @@ babel-cli@^6.24.1:
optionalDependencies: optionalDependencies:
chokidar "^1.6.1" chokidar "^1.6.1"
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: babel-code-frame@^6.26.0:
version "6.26.0" version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
dependencies: dependencies:
@ -1633,7 +1629,7 @@ concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.2: concat-stream@^1.5.0, concat-stream@^1.6.2:
version "1.6.2" version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
dependencies: dependencies:
@ -1738,7 +1734,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
sha.js "^2.4.8" sha.js "^2.4.8"
cross-spawn@^5.0.1, cross-spawn@^5.1.0: cross-spawn@^5.0.1:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
dependencies: dependencies:
@ -2220,6 +2216,16 @@ error-ex@^1.2.0:
dependencies: dependencies:
is-arrayish "^0.2.1" is-arrayish "^0.2.1"
es-abstract@^1.10.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
dependencies:
es-to-primitive "^1.1.1"
function-bind "^1.1.1"
has "^1.0.1"
is-callable "^1.1.3"
is-regex "^1.0.4"
es-abstract@^1.5.1, es-abstract@^1.7.0: es-abstract@^1.5.1, es-abstract@^1.7.0:
version "1.11.0" version "1.11.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681"
@ -2268,59 +2274,66 @@ eslint-scope@^3.7.1, eslint-scope@~3.7.1:
esrecurse "^4.1.0" esrecurse "^4.1.0"
estraverse "^4.1.1" estraverse "^4.1.1"
eslint-scope@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-visitor-keys@^1.0.0: eslint-visitor-keys@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
eslint@^4.16.0: eslint@^5.0.1:
version "4.19.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.0.1.tgz#109b90ab7f7a736f54e0f341c8bb9d09777494c3"
dependencies: dependencies:
ajv "^5.3.0" ajv "^6.5.0"
babel-code-frame "^6.22.0" babel-code-frame "^6.26.0"
chalk "^2.1.0" chalk "^2.1.0"
concat-stream "^1.6.0" cross-spawn "^6.0.5"
cross-spawn "^5.1.0"
debug "^3.1.0" debug "^3.1.0"
doctrine "^2.1.0" doctrine "^2.1.0"
eslint-scope "^3.7.1" eslint-scope "^4.0.0"
eslint-visitor-keys "^1.0.0" eslint-visitor-keys "^1.0.0"
espree "^3.5.4" espree "^4.0.0"
esquery "^1.0.0" esquery "^1.0.1"
esutils "^2.0.2" esutils "^2.0.2"
file-entry-cache "^2.0.0" file-entry-cache "^2.0.0"
functional-red-black-tree "^1.0.1" functional-red-black-tree "^1.0.1"
glob "^7.1.2" glob "^7.1.2"
globals "^11.0.1" globals "^11.5.0"
ignore "^3.3.3" ignore "^3.3.3"
imurmurhash "^0.1.4" imurmurhash "^0.1.4"
inquirer "^3.0.6" inquirer "^5.2.0"
is-resolvable "^1.0.0" is-resolvable "^1.1.0"
js-yaml "^3.9.1" js-yaml "^3.11.0"
json-stable-stringify-without-jsonify "^1.0.1" json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.3.0" levn "^0.3.0"
lodash "^4.17.4" lodash "^4.17.5"
minimatch "^3.0.2" minimatch "^3.0.4"
mkdirp "^0.5.1" mkdirp "^0.5.1"
natural-compare "^1.4.0" natural-compare "^1.4.0"
optionator "^0.8.2" optionator "^0.8.2"
path-is-inside "^1.0.2" path-is-inside "^1.0.2"
pluralize "^7.0.0" pluralize "^7.0.0"
progress "^2.0.0" progress "^2.0.0"
regexpp "^1.0.1" regexpp "^1.1.0"
require-uncached "^1.0.3" require-uncached "^1.0.3"
semver "^5.3.0" semver "^5.5.0"
string.prototype.matchall "^2.0.0"
strip-ansi "^4.0.0" strip-ansi "^4.0.0"
strip-json-comments "~2.0.1" strip-json-comments "^2.0.1"
table "4.0.2" table "^4.0.3"
text-table "~0.2.0" text-table "^0.2.0"
espree@^3.5.4: espree@^4.0.0:
version "3.5.4" version "4.0.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634"
dependencies: dependencies:
acorn "^5.5.0" acorn "^5.6.0"
acorn-jsx "^3.0.0" acorn-jsx "^4.1.1"
esprima@^2.6.0: esprima@^2.6.0:
version "2.7.3" version "2.7.3"
@ -2330,7 +2343,7 @@ esprima@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
esquery@^1.0.0: esquery@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
dependencies: dependencies:
@ -2463,7 +2476,7 @@ extend@^3.0.0, extend@~3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
external-editor@^2.0.4: external-editor@^2.1.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
dependencies: dependencies:
@ -2510,6 +2523,10 @@ fast-deep-equal@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
fast-json-stable-stringify@^2.0.0: fast-json-stable-stringify@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@ -2635,9 +2652,9 @@ flatten@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flow-bin@^0.70.0: flow-bin@^0.75.0:
version "0.70.0" version "0.75.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.70.0.tgz#080ae83a997f2b4ddb3dc2649bf13336825292b5" resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.75.0.tgz#b96d1ee99d3b446a3226be66b4013224ce9df260"
flow-typed@^2.3.0: flow-typed@^2.3.0:
version "2.4.0" version "2.4.0"
@ -2872,10 +2889,14 @@ global@~4.3.0:
min-document "^2.19.0" min-document "^2.19.0"
process "~0.5.1" process "~0.5.1"
globals@^11.0.1, globals@^11.1.0: globals@^11.1.0:
version "11.4.0" version "11.4.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc" resolved "https://registry.yarnpkg.com/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc"
globals@^11.5.0:
version "11.7.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
globals@^9.18.0: globals@^9.18.0:
version "9.18.0" version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
@ -2957,6 +2978,10 @@ has-symbol-support-x@^1.4.1:
version "1.4.2" version "1.4.2"
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
has-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
has-to-string-tag-x@^1.2.0: has-to-string-tag-x@^1.2.0:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
@ -3273,21 +3298,20 @@ ini@~1.3.0:
version "1.3.5" version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
inquirer@^3.0.6: inquirer@^5.2.0:
version "3.3.0" version "5.2.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726"
dependencies: dependencies:
ansi-escapes "^3.0.0" ansi-escapes "^3.0.0"
chalk "^2.0.0" chalk "^2.0.0"
cli-cursor "^2.1.0" cli-cursor "^2.1.0"
cli-width "^2.0.0" cli-width "^2.0.0"
external-editor "^2.0.4" external-editor "^2.1.0"
figures "^2.0.0" figures "^2.0.0"
lodash "^4.3.0" lodash "^4.3.0"
mute-stream "0.0.7" mute-stream "0.0.7"
run-async "^2.2.0" run-async "^2.2.0"
rx-lite "^4.0.8" rxjs "^5.5.2"
rx-lite-aggregates "^4.0.8"
string-width "^2.1.0" string-width "^2.1.0"
strip-ansi "^4.0.0" strip-ansi "^4.0.0"
through "^2.3.6" through "^2.3.6"
@ -3573,7 +3597,7 @@ is-relative@^1.0.0:
dependencies: dependencies:
is-unc-path "^1.0.0" is-unc-path "^1.0.0"
is-resolvable@^1.0.0: is-resolvable@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
@ -3665,9 +3689,9 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
js-yaml@^3.9.1: js-yaml@^3.11.0:
version "3.11.0" version "3.12.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
dependencies: dependencies:
argparse "^1.0.7" argparse "^1.0.7"
esprima "^4.0.0" esprima "^4.0.0"
@ -3699,6 +3723,10 @@ json-schema-traverse@^0.3.0:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
json-schema@0.2.3: json-schema@0.2.3:
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
@ -5399,7 +5427,13 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2" extend-shallow "^3.0.2"
safe-regex "^1.1.0" safe-regex "^1.1.0"
regexpp@^1.0.1: regexp.prototype.flags@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c"
dependencies:
define-properties "^1.1.2"
regexpp@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab"
@ -5565,15 +5599,11 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies: dependencies:
aproba "^1.1.1" aproba "^1.1.1"
rx-lite-aggregates@^4.0.8: rxjs@^5.5.2:
version "4.0.8" version "5.5.11"
resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87"
dependencies: dependencies:
rx-lite "*" symbol-observable "1.0.1"
rx-lite@*, rx-lite@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
rxjs@^6.1.0: rxjs@^6.1.0:
version "6.2.1" version "6.2.1"
@ -5970,6 +6000,16 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
is-fullwidth-code-point "^2.0.0" is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0" strip-ansi "^4.0.0"
string.prototype.matchall@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz#2af8fe3d2d6dc53ca2a59bd376b089c3c152b3c8"
dependencies:
define-properties "^1.1.2"
es-abstract "^1.10.0"
function-bind "^1.1.1"
has-symbols "^1.0.0"
regexp.prototype.flags "^1.2.0"
string_decoder@^1.0.0, string_decoder@~1.1.1: string_decoder@^1.0.0, string_decoder@~1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@ -6016,7 +6056,7 @@ strip-indent@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
strip-json-comments@~2.0.1: strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@ -6061,6 +6101,10 @@ svgo@^0.7.0:
sax "~1.2.1" sax "~1.2.1"
whet.extend "~0.9.9" whet.extend "~0.9.9"
symbol-observable@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
symbol-observable@1.0.4: symbol-observable@1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
@ -6069,18 +6113,7 @@ symbol-observable@^1.0.3, symbol-observable@^1.0.4, symbol-observable@^1.1.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
table@4.0.2: table@^4.0.2, table@^4.0.3:
version "4.0.2"
resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36"
dependencies:
ajv "^5.2.3"
ajv-keywords "^2.1.0"
chalk "^2.1.0"
lodash "^4.17.4"
slice-ansi "1.0.0"
string-width "^2.1.1"
table@^4.0.2:
version "4.0.3" version "4.0.3"
resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc"
dependencies: dependencies:
@ -6116,7 +6149,7 @@ tar@^2.2.1:
fstream "^1.0.2" fstream "^1.0.2"
inherits "2" inherits "2"
text-table@~0.2.0: text-table@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -6393,6 +6426,12 @@ uri-js@^3.0.2:
dependencies: dependencies:
punycode "^2.1.0" punycode "^2.1.0"
uri-js@^4.2.1:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
dependencies:
punycode "^2.1.0"
urix@^0.1.0: urix@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"