diff options
author | Matthew Shao <me@matshao.com> | 2017-07-05 08:40:21 +0800 |
---|---|---|
committer | Matthew Shao <me@matshao.com> | 2017-07-05 08:40:21 +0800 |
commit | aa01a62df7ce015ba4bf3c5ba9f3074616530496 (patch) | |
tree | 4e5a54ecde0e9a354d40c654fd3d2a5bcc9cdb45 | |
parent | 2e6f56c4e7de1d375eb91e188c3697383b31638f (diff) | |
download | mitmproxy-aa01a62df7ce015ba4bf3c5ba9f3074616530496.tar.gz mitmproxy-aa01a62df7ce015ba4bf3c5ba9f3074616530496.tar.bz2 mitmproxy-aa01a62df7ce015ba4bf3c5ba9f3074616530496.zip |
[web] Add keys argument for dump_dict in optmanager.
-rw-r--r-- | mitmproxy/optmanager.py | 5 | ||||
-rw-r--r-- | test/mitmproxy/test_optmanager.py | 1 | ||||
-rw-r--r-- | test/mitmproxy/tools/web/test_app.py | 4 | ||||
-rw-r--r-- | web/src/js/components/Modal/OptionMaster.jsx | 138 | ||||
-rw-r--r-- | web/src/js/components/Modal/OptionTypes.jsx | 48 |
5 files changed, 144 insertions, 52 deletions
diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py index 5692d751..e1d74b8e 100644 --- a/mitmproxy/optmanager.py +++ b/mitmproxy/optmanager.py @@ -409,14 +409,15 @@ def dump_defaults(opts): 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. Return: A list like: { "anticache": { type: "bool", default: false, value: true, help: "help text"} } """ options_dict = {} - for k in sorted(opts.keys()): + keys = keys if keys else opts.keys() + for k in sorted(keys): o = opts._options[k] t = typecheck.typespec_to_str(o.typespec) option = { diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py index 0c400683..7b4ffb8b 100644 --- a/test/mitmproxy/test_optmanager.py +++ b/test/mitmproxy/test_optmanager.py @@ -341,6 +341,7 @@ def test_dump_defaults(): def test_dump_dicts(): o = options.Options() assert optmanager.dump_dicts(o) + assert optmanager.dump_dicts(o, ['http2', 'anticomp']) class TTypes(optmanager.OptManager): diff --git a/test/mitmproxy/tools/web/test_app.py b/test/mitmproxy/tools/web/test_app.py index e6d563e7..044b4595 100644 --- a/test/mitmproxy/tools/web/test_app.py +++ b/test/mitmproxy/tools/web/test_app.py @@ -255,8 +255,8 @@ class TestApp(tornado.testing.AsyncHTTPTestCase): def test_options(self): j = json(self.fetch("/options")) - assert type(j) == list - assert type(j[0]) == dict + assert type(j) == dict + assert type(j['anticache']) == dict def test_option_update(self): assert self.put_json("/options", {"anticache": True}).code == 200 diff --git a/web/src/js/components/Modal/OptionMaster.jsx b/web/src/js/components/Modal/OptionMaster.jsx new file mode 100644 index 00000000..e16319fb --- /dev/null +++ b/web/src/js/components/Modal/OptionMaster.jsx @@ -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) diff --git a/web/src/js/components/Modal/OptionTypes.jsx b/web/src/js/components/Modal/OptionTypes.jsx deleted file mode 100644 index 8a9325e1..00000000 --- a/web/src/js/components/Modal/OptionTypes.jsx +++ /dev/null @@ -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) |