mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-22 07:08:10 +00:00
[web] style options menu
The other menus are WIP.
This commit is contained in:
parent
b92980efec
commit
795e76eee2
@ -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 {
|
||||
|
@ -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>
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
69
web/src/js/components/Header/MenuToggle.jsx
Normal file
69
web/src/js/components/Header/MenuToggle.jsx
Normal 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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
14
web/src/js/components/common/DocsLink.jsx
Normal file
14
web/src/js/components/common/DocsLink.jsx
Normal 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>
|
||||
)
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user