[web] style options menu

The other menus are WIP.
This commit is contained in:
Maximilian Hils 2016-12-11 17:37:11 +01:00
parent b92980efec
commit 795e76eee2
10 changed files with 203 additions and 133 deletions

View File

@ -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 {

View File

@ -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>
}

View File

@ -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>
)
}

View File

@ -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>
)
}

View File

@ -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>
)
}

View File

@ -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)

View File

@ -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="clearfix"/>
<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="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)

View File

@ -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)

View File

@ -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>
)
}

View File

@ -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,
}
}