[web] Add keys argument for dump_dict in optmanager.

This commit is contained in:
Matthew Shao 2017-07-05 08:40:21 +08:00
parent 2e6f56c4e7
commit aa01a62df7
5 changed files with 144 additions and 52 deletions

View File

@ -409,14 +409,15 @@ def dump_defaults(opts):
return ruamel.yaml.round_trip_dump(s) return ruamel.yaml.round_trip_dump(s)
def dump_dicts(opts): def dump_dicts(opts, keys: typing.List[str]=None):
""" """
Dumps the options into a list of dict object. Dumps the options into a list of dict object.
Return: A list like: { "anticache": { type: "bool", default: false, value: true, help: "help text"} } Return: A list like: { "anticache": { type: "bool", default: false, value: true, help: "help text"} }
""" """
options_dict = {} options_dict = {}
for k in sorted(opts.keys()): keys = keys if keys else opts.keys()
for k in sorted(keys):
o = opts._options[k] o = opts._options[k]
t = typecheck.typespec_to_str(o.typespec) t = typecheck.typespec_to_str(o.typespec)
option = { option = {

View File

@ -341,6 +341,7 @@ def test_dump_defaults():
def test_dump_dicts(): def test_dump_dicts():
o = options.Options() o = options.Options()
assert optmanager.dump_dicts(o) assert optmanager.dump_dicts(o)
assert optmanager.dump_dicts(o, ['http2', 'anticomp'])
class TTypes(optmanager.OptManager): class TTypes(optmanager.OptManager):

View File

@ -255,8 +255,8 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
def test_options(self): def test_options(self):
j = json(self.fetch("/options")) j = json(self.fetch("/options"))
assert type(j) == list assert type(j) == dict
assert type(j[0]) == dict assert type(j['anticache']) == dict
def test_option_update(self): def test_option_update(self):
assert self.put_json("/options", {"anticache": True}).code == 200 assert self.put_json("/options", {"anticache": True}).code == 200

View File

@ -0,0 +1,138 @@
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { update as updateOptions } from '../../ducks/options'
PureBooleanOption.PropTypes = {
value: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
}
function PureBooleanOption({ value, onChange, name, help}) {
return (
<div className="menu-entry">
<label>
<input type="checkbox"
checked={value}
onChange={onChange}
title={help}
/>
{ name }
</label>
</div>
)
}
PureStringOption.PropTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
}
function PureStringOption( { value, onChange, name, help }) {
let onKeyDown = (e) => {e.stopPropagation()}
return (
<div className="menu-entry">
<label>
{ name }
<input type="text"
value={value}
onChange={onChange}
title={help}
onKeyDown={onKeyDown}
/>
</label>
</div>
)
}
PureNumberOption.PropTypes = {
value: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired,
}
function PureNumberOption( {value, onChange, name, help }) {
let onKeyDown = (e) => {e.stopPropagation()}
return (
<div className="menu-entry">
<label>
{ name }
<input type="number"
value={value}
onChange={onChange}
title={help}
onKeyDown={onKeyDown}
/>
</label>
</div>
)
}
PureChoicesOption.PropTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
}
function PureChoicesOption( { value, onChange, name, help, choices }) {
return (
<div className="menu-entry">
<label htmlFor="">
{ name }
<select name={name} onChange={onChange} title={help} selected={value}>
{ choices.map(choice => (
<option value={choice}> {choice} </option>
))}
</select>
</label>
</div>
)
}
const OptionTypes = {
bool: PureBooleanOption,
str: PureStringOption,
int: PureNumberOption,
"optional str": PureStringOption,
"sequence of str": PureStringOption,
}
Wrapper.displayName = 'OptionWrapper'
function Wrapper({option, options, updateOptions, ...props}) {
let optionObj = options[option],
WrappedComponent = null
if (optionObj.choices) {
WrappedComponent = PureChoicesOption
} else {
WrappedComponent = OptionTypes[optionObj.type]
}
let onChange = (e) => {
switch (optionObj.type) {
case 'bool' :
updateOptions({[option]: !optionObj.value})
break
case 'int':
updateOptions({[option]: parseInt(e.target.value)})
break
default:
updateOptions({[option]: e.target.value})
}
}
return <WrappedComponent
children={props.children}
value={optionObj.value}
onChange={onChange}
name={option}
help={optionObj.help}
choices={optionObj.choices}
/>
}
export default connect(
state => ({
options: state.options,
}),
{
updateOptions,
}
)(Wrapper)

View File

@ -1,48 +0,0 @@
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { update as updateOptions } from '../../ducks/options'
MenuToggle.propTypes = {
value: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
children: PropTypes.node.isRequired,
}
export function MenuToggle({ value, onChange, children }) {
return (
<div className="menu-entry">
<label>
<input type="checkbox"
checked={value}
onChange={onChange}/>
{children}
</label>
</div>
)
}
OptionsToggle.propTypes = {
option: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
}
export function OptionsToggle({ option, children, options, updateOptions }) {
return (
<MenuToggle
value={ options[option].value }
onChange={() => {console.log(options[option]);
updateOptions({ [option]: !(options[option].value)}) }}
>
{children}
</MenuToggle>
)
}
OptionsToggle = connect(
state => ({
options: state.options,
}),
{
updateOptions,
}
)(OptionsToggle)