aboutsummaryrefslogtreecommitdiffstats
path: root/web/src
diff options
context:
space:
mode:
Diffstat (limited to 'web/src')
-rw-r--r--web/src/css/app.less1
-rw-r--r--web/src/css/modal.less10
-rw-r--r--web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.js.snap79
-rw-r--r--web/src/js/__tests__/ducks/tutils.js30
-rw-r--r--web/src/js/backends/websocket.js1
-rw-r--r--web/src/js/components/Modal/OptionMaster.jsx119
-rw-r--r--web/src/js/components/Modal/OptionModal.jsx27
-rw-r--r--web/src/js/ducks/index.js2
8 files changed, 263 insertions, 6 deletions
diff --git a/web/src/css/app.less b/web/src/css/app.less
index 353e412a..b9b5b310 100644
--- a/web/src/css/app.less
+++ b/web/src/css/app.less
@@ -19,3 +19,4 @@ html {
@import (less) "footer.less";
@import (less) "codemirror.less";
@import (less) "contentview.less";
+@import (less) "modal.less";
diff --git a/web/src/css/modal.less b/web/src/css/modal.less
index b08e309a..8d578f03 100644
--- a/web/src/css/modal.less
+++ b/web/src/css/modal.less
@@ -1,3 +1,13 @@
.modal-visible {
display: block;
}
+
+
+.modal-dialog {
+ overflow-y: initial !important;
+}
+
+.modal-body {
+ max-height: calc(100vh - 20px);
+ overflow-y: auto;
+}
diff --git a/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.js.snap b/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.js.snap
index 4fe163d1..af587ae4 100644
--- a/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.js.snap
+++ b/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.js.snap
@@ -46,7 +46,84 @@ exports[`Modal Component should render correctly 2`] = `
<div
className="modal-body"
>
- ...
+ <div
+ className="menu-entry"
+ >
+ <label>
+ booleanOption
+ <input
+ checked={false}
+ onChange={[Function]}
+ title="foo"
+ type="checkbox"
+ />
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label
+ htmlFor=""
+ >
+ choiceOption
+ <select
+ name="choiceOption"
+ onChange={[Function]}
+ selected="b"
+ title="foo"
+ >
+ <option
+ value="a"
+ >
+
+ a
+
+ </option>
+ <option
+ value="b"
+ >
+
+ b
+
+ </option>
+ <option
+ value="c"
+ >
+
+ c
+
+ </option>
+ </select>
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ intOption
+ <input
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ title="foo"
+ type="number"
+ value={1}
+ />
+ </label>
+ </div>
+ <div
+ className="menu-entry"
+ >
+ <label>
+ strOption
+ <input
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ title="foo"
+ type="text"
+ value="str content"
+ />
+ </label>
+ </div>
</div>
<div
className="modal-footer"
diff --git a/web/src/js/__tests__/ducks/tutils.js b/web/src/js/__tests__/ducks/tutils.js
index 9b92e676..a3e9c168 100644
--- a/web/src/js/__tests__/ducks/tutils.js
+++ b/web/src/js/__tests__/ducks/tutils.js
@@ -42,6 +42,36 @@ export function TStore(){
anticache: true,
anticomp: false
},
+ options: {
+ booleanOption: {
+ choices: null,
+ default: false,
+ help: "foo",
+ type: "bool",
+ value: false
+ },
+ strOption: {
+ choices: null,
+ default: null,
+ help: "foo",
+ type: "str",
+ value: "str content"
+ },
+ intOption: {
+ choices: null,
+ default: 0,
+ help: "foo",
+ type: "int",
+ value: 1
+ },
+ choiceOption: {
+ choices: ['a', 'b', 'c'],
+ default: 'a',
+ help: "foo",
+ type: "str",
+ value: "b"
+ },
+ },
flows: {
selected: ["d91165be-ca1f-4612-88a9-c0f8696f3e29"],
byId: {"d91165be-ca1f-4612-88a9-c0f8696f3e29": tflow},
diff --git a/web/src/js/backends/websocket.js b/web/src/js/backends/websocket.js
index 01094ac4..d7e13bb2 100644
--- a/web/src/js/backends/websocket.js
+++ b/web/src/js/backends/websocket.js
@@ -27,6 +27,7 @@ export default class WebsocketBackend {
this.fetchData("settings")
this.fetchData("flows")
this.fetchData("events")
+ this.fetchData("options")
this.store.dispatch(connectionActions.startFetching())
}
diff --git a/web/src/js/components/Modal/OptionMaster.jsx b/web/src/js/components/Modal/OptionMaster.jsx
new file mode 100644
index 00000000..c25dda72
--- /dev/null
+++ b/web/src/js/components/Modal/OptionMaster.jsx
@@ -0,0 +1,119 @@
+import PropTypes from 'prop-types'
+
+PureBooleanOption.PropTypes = {
+ value: PropTypes.bool.isRequired,
+ onChange: PropTypes.func.isRequired,
+}
+
+function PureBooleanOption({ value, onChange, name, help}) {
+ return (
+ <label>
+ { name }
+ <input type="checkbox"
+ checked={value}
+ onChange={onChange}
+ title={help}
+ />
+ </label>
+ )
+}
+
+PureStringOption.PropTypes = {
+ value: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+}
+
+function PureStringOption( { value, onChange, name, help }) {
+ let onKeyDown = (e) => {e.stopPropagation()}
+ return (
+ <label>
+ { name }
+ <input type="text"
+ value={value}
+ onChange={onChange}
+ title={help}
+ onKeyDown={onKeyDown}
+ />
+ </label>
+ )
+}
+
+PureNumberOption.PropTypes = {
+ value: PropTypes.number.isRequired,
+ onChange: PropTypes.func.isRequired,
+}
+
+function PureNumberOption( {value, onChange, name, help }) {
+ let onKeyDown = (e) => {e.stopPropagation()}
+ return (
+ <label>
+ { name }
+ <input type="number"
+ value={value}
+ onChange={onChange}
+ title={help}
+ onKeyDown={onKeyDown}
+ />
+ </label>
+ )
+}
+
+PureChoicesOption.PropTypes = {
+ value: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+}
+
+function PureChoicesOption( { value, onChange, name, help, choices }) {
+ return (
+ <label htmlFor="">
+ { name }
+ <select name={name} onChange={onChange} title={help} selected={value}>
+ { choices.map((choice, index) => (
+ <option key={index} value={choice}> {choice} </option>
+ ))}
+ </select>
+ </label>
+ )
+}
+
+const OptionTypes = {
+ bool: PureBooleanOption,
+ str: PureStringOption,
+ int: PureNumberOption,
+ "optional str": PureStringOption,
+ "sequence of str": PureStringOption,
+}
+
+export default function OptionMaster({option, name, updateOptions, ...props}) {
+ let WrappedComponent = null
+ if (option.choices) {
+ WrappedComponent = PureChoicesOption
+ } else {
+ WrappedComponent = OptionTypes[option.type]
+ }
+
+ let onChange = (e) => {
+ switch (option.type) {
+ case 'bool' :
+ updateOptions({[name]: !option.value})
+ break
+ case 'int':
+ updateOptions({[name]: parseInt(e.target.value)})
+ break
+ default:
+ updateOptions({[name]: e.target.value})
+ }
+ }
+ return (
+ <div className="menu-entry">
+ <WrappedComponent
+ children={props.children}
+ value={option.value}
+ onChange={onChange}
+ name={name}
+ help={option.help}
+ choices={option.choices}
+ />
+ </div>
+ )
+}
diff --git a/web/src/js/components/Modal/OptionModal.jsx b/web/src/js/components/Modal/OptionModal.jsx
index 500495c4..ef3a224a 100644
--- a/web/src/js/components/Modal/OptionModal.jsx
+++ b/web/src/js/components/Modal/OptionModal.jsx
@@ -1,16 +1,18 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import * as modalAction from '../../ducks/ui/modal'
+import { update as updateOptions } from '../../ducks/options'
+import Option from './OptionMaster'
class PureOptionModal extends Component {
constructor(props, context) {
super(props, context)
- this.state = { title: 'Options', }
+ this.state = { title: 'Options' }
}
render() {
- const { hideModal } = this.props
+ const { hideModal, options } = this.props
const { title } = this.state
return (
<div>
@@ -26,7 +28,19 @@ class PureOptionModal extends Component {
</div>
<div className="modal-body">
- ...
+ {
+ Object.keys(options).sort()
+ .map((key, index) => {
+ let option = options[key];
+ return (
+ <Option
+ key={index}
+ name={key}
+ updateOptions={updateOptions}
+ option={option}
+ />)
+ })
+ }
</div>
<div className="modal-footer">
@@ -39,7 +53,10 @@ class PureOptionModal extends Component {
export default connect(
state => ({
-
+ options: state.options
}),
- { hideModal: modalAction.hideModal }
+ {
+ hideModal: modalAction.hideModal,
+ updateOptions: updateOptions,
+ }
)(PureOptionModal)
diff --git a/web/src/js/ducks/index.js b/web/src/js/ducks/index.js
index 0f2426ec..be2f2885 100644
--- a/web/src/js/ducks/index.js
+++ b/web/src/js/ducks/index.js
@@ -4,6 +4,7 @@ import flows from "./flows"
import settings from "./settings"
import ui from "./ui/index"
import connection from "./connection"
+import options from './options'
export default combineReducers({
eventLog,
@@ -11,4 +12,5 @@ export default combineReducers({
settings,
connection,
ui,
+ options,
})