More ESLint options
This commit is contained in:
parent
a60e800cee
commit
19b91cfd0a
8 changed files with 200 additions and 59 deletions
125
.eslintrc.js
125
.eslintrc.js
|
|
@ -4,7 +4,11 @@ module.exports = {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:flowtype/recommended",
|
||||||
|
"plugin:react/recommended"
|
||||||
|
],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"experimentalObjectRestSpread": true,
|
"experimentalObjectRestSpread": true,
|
||||||
|
|
@ -16,21 +20,118 @@ module.exports = {
|
||||||
"react", "flowtype"
|
"react", "flowtype"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"indent": ["error", 2],
|
// possible errors
|
||||||
"linebreak-style": ["error", "unix"],
|
"getter-return": "error",
|
||||||
"quotes": ["error","double"],
|
"no-extra-parens": ["error", "functions"],
|
||||||
"semi": ["error","always"],
|
"no-template-curly-in-string": "error",
|
||||||
|
"valid-jsdoc": "error",
|
||||||
|
|
||||||
|
// best practices
|
||||||
|
"accessor-pairs": "error",
|
||||||
|
"array-callback-return": "error",
|
||||||
|
"block-scoped-var": "error",
|
||||||
|
"consistent-return": ["error", { "treatUndefinedAsUnspecified": true }],
|
||||||
|
"curly": "error",
|
||||||
|
"default-case": ["error", { "commentPattern": "^skip\\sdefault" }],
|
||||||
|
"dot-location": ["error", "property"],
|
||||||
|
"eqeqeq": ["error", "smart"],
|
||||||
|
"no-alert": "error",
|
||||||
|
"no-caller": "error",
|
||||||
|
"no-eval": "error",
|
||||||
|
"no-extend-native": "error",
|
||||||
|
"no-extra-label": "error",
|
||||||
|
"no-floating-decimal": "error",
|
||||||
|
"no-implicit-coercion": "error",
|
||||||
|
"no-implied-eval": "error",
|
||||||
|
"no-invalid-this": "error",
|
||||||
|
"no-iterator": "error",
|
||||||
|
"no-loop-func": "error",
|
||||||
|
"no-multi-spaces": "warn",
|
||||||
|
"no-multi-str": "error",
|
||||||
|
"no-new": "warn",
|
||||||
|
"no-new-func": "error",
|
||||||
|
"no-new-wrappers": "error",
|
||||||
|
"no-octal-escape": "error",
|
||||||
|
"no-param-reassign": "error",
|
||||||
|
"no-proto": "error",
|
||||||
|
"no-return-assign": "error",
|
||||||
|
"no-return-await": "error",
|
||||||
|
"no-script-url": "error",
|
||||||
|
"no-self-compare": "error",
|
||||||
|
"no-sequences": "error",
|
||||||
|
"no-throw-literal": "error",
|
||||||
|
"no-unmodified-loop-condition": "error",
|
||||||
|
"no-unused-expressions": ["error", {
|
||||||
|
"allowShortCircuit": true,
|
||||||
|
"allowTernary": true
|
||||||
|
}],
|
||||||
|
"no-useless-call": "warn",
|
||||||
|
"no-useless-return": "error",
|
||||||
|
"no-warning-comments": ["warn", { "terms": ["todo", "fixme", "error", "bug"] }],
|
||||||
|
"no-with": "error",
|
||||||
|
"prefer-promise-reject-errors": "error",
|
||||||
|
"radix": "warn",
|
||||||
|
"require-await": "warn",
|
||||||
|
"vars-on-top": "warn",
|
||||||
|
"yoda": "warn",
|
||||||
|
|
||||||
|
// variables
|
||||||
|
"init-declarations": ["error", "always"],
|
||||||
"no-unused-vars": ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" }],
|
"no-unused-vars": ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" }],
|
||||||
|
"no-catch-shadow": "error",
|
||||||
|
"no-label-var": "error",
|
||||||
|
"no-shadow": "error",
|
||||||
|
"no-shadow-restricted-names": "error",
|
||||||
|
"no-undef-init": "error",
|
||||||
|
"no-undefined": "error",
|
||||||
|
"no-use-before-define": "error",
|
||||||
|
|
||||||
"react/jsx-uses-react": 2,
|
// stylistic issues
|
||||||
"react/jsx-uses-vars": 2,
|
"array-bracket-spacing": ["error", "never"],
|
||||||
"react/react-in-jsx-scope": "error",
|
"block-spacing": ["error", "always"],
|
||||||
|
"brace-style": ["warn", "1tbs"],
|
||||||
|
"camelcase": ["warn", { properties: "always" }],
|
||||||
|
"comma-dangle": ["error", {
|
||||||
|
"arrays": "never",
|
||||||
|
"objects": "never",
|
||||||
|
"imports": "never",
|
||||||
|
"exports": "never",
|
||||||
|
"functions": "never"
|
||||||
|
}],
|
||||||
|
"comma-spacing": "warn",
|
||||||
|
"computed-property-spacing": ["warn", "never"],
|
||||||
|
"eol-last": ["warn", "always"],
|
||||||
|
"func-call-spacing": ["warn", "never"],
|
||||||
|
"func-names": ["warn", "as-needed"],
|
||||||
|
"indent": ["warn", 2],
|
||||||
|
"jsx-quotes": "warn",
|
||||||
|
"key-spacing": "warn",
|
||||||
|
"keyword-spacing": "warn",
|
||||||
|
"linebreak-style": ["error", "unix"],
|
||||||
|
"lines-around-comment": "warn",
|
||||||
|
"lines-between-class-members": ["warn", "always"],
|
||||||
|
"max-len": "error",
|
||||||
|
"max-nested-callbacks": ["error", 5],
|
||||||
|
"max-statements-per-line": "error",
|
||||||
|
"multiline-comment-style": ["error", "starred-block"],
|
||||||
|
"new-parens": "error",
|
||||||
|
"no-array-constructor": "error",
|
||||||
|
"no-trailing-spaces": "error",
|
||||||
|
"no-unneeded-ternary": "warn",
|
||||||
|
"no-whitespace-before-property": "error",
|
||||||
|
"one-var": ["error", "never"],
|
||||||
|
"semi": ["error", "always"],
|
||||||
|
"semi-spacing": "error",
|
||||||
|
"semi-style": "error",
|
||||||
|
"space-before-blocks": "error",
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
|
||||||
"flowtype/define-flow-type": 2,
|
// react
|
||||||
"flowtype/boolean-style": "error",
|
"react/prop-types": "off",
|
||||||
"flowtype/generic-spacing": ["error", "never"],
|
"react/display-name": "off",
|
||||||
|
|
||||||
|
// flow
|
||||||
"flowtype/no-dupe-keys": "error",
|
"flowtype/no-dupe-keys": "error",
|
||||||
"flowtype/union-intersection-spacing": ["error", "always"],
|
|
||||||
"flowtype/no-weak-types": "warn",
|
"flowtype/no-weak-types": "warn",
|
||||||
"flowtype/require-variable-type": "warn"
|
"flowtype/require-variable-type": "warn"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
"production-build": "webpack --bail --config webpack.prod.js",
|
"production-build": "webpack --bail --config webpack.prod.js",
|
||||||
"watch": "webpack-dev-server --open --config webpack.dev.js",
|
"watch": "webpack-dev-server --open --config webpack.dev.js",
|
||||||
"travis": "yarn lint && yarn build && yarn production-build",
|
"travis": "yarn lint && yarn build && yarn production-build",
|
||||||
"lint": "yarn eslint -- --ext js --ext jsx src/",
|
"lint": "eslint -- --ext js --ext jsx src/",
|
||||||
"precommit": "yarn lint"
|
"precommit": "yarn lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -14,23 +14,36 @@ import {
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemSecondaryAction,
|
ListItemSecondaryAction,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
ListSubheader,
|
ListSubheader
|
||||||
} from "material-ui/List";
|
} from "material-ui/List";
|
||||||
import Button from "material-ui/Button";
|
import Button from "material-ui/Button";
|
||||||
|
|
||||||
const enabled = (props: ControlUI, state: State) => {
|
const enabled = (props: ControlUI, state: State) => {
|
||||||
if (props.enableCondition == null) return true;
|
if (props.enableCondition == null) {
|
||||||
else {
|
return true;
|
||||||
|
} else {
|
||||||
const val = state.values[props.topic];
|
const val = state.values[props.topic];
|
||||||
return props.enableCondition(
|
return props.enableCondition(
|
||||||
val.internal == null ? val.actual : val.internal, val.actual, R.map(x => x.internal == null ?
|
val.internal == null ? val.actual : val.internal, val.actual,
|
||||||
x.actual : x.internal, state.values == null ? {} : state.values));
|
R.map(x => x.internal == null ? x.actual
|
||||||
|
: x.internal, state.values == null ? {} : state.values));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getValue = (topic: string, val: string) =>
|
const getValue = (topic: string, val: string) =>
|
||||||
Config.topics[topic].values[val];
|
Config.topics[topic].values[val];
|
||||||
|
|
||||||
|
const renderIcon = (icon: string) => {
|
||||||
|
if (icon != null) {
|
||||||
|
return (
|
||||||
|
<ListItemIcon>
|
||||||
|
<i className={`mdi mdi-${icon} mdi-24px`}></i>
|
||||||
|
</ListItemIcon>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
export const onSwitch = (topic: string, props: ControlUI, state: State) =>
|
export const onSwitch = (topic: string, props: ControlUI, state: State) =>
|
||||||
(x, toggled: boolean) => {
|
(x, toggled: boolean) => {
|
||||||
if (state.mqtt != null) {
|
if (state.mqtt != null) {
|
||||||
|
|
@ -53,11 +66,11 @@ export const isToggled = (state: State, props: ControlUI) => {
|
||||||
export const toggle = (state: State, props: ControlUI) => {
|
export const toggle = (state: State, props: ControlUI) => {
|
||||||
return (
|
return (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
{props.icon && <ListItemIcon><i className={`mdi mdi-${props.icon} mdi-24px`}></i></ListItemIcon>}
|
{renderIcon(props.icon)}
|
||||||
<ListItemText primary={props.text} />
|
<ListItemText primary={props.text} />
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Switch label={props.text}
|
<Switch label={props.text}
|
||||||
checked={isToggled(state,props)}
|
checked={isToggled(state, props)}
|
||||||
onChange={onSwitch(props.topic, props, state)}
|
onChange={onSwitch(props.topic, props, state)}
|
||||||
disabled={!(enabled(props, state))} />
|
disabled={!(enabled(props, state))} />
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
|
|
@ -77,10 +90,11 @@ const dropDownItem = (topic: string) => (text: string, key: string) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
export const dropDown = (state: State, props: ControlUI) => {
|
export const dropDown = (state: State, props: ControlUI) => {
|
||||||
const id = `${props.topic}.${Object.keys(props.options).reduce((v,r) => v + "." + r)}`;
|
const id = `${props.topic}.${Object.keys(props.options)
|
||||||
|
.reduce((v, r) => v + "." + r)}`;
|
||||||
return (
|
return (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
{props.icon && <ListItemIcon><i className={`mdi mdi-${props.icon} mdi-24px`}></i></ListItemIcon>}
|
{renderIcon(props.icon)}
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<InputLabel htmlFor={id}>{props.text}</InputLabel>
|
<InputLabel htmlFor={id}>{props.text}</InputLabel>
|
||||||
<Select value={state.values[props.topic].actual}
|
<Select value={state.values[props.topic].actual}
|
||||||
|
|
@ -104,7 +118,7 @@ const onSliderChange = (state: State, props: ControlUI) =>
|
||||||
|
|
||||||
export const slider = (state: State, props: ControlUI) => (
|
export const slider = (state: State, props: ControlUI) => (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
{props.icon && <ListItemIcon><i className={`mdi mdi-${props.icon} mdi-24px`}></i></ListItemIcon>}
|
{renderIcon(props.icon)}
|
||||||
<ListItemText primary={props.text} />
|
<ListItemText primary={props.text} />
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<MuiThemeProvider>
|
<MuiThemeProvider>
|
||||||
|
|
@ -125,7 +139,10 @@ export const section = (state: State, props: ControlUI) => (
|
||||||
|
|
||||||
export const link = (state: State, props: ControlUI) => (
|
export const link = (state: State, props: ControlUI) => (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Button raised onClick={() => window.open(props.link, "_blank")} color="primary">
|
<Button raised
|
||||||
|
onClick={() => window.open(props.link, "_blank")}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
{props.text}
|
{props.text}
|
||||||
</Button>
|
</Button>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import Typography from "material-ui/Typography";
|
||||||
|
|
||||||
const TopBarLayerSelector = (_props: Object) => (
|
const TopBarLayerSelector = (_props: Object) => (
|
||||||
<IconButton>
|
<IconButton>
|
||||||
<Icon>layers</Icon>
|
<i className="mdi mdi-layers"></i>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -23,7 +23,8 @@ const TopBarIndicatorMenu = (props: Object) => (
|
||||||
|
|
||||||
const TopBarIndicator = (props: Object) => {
|
const TopBarIndicator = (props: Object) => {
|
||||||
if (props.mqtt == null || props.mqtt.reconnecting) {
|
if (props.mqtt == null || props.mqtt.reconnecting) {
|
||||||
return (<CircularProgress size={48} style={{color: "rgba(0, 0, 0, 0.54)"}} />);
|
return (<CircularProgress size={48}
|
||||||
|
style={{color: "rgba(0, 0, 0, 0.54)"}} />);
|
||||||
} else {
|
} else {
|
||||||
return (<TopBarIndicatorMenu {...props} />);
|
return (<TopBarIndicatorMenu {...props} />);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
src/map.js
38
src/map.js
|
|
@ -23,22 +23,32 @@ const iconHtml = (el, state: State) =>
|
||||||
+ "color:" + color(el.iconColor, state) + ";\">"
|
+ "color:" + color(el.iconColor, state) + ";\">"
|
||||||
+ "</i>";
|
+ "</i>";
|
||||||
|
|
||||||
const Markers = (props) => R.values(R.mapObjIndexed((el,key) => (
|
const Markers = (props) => R.values(R.mapObjIndexed((el, key) => (
|
||||||
<Marker position={c(el.position)} key={el.name}
|
<Marker position={c(el.position)} key={el.name}
|
||||||
icon={Leaflet.divIcon(
|
icon={Leaflet.divIcon(
|
||||||
{
|
{
|
||||||
html: iconHtml(el, props.state),
|
html: iconHtml(el, props.state),
|
||||||
iconSize: Leaflet.point(36,36),
|
iconSize: Leaflet.point(36, 36),
|
||||||
iconAnchor: Leaflet.point(18,18)
|
iconAnchor: Leaflet.point(18, 18)
|
||||||
})}
|
})}
|
||||||
onClick={(e) => store.dispatch({type: Actions.CHANGE_UI, payload: key, toggle: e.originalEvent.ctrlKey})}>
|
onClick={(e) => store.dispatch({
|
||||||
|
type: Actions.CHANGE_UI,
|
||||||
|
payload: key,
|
||||||
|
toggle: e.originalEvent.ctrlKey})}>
|
||||||
</Marker>
|
</Marker>
|
||||||
), R.propOr({}, "controls", Config)));
|
), R.propOr({}, "controls", Config)));
|
||||||
|
|
||||||
class SpaceMap extends React.Component<{state: State, width: number, height: number,
|
type SpaceMapProps = {
|
||||||
zoom: number, image: string}> {
|
state: State,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
zoom: number,
|
||||||
|
image: string
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
class SpaceMap extends React.Component<SpaceMapProps> {
|
||||||
|
|
||||||
|
constructor(props: SpaceMapProps) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,19 +58,23 @@ class SpaceMap extends React.Component<{state: State, width: number, height: num
|
||||||
<Map center={c([props.width / 2, props.height / 2])} zoom={props.zoom}
|
<Map center={c([props.width / 2, props.height / 2])} zoom={props.zoom}
|
||||||
crs={Leaflet.CRS.Simple}>
|
crs={Leaflet.CRS.Simple}>
|
||||||
{Markers(props)}
|
{Markers(props)}
|
||||||
<LayersControl position='topright'>
|
<LayersControl position="topright">
|
||||||
{Config.layers.map(x => this.renderLayer(x, [c([0,0]), c([props.width, props.height])]))}
|
{Config.layers.map(x =>
|
||||||
|
this.renderLayer(x, [c([0, 0]), c([props.width, props.height])]))}
|
||||||
</LayersControl>
|
</LayersControl>
|
||||||
</Map>
|
</Map>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLayer(layer, bounds) {
|
renderLayer(layer, bounds) {
|
||||||
const LayersControlType = layer.baseLayer ? LayersControl.BaseLayer : LayersControl.Overlay;
|
const LayersControlType =
|
||||||
|
layer.baseLayer ? LayersControl.BaseLayer : LayersControl.Overlay;
|
||||||
return (
|
return (
|
||||||
<LayersControlType name={layer.name}
|
<LayersControlType name={layer.name}
|
||||||
checked={layer.defaultVisibility == "visible"}>
|
checked={layer.defaultVisibility === "visible"}>
|
||||||
<ImageOverlay url={layer.image} bounds={bounds} opacity={layer.opacity} />
|
<ImageOverlay url={layer.image}
|
||||||
|
bounds={bounds}
|
||||||
|
opacity={layer.opacity} />
|
||||||
</LayersControlType>
|
</LayersControlType>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { Store } from "redux";
|
||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
import R from "ramda";
|
import R from "ramda";
|
||||||
|
|
||||||
export default function connectMqtt(url: string, store: Store<*,*>) {
|
export default function connectMqtt(url: string, store: Store<*, *>) {
|
||||||
const client = mqtt.connect(url);
|
const client = mqtt.connect(url);
|
||||||
client.on("connect", () => {
|
client.on("connect", () => {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
|
|
|
||||||
36
src/state.js
36
src/state.js
|
|
@ -15,22 +15,29 @@ const initState : State = {
|
||||||
mqtt: null,
|
mqtt: null,
|
||||||
uiOpened: null,
|
uiOpened: null,
|
||||||
values: R.map(
|
values: R.map(
|
||||||
topic => { return {
|
topic => {
|
||||||
|
return {
|
||||||
internal: keyOf(topic.values, topic.defaultValue),
|
internal: keyOf(topic.values, topic.defaultValue),
|
||||||
actual: topic.defaultValue
|
actual: topic.defaultValue
|
||||||
};}, Config.topics),
|
};
|
||||||
|
}, Config.topics),
|
||||||
visibleLayers: []
|
visibleLayers: []
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMessage = (state: State, action: StateAction) => {
|
const onMessage = (state: State, action: StateAction) => {
|
||||||
if (action.payload == undefined) return state;
|
if (action.payload == null) {
|
||||||
// action.payload.topic is the mqtt topic
|
return state;
|
||||||
// topics is the list of all internal topic references
|
}
|
||||||
// that have their state topic set to action.payload.topic
|
|
||||||
const payload = action.payload == undefined ? { topic: "", message: {} }
|
/*
|
||||||
|
* action.payload.topic is the mqtt topic
|
||||||
|
* topics is the list of all internal topic references
|
||||||
|
* that have their state topic set to action.payload.topic
|
||||||
|
*/
|
||||||
|
const payload = action.payload == null ? { topic: "", message: {} }
|
||||||
: action.payload; // thx flow </3
|
: action.payload; // thx flow </3
|
||||||
const topics = R.keys(R.pickBy(
|
const topics = R.keys(R.pickBy(
|
||||||
val => val.state == payload.topic, Config.topics));
|
val => val.state === payload.topic, Config.topics));
|
||||||
const message = payload.message;
|
const message = payload.message;
|
||||||
const parsedMessage = (topic: string) => {
|
const parsedMessage = (topic: string) => {
|
||||||
let parseFunction = Config.topics[topic].parseState;
|
let parseFunction = Config.topics[topic].parseState;
|
||||||
|
|
@ -43,7 +50,7 @@ const onMessage = (state: State, action: StateAction) => {
|
||||||
const newValue = (topic: string) => {
|
const newValue = (topic: string) => {
|
||||||
return {
|
return {
|
||||||
actual: parsedMessage(topic),
|
actual: parsedMessage(topic),
|
||||||
internal: keyOf(Config.topics[topic].values,parsedMessage(topic))
|
internal: keyOf(Config.topics[topic].values, parsedMessage(topic))
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return R.mergeDeepRight(state, R.objOf("values", R.mergeAll(
|
return R.mergeDeepRight(state, R.objOf("values", R.mergeAll(
|
||||||
|
|
@ -51,14 +58,15 @@ const onMessage = (state: State, action: StateAction) => {
|
||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
|
|
||||||
const match = (value: any, array: Map<any,any>) => array[value];
|
const match = (value: any, array: Map<any, any>) => array[value];
|
||||||
const handleEvent = (state: State = initState, action: StateAction) => {
|
const handleEvent = (state: State = initState, action: StateAction) => {
|
||||||
return match(action.type, {
|
return match(action.type, {
|
||||||
[Actions.MQTT_CONNECT ]: R.merge(state, { mqtt: action.payload }),
|
[Actions.MQTT_CONNECT]: R.merge(state, { mqtt: action.payload }),
|
||||||
[Actions.MQTT_MESSAGE ]: onMessage(state, action),
|
[Actions.MQTT_MESSAGE]: onMessage(state, action),
|
||||||
[Actions.CHANGE_UI ]: (() => {
|
[Actions.CHANGE_UI]: (() => {
|
||||||
const control = Config.controls[action.payload];
|
const control = Config.controls[action.payload];
|
||||||
if (action.toggle && control.ui.length > 0 && control.ui[0].type == "toggle") {
|
if (action.toggle && control.ui.length > 0
|
||||||
|
&& control.ui[0].type === "toggle") {
|
||||||
const props = control.ui[0];
|
const props = control.ui[0];
|
||||||
onSwitch(props.topic, props, state)(null, !isToggled(state, props));
|
onSwitch(props.topic, props, state)(null, !isToggled(state, props));
|
||||||
return state;
|
return state;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import R from "ramda";
|
import R from "ramda";
|
||||||
|
|
||||||
export const keyOf = <a,b> (map: Map<b,a>, value: a) : ?b =>
|
export const keyOf = <a, b> (map: Map<b, a>, value: a): ?b =>
|
||||||
((keys) => keys[R.findIndex(k => map[k] == value, keys)])(R.keys(map));
|
((keys) => keys[R.findIndex(k => map[k] === value, keys)])(R.keys(map));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue