diff options
author | Jason <jason.daurus@gmail.com> | 2016-06-22 00:49:21 +0800 |
---|---|---|
committer | Jason <jason.daurus@gmail.com> | 2016-06-22 00:49:21 +0800 |
commit | 0cab9ef1fae927f9ef365526262bef32bd1b526b (patch) | |
tree | e3d64264e0239f21e71b1c2132443001fdadd363 /web/src | |
parent | 9cb5b0af9db83d84af0bdb45d56a9755b400c212 (diff) | |
parent | 4576dbf8aac8996f7f87320aba3132b657b02278 (diff) | |
download | mitmproxy-0cab9ef1fae927f9ef365526262bef32bd1b526b.tar.gz mitmproxy-0cab9ef1fae927f9ef365526262bef32bd1b526b.tar.bz2 mitmproxy-0cab9ef1fae927f9ef365526262bef32bd1b526b.zip |
Merge remote-tracking branch 'origin/master' into websocket
Conflicts:
mitmproxy/web/static/app.js
web/src/js/components/ProxyApp.jsx
Diffstat (limited to 'web/src')
-rw-r--r-- | web/src/js/__tests__/ducks/ui.js | 35 | ||||
-rw-r--r-- | web/src/js/__tests__/utils.js | 8 | ||||
-rw-r--r-- | web/src/js/actions.js | 23 | ||||
-rw-r--r-- | web/src/js/components/Footer.jsx | 9 | ||||
-rw-r--r-- | web/src/js/components/Header.jsx | 9 | ||||
-rw-r--r-- | web/src/js/components/Header/FlowMenu.jsx | 10 | ||||
-rw-r--r-- | web/src/js/components/Header/MainMenu.jsx | 39 | ||||
-rw-r--r-- | web/src/js/components/Header/OptionMenu.jsx | 33 | ||||
-rw-r--r-- | web/src/js/components/ProxyApp.jsx | 6 | ||||
-rw-r--r-- | web/src/js/components/common/Button.jsx | 6 | ||||
-rw-r--r-- | web/src/js/ducks/settings.js | 20 | ||||
-rw-r--r-- | web/src/js/ducks/ui.js | 4 |
12 files changed, 116 insertions, 86 deletions
diff --git a/web/src/js/__tests__/ducks/ui.js b/web/src/js/__tests__/ducks/ui.js new file mode 100644 index 00000000..81ae852c --- /dev/null +++ b/web/src/js/__tests__/ducks/ui.js @@ -0,0 +1,35 @@ +jest.unmock("../../ducks/ui"); +jest.unmock("../../ducks/flows"); + +import reducer, {setActiveMenu} from '../../ducks/ui'; +import {SELECT_FLOW} from '../../ducks/flows'; + +describe("ui reducer", () => { + it("should return the initial state", () => { + expect(reducer(undefined, {})).toEqual({ activeMenu: 'Start'}) + }), + it("should return the state for view", () => { + expect(reducer(undefined, setActiveMenu('View'))).toEqual({ activeMenu: 'View'}) + }), + it("should change the state to Start when deselecting a flow and we a currently at the flow tab", () => { + expect(reducer({activeMenu: 'Flow'}, + { type: SELECT_FLOW, + currentSelection: '1', + flowId : undefined + })).toEqual({ activeMenu: 'Start'}) + }), + it("should change the state to Flow when we selected a flow and no flow was selected before", () => { + expect(reducer({activeMenu: 'Start'}, + { type: SELECT_FLOW, + currentSelection: undefined, + flowId : '1' + })).toEqual({ activeMenu: 'Flow'}) + }), + it("should not change the state to Flow when OPTIONS tab is selected and we selected a flow and a flow as selected before", () => { + expect(reducer({activeMenu: 'Options'}, + { type: SELECT_FLOW, + currentSelection: '1', + flowId : '2' + })).toEqual({ activeMenu: 'Options'}) + }) +}); diff --git a/web/src/js/__tests__/utils.js b/web/src/js/__tests__/utils.js index eda740a1..b216d7d4 100644 --- a/web/src/js/__tests__/utils.js +++ b/web/src/js/__tests__/utils.js @@ -1,9 +1,9 @@ -jest.unmock("../utils.js"); +jest.unmock("../utils"); -import {formatSize} from "../utils.js" +import {formatSize} from "../utils" -describe("utils", function () { - it("formatSize", function(){ +describe("utils", () => { + it("formatSize", () => { expect(formatSize(1024)).toEqual("1kb"); expect(formatSize(0)).toEqual("0"); expect(formatSize(10)).toEqual("10b"); diff --git a/web/src/js/actions.js b/web/src/js/actions.js index 588245ae..bb1d0dd6 100644 --- a/web/src/js/actions.js +++ b/web/src/js/actions.js @@ -39,27 +39,6 @@ export var ConnectionActions = { } }; -export var SettingsActions = { - update: function (settings) { - - $.ajax({ - type: "PUT", - url: "/settings", - contentType: 'application/json', - data: JSON.stringify(settings) - }); - - /* - //Facebook Flux: We do an optimistic update on the client already. - AppDispatcher.dispatchViewAction({ - type: ActionTypes.SETTINGS_STORE, - cmd: StoreCmds.UPDATE, - data: settings - }); - */ - } -}; - export var FlowActions = { accept: function (flow) { $.post("/flows/" + flow.id + "/accept"); @@ -119,4 +98,4 @@ export var Query = { SEARCH: "s", HIGHLIGHT: "h", SHOW_EVENTLOG: "e" -};
\ No newline at end of file +}; diff --git a/web/src/js/components/Footer.jsx b/web/src/js/components/Footer.jsx index 1f6de2d7..82d6d8a1 100644 --- a/web/src/js/components/Footer.jsx +++ b/web/src/js/components/Footer.jsx @@ -1,11 +1,12 @@ import React from 'react' +import { connect } from 'react-redux' import { formatSize } from '../utils.js' Footer.propTypes = { settings: React.PropTypes.object.isRequired, } -export default function Footer({ settings }) { +function Footer({ settings }) { return ( <footer> {settings.mode && settings.mode != "regular" && ( @@ -44,3 +45,9 @@ export default function Footer({ settings }) { </footer> ) } + +export default connect( + state => ({ + settings: state.settings.settings, + }) +)(Footer) diff --git a/web/src/js/components/Header.jsx b/web/src/js/components/Header.jsx index 93ca5154..ab25eb41 100644 --- a/web/src/js/components/Header.jsx +++ b/web/src/js/components/Header.jsx @@ -12,10 +12,6 @@ import {setActiveMenu} from '../ducks/ui.js' class Header extends Component { static entries = [MainMenu, ViewMenu, OptionMenu] - static propTypes = { - settings: PropTypes.object.isRequired, - } - handleClick(active, e) { e.preventDefault() this.props.setActiveMenu(active.title) @@ -24,7 +20,7 @@ class Header extends Component { } render() { - const { settings, updateLocation, query, selectedFlow, activeMenu} = this.props + const { updateLocation, query, selectedFlow, activeMenu} = this.props let entries = [...Header.entries] if(selectedFlow) @@ -47,10 +43,9 @@ class Header extends Component { </nav> <div className="menu"> <Active - settings={settings} updateLocation={updateLocation} query={query} - /> + /> </div> </header> ) diff --git a/web/src/js/components/Header/FlowMenu.jsx b/web/src/js/components/Header/FlowMenu.jsx index 96f42652..abecf0dc 100644 --- a/web/src/js/components/Header/FlowMenu.jsx +++ b/web/src/js/components/Header/FlowMenu.jsx @@ -15,10 +15,12 @@ function FlowMenu({ flow }) { return ( <div> <div className="menu-row"> - <Button disabled title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={FlowActions.replay.bind(null, flow)} /> - <Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={FlowActions.duplicate.bind(null, flow)} /> - <Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={FlowActions.delete.bind(null, flow)}/> - <Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/> + <Button disabled={!flow.intercepted} title="[a]ccept intercepted flow" text="Accept" icon="fa-play" onClick={() => FlowActions.accept(flow)} /> + <Button title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={FlowActions.replay.bind(null, flow)} /> + <Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={FlowActions.duplicate.bind(null, flow)} /> + <Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={FlowActions.delete.bind(null, flow)}/> + <Button disabled={!flow.modified} title="revert changes to flow [V]" text="Revert" icon="fa-history" onClick={() => FlowActions.revert(flow)} /> + <Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/> </div> <div className="clearfix"/> </div> diff --git a/web/src/js/components/Header/MainMenu.jsx b/web/src/js/components/Header/MainMenu.jsx index 7b0b542c..a466a980 100644 --- a/web/src/js/components/Header/MainMenu.jsx +++ b/web/src/js/components/Header/MainMenu.jsx @@ -1,8 +1,8 @@ import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' import FilterInput from './FilterInput' import { Query } from '../../actions.js' -import {setInterceptPattern} from "../../ducks/settings" -import { connect } from 'react-redux' +import { updateSettings } from '../../ducks/settings' class MainMenu extends Component { @@ -10,14 +10,16 @@ class MainMenu extends Component { static route = 'flows' static propTypes = { - settings: React.PropTypes.object.isRequired, + query: PropTypes.object.isRequired, + settings: PropTypes.object.isRequired, + updateLocation: PropTypes.func.isRequired, + onSettingsChange: PropTypes.func.isRequired, } constructor(props, context) { super(props, context) this.onSearchChange = this.onSearchChange.bind(this) this.onHighlightChange = this.onHighlightChange.bind(this) - this.onInterceptChange = this.onInterceptChange.bind(this) } onSearchChange(val) { @@ -28,16 +30,8 @@ class MainMenu extends Component { this.props.updateLocation(undefined, { [Query.HIGHLIGHT]: val }) } - onInterceptChange(val) { - this.props.setInterceptPattern(val); - } - render() { - const { query, settings } = this.props - - const search = query[Query.SEARCH] || '' - const highlight = query[Query.HIGHLIGHT] || '' - const intercept = settings.intercept || '' + const { query, settings, onSettingsChange } = this.props return ( <div> @@ -47,7 +41,7 @@ class MainMenu extends Component { placeholder="Search" type="search" color="black" - value={search} + value={query[Query.SEARCH] || ''} onChange={this.onSearchChange} /> <FilterInput @@ -55,7 +49,7 @@ class MainMenu extends Component { placeholder="Highlight" type="tag" color="hsl(48, 100%, 50%)" - value={highlight} + value={query[Query.HIGHLIGHT] || ''} onChange={this.onHighlightChange} /> <FilterInput @@ -63,8 +57,8 @@ class MainMenu extends Component { placeholder="Intercept" type="pause" color="hsl(208, 56%, 53%)" - value={intercept} - onChange={this.onInterceptChange} + value={settings.intercept || ''} + onChange={intercept => onSettingsChange({ intercept })} /> </div> <div className="clearfix"></div> @@ -73,6 +67,11 @@ class MainMenu extends Component { } } -export default connect(undefined, { - setInterceptPattern -})(MainMenu); +export default connect( + state => ({ + settings: state.settings.settings, + }), + { + onSettingsChange: updateSettings, + } +)(MainMenu); diff --git a/web/src/js/components/Header/OptionMenu.jsx b/web/src/js/components/Header/OptionMenu.jsx index 44f309fd..f871ec92 100644 --- a/web/src/js/components/Header/OptionMenu.jsx +++ b/web/src/js/components/Header/OptionMenu.jsx @@ -1,61 +1,72 @@ import React, { PropTypes } from 'react' +import { connect } from 'react-redux' import ToggleButton from '../common/ToggleButton' import ToggleInputButton from '../common/ToggleInputButton' -import { SettingsActions } from '../../actions.js' +import { updateSettings } from '../../ducks/settings' OptionMenu.title = 'Options' OptionMenu.propTypes = { settings: PropTypes.object.isRequired, + onSettingsChange: PropTypes.func.isRequired, } -export default function OptionMenu({ settings }) { +function OptionMenu({ settings, onSettingsChange }) { // @todo use settings.map return ( <div> <div className="menu-row"> <ToggleButton text="showhost" checked={settings.showhost} - onToggle={() => SettingsActions.update({ showhost: !settings.showhost })} + onToggle={() => onSettingsChange({ showhost: !settings.showhost })} /> <ToggleButton text="no_upstream_cert" checked={settings.no_upstream_cert} - onToggle={() => SettingsActions.update({ no_upstream_cert: !settings.no_upstream_cert })} + onToggle={() => onSettingsChange({ no_upstream_cert: !settings.no_upstream_cert })} /> <ToggleButton text="rawtcp" checked={settings.rawtcp} - onToggle={() => SettingsActions.update({ rawtcp: !settings.rawtcp })} + onToggle={() => onSettingsChange({ rawtcp: !settings.rawtcp })} /> <ToggleButton text="http2" checked={settings.http2} - onToggle={() => SettingsActions.update({ http2: !settings.http2 })} + onToggle={() => onSettingsChange({ http2: !settings.http2 })} /> <ToggleButton text="anticache" checked={settings.anticache} - onToggle={() => SettingsActions.update({ anticache: !settings.anticache })} + onToggle={() => onSettingsChange({ anticache: !settings.anticache })} /> <ToggleButton text="anticomp" checked={settings.anticomp} - onToggle={() => SettingsActions.update({ anticomp: !settings.anticomp })} + onToggle={() => onSettingsChange({ anticomp: !settings.anticomp })} /> <ToggleInputButton name="stickyauth" placeholder="Sticky auth filter" checked={!!settings.stickyauth} txt={settings.stickyauth || ''} - onToggleChanged={txt => SettingsActions.update({ stickyauth: !settings.stickyauth ? txt : null })} + onToggleChanged={txt => onSettingsChange({ stickyauth: !settings.stickyauth ? txt : null })} /> <ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter" checked={!!settings.stickycookie} txt={settings.stickycookie || ''} - onToggleChanged={txt => SettingsActions.update({ stickycookie: !settings.stickycookie ? txt : null })} + onToggleChanged={txt => onSettingsChange({ stickycookie: !settings.stickycookie ? txt : null })} /> <ToggleInputButton name="stream" placeholder="stream..." checked={!!settings.stream} txt={settings.stream || ''} inputType="number" - onToggleChanged={txt => SettingsActions.update({ stream: !settings.stream ? txt : null })} + onToggleChanged={txt => onSettingsChange({ stream: !settings.stream ? txt : null })} /> </div> <div className="clearfix"/> </div> ) } + +export default connect( + state => ({ + settings: state.settings.settings, + }), + { + onSettingsChange: updateSettings, + } +)(OptionMenu) diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx index 89bd95fd..84564c32 100644 --- a/web/src/js/components/ProxyApp.jsx +++ b/web/src/js/components/ProxyApp.jsx @@ -120,11 +120,11 @@ class ProxyAppMain extends Component { } render() { - const { showEventLog, location, children, settings } = this.props + const { showEventLog, location, children } = this.props const query = this.getQuery() return ( <div id="container" tabIndex="0" onKeyDown={this.onKeyDown}> - <Header ref="header" settings={settings} updateLocation={this.updateLocation} query={query} /> + <Header ref="header" updateLocation={this.updateLocation} query={query} /> {React.cloneElement( children, { ref: 'view', location, query, updateLocation: this.updateLocation } @@ -132,7 +132,7 @@ class ProxyAppMain extends Component { {showEventLog && ( <EventLog key="eventlog"/> )} - <Footer settings={settings}/> + <Footer /> </div> ) } diff --git a/web/src/js/components/common/Button.jsx b/web/src/js/components/common/Button.jsx index cc2fe9dd..574288df 100644 --- a/web/src/js/components/common/Button.jsx +++ b/web/src/js/components/common/Button.jsx @@ -5,9 +5,11 @@ Button.propTypes = { text: PropTypes.string.isRequired } -export default function Button({ onClick, text, icon }) { +export default function Button({ onClick, text, icon, disabled }) { return ( - <div className={"btn btn-default"} onClick={onClick}> + <div className={"btn btn-default"} + onClick={onClick} + disabled={disabled}> <i className={"fa fa-fw " + icon}/> {text} diff --git a/web/src/js/ducks/settings.js b/web/src/js/ducks/settings.js index 73c62120..3e6c8366 100644 --- a/web/src/js/ducks/settings.js +++ b/web/src/js/ducks/settings.js @@ -1,8 +1,8 @@ -import {fetchApi} from "../utils"; +import {fetchApi} from '../utils'; -export const REQUEST_SETTINGS = "REQUEST_SETTINGS" -export const RECEIVE_SETTINGS = "RECEIVE_SETTINGS" -export const UPDATE_SETTINGS = "UPDATE_SETTINGS" +export const REQUEST_SETTINGS = 'REQUEST_SETTINGS' +export const RECEIVE_SETTINGS = 'RECEIVE_SETTINGS' +export const UPDATE_SETTINGS = 'UPDATE_SETTINGS' const defaultState = { settings: {}, @@ -49,20 +49,20 @@ export default function reducer(state = defaultState, action) { export function updateSettings(event) { /* This action creator takes all WebSocket events */ - if (event.cmd === "update") { + if (event.cmd === 'update') { return { type: UPDATE_SETTINGS, settings: event.data } } - console.error("unknown settings update", event) + console.error('unknown settings update', event) } export function fetchSettings() { return dispatch => { dispatch({type: REQUEST_SETTINGS}) - return fetchApi("/settings") + return fetchApi('/settings') .then(response => response.json()) .then(json => dispatch({type: RECEIVE_SETTINGS, settings: json.data}) @@ -71,7 +71,7 @@ export function fetchSettings() { } } -export function setInterceptPattern(intercept) { - return dispatch => - fetchApi.put("/settings", {intercept}) +export function updateSettings(settings) { + fetchApi.put('/settings', settings) + return { type: SET_INTERCEPT } } diff --git a/web/src/js/ducks/ui.js b/web/src/js/ducks/ui.js index 28a13ea4..c17e042b 100644 --- a/web/src/js/ducks/ui.js +++ b/web/src/js/ducks/ui.js @@ -1,5 +1,5 @@ -import { SELECT_FLOW } from './flows' -const SET_ACTIVE_MENU = 'SET_ACTIVE_MENU' +import {SELECT_FLOW} from "./flows" +export const SET_ACTIVE_MENU = 'SET_ACTIVE_MENU'; const defaultState = { |