diff options
-rw-r--r-- | web/src/css/header.less | 58 | ||||
-rw-r--r-- | web/src/js/components/FlowView/ToggleEdit.jsx | 4 | ||||
-rw-r--r-- | web/src/js/components/Header.jsx | 7 | ||||
-rw-r--r-- | web/src/js/components/Header/FlowMenu.jsx | 15 | ||||
-rw-r--r-- | web/src/js/components/Header/MainMenu.jsx | 21 | ||||
-rw-r--r-- | web/src/js/components/Header/MenuToggle.jsx | 69 | ||||
-rw-r--r-- | web/src/js/components/Header/OptionMenu.jsx | 112 | ||||
-rw-r--r-- | web/src/js/components/Header/ViewMenu.jsx | 32 | ||||
-rw-r--r-- | web/src/js/components/common/DocsLink.jsx | 14 | ||||
-rw-r--r-- | web/src/js/ducks/ui/header.js | 4 |
10 files changed, 203 insertions, 133 deletions
diff --git a/web/src/css/header.less b/web/src/css/header.less index 4813b933..90907ec7 100644 --- a/web/src/css/header.less +++ b/web/src/css/header.less @@ -1,24 +1,66 @@ @import (reference) '../../node_modules/bootstrap/less/variables.less'; @import (reference) '../../node_modules/bootstrap/less/mixins/grid.less'; +@menu-height: 85px; + + header { - padding-top: 0.5em; + padding-top: 6px; background-color: white; @separator-color: lighten(grey, 15%); - .menu { - padding: 10px; + menu { + display: block; + margin: 0; + padding: 0; border-bottom: solid @separator-color 1px; + height: @menu-height; + overflow: visible; // search help context laps over. } } -@menu-row-gutter-width: 5px; -.menu-row { - .make-row(@menu-row-gutter-width); +.menu-group { + @description-height: 16px; + display: inline-block; + height: @menu-height; + vertical-align: top; + + .entry { + height: (@menu-height - @description-height)/3; + line-height: 1; + padding: 0.5rem 1rem; + + label { + font-size: 1.2rem; + font-weight: normal; + margin: 0; + } + input[type=checkbox] { + margin: 0 2px; + vertical-align: middle; + } + } + .description { + height: @description-height; + text-align: center; + font-size: 0.9rem; + } +} +.menu-group + .menu-group:before { + @space: 10px; + content: " "; + border-left: solid 1px lighten(grey, 40%); + margin-top: @space; + height: @menu-height - @space*2; + position: absolute; +} + +@menu-main-gutter-width: 5px; +.menu-main { + .make-row(@menu-main-gutter-width); } .filter-input { - .make-sm-column(3, @menu-row-gutter-width); - margin-bottom:5px; + .make-sm-column(4, @menu-main-gutter-width); } .filter-input .popover { diff --git a/web/src/js/components/FlowView/ToggleEdit.jsx b/web/src/js/components/FlowView/ToggleEdit.jsx index 9016348e..6a691a3d 100644 --- a/web/src/js/components/FlowView/ToggleEdit.jsx +++ b/web/src/js/components/FlowView/ToggleEdit.jsx @@ -14,11 +14,11 @@ function ToggleEdit({ isEdit, startEdit, stopEdit, flow, modifiedFlow }) { return ( <div className="edit-flow-container"> {isEdit ? - <a className="edit-flow" onClick={() => stopEdit(flow, modifiedFlow)}> + <a className="edit-flow" title="Finish Edit" onClick={() => stopEdit(flow, modifiedFlow)}> <i className="fa fa-check"/> </a> : - <a className="edit-flow" onClick={() => startEdit(flow)}> + <a className="edit-flow" title="Edit Flow" onClick={() => startEdit(flow)}> <i className="fa fa-pencil"/> </a> } diff --git a/web/src/js/components/Header.jsx b/web/src/js/components/Header.jsx index 702786e6..1500db1b 100644 --- a/web/src/js/components/Header.jsx +++ b/web/src/js/components/Header.jsx @@ -2,14 +2,13 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import classnames from 'classnames' import MainMenu from './Header/MainMenu' -import ViewMenu from './Header/ViewMenu' import OptionMenu from './Header/OptionMenu' import FileMenu from './Header/FileMenu' import FlowMenu from './Header/FlowMenu' import {setActiveMenu} from '../ducks/ui/header' class Header extends Component { - static entries = [MainMenu, ViewMenu, OptionMenu] + static entries = [MainMenu, OptionMenu] handleClick(active, e) { e.preventDefault() @@ -38,9 +37,9 @@ class Header extends Component { </a> ))} </nav> - <div className="menu"> + <menu> <Active/> - </div> + </menu> </header> ) } diff --git a/web/src/js/components/Header/FlowMenu.jsx b/web/src/js/components/Header/FlowMenu.jsx index e78a49aa..e0c59afe 100644 --- a/web/src/js/components/Header/FlowMenu.jsx +++ b/web/src/js/components/Header/FlowMenu.jsx @@ -18,15 +18,12 @@ FlowMenu.propTypes = { function FlowMenu({ flow, acceptFlow, replayFlow, duplicateFlow, removeFlow, revertFlow }) { return ( <div> - <div className="menu-row"> - <Button disabled={!flow || !flow.intercepted} title="[a]ccept intercepted flow" text="Accept" icon="fa-play" onClick={() => acceptFlow(flow)} /> - <Button title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={() => replayFlow(flow)} /> - <Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={() => duplicateFlow(flow)} /> - <Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={() => removeFlow(flow)}/> - <Button disabled={!flow || !flow.modified} title="revert changes to flow [V]" text="Revert" icon="fa-history" onClick={() => revertFlow(flow)} /> - <Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/> - </div> - <div className="clearfix"/> + <Button disabled={!flow || !flow.intercepted} title="[a]ccept intercepted flow" text="Accept" icon="fa-play" onClick={() => acceptFlow(flow)} /> + <Button title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={() => replayFlow(flow)} /> + <Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={() => duplicateFlow(flow)} /> + <Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={() => removeFlow(flow)}/> + <Button disabled={!flow || !flow.modified} title="revert changes to flow [V]" text="Revert" icon="fa-history" onClick={() => revertFlow(flow)} /> + <Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/> </div> ) } diff --git a/web/src/js/components/Header/MainMenu.jsx b/web/src/js/components/Header/MainMenu.jsx index 5ab3fa9d..6a4e12bf 100644 --- a/web/src/js/components/Header/MainMenu.jsx +++ b/web/src/js/components/Header/MainMenu.jsx @@ -1,20 +1,17 @@ -import React, { Component, PropTypes } from 'react' -import { connect } from 'react-redux' -import FilterInput from './FilterInput' -import { update as updateSettings } from '../../ducks/settings' -import { setFilter, setHighlight } from '../../ducks/flows' +import React, { Component, PropTypes } from "react" +import { connect } from "react-redux" +import FilterInput from "./FilterInput" +import { update as updateSettings } from "../../ducks/settings" +import { setFilter, setHighlight } from "../../ducks/flows" MainMenu.title = "Start" export default function MainMenu() { return ( - <div> - <div className="menu-row"> - <FlowFilterInput/> - <HighlightInput/> - <InterceptInput/> - </div> - <div className="clearfix"></div> + <div className="menu-main"> + <FlowFilterInput/> + <HighlightInput/> + <InterceptInput/> </div> ) } diff --git a/web/src/js/components/Header/MenuToggle.jsx b/web/src/js/components/Header/MenuToggle.jsx new file mode 100644 index 00000000..726db7bd --- /dev/null +++ b/web/src/js/components/Header/MenuToggle.jsx @@ -0,0 +1,69 @@ +import { PropTypes } from "react" +import { connect } from "react-redux" +import { update as updateSettings } from "../../ducks/settings" +import { toggleVisibility } from "../../ducks/eventLog" + +MenuToggle.propTypes = { + value: PropTypes.bool.isRequired, + onChange: PropTypes.func.isRequired, + children: PropTypes.node.isRequired, +} + +export function MenuToggle({ value, onChange, children }) { + return ( + <div className="entry"> + <label> + <input type="checkbox" + value={value} + onChange={onChange}/> + {children} + </label> + </div> + ) +} + + +SettingsToggle.propTypes = { + setting: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, +} + +export function SettingsToggle({ setting, children, settings, updateSettings }) { + return ( + <MenuToggle + value={settings[setting] || false} // we don't have settings initially, so just pass false. + onChange={() => updateSettings({ [setting]: !settings[setting] })} + > + {children} + </MenuToggle> + ) +} +SettingsToggle = connect( + state => ({ + settings: state.settings, + }), + { + updateSettings, + } +)(SettingsToggle) + + +export function EventlogToggle({ toggleVisibility, eventLogVisible }) { + return ( + <MenuToggle + value={eventLogVisible} + onChange={toggleVisibility} + > + Display Event Log + </MenuToggle> + ) +} +EventlogToggle = connect( + state => ({ + eventLogVisible: state.eventLog.visible, + }), + { + toggleVisibility, + } +)(EventlogToggle) + diff --git a/web/src/js/components/Header/OptionMenu.jsx b/web/src/js/components/Header/OptionMenu.jsx index f1d19f48..4fb5dc1f 100644 --- a/web/src/js/components/Header/OptionMenu.jsx +++ b/web/src/js/components/Header/OptionMenu.jsx @@ -1,75 +1,59 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' -import ToggleButton from '../common/ToggleButton' -import ToggleInputButton from '../common/ToggleInputButton' -import { update as updateSettings } from '../../ducks/settings' +import {SettingsToggle, EventlogToggle} from './MenuToggle' +import DocsLink from '../common/DocsLink' OptionMenu.title = 'Options' -OptionMenu.propTypes = { - settings: PropTypes.object.isRequired, - updateSettings: PropTypes.func.isRequired, -} - -function OptionMenu({ settings, updateSettings }) { +export default function OptionMenu() { return ( <div> - <div className="menu-row"> - <ToggleButton text="showhost" - checked={settings.showhost} - onToggle={() => updateSettings({ showhost: !settings.showhost })} - /> - <ToggleButton text="no_upstream_cert" - checked={settings.no_upstream_cert} - onToggle={() => updateSettings({ no_upstream_cert: !settings.no_upstream_cert })} - /> - <ToggleButton text="rawtcp" - checked={settings.rawtcp} - onToggle={() => updateSettings({ rawtcp: !settings.rawtcp })} - /> - <ToggleButton text="http2" - checked={settings.http2} - onToggle={() => updateSettings({ http2: !settings.http2 })} - /> - <ToggleButton text="websocket" - checked={settings.websocket} - onToggle={() => updateSettings({ websocket: !settings.websocket })} - /> - <ToggleButton text="anticache" - checked={settings.anticache} - onToggle={() => updateSettings({ anticache: !settings.anticache })} - /> - <ToggleButton text="anticomp" - checked={settings.anticomp} - onToggle={() => updateSettings({ anticomp: !settings.anticomp })} - /> - <ToggleInputButton name="stickyauth" placeholder="Sticky auth filter" - checked={!!settings.stickyauth} - txt={settings.stickyauth} - onToggleChanged={txt => updateSettings({ stickyauth: !settings.stickyauth ? txt : null })} - /> - <ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter" - checked={!!settings.stickycookie} - txt={settings.stickycookie} - onToggleChanged={txt => updateSettings({ stickycookie: !settings.stickycookie ? txt : null })} - /> - <ToggleInputButton name="stream_large_bodies" placeholder="stream..." - checked={!!settings.stream_large_bodies} - txt={settings.stream_large_bodies} - inputType="number" - onToggleChanged={txt => updateSettings({ stream_large_bodies: !settings.stream_large_bodies ? txt : null })} - /> + <div className="menu-group"> + <SettingsToggle setting="http2">HTTP/2.0</SettingsToggle> + <SettingsToggle setting="websocket">WebSockets</SettingsToggle> + <SettingsToggle setting="rawtcp">Raw TCP</SettingsToggle> + <div className="description">Protocol Support</div> + </div> + <div className="menu-group"> + <SettingsToggle setting="anticache"> + Disable Caching <DocsLink resource="features/anticache.html"/> + </SettingsToggle> + <SettingsToggle setting="anticomp"> + Disable Compression <i className="fa fa-question-circle" title="Do not forward Accept-Encoding headers to the server to force an uncompressed response."></i> + </SettingsToggle> + <div className="entry"/> + <div className="description">HTTP Options</div> </div> - <div className="clearfix"/> + <div className="menu-group"> + <SettingsToggle setting="showhost"> + Use Host Header <i className="fa fa-question-circle" title="Use the Host header to construct URLs for display."></i> + </SettingsToggle> + <EventlogToggle/> + <div className="entry"/> + <div className="description">View Options</div> + </div> + { /* + <ToggleButton text="no_upstream_cert" + checked={settings.no_upstream_cert} + onToggle={() => updateSettings({ no_upstream_cert: !settings.no_upstream_cert })} + /> + <ToggleInputButton name="stickyauth" placeholder="Sticky auth filter" + checked={!!settings.stickyauth} + txt={settings.stickyauth} + onToggleChanged={txt => updateSettings({ stickyauth: !settings.stickyauth ? txt : null })} + /> + <ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter" + checked={!!settings.stickycookie} + txt={settings.stickycookie} + onToggleChanged={txt => updateSettings({ stickycookie: !settings.stickycookie ? txt : null })} + /> + <ToggleInputButton name="stream_large_bodies" placeholder="stream..." + checked={!!settings.stream_large_bodies} + txt={settings.stream_large_bodies} + inputType="number" + onToggleChanged={txt => updateSettings({ stream_large_bodies: !settings.stream_large_bodies ? txt : null })} + /> + */} </div> ) } - -export default connect( - state => ({ - settings: state.settings, - }), - { - updateSettings, - } -)(OptionMenu) diff --git a/web/src/js/components/Header/ViewMenu.jsx b/web/src/js/components/Header/ViewMenu.jsx deleted file mode 100644 index 22b370d1..00000000 --- a/web/src/js/components/Header/ViewMenu.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { PropTypes } from 'react' -import { connect } from 'react-redux' -import ToggleButton from '../common/ToggleButton' -import { toggleVisibility } from '../../ducks/eventLog' - -ViewMenu.title = 'View' -ViewMenu.route = 'flows' - -ViewMenu.propTypes = { - eventLogVisible: PropTypes.bool.isRequired, - toggleEventLog: PropTypes.func.isRequired, -} - -function ViewMenu({ eventLogVisible, toggleEventLog }) { - return ( - <div> - <div className="menu-row"> - <ToggleButton text="Show Event Log" checked={eventLogVisible} onToggle={toggleEventLog} /> - </div> - <div className="clearfix"></div> - </div> - ) -} - -export default connect( - state => ({ - eventLogVisible: state.eventLog.visible, - }), - { - toggleEventLog: toggleVisibility, - } -)(ViewMenu) diff --git a/web/src/js/components/common/DocsLink.jsx b/web/src/js/components/common/DocsLink.jsx new file mode 100644 index 00000000..182811a3 --- /dev/null +++ b/web/src/js/components/common/DocsLink.jsx @@ -0,0 +1,14 @@ +import { PropTypes } from 'react' + +DocsLink.propTypes = { + resource: PropTypes.string.isRequired, +} + +export default function DocsLink({ children, resource }) { + let url = `http://docs.mitmproxy.org/en/stable/${resource}` + return ( + <a target="_blank" href={url}> + {children || <i className="fa fa-question-circle"></i>} + </a> + ) +} diff --git a/web/src/js/ducks/ui/header.js b/web/src/js/ducks/ui/header.js index 25dfe602..1eff3ef6 100644 --- a/web/src/js/ducks/ui/header.js +++ b/web/src/js/ducks/ui/header.js @@ -4,7 +4,7 @@ export const SET_ACTIVE_MENU = 'UI_SET_ACTIVE_MENU' const defaultState = { - activeMenu: 'Start', + activeMenu: 'Options', isFlowSelected: false, } @@ -22,7 +22,7 @@ export default function reducer(state = defaultState, action) { if (action.flowIds.length && !state.isFlowSelected) { return { ...state, - activeMenu: 'Flow', + activeMenu: 'Options', isFlowSelected: true, } } |