aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@corte.si>2016-06-11 16:08:14 +1200
committerGitHub <noreply@github.com>2016-06-11 16:08:14 +1200
commit227d762cace09bc315e57644da2135480bf32cb9 (patch)
treedd1b458e77d79a8f7867e31f7a352c19e586e129
parent250b47487aa071e61f0bd2960992e80222103a3a (diff)
parent0b241a1da71ef9eb7632fc0e32abcf061dcbd217 (diff)
downloadmitmproxy-227d762cace09bc315e57644da2135480bf32cb9.tar.gz
mitmproxy-227d762cace09bc315e57644da2135480bf32cb9.tar.bz2
mitmproxy-227d762cace09bc315e57644da2135480bf32cb9.zip
Merge branch 'master' into toxfiddle
-rw-r--r--mitmproxy/web/static/app.js113
-rw-r--r--web/conf.js4
-rw-r--r--web/gulpfile.js1
-rw-r--r--web/src/js/app.jsx (renamed from web/src/js/app.js)0
-rw-r--r--web/src/js/components/EventLog.jsx41
-rw-r--r--web/src/js/components/EventLog/EventList.jsx90
-rw-r--r--web/src/js/components/FlowTable.jsx120
-rw-r--r--web/src/js/components/FlowTable/FlowColumns.jsx137
-rw-r--r--web/src/js/components/FlowTable/FlowRow.jsx28
-rw-r--r--web/src/js/components/FlowTable/FlowTableHead.jsx43
-rw-r--r--web/src/js/components/Footer.jsx (renamed from web/src/js/components/footer.js)45
-rw-r--r--web/src/js/components/Header.js56
-rw-r--r--web/src/js/components/Header/FileMenu.jsx100
-rw-r--r--web/src/js/components/Header/FilterDocs.jsx56
-rw-r--r--web/src/js/components/Header/FilterInput.jsx133
-rw-r--r--web/src/js/components/Header/MainMenu.jsx73
-rw-r--r--web/src/js/components/Header/OptionMenu.jsx60
-rw-r--r--web/src/js/components/Header/ViewMenu.jsx33
-rw-r--r--web/src/js/components/MainView.jsx (renamed from web/src/js/components/MainView.js)47
-rw-r--r--web/src/js/components/ProxyApp.jsx (renamed from web/src/js/components/ProxyApp.js)11
-rw-r--r--web/src/js/components/eventlog.js153
-rw-r--r--web/src/js/components/flowtable-columns.js131
-rw-r--r--web/src/js/components/flowtable.js201
-rw-r--r--web/src/js/components/header.js453
-rw-r--r--web/src/js/components/prompt.js4
-rw-r--r--web/src/js/ducks/flows.js6
26 files changed, 1103 insertions, 1036 deletions
diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js
index f546e5f8..2fc1540b 100644
--- a/mitmproxy/web/static/app.js
+++ b/mitmproxy/web/static/app.js
@@ -4,94 +4,121 @@ function EventEmitter(){this._events=this._events||{},this._maxListeners=this._m
},{}],2:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.Query=exports.FlowActions=exports.SettingsActions=exports.ConnectionActions=exports.StoreCmds=exports.ActionTypes=void 0;var _jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),_dispatcher=require("./dispatcher.js"),_utils=require("./utils.js"),ActionTypes=exports.ActionTypes={CONNECTION_OPEN:"connection_open",CONNECTION_CLOSE:"connection_close",CONNECTION_ERROR:"connection_error",SETTINGS_STORE:"settings",EVENT_STORE:"events",FLOW_STORE:"flows"},StoreCmds=exports.StoreCmds={ADD:"add",UPDATE:"update",REMOVE:"remove",RESET:"reset"},ConnectionActions=exports.ConnectionActions={open:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_OPEN})},close:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_CLOSE})},error:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_ERROR})}},SettingsActions=exports.SettingsActions={update:function(e){_jquery2["default"].ajax({type:"PUT",url:"/settings",contentType:"application/json",data:JSON.stringify(e)})}},FlowActions=exports.FlowActions={accept:function(e){_jquery2["default"].post("/flows/"+e.id+"/accept")},accept_all:function(){_jquery2["default"].post("/flows/accept")},"delete":function(e){_jquery2["default"].ajax({type:"DELETE",url:"/flows/"+e.id})},duplicate:function(e){_jquery2["default"].post("/flows/"+e.id+"/duplicate")},replay:function(e){_jquery2["default"].post("/flows/"+e.id+"/replay")},revert:function(e){_jquery2["default"].post("/flows/"+e.id+"/revert")},update:function(e,t){_jquery2["default"].ajax({type:"PUT",url:"/flows/"+e.id,contentType:"application/json",data:JSON.stringify(t)})},clear:function(){_jquery2["default"].post("/clear")},download:function(){return window.location="/flows/dump"},upload:function(e){var t=new FormData;t.append("file",e),(0,_utils.fetchApi)("/flows/dump",{method:"post",body:t})}},Query=exports.Query={SEARCH:"s",HIGHLIGHT:"h",SHOW_EVENTLOG:"e"};
-},{"./dispatcher.js":22,"./utils.js":32,"jquery":"jquery"}],3:[function(require,module,exports){
+},{"./dispatcher.js":31,"./utils.js":41,"jquery":"jquery"}],3:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}var _react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_redux=require("redux"),_reactRedux=require("react-redux"),_reduxLogger=require("redux-logger"),_reduxLogger2=_interopRequireDefault(_reduxLogger),_reduxThunk=require("redux-thunk"),_reduxThunk2=_interopRequireDefault(_reduxThunk),_reactRouter=require("react-router"),_connection=require("./connection"),_connection2=_interopRequireDefault(_connection),_ProxyApp=require("./components/ProxyApp"),_ProxyApp2=_interopRequireDefault(_ProxyApp),_MainView=require("./components/MainView"),_MainView2=_interopRequireDefault(_MainView),_index=require("./ducks/index"),_index2=_interopRequireDefault(_index),_eventLog=require("./ducks/eventLog"),store=(0,_redux.createStore)(_index2["default"],(0,_redux.applyMiddleware)(_reduxThunk2["default"],(0,_reduxLogger2["default"])()));window.addEventListener("error",function(e){store.dispatch((0,_eventLog.addLogEntry)(e))}),document.addEventListener("DOMContentLoaded",function(){window.ws=new _connection2["default"]("/updates",store.dispatch),(0,_reactDom.render)(_react2["default"].createElement(_reactRedux.Provider,{store:store},_react2["default"].createElement(_reactRouter.Router,{history:_reactRouter.hashHistory},_react2["default"].createElement(_reactRouter.Redirect,{from:"/",to:"/flows"}),_react2["default"].createElement(_reactRouter.Route,{path:"/",component:_ProxyApp2["default"]},_react2["default"].createElement(_reactRouter.Route,{path:"flows",component:_MainView2["default"]}),_react2["default"].createElement(_reactRouter.Route,{path:"flows/:flowId/:detailTab",component:_MainView2["default"]})))),document.getElementById("mitmproxy"))});
-},{"./components/MainView":4,"./components/ProxyApp":5,"./connection":21,"./ducks/eventLog":23,"./ducks/index":25,"react":"react","react-dom":"react-dom","react-redux":"react-redux","react-router":"react-router","redux":"redux","redux-logger":"redux-logger","redux-thunk":"redux-thunk"}],4:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var s=0;s<t.length;s++){var l=t[s];l.enumerable=l.enumerable||!1,l.configurable=!0,"value"in l&&(l.writable=!0),Object.defineProperty(e,l.key,l)}}return function(t,s,l){return s&&e(t.prototype,s),l&&e(t,l),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_actions=require("../actions.js"),_utils=require("../utils.js"),_common=require("./common.js"),_flowtable=require("./flowtable.js"),_flowtable2=_interopRequireDefault(_flowtable),_index=require("./flowview/index.js"),_index2=_interopRequireDefault(_index),_reactRedux=require("react-redux"),_flows=require("../ducks/flows"),MainView=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,Object.getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),_createClass(t,[{key:"componentWillReceiveProps",value:function(e){e.routeParams.flowId!==(e.selectedFlow||{}).id&&this.props.selectFlow(e.routeParams.flowId),e.location.query[_actions.Query.SEARCH]!==e.filter&&this.props.setFilter(e.location.query[_actions.Query.SEARCH],!1),e.location.query[_actions.Query.HIGHLIGHT]!==e.highlight&&this.props.setHighlight(e.location.query[_actions.Query.HIGHLIGHT],!1)}},{key:"selectFlow",value:function(e){e?this.props.updateLocation("/flows/"+e.id+"/"+(this.props.routeParams.detailTab||"request")):this.props.updateLocation("/flows")}},{key:"selectFlowRelative",value:function(e){var t=this.props,s=t.flows,l=t.routeParams,i=t.selectedFlow,o=0;l.flowId?o=Math.min(Math.max(0,s.indexOf(i)+e),s.length-1):0>e&&(o=s.length-1),this.selectFlow(s[o])}},{key:"onMainKeyDown",value:function(e){var t=this.props.selectedFlow;if(!e.ctrlKey){switch(e.keyCode){case _utils.Key.K:case _utils.Key.UP:this.selectFlowRelative(-1);break;case _utils.Key.J:case _utils.Key.DOWN:this.selectFlowRelative(1);break;case _utils.Key.SPACE:case _utils.Key.PAGE_DOWN:this.selectFlowRelative(10);break;case _utils.Key.PAGE_UP:this.selectFlowRelative(-10);break;case _utils.Key.END:this.selectFlowRelative(1e10);break;case _utils.Key.HOME:this.selectFlowRelative(-1e10);break;case _utils.Key.ESC:this.selectFlow(null);break;case _utils.Key.H:case _utils.Key.LEFT:this.refs.flowDetails&&this.refs.flowDetails.nextTab(-1);break;case _utils.Key.L:case _utils.Key.TAB:case _utils.Key.RIGHT:this.refs.flowDetails&&this.refs.flowDetails.nextTab(1);break;case _utils.Key.C:e.shiftKey&&_actions.FlowActions.clear();break;case _utils.Key.D:t&&(e.shiftKey?_actions.FlowActions.duplicate(t):_actions.FlowActions["delete"](t));break;case _utils.Key.A:e.shiftKey?_actions.FlowActions.accept_all():t&&t.intercepted&&_actions.FlowActions.accept(t);break;case _utils.Key.R:!e.shiftKey&&t&&_actions.FlowActions.replay(t);break;case _utils.Key.V:e.shiftKey&&t&&t.modified&&_actions.FlowActions.revert(t);break;case _utils.Key.E:this.refs.flowDetails&&this.refs.flowDetails.promptEdit();break;case _utils.Key.SHIFT:break;default:return void console.debug("keydown",e.keyCode)}e.preventDefault()}}},{key:"render",value:function(){var e=this,t=this.props.selectedFlow;return _react2["default"].createElement("div",{className:"main-view"},_react2["default"].createElement(_flowtable2["default"],{ref:"flowTable",selectFlow:function(t){return e.selectFlow(t)},selected:t}),t&&[_react2["default"].createElement(_common.Splitter,{key:"splitter"}),_react2["default"].createElement(_index2["default"],{key:"flowDetails",ref:"flowDetails",tab:this.props.routeParams.detailTab,query:this.props.query,updateLocation:this.props.updateLocation,flow:t})])}}]),t}(_react.Component);exports["default"]=(0,_reactRedux.connect)(function(e){return{flows:e.flows.view,filter:e.flows.filter,highlight:e.flows.highlight,selectedFlow:e.flows.all.byId[e.flows.selected[0]]}},function(e){return{selectFlow:function(t){return e((0,_flows.selectFlow)(t))},setFilter:function(t){return e((0,_flows.setFilter)(t))},setHighlight:function(t){return e((0,_flows.setHighlight)(t))}}},void 0,{withRef:!0})(MainView);
+},{"./components/MainView":18,"./components/ProxyApp":19,"./connection":30,"./ducks/eventLog":32,"./ducks/index":34,"react":"react","react-dom":"react-dom","react-redux":"react-redux","react-router":"react-router","redux":"redux","redux-logger":"redux-logger","redux-thunk":"redux-thunk"}],4:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function EventLog(e){var t=e.filters,r=e.events,n=e.onToggleFilter,o=e.onClose;return _react2["default"].createElement("div",{className:"eventlog"},_react2["default"].createElement("div",null,"Eventlog",_react2["default"].createElement("div",{className:"pull-right"},["debug","info","web"].map(function(e){return _react2["default"].createElement(_common.ToggleButton,{key:e,text:e,checked:t[e],onToggle:function(){return n(e)}})}),_react2["default"].createElement("i",{onClick:o,className:"fa fa-close"}))),_react2["default"].createElement(_EventList2["default"],{events:r}))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_redux=require("redux"),_reactRedux=require("react-redux"),_eventLog=require("../ducks/eventLog"),_common=require("./common"),_EventList=require("./EventLog/EventList"),_EventList2=_interopRequireDefault(_EventList);EventLog.propTypes={filters:_react.PropTypes.object.isRequired,events:_react.PropTypes.array.isRequired,onToggleFilter:_react.PropTypes.func.isRequired,onClose:_react.PropTypes.func.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{filters:e.eventLog.filter,events:e.eventLog.filteredEvents}},function(e){return(0,_redux.bindActionCreators)({onClose:_eventLog.toggleEventLogVisibility,onToggleFilter:_eventLog.toggleEventLogFilter},e)})(EventLog);
-},{"../actions.js":2,"../ducks/flows":24,"../utils.js":32,"./common.js":6,"./flowtable.js":10,"./flowview/index.js":13,"react":"react","react-redux":"react-redux"}],5:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_reactRedux=require("react-redux"),_common=require("./common.js"),_header=require("./header.js"),_eventlog=require("./eventlog.js"),_eventlog2=_interopRequireDefault(_eventlog),_footer=require("./footer.js"),_footer2=_interopRequireDefault(_footer),_store=require("../store/store.js"),_utils=require("../utils.js"),ProxyAppMain=function(e){function t(e,r){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return n.settingsStore=new _store.SettingsStore,_lodash2["default"].extend(n.settingsStore.dict,{}),n.state={settings:n.settingsStore.dict},n.onKeyDown=n.onKeyDown.bind(n),n.updateLocation=n.updateLocation.bind(n),n.onSettingsChange=n.onSettingsChange.bind(n),n}return _inherits(t,e),_createClass(t,[{key:"updateLocation",value:function(e,t){void 0===e&&(e=this.props.location.pathname);var r=this.props.location.query,n=!0,o=!1,a=void 0;try{for(var s,u=Object.keys(t||{})[Symbol.iterator]();!(n=(s=u.next()).done);n=!0){s.value;r[i]=t[i]||void 0}}catch(c){o=!0,a=c}finally{try{!n&&u["return"]&&u["return"]()}finally{if(o)throw a}}this.context.router.replace({pathname:e,query:r})}},{key:"getQuery",value:function(){return _lodash2["default"].clone(this.props.location.query)}},{key:"componentDidMount",value:function(){this.focus(),this.settingsStore.addListener("recalculate",this.onSettingsChange)}},{key:"componentWillUnmount",value:function(){this.settingsStore.removeListener("recalculate",this.onSettingsChange)}},{key:"onSettingsChange",value:function(){this.setState({settings:this.settingsStore.dict})}},{key:"getChildContext",value:function(){return{returnFocus:this.focus,location:this.props.location}}},{key:"focus",value:function(){document.activeElement.blur(),window.getSelection().removeAllRanges(),_reactDom2["default"].findDOMNode(this).focus()}},{key:"onKeyDown",value:function(e){var t=this,r=null;switch(e.keyCode){case _utils.Key.I:r="intercept";break;case _utils.Key.L:r="search";break;case _utils.Key.H:r="highlight";break;default:var n=this.refs.view;return this.refs.view.getWrappedInstance&&(n=this.refs.view.getWrappedInstance()),void(n.onMainKeyDown&&n.onMainKeyDown(e))}r&&!function(){var e=t.refs.header;e.setState({active:_header.MainMenu},function(){e.refs.active.refs[r].select()})}(),e.preventDefault()}},{key:"render",value:function(){var e=this.props,t=e.showEventLog,r=e.location,n=e.children,o=this.state.settings,i=this.getQuery();return _react2["default"].createElement("div",{id:"container",tabIndex:"0",onKeyDown:this.onKeyDown},_react2["default"].createElement(_header.Header,{ref:"header",settings:o,updateLocation:this.updateLocation,query:i}),_react2["default"].cloneElement(n,{ref:"view",location:r,query:i,updateLocation:this.updateLocation}),t&&[_react2["default"].createElement(_common.Splitter,{key:"splitter",axis:"y"}),_react2["default"].createElement(_eventlog2["default"],{key:"eventlog"})],_react2["default"].createElement(_footer2["default"],{settings:o}))}}]),t}(_react.Component);ProxyAppMain.childContextTypes={returnFocus:_react.PropTypes.func.isRequired,location:_react.PropTypes.object.isRequired},ProxyAppMain.contextTypes={router:_react.PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{showEventLog:e.eventLog.visible}})(ProxyAppMain);
+},{"../ducks/eventLog":32,"./EventLog/EventList":5,"./common":20,"react":"react","react-redux":"react-redux","redux":"redux"}],5:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function LogIcon(e){var t=e.event,r={web:"html5",debug:"bug"}[t.level]||"info";return _react2["default"].createElement("i",{className:"fa fa-fw fa-"+r})}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var o=t[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,r,o){return r&&e(t.prototype,r),o&&e(t,o),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_shallowequal=require("shallowequal"),_shallowequal2=_interopRequireDefault(_shallowequal),_AutoScroll=require("../helpers/AutoScroll"),_AutoScroll2=_interopRequireDefault(_AutoScroll),_VirtualScroll=require("../helpers/VirtualScroll"),EventLogList=function(e){function t(e){_classCallCheck(this,t);var r=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e));return r.heights={},r.state={vScroll:(0,_VirtualScroll.calcVScroll)()},r.onViewportUpdate=r.onViewportUpdate.bind(r),r}return _inherits(t,e),_createClass(t,[{key:"componentDidMount",value:function(){window.addEventListener("resize",this.onViewportUpdate),this.onViewportUpdate()}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onViewportUpdate)}},{key:"componentDidUpdate",value:function(){this.onViewportUpdate()}},{key:"onViewportUpdate",value:function(){var e=this,t=_reactDom2["default"].findDOMNode(this),r=(0,_VirtualScroll.calcVScroll)({itemCount:this.props.events.length,rowHeight:this.props.rowHeight,viewportTop:t.scrollTop,viewportHeight:t.offsetHeight,itemHeights:this.props.events.map(function(t){return e.heights[t.id]})});(0,_shallowequal2["default"])(this.state.vScroll,r)||this.setState({vScroll:r})}},{key:"setHeight",value:function(e,t){if(t&&!this.heights[e]){var r=t.offsetHeight;this.heights[e]!==r&&(this.heights[e]=r,this.onViewportUpdate())}}},{key:"render",value:function(){var e=this,t=this.state.vScroll,r=this.props.events;return _react2["default"].createElement("pre",{onScroll:this.onViewportUpdate},_react2["default"].createElement("div",{style:{height:t.paddingTop}}),r.slice(t.start,t.end).map(function(t){return _react2["default"].createElement("div",{key:t.id,ref:function(r){return e.setHeight(t.id,r)}},_react2["default"].createElement(LogIcon,{event:t}),t.message)}),_react2["default"].createElement("div",{style:{height:t.paddingBottom}}))}}]),t}(_react.Component);EventLogList.propTypes={events:_react.PropTypes.array.isRequired,rowHeight:_react.PropTypes.number},EventLogList.defaultProps={rowHeight:18},exports["default"]=(0,_AutoScroll2["default"])(EventLogList);
-},{"../store/store.js":31,"../utils.js":32,"./common.js":6,"./eventlog.js":8,"./footer.js":16,"./header.js":17,"lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux"}],6:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToggleInputButton=exports.ToggleButton=exports.Splitter=void 0;var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_utils=require("../utils.js"),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),Splitter=exports.Splitter=_react2["default"].createClass({displayName:"Splitter",getDefaultProps:function(){return{axis:"x"}},getInitialState:function(){return{applied:!1,startX:!1,startY:!1}},onMouseDown:function(e){this.setState({startX:e.pageX,startY:e.pageY}),window.addEventListener("mousemove",this.onMouseMove),window.addEventListener("mouseup",this.onMouseUp),window.addEventListener("dragend",this.onDragEnd)},onDragEnd:function(){_reactDom2["default"].findDOMNode(this).style.transform="",window.removeEventListener("dragend",this.onDragEnd),window.removeEventListener("mouseup",this.onMouseUp),window.removeEventListener("mousemove",this.onMouseMove)},onMouseUp:function(e){this.onDragEnd();var t,n=_reactDom2["default"].findDOMNode(this),r=n.previousElementSibling,o=n.nextElementSibling,a=e.pageX-this.state.startX,s=e.pageY-this.state.startY;t="x"===this.props.axis?r.offsetWidth+a:r.offsetHeight+s,r.style.flex="0 0 "+Math.max(0,t)+"px",o.style.flex="1 1 auto",this.setState({applied:!0}),this.onResize()},onMouseMove:function(e){var t=0,n=0;"x"===this.props.axis?t=e.pageX-this.state.startX:n=e.pageY-this.state.startY,_reactDom2["default"].findDOMNode(this).style.transform="translate("+t+"px,"+n+"px)"},onResize:function(){window.setTimeout(function(){window.dispatchEvent(new CustomEvent("resize"))},1)},reset:function(e){if(this.state.applied){var t=_reactDom2["default"].findDOMNode(this),n=t.previousElementSibling,r=t.nextElementSibling;n.style.flex="",r.style.flex="",e||this.setState({applied:!1}),this.onResize()}},componentWillUnmount:function(){this.reset(!0)},render:function(){var e="splitter";return e+="x"===this.props.axis?" splitter-x":" splitter-y",_react2["default"].createElement("div",{className:e},_react2["default"].createElement("div",{onMouseDown:this.onMouseDown,draggable:"true"}))}}),ToggleButton=exports.ToggleButton=function(e){var t=e.checked,n=e.onToggle,r=e.text;return _react2["default"].createElement("div",{className:"btn btn-toggle "+(t?"btn-primary":"btn-default"),onClick:n},_react2["default"].createElement("i",{className:"fa fa-fw "+(t?"fa-check-square-o":"fa-square-o")})," ",r)};ToggleButton.propTypes={checked:_react2["default"].PropTypes.bool.isRequired,onToggle:_react2["default"].PropTypes.func.isRequired,text:_react2["default"].PropTypes.string.isRequired};var ToggleInputButton=exports.ToggleInputButton=function(e){function t(e){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e));return n.state={txt:e.txt},n}return _inherits(t,e),_createClass(t,[{key:"render",value:function(){var e=this;return _react2["default"].createElement("div",{className:"input-group toggle-input-btn"},_react2["default"].createElement("span",{className:"input-group-btn",onClick:function(){return e.props.onToggleChanged(e.state.txt)}},_react2["default"].createElement("div",{className:"btn "+(this.props.checked?"btn-primary":"btn-default")},_react2["default"].createElement("span",{className:"fa "+(this.props.checked?"fa-check-square-o":"fa-square-o")})," ",this.props.name)),_react2["default"].createElement("input",{className:"form-control",placeholder:this.props.placeholder,disabled:this.props.checked,value:this.state.txt,type:this.props.inputType,onChange:function(t){return e.setState({txt:t.target.value})},onKeyDown:function(t){t.keyCode===_utils.Key.ENTER&&e.props.onToggleChanged(e.state.txt),t.stopPropagation()}}))}}]),t}(_react2["default"].Component);ToggleInputButton.propTypes={name:_react2["default"].PropTypes.string.isRequired,txt:_react2["default"].PropTypes.string.isRequired,onToggleChanged:_react2["default"].PropTypes.func.isRequired};
+},{"../helpers/AutoScroll":27,"../helpers/VirtualScroll":28,"react":"react","react-dom":"react-dom","shallowequal":"shallowequal"}],6:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var o=0;o<t.length;o++){var r=t[o];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,o,r){return o&&e(t.prototype,o),r&&e(t,r),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_shallowequal=require("shallowequal"),_shallowequal2=_interopRequireDefault(_shallowequal),_AutoScroll=require("./helpers/AutoScroll"),_AutoScroll2=_interopRequireDefault(_AutoScroll),_VirtualScroll=require("./helpers/VirtualScroll"),_FlowTableHead=require("./FlowTable/FlowTableHead"),_FlowTableHead2=_interopRequireDefault(_FlowTableHead),_FlowRow=require("./FlowTable/FlowRow"),_FlowRow2=_interopRequireDefault(_FlowRow),_filt=require("../filt/filt"),_filt2=_interopRequireDefault(_filt),FlowTable=function(e){function t(e,o){_classCallCheck(this,t);var r=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,o));return r.state={vScroll:(0,_VirtualScroll.calcVScroll)()},r.onViewportUpdate=r.onViewportUpdate.bind(r),r}return _inherits(t,e),_createClass(t,[{key:"componentWillMount",value:function(){window.addEventListener("resize",this.onViewportUpdate)}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onViewportUpdate)}},{key:"componentDidUpdate",value:function(){if(this.onViewportUpdate(),this.shouldScrollIntoView){this.shouldScrollIntoView=!1;var e=this.props,t=e.rowHeight,o=e.flows,r=e.selected,l=_reactDom2["default"].findDOMNode(this),a=_reactDom2["default"].findDOMNode(this.refs.head),i=a?a.offsetHeight:0,n=o.indexOf(r)*t+i,u=n+t,c=l.scrollTop,s=l.offsetHeight;c>n-i?l.scrollTop=n-i:u>c+s&&(l.scrollTop=u-s)}}},{key:"componentWillReceiveProps",value:function(e){e.selected&&e.selected!==this.props.selected&&(this.shouldScrollIntoView=!0)}},{key:"onViewportUpdate",value:function(){var e=_reactDom2["default"].findDOMNode(this),t=e.scrollTop,o=(0,_VirtualScroll.calcVScroll)({viewportTop:t,viewportHeight:e.offsetHeight,itemCount:this.props.flows.length,rowHeight:this.props.rowHeight});this.state.viewportTop===t&&(0,_shallowequal2["default"])(this.state.vScroll,o)||this.setState({vScroll:o,viewportTop:t})}},{key:"render",value:function(){var e=this,t=this.state,o=t.vScroll,r=t.viewportTop,l=this.props,a=l.flows,i=l.selected,n=l.highlight,u=n?_filt2["default"].parse(n):function(){return!1};return _react2["default"].createElement("div",{className:"flow-table",onScroll:this.onViewportUpdate},_react2["default"].createElement("table",null,_react2["default"].createElement("thead",{ref:"head",style:{transform:"translateY("+r+"px)"}},_react2["default"].createElement(_FlowTableHead2["default"],null)),_react2["default"].createElement("tbody",null,_react2["default"].createElement("tr",{style:{height:o.paddingTop}}),a.slice(o.start,o.end).map(function(t){return _react2["default"].createElement(_FlowRow2["default"],{key:t.id,flow:t,selected:t===i,highlighted:u(t),onSelect:e.props.onSelect})}),_react2["default"].createElement("tr",{style:{height:o.paddingBottom}}))))}}]),t}(_react2["default"].Component);FlowTable.propTypes={onSelect:_react.PropTypes.func.isRequired,flows:_react.PropTypes.array.isRequired,rowHeight:_react.PropTypes.number,highlight:_react.PropTypes.string,selected:_react.PropTypes.object},FlowTable.defaultProps={rowHeight:32},exports["default"]=(0,_AutoScroll2["default"])(FlowTable);
-},{"../utils.js":32,"lodash":"lodash","react":"react","react-dom":"react-dom"}],7:[function(require,module,exports){
-"use strict";function _interopRequireDefault(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ValueEditor=void 0;var _extends=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var o=arguments[e];for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&(t[n]=o[n])}return t},_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_utils=require("../utils.js"),contentToHtml=function(t){return _.escape(t)},nodeToContent=function(t){return t.textContent},EditorBase=_react2["default"].createClass({displayName:"EditorBase",propTypes:{content:_react2["default"].PropTypes.string.isRequired,onDone:_react2["default"].PropTypes.func.isRequired,contentToHtml:_react2["default"].PropTypes.func,nodeToContent:_react2["default"].PropTypes.func,onStop:_react2["default"].PropTypes.func,submitOnEnter:_react2["default"].PropTypes.bool,className:_react2["default"].PropTypes.string,tag:_react2["default"].PropTypes.string},getDefaultProps:function(){return{contentToHtml:contentToHtml,nodeToContent:nodeToContent,submitOnEnter:!0,className:"",tag:"div"}},getInitialState:function(){return{editable:!1}},render:function(){var t="inline-input "+this.props.className,e={__html:this.props.contentToHtml(this.props.content)},o=this.props.tag;return _react2["default"].createElement(o,_extends({},this.props,{tabIndex:"0",className:t,contentEditable:this.state.editable||void 0,onFocus:this.onFocus,onMouseDown:this.onMouseDown,onClick:this.onClick,onBlur:this._stop,onKeyDown:this.onKeyDown,onInput:this.onInput,onPaste:this.onPaste,dangerouslySetInnerHTML:e}))},onPaste:function(t){t.preventDefault();var e=t.clipboardData.getData("text/plain");document.execCommand("insertHTML",!1,e)},onMouseDown:function(t){this._mouseDown=!0,window.addEventListener("mouseup",this.onMouseUp),this.props.onMouseDown&&this.props.onMouseDown(t)},onMouseUp:function(){this._mouseDown&&(this._mouseDown=!1,window.removeEventListener("mouseup",this.onMouseUp))},onClick:function(t){this.onMouseUp(),this.onFocus(t)},onFocus:function(t){if(console.log("onFocus",this._mouseDown,this._ignore_events,this.state.editable),!(this._mouseDown||this._ignore_events||this.state.editable)){var e,o=window.getSelection();if(o.rangeCount>0)e=o.getRangeAt(0);else if(document.caretPositionFromPoint&&t.clientX&&t.clientY){var n=document.caretPositionFromPoint(t.clientX,t.clientY);e=document.createRange(),e.setStart(n.offsetNode,n.offset)}else document.caretRangeFromPoint&&t.clientX&&t.clientY?e=document.caretRangeFromPoint(t.clientX,t.clientY):(e=document.createRange(),e.selectNodeContents(_reactDom2["default"].findDOMNode(this)));this._ignore_events=!0,this.setState({editable:!0},function(){var t=_reactDom2["default"].findDOMNode(this);t.blur(),t.focus(),this._ignore_events=!1})}},stop:function(){_reactDom2["default"].findDOMNode(this).blur(),this.props.onStop&&this.props.onStop()},_stop:function(t){if(!this._ignore_events){console.log("_stop",_.extend({},t)),window.getSelection().removeAllRanges();var e=_reactDom2["default"].findDOMNode(this),o=this.props.nodeToContent(e);this.setState({editable:!1}),this.props.onDone(o),this.props.onBlur&&this.props.onBlur(t)}},reset:function(){_reactDom2["default"].findDOMNode(this).innerHTML=this.props.contentToHtml(this.props.content)},onKeyDown:function(t){switch(t.stopPropagation(),t.keyCode){case _utils.Key.ESC:t.preventDefault(),this.reset(),this.stop();break;case _utils.Key.ENTER:this.props.submitOnEnter&&!t.shiftKey&&(t.preventDefault(),this.stop())}},onInput:function(){var t=_reactDom2["default"].findDOMNode(this),e=this.props.nodeToContent(t);this.props.onInput&&this.props.onInput(e)}}),ValidateEditor=_react2["default"].createClass({displayName:"ValidateEditor",propTypes:{content:_react2["default"].PropTypes.string.isRequired,onDone:_react2["default"].PropTypes.func.isRequired,onInput:_react2["default"].PropTypes.func,isValid:_react2["default"].PropTypes.func,className:_react2["default"].PropTypes.string},getInitialState:function(){return{currentContent:this.props.content}},componentWillReceiveProps:function(){this.setState({currentContent:this.props.content})},onInput:function(t){this.setState({currentContent:t}),this.props.onInput&&this.props.onInput(t)},render:function(){var t=this.props.className||"";return this.props.isValid&&(t+=this.props.isValid(this.state.currentContent)?" has-success":" has-warning"),_react2["default"].createElement(EditorBase,_extends({},this.props,{ref:"editor",className:t,onDone:this.onDone,onInput:this.onInput}))},onDone:function(t){this.props.isValid&&!this.props.isValid(t)&&(this.refs.editor.reset(),t=this.props.content),this.props.onDone(t)}}),ValueEditor=exports.ValueEditor=_react2["default"].createClass({displayName:"ValueEditor",contextTypes:{returnFocus:_react2["default"].PropTypes.func},propTypes:{content:_react2["default"].PropTypes.string.isRequired,onDone:_react2["default"].PropTypes.func.isRequired,inline:_react2["default"].PropTypes.bool},render:function(){var t=this.props.inline?"span":"div";return _react2["default"].createElement(ValidateEditor,_extends({},this.props,{onStop:this.onStop,tag:t}))},focus:function(){_reactDom2["default"].findDOMNode(this).focus()},onStop:function(){this.context.returnFocus()}});
+},{"../filt/filt":38,"./FlowTable/FlowRow":8,"./FlowTable/FlowTableHead":9,"./helpers/AutoScroll":27,"./helpers/VirtualScroll":28,"react":"react","react-dom":"react-dom","shallowequal":"shallowequal"}],7:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function TLSColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:(0,_classnames2["default"])("col-tls","https"===t.request.scheme?"col-tls-https":"col-tls-http")})}function IconColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-icon"},_react2["default"].createElement("div",{className:(0,_classnames2["default"])("resource-icon",IconColumn.getIcon(t))}))}function PathColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-path"},t.request.is_replay&&_react2["default"].createElement("i",{className:"fa fa-fw fa-repeat pull-right"}),t.intercepted&&_react2["default"].createElement("i",{className:"fa fa-fw fa-pause pull-right"}),_utils.RequestUtils.pretty_url(t.request))}function MethodColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-method"},t.request.method)}function StatusColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-status"},t.response&&t.response.status_code)}function SizeColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-size"},(0,_utils2.formatSize)(SizeColumn.getTotalSize(t)))}function TimeColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-time"},t.response?(0,_utils2.formatTimeDelta)(1e3*(t.response.timestamp_end-t.request.timestamp_start)):"...")}Object.defineProperty(exports,"__esModule",{value:!0}),exports.TLSColumn=TLSColumn,exports.IconColumn=IconColumn,exports.PathColumn=PathColumn,exports.MethodColumn=MethodColumn,exports.StatusColumn=StatusColumn,exports.SizeColumn=SizeColumn,exports.TimeColumn=TimeColumn;var _react=require("react"),_react2=_interopRequireDefault(_react),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_utils=require("../../flow/utils.js"),_utils2=require("../../utils.js");TLSColumn.sortKeyFun=function(e){return e.request.scheme},TLSColumn.headerClass="col-tls",TLSColumn.headerName="",IconColumn.headerClass="col-icon",IconColumn.headerName="",IconColumn.getIcon=function(e){if(!e.response)return"resource-icon-plain";var t=_utils.ResponseUtils.getContentType(e.response)||"";return 304===e.response.status_code?"resource-icon-not-modified":300<=e.response.status_code&&e.response.status_code<400?"resource-icon-redirect":t.indexOf("image")>=0?"resource-icon-image":t.indexOf("javascript")>=0?"resource-icon-js":t.indexOf("css")>=0?"resource-icon-css":t.indexOf("html")>=0?"resource-icon-document":"resource-icon-plain"},PathColumn.sortKeyFun=function(e){return _utils.RequestUtils.pretty_url(e.request)},PathColumn.headerClass="col-path",PathColumn.headerName="Path",MethodColumn.sortKeyFun=function(e){return e.request.method},MethodColumn.headerClass="col-method",MethodColumn.headerName="Method",StatusColumn.sortKeyFun=function(e){return e.response&&e.response.status_code},StatusColumn.headerClass="col-status",StatusColumn.headerName="Status",SizeColumn.sortKeyFun=function(e){var t=e.request.contentLength;return e.response&&(t+=e.response.contentLength||0),t},SizeColumn.getTotalSize=SizeColumn.sortKeyFun,SizeColumn.headerClass="col-size",SizeColumn.headerName="Size",TimeColumn.sortKeyFun=function(e){return e.response&&e.response.timestamp_end-e.request.timestamp_start},TimeColumn.headerClass="col-time",TimeColumn.headerName="Time",exports["default"]=[TLSColumn,IconColumn,PathColumn,MethodColumn,StatusColumn,SizeColumn,TimeColumn];
+
+},{"../../flow/utils.js":39,"../../utils.js":41,"classnames":"classnames","react":"react"}],8:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function FlowRow(e){var t=e.flow,r=e.selected,l=e.highlighted,o=e.onSelect,s=(0,_classnames2["default"])({selected:r,highlighted:l,intercepted:t.intercepted,"has-request":t.request,"has-response":t.response});return _react2["default"].createElement("tr",{className:s,onClick:function(){return o(t)}},_FlowColumns2["default"].map(function(e){return _react2["default"].createElement(e,{key:e.name,flow:t})}))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=FlowRow;var _react=require("react"),_react2=_interopRequireDefault(_react),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_FlowColumns=require("./FlowColumns"),_FlowColumns2=_interopRequireDefault(_FlowColumns);FlowRow.propTypes={onSelect:_react.PropTypes.func.isRequired,flow:_react.PropTypes.object.isRequired,highlighted:_react.PropTypes.bool,selected:_react.PropTypes.bool};
+
+},{"./FlowColumns":7,"classnames":"classnames","react":"react"}],9:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function FlowTableHead(e){function r(e){s({sortColumn:e.name,sortDesc:e.name!==t?!1:!o})}var t=e.sortColumn,o=e.sortDesc,s=e.onSort,u=o?"sort-desc":"sort-asc";return _react2["default"].createElement("tr",null,_FlowColumns2["default"].map(function(e){return _react2["default"].createElement("th",{className:(0,_classnames2["default"])(e.headerClass,t===e.name&&u),key:e.name,onClick:function(){return r(e)}},e.headerName)}))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_redux=require("redux"),_reactRedux=require("react-redux"),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_FlowColumns=require("./FlowColumns"),_FlowColumns2=_interopRequireDefault(_FlowColumns),_flows=require("../../ducks/flows");FlowTableHead.propTypes={onSort:_react.PropTypes.func.isRequired,sortDesc:_react2["default"].PropTypes.bool.isRequired,sortColumn:_react2["default"].PropTypes.string},exports["default"]=(0,_reactRedux.connect)(function(e){return{sortDesc:e.flows.sort.sortDesc,sortColumn:e.flows.sort.sortColumn}},function(e){return(0,_redux.bindActionCreators)({onSort:_flows.setSort},e)})(FlowTableHead);
+
+},{"../../ducks/flows":33,"./FlowColumns":7,"classnames":"classnames","react":"react","react-redux":"react-redux","redux":"redux"}],10:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function Footer(e){var a=e.settings;return _react2["default"].createElement("footer",null,a.mode&&"regular"!=a.mode&&_react2["default"].createElement("span",{className:"label label-success"},a.mode," mode"),a.intercept&&_react2["default"].createElement("span",{className:"label label-success"},"Intercept: ",a.intercept),a.showhost&&_react2["default"].createElement("span",{className:"label label-success"},"showhost"),a.no_upstream_cert&&_react2["default"].createElement("span",{className:"label label-success"},"no-upstream-cert"),a.rawtcp&&_react2["default"].createElement("span",{className:"label label-success"},"raw-tcp"),!a.http2&&_react2["default"].createElement("span",{className:"label label-success"},"no-http2"),a.anticache&&_react2["default"].createElement("span",{className:"label label-success"},"anticache"),a.anticomp&&_react2["default"].createElement("span",{className:"label label-success"},"anticomp"),a.stickyauth&&_react2["default"].createElement("span",{className:"label label-success"},"stickyauth: ",a.stickyauth),a.stickycookie&&_react2["default"].createElement("span",{className:"label label-success"},"stickycookie: ",a.stickycookie),a.stream&&_react2["default"].createElement("span",{className:"label label-success"},"stream: ",(0,_utils.formatSize)(a.stream)))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Footer;var _react=require("react"),_react2=_interopRequireDefault(_react),_utils=require("../utils.js"),_common=require("./common.js");Footer.propTypes={settings:_react2["default"].PropTypes.object.isRequired};
+
+},{"../utils.js":41,"./common.js":20,"react":"react"}],11:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_eventLog=require("../ducks/eventLog"),_MainMenu=require("./Header/MainMenu"),_MainMenu2=_interopRequireDefault(_MainMenu),_ViewMenu=require("./Header/ViewMenu"),_ViewMenu2=_interopRequireDefault(_ViewMenu),_OptionMenu=require("./Header/OptionMenu"),_OptionMenu2=_interopRequireDefault(_OptionMenu),_FileMenu=require("./Header/FileMenu"),_FileMenu2=_interopRequireDefault(_FileMenu),Header=function(e){function t(e,n){_classCallCheck(this,t);var r=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,n));return r.state={active:t.entries[0]},r}return _inherits(t,e),_createClass(t,[{key:"handleClick",value:function(e,t){t.preventDefault(),this.props.updateLocation(e.route),this.setState({active:e})}},{key:"render",value:function(){var e=this,n=this.state.active,r=this.props,a=r.settings,u=r.updateLocation,i=r.query;return _react2["default"].createElement("header",null,_react2["default"].createElement("nav",{className:"nav-tabs nav-tabs-lg"},_react2["default"].createElement(_FileMenu2["default"],null),t.entries.map(function(t){return _react2["default"].createElement("a",{key:t.title,href:"#",className:(0,_classnames2["default"])({active:t===n}),onClick:function(n){return e.handleClick(t,n)}},t.title)})),_react2["default"].createElement("div",{className:"menu"},_react2["default"].createElement(n,{ref:"active",settings:a,updateLocation:u,query:i})))}}]),t}(_react.Component);Header.entries=[_MainMenu2["default"],_ViewMenu2["default"],_OptionMenu2["default"]],Header.propTypes={settings:_react.PropTypes.object.isRequired},exports["default"]=Header;
+
+},{"../ducks/eventLog":32,"./Header/FileMenu":12,"./Header/MainMenu":15,"./Header/OptionMenu":16,"./Header/ViewMenu":17,"classnames":"classnames","react":"react"}],12:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(t,n,a){return n&&e(t.prototype,n),a&&e(t,a),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_actions=require("../../actions.js"),FileMenu=function(e){function t(e,n){_classCallCheck(this,t);var a=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,n));return a.state={show:!1},a.close=a.close.bind(a),a.onFileClick=a.onFileClick.bind(a),a.onNewClick=a.onNewClick.bind(a),a.onOpenClick=a.onOpenClick.bind(a),a.onOpenFile=a.onOpenFile.bind(a),a.onSaveClick=a.onSaveClick.bind(a),a}return _inherits(t,e),_createClass(t,[{key:"close",value:function(){this.setState({show:!1}),document.removeEventListener("click",this.close)}},{key:"onFileClick",value:function(e){e.preventDefault(),this.state.show||(document.addEventListener("click",this.close),this.setState({show:!0}))}},{key:"onNewClick",value:function(e){e.preventDefault(),confirm("Delete all flows?")&&_actions.FlowActions.clear()}},{key:"onOpenClick",value:function(e){e.preventDefault(),this.fileInput.click()}},{key:"onOpenFile",value:function(e){e.preventDefault(),e.target.files.length>0&&(_actions.FlowActions.upload(e.target.files[0]),this.fileInput.value="")}},{key:"onSaveClick",value:function(e){e.preventDefault(),_actions.FlowActions.download()}},{key:"render",value:function(){var e=this;return _react2["default"].createElement("div",{className:(0,_classnames2["default"])("dropdown pull-left",{open:this.state.show})},_react2["default"].createElement("a",{href:"#",className:"special",onClick:this.onFileClick},"mitmproxy"),_react2["default"].createElement("ul",{className:"dropdown-menu",role:"menu"},_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.onNewClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-file"}),"New")),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.onOpenClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-folder-open"}),"Open..."),_react2["default"].createElement("input",{ref:function(t){return e.fileInput=t},className:"hidden",type:"file",onChange:this.onOpenFile})),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.onSaveClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-floppy-o"}),"Save...")),_react2["default"].createElement("li",{role:"presentation",className:"divider"}),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"http://mitm.it/",target:"_blank"},_react2["default"].createElement("i",{className:"fa fa-fw fa-external-link"}),"Install Certificates..."))))}}]),t}(_react.Component);exports["default"]=FileMenu;
+
+},{"../../actions.js":2,"classnames":"classnames","react":"react"}],13:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),FilterDocs=function(e){function t(e,r){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return n.state={doc:t.doc},n}return _inherits(t,e),_createClass(t,[{key:"componentWillMount",value:function(){var e=this;t.xhr||(t.xhr=_jquery2["default"].getJSON("/filter-help"),t.xhr.fail(function(){t.xhr=null})),this.state.doc||t.xhr.done(function(r){t.doc=r,e.setState({doc:r})})}},{key:"render",value:function(){var e=this.state.doc;return e?_react2["default"].createElement("table",{className:"table table-condensed"},_react2["default"].createElement("tbody",null,e.commands.map(function(e){return _react2["default"].createElement("tr",{key:e[1]},_react2["default"].createElement("td",null,e[0].replace(" "," ")),_react2["default"].createElement("td",null,e[1]))}),_react2["default"].createElement("tr",{key:"docs-link"},_react2["default"].createElement("td",{colSpan:"2"},_react2["default"].createElement("a",{href:"http://docs.mitmproxy.org/en/stable/features/filters.html",target:"_blank"},_react2["default"].createElement("i",{className:"fa fa-external-link"}),"&nbsp mitmproxy docs"))))):_react2["default"].createElement("i",{className:"fa fa-spinner fa-spin"})}}]),t}(_react.Component);FilterDocs.xhr=null,FilterDocs.doc=null,exports["default"]=FilterDocs;
+
+},{"jquery":"jquery","react":"react"}],14:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_utils=require("../../utils.js"),_filt=require("../../filt/filt"),_filt2=_interopRequireDefault(_filt),_FilterDocs=require("./FilterDocs"),_FilterDocs2=_interopRequireDefault(_FilterDocs),FilterInput=function(e){function t(e,n){_classCallCheck(this,t);var o=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,n));return o.state={value:o.props.value,focus:!1,mousefocus:!1},o.onChange=o.onChange.bind(o),o.onFocus=o.onFocus.bind(o),o.onBlur=o.onBlur.bind(o),o.onKeyDown=o.onKeyDown.bind(o),o.onMouseEnter=o.onMouseEnter.bind(o),o.onMouseLeave=o.onMouseLeave.bind(o),o}return _inherits(t,e),_createClass(t,[{key:"componentWillReceiveProps",value:function(e){this.setState({value:e.value})}},{key:"isValid",value:function(e){try{var t=null==e?this.state.value:e;return t&&_filt2["default"].parse(t),!0}catch(n){return!1}}},{key:"getDesc",value:function(){if(!this.state.value)return _react2["default"].createElement(_FilterDocs2["default"],null);try{return _filt2["default"].parse(this.state.value).desc}catch(e){return""+e}}},{key:"onChange",value:function(e){var t=e.target.value;this.setState({value:t}),this.isValid(t)&&this.props.onChange(t)}},{key:"onFocus",value:function(){this.setState({focus:!0})}},{key:"onBlur",value:function(){this.setState({focus:!1})}},{key:"onMouseEnter",value:function(){this.setState({mousefocus:!0})}},{key:"onMouseLeave",value:function(){this.setState({mousefocus:!1})}},{key:"onKeyDown",value:function(e){e.keyCode!==_utils.Key.ESC&&e.keyCode!==_utils.Key.ENTER||(this.blur(),this.setState({mousefocus:!1})),e.stopPropagation()}},{key:"blur",value:function(){_reactDom2["default"].findDOMNode(this.refs.input).blur(),this.context.returnFocus()}},{key:"select",value:function(){_reactDom2["default"].findDOMNode(this.refs.input).select()}},{key:"render",value:function(){var e=this.props,t=e.type,n=e.color,o=e.placeholder,r=this.state,a=r.value,u=r.focus,s=r.mousefocus;return _react2["default"].createElement("div",{className:(0,_classnames2["default"])("filter-input input-group",{"has-error":!this.isValid()})},_react2["default"].createElement("span",{className:"input-group-addon"},_react2["default"].createElement("i",{className:"fa fa-fw fa-"+t,style:{color:n}})),_react2["default"].createElement("input",{type:"text",ref:"input",placeholder:o,className:"form-control",value:a,onChange:this.onChange,onFocus:this.onFocus,onBlur:this.onBlur,onKeyDown:this.onKeyDown}),(u||s)&&_react2["default"].createElement("div",{className:"popover bottom",onMouseEnter:this.onMouseEnter,onMouseLeave:this.onMouseLeave},_react2["default"].createElement("div",{className:"arrow"}),_react2["default"].createElement("div",{className:"popover-content"},this.getDesc())))}}]),t}(_react.Component);FilterInput.contextTypes={returnFocus:_react2["default"].PropTypes.func},exports["default"]=FilterInput;
+
+},{"../../filt/filt":38,"../../utils.js":41,"./FilterDocs":13,"classnames":"classnames","react":"react","react-dom":"react-dom"}],15:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_actions=require("../../actions.js"),_FilterInput=require("./FilterInput"),_FilterInput2=_interopRequireDefault(_FilterInput),MainMenu=function(e){function t(e,n){_classCallCheck(this,t);var r=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,n));return r.onSearchChange=r.onSearchChange.bind(r),r.onHighlightChange=r.onHighlightChange.bind(r),r.onInterceptChange=r.onInterceptChange.bind(r),r}return _inherits(t,e),_createClass(t,[{key:"onSearchChange",value:function(e){this.props.updateLocation(void 0,_defineProperty({},_actions.Query.SEARCH,e))}},{key:"onHighlightChange",value:function(e){this.props.updateLocation(void 0,_defineProperty({},_actions.Query.HIGHLIGHT,e))}},{key:"onInterceptChange",value:function(e){_actions.SettingsActions.update({intercept:e})}},{key:"render",value:function(){var e=this.props,t=e.query,n=e.settings,r=t[_actions.Query.SEARCH]||"",a=t[_actions.Query.HIGHLIGHT]||"",o=n.intercept||"";return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_FilterInput2["default"],{ref:"search",placeholder:"Search",type:"search",color:"black",value:r,onChange:this.onSearchChange}),_react2["default"].createElement(_FilterInput2["default"],{ref:"highlight",placeholder:"Highlight",type:"tag",color:"hsl(48, 100%, 50%)",value:a,onChange:this.onHighlightChange}),_react2["default"].createElement(_FilterInput2["default"],{ref:"intercept",placeholder:"Intercept",type:"pause",color:"hsl(208, 56%, 53%)",value:o,onChange:this.onInterceptChange})),_react2["default"].createElement("div",{className:"clearfix"}))}}]),t}(_react.Component);MainMenu.title="Start",MainMenu.route="flows",MainMenu.propTypes={settings:_react2["default"].PropTypes.object.isRequired},exports["default"]=MainMenu;
-},{"../utils.js":32,"react":"react","react-dom":"react-dom"}],8:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function LogIcon(e){var t=e.event,n={web:"html5",debug:"bug"}[t.level]||"info";return _react2["default"].createElement("i",{className:"fa fa-fw fa-"+n})}function LogEntry(e){var t=e.event,n=e.registerHeight;return _react2["default"].createElement("div",{ref:n},_react2["default"].createElement(LogIcon,{event:t}),t.message)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToggleEventLog=void 0;var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_reactRedux=require("react-redux"),_shallowequal=require("shallowequal"),_shallowequal2=_interopRequireDefault(_shallowequal),_eventLog=require("../ducks/eventLog"),_AutoScroll=require("./helpers/AutoScroll"),_AutoScroll2=_interopRequireDefault(_AutoScroll),_VirtualScroll=require("./helpers/VirtualScroll"),_common=require("./common"),EventLogContents=function(e){function t(e){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e));return n.heights={},n.state={vScroll:(0,_VirtualScroll.calcVScroll)()},n.onViewportUpdate=n.onViewportUpdate.bind(n),n}return _inherits(t,e),_createClass(t,[{key:"componentDidMount",value:function(){window.addEventListener("resize",this.onViewportUpdate),this.onViewportUpdate()}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onViewportUpdate)}},{key:"componentDidUpdate",value:function(){this.onViewportUpdate()}},{key:"onViewportUpdate",value:function(){var e=this,t=_reactDom2["default"].findDOMNode(this),n=(0,_VirtualScroll.calcVScroll)({itemCount:this.props.events.length,rowHeight:this.props.rowHeight,viewportTop:t.scrollTop,viewportHeight:t.offsetHeight,itemHeights:this.props.events.map(function(t){return e.heights[t.id]})});(0,_shallowequal2["default"])(this.state.vScroll,n)||this.setState({vScroll:n})}},{key:"setHeight",value:function(e,t){if(t&&!this.heights[e]){var n=t.offsetHeight;this.heights[e]!==n&&(this.heights[e]=n,this.onViewportUpdate())}}},{key:"render",value:function(){var e=this,t=this.state.vScroll,n=this.props.events.slice(t.start,t.end).map(function(t){return _react2["default"].createElement(LogEntry,{event:t,key:t.id,registerHeight:function(n){return e.setHeight(t.id,n)}})});return _react2["default"].createElement("pre",{onScroll:this.onViewportUpdate},_react2["default"].createElement("div",{style:{height:t.paddingTop}}),n,_react2["default"].createElement("div",{style:{height:t.paddingBottom}}))}}]),t}(_react2["default"].Component);EventLogContents.defaultProps={rowHeight:18},EventLogContents=(0,_AutoScroll2["default"])(EventLogContents);var EventLogContentsContainer=(0,_reactRedux.connect)(function(e){return{events:e.eventLog.filteredEvents}})(EventLogContents),ToggleEventLog=exports.ToggleEventLog=(0,_reactRedux.connect)(function(e){return{checked:e.eventLog.visible}},function(e){return{onToggle:function(){return e((0,_eventLog.toggleEventLogVisibility)())}}})(_common.ToggleButton),ToggleFilter=(0,_reactRedux.connect)(function(e,t){return{checked:e.eventLog.filter[t.text]}},function(e,t){return{onToggle:function(){return e((0,_eventLog.toggleEventLogFilter)(t.text))}}})(_common.ToggleButton),EventLog=function(e){var t=e.close;return _react2["default"].createElement("div",{className:"eventlog"},_react2["default"].createElement("div",null,"Eventlog",_react2["default"].createElement("div",{className:"pull-right"},_react2["default"].createElement(ToggleFilter,{text:"debug"}),_react2["default"].createElement(ToggleFilter,{text:"info"}),_react2["default"].createElement(ToggleFilter,{text:"web"}),_react2["default"].createElement("i",{onClick:t,className:"fa fa-close"}))),_react2["default"].createElement(EventLogContentsContainer,null))};EventLog.propTypes={close:_react2["default"].PropTypes.func.isRequired};var EventLogContainer=(0,_reactRedux.connect)(void 0,function(e){return{close:function(){return e((0,_eventLog.toggleEventLogVisibility)())}}})(EventLog);exports["default"]=EventLogContainer;
+},{"../../actions.js":2,"./FilterInput":14,"react":"react"}],16:[function(require,module,exports){
+"use strict";function _interopRequireDefault(t){return t&&t.__esModule?t:{"default":t}}function OptionMenu(t){var e=t.settings;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_common.ToggleButton,{text:"showhost",checked:e.showhost,onToggle:function(){return _actions.SettingsActions.update({showhost:!e.showhost})}}),_react2["default"].createElement(_common.ToggleButton,{text:"no_upstream_cert",checked:e.no_upstream_cert,onToggle:function(){return _actions.SettingsActions.update({no_upstream_cert:!e.no_upstream_cert})}}),_react2["default"].createElement(_common.ToggleButton,{text:"rawtcp",checked:e.rawtcp,onToggle:function(){return _actions.SettingsActions.update({rawtcp:!e.rawtcp})}}),_react2["default"].createElement(_common.ToggleButton,{text:"http2",checked:e.http2,onToggle:function(){return _actions.SettingsActions.update({http2:!e.http2})}}),_react2["default"].createElement(_common.ToggleButton,{text:"anticache",checked:e.anticache,onToggle:function(){return _actions.SettingsActions.update({anticache:!e.anticache})}}),_react2["default"].createElement(_common.ToggleButton,{text:"anticomp",checked:e.anticomp,onToggle:function(){return _actions.SettingsActions.update({anticomp:!e.anticomp})}}),_react2["default"].createElement(_common.ToggleInputButton,{name:"stickyauth",placeholder:"Sticky auth filter",checked:!!e.stickyauth,txt:e.stickyauth||"",onToggleChanged:function(t){return _actions.SettingsActions.update({stickyauth:e.stickyauth?null:t})}}),_react2["default"].createElement(_common.ToggleInputButton,{name:"stickycookie",placeholder:"Sticky cookie filter",checked:!!e.stickycookie,txt:e.stickycookie||"",onToggleChanged:function(t){return _actions.SettingsActions.update({stickycookie:e.stickycookie?null:t})}}),_react2["default"].createElement(_common.ToggleInputButton,{name:"stream",placeholder:"stream...",checked:!!e.stream,txt:e.stream||"",inputType:"number",onToggleChanged:function(t){return _actions.SettingsActions.update({stream:e.stream?null:t})}})),_react2["default"].createElement("div",{className:"clearfix"}))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=OptionMenu;var _react=require("react"),_react2=_interopRequireDefault(_react),_common=require("../common.js"),_actions=require("../../actions.js");OptionMenu.title="Options",OptionMenu.propTypes={settings:_react.PropTypes.object.isRequired};
-},{"../ducks/eventLog":23,"./common":6,"./helpers/AutoScroll":18,"./helpers/VirtualScroll":19,"react":"react","react-dom":"react-dom","react-redux":"react-redux","shallowequal":"shallowequal"}],9:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _objectWithoutProperties(e,t){var o={};for(var r in e)t.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(e,r)&&(o[r]=e[r]);return o}function TLSColumn(e){var t=e.flow,o="https"===t.request.scheme,r=void 0;return r=o?"col-tls col-tls-https":"col-tls col-tls-http",_react2["default"].createElement("td",{className:r})}function IconColumn(e){var t=e.flow,o=void 0;if(t.response){var r=_utils.ResponseUtils.getContentType(t.response);304===t.response.status_code?o="resource-icon-not-modified":300<=t.response.status_code&&t.response.status_code<400?o="resource-icon-redirect":r&&r.indexOf("image")>=0?o="resource-icon-image":r&&r.indexOf("javascript")>=0?o="resource-icon-js":r&&r.indexOf("css")>=0?o="resource-icon-css":r&&r.indexOf("html")>=0&&(o="resource-icon-document")}return o||(o="resource-icon-plain"),o+=" resource-icon",_react2["default"].createElement("td",{className:"col-icon"},_react2["default"].createElement("div",{className:o}))}function PathColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-path"},t.request.is_replay?_react2["default"].createElement("i",{className:"fa fa-fw fa-repeat pull-right"}):null,t.intercepted?_react2["default"].createElement("i",{className:"fa fa-fw fa-pause pull-right"}):null,_utils.RequestUtils.pretty_url(t.request))}function MethodColumn(e){var t=e.flow;return _react2["default"].createElement("td",{className:"col-method"},t.request.method)}function StatusColumn(e){var t=e.flow,o=void 0;return o=t.response?t.response.status_code:null,_react2["default"].createElement("td",{className:"col-status"},o)}function SizeColumn(e){var t=e.flow,o=t.request.contentLength;t.response&&(o+=t.response.contentLength||0);var r=(0,_utils2.formatSize)(o);return _react2["default"].createElement("td",{className:"col-size"},r)}function TimeColumn(e){var t=e.flow,o=void 0;return o=t.response?(0,_utils2.formatTimeDelta)(1e3*(t.response.timestamp_end-t.request.timestamp_start)):"...",_react2["default"].createElement("td",{className:"col-time"},o)}Object.defineProperty(exports,"__esModule",{value:!0});var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var o=arguments[t];for(var r in o)Object.prototype.hasOwnProperty.call(o,r)&&(e[r]=o[r])}return e};exports.TLSColumn=TLSColumn,exports.IconColumn=IconColumn,exports.PathColumn=PathColumn,exports.MethodColumn=MethodColumn,exports.StatusColumn=StatusColumn,exports.SizeColumn=SizeColumn,exports.TimeColumn=TimeColumn;var _react=require("react"),_react2=_interopRequireDefault(_react),_utils=require("../flow/utils.js"),_utils2=require("../utils.js");TLSColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-tls "+o}))},TLSColumn.sortKeyFun=function(e){return e.request.scheme},IconColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-icon "+o}))},PathColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-path "+o}),"Path")},PathColumn.sortKeyFun=function(e){return _utils.RequestUtils.pretty_url(e.request)},MethodColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-method "+o}),"Method")},MethodColumn.sortKeyFun=function(e){return e.request.method},StatusColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-status "+o}),"Status")},StatusColumn.sortKeyFun=function(e){return e.response?e.response.status_code:void 0},SizeColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-size "+o}),"Size")},SizeColumn.sortKeyFun=function(e){var t=e.request.contentLength;return e.response&&(t+=e.response.contentLength||0),t},TimeColumn.Title=function(e){var t=e.className,o=void 0===t?"":t,r=_objectWithoutProperties(e,["className"]);return _react2["default"].createElement("th",_extends({},r,{className:"col-time "+o}),"Time")},TimeColumn.sortKeyFun=function(e){return e.response.timestamp_end-e.request.timestamp_start};var all_columns=[TLSColumn,IconColumn,PathColumn,MethodColumn,StatusColumn,SizeColumn,TimeColumn];exports["default"]=all_columns;
+},{"../../actions.js":2,"../common.js":20,"react":"react"}],17:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function ViewMenu(e){var t=e.visible,r=e.onToggle;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_common.ToggleButton,{text:"Show Event Log",checked:t,onToggle:r})),_react2["default"].createElement("div",{className:"clearfix"}))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_redux=require("redux"),_reactRedux=require("react-redux"),_common=require("../common.js"),_eventLog=require("../../ducks/eventLog");ViewMenu.title="View",ViewMenu.route="flows",ViewMenu.propTypes={visible:_react.PropTypes.bool.isRequired,onToggle:_react.PropTypes.func.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{visible:e.eventLog.visible}},function(e){return(0,_redux.bindActionCreators)({onToggle:_eventLog.toggleEventLogVisibility},e)})(ViewMenu);
-},{"../flow/utils.js":30,"../utils.js":32,"react":"react"}],10:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function FlowRow(e){var t=e.flow,r=e.selected,o=e.highlight,l=e.columns,a=e.selectFlow,n=(0,_classnames2["default"])({selected:r,highlighted:o&&parseFilter(o)(t),intercepted:t.intercepted,"has-request":t.request,"has-response":t.response});return _react2["default"].createElement("tr",{className:n,onClick:function(){return a(t)}},l.map(function(e){return _react2["default"].createElement(e,{key:e.name,flow:t})}))}function FlowTableHead(e){var t=e.setSort,r=e.columns,o=e.sort,l=o.sortColumn,a=o.sortDesc?"sort-desc":"sort-asc";return _react2["default"].createElement("tr",null,r.map(function(e){return _react2["default"].createElement(e.Title,{key:e.name,onClick:function(){return t({sortColumn:e.name,sortDesc:e.name!=o.sortColumn?!1:!o.sortDesc})},className:l===e.name?a:void 0})}))}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var o=t[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,r,o){return r&&e(t.prototype,r),o&&e(t,o),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_reactRedux=require("react-redux"),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_shallowequal=require("shallowequal"),_shallowequal2=_interopRequireDefault(_shallowequal),_AutoScroll=require("./helpers/AutoScroll"),_AutoScroll2=_interopRequireDefault(_AutoScroll),_VirtualScroll=require("./helpers/VirtualScroll"),_flowtableColumns=require("./flowtable-columns.js"),_flowtableColumns2=_interopRequireDefault(_flowtableColumns),_filt=require("../filt/filt"),_filt2=_interopRequireDefault(_filt),_flows=require("../ducks/flows");FlowRow.propTypes={selectFlow:_react2["default"].PropTypes.func.isRequired,columns:_react2["default"].PropTypes.array.isRequired,flow:_react2["default"].PropTypes.object.isRequired,highlight:_react2["default"].PropTypes.string,selected:_react2["default"].PropTypes.bool};var FlowRowContainer=(0,_reactRedux.connect)(function(e,t){return{flow:e.flows.all.byId[t.flowId],highlight:e.flows.highlight,selected:e.flows.selected.indexOf(t.flowId)>=0}})(FlowRow);FlowTableHead.propTypes={setSort:_react2["default"].PropTypes.func.isRequired,sort:_react2["default"].PropTypes.object.isRequired,columns:_react2["default"].PropTypes.array.isRequired};var FlowTableHeadContainer=(0,_reactRedux.connect)(function(e){return{sort:e.flows.sort}},function(e){return{setSort:function(t){return e((0,_flows.setSort)(t))}}})(FlowTableHead),FlowTable=function(e){function t(e,r){_classCallCheck(this,t);var o=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return o.state={vScroll:(0,_VirtualScroll.calcVScroll)()},o.onViewportUpdate=o.onViewportUpdate.bind(o),o}return _inherits(t,e),_createClass(t,[{key:"componentWillMount",value:function(){window.addEventListener("resize",this.onViewportUpdate)}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onViewportUpdate)}},{key:"componentWillReceiveProps",value:function(e){var t=this;e.selected&&e.selected!==this.props.selected&&window.setTimeout(function(){return t.scrollIntoView(e.selected)},1)}},{key:"componentDidUpdate",value:function(){this.onViewportUpdate()}},{key:"onViewportUpdate",value:function(){var e=_reactDom2["default"].findDOMNode(this),t=e.scrollTop,r=(0,_VirtualScroll.calcVScroll)({viewportTop:t,viewportHeight:e.offsetHeight,itemCount:this.props.flows.length,rowHeight:this.props.rowHeight});(0,_shallowequal2["default"])(this.state.vScroll,r)&&this.state.viewportTop===t||this.setState({vScroll:r,viewportTop:t})}},{key:"scrollIntoView",value:function(e){var t=_reactDom2["default"].findDOMNode(this),r=this.props.flows.indexOf(e),o=this.props.rowHeight,l=_reactDom2["default"].findDOMNode(this.refs.head),a=l?l.offsetHeight:0,n=r*o+a,s=n+o,i=t.scrollTop,u=t.offsetHeight;i>n-a?t.scrollTop=n-a:s>i+u&&(t.scrollTop=s-u)}},{key:"render",value:function(){var e=this,t=this.state.vScroll,r=this.props.flows.slice(t.start,t.end),o="translate(0,"+this.state.viewportTop+"px)";return _react2["default"].createElement("div",{className:"flow-table",onScroll:this.onViewportUpdate},_react2["default"].createElement("table",null,_react2["default"].createElement("thead",{ref:"head",style:{transform:o}},_react2["default"].createElement(FlowTableHeadContainer,{columns:_flowtableColumns2["default"],setSortKeyFun:this.props.setSortKeyFun,setSort:this.props.setSort})),_react2["default"].createElement("tbody",null,_react2["default"].createElement("tr",{style:{height:t.paddingTop}}),r.map(function(t){return _react2["default"].createElement(FlowRowContainer,{key:t.id,flowId:t.id,columns:_flowtableColumns2["default"],selectFlow:e.props.selectFlow})}),_react2["default"].createElement("tr",{style:{height:t.paddingBottom}}))))}}]),t}(_react2["default"].Component);FlowTable.propTypes={rowHeight:_react2["default"].PropTypes.number},FlowTable.defaultProps={rowHeight:32},FlowTable=(0,_AutoScroll2["default"])(FlowTable);var parseFilter=_lodash2["default"].memoize(_filt2["default"].parse),FlowTableContainer=(0,_reactRedux.connect)(function(e){return{flows:e.flows.view}})(FlowTable);exports["default"]=FlowTableContainer;
+},{"../../ducks/eventLog":32,"../common.js":20,"react":"react","react-redux":"react-redux","redux":"redux"}],18:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var s=0;s<t.length;s++){var i=t[s];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,s,i){return s&&e(t.prototype,s),i&&e(t,i),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_redux=require("redux"),_actions=require("../actions.js"),_utils=require("../utils.js"),_common=require("./common.js"),_FlowTable=require("./FlowTable"),_FlowTable2=_interopRequireDefault(_FlowTable),_index=require("./flowview/index.js"),_index2=_interopRequireDefault(_index),_flows=require("../ducks/flows"),MainView=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,Object.getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),_createClass(t,[{key:"componentWillReceiveProps",value:function(e){e.routeParams.flowId!==(e.selectedFlow||{}).id&&this.props.selectFlow(e.routeParams.flowId),e.location.query[_actions.Query.SEARCH]!==e.filter&&this.props.setFilter(e.location.query[_actions.Query.SEARCH],!1),e.location.query[_actions.Query.HIGHLIGHT]!==e.highlight&&this.props.setHighlight(e.location.query[_actions.Query.HIGHLIGHT],!1)}},{key:"selectFlow",value:function(e){e?this.props.updateLocation("/flows/"+e.id+"/"+(this.props.routeParams.detailTab||"request")):this.props.updateLocation("/flows")}},{key:"selectFlowRelative",value:function(e){var t=this.props,s=t.flows,i=t.routeParams,l=t.selectedFlow,o=0;i.flowId?o=Math.min(Math.max(0,s.indexOf(l)+e),s.length-1):0>e&&(o=s.length-1),this.selectFlow(s[o])}},{key:"onMainKeyDown",value:function(e){var t=this.props.selectedFlow;if(!e.ctrlKey){switch(e.keyCode){case _utils.Key.K:case _utils.Key.UP:this.selectFlowRelative(-1);break;case _utils.Key.J:case _utils.Key.DOWN:this.selectFlowRelative(1);break;case _utils.Key.SPACE:case _utils.Key.PAGE_DOWN:this.selectFlowRelative(10);break;case _utils.Key.PAGE_UP:this.selectFlowRelative(-10);break;case _utils.Key.END:this.selectFlowRelative(1e10);break;case _utils.Key.HOME:this.selectFlowRelative(-1e10);break;case _utils.Key.ESC:this.selectFlow(null);break;case _utils.Key.H:case _utils.Key.LEFT:this.refs.flowDetails&&this.refs.flowDetails.nextTab(-1);break;case _utils.Key.L:case _utils.Key.TAB:case _utils.Key.RIGHT:this.refs.flowDetails&&this.refs.flowDetails.nextTab(1);break;case _utils.Key.C:e.shiftKey&&_actions.FlowActions.clear();break;case _utils.Key.D:t&&(e.shiftKey?_actions.FlowActions.duplicate(t):_actions.FlowActions["delete"](t));break;case _utils.Key.A:e.shiftKey?_actions.FlowActions.accept_all():t&&t.intercepted&&_actions.FlowActions.accept(t);break;case _utils.Key.R:!e.shiftKey&&t&&_actions.FlowActions.replay(t);break;case _utils.Key.V:e.shiftKey&&t&&t.modified&&_actions.FlowActions.revert(t);break;case _utils.Key.E:this.refs.flowDetails&&this.refs.flowDetails.promptEdit();break;case _utils.Key.SHIFT:break;default:return void console.debug("keydown",e.keyCode)}e.preventDefault()}}},{key:"render",value:function(){var e=this,t=this.props,s=t.flows,i=t.selectedFlow,l=t.highlight;t.sort;return _react2["default"].createElement("div",{className:"main-view"},_react2["default"].createElement(_FlowTable2["default"],{ref:"flowTable",flows:s,selected:i,highlight:l,onSelect:function(t){return e.selectFlow(t)}}),i&&[_react2["default"].createElement(_common.Splitter,{key:"splitter"}),_react2["default"].createElement(_index2["default"],{key:"flowDetails",ref:"flowDetails",tab:this.props.routeParams.detailTab,query:this.props.query,updateLocation:this.props.updateLocation,flow:i})])}}]),t}(_react.Component);MainView.propTypes={highlight:_react.PropTypes.string,sort:_react.PropTypes.object},exports["default"]=(0,_reactRedux.connect)(function(e){return{flows:e.flows.view,filter:e.flows.filter,sort:e.flows.sort,highlight:e.flows.highlight,selectedFlow:e.flows.all.byId[e.flows.selected[0]]}},function(e){return(0,_redux.bindActionCreators)({selectFlow:_flows.selectFlow,setFilter:_flows.setFilter,setHighlight:_flows.setHighlight},e)},void 0,{withRef:!0})(MainView);
-},{"../ducks/flows":24,"../filt/filt":29,"./flowtable-columns.js":9,"./helpers/AutoScroll":18,"./helpers/VirtualScroll":19,"classnames":"classnames","lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux","shallowequal":"shallowequal"}],11:[function(require,module,exports){
+},{"../actions.js":2,"../ducks/flows":33,"../utils.js":41,"./FlowTable":6,"./common.js":20,"./flowview/index.js":24,"react":"react","react-redux":"react-redux","redux":"redux"}],19:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_reactRedux=require("react-redux"),_common=require("./common.js"),_Header=require("./Header"),_Header2=_interopRequireDefault(_Header),_EventLog=require("./EventLog"),_EventLog2=_interopRequireDefault(_EventLog),_Footer=require("./Footer"),_Footer2=_interopRequireDefault(_Footer),_store=require("../store/store.js"),_utils=require("../utils.js"),ProxyAppMain=function(e){function t(e,r){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return n.settingsStore=new _store.SettingsStore,_lodash2["default"].extend(n.settingsStore.dict,{}),n.state={settings:n.settingsStore.dict},n.focus=n.focus.bind(n),n.onKeyDown=n.onKeyDown.bind(n),n.updateLocation=n.updateLocation.bind(n),n.onSettingsChange=n.onSettingsChange.bind(n),n}return _inherits(t,e),_createClass(t,[{key:"updateLocation",value:function(e,t){void 0===e&&(e=this.props.location.pathname);var r=this.props.location.query,n=!0,o=!1,i=void 0;try{for(var a,s=Object.keys(t||{})[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var u=a.value;r[u]=t[u]||void 0}}catch(c){o=!0,i=c}finally{try{!n&&s["return"]&&s["return"]()}finally{if(o)throw i}}this.context.router.replace({pathname:e,query:r})}},{key:"getQuery",value:function(){return _lodash2["default"].clone(this.props.location.query)}},{key:"componentDidMount",value:function(){this.focus(),this.settingsStore.addListener("recalculate",this.onSettingsChange)}},{key:"componentWillUnmount",value:function(){this.settingsStore.removeListener("recalculate",this.onSettingsChange)}},{key:"onSettingsChange",value:function(){this.setState({settings:this.settingsStore.dict})}},{key:"getChildContext",value:function(){return{returnFocus:this.focus,location:this.props.location}}},{key:"focus",value:function(){document.activeElement.blur(),window.getSelection().removeAllRanges(),_reactDom2["default"].findDOMNode(this).focus()}},{key:"onKeyDown",value:function(e){var t=this,r=null;switch(e.keyCode){case _utils.Key.I:r="intercept";break;case _utils.Key.L:r="search";break;case _utils.Key.H:r="highlight";break;default:var n=this.refs.view;return this.refs.view.getWrappedInstance&&(n=this.refs.view.getWrappedInstance()),void(n.onMainKeyDown&&n.onMainKeyDown(e))}r&&!function(){var e=t.refs.header;e.setState({active:_Header2["default"].entries.MainMenu},function(){e.refs.active.refs[r].select()})}(),e.preventDefault()}},{key:"render",value:function(){var e=this.props,t=e.showEventLog,r=e.location,n=e.children,o=this.state.settings,i=this.getQuery();return _react2["default"].createElement("div",{id:"container",tabIndex:"0",onKeyDown:this.onKeyDown},_react2["default"].createElement(_Header2["default"],{ref:"header",settings:o,updateLocation:this.updateLocation,query:i}),_react2["default"].cloneElement(n,{ref:"view",location:r,query:i,updateLocation:this.updateLocation}),t&&[_react2["default"].createElement(_common.Splitter,{key:"splitter",axis:"y"}),_react2["default"].createElement(_EventLog2["default"],{key:"eventlog"})],_react2["default"].createElement(_Footer2["default"],{settings:o}))}}]),t}(_react.Component);ProxyAppMain.childContextTypes={returnFocus:_react.PropTypes.func.isRequired,location:_react.PropTypes.object.isRequired},ProxyAppMain.contextTypes={router:_react.PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{showEventLog:e.eventLog.visible}})(ProxyAppMain);
+
+},{"../store/store.js":40,"../utils.js":41,"./EventLog":4,"./Footer":10,"./Header":11,"./common.js":20,"lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux"}],20:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToggleInputButton=exports.ToggleButton=exports.Splitter=void 0;var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_utils=require("../utils.js"),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),Splitter=exports.Splitter=_react2["default"].createClass({displayName:"Splitter",getDefaultProps:function(){return{axis:"x"}},getInitialState:function(){return{applied:!1,startX:!1,startY:!1}},onMouseDown:function(e){this.setState({startX:e.pageX,startY:e.pageY}),window.addEventListener("mousemove",this.onMouseMove),window.addEventListener("mouseup",this.onMouseUp),window.addEventListener("dragend",this.onDragEnd)},onDragEnd:function(){_reactDom2["default"].findDOMNode(this).style.transform="",window.removeEventListener("dragend",this.onDragEnd),window.removeEventListener("mouseup",this.onMouseUp),window.removeEventListener("mousemove",this.onMouseMove)},onMouseUp:function(e){this.onDragEnd();var t,n=_reactDom2["default"].findDOMNode(this),r=n.previousElementSibling,o=n.nextElementSibling,a=e.pageX-this.state.startX,s=e.pageY-this.state.startY;t="x"===this.props.axis?r.offsetWidth+a:r.offsetHeight+s,r.style.flex="0 0 "+Math.max(0,t)+"px",o.style.flex="1 1 auto",this.setState({applied:!0}),this.onResize()},onMouseMove:function(e){var t=0,n=0;"x"===this.props.axis?t=e.pageX-this.state.startX:n=e.pageY-this.state.startY,_reactDom2["default"].findDOMNode(this).style.transform="translate("+t+"px,"+n+"px)"},onResize:function(){window.setTimeout(function(){window.dispatchEvent(new CustomEvent("resize"))},1)},reset:function(e){if(this.state.applied){var t=_reactDom2["default"].findDOMNode(this),n=t.previousElementSibling,r=t.nextElementSibling;n.style.flex="",r.style.flex="",e||this.setState({applied:!1}),this.onResize()}},componentWillUnmount:function(){this.reset(!0)},render:function(){var e="splitter";return e+="x"===this.props.axis?" splitter-x":" splitter-y",_react2["default"].createElement("div",{className:e},_react2["default"].createElement("div",{onMouseDown:this.onMouseDown,draggable:"true"}))}}),ToggleButton=exports.ToggleButton=function(e){var t=e.checked,n=e.onToggle,r=e.text;return _react2["default"].createElement("div",{className:"btn btn-toggle "+(t?"btn-primary":"btn-default"),onClick:n},_react2["default"].createElement("i",{className:"fa fa-fw "+(t?"fa-check-square-o":"fa-square-o")})," ",r)};ToggleButton.propTypes={checked:_react2["default"].PropTypes.bool.isRequired,onToggle:_react2["default"].PropTypes.func.isRequired,text:_react2["default"].PropTypes.string.isRequired};var ToggleInputButton=exports.ToggleInputButton=function(e){function t(e){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e));return n.state={txt:e.txt},n}return _inherits(t,e),_createClass(t,[{key:"render",value:function(){var e=this;return _react2["default"].createElement("div",{className:"input-group toggle-input-btn"},_react2["default"].createElement("span",{className:"input-group-btn",onClick:function(){return e.props.onToggleChanged(e.state.txt)}},_react2["default"].createElement("div",{className:"btn "+(this.props.checked?"btn-primary":"btn-default")},_react2["default"].createElement("span",{className:"fa "+(this.props.checked?"fa-check-square-o":"fa-square-o")})," ",this.props.name)),_react2["default"].createElement("input",{className:"form-control",placeholder:this.props.placeholder,disabled:this.props.checked,value:this.state.txt,type:this.props.inputType,onChange:function(t){return e.setState({txt:t.target.value})},onKeyDown:function(t){t.keyCode===_utils.Key.ENTER&&e.props.onToggleChanged(e.state.txt),t.stopPropagation()}}))}}]),t}(_react2["default"].Component);ToggleInputButton.propTypes={name:_react2["default"].PropTypes.string.isRequired,txt:_react2["default"].PropTypes.string.isRequired,onToggleChanged:_react2["default"].PropTypes.func.isRequired};
+
+},{"../utils.js":41,"lodash":"lodash","react":"react","react-dom":"react-dom"}],21:[function(require,module,exports){
+"use strict";function _interopRequireDefault(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ValueEditor=void 0;var _extends=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var o=arguments[e];for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&(t[n]=o[n])}return t},_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_utils=require("../utils.js"),contentToHtml=function(t){return _.escape(t)},nodeToContent=function(t){return t.textContent},EditorBase=_react2["default"].createClass({displayName:"EditorBase",propTypes:{content:_react2["default"].PropTypes.string.isRequired,onDone:_react2["default"].PropTypes.func.isRequired,contentToHtml:_react2["default"].PropTypes.func,nodeToContent:_react2["default"].PropTypes.func,onStop:_react2["default"].PropTypes.func,submitOnEnter:_react2["default"].PropTypes.bool,className:_react2["default"].PropTypes.string,tag:_react2["default"].PropTypes.string},getDefaultProps:function(){return{contentToHtml:contentToHtml,nodeToContent:nodeToContent,submitOnEnter:!0,className:"",tag:"div"}},getInitialState:function(){return{editable:!1}},render:function(){var t="inline-input "+this.props.className,e={__html:this.props.contentToHtml(this.props.content)},o=this.props.tag;return _react2["default"].createElement(o,_extends({},this.props,{tabIndex:"0",className:t,contentEditable:this.state.editable||void 0,onFocus:this.onFocus,onMouseDown:this.onMouseDown,onClick:this.onClick,onBlur:this._stop,onKeyDown:this.onKeyDown,onInput:this.onInput,onPaste:this.onPaste,dangerouslySetInnerHTML:e}))},onPaste:function(t){t.preventDefault();var e=t.clipboardData.getData("text/plain");document.execCommand("insertHTML",!1,e)},onMouseDown:function(t){this._mouseDown=!0,window.addEventListener("mouseup",this.onMouseUp),this.props.onMouseDown&&this.props.onMouseDown(t)},onMouseUp:function(){this._mouseDown&&(this._mouseDown=!1,window.removeEventListener("mouseup",this.onMouseUp))},onClick:function(t){this.onMouseUp(),this.onFocus(t)},onFocus:function(t){if(console.log("onFocus",this._mouseDown,this._ignore_events,this.state.editable),!(this._mouseDown||this._ignore_events||this.state.editable)){var e,o=window.getSelection();if(o.rangeCount>0)e=o.getRangeAt(0);else if(document.caretPositionFromPoint&&t.clientX&&t.clientY){var n=document.caretPositionFromPoint(t.clientX,t.clientY);e=document.createRange(),e.setStart(n.offsetNode,n.offset)}else document.caretRangeFromPoint&&t.clientX&&t.clientY?e=document.caretRangeFromPoint(t.clientX,t.clientY):(e=document.createRange(),e.selectNodeContents(_reactDom2["default"].findDOMNode(this)));this._ignore_events=!0,this.setState({editable:!0},function(){var t=_reactDom2["default"].findDOMNode(this);t.blur(),t.focus(),this._ignore_events=!1})}},stop:function(){_reactDom2["default"].findDOMNode(this).blur(),this.props.onStop&&this.props.onStop()},_stop:function(t){if(!this._ignore_events){console.log("_stop",_.extend({},t)),window.getSelection().removeAllRanges();var e=_reactDom2["default"].findDOMNode(this),o=this.props.nodeToContent(e);this.setState({editable:!1}),this.props.onDone(o),this.props.onBlur&&this.props.onBlur(t)}},reset:function(){_reactDom2["default"].findDOMNode(this).innerHTML=this.props.contentToHtml(this.props.content)},onKeyDown:function(t){switch(t.stopPropagation(),t.keyCode){case _utils.Key.ESC:t.preventDefault(),this.reset(),this.stop();break;case _utils.Key.ENTER:this.props.submitOnEnter&&!t.shiftKey&&(t.preventDefault(),this.stop())}},onInput:function(){var t=_reactDom2["default"].findDOMNode(this),e=this.props.nodeToContent(t);this.props.onInput&&this.props.onInput(e)}}),ValidateEditor=_react2["default"].createClass({displayName:"ValidateEditor",propTypes:{content:_react2["default"].PropTypes.string.isRequired,onDone:_react2["default"].PropTypes.func.isRequired,onInput:_react2["default"].PropTypes.func,isValid:_react2["default"].PropTypes.func,className:_react2["default"].PropTypes.string},getInitialState:function(){return{currentContent:this.props.content}},componentWillReceiveProps:function(){this.setState({currentContent:this.props.content})},onInput:function(t){this.setState({currentContent:t}),this.props.onInput&&this.props.onInput(t)},render:function(){var t=this.props.className||"";return this.props.isValid&&(t+=this.props.isValid(this.state.currentContent)?" has-success":" has-warning"),_react2["default"].createElement(EditorBase,_extends({},this.props,{ref:"editor",className:t,onDone:this.onDone,onInput:this.onInput}))},onDone:function(t){this.props.isValid&&!this.props.isValid(t)&&(this.refs.editor.reset(),t=this.props.content),this.props.onDone(t)}}),ValueEditor=exports.ValueEditor=_react2["default"].createClass({displayName:"ValueEditor",contextTypes:{returnFocus:_react2["default"].PropTypes.func},propTypes:{content:_react2["default"].PropTypes.string.isRequired,onDone:_react2["default"].PropTypes.func.isRequired,inline:_react2["default"].PropTypes.bool},render:function(){var t=this.props.inline?"span":"div";return _react2["default"].createElement(ValidateEditor,_extends({},this.props,{onStop:this.onStop,tag:t}))},focus:function(){_reactDom2["default"].findDOMNode(this).focus()},onStop:function(){this.context.returnFocus()}});
+
+},{"../utils.js":41,"react":"react","react-dom":"react-dom"}],22:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var s in a)Object.prototype.hasOwnProperty.call(a,s)&&(e[s]=a[s])}return e},_react=require("react"),_react2=_interopRequireDefault(_react),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_utils=require("../../flow/utils.js"),_utils2=require("../../utils.js"),ViewImage=_react2["default"].createClass({displayName:"ViewImage",propTypes:{flow:_react2["default"].PropTypes.object.isRequired,message:_react2["default"].PropTypes.object.isRequired},statics:{regex:/^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i,matches:function(e){return ViewImage.regex.test(_utils.MessageUtils.getContentType(e))}},render:function(){var e=_utils.MessageUtils.getContentURL(this.props.flow,this.props.message);return _react2["default"].createElement("div",{className:"flowview-image"},_react2["default"].createElement("img",{src:e,alt:"preview",className:"img-thumbnail"}))}}),ContentLoader=_react2["default"].createClass({displayName:"ContentLoader",propTypes:{flow:_react2["default"].PropTypes.object.isRequired,message:_react2["default"].PropTypes.object.isRequired},getInitialState:function(){return{content:void 0,request:void 0}},requestContent:function(e){this.state.request&&this.state.request.abort();var t=_utils.MessageUtils.getContent(e.flow,e.message);this.setState({content:void 0,request:t}),t.done(function(e){this.setState({content:e})}.bind(this)).fail(function(e,t,a){"abort"!==t&&this.setState({content:"AJAX Error: "+t+"\r\n"+a})}.bind(this)).always(function(){this.setState({request:void 0})}.bind(this))},componentWillMount:function(){this.requestContent(this.props)},componentWillReceiveProps:function(e){e.message!==this.props.message&&this.requestContent(e)},componentWillUnmount:function(){this.state.request&&this.state.request.abort()},render:function(){return this.state.content?_react2["default"].cloneElement(this.props.children,{content:this.state.content}):_react2["default"].createElement("div",{className:"text-center"},_react2["default"].createElement("i",{className:"fa fa-spinner fa-spin"}))}}),ViewRaw=_react2["default"].createClass({displayName:"ViewRaw",propTypes:{content:_react2["default"].PropTypes.string.isRequired},statics:{textView:!0,matches:function(e){return!0}},render:function(){return _react2["default"].createElement("pre",null,this.props.content)}}),ViewJSON=_react2["default"].createClass({displayName:"ViewJSON",propTypes:{content:_react2["default"].PropTypes.string.isRequired},statics:{textView:!0,regex:/^application\/json$/i,matches:function(e){return ViewJSON.regex.test(_utils.MessageUtils.getContentType(e))}},render:function(){var e=this.props.content;try{e=JSON.stringify(JSON.parse(e),null,2)}catch(t){}return _react2["default"].createElement("pre",null,e)}}),ViewAuto=_react2["default"].createClass({displayName:"ViewAuto",propTypes:{message:_react2["default"].PropTypes.object.isRequired,flow:_react2["default"].PropTypes.object.isRequired},statics:{matches:function(){return!1},findView:function(e){for(var t=0;t<all.length;t++)if(all[t].matches(e))return all[t];return all[all.length-1]}},render:function(){var e=this.props,t=e.message,a=e.flow,s=ViewAuto.findView(this.props.message);return s.textView?_react2["default"].createElement(ContentLoader,{message:t,flow:a},_react2["default"].createElement(s,{content:""})):_react2["default"].createElement(s,{message:t,flow:a})}}),all=[ViewAuto,ViewImage,ViewJSON,ViewRaw],ContentEmpty=_react2["default"].createClass({displayName:"ContentEmpty",render:function(){var e=this.props.flow.request===this.props.message?"request":"response";return _react2["default"].createElement("div",{className:"alert alert-info"},"No ",e," content.")}}),ContentMissing=_react2["default"].createClass({displayName:"ContentMissing",render:function(){var e=this.props.flow.request===this.props.message?"Request":"Response";return _react2["default"].createElement("div",{className:"alert alert-info"},e," content missing.")}}),TooLarge=_react2["default"].createClass({displayName:"TooLarge",statics:{isTooLarge:function(e){var t=ViewImage.matches(e)?10:.2;return e.contentLength>1048576*t}},render:function(){var e=(0,_utils2.formatSize)(this.props.message.contentLength);return _react2["default"].createElement("div",{className:"alert alert-warning"},_react2["default"].createElement("button",{onClick:this.props.onClick,className:"btn btn-xs btn-warning pull-right"},"Display anyway"),e," content size.")}}),ViewSelector=_react2["default"].createClass({displayName:"ViewSelector",render:function(){for(var e=[],t=0;t<all.length;t++){var a=all[t],s="btn btn-default";a===this.props.active&&(s+=" active");var r;r=a===ViewAuto?"auto: "+ViewAuto.findView(this.props.message).displayName.toLowerCase().replace("view",""):a.displayName.toLowerCase().replace("view",""),e.push(_react2["default"].createElement("button",{key:a.displayName,onClick:this.props.selectView.bind(null,a),className:s},r))}return _react2["default"].createElement("div",{className:"view-selector btn-group btn-group-xs"},e)}}),ContentView=_react2["default"].createClass({displayName:"ContentView",getInitialState:function(){return{displayLarge:!1,View:ViewAuto}},propTypes:{flow:_react2["default"].PropTypes.object.isRequired,message:_react2["default"].PropTypes.object.isRequired},selectView:function(e){this.setState({View:e})},displayLarge:function(){this.setState({displayLarge:!0})},componentWillReceiveProps:function(e){e.message!==this.props.message&&this.setState(this.getInitialState())},render:function(){var e=this.props,t=e.flow,a=e.message,a=this.props.message;if(0===a.contentLength)return _react2["default"].createElement(ContentEmpty,this.props);if(null===a.contentLength)return _react2["default"].createElement(ContentMissing,this.props);if(!this.state.displayLarge&&TooLarge.isTooLarge(a))return _react2["default"].createElement(TooLarge,_extends({},this.props,{onClick:this.displayLarge}));var s=_utils.MessageUtils.getContentURL(this.props.flow,a);return _react2["default"].createElement("div",null,this.state.View.textView?_react2["default"].createElement(ContentLoader,{flow:t,message:a},_react2["default"].createElement(this.state.View,{content:""})):_react2["default"].createElement(this.state.View,{flow:t,message:a}),_react2["default"].createElement("div",{className:"view-options text-center"},_react2["default"].createElement(ViewSelector,{selectView:this.selectView,active:this.state.View,message:a})," ",_react2["default"].createElement("a",{className:"btn btn-default btn-xs",href:s},_react2["default"].createElement("i",{className:"fa fa-download"}))))}});exports["default"]=ContentView;
-},{"../../flow/utils.js":30,"../../utils.js":32,"lodash":"lodash","react":"react"}],12:[function(require,module,exports){
+},{"../../flow/utils.js":39,"../../utils.js":41,"lodash":"lodash","react":"react"}],23:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_utils=require("../../utils.js"),TimeStamp=_react2["default"].createClass({displayName:"TimeStamp",render:function(){if(!this.props.t)return _react2["default"].createElement("tr",null);var e,t=(0,_utils.formatTimeStamp)(this.props.t);return this.props.deltaTo?(e=(0,_utils.formatTimeDelta)(1e3*(this.props.t-this.props.deltaTo)),e=_react2["default"].createElement("span",{className:"text-muted"},"("+e+")")):e=null,_react2["default"].createElement("tr",null,_react2["default"].createElement("td",null,this.props.title+":"),_react2["default"].createElement("td",null,t," ",e))}}),ConnectionInfo=_react2["default"].createClass({displayName:"ConnectionInfo",render:function(){var e=this.props.conn,t=e.address.address.join(":"),a=_react2["default"].createElement("tr",{key:"sni"});return e.sni&&(a=_react2["default"].createElement("tr",{key:"sni"},_react2["default"].createElement("td",null,_react2["default"].createElement("abbr",{title:"TLS Server Name Indication"},"TLS SNI:")),_react2["default"].createElement("td",null,e.sni))),_react2["default"].createElement("table",{className:"connection-table"},_react2["default"].createElement("tbody",null,_react2["default"].createElement("tr",{key:"address"},_react2["default"].createElement("td",null,"Address:"),_react2["default"].createElement("td",null,t)),a))}}),CertificateInfo=_react2["default"].createClass({displayName:"CertificateInfo",render:function(){var e=this.props.flow,t=e.client_conn,a=e.server_conn,r={maxHeight:100};return _react2["default"].createElement("div",null,t.cert?_react2["default"].createElement("h4",null,"Client Certificate"):null,t.cert?_react2["default"].createElement("pre",{style:r},t.cert):null,a.cert?_react2["default"].createElement("h4",null,"Server Certificate"):null,a.cert?_react2["default"].createElement("pre",{style:r},a.cert):null)}}),Timing=_react2["default"].createClass({displayName:"Timing",render:function(){var e=this.props.flow,t=e.server_conn,a=e.client_conn,r=e.request,l=e.response,n=[{title:"Server conn. initiated",t:t.timestamp_start,deltaTo:r.timestamp_start},{title:"Server conn. TCP handshake",t:t.timestamp_tcp_setup,deltaTo:r.timestamp_start},{title:"Server conn. SSL handshake",t:t.timestamp_ssl_setup,deltaTo:r.timestamp_start},{title:"Client conn. established",t:a.timestamp_start,deltaTo:r.timestamp_start},{title:"Client conn. SSL handshake",t:a.timestamp_ssl_setup,deltaTo:r.timestamp_start},{title:"First request byte",t:r.timestamp_start},{title:"Request complete",t:r.timestamp_end,deltaTo:r.timestamp_start}];e.response&&n.push({title:"First response byte",t:l.timestamp_start,deltaTo:r.timestamp_start},{title:"Response complete",t:l.timestamp_end,deltaTo:r.timestamp_start}),n.forEach(function(e){e.key=e.title}),n=_lodash2["default"].sortBy(n,"t");var s=n.map(function(e){return _react2["default"].createElement(TimeStamp,e)});return _react2["default"].createElement("div",null,_react2["default"].createElement("h4",null,"Timing"),_react2["default"].createElement("table",{className:"timing-table"},_react2["default"].createElement("tbody",null,s)))}}),Details=_react2["default"].createClass({displayName:"Details",render:function(){var e=this.props.flow,t=e.client_conn,a=e.server_conn;return _react2["default"].createElement("section",null,_react2["default"].createElement("h4",null,"Client Connection"),_react2["default"].createElement(ConnectionInfo,{conn:t}),_react2["default"].createElement("h4",null,"Server Connection"),_react2["default"].createElement(ConnectionInfo,{conn:a}),_react2["default"].createElement(CertificateInfo,{flow:e}),_react2["default"].createElement(Timing,{flow:e}))}});exports["default"]=Details;
-},{"../../utils.js":32,"lodash":"lodash","react":"react"}],13:[function(require,module,exports){
+},{"../../utils.js":41,"lodash":"lodash","react":"react"}],24:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_nav=require("./nav.js"),_nav2=_interopRequireDefault(_nav),_messages=require("./messages.js"),_details=require("./details.js"),_details2=_interopRequireDefault(_details),_prompt=require("../prompt.js"),_prompt2=_interopRequireDefault(_prompt),allTabs={request:_messages.Request,response:_messages.Response,error:_messages.Error,details:_details2["default"]},FlowView=_react2["default"].createClass({displayName:"FlowView",getInitialState:function(){return{prompt:!1}},getTabs:function(e){var t=[];return["request","response","error"].forEach(function(r){e[r]&&t.push(r)}),t.push("details"),t},nextTab:function(e){var t=this.getTabs(this.props.flow),r=t.indexOf(this.props.tab),s=(r+e+t.length)%t.length;this.selectTab(t[s])},selectTab:function(e){this.props.updateLocation("/flows/"+this.props.flow.id+"/"+e)},promptEdit:function(){var e;switch(this.props.tab){case"request":e=["method","url",{text:"http version",key:"v"},"header"];break;case"response":e=[{text:"http version",key:"v"},"code","message","header"];break;case"details":return;default:throw"Unknown tab for edit: "+this.props.tab}this.setState({prompt:{done:function(e){this.setState({prompt:!1}),e&&this.refs.tab.edit(e)}.bind(this),options:e}})},render:function(){var e=this.props.flow,t=this.getTabs(e),r=this.props.tab;t.indexOf(r)<0&&(r="response"===r&&e.error?"error":"error"===r&&e.response?"response":t[0]);var s=null;this.state.prompt&&(s=_react2["default"].createElement(_prompt2["default"],this.state.prompt));var a=allTabs[r];return _react2["default"].createElement("div",{className:"flow-detail",onScroll:this.adjustHead},_react2["default"].createElement(_nav2["default"],{ref:"head",flow:e,tabs:t,active:r,selectTab:this.selectTab}),_react2["default"].createElement(a,{ref:"tab",flow:e}),s)}});exports["default"]=FlowView;
-},{"../prompt.js":20,"./details.js":12,"./messages.js":14,"./nav.js":15,"react":"react"}],14:[function(require,module,exports){
+},{"../prompt.js":29,"./details.js":23,"./messages.js":25,"./nav.js":26,"react":"react"}],25:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.Error=exports.Response=exports.Request=void 0;var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var s in r)Object.prototype.hasOwnProperty.call(r,s)&&(e[s]=r[s])}return e},_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_actions=require("../../actions.js"),_utils=require("../../flow/utils.js"),_utils2=require("../../utils.js"),_contentview=require("./contentview.js"),_contentview2=_interopRequireDefault(_contentview),_editor=require("../editor.js"),Headers=_react2["default"].createClass({displayName:"Headers",propTypes:{onChange:_react2["default"].PropTypes.func.isRequired,message:_react2["default"].PropTypes.object.isRequired},onChange:function(e,t,r){var s=_lodash2["default"].cloneDeep(this.props.message.headers);s[e][t]=r,s[e][0]||s[e][1]||(1===s.length?(s[0][0]="Name",s[0][1]="Value"):(s.splice(e,1),e===s.length&&(this._nextSel=e-1+"-value"))),this.props.onChange(s)},edit:function(){this.refs["0-key"].focus()},onTab:function(e,t,r){var s=this.props.message.headers;if(e===s.length-1&&1===t){r.preventDefault();var n=_lodash2["default"].cloneDeep(this.props.message.headers);n.push(["Name","Value"]),this.props.onChange(n),this._nextSel=e+1+"-key"}},componentDidUpdate:function(){this._nextSel&&this.refs[this._nextSel]&&(this.refs[this._nextSel].focus(),this._nextSel=void 0)},onRemove:function(e,t,r){1===t?(r.preventDefault(),this.refs[e+"-key"].focus()):e>0&&(r.preventDefault(),this.refs[e-1+"-value"].focus())},render:function(){var e=this.props.message.headers.map(function(e,t){var r=_react2["default"].createElement(HeaderEditor,{ref:t+"-key",content:e[0],onDone:this.onChange.bind(null,t,0),onRemove:this.onRemove.bind(null,t,0),onTab:this.onTab.bind(null,t,0)}),s=_react2["default"].createElement(HeaderEditor,{ref:t+"-value",content:e[1],onDone:this.onChange.bind(null,t,1),onRemove:this.onRemove.bind(null,t,1),onTab:this.onTab.bind(null,t,1)});return _react2["default"].createElement("tr",{key:t},_react2["default"].createElement("td",{className:"header-name"},r,":"),_react2["default"].createElement("td",{className:"header-value"},s))}.bind(this));return _react2["default"].createElement("table",{className:"header-table"},_react2["default"].createElement("tbody",null,e))}}),HeaderEditor=_react2["default"].createClass({displayName:"HeaderEditor",render:function(){return _react2["default"].createElement(_editor.ValueEditor,_extends({ref:"input"},this.props,{onKeyDown:this.onKeyDown,inline:!0}))},focus:function(){_reactDom2["default"].findDOMNode(this).focus()},onKeyDown:function(e){switch(e.keyCode){case _utils2.Key.BACKSPACE:var t=window.getSelection().getRangeAt(0);0===t.startOffset&&0===t.endOffset&&this.props.onRemove(e);break;case _utils2.Key.TAB:e.shiftKey||this.props.onTab(e)}}}),RequestLine=_react2["default"].createClass({displayName:"RequestLine",render:function(){var e=this.props.flow,t=_utils.RequestUtils.pretty_url(e.request),r=e.request.http_version;return _react2["default"].createElement("div",{className:"first-line request-line"},_react2["default"].createElement(_editor.ValueEditor,{ref:"method",content:e.request.method,onDone:this.onMethodChange,inline:!0})," ",_react2["default"].createElement(_editor.ValueEditor,{ref:"url",content:t,onDone:this.onUrlChange,isValid:this.isValidUrl,inline:!0})," ",_react2["default"].createElement(_editor.ValueEditor,{ref:"httpVersion",content:r,onDone:this.onHttpVersionChange,isValid:_utils.isValidHttpVersion,inline:!0}))},isValidUrl:function(e){var t=(0,_utils.parseUrl)(e);return!!t.host},onMethodChange:function(e){_actions.FlowActions.update(this.props.flow,{request:{method:e}})},onUrlChange:function(e){var t=(0,_utils.parseUrl)(e);t.path=t.path||"",_actions.FlowActions.update(this.props.flow,{request:t})},onHttpVersionChange:function(e){var t=(0,_utils.parseHttpVersion)(e);_actions.FlowActions.update(this.props.flow,{request:{http_version:t}})}}),ResponseLine=_react2["default"].createClass({displayName:"ResponseLine",render:function(){var e=this.props.flow,t=e.response.http_version;return _react2["default"].createElement("div",{className:"first-line response-line"},_react2["default"].createElement(_editor.ValueEditor,{ref:"httpVersion",content:t,onDone:this.onHttpVersionChange,isValid:_utils.isValidHttpVersion,inline:!0})," ",_react2["default"].createElement(_editor.ValueEditor,{ref:"code",content:e.response.status_code+"",onDone:this.onCodeChange,isValid:this.isValidCode,inline:!0})," ",_react2["default"].createElement(_editor.ValueEditor,{ref:"msg",content:e.response.reason,onDone:this.onMsgChange,inline:!0}))},isValidCode:function(e){return/^\d+$/.test(e)},onHttpVersionChange:function(e){var t=(0,_utils.parseHttpVersion)(e);_actions.FlowActions.update(this.props.flow,{response:{http_version:t}})},onMsgChange:function(e){_actions.FlowActions.update(this.props.flow,{response:{msg:e}})},onCodeChange:function(e){e=parseInt(e),_actions.FlowActions.update(this.props.flow,{response:{code:e}})}}),Request=exports.Request=_react2["default"].createClass({displayName:"Request",render:function(){var e=this.props.flow;return _react2["default"].createElement("section",{className:"request"},_react2["default"].createElement(RequestLine,{ref:"requestLine",flow:e}),_react2["default"].createElement(Headers,{ref:"headers",message:e.request,onChange:this.onHeaderChange}),_react2["default"].createElement("hr",null),_react2["default"].createElement(_contentview2["default"],{flow:e,message:e.request}))},edit:function(e){switch(e){case"m":this.refs.requestLine.refs.method.focus();break;case"u":this.refs.requestLine.refs.url.focus();break;case"v":this.refs.requestLine.refs.httpVersion.focus();break;case"h":this.refs.headers.edit();break;default:throw"Unimplemented: "+e}},onHeaderChange:function(e){_actions.FlowActions.update(this.props.flow,{request:{headers:e}})}}),Response=exports.Response=_react2["default"].createClass({displayName:"Response",render:function(){var e=this.props.flow;return _react2["default"].createElement("section",{className:"response"},_react2["default"].createElement(ResponseLine,{ref:"responseLine",flow:e}),_react2["default"].createElement(Headers,{ref:"headers",message:e.response,onChange:this.onHeaderChange}),_react2["default"].createElement("hr",null),_react2["default"].createElement(_contentview2["default"],{flow:e,message:e.response}))},edit:function(e){switch(e){case"c":this.refs.responseLine.refs.status_code.focus();break;case"m":this.refs.responseLine.refs.msg.focus();break;case"v":this.refs.responseLine.refs.httpVersion.focus();break;case"h":this.refs.headers.edit();break;default:throw"Unimplemented: "+e}},onHeaderChange:function(e){_actions.FlowActions.update(this.props.flow,{response:{headers:e}})}}),Error=exports.Error=_react2["default"].createClass({displayName:"Error",render:function(){var e=this.props.flow;return _react2["default"].createElement("section",null,_react2["default"].createElement("div",{className:"alert alert-warning"},e.error.msg,_react2["default"].createElement("div",null,_react2["default"].createElement("small",null,(0,_utils2.formatTimeStamp)(e.error.timestamp)))))}});
-},{"../../actions.js":2,"../../flow/utils.js":30,"../../utils.js":32,"../editor.js":7,"./contentview.js":11,"lodash":"lodash","react":"react","react-dom":"react-dom"}],15:[function(require,module,exports){
+},{"../../actions.js":2,"../../flow/utils.js":39,"../../utils.js":41,"../editor.js":21,"./contentview.js":22,"lodash":"lodash","react":"react","react-dom":"react-dom"}],26:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_actions=require("../../actions.js"),NavAction=_react2["default"].createClass({displayName:"NavAction",onClick:function(e){e.preventDefault(),this.props.onClick()},render:function(){return _react2["default"].createElement("a",{title:this.props.title,href:"#",className:"nav-action",onClick:this.onClick},_react2["default"].createElement("i",{className:"fa fa-fw "+this.props.icon}))}}),Nav=_react2["default"].createClass({displayName:"Nav",render:function(){var e=this.props.flow,t=this.props.tabs.map(function(e){var t=e.charAt(0).toUpperCase()+e.slice(1),a=this.props.active===e?"active":"",c=function(t){this.props.selectTab(e),t.preventDefault()}.bind(this);return _react2["default"].createElement("a",{key:e,href:"#",className:a,onClick:c},t)}.bind(this)),a=null;e.intercepted&&(a=_react2["default"].createElement(NavAction,{title:"[a]ccept intercepted flow",icon:"fa-play",onClick:_actions.FlowActions.accept.bind(null,e)}));var c=null;return e.modified&&(c=_react2["default"].createElement(NavAction,{title:"revert changes to flow [V]",icon:"fa-history",onClick:_actions.FlowActions.revert.bind(null,e)})),_react2["default"].createElement("nav",{ref:"head",className:"nav-tabs nav-tabs-sm"},t,_react2["default"].createElement(NavAction,{title:"[d]elete flow",icon:"fa-trash",onClick:_actions.FlowActions["delete"].bind(null,e)}),_react2["default"].createElement(NavAction,{title:"[D]uplicate flow",icon:"fa-copy",onClick:_actions.FlowActions.duplicate.bind(null,e)}),_react2["default"].createElement(NavAction,{disabled:!0,title:"[r]eplay flow",icon:"fa-repeat",onClick:_actions.FlowActions.replay.bind(null,e)}),a,c)}});exports["default"]=Nav;
-},{"../../actions.js":2,"react":"react"}],16:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function Footer(e){var a=e.settings,t=a.mode,s=a.intercept,l=a.showhost,c=a.no_upstream_cert,r=a.rawtcp,u=a.http2,n=a.anticache,o=a.anticomp,m=a.stickyauth,p=a.stickycookie,i=a.stream;return _react2["default"].createElement("footer",null,t&&"regular"!=t&&_react2["default"].createElement("span",{className:"label label-success"},t," mode"),s&&_react2["default"].createElement("span",{className:"label label-success"},"Intercept: ",s),l&&_react2["default"].createElement("span",{className:"label label-success"},"showhost"),c&&_react2["default"].createElement("span",{className:"label label-success"},"no-upstream-cert"),r&&_react2["default"].createElement("span",{className:"label label-success"},"raw-tcp"),!u&&_react2["default"].createElement("span",{className:"label label-success"},"no-http2"),n&&_react2["default"].createElement("span",{className:"label label-success"},"anticache"),o&&_react2["default"].createElement("span",{className:"label label-success"},"anticomp"),m&&_react2["default"].createElement("span",{className:"label label-success"},"stickyauth: ",m),p&&_react2["default"].createElement("span",{className:"label label-success"},"stickycookie: ",p),i&&_react2["default"].createElement("span",{className:"label label-success"},"stream: ",(0,_utils.formatSize)(i)))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Footer;var _react=require("react"),_react2=_interopRequireDefault(_react),_utils=require("../utils.js"),_common=require("./common.js");Footer.propTypes={settings:_react2["default"].PropTypes.object.isRequired};
-
-},{"../utils.js":32,"./common.js":6,"react":"react"}],17:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.Header=exports.OptionMenu=exports.MainMenu=void 0;var _react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),_reactRedux=require("react-redux"),_filt=require("../filt/filt.js"),_filt2=_interopRequireDefault(_filt),_utils=require("../utils.js"),_common=require("./common.js"),_actions=require("../actions.js"),_eventlog=require("./eventlog"),FilterDocs=_react2["default"].createClass({displayName:"FilterDocs",statics:{xhr:!1,doc:!1},componentWillMount:function(){FilterDocs.doc||(FilterDocs.xhr=_jquery2["default"].getJSON("/filter-help").done(function(e){FilterDocs.doc=e,FilterDocs.xhr=!1})),FilterDocs.xhr&&FilterDocs.xhr.done(function(){this.forceUpdate()}.bind(this))},render:function(){if(FilterDocs.doc){var e=FilterDocs.doc.commands.map(function(e){return _react2["default"].createElement("tr",{key:e[1]},_react2["default"].createElement("td",null,e[0].replace(" "," ")),_react2["default"].createElement("td",null,e[1]))});return e.push(_react2["default"].createElement("tr",{key:"docs-link"},_react2["default"].createElement("td",{colSpan:"2"},_react2["default"].createElement("a",{href:"http://docs.mitmproxy.org/en/stable/features/filters.html",target:"_blank"},_react2["default"].createElement("i",{className:"fa fa-external-link"}),"  mitmproxy docs")))),_react2["default"].createElement("table",{className:"table table-condensed"},_react2["default"].createElement("tbody",null,e))}return _react2["default"].createElement("i",{className:"fa fa-spinner fa-spin"})}}),FilterInput=_react2["default"].createClass({displayName:"FilterInput",contextTypes:{returnFocus:_react2["default"].PropTypes.func},getInitialState:function(){return{value:this.props.value,focus:!1,mousefocus:!1}},componentWillReceiveProps:function(e){this.setState({value:e.value})},onChange:function(e){var t=e.target.value;this.setState({value:t}),this.isValid(t)&&this.props.onChange(t)},isValid:function(e){try{var t=e||this.state.value;return t&&_filt2["default"].parse(e||this.state.value),!0}catch(a){return!1}},getDesc:function(){if(this.state.value)try{return _filt2["default"].parse(this.state.value).desc}catch(e){return""+e}return _react2["default"].createElement(FilterDocs,null)},onFocus:function(){this.setState({focus:!0})},onBlur:function(){this.setState({focus:!1})},onMouseEnter:function(){this.setState({mousefocus:!0})},onMouseLeave:function(){this.setState({mousefocus:!1})},onKeyDown:function(e){e.keyCode!==_utils.Key.ESC&&e.keyCode!==_utils.Key.ENTER||(this.blur(),this.setState({mousefocus:!1})),e.stopPropagation()},blur:function(){_reactDom2["default"].findDOMNode(this.refs.input).blur(),this.context.returnFocus()},select:function(){_reactDom2["default"].findDOMNode(this.refs.input).select()},render:function(){var e,t=this.isValid(),a="fa fa-fw fa-"+this.props.type,n="filter-input input-group"+(t?"":" has-error");return(this.state.focus||this.state.mousefocus)&&(e=_react2["default"].createElement("div",{className:"popover bottom",onMouseEnter:this.onMouseEnter,onMouseLeave:this.onMouseLeave},_react2["default"].createElement("div",{className:"arrow"}),_react2["default"].createElement("div",{className:"popover-content"},this.getDesc()))),_react2["default"].createElement("div",{className:n},_react2["default"].createElement("span",{className:"input-group-addon"},_react2["default"].createElement("i",{className:a,style:{color:this.props.color}})),_react2["default"].createElement("input",{type:"text",placeholder:this.props.placeholder,className:"form-control",ref:"input",onChange:this.onChange,onFocus:this.onFocus,onBlur:this.onBlur,onKeyDown:this.onKeyDown,value:this.state.value}),e)}}),MainMenu=exports.MainMenu=_react2["default"].createClass({displayName:"MainMenu",propTypes:{settings:_react2["default"].PropTypes.object.isRequired},statics:{title:"Start",route:"flows"},onSearchChange:function(e){var t={};t[_actions.Query.SEARCH]=e,this.props.updateLocation(void 0,t)},onHighlightChange:function(e){var t={};t[_actions.Query.HIGHLIGHT]=e,this.props.updateLocation(void 0,t)},onInterceptChange:function(e){_actions.SettingsActions.update({intercept:e})},render:function(){var e=this.props.query[_actions.Query.SEARCH]||"",t=this.props.query[_actions.Query.HIGHLIGHT]||"",a=this.props.settings.intercept||"";return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(FilterInput,{ref:"search",placeholder:"Search",type:"search",color:"black",value:e,onChange:this.onSearchChange}),_react2["default"].createElement(FilterInput,{ref:"highlight",placeholder:"Highlight",type:"tag",color:"hsl(48, 100%, 50%)",value:t,onChange:this.onHighlightChange}),_react2["default"].createElement(FilterInput,{ref:"intercept",placeholder:"Intercept",type:"pause",color:"hsl(208, 56%, 53%)",value:a,onChange:this.onInterceptChange})),_react2["default"].createElement("div",{className:"clearfix"}))}}),ViewMenu=_react2["default"].createClass({displayName:"ViewMenu",statics:{title:"View",route:"flows"},render:function(){return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_eventlog.ToggleEventLog,{text:"Show Event Log"})),_react2["default"].createElement("div",{className:"clearfix"}))}}),OptionMenu=exports.OptionMenu=function(e){var t=e.settings,a=(t.mode,t.intercept,t.showhost),n=t.no_upstream_cert,r=t.rawtcp,l=t.http2,c=t.anticache,i=t.anticomp,o=t.stickycookie,s=t.stickyauth,u=t.stream;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_common.ToggleButton,{text:"showhost",checked:a,onToggle:function(){return _actions.SettingsActions.update({showhost:!a})}}),_react2["default"].createElement(_common.ToggleButton,{text:"no_upstream_cert",checked:n,onToggle:function(){return _actions.SettingsActions.update({no_upstream_cert:!n})}}),_react2["default"].createElement(_common.ToggleButton,{text:"rawtcp",checked:r,onToggle:function(){return _actions.SettingsActions.update({rawtcp:!r})}}),_react2["default"].createElement(_common.ToggleButton,{text:"http2",checked:l,onToggle:function(){return _actions.SettingsActions.update({http2:!l})}}),_react2["default"].createElement(_common.ToggleButton,{text:"anticache",checked:c,onToggle:function(){return _actions.SettingsActions.update({anticache:!c})}}),_react2["default"].createElement(_common.ToggleButton,{text:"anticomp",checked:i,onToggle:function(){return _actions.SettingsActions.update({anticomp:!i})}}),_react2["default"].createElement(_common.ToggleInputButton,{name:"stickyauth",placeholder:"Sticky auth filter",checked:Boolean(s),txt:s||"",onToggleChanged:function(e){return _actions.SettingsActions.update({stickyauth:s?null:e})}}),_react2["default"].createElement(_common.ToggleInputButton,{name:"stickycookie",placeholder:"Sticky cookie filter",checked:Boolean(o),txt:o||"",onToggleChanged:function(e){return _actions.SettingsActions.update({stickycookie:o?null:e})}}),_react2["default"].createElement(_common.ToggleInputButton,{name:"stream",placeholder:"stream...",checked:Boolean(u),txt:u||"",inputType:"number",onToggleChanged:function(e){return _actions.SettingsActions.update({stream:u?null:e})}})),_react2["default"].createElement("div",{className:"clearfix"}))};OptionMenu.title="Options",OptionMenu.propTypes={settings:_react2["default"].PropTypes.object.isRequired};var ReportsMenu=_react2["default"].createClass({displayName:"ReportsMenu",statics:{title:"Visualization",route:"reports"},render:function(){return _react2["default"].createElement("div",null,"Reports Menu")}}),FileMenu=_react2["default"].createClass({displayName:"FileMenu",getInitialState:function(){return{showFileMenu:!1}},handleFileClick:function(e){if(e.preventDefault(),!this.state.showFileMenu){var t=function(){this.setState({showFileMenu:!1}),document.removeEventListener("click",t)}.bind(this);document.addEventListener("click",t),this.setState({showFileMenu:!0})}},handleNewClick:function(e){e.preventDefault(),confirm("Delete all flows?")&&_actions.FlowActions.clear()},handleOpenClick:function(e){this.fileInput.click(),e.preventDefault()},handleOpenFile:function(e){e.target.files.length>0&&(_actions.FlowActions.upload(e.target.files[0]),this.fileInput.value=""),e.preventDefault()},handleSaveClick:function(e){e.preventDefault(),_actions.FlowActions.download()},handleShutdownClick:function(e){e.preventDefault(),console.error("unimplemented: handleShutdownClick")},render:function(){var e=this,t="dropdown pull-left"+(this.state.showFileMenu?" open":"");return _react2["default"].createElement("div",{className:t},_react2["default"].createElement("a",{href:"#",className:"special",onClick:this.handleFileClick}," mitmproxy "),_react2["default"].createElement("ul",{className:"dropdown-menu",role:"menu"},_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.handleNewClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-file"}),"New")),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.handleOpenClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-folder-open"}),"Open..."),_react2["default"].createElement("input",{ref:function(t){return e.fileInput=t},className:"hidden",type:"file",onChange:this.handleOpenFile})),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.handleSaveClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-floppy-o"}),"Save...")),_react2["default"].createElement("li",{role:"presentation",className:"divider"}),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"http://mitm.it/",target:"_blank"},_react2["default"].createElement("i",{className:"fa fa-fw fa-external-link"}),"Install Certificates..."))))}}),header_entries=[MainMenu,ViewMenu,OptionMenu],Header=exports.Header=_react2["default"].createClass({displayName:"Header",propTypes:{settings:_react2["default"].PropTypes.object.isRequired},getInitialState:function(){return{active:header_entries[0]}},handleClick:function(e,t){t.preventDefault(),this.props.updateLocation(e.route),this.setState({active:e})},render:function(){var e=header_entries.map(function(e,t){var a;return a=e===this.state.active?"active":"",_react2["default"].createElement("a",{key:t,href:"#",className:a,onClick:this.handleClick.bind(this,e)},e.title)}.bind(this));return _react2["default"].createElement("header",null,_react2["default"].createElement("nav",{className:"nav-tabs nav-tabs-lg"},_react2["default"].createElement(FileMenu,null),e),_react2["default"].createElement("div",{className:"menu"},_react2["default"].createElement(this.state.active,{settings:this.props.settings,updateLocation:this.props.updateLocation,query:this.props.query})))}});
-
-},{"../actions.js":2,"../filt/filt.js":29,"../utils.js":32,"./common.js":6,"./eventlog":8,"jquery":"jquery","react":"react","react-dom":"react-dom","react-redux":"react-redux"}],18:[function(require,module,exports){
+},{"../../actions.js":2,"react":"react"}],27:[function(require,module,exports){
"use strict";function _interopRequireDefault(t){return t&&t.__esModule?t:{"default":t}}function _classCallCheck(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function _inherits(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function t(t,e){for(var o=0;o<e.length;o++){var r=e[o];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(e,o,r){return o&&t(e.prototype,o),r&&t(e,r),e}}(),_get=function t(e,o,r){null===e&&(e=Function.prototype);var n=Object.getOwnPropertyDescriptor(e,o);if(void 0===n){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,o,r)}if("value"in n)return n.value;var c=n.get;if(void 0!==c)return c.call(r)},_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),symShouldStick=Symbol("shouldStick"),isAtBottom=function(t){return t.scrollTop+t.clientHeight===t.scrollHeight};exports["default"]=function(t){var e,o;return Object.assign((o=e=function(t){function e(){return _classCallCheck(this,e),_possibleConstructorReturn(this,Object.getPrototypeOf(e).apply(this,arguments))}return _inherits(e,t),_createClass(e,[{key:"componentWillUpdate",value:function(){var t=_reactDom2["default"].findDOMNode(this);this[symShouldStick]=t.scrollTop&&isAtBottom(t),_get(Object.getPrototypeOf(e.prototype),"componentWillUpdate",this)&&_get(Object.getPrototypeOf(e.prototype),"componentWillUpdate",this).call(this)}},{key:"componentDidUpdate",value:function(){var t=_reactDom2["default"].findDOMNode(this);this[symShouldStick]&&!isAtBottom(t)&&(t.scrollTop=t.scrollHeight),_get(Object.getPrototypeOf(e.prototype),"componentDidUpdate",this)&&_get(Object.getPrototypeOf(e.prototype),"componentDidUpdate",this).call(this)}}]),e}(t),e.displayName=t.name,o),t)};
-},{"react":"react","react-dom":"react-dom"}],19:[function(require,module,exports){
+},{"react":"react","react-dom":"react-dom"}],28:[function(require,module,exports){
"use strict";function calcVScroll(t){if(!t)return{start:0,end:0,paddingTop:0,paddingBottom:0};var e=t.itemCount,o=t.rowHeight,r=t.viewportTop,a=t.viewportHeight,i=t.itemHeights,l=r+a,n=0,c=0,d=0,p=0;if(i)for(var h=0,s=0;e>h;h++){var m=i[h]||o;r>=s&&h%2===0&&(d=s,n=h),l>=s?c=h+1:p+=m,s+=m}else n=-2&Math.max(0,Math.floor(r/o)-1),c=Math.min(e,n+Math.ceil(a/o)+2),d=Math.min(n,e)*o,p=Math.max(0,e-c)*o;return{start:n,end:c,paddingTop:d,paddingBottom:p}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.calcVScroll=calcVScroll;
-},{}],20:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_utils=require("../utils.js"),Prompt=_react2["default"].createClass({displayName:"Prompt",contextTypes:{returnFocus:_react2["default"].PropTypes.func},propTypes:{options:_react2["default"].PropTypes.array.isRequired,done:_react2["default"].PropTypes.func.isRequired,prompt:_react2["default"].PropTypes.string},componentDidMount:function(){_reactDom2["default"].findDOMNode(this).focus()},onKeyDown:function(e){e.stopPropagation(),e.preventDefault();for(var t=this.getOptions(),r=0;r<t.length;r++){var o=t[r].key;if(_utils.Key[o.toUpperCase()]===e.keyCode)return void this.done(o)}e.keyCode!==_utils.Key.ESC&&e.keyCode!==_utils.Key.ENTER||this.done(!1)},onClick:function(e){this.done(!1)},done:function(e){this.props.done(e),this.context.returnFocus()},getOptions:function(){for(var e=[],t=function(t){return _lodash2["default"].includes(_lodash2["default"].pluck(e,"key"),t)},r=0;r<this.props.options.length;r++){var o=this.props.options[r];if(_lodash2["default"].isString(o)){for(var n=o;n.length>0&&t(n[0]);)n=n.substr(1);o={text:o,key:n[0]}}if(!o.text||!o.key||t(o.key))throw"invalid options";e.push(o)}return e},render:function(){var e=this.getOptions();return e=_lodash2["default"].map(e,function(e){var t,r,o=e.text.indexOf(e.key);-1!==o?(t=e.text.substring(0,o),r=e.text.substring(o+1)):(t=e.text+" (",r=")");var n=function(t){this.done(e.key),t.stopPropagation()}.bind(this);return _react2["default"].createElement("span",{key:e.key,className:"option",onClick:n},t,_react2["default"].createElement("strong",{className:"text-primary"},e.key),r)}.bind(this)),_react2["default"].createElement("div",{tabIndex:"0",onKeyDown:this.onKeyDown,onClick:this.onClick,className:"prompt-dialog"},_react2["default"].createElement("div",{className:"prompt-content"},this.props.prompt||_react2["default"].createElement("strong",null,"Select: "),e))}});exports["default"]=Prompt;
+},{}],29:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_utils=require("../utils.js"),Prompt=_react2["default"].createClass({displayName:"Prompt",contextTypes:{returnFocus:_react2["default"].PropTypes.func},propTypes:{options:_react2["default"].PropTypes.array.isRequired,done:_react2["default"].PropTypes.func.isRequired,prompt:_react2["default"].PropTypes.string},componentDidMount:function(){_reactDom2["default"].findDOMNode(this).focus()},onKeyDown:function(e){e.stopPropagation(),e.preventDefault();for(var t=this.getOptions(),r=0;r<t.length;r++){var o=t[r].key;if(_utils.Key[o.toUpperCase()]===e.keyCode)return void this.done(o)}e.keyCode!==_utils.Key.ESC&&e.keyCode!==_utils.Key.ENTER||this.done(!1)},onClick:function(e){this.done(!1)},done:function(e){this.props.done(e),this.context.returnFocus()},getOptions:function(){for(var e=[],t=function(t){return _lodash2["default"].includes(_lodash2["default"].map(e,"key"),t)},r=0;r<this.props.options.length;r++){var o=this.props.options[r];if(_lodash2["default"].isString(o)){for(var n=o;n.length>0&&t(n[0]);)n=n.substr(1);o={text:o,key:n[0]}}if(!o.text||!o.key||t(o.key))throw"invalid options";e.push(o)}return e},render:function(){var e=this.getOptions();return e=_lodash2["default"].map(e,function(e){var t,r,o=e.text.indexOf(e.key);-1!==o?(t=e.text.substring(0,o),r=e.text.substring(o+1)):(t=e.text+" (",r=")");var n=function(t){this.done(e.key),t.stopPropagation()}.bind(this);return _react2["default"].createElement("span",{key:e.key,className:"option",onClick:n},t,_react2["default"].createElement("strong",{className:"text-primary"},e.key),r)}.bind(this)),_react2["default"].createElement("div",{tabIndex:"0",onKeyDown:this.onKeyDown,onClick:this.onClick,className:"prompt-dialog"},_react2["default"].createElement("div",{className:"prompt-content"},this.props.prompt||_react2["default"].createElement("strong",null,"Select: "),e))}});exports["default"]=Prompt;
-},{"../utils.js":32,"lodash":"lodash","react":"react","react-dom":"react-dom"}],21:[function(require,module,exports){
+},{"../utils.js":41,"lodash":"lodash","react":"react","react-dom":"react-dom"}],30:[function(require,module,exports){
"use strict";function _interopRequireWildcard(e){if(e&&e.__esModule)return e;var o={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(o[n]=e[n]);return o["default"]=e,o}function Connection(e,o){"/"===e[0]&&(e=location.origin.replace("http","ws")+e);var n=new WebSocket(e);return n.onopen=function(){o(webSocketActions.connected()),o(flowActions.fetchFlows()).then(function(){console.log("flows are loaded now"),_actions.ConnectionActions.open()}),o(eventLogActions.fetchLogEntries())},n.onmessage=function(e){var n=JSON.parse(e.data);switch(_dispatcher.AppDispatcher.dispatchServerAction(n),n.type){case eventLogActions.UPDATE_LOG:return o(eventLogActions.updateLogEntries(n));case flowActions.UPDATE_FLOWS:return o(flowActions.updateFlows(n));default:console.warn("unknown message",n)}},n.onerror=function(){_actions.ConnectionActions.error(),o(eventLogActions.addLogEntry("WebSocket connection error."))},n.onclose=function(){_actions.ConnectionActions.close(),o(eventLogActions.addLogEntry("WebSocket connection closed.")),o(webSocketActions.disconnected())},n}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Connection;var _actions=require("./actions.js"),_dispatcher=require("./dispatcher.js"),_websocket=require("./ducks/websocket"),webSocketActions=_interopRequireWildcard(_websocket),_eventLog=require("./ducks/eventLog"),eventLogActions=_interopRequireWildcard(_eventLog),_flows=require("./ducks/flows"),flowActions=_interopRequireWildcard(_flows);
-},{"./actions.js":2,"./dispatcher.js":22,"./ducks/eventLog":23,"./ducks/flows":24,"./ducks/websocket":28}],22:[function(require,module,exports){
+},{"./actions.js":2,"./dispatcher.js":31,"./ducks/eventLog":32,"./ducks/flows":33,"./ducks/websocket":37}],31:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.AppDispatcher=void 0;var _flux=require("flux"),_flux2=_interopRequireDefault(_flux),PayloadSources={VIEW:"view",SERVER:"server"},AppDispatcher=exports.AppDispatcher=new _flux2["default"].Dispatcher;AppDispatcher.dispatchViewAction=function(e){e.source=PayloadSources.VIEW,this.dispatch(e)},AppDispatcher.dispatchServerAction=function(e){e.source=PayloadSources.SERVER,this.dispatch(e)};
-},{"flux":"flux"}],23:[function(require,module,exports){
+},{"flux":"flux"}],32:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _defineProperty(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function reducer(){var e=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],t=arguments[1];switch(t.type){case TOGGLE_FILTER:var i=_extends({},e.filter,_defineProperty({},t.filter,!e.filter[t.filter]));return _extends({},e,{filter:i,filteredEvents:(0,_view.updateViewFilter)(e.events,function(e){return i[e.level]})});case TOGGLE_VISIBILITY:return _extends({},e,{visible:!e.visible});case UPDATE_LOG:var r=reduceList(e.events,t);return _extends({},e,{events:r,filteredEvents:(0,_view.updateViewList)(e.filteredEvents,e.events,r,t,function(t){return e.filter[t.level]})});default:return e}}function toggleEventLogFilter(e){return{type:TOGGLE_FILTER,filter:e}}function toggleEventLogVisibility(){return{type:TOGGLE_VISIBILITY}}function addLogEntry(e){var t=arguments.length<=1||void 0===arguments[1]?"web":arguments[1];return addItem({message:e,level:t,id:"log-"+id++})}Object.defineProperty(exports,"__esModule",{value:!0}),exports.fetchLogEntries=exports.updateLogEntries=exports.UPDATE_LOG=void 0;var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var i=arguments[t];for(var r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r])}return e};exports["default"]=reducer,exports.toggleEventLogFilter=toggleEventLogFilter,exports.toggleEventLogVisibility=toggleEventLogVisibility,exports.addLogEntry=addLogEntry;var _list=require("./utils/list"),_list2=_interopRequireDefault(_list),_view=require("./utils/view"),TOGGLE_FILTER="TOGGLE_EVENTLOG_FILTER",TOGGLE_VISIBILITY="TOGGLE_EVENTLOG_VISIBILITY",UPDATE_LOG=exports.UPDATE_LOG="UPDATE_EVENTLOG",_makeList=(0,_list2["default"])(UPDATE_LOG,"/events"),reduceList=_makeList.reduceList,updateList=_makeList.updateList,fetchList=_makeList.fetchList,addItem=_makeList.addItem,defaultState={visible:!1,filter:{debug:!1,info:!0,web:!0},events:reduceList(),filteredEvents:[]},id=0;exports.updateLogEntries=updateList,exports.fetchLogEntries=fetchList;
-},{"./utils/list":26,"./utils/view":27}],24:[function(require,module,exports){
-"use strict";function _interopRequireWildcard(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t["default"]=e,t}function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function makeFilterFn(e){return e?_filt2["default"].parse(e):function(){return!0}}function makeSortFn(e){var t=flow_table_columns[e.sortColumn];if(t){var r=t.sortKeyFun;return e.sortDesc&&(r=r&&function(e){var r=t.sortKeyFun(e);return _.isString(r)?(0,_utils.reverseString)(""+r):-r}),r}}function reducer(){var e=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],t=arguments[1];switch(t.type){case UPDATE_FLOWS:var r=reduceList(e.all,t);return _extends({},e,{all:r,view:(0,_view.updateViewList)(e.view,e.all,r,t,makeFilterFn(t.filter),makeSortFn(e.sort))});case SET_FILTER:return _extends({},e,{filter:t.filter,view:(0,_view.updateViewFilter)(e.all,makeFilterFn(t.filter),makeSortFn(e.sort))});case SET_HIGHLIGHT:return _extends({},e,{highlight:t.highlight});case SET_SORT:return _extends({},e,{sort:t.sort,view:(0,_view.updateViewSort)(e.view,makeSortFn(t.sort))});case SELECT_FLOW:return _extends({},e,{selected:[t.flowId]});default:return e}}function setFilter(e){return{type:SET_FILTER,filter:e}}function setHighlight(e){return{type:SET_HIGHLIGHT,highlight:e}}function setSort(e){return{type:SET_SORT,sort:e}}function selectFlow(e){return{type:SELECT_FLOW,flowId:e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.fetchFlows=exports.updateFlows=exports.SELECT_FLOW=exports.SET_SORT=exports.SET_HIGHLIGHT=exports.SET_FILTER=exports.UPDATE_FLOWS=void 0;var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var i in r)Object.prototype.hasOwnProperty.call(r,i)&&(e[i]=r[i])}return e};exports["default"]=reducer,exports.setFilter=setFilter,exports.setHighlight=setHighlight,exports.setSort=setSort,exports.selectFlow=selectFlow;var _list=require("./utils/list"),_list2=_interopRequireDefault(_list),_filt=require("../filt/filt"),_filt2=_interopRequireDefault(_filt),_view=require("./utils/view"),_utils=require("../utils.js"),_flowtableColumns=require("../components/flowtable-columns.js"),flow_table_columns=_interopRequireWildcard(_flowtableColumns),UPDATE_FLOWS=exports.UPDATE_FLOWS="UPDATE_FLOWS",SET_FILTER=exports.SET_FILTER="SET_FLOW_FILTER",SET_HIGHLIGHT=exports.SET_HIGHLIGHT="SET_FLOW_HIGHLIGHT",SET_SORT=exports.SET_SORT="SET_FLOW_SORT",SELECT_FLOW=exports.SELECT_FLOW="SELECT_FLOW",_makeList=(0,_list2["default"])(UPDATE_FLOWS,"/flows"),reduceList=_makeList.reduceList,updateList=_makeList.updateList,fetchList=_makeList.fetchList,defaultState={all:reduceList(),selected:[],view:[],filter:void 0,highlight:void 0,sort:{sortColumn:void 0,sortDesc:!1}};exports.updateFlows=updateList,exports.fetchFlows=fetchList;
+},{"./utils/list":35,"./utils/view":36}],33:[function(require,module,exports){
+"use strict";function _interopRequireWildcard(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t["default"]=e,t}function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function makeFilterFn(e){return e?_filt2["default"].parse(e):function(){return!0}}function makeSortFn(e){var t=columns[e.sortColumn];if(t){var r=t.sortKeyFun;return e.sortDesc&&(r=r&&function(e){var r=t.sortKeyFun(e);return _.isString(r)?(0,_utils.reverseString)(""+r):-r}),r}}function reducer(){var e=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],t=arguments[1];switch(t.type){case UPDATE_FLOWS:var r=reduceList(e.all,t);return _extends({},e,{all:r,view:(0,_view.updateViewList)(e.view,e.all,r,t,makeFilterFn(t.filter),makeSortFn(e.sort))});case SET_FILTER:return _extends({},e,{filter:t.filter,view:(0,_view.updateViewFilter)(e.all,makeFilterFn(t.filter),makeSortFn(e.sort))});case SET_HIGHLIGHT:return _extends({},e,{highlight:t.highlight});case SET_SORT:return _extends({},e,{sort:t.sort,view:(0,_view.updateViewSort)(e.view,makeSortFn(t.sort))});case SELECT_FLOW:return _extends({},e,{selected:[t.flowId]});default:return e}}function setFilter(e){return{type:SET_FILTER,filter:e}}function setHighlight(e){return{type:SET_HIGHLIGHT,highlight:e}}function setSort(e){return{type:SET_SORT,sort:e}}function selectFlow(e){return{type:SELECT_FLOW,flowId:e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.fetchFlows=exports.updateFlows=exports.SELECT_FLOW=exports.SET_SORT=exports.SET_HIGHLIGHT=exports.SET_FILTER=exports.UPDATE_FLOWS=void 0;var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var i in r)Object.prototype.hasOwnProperty.call(r,i)&&(e[i]=r[i])}return e};exports["default"]=reducer,exports.setFilter=setFilter,exports.setHighlight=setHighlight,exports.setSort=setSort,exports.selectFlow=selectFlow;var _list=require("./utils/list"),_list2=_interopRequireDefault(_list),_filt=require("../filt/filt"),_filt2=_interopRequireDefault(_filt),_view=require("./utils/view"),_utils=require("../utils.js"),_FlowColumns=require("../components/FlowTable/FlowColumns"),columns=_interopRequireWildcard(_FlowColumns),UPDATE_FLOWS=exports.UPDATE_FLOWS="UPDATE_FLOWS",SET_FILTER=exports.SET_FILTER="SET_FLOW_FILTER",SET_HIGHLIGHT=exports.SET_HIGHLIGHT="SET_FLOW_HIGHLIGHT",SET_SORT=exports.SET_SORT="SET_FLOW_SORT",SELECT_FLOW=exports.SELECT_FLOW="SELECT_FLOW",_makeList=(0,_list2["default"])(UPDATE_FLOWS,"/flows"),reduceList=_makeList.reduceList,updateList=_makeList.updateList,fetchList=_makeList.fetchList,defaultState={all:reduceList(),selected:[],view:[],filter:void 0,highlight:void 0,sort:{sortColumn:void 0,sortDesc:!1}};exports.updateFlows=updateList,exports.fetchFlows=fetchList;
-},{"../components/flowtable-columns.js":9,"../filt/filt":29,"../utils.js":32,"./utils/list":26,"./utils/view":27}],25:[function(require,module,exports){
+},{"../components/FlowTable/FlowColumns":7,"../filt/filt":38,"../utils.js":41,"./utils/list":35,"./utils/view":36}],34:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _redux=require("redux"),_eventLog=require("./eventLog"),_eventLog2=_interopRequireDefault(_eventLog),_websocket=require("./websocket"),_websocket2=_interopRequireDefault(_websocket),_flows=require("./flows"),_flows2=_interopRequireDefault(_flows),rootReducer=(0,_redux.combineReducers)({eventLog:_eventLog2["default"],websocket:_websocket2["default"],flows:_flows2["default"]});exports["default"]=rootReducer;
-},{"./eventLog":23,"./flows":24,"./websocket":28,"redux":"redux"}],26:[function(require,module,exports){
+},{"./eventLog":32,"./flows":33,"./websocket":37,"redux":"redux"}],35:[function(require,module,exports){
"use strict";function _defineProperty(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t<e.length;t++)r[t]=e[t];return r}return Array.from(e)}function makeList(e,t){function r(){var t=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];if(n.type!==e)return t;if(n.cmd===RECEIVE_LIST){for(var i={isFetching:!1,actionsDuringFetch:[],list:n.list,byId:{},indexOf:{}},o=0;o<n.list.length;o++){var d=n.list[o];i.byId[d.id]=d,i.indexOf[d.id]=o}var a=!0,s=!1,u=void 0;try{for(var c,f=t.actionsDuringFetch[Symbol.iterator]();!(a=(c=f.next()).done);a=!0)n=c.value,i=r(i,n)}catch(l){s=!0,u=l}finally{try{!a&&f["return"]&&f["return"]()}finally{if(s)throw u}}return i}if(t.isFetching)return _extends({},t,{actionsDuringFetch:[].concat(_toConsumableArray(t.actionsDuringFetch),[n])});var E=void 0,y=void 0;switch(n.cmd){case ADD:return{list:[].concat(_toConsumableArray(t.list),[n.item]),byId:_extends({},t.byId,_defineProperty({},n.item.id,n.item)),indexOf:_extends({},t.indexOf,_defineProperty({},n.item.id,t.list.length))};case UPDATE:return E=[].concat(_toConsumableArray(t.list)),y=t.indexOf[n.item.id],E[y]=n.item,_extends({},t,{list:E,byId:_extends({},t.byId,_defineProperty({},n.item.id,n.item))});case REMOVE:return E=[].concat(_toConsumableArray(t.list)),y=t.indexOf[n.item.id],E.splice(y,1),_extends({},t,{list:E,byId:_extends({},t.byId,_defineProperty({},n.item.id,void 0)),indexOf:_extends({},t.indexOf,_defineProperty({},n.item.id,void 0))});case REQUEST_LIST:return _extends({},t,{isFetching:!0});default:return console.debug("unknown action",n),t}}function n(t){return{type:e,cmd:ADD,item:t}}function i(t){return{type:e,cmd:UPDATE,item:t}}function o(t){return{type:e,cmd:REMOVE,item:t}}function d(e){return function(t){switch(e.cmd){case"add":return t(n(e.data));case"update":return t(i(e.data));case"remove":return t(o(e.data));case"reset":return t(u());default:console.error("unknown list update",e)}}}function a(){return{type:e,cmd:REQUEST_LIST}}function s(t){return{type:e,cmd:RECEIVE_LIST,list:t}}function u(){return function(e){return e(a()),(0,_utils.fetchApi)(t).then(function(t){return t.json().then(function(t){e(s(t.data))})})}}return{reduceList:r,updateList:d,fetchList:u,addItem:n,updateItem:i,removeItem:o}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.RECEIVE_LIST=exports.REQUEST_LIST=exports.REMOVE=exports.UPDATE=exports.ADD=void 0;var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e};exports["default"]=makeList;var _utils=require("../../utils"),ADD=exports.ADD="ADD",UPDATE=exports.UPDATE="UPDATE",REMOVE=exports.REMOVE="REMOVE",REQUEST_LIST=exports.REQUEST_LIST="REQUEST_LIST",RECEIVE_LIST=exports.RECEIVE_LIST="RECEIVE_LIST",defaultState={list:[],isFetching:!1,actionsDuringFetch:[],byId:{},indexOf:{}};
-},{"../../utils":32}],27:[function(require,module,exports){
+},{"../../utils":41}],36:[function(require,module,exports){
"use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t<e.length;t++)r[t]=e[t];return r}return Array.from(e)}function sortedIndexOf(e,t,r){r||(r=function(e){return 0});for(var n=0,o=e.length,i=r(t),u=void 0;o>n;)u=n+o>>>1,r(e[u])<i?n=u+1:o=u;for(;e[n].id!==t.id&&r(e[n+1])===i;)n++;return n}function updateViewList(e,t,r,n){var o=arguments.length<=4||void 0===arguments[4]?defaultFilterFn:arguments[4],i=arguments.length<=5||void 0===arguments[5]?defaultSortFn:arguments[5];switch(n.cmd){case _list.REQUEST_LIST:return e;case _list.RECEIVE_LIST:return updateViewFilter(r,o,i);case _list.ADD:return o(n.item)?sortedInsert(e,i,n.item):e;case _list.UPDATE:var u=t.byId[n.item.id],d=n.item,f=o(u),a=o(d);if(!f&&a)return sortedInsert(e,i,n.item);if(f&&!a)return sortedRemove(e,i,n.item);if(f&&a){var s=function(){var t=[].concat(_toConsumableArray(e));return t.indexOf=function(e){return sortedIndexOf(t,e,i)},t[t.indexOf(u)]=d,i&&i(u)!==i(d)&&t.sort(makeCompareFn(i)),{v:t}}();if("object"===("undefined"==typeof s?"undefined":_typeof(s)))return s.v}return e;case _list.REMOVE:var l=o(t.byId[n.item.id]);return l?sortedRemove(e,i,n.item):e;default:return console.error("Unknown list action: ",n),e}}function updateViewFilter(e){var t=arguments.length<=1||void 0===arguments[1]?defaultFilterFn:arguments[1],r=arguments.length<=2||void 0===arguments[2]?defaultSortFn:arguments[2],n=e.list.filter(t);return r&&n.sort(makeCompareFn(r)),n.indexOf=function(e){return sortedIndexOf(n,e,r)},n}function updateViewSort(e){var t=arguments.length<=1||void 0===arguments[1]?defaultSortFn:arguments[1],r=e.slice(0);return t&&r.sort(makeCompareFn(t)),r.indexOf=function(e){return sortedIndexOf(r,e,t)},r}Object.defineProperty(exports,"__esModule",{value:!0});var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};exports.sortedIndexOf=sortedIndexOf,exports.updateViewList=updateViewList,exports.updateViewFilter=updateViewFilter,exports.updateViewSort=updateViewSort;var _list=require("./list"),defaultFilterFn=function(e){return!0},defaultSortFn=!1,makeCompareFn=function(e){var t=function(t,r){var n=e(t),o=e(r);return o>n?-1:n>o?1:0};return t},sortedInsert=function(e,t,r){var n=[].concat(_toConsumableArray(e),[r]);n.indexOf=function(e){return sortedIndexOf(n,e,t)};var o=makeCompareFn(t);return t&&o(e[e.length-1],r)>0&&(console.debug("sorting view..."),n.sort(o)),n},sortedRemove=function(e,t,r){var n=r.id,o=e.filter(function(e){return e.id!==n});return o.indexOf=function(e){return sortedIndexOf(o,e,t)},o};
-},{"./list":26}],28:[function(require,module,exports){
+},{"./list":35}],37:[function(require,module,exports){
"use strict";function reducer(){var e=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],t=arguments[1];switch(t.type){case CONNECTED:return{connected:!0};case DISCONNECTED:return{connected:!1};default:return e}}function connected(){return{type:CONNECTED}}function disconnected(){return{type:DISCONNECTED}}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=reducer,exports.connected=connected,exports.disconnected=disconnected;var CONNECTED="WEBSOCKET_CONNECTED",DISCONNECTED="WEBSOCKET_DISCONNECTED",defaultState={connected:!1};
-},{}],29:[function(require,module,exports){
+},{}],38:[function(require,module,exports){
"use strict";module.exports=function(){function e(e,t){function r(){this.constructor=e}r.prototype=t.prototype,e.prototype=new r}function t(e,r,n,i){this.message=e,this.expected=r,this.found=n,this.location=i,this.name="SyntaxError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,t)}function r(e){function r(t){var r,n,i=Ot[t];if(i)return i;for(r=t-1;!Ot[r];)r--;for(i=Ot[r],i={line:i.line,column:i.column,seenCR:i.seenCR};t>r;)n=e.charAt(r),"\n"===n?(i.seenCR||i.line++,i.column=1,i.seenCR=!1):"\r"===n||"\u2028"===n||"\u2029"===n?(i.line++,i.column=1,i.seenCR=!0):(i.column++,i.seenCR=!1),r++;return Ot[t]=i,i}function n(e,t){var n=r(e),i=r(t);return{start:{offset:e,line:n.line,column:n.column},end:{offset:t,line:i.line,column:i.column}}}function i(e){Pt>Mt||(Mt>Pt&&(Pt=Mt,Qt=[]),Qt.push(e))}function s(e,r,n,i){function s(e){var t=1;for(e.sort(function(e,t){return e.description<t.description?-1:e.description>t.description?1:0});t<e.length;)e[t-1]===e[t]?e.splice(t,1):t++}function u(e,t){function r(e){function t(e){return e.charCodeAt(0).toString(16).toUpperCase()}return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x07\x0B\x0E\x0F]/g,function(e){return"\\x0"+t(e)}).replace(/[\x10-\x1F\x80-\xFF]/g,function(e){return"\\x"+t(e)}).replace(/[\u0100-\u0FFF]/g,function(e){return"\\u0"+t(e)}).replace(/[\u1000-\uFFFF]/g,function(e){return"\\u"+t(e)})}var n,i,s,u=new Array(e.length);for(s=0;s<e.length;s++)u[s]=e[s].description;return n=e.length>1?u.slice(0,-1).join(", ")+" or "+u[e.length-1]:u[0],i=t?'"'+r(t)+'"':"end of input","Expected "+n+" but "+i+" found."}return null!==r&&s(r),new t(null!==e?e:u(r,n),r,n,i)}function u(){var e,t,r,n;return Vt++,e=Mt,t=a(),t!==P?(r=l(),r!==P?(n=a(),n!==P?(Nt=e,t=X(r),e=t):(Mt=e,e=P)):(Mt=e,e=P)):(Mt=e,e=P),Vt--,e===P&&(t=P,0===Vt&&i(W)),e}function c(){var t,r;return Vt++,Z.test(e.charAt(Mt))?(t=e.charAt(Mt),Mt++):(t=P,0===Vt&&i($)),Vt--,t===P&&(r=P,0===Vt&&i(Y)),t}function o(){var t,r;return Vt++,te.test(e.charAt(Mt))?(t=e.charAt(Mt),Mt++):(t=P,0===Vt&&i(re)),Vt--,t===P&&(r=P,0===Vt&&i(ee)),t}function a(){var e,t;for(Vt++,e=[],t=c();t!==P;)e.push(t),t=c();return Vt--,e===P&&(t=P,0===Vt&&i(ne)),e}function l(){var t,r,n,s,u,c;return t=Mt,r=p(),r!==P?(n=a(),n!==P?(124===e.charCodeAt(Mt)?(s=ie,Mt++):(s=P,0===Vt&&i(se)),s!==P?(u=a(),u!==P?(c=l(),c!==P?(Nt=t,r=ue(r,c),t=r):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P),t===P&&(t=p()),t}function p(){var t,r,n,s,u,o;if(t=Mt,r=f(),r!==P?(n=a(),n!==P?(38===e.charCodeAt(Mt)?(s=ce,Mt++):(s=P,0===Vt&&i(oe)),s!==P?(u=a(),u!==P?(o=p(),o!==P?(Nt=t,r=ae(r,o),t=r):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P),t===P){if(t=Mt,r=f(),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=p(),s!==P?(Nt=t,r=ae(r,s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;t===P&&(t=f())}return t}function f(){var t,r,n,s;return t=Mt,33===e.charCodeAt(Mt)?(r=le,Mt++):(r=P,0===Vt&&i(pe)),r!==P?(n=a(),n!==P?(s=f(),s!==P?(Nt=t,r=fe(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P),t===P&&(t=h()),t}function h(){var t,r,n,s,u,c;return t=Mt,40===e.charCodeAt(Mt)?(r=he,Mt++):(r=P,0===Vt&&i(de)),r!==P?(n=a(),n!==P?(s=l(),s!==P?(u=a(),u!==P?(41===e.charCodeAt(Mt)?(c=ve,Mt++):(c=P,0===Vt&&i(ye)),c!==P?(Nt=t,r=ge(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P)):(Mt=t,t=P),t===P&&(t=d()),t}function d(){var e;return e=v(),e===P&&(e=g()),e}function v(){var t,r;return t=y(),t===P&&(t=Mt,e.substr(Mt,2)===Ae?(r=Ae,Mt+=2):(r=P,0===Vt&&i(xe)),r!==P&&(Nt=t,r=Re()),t=r,t===P&&(t=Mt,e.substr(Mt,2)===me?(r=me,Mt+=2):(r=P,0===Vt&&i(qe)),r!==P&&(Nt=t,r=Ce()),t=r,t===P&&(t=Mt,e.substr(Mt,2)===we?(r=we,Mt+=2):(r=P,0===Vt&&i(Ee)),r!==P&&(Nt=t,r=be()),t=r,t===P&&(t=Mt,e.substr(Mt,2)===Fe?(r=Fe,Mt+=2):(r=P,0===Vt&&i(Ue)),r!==P&&(Nt=t,r=je()),t=r)))),t}function y(){var t,r;return t=Mt,e.substr(Mt,4)===Te?(r=Te,Mt+=4):(r=P,0===Vt&&i(_e)),r!==P&&(Nt=t,r=Se()),t=r,t===P&&(t=Mt,e.substr(Mt,5)===ke?(r=ke,Mt+=5):(r=P,0===Vt&&i(Be)),r!==P&&(Nt=t,r=Ie()),t=r),t}function g(){var t,r,n,s;if(t=Mt,e.substr(Mt,2)===ze?(r=ze,Mt+=2):(r=P,0===Vt&&i(De)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=A(),s!==P?(Nt=t,r=Ge(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,2)===He?(r=He,Mt+=2):(r=P,0===Vt&&i(Je)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=Ke(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,2)===Le?(r=Le,Mt+=2):(r=P,0===Vt&&i(Me)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=Ne(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,3)===Oe?(r=Oe,Mt+=3):(r=P,0===Vt&&i(Pe)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=Qe(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,3)===Ve?(r=Ve,Mt+=3):(r=P,0===Vt&&i(We)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=Xe(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,2)===Ye?(r=Ye,Mt+=2):(r=P,0===Vt&&i(Ze)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=$e(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,2)===et?(r=et,Mt+=2):(r=P,0===Vt&&i(tt)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=rt(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,3)===nt?(r=nt,Mt+=3):(r=P,0===Vt&&i(it)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=st(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,3)===ut?(r=ut,Mt+=3):(r=P,0===Vt&&i(ct)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=ot(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,e.substr(Mt,2)===at?(r=at,Mt+=2):(r=P,0===Vt&&i(lt)),r!==P){if(n=[],s=c(),s!==P)for(;s!==P;)n.push(s),s=c();else n=P;n!==P?(s=x(),s!==P?(Nt=t,r=pt(s),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;t===P&&(t=Mt,r=x(),r!==P&&(Nt=t,r=pt(r)),t=r)}}}}}}}}}return t}function A(){var t,r,n,s;if(Vt++,t=Mt,ht.test(e.charAt(Mt))?(r=e.charAt(Mt),Mt++):(r=P,0===Vt&&i(dt)),r===P&&(r=null),r!==P){if(n=[],vt.test(e.charAt(Mt))?(s=e.charAt(Mt),Mt++):(s=P,0===Vt&&i(yt)),s!==P)for(;s!==P;)n.push(s),vt.test(e.charAt(Mt))?(s=e.charAt(Mt),Mt++):(s=P,0===Vt&&i(yt));else n=P;n!==P?(ht.test(e.charAt(Mt))?(s=e.charAt(Mt),Mt++):(s=P,0===Vt&&i(dt)),s===P&&(s=null),s!==P?(Nt=t,r=gt(n),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;return Vt--,t===P&&(r=P,0===Vt&&i(ft)),t}function x(){var t,r,n,s;if(Vt++,t=Mt,34===e.charCodeAt(Mt)?(r=xt,Mt++):(r=P,0===Vt&&i(Rt)),r!==P){for(n=[],s=R();s!==P;)n.push(s),s=R();n!==P?(34===e.charCodeAt(Mt)?(s=xt,Mt++):(s=P,0===Vt&&i(Rt)),s!==P?(Nt=t,r=mt(n),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P){if(t=Mt,39===e.charCodeAt(Mt)?(r=qt,Mt++):(r=P,0===Vt&&i(Ct)),r!==P){for(n=[],s=m();s!==P;)n.push(s),s=m();n!==P?(39===e.charCodeAt(Mt)?(s=qt,Mt++):(s=P,0===Vt&&i(Ct)),s!==P?(Nt=t,r=mt(n),t=r):(Mt=t,t=P)):(Mt=t,t=P)}else Mt=t,t=P;if(t===P)if(t=Mt,r=Mt,Vt++,n=o(),Vt--,n===P?r=void 0:(Mt=r,r=P),r!==P){if(n=[],s=q(),s!==P)for(;s!==P;)n.push(s),s=q();else n=P;n!==P?(Nt=t,r=mt(n),t=r):(Mt=t,t=P)}else Mt=t,t=P}return Vt--,t===P&&(r=P,0===Vt&&i(At)),t}function R(){var t,r,n;return t=Mt,r=Mt,Vt++,wt.test(e.charAt(Mt))?(n=e.charAt(Mt),Mt++):(n=P,0===Vt&&i(Et)),Vt--,n===P?r=void 0:(Mt=r,r=P),r!==P?(e.length>Mt?(n=e.charAt(Mt),Mt++):(n=P,0===Vt&&i(bt)),n!==P?(Nt=t,r=Ft(n),t=r):(Mt=t,t=P)):(Mt=t,t=P),t===P&&(t=Mt,92===e.charCodeAt(Mt)?(r=Ut,Mt++):(r=P,0===Vt&&i(jt)),r!==P?(n=C(),n!==P?(Nt=t,r=Ft(n),t=r):(Mt=t,t=P)):(Mt=t,t=P)),t}function m(){var t,r,n;return t=Mt,r=Mt,Vt++,Tt.test(e.charAt(Mt))?(n=e.charAt(Mt),Mt++):(n=P,0===Vt&&i(_t)),Vt--,n===P?r=void 0:(Mt=r,r=P),r!==P?(e.length>Mt?(n=e.charAt(Mt),Mt++):(n=P,0===Vt&&i(bt)),n!==P?(Nt=t,r=Ft(n),t=r):(Mt=t,t=P)):(Mt=t,t=P),t===P&&(t=Mt,92===e.charCodeAt(Mt)?(r=Ut,Mt++):(r=P,0===Vt&&i(jt)),r!==P?(n=C(),n!==P?(Nt=t,r=Ft(n),t=r):(Mt=t,t=P)):(Mt=t,t=P)),t}function q(){var t,r,n;return t=Mt,r=Mt,Vt++,n=c(),Vt--,n===P?r=void 0:(Mt=r,r=P),r!==P?(e.length>Mt?(n=e.charAt(Mt),Mt++):(n=P,0===Vt&&i(bt)),n!==P?(Nt=t,r=Ft(n),t=r):(Mt=t,t=P)):(Mt=t,t=P),t}function C(){var t,r;return St.test(e.charAt(Mt))?(t=e.charAt(Mt),Mt++):(t=P,0===Vt&&i(kt)),t===P&&(t=Mt,110===e.charCodeAt(Mt)?(r=Bt,Mt++):(r=P,0===Vt&&i(It)),r!==P&&(Nt=t,r=zt()),t=r,t===P&&(t=Mt,114===e.charCodeAt(Mt)?(r=Dt,Mt++):(r=P,0===Vt&&i(Gt)),r!==P&&(Nt=t,r=Ht()),t=r,t===P&&(t=Mt,116===e.charCodeAt(Mt)?(r=Jt,Mt++):(r=P,0===Vt&&i(Kt)),r!==P&&(Nt=t,r=Lt()),t=r))),t}function w(e,t){function r(){return e.apply(this,arguments)||t.apply(this,arguments)}return r.desc=e.desc+" or "+t.desc,r}function E(e,t){function r(){return e.apply(this,arguments)&&t.apply(this,arguments)}return r.desc=e.desc+" and "+t.desc,r}function b(e){function t(){return!e.apply(this,arguments)}return t.desc="not "+e.desc,t}function F(e){function t(){return e.apply(this,arguments)}return t.desc="("+e.desc+")",t}function U(e){return!0}function j(e){return!1}function T(e){if(e.response)for(var t=Wt.ResponseUtils.getContentType(e.response),r=Xt.length;r--;)if(Xt[r].test(t))return!0;return!1}function _(e){function t(t){return t.response&&t.response.status_code===e}return t.desc="resp. code is "+e,t}function S(e){function t(t){return t.request&&e.test(t.request.host)}return e=new RegExp(e,"i"),t.desc="domain matches "+e,t}function k(e){return!!e.error}function B(e){function t(t){return t.request&&Wt.RequestUtils.match_header(t.request,e)||t.response&&Wt.ResponseUtils.match_header(t.response,e)}return e=new RegExp(e,"i"),t.desc="header matches "+e,t}function I(e){function t(t){return t.request&&Wt.RequestUtils.match_header(t.request,e)}return e=new RegExp(e,"i"),t.desc="req. header matches "+e,t}function z(e){function t(t){return t.response&&Wt.ResponseUtils.match_header(t.response,e)}return e=new RegExp(e,"i"),t.desc="resp. header matches "+e,t}function D(e){function t(t){return t.request&&e.test(t.request.method)}return e=new RegExp(e,"i"),t.desc="method matches "+e,t}function G(e){return e.request&&!e.response}function H(e){return!!e.response}function J(e){function t(t){return t.request&&e.test(Wt.RequestUtils.getContentType(t.request))||t.response&&e.test(Wt.ResponseUtils.getContentType(t.response))}return e=new RegExp(e,"i"),t.desc="content type matches "+e,t}function K(e){function t(t){return t.request&&e.test(Wt.RequestUtils.getContentType(t.request))}return e=new RegExp(e,"i"),t.desc="req. content type matches "+e,t}function L(e){function t(t){return t.response&&e.test(Wt.ResponseUtils.getContentType(t.response))}return e=new RegExp(e,"i"),t.desc="resp. content type matches "+e,t}function M(e){function t(t){return t.request&&e.test(Wt.RequestUtils.pretty_url(t.request))}return e=new RegExp(e,"i"),t.desc="url matches "+e,t}var N,O=arguments.length>1?arguments[1]:{},P={},Q={start:u},V=u,W={type:"other",description:"filter expression"},X=function(e){return e},Y={type:"other",description:"whitespace"},Z=/^[ \t\n\r]/,$={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},ee={type:"other",description:"control character"},te=/^[|&!()~"]/,re={type:"class",value:'[|&!()~"]',description:'[|&!()~"]'},ne={type:"other",description:"optional whitespace"},ie="|",se={type:"literal",value:"|",description:'"|"'},ue=function(e,t){return w(e,t)},ce="&",oe={type:"literal",value:"&",description:'"&"'},ae=function(e,t){return E(e,t)},le="!",pe={type:"literal",value:"!",description:'"!"'},fe=function(e){return b(e)},he="(",de={type:"literal",value:"(",description:'"("'},ve=")",ye={type:"literal",value:")",description:'")"'},ge=function(e){return F(e)},Ae="~a",xe={type:"literal",value:"~a",description:'"~a"'},Re=function(){return T},me="~e",qe={type:"literal",value:"~e",description:'"~e"'},Ce=function(){return k},we="~q",Ee={type:"literal",value:"~q",description:'"~q"'},be=function(){return G},Fe="~s",Ue={type:"literal",value:"~s",description:'"~s"'},je=function(){return H},Te="true",_e={type:"literal",value:"true",description:'"true"'},Se=function(){return U},ke="false",Be={type:"literal",value:"false",description:'"false"'},Ie=function(){return j},ze="~c",De={type:"literal",value:"~c",description:'"~c"'},Ge=function(e){return _(e)},He="~d",Je={type:"literal",value:"~d",description:'"~d"'},Ke=function(e){return S(e)},Le="~h",Me={type:"literal",value:"~h",description:'"~h"'},Ne=function(e){return B(e)},Oe="~hq",Pe={type:"literal",value:"~hq",description:'"~hq"'},Qe=function(e){return I(e)},Ve="~hs",We={type:"literal",value:"~hs",description:'"~hs"'},Xe=function(e){return z(e)},Ye="~m",Ze={type:"literal",value:"~m",description:'"~m"'},$e=function(e){return D(e)},et="~t",tt={type:"literal",value:"~t",description:'"~t"'},rt=function(e){return J(e)},nt="~tq",it={type:"literal",value:"~tq",description:'"~tq"'},st=function(e){return K(e)},ut="~ts",ct={type:"literal",value:"~ts",description:'"~ts"'},ot=function(e){return L(e)},at="~u",lt={type:"literal",value:"~u",description:'"~u"'},pt=function(e){return M(e)},ft={type:"other",description:"integer"},ht=/^['"]/,dt={type:"class",value:"['\"]",description:"['\"]"},vt=/^[0-9]/,yt={type:"class",value:"[0-9]",description:"[0-9]"},gt=function(e){return parseInt(e.join(""),10)},At={type:"other",description:"string"},xt='"',Rt={type:"literal",value:'"',description:'"\\""'},mt=function(e){return e.join("")},qt="'",Ct={type:"literal",value:"'",description:'"\'"'},wt=/^["\\]/,Et={type:"class",value:'["\\\\]',description:'["\\\\]'},bt={type:"any",description:"any character"},Ft=function(e){return e},Ut="\\",jt={type:"literal",value:"\\",description:'"\\\\"'},Tt=/^['\\]/,_t={type:"class",value:"['\\\\]",description:"['\\\\]"},St=/^['"\\]/,kt={type:"class",value:"['\"\\\\]",description:"['\"\\\\]"},Bt="n",It={type:"literal",value:"n",description:'"n"'},zt=function(){return"\n"},Dt="r",Gt={type:"literal",value:"r",description:'"r"'},Ht=function(){return"\r"},Jt="t",Kt={type:"literal",value:"t",description:'"t"'},Lt=function(){return" "},Mt=0,Nt=0,Ot=[{line:1,column:1,seenCR:!1}],Pt=0,Qt=[],Vt=0;if("startRule"in O){if(!(O.startRule in Q))throw new Error("Can't start parsing from rule \""+O.startRule+'".');V=Q[O.startRule]}var Wt=require("../flow/utils.js");U.desc="true",j.desc="false";var Xt=[new RegExp("text/javascript"),new RegExp("application/x-javascript"),new RegExp("application/javascript"),new RegExp("text/css"),new RegExp("image/.*"),new RegExp("application/x-shockwave-flash")];if(T.desc="is asset",k.desc="has error",G.desc="has no response",H.desc="has response",N=V(),N!==P&&Mt===e.length)return N;throw N!==P&&Mt<e.length&&i({type:"end",description:"end of input"}),s(null,Qt,Pt<e.length?e.charAt(Pt):null,Pt<e.length?n(Pt,Pt+1):n(Pt,Pt))}return e(t,Error),{SyntaxError:t,parse:r}}();
-},{"../flow/utils.js":30}],30:[function(require,module,exports){
+},{"../flow/utils.js":39}],39:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.parseHttpVersion=exports.isValidHttpVersion=exports.parseUrl=exports.ResponseUtils=exports.RequestUtils=exports.MessageUtils=void 0;var _lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),defaultPorts={http:80,https:443},MessageUtils=exports.MessageUtils={getContentType:function(e){var t=this.get_first_header(e,/^Content-Type$/i);return t?t.split(";")[0].trim():void 0},get_first_header:function(e,t){if(e._headerLookups||Object.defineProperty(e,"_headerLookups",{value:{},configurable:!1,enumerable:!1,writable:!1}),!(t in e._headerLookups)){for(var r,s=0;s<e.headers.length;s++)if(e.headers[s][0].match(t)){r=e.headers[s];break}e._headerLookups[t]=r?r[1]:void 0}return e._headerLookups[t]},match_header:function(e,t){for(var r=e.headers,s=r.length;s--;)if(t.test(r[s].join(" ")))return r[s];return!1},getContentURL:function(e,t){return t===e.request?t="request":t===e.response&&(t="response"),"/flows/"+e.id+"/"+t+"/content"},getContent:function(e,t){var r=MessageUtils.getContentURL(e,t);return _jquery2["default"].get(r)}},RequestUtils=exports.RequestUtils=_lodash2["default"].extend(MessageUtils,{pretty_host:function(e){return e.host},pretty_url:function(e){var t="";return defaultPorts[e.scheme]!==e.port&&(t=":"+e.port),e.scheme+"://"+this.pretty_host(e)+t+e.path}}),ResponseUtils=exports.ResponseUtils=_lodash2["default"].extend(MessageUtils,{}),parseUrl_regex=/^(?:(https?):\/\/)?([^\/:]+)?(?::(\d+))?(\/.*)?$/i,parseUrl=exports.parseUrl=function(e){var t=parseUrl_regex.exec(e);if(!t)return!1;var r=t[1],s=t[2],o=parseInt(t[3]),n=t[4];r&&(o=o||defaultPorts[r]);var i={};return r&&(i.scheme=r),s&&(i.host=s),o&&(i.port=o),n&&(i.path=n),i},isValidHttpVersion_regex=/^HTTP\/\d+(\.\d+)*$/i,isValidHttpVersion=exports.isValidHttpVersion=function(e){return isValidHttpVersion_regex.test(e)},parseHttpVersion=exports.parseHttpVersion=function(e){return e=e.replace("HTTP/","").split("."),_lodash2["default"].map(e,function(e){return parseInt(e)})};
-},{"jquery":"jquery","lodash":"lodash"}],31:[function(require,module,exports){
+},{"jquery":"jquery","lodash":"lodash"}],40:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function DictStore(){_events.EventEmitter.call(this),this.reset()}function LiveStoreMixin(e){this.type=e,this._updates_before_fetch=void 0,this._fetchxhr=!1,this.handle=this.handle.bind(this),_dispatcher.AppDispatcher.register(this.handle),window.ws&&window.ws.readyState===WebSocket.CONNECTING||this.fetch()}function LiveDictStore(e){DictStore.call(this),LiveStoreMixin.call(this,e)}function SettingsStore(){return new LiveDictStore(_actions.ActionTypes.SETTINGS_STORE)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.SettingsStore=SettingsStore;var _lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),_events=require("events"),_actions=require("../actions.js"),_dispatcher=require("../dispatcher.js");_lodash2["default"].extend(DictStore.prototype,_events.EventEmitter.prototype,{update:function(e){_lodash2["default"].merge(this.dict,e),this.emit("recalculate")},reset:function(e){this.dict=e||{},this.emit("recalculate")}}),_lodash2["default"].extend(LiveStoreMixin.prototype,{handle:function(e){return e.type===_actions.ActionTypes.CONNECTION_OPEN?this.fetch():void(e.type===this.type&&(e.cmd===_actions.StoreCmds.RESET?this.fetch(e.data):this._updates_before_fetch?(console.log("defer update",e),this._updates_before_fetch.push(e)):this[e.cmd](e.data)))},close:function(){_dispatcher.AppDispatcher.unregister(this.handle)},fetch:function(e){console.log("fetch "+this.type),this._fetchxhr&&this._fetchxhr.abort(),this._updates_before_fetch=[],e?this.handle_fetch(e):this._fetchxhr=_jquery2["default"].getJSON("/"+this.type).done(function(e){this.handle_fetch(e.data)}.bind(this)).fail(function(){console.error("Could not fetch "+this.type)}.bind(this))},handle_fetch:function(e){this._fetchxhr=!1,console.log(this.type+" fetched.",this._updates_before_fetch),this.reset(e);var t=this._updates_before_fetch;this._updates_before_fetch=!1;for(var i=0;i<t.length;i++)this.handle(t[i])}}),_lodash2["default"].extend(LiveDictStore.prototype,DictStore.prototype,LiveStoreMixin.prototype);
-},{"../actions.js":2,"../dispatcher.js":22,"events":1,"jquery":"jquery","lodash":"lodash"}],32:[function(require,module,exports){
+},{"../actions.js":2,"../dispatcher.js":31,"events":1,"jquery":"jquery","lodash":"lodash"}],41:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function reverseString(e){return String.fromCharCode.apply(String,_lodash2["default"].map(e.split(""),function(e){return 65535-e.charCodeAt(0)}))+end}function getCookie(e){var r=document.cookie.match(new RegExp("\\b"+e+"=([^;]*)\\b"));return r?r[1]:void 0}function fetchApi(e,r){return e+=-1===e.indexOf("?")?"?"+xsrf:"&"+xsrf,fetch(e,_extends({},r,{credentials:"same-origin"}))}Object.defineProperty(exports,"__esModule",{value:!0}),exports.formatTimeStamp=exports.formatTimeDelta=exports.formatSize=exports.Key=void 0;var _extends=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e};exports.reverseString=reverseString,exports.fetchApi=fetchApi;var _jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_actions=require("./actions.js"),_actions2=_interopRequireDefault(_actions);window.$=_jquery2["default"],window._=_lodash2["default"],window.React=require("react");for(var Key=exports.Key={UP:38,DOWN:40,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,LEFT:37,RIGHT:39,ENTER:13,ESC:27,TAB:9,SPACE:32,BACKSPACE:8,SHIFT:16},i=65;90>=i;i++)Key[String.fromCharCode(i)]=i;var formatSize=exports.formatSize=function(e){if(0===e)return"0";for(var r=["b","kb","mb","gb","tb"],t=0;t<r.length&&!(Math.pow(1024,t+1)>e);t++);var o;return o=e%Math.pow(1024,t)===0?0:1,(e/Math.pow(1024,t)).toFixed(o)+r[t]},formatTimeDelta=exports.formatTimeDelta=function(e){for(var r=e,t=["ms","s","min","h"],o=[1e3,60,60],a=0;Math.abs(r)>=o[a]&&a<o.length;)r/=o[a],a++;return Math.round(r)+t[a]},formatTimeStamp=exports.formatTimeStamp=function(e){var r=new Date(1e3*e).toISOString();return r.replace("T"," ").replace("Z","")},end=String.fromCharCode(65535),xsrf="_xsrf="+getCookie("_xsrf");_jquery2["default"].ajaxPrefilter(function(e){["post","put","delete"].indexOf(e.type.toLowerCase())>=0&&"/"===e.url[0]&&(-1===e.url.indexOf("?")?e.url+="?"+xsrf:e.url+="&"+xsrf)}),(0,_jquery2["default"])(document).ajaxError(function(e,r,t,o){if("abort"!==o){var a=r.responseText;console.error(o,a,arguments),alert(a)}});
},{"./actions.js":2,"jquery":"jquery","lodash":"lodash","react":"react"}]},{},[3])
diff --git a/web/conf.js b/web/conf.js
index 7fe75da4..cc616a63 100644
--- a/web/conf.js
+++ b/web/conf.js
@@ -11,7 +11,7 @@ var conf = {
// Package these as well as the dependencies
vendor_includes: [
],
- app: 'src/js/app.js',
+ app: 'src/js/app',
eslint: ["src/js/**/*.js", "!src/js/filt/filt.js"]
},
css: {
@@ -27,4 +27,4 @@ var conf = {
peg: ["src/js/filt/filt.peg"]
};
-module.exports = conf; \ No newline at end of file
+module.exports = conf;
diff --git a/web/gulpfile.js b/web/gulpfile.js
index ffa5387a..4a8c765f 100644
--- a/web/gulpfile.js
+++ b/web/gulpfile.js
@@ -142,6 +142,7 @@ function app_stream(dev) {
var bundler = browserify({
entries: [conf.js.app],
debug: true,
+ extensions: ['.jsx'],
cache: {}, // required for watchify
packageCache: {} // required for watchify
});
diff --git a/web/src/js/app.js b/web/src/js/app.jsx
index 8fa52a00..8fa52a00 100644
--- a/web/src/js/app.js
+++ b/web/src/js/app.jsx
diff --git a/web/src/js/components/EventLog.jsx b/web/src/js/components/EventLog.jsx
new file mode 100644
index 00000000..24b3c2bf
--- /dev/null
+++ b/web/src/js/components/EventLog.jsx
@@ -0,0 +1,41 @@
+import React, { PropTypes } from 'react'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+import { toggleEventLogFilter, toggleEventLogVisibility } from '../ducks/eventLog'
+import { ToggleButton } from './common'
+import EventList from './EventLog/EventList'
+
+EventLog.propTypes = {
+ filters: PropTypes.object.isRequired,
+ events: PropTypes.array.isRequired,
+ onToggleFilter: PropTypes.func.isRequired,
+ onClose: PropTypes.func.isRequired
+}
+
+function EventLog({ filters, events, onToggleFilter, onClose }) {
+ return (
+ <div className="eventlog">
+ <div>
+ Eventlog
+ <div className="pull-right">
+ {['debug', 'info', 'web'].map(type => (
+ <ToggleButton key={type} text={type} checked={filters[type]} onToggle={() => onToggleFilter(type)}/>
+ ))}
+ <i onClick={onClose} className="fa fa-close"></i>
+ </div>
+ </div>
+ <EventList events={events} />
+ </div>
+ )
+}
+
+export default connect(
+ state => ({
+ filters: state.eventLog.filter,
+ events: state.eventLog.filteredEvents,
+ }),
+ dispatch => bindActionCreators({
+ onClose: toggleEventLogVisibility,
+ onToggleFilter: toggleEventLogFilter,
+ }, dispatch)
+)(EventLog)
diff --git a/web/src/js/components/EventLog/EventList.jsx b/web/src/js/components/EventLog/EventList.jsx
new file mode 100644
index 00000000..d0b036e7
--- /dev/null
+++ b/web/src/js/components/EventLog/EventList.jsx
@@ -0,0 +1,90 @@
+import React, { Component, PropTypes } from 'react'
+import ReactDOM from 'react-dom'
+import shallowEqual from 'shallowequal'
+import AutoScroll from '../helpers/AutoScroll'
+import { calcVScroll } from '../helpers/VirtualScroll'
+
+class EventLogList extends Component {
+
+ static propTypes = {
+ events: PropTypes.array.isRequired,
+ rowHeight: PropTypes.number,
+ }
+
+ static defaultProps = {
+ rowHeight: 18,
+ }
+
+ constructor(props) {
+ super(props)
+
+ this.heights = {}
+ this.state = { vScroll: calcVScroll() }
+
+ this.onViewportUpdate = this.onViewportUpdate.bind(this)
+ }
+
+ componentDidMount() {
+ window.addEventListener('resize', this.onViewportUpdate)
+ this.onViewportUpdate()
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.onViewportUpdate)
+ }
+
+ componentDidUpdate() {
+ this.onViewportUpdate()
+ }
+
+ onViewportUpdate() {
+ const viewport = ReactDOM.findDOMNode(this)
+
+ const vScroll = calcVScroll({
+ itemCount: this.props.events.length,
+ rowHeight: this.props.rowHeight,
+ viewportTop: viewport.scrollTop,
+ viewportHeight: viewport.offsetHeight,
+ itemHeights: this.props.events.map(entry => this.heights[entry.id]),
+ })
+
+ if (!shallowEqual(this.state.vScroll, vScroll)) {
+ this.setState({vScroll})
+ }
+ }
+
+ setHeight(id, node) {
+ if (node && !this.heights[id]) {
+ const height = node.offsetHeight
+ if (this.heights[id] !== height) {
+ this.heights[id] = height
+ this.onViewportUpdate()
+ }
+ }
+ }
+
+ render() {
+ const { vScroll } = this.state
+ const { events } = this.props
+
+ return (
+ <pre onScroll={this.onViewportUpdate}>
+ <div style={{ height: vScroll.paddingTop }}></div>
+ {events.slice(vScroll.start, vScroll.end).map(event => (
+ <div key={event.id} ref={node => this.setHeight(event.id, node)}>
+ <LogIcon event={event}/>
+ {event.message}
+ </div>
+ ))}
+ <div style={{ height: vScroll.paddingBottom }}></div>
+ </pre>
+ )
+ }
+}
+
+function LogIcon({ event }) {
+ const icon = { web: 'html5', debug: 'bug' }[event.level] || 'info'
+ return <i className={`fa fa-fw fa-${icon}`}></i>
+}
+
+export default AutoScroll(EventLogList)
diff --git a/web/src/js/components/FlowTable.jsx b/web/src/js/components/FlowTable.jsx
new file mode 100644
index 00000000..eddeed62
--- /dev/null
+++ b/web/src/js/components/FlowTable.jsx
@@ -0,0 +1,120 @@
+import React, { PropTypes } from 'react'
+import ReactDOM from 'react-dom'
+import shallowEqual from 'shallowequal'
+import AutoScroll from './helpers/AutoScroll'
+import { calcVScroll } from './helpers/VirtualScroll'
+import FlowTableHead from './FlowTable/FlowTableHead'
+import FlowRow from './FlowTable/FlowRow'
+import Filt from "../filt/filt"
+
+class FlowTable extends React.Component {
+
+ static propTypes = {
+ onSelect: PropTypes.func.isRequired,
+ flows: PropTypes.array.isRequired,
+ rowHeight: PropTypes.number,
+ highlight: PropTypes.string,
+ selected: PropTypes.object,
+ }
+
+ static defaultProps = {
+ rowHeight: 32,
+ }
+
+ constructor(props, context) {
+ super(props, context)
+
+ this.state = { vScroll: calcVScroll() }
+ this.onViewportUpdate = this.onViewportUpdate.bind(this)
+ }
+
+ componentWillMount() {
+ window.addEventListener('resize', this.onViewportUpdate)
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.onViewportUpdate)
+ }
+
+ componentDidUpdate() {
+ this.onViewportUpdate()
+
+ if (!this.shouldScrollIntoView) {
+ return
+ }
+
+ this.shouldScrollIntoView = false
+
+ const { rowHeight, flows, selected } = this.props
+ const viewport = ReactDOM.findDOMNode(this)
+ const head = ReactDOM.findDOMNode(this.refs.head)
+
+ const headHeight = head ? head.offsetHeight : 0
+
+ const rowTop = (flows.indexOf(selected) * rowHeight) + headHeight
+ const rowBottom = rowTop + rowHeight
+
+ const viewportTop = viewport.scrollTop
+ const viewportHeight = viewport.offsetHeight
+
+ // Account for pinned thead
+ if (rowTop - headHeight < viewportTop) {
+ viewport.scrollTop = rowTop - headHeight
+ } else if (rowBottom > viewportTop + viewportHeight) {
+ viewport.scrollTop = rowBottom - viewportHeight
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.selected && nextProps.selected !== this.props.selected) {
+ this.shouldScrollIntoView = true
+ }
+ }
+
+ onViewportUpdate() {
+ const viewport = ReactDOM.findDOMNode(this)
+ const viewportTop = viewport.scrollTop
+
+ const vScroll = calcVScroll({
+ viewportTop,
+ viewportHeight: viewport.offsetHeight,
+ itemCount: this.props.flows.length,
+ rowHeight: this.props.rowHeight,
+ })
+
+ if (this.state.viewportTop !== viewportTop || !shallowEqual(this.state.vScroll, vScroll)) {
+ this.setState({ vScroll, viewportTop })
+ }
+ }
+
+ render() {
+ const { vScroll, viewportTop } = this.state
+ const { flows, selected, highlight } = this.props
+ const isHighlighted = highlight ? Filt.parse(highlight) : () => false
+
+ return (
+ <div className="flow-table" onScroll={this.onViewportUpdate}>
+ <table>
+ <thead ref="head" style={{ transform: `translateY(${viewportTop}px)` }}>
+ <FlowTableHead />
+ </thead>
+ <tbody>
+ <tr style={{ height: vScroll.paddingTop }}></tr>
+ {flows.slice(vScroll.start, vScroll.end).map(flow => (
+ <FlowRow
+ key={flow.id}
+ flow={flow}
+ selected={flow === selected}
+ highlighted={isHighlighted(flow)}
+ onSelect={this.props.onSelect}
+ />
+ ))}
+ <tr style={{ height: vScroll.paddingBottom }}></tr>
+ </tbody>
+ </table>
+ </div>
+ )
+ }
+}
+
+export default AutoScroll(FlowTable)
diff --git a/web/src/js/components/FlowTable/FlowColumns.jsx b/web/src/js/components/FlowTable/FlowColumns.jsx
new file mode 100644
index 00000000..11c0796c
--- /dev/null
+++ b/web/src/js/components/FlowTable/FlowColumns.jsx
@@ -0,0 +1,137 @@
+import React, { Component } from 'react'
+import classnames from 'classnames'
+import { RequestUtils, ResponseUtils } from '../../flow/utils.js'
+import { formatSize, formatTimeDelta } from '../../utils.js'
+
+export function TLSColumn({ flow }) {
+ return (
+ <td className={classnames('col-tls', flow.request.scheme === 'https' ? 'col-tls-https' : 'col-tls-http')}></td>
+ )
+}
+
+TLSColumn.sortKeyFun = flow => flow.request.scheme
+TLSColumn.headerClass = 'col-tls'
+TLSColumn.headerName = ''
+
+export function IconColumn({ flow }) {
+ return (
+ <td className="col-icon">
+ <div className={classnames('resource-icon', IconColumn.getIcon(flow))}></div>
+ </td>
+ )
+}
+
+IconColumn.headerClass = 'col-icon'
+IconColumn.headerName = ''
+
+IconColumn.getIcon = flow => {
+ if (!flow.response) {
+ return 'resource-icon-plain'
+ }
+
+ var contentType = ResponseUtils.getContentType(flow.response) || ''
+
+ // @todo We should assign a type to the flow somewhere else.
+ if (flow.response.status_code === 304) {
+ return 'resource-icon-not-modified'
+ }
+ if (300 <= flow.response.status_code && flow.response.status_code < 400) {
+ return 'resource-icon-redirect'
+ }
+ if (contentType.indexOf('image') >= 0) {
+ return 'resource-icon-image'
+ }
+ if (contentType.indexOf('javascript') >= 0) {
+ return 'resource-icon-js'
+ }
+ if (contentType.indexOf('css') >= 0) {
+ return 'resource-icon-css'
+ }
+ if (contentType.indexOf('html') >= 0) {
+ return 'resource-icon-document'
+ }
+
+ return 'resource-icon-plain'
+}
+
+export function PathColumn({ flow }) {
+ return (
+ <td className="col-path">
+ {flow.request.is_replay && (
+ <i className="fa fa-fw fa-repeat pull-right"></i>
+ )}
+ {flow.intercepted && (
+ <i className="fa fa-fw fa-pause pull-right"></i>
+ )}
+ {RequestUtils.pretty_url(flow.request)}
+ </td>
+ )
+}
+
+PathColumn.sortKeyFun = flow => RequestUtils.pretty_url(flow.request)
+PathColumn.headerClass = 'col-path'
+PathColumn.headerName = 'Path'
+
+export function MethodColumn({ flow }) {
+ return (
+ <td className="col-method">{flow.request.method}</td>
+ )
+}
+
+MethodColumn.sortKeyFun = flow => flow.request.method
+MethodColumn.headerClass = 'col-method'
+MethodColumn.headerName = 'Method'
+
+export function StatusColumn({ flow }) {
+ return (
+ <td className="col-status">{flow.response && flow.response.status_code}</td>
+ )
+}
+
+StatusColumn.sortKeyFun = flow => flow.response && flow.response.status_code
+StatusColumn.headerClass = 'col-status'
+StatusColumn.headerName = 'Status'
+
+export function SizeColumn({ flow }) {
+ return (
+ <td className="col-size">{formatSize(SizeColumn.getTotalSize(flow))}</td>
+ )
+}
+
+SizeColumn.sortKeyFun = flow => {
+ let total = flow.request.contentLength
+ if (flow.response) {
+ total += flow.response.contentLength || 0
+ }
+ return total
+}
+
+SizeColumn.getTotalSize = SizeColumn.sortKeyFun
+SizeColumn.headerClass = 'col-size'
+SizeColumn.headerName = 'Size'
+
+export function TimeColumn({ flow }) {
+ return (
+ <td className="col-time">
+ {flow.response ? (
+ formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start))
+ ) : (
+ '...'
+ )}
+ </td>
+ )
+}
+
+TimeColumn.sortKeyFun = flow => flow.response && flow.response.timestamp_end - flow.request.timestamp_start
+TimeColumn.headerClass = 'col-time'
+TimeColumn.headerName = 'Time'
+
+export default [
+ TLSColumn,
+ IconColumn,
+ PathColumn,
+ MethodColumn,
+ StatusColumn,
+ SizeColumn,
+ TimeColumn,
+]
diff --git a/web/src/js/components/FlowTable/FlowRow.jsx b/web/src/js/components/FlowTable/FlowRow.jsx
new file mode 100644
index 00000000..749bc0ce
--- /dev/null
+++ b/web/src/js/components/FlowTable/FlowRow.jsx
@@ -0,0 +1,28 @@
+import React, { PropTypes } from 'react'
+import classnames from 'classnames'
+import columns from './FlowColumns'
+
+FlowRow.propTypes = {
+ onSelect: PropTypes.func.isRequired,
+ flow: PropTypes.object.isRequired,
+ highlighted: PropTypes.bool,
+ selected: PropTypes.bool,
+}
+
+export default function FlowRow({ flow, selected, highlighted, onSelect }) {
+ const className = classnames({
+ 'selected': selected,
+ 'highlighted': highlighted,
+ 'intercepted': flow.intercepted,
+ 'has-request': flow.request,
+ 'has-response': flow.response,
+ })
+
+ return (
+ <tr className={className} onClick={() => onSelect(flow)}>
+ {columns.map(Column => (
+ <Column key={Column.name} flow={flow}/>
+ ))}
+ </tr>
+ )
+}
diff --git a/web/src/js/components/FlowTable/FlowTableHead.jsx b/web/src/js/components/FlowTable/FlowTableHead.jsx
new file mode 100644
index 00000000..a46219d1
--- /dev/null
+++ b/web/src/js/components/FlowTable/FlowTableHead.jsx
@@ -0,0 +1,43 @@
+import React, { PropTypes } from 'react'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+import classnames from 'classnames'
+import columns from './FlowColumns'
+
+import { setSort } from "../../ducks/flows"
+
+FlowTableHead.propTypes = {
+ onSort: PropTypes.func.isRequired,
+ sortDesc: React.PropTypes.bool.isRequired,
+ sortColumn: React.PropTypes.string,
+}
+
+function FlowTableHead({ sortColumn, sortDesc, onSort }) {
+ const sortType = sortDesc ? 'sort-desc' : 'sort-asc'
+
+ return (
+ <tr>
+ {columns.map(Column => (
+ <th className={classnames(Column.headerClass, sortColumn === Column.name && sortType)}
+ key={Column.name}
+ onClick={() => onClick(Column)}>
+ {Column.headerName}
+ </th>
+ ))}
+ </tr>
+ )
+
+ function onClick(Column) {
+ onSort({ sortColumn: Column.name, sortDesc: Column.name !== sortColumn ? false : !sortDesc })
+ }
+}
+
+export default connect(
+ state => ({
+ sortDesc: state.flows.sort.sortDesc,
+ sortColumn: state.flows.sort.sortColumn,
+ }),
+ dispatch => bindActionCreators({
+ onSort: setSort,
+ }, dispatch)
+)(FlowTableHead)
diff --git a/web/src/js/components/footer.js b/web/src/js/components/Footer.jsx
index 8fe1081b..903522f4 100644
--- a/web/src/js/components/footer.js
+++ b/web/src/js/components/Footer.jsx
@@ -1,50 +1,47 @@
-import React from "react";
-import {formatSize} from "../utils.js"
-import {SettingsState} from "./common.js";
+import React from 'react'
+import { formatSize } from '../utils.js'
+import { SettingsState } from './common.js'
Footer.propTypes = {
settings: React.PropTypes.object.isRequired,
-};
+}
export default function Footer({ settings }) {
- const {mode, intercept, showhost, no_upstream_cert, rawtcp, http2, anticache, anticomp, stickyauth, stickycookie, stream} = settings;
return (
<footer>
- {mode && mode != "regular" && (
- <span className="label label-success">{mode} mode</span>
+ {settings.mode && settings.mode != "regular" && (
+ <span className="label label-success">{settings.mode} mode</span>
)}
- {intercept && (
- <span className="label label-success">Intercept: {intercept}</span>
+ {settings.intercept && (
+ <span className="label label-success">Intercept: {settings.intercept}</span>
)}
- {showhost && (
+ {settings.showhost && (
<span className="label label-success">showhost</span>
)}
- {no_upstream_cert && (
+ {settings.no_upstream_cert && (
<span className="label label-success">no-upstream-cert</span>
)}
- {rawtcp && (
+ {settings.rawtcp && (
<span className="label label-success">raw-tcp</span>
)}
- {!http2 && (
+ {!settings.http2 && (
<span className="label label-success">no-http2</span>
)}
- {anticache && (
+ {settings.anticache && (
<span className="label label-success">anticache</span>
)}
- {anticomp && (
+ {settings.anticomp && (
<span className="label label-success">anticomp</span>
)}
- {stickyauth && (
- <span className="label label-success">stickyauth: {stickyauth}</span>
+ {settings.stickyauth && (
+ <span className="label label-success">stickyauth: {settings.stickyauth}</span>
)}
- {stickycookie && (
- <span className="label label-success">stickycookie: {stickycookie}</span>
+ {settings.stickycookie && (
+ <span className="label label-success">stickycookie: {settings.stickycookie}</span>
)}
- {stream && (
- <span className="label label-success">stream: {formatSize(stream)}</span>
+ {settings.stream && (
+ <span className="label label-success">stream: {formatSize(settings.stream)}</span>
)}
-
-
</footer>
- );
+ )
}
diff --git a/web/src/js/components/Header.js b/web/src/js/components/Header.js
new file mode 100644
index 00000000..7134f7d9
--- /dev/null
+++ b/web/src/js/components/Header.js
@@ -0,0 +1,56 @@
+import React, { Component, PropTypes } from 'react'
+import classnames from 'classnames'
+import { toggleEventLogVisibility } from '../ducks/eventLog'
+import MainMenu from './Header/MainMenu'
+import ViewMenu from './Header/ViewMenu'
+import OptionMenu from './Header/OptionMenu'
+import FileMenu from './Header/FileMenu'
+
+export default class Header extends Component {
+
+ static entries = [MainMenu, ViewMenu, OptionMenu]
+
+ static propTypes = {
+ settings: PropTypes.object.isRequired,
+ }
+
+ constructor(props, context) {
+ super(props, context)
+ this.state = { active: Header.entries[0] }
+ }
+
+ handleClick(active, e) {
+ e.preventDefault()
+ this.props.updateLocation(active.route)
+ this.setState({ active })
+ }
+
+ render() {
+ const { active: Active } = this.state
+ const { settings, updateLocation, query } = this.props
+
+ return (
+ <header>
+ <nav className="nav-tabs nav-tabs-lg">
+ <FileMenu/>
+ {Header.entries.map(Entry => (
+ <a key={Entry.title}
+ href="#"
+ className={classnames({ active: Entry === Active })}
+ onClick={e => this.handleClick(Entry, e)}>
+ {Entry.title}
+ </a>
+ ))}
+ </nav>
+ <div className="menu">
+ <Active
+ ref="active"
+ settings={settings}
+ updateLocation={updateLocation}
+ query={query}
+ />
+ </div>
+ </header>
+ )
+ }
+}
diff --git a/web/src/js/components/Header/FileMenu.jsx b/web/src/js/components/Header/FileMenu.jsx
new file mode 100644
index 00000000..b075b3c8
--- /dev/null
+++ b/web/src/js/components/Header/FileMenu.jsx
@@ -0,0 +1,100 @@
+import React, { Component } from 'react'
+import classnames from 'classnames'
+import { FlowActions } from '../../actions.js'
+
+export default class FileMenu extends Component {
+
+ constructor(props, context) {
+ super(props, context)
+ this.state = { show: false }
+
+ this.close = this.close.bind(this)
+ this.onFileClick = this.onFileClick.bind(this)
+ this.onNewClick = this.onNewClick.bind(this)
+ this.onOpenClick = this.onOpenClick.bind(this)
+ this.onOpenFile = this.onOpenFile.bind(this)
+ this.onSaveClick = this.onSaveClick.bind(this)
+ }
+
+ close() {
+ this.setState({ show: false })
+ document.removeEventListener('click', this.close)
+ }
+
+ onFileClick(e) {
+ e.preventDefault()
+
+ if (this.state.show) {
+ return
+ }
+
+ document.addEventListener('click', this.close)
+ this.setState({ show: true })
+ }
+
+ onNewClick(e) {
+ e.preventDefault()
+ if (confirm('Delete all flows?')) {
+ FlowActions.clear()
+ }
+ }
+
+ onOpenClick(e) {
+ e.preventDefault()
+ this.fileInput.click()
+ }
+
+ onOpenFile(e) {
+ e.preventDefault()
+ if (e.target.files.length > 0) {
+ FlowActions.upload(e.target.files[0])
+ this.fileInput.value = ''
+ }
+ }
+
+ onSaveClick(e) {
+ e.preventDefault()
+ FlowActions.download()
+ }
+
+ render() {
+ return (
+ <div className={classnames('dropdown pull-left', { open: this.state.show })}>
+ <a href="#" className="special" onClick={this.onFileClick}>mitmproxy</a>
+ <ul className="dropdown-menu" role="menu">
+ <li>
+ <a href="#" onClick={this.onNewClick}>
+ <i className="fa fa-fw fa-file"></i>
+ New
+ </a>
+ </li>
+ <li>
+ <a href="#" onClick={this.onOpenClick}>
+ <i className="fa fa-fw fa-folder-open"></i>
+ Open...
+ </a>
+ <input
+ ref={ref => this.fileInput = ref}
+ className="hidden"
+ type="file"
+ onChange={this.onOpenFile}
+ />
+ </li>
+ <li>
+ <a href="#" onClick={this.onSaveClick}>
+ <i className="fa fa-fw fa-floppy-o"></i>
+ Save...
+ </a>
+ </li>
+ <li role="presentation" className="divider"></li>
+ <li>
+ <a href="http://mitm.it/" target="_blank">
+ <i className="fa fa-fw fa-external-link"></i>
+ Install Certificates...
+ </a>
+ </li>
+ </ul>
+ </div>
+ )
+ }
+}
diff --git a/web/src/js/components/Header/FilterDocs.jsx b/web/src/js/components/Header/FilterDocs.jsx
new file mode 100644
index 00000000..efb4818c
--- /dev/null
+++ b/web/src/js/components/Header/FilterDocs.jsx
@@ -0,0 +1,56 @@
+import React, { Component } from 'react'
+import $ from 'jquery'
+
+export default class FilterDocs extends Component {
+
+ // @todo move to redux
+
+ static xhr = null
+ static doc = null
+
+ constructor(props, context) {
+ super(props, context)
+ this.state = { doc: FilterDocs.doc }
+ }
+
+ componentWillMount() {
+ if (!FilterDocs.xhr) {
+ FilterDocs.xhr = $.getJSON('/filter-help')
+ FilterDocs.xhr.fail(() => {
+ FilterDocs.xhr = null
+ })
+ }
+ if (!this.state.doc) {
+ FilterDocs.xhr.done(doc => {
+ FilterDocs.doc = doc
+ this.setState({ doc })
+ })
+ }
+ }
+
+ render() {
+ const { doc } = this.state
+ return !doc ? (
+ <i className="fa fa-spinner fa-spin"></i>
+ ) : (
+ <table className="table table-condensed">
+ <tbody>
+ {doc.commands.map(cmd => (
+ <tr key={cmd[1]}>
+ <td>{cmd[0].replace(' ', '\u00a0')}</td>
+ <td>{cmd[1]}</td>
+ </tr>
+ ))}
+ <tr key="docs-link">
+ <td colSpan="2">
+ <a href="http://docs.mitmproxy.org/en/stable/features/filters.html"
+ target="_blank">
+ <i className="fa fa-external-link"></i>
+ &nbsp mitmproxy docs</a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ )
+ }
+}
diff --git a/web/src/js/components/Header/FilterInput.jsx b/web/src/js/components/Header/FilterInput.jsx
new file mode 100644
index 00000000..5b49b788
--- /dev/null
+++ b/web/src/js/components/Header/FilterInput.jsx
@@ -0,0 +1,133 @@
+import React, { PropTypes, Component } from 'react'
+import ReactDOM from 'react-dom'
+import classnames from 'classnames'
+import { Key } from '../../utils.js'
+import Filt from '../../filt/filt'
+import FilterDocs from './FilterDocs'
+
+export default class FilterInput extends Component {
+
+ static contextTypes = {
+ returnFocus: React.PropTypes.func,
+ }
+
+ constructor(props, context) {
+ super(props, context)
+
+ // Consider both focus and mouseover for showing/hiding the tooltip,
+ // because onBlur of the input is triggered before the click on the tooltip
+ // finalized, hiding the tooltip just as the user clicks on it.
+ this.state = { value: this.props.value, focus: false, mousefocus: false }
+
+ this.onChange = this.onChange.bind(this)
+ this.onFocus = this.onFocus.bind(this)
+ this.onBlur = this.onBlur.bind(this)
+ this.onKeyDown = this.onKeyDown.bind(this)
+ this.onMouseEnter = this.onMouseEnter.bind(this)
+ this.onMouseLeave = this.onMouseLeave.bind(this)
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({ value: nextProps.value })
+ }
+
+ isValid(filt) {
+ try {
+ const str = filt == null ? this.state.value : filt
+ if (str) {
+ Filt.parse(str)
+ }
+ return true
+ } catch (e) {
+ return false
+ }
+ }
+
+ getDesc() {
+ if (!this.state.value) {
+ return <FilterDocs/>
+ }
+ try {
+ return Filt.parse(this.state.value).desc
+ } catch (e) {
+ return '' + e
+ }
+ }
+
+ onChange(e) {
+ const value = e.target.value
+ this.setState({ value })
+
+ // Only propagate valid filters upwards.
+ if (this.isValid(value)) {
+ this.props.onChange(value)
+ }
+ }
+
+ onFocus() {
+ this.setState({ focus: true })
+ }
+
+ onBlur() {
+ this.setState({ focus: false })
+ }
+
+ onMouseEnter() {
+ this.setState({ mousefocus: true })
+ }
+
+ onMouseLeave() {
+ this.setState({ mousefocus: false })
+ }
+
+ onKeyDown(e) {
+ if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) {
+ this.blur()
+ // If closed using ESC/ENTER, hide the tooltip.
+ this.setState({mousefocus: false})
+ }
+ e.stopPropagation()
+ }
+
+ blur() {
+ ReactDOM.findDOMNode(this.refs.input).blur()
+ this.context.returnFocus()
+ }
+
+ select() {
+ ReactDOM.findDOMNode(this.refs.input).select()
+ }
+
+ render() {
+ const { type, color, placeholder } = this.props
+ const { value, focus, mousefocus } = this.state
+ return (
+ <div className={classnames('filter-input input-group', { 'has-error': !this.isValid() })}>
+ <span className="input-group-addon">
+ <i className={'fa fa-fw fa-' + type} style={{ color }}></i>
+ </span>
+ <input
+ type="text"
+ ref="input"
+ placeholder={placeholder}
+ className="form-control"
+ value={value}
+ onChange={this.onChange}
+ onFocus={this.onFocus}
+ onBlur={this.onBlur}
+ onKeyDown={this.onKeyDown}
+ />
+ {(focus || mousefocus) && (
+ <div className="popover bottom"
+ onMouseEnter={this.onMouseEnter}
+ onMouseLeave={this.onMouseLeave}>
+ <div className="arrow"></div>
+ <div className="popover-content">
+ {this.getDesc()}
+ </div>
+ </div>
+ )}
+ </div>
+ )
+ }
+}
diff --git a/web/src/js/components/Header/MainMenu.jsx b/web/src/js/components/Header/MainMenu.jsx
new file mode 100644
index 00000000..86bf961a
--- /dev/null
+++ b/web/src/js/components/Header/MainMenu.jsx
@@ -0,0 +1,73 @@
+import React, { Component, PropTypes } from 'react'
+import { SettingsActions } from "../../actions.js"
+import FilterInput from './FilterInput'
+import { Query } from '../../actions.js'
+
+export default class MainMenu extends Component {
+
+ static title = 'Start'
+ static route = 'flows'
+
+ static propTypes = {
+ settings: React.PropTypes.object.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) {
+ this.props.updateLocation(undefined, { [Query.SEARCH]: val })
+ }
+
+ onHighlightChange(val) {
+ this.props.updateLocation(undefined, { [Query.HIGHLIGHT]: val })
+ }
+
+ onInterceptChange(val) {
+ SettingsActions.update({ intercept: val })
+ }
+
+ render() {
+ const { query, settings } = this.props
+
+ const search = query[Query.SEARCH] || ''
+ const highlight = query[Query.HIGHLIGHT] || ''
+ const intercept = settings.intercept || ''
+
+ return (
+ <div>
+ <div className="menu-row">
+ <FilterInput
+ ref="search"
+ placeholder="Search"
+ type="search"
+ color="black"
+ value={search}
+ onChange={this.onSearchChange}
+ />
+ <FilterInput
+ ref="highlight"
+ placeholder="Highlight"
+ type="tag"
+ color="hsl(48, 100%, 50%)"
+ value={highlight}
+ onChange={this.onHighlightChange}
+ />
+ <FilterInput
+ ref="intercept"
+ placeholder="Intercept"
+ type="pause"
+ color="hsl(208, 56%, 53%)"
+ value={intercept}
+ onChange={this.onInterceptChange}
+ />
+ </div>
+ <div className="clearfix"></div>
+ </div>
+ )
+ }
+}
diff --git a/web/src/js/components/Header/OptionMenu.jsx b/web/src/js/components/Header/OptionMenu.jsx
new file mode 100644
index 00000000..6bbf15d5
--- /dev/null
+++ b/web/src/js/components/Header/OptionMenu.jsx
@@ -0,0 +1,60 @@
+import React, { PropTypes } from 'react'
+import { ToggleInputButton, ToggleButton } from '../common.js'
+import { SettingsActions } from '../../actions.js'
+
+OptionMenu.title = "Options"
+
+OptionMenu.propTypes = {
+ settings: PropTypes.object.isRequired,
+}
+
+export default function OptionMenu({ settings }) {
+ // @todo use settings.map
+ return (
+ <div>
+ <div className="menu-row">
+ <ToggleButton text="showhost"
+ checked={settings.showhost}
+ onToggle={() => SettingsActions.update({ showhost: !settings.showhost })}
+ />
+ <ToggleButton text="no_upstream_cert"
+ checked={settings.no_upstream_cert}
+ onToggle={() => SettingsActions.update({ no_upstream_cert: !settings.no_upstream_cert })}
+ />
+ <ToggleButton text="rawtcp"
+ checked={settings.rawtcp}
+ onToggle={() => SettingsActions.update({ rawtcp: !settings.rawtcp })}
+ />
+ <ToggleButton text="http2"
+ checked={settings.http2}
+ onToggle={() => SettingsActions.update({ http2: !settings.http2 })}
+ />
+ <ToggleButton text="anticache"
+ checked={settings.anticache}
+ onToggle={() => SettingsActions.update({ anticache: !settings.anticache })}
+ />
+ <ToggleButton text="anticomp"
+ checked={settings.anticomp}
+ onToggle={() => SettingsActions.update({ 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 })}
+ />
+ <ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter"
+ checked={!!settings.stickycookie}
+ txt={settings.stickycookie || ''}
+ onToggleChanged={txt => SettingsActions.update({ 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 })}
+ />
+ </div>
+ <div className="clearfix"/>
+ </div>
+ )
+}
diff --git a/web/src/js/components/Header/ViewMenu.jsx b/web/src/js/components/Header/ViewMenu.jsx
new file mode 100644
index 00000000..45359a83
--- /dev/null
+++ b/web/src/js/components/Header/ViewMenu.jsx
@@ -0,0 +1,33 @@
+import React, { PropTypes } from 'react'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+import { ToggleButton } from '../common.js'
+import { toggleEventLogVisibility } from '../../ducks/eventLog'
+
+ViewMenu.title = 'View'
+ViewMenu.route = 'flows'
+
+ViewMenu.propTypes = {
+ visible: PropTypes.bool.isRequired,
+ onToggle: PropTypes.func.isRequired,
+}
+
+function ViewMenu({ visible, onToggle }) {
+ return (
+ <div>
+ <div className="menu-row">
+ <ToggleButton text="Show Event Log" checked={visible} onToggle={onToggle} />
+ </div>
+ <div className="clearfix"></div>
+ </div>
+ )
+}
+
+export default connect(
+ state => ({
+ visible: state.eventLog.visible,
+ }),
+ dispatch => bindActionCreators({
+ onToggle: toggleEventLogVisibility,
+ }, dispatch)
+)(ViewMenu)
diff --git a/web/src/js/components/MainView.js b/web/src/js/components/MainView.jsx
index 6172ce77..dbea76e5 100644
--- a/web/src/js/components/MainView.js
+++ b/web/src/js/components/MainView.jsx
@@ -1,16 +1,22 @@
-import React, { Component } from "react"
-
-import { FlowActions } from "../actions.js"
-import { Query } from "../actions.js"
-import { Key } from "../utils.js"
-import { Splitter } from "./common.js"
-import FlowTable from "./flowtable.js"
-import FlowView from "./flowview/index.js"
+import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
-import { selectFlow, setFilter, setHighlight } from "../ducks/flows"
+import { bindActionCreators } from 'redux'
+
+import { FlowActions } from '../actions.js'
+import { Query } from '../actions.js'
+import { Key } from '../utils.js'
+import { Splitter } from './common.js'
+import FlowTable from './FlowTable'
+import FlowView from './flowview/index.js'
+import { selectFlow, setFilter, setHighlight } from '../ducks/flows'
class MainView extends Component {
+ static propTypes = {
+ highlight: PropTypes.string,
+ sort: PropTypes.object,
+ }
+
/**
* @todo move to actions
* @todo replace with mapStateToProps
@@ -33,9 +39,9 @@ class MainView extends Component {
*/
selectFlow(flow) {
if (flow) {
- this.props.updateLocation(`/flows/${flow.id}/${this.props.routeParams.detailTab || "request"}`)
+ this.props.updateLocation(`/flows/${flow.id}/${this.props.routeParams.detailTab || 'request'}`)
} else {
- this.props.updateLocation("/flows")
+ this.props.updateLocation('/flows')
}
}
@@ -143,20 +149,22 @@ class MainView extends Component {
case Key.SHIFT:
break
default:
- console.debug("keydown", e.keyCode)
+ console.debug('keydown', e.keyCode)
return
}
e.preventDefault()
}
render() {
- const { selectedFlow } = this.props
+ const { flows, selectedFlow, highlight, sort } = this.props
return (
<div className="main-view">
<FlowTable
ref="flowTable"
- selectFlow={flow => this.selectFlow(flow)}
+ flows={flows}
selected={selectedFlow}
+ highlight={highlight}
+ onSelect={flow => this.selectFlow(flow)}
/>
{selectedFlow && [
<Splitter key="splitter"/>,
@@ -178,14 +186,15 @@ export default connect(
state => ({
flows: state.flows.view,
filter: state.flows.filter,
+ sort: state.flows.sort,
highlight: state.flows.highlight,
selectedFlow: state.flows.all.byId[state.flows.selected[0]]
}),
- dispatch => ({
- selectFlow: flowId => dispatch(selectFlow(flowId)),
- setFilter: filter => dispatch(setFilter(filter)),
- setHighlight: highlight => dispatch(setHighlight(highlight))
- }),
+ dispatch => bindActionCreators({
+ selectFlow,
+ setFilter,
+ setHighlight,
+ }, dispatch),
undefined,
{ withRef: true }
)(MainView)
diff --git a/web/src/js/components/ProxyApp.js b/web/src/js/components/ProxyApp.jsx
index 71a7bf9b..81272268 100644
--- a/web/src/js/components/ProxyApp.js
+++ b/web/src/js/components/ProxyApp.jsx
@@ -4,9 +4,9 @@ import _ from "lodash"
import { connect } from 'react-redux'
import { Splitter } from "./common.js"
-import { Header, MainMenu } from "./header.js"
-import EventLog from "./eventlog.js"
-import Footer from "./footer.js"
+import Header from "./Header"
+import EventLog from "./EventLog"
+import Footer from "./Footer"
import { SettingsStore } from "../store/store.js"
import { Key } from "../utils.js"
@@ -31,6 +31,7 @@ class ProxyAppMain extends Component {
this.state = { settings: this.settingsStore.dict }
+ this.focus = this.focus.bind(this)
this.onKeyDown = this.onKeyDown.bind(this)
this.updateLocation = this.updateLocation.bind(this)
this.onSettingsChange = this.onSettingsChange.bind(this)
@@ -45,7 +46,7 @@ class ProxyAppMain extends Component {
}
const query = this.props.location.query
for (const key of Object.keys(queryUpdate || {})) {
- query[i] = queryUpdate[i] || undefined
+ query[key] = queryUpdate[key] || undefined
}
this.context.router.replace({ pathname, query })
}
@@ -133,7 +134,7 @@ class ProxyAppMain extends Component {
if (name) {
const headerComponent = this.refs.header
- headerComponent.setState({active: MainMenu}, function () {
+ headerComponent.setState({ active: Header.entries.MainMenu }, () => {
headerComponent.refs.active.refs[name].select()
})
}
diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js
deleted file mode 100644
index 6ada58ff..00000000
--- a/web/src/js/components/eventlog.js
+++ /dev/null
@@ -1,153 +0,0 @@
-import React from "react"
-import ReactDOM from "react-dom"
-import {connect} from 'react-redux'
-import shallowEqual from "shallowequal"
-import {toggleEventLogFilter, toggleEventLogVisibility} from "../ducks/eventLog"
-import AutoScroll from "./helpers/AutoScroll";
-import {calcVScroll} from "./helpers/VirtualScroll"
-import {ToggleButton} from "./common";
-
-function LogIcon({event}) {
- let icon = {web: "html5", debug: "bug"}[event.level] || "info";
- return <i className={`fa fa-fw fa-${icon}`}></i>
-}
-
-function LogEntry({event, registerHeight}) {
- return <div ref={registerHeight}>
- <LogIcon event={event}/>
- {event.message}
- </div>;
-}
-
-class EventLogContents extends React.Component {
-
- static defaultProps = {
- rowHeight: 18,
- };
-
- constructor(props) {
- super(props);
-
- this.heights = {};
- this.state = {vScroll: calcVScroll()};
-
- this.onViewportUpdate = this.onViewportUpdate.bind(this);
- }
-
- componentDidMount() {
- window.addEventListener("resize", this.onViewportUpdate);
- this.onViewportUpdate();
- }
-
- componentWillUnmount() {
- window.removeEventListener("resize", this.onViewportUpdate);
- }
-
- componentDidUpdate() {
- this.onViewportUpdate();
- }
-
- onViewportUpdate() {
- const viewport = ReactDOM.findDOMNode(this);
-
- const vScroll = calcVScroll({
- itemCount: this.props.events.length,
- rowHeight: this.props.rowHeight,
- viewportTop: viewport.scrollTop,
- viewportHeight: viewport.offsetHeight,
- itemHeights: this.props.events.map(entry => this.heights[entry.id]),
- });
-
- if (!shallowEqual(this.state.vScroll, vScroll)) {
- this.setState({vScroll});
- }
- }
-
- setHeight(id, node) {
- if (node && !this.heights[id]) {
- const height = node.offsetHeight;
- if (this.heights[id] !== height) {
- this.heights[id] = height;
- this.onViewportUpdate();
- }
- }
- }
-
- render() {
- const vScroll = this.state.vScroll;
- const events = this.props.events
- .slice(vScroll.start, vScroll.end)
- .map(event =>
- <LogEntry
- event={event}
- key={event.id}
- registerHeight={(node) => this.setHeight(event.id, node)}
- />
- );
-
- return (
- <pre onScroll={this.onViewportUpdate}>
- <div style={{ height: vScroll.paddingTop }}></div>
- {events}
- <div style={{ height: vScroll.paddingBottom }}></div>
- </pre>
- );
- }
-}
-
-EventLogContents = AutoScroll(EventLogContents);
-
-
-const EventLogContentsContainer = connect(
- state => ({
- events: state.eventLog.filteredEvents
- })
-)(EventLogContents);
-
-
-export const ToggleEventLog = connect(
- state => ({
- checked: state.eventLog.visible
- }),
- dispatch => ({
- onToggle: () => dispatch(toggleEventLogVisibility())
- })
-)(ToggleButton);
-
-
-const ToggleFilter = connect(
- (state, ownProps) => ({
- checked: state.eventLog.filter[ownProps.text]
- }),
- (dispatch, ownProps) => ({
- onToggle: () => dispatch(toggleEventLogFilter(ownProps.text))
- })
-)(ToggleButton);
-
-
-const EventLog = ({close}) =>
- <div className="eventlog">
- <div>
- Eventlog
- <div className="pull-right">
- <ToggleFilter text="debug"/>
- <ToggleFilter text="info"/>
- <ToggleFilter text="web"/>
- <i onClick={close} className="fa fa-close"></i>
- </div>
- </div>
- <EventLogContentsContainer/>
- </div>;
-
-EventLog.propTypes = {
- close: React.PropTypes.func.isRequired
-};
-
-const EventLogContainer = connect(
- undefined,
- dispatch => ({
- close: () => dispatch(toggleEventLogVisibility())
- })
-)(EventLog);
-
-export default EventLogContainer;
diff --git a/web/src/js/components/flowtable-columns.js b/web/src/js/components/flowtable-columns.js
deleted file mode 100644
index 799b3f9f..00000000
--- a/web/src/js/components/flowtable-columns.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import React from "react"
-import {RequestUtils, ResponseUtils} from "../flow/utils.js"
-import {formatSize, formatTimeDelta} from "../utils.js"
-
-
-export function TLSColumn({flow}) {
- let ssl = (flow.request.scheme === "https")
- let classes
- if (ssl) {
- classes = "col-tls col-tls-https"
- } else {
- classes = "col-tls col-tls-http"
- }
- return <td className={classes}></td>
-}
-TLSColumn.Title = ({className = "", ...props}) => <th {...props} className={"col-tls " + className }></th>
-TLSColumn.sortKeyFun = flow => flow.request.scheme
-
-
-export function IconColumn({flow}) {
- let icon
- if (flow.response) {
- var contentType = ResponseUtils.getContentType(flow.response)
-
- //TODO: We should assign a type to the flow somewhere else.
- if (flow.response.status_code === 304) {
- icon = "resource-icon-not-modified"
- } else if (300 <= flow.response.status_code && flow.response.status_code < 400) {
- icon = "resource-icon-redirect"
- } else if (contentType && contentType.indexOf("image") >= 0) {
- icon = "resource-icon-image"
- } else if (contentType && contentType.indexOf("javascript") >= 0) {
- icon = "resource-icon-js"
- } else if (contentType && contentType.indexOf("css") >= 0) {
- icon = "resource-icon-css"
- } else if (contentType && contentType.indexOf("html") >= 0) {
- icon = "resource-icon-document"
- }
- }
- if (!icon) {
- icon = "resource-icon-plain"
- }
-
- icon += " resource-icon"
- return <td className="col-icon">
- <div className={icon}></div>
- </td>
-}
-IconColumn.Title = ({className = "", ...props}) => <th {...props} className={"col-icon " + className }></th>
-
-
-export function PathColumn({flow}) {
- return <td className="col-path">
- {flow.request.is_replay ? <i className="fa fa-fw fa-repeat pull-right"></i> : null}
- {flow.intercepted ? <i className="fa fa-fw fa-pause pull-right"></i> : null}
- { RequestUtils.pretty_url(flow.request) }
- </td>
-}
-PathColumn.Title = ({className = "", ...props}) =>
- <th {...props} className={"col-path " + className }>Path</th>
-PathColumn.sortKeyFun = flow => RequestUtils.pretty_url(flow.request)
-
-
-export function MethodColumn({flow}) {
- return <td className="col-method">{flow.request.method}</td>
-}
-MethodColumn.Title = ({className = "", ...props}) =>
- <th {...props} className={"col-method " + className }>Method</th>
-MethodColumn.sortKeyFun = flow => flow.request.method
-
-
-export function StatusColumn({flow}) {
- let status
- if (flow.response) {
- status = flow.response.status_code
- } else {
- status = null
- }
- return <td className="col-status">{status}</td>
-
-}
-StatusColumn.Title = ({className = "", ...props}) =>
- <th {...props} className={"col-status " + className }>Status</th>
-StatusColumn.sortKeyFun = flow => flow.response ? flow.response.status_code : undefined
-
-
-export function SizeColumn({flow}) {
- let total = flow.request.contentLength
- if (flow.response) {
- total += flow.response.contentLength || 0
- }
- let size = formatSize(total)
- return <td className="col-size">{size}</td>
-
-}
-SizeColumn.Title = ({className = "", ...props}) =>
- <th {...props} className={"col-size " + className }>Size</th>
-SizeColumn.sortKeyFun = flow => {
- let total = flow.request.contentLength
- if (flow.response) {
- total += flow.response.contentLength || 0
- }
- return total
-}
-
-
-export function TimeColumn({flow}) {
- let time
- if (flow.response) {
- time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start))
- } else {
- time = "..."
- }
- return <td className="col-time">{time}</td>
-}
-TimeColumn.Title = ({className = "", ...props}) =>
- <th {...props} className={"col-time " + className }>Time</th>
-TimeColumn.sortKeyFun = flow => flow.response.timestamp_end - flow.request.timestamp_start
-
-
-var all_columns = [
- TLSColumn,
- IconColumn,
- PathColumn,
- MethodColumn,
- StatusColumn,
- SizeColumn,
- TimeColumn
-]
-
-export default all_columns
diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js
deleted file mode 100644
index 5a0793ba..00000000
--- a/web/src/js/components/flowtable.js
+++ /dev/null
@@ -1,201 +0,0 @@
-import React from "react";
-import ReactDOM from "react-dom";
-import {connect} from 'react-redux'
-import classNames from "classnames";
-import _ from "lodash";
-import shallowEqual from "shallowequal";
-import AutoScroll from "./helpers/AutoScroll";
-import {calcVScroll} from "./helpers/VirtualScroll";
-import flowtable_columns from "./flowtable-columns.js";
-import Filt from "../filt/filt";
-import {setSort} from "../ducks/flows";
-
-
-FlowRow.propTypes = {
- selectFlow: React.PropTypes.func.isRequired,
- columns: React.PropTypes.array.isRequired,
- flow: React.PropTypes.object.isRequired,
- highlight: React.PropTypes.string,
- selected: React.PropTypes.bool,
-};
-
-function FlowRow({flow, selected, highlight, columns, selectFlow}) {
-
- const className = classNames({
- "selected": selected,
- "highlighted": highlight && parseFilter(highlight)(flow),
- "intercepted": flow.intercepted,
- "has-request": flow.request,
- "has-response": flow.response,
- });
-
- return (
- <tr className={className} onClick={() => selectFlow(flow)}>
- {columns.map(Column => (
- <Column key={Column.name} flow={flow}/>
- ))}
- </tr>
- );
-}
-
-const FlowRowContainer = connect(
- (state, ownProps) => ({
- flow: state.flows.all.byId[ownProps.flowId],
- highlight: state.flows.highlight,
- selected: state.flows.selected.indexOf(ownProps.flowId) >= 0
- })
-)(FlowRow)
-
-function FlowTableHead({setSort, columns, sort}) {
- const sortColumn = sort.sortColumn;
- const sortType = sort.sortDesc ? "sort-desc" : "sort-asc";
-
- return (
- <tr>
- {columns.map(Column => (
- <Column.Title
- key={Column.name}
- onClick={() => setSort({sortColumn: Column.name, sortDesc: Column.name != sort.sortColumn ? false : !sort.sortDesc})}
- className={sortColumn === Column.name ? sortType : undefined}
- />
- ))}
- </tr>
- );
-}
-
-FlowTableHead.propTypes = {
- setSort: React.PropTypes.func.isRequired,
- sort: React.PropTypes.object.isRequired,
- columns: React.PropTypes.array.isRequired
-};
-
-const FlowTableHeadContainer = connect(
- state => ({
- sort: state.flows.sort
- }),
- dispatch => ({
- setSort: (sort) => dispatch(setSort(sort)),
- })
-)(FlowTableHead)
-
-class FlowTable extends React.Component {
-
- static propTypes = {
- rowHeight: React.PropTypes.number,
- };
-
- static defaultProps = {
- rowHeight: 32,
- };
-
- constructor(props, context) {
- super(props, context);
-
- this.state = {vScroll: calcVScroll()};
-
- this.onViewportUpdate = this.onViewportUpdate.bind(this);
- }
-
- componentWillMount() {
- window.addEventListener("resize", this.onViewportUpdate);
- }
-
- componentWillUnmount() {
- window.removeEventListener("resize", this.onViewportUpdate);
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.selected && nextProps.selected !== this.props.selected) {
- window.setTimeout(() => this.scrollIntoView(nextProps.selected), 1)
- }
- }
-
- componentDidUpdate() {
- this.onViewportUpdate();
- }
-
- onViewportUpdate() {
- const viewport = ReactDOM.findDOMNode(this);
- const viewportTop = viewport.scrollTop;
-
- const vScroll = calcVScroll({
- viewportTop,
- viewportHeight: viewport.offsetHeight,
- itemCount: this.props.flows.length,
- rowHeight: this.props.rowHeight,
- });
-
- if (!shallowEqual(this.state.vScroll, vScroll) ||
- this.state.viewportTop !== viewportTop) {
- this.setState({vScroll, viewportTop});
- }
- }
-
- scrollIntoView(flow) {
- const viewport = ReactDOM.findDOMNode(this);
- const index = this.props.flows.indexOf(flow);
- const rowHeight = this.props.rowHeight;
- const head = ReactDOM.findDOMNode(this.refs.head);
-
- const headHeight = head ? head.offsetHeight : 0;
-
- const rowTop = (index * rowHeight) + headHeight;
- const rowBottom = rowTop + rowHeight;
-
- const viewportTop = viewport.scrollTop;
- const viewportHeight = viewport.offsetHeight;
-
- // Account for pinned thead
- if (rowTop - headHeight < viewportTop) {
- viewport.scrollTop = rowTop - headHeight;
- } else if (rowBottom > viewportTop + viewportHeight) {
- viewport.scrollTop = rowBottom - viewportHeight;
- }
- }
-
- render() {
- const vScroll = this.state.vScroll;
- const flows = this.props.flows.slice(vScroll.start, vScroll.end);
-
- const transform = `translate(0,${this.state.viewportTop}px)`;
-
- return (
- <div className="flow-table" onScroll={this.onViewportUpdate}>
- <table>
- <thead ref="head" style={{ transform }}>
- <FlowTableHeadContainer
- columns={flowtable_columns}
- setSortKeyFun={this.props.setSortKeyFun}
- setSort={this.props.setSort}
- />
- </thead>
- <tbody>
- <tr style={{ height: vScroll.paddingTop }}></tr>
- {flows.map(flow => (
- <FlowRowContainer
- key={flow.id}
- flowId={flow.id}
- columns={flowtable_columns}
- selectFlow={this.props.selectFlow}
- />
- ))}
- <tr style={{ height: vScroll.paddingBottom }}></tr>
- </tbody>
- </table>
- </div>
- );
- }
-}
-
-FlowTable = AutoScroll(FlowTable)
-
-
-const parseFilter = _.memoize(Filt.parse)
-
-const FlowTableContainer = connect(
- state => ({
- flows: state.flows.view
- })
-)(FlowTable)
-
-export default FlowTableContainer;
diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js
deleted file mode 100644
index 4152e95c..00000000
--- a/web/src/js/components/header.js
+++ /dev/null
@@ -1,453 +0,0 @@
-import React from "react";
-import ReactDOM from 'react-dom';
-import $ from "jquery";
-import {connect} from 'react-redux'
-
-import Filt from "../filt/filt.js";
-import {Key} from "../utils.js";
-import {ToggleInputButton, ToggleButton} from "./common.js";
-import {SettingsActions, FlowActions} from "../actions.js";
-import {Query} from "../actions.js";
-import {SettingsState} from "./common.js";
-import {ToggleEventLog} from "./eventlog"
-
-var FilterDocs = React.createClass({
- statics: {
- xhr: false,
- doc: false
- },
- componentWillMount: function () {
- if (!FilterDocs.doc) {
- FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
- FilterDocs.doc = doc;
- FilterDocs.xhr = false;
- });
- }
- if (FilterDocs.xhr) {
- FilterDocs.xhr.done(function () {
- this.forceUpdate();
- }.bind(this));
- }
- },
- render: function () {
- if (!FilterDocs.doc) {
- return <i className="fa fa-spinner fa-spin"></i>;
- } else {
- var commands = FilterDocs.doc.commands.map(function (c) {
- return <tr key={c[1]}>
- <td>{c[0].replace(" ", '\u00a0')}</td>
- <td>{c[1]}</td>
- </tr>;
- });
- commands.push(<tr key="docs-link">
- <td colSpan="2">
- <a href="http://docs.mitmproxy.org/en/stable/features/filters.html"
- target="_blank">
- <i className="fa fa-external-link"></i>
- &nbsp; mitmproxy docs</a>
- </td>
- </tr>);
- return <table className="table table-condensed">
- <tbody>{commands}</tbody>
- </table>;
- }
- }
-});
-var FilterInput = React.createClass({
- contextTypes: {
- returnFocus: React.PropTypes.func
- },
- getInitialState: function () {
- // Consider both focus and mouseover for showing/hiding the tooltip,
- // because onBlur of the input is triggered before the click on the tooltip
- // finalized, hiding the tooltip just as the user clicks on it.
- return {
- value: this.props.value,
- focus: false,
- mousefocus: false
- };
- },
- componentWillReceiveProps: function (nextProps) {
- this.setState({value: nextProps.value});
- },
- onChange: function (e) {
- var nextValue = e.target.value;
- this.setState({
- value: nextValue
- });
- // Only propagate valid filters upwards.
- if (this.isValid(nextValue)) {
- this.props.onChange(nextValue);
- }
- },
- isValid: function (filt) {
- try {
- var str = filt || this.state.value;
- if(str){
- Filt.parse(filt || this.state.value);
- }
- return true;
- } catch (e) {
- return false;
- }
- },
- getDesc: function () {
- if(this.state.value) {
- try {
- return Filt.parse(this.state.value).desc;
- } catch (e) {
- return "" + e;
- }
- }
- return <FilterDocs/>;
- },
- onFocus: function () {
- this.setState({focus: true});
- },
- onBlur: function () {
- this.setState({focus: false});
- },
- onMouseEnter: function () {
- this.setState({mousefocus: true});
- },
- onMouseLeave: function () {
- this.setState({mousefocus: false});
- },
- onKeyDown: function (e) {
- if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) {
- this.blur();
- // If closed using ESC/ENTER, hide the tooltip.
- this.setState({mousefocus: false});
- }
- e.stopPropagation();
- },
- blur: function () {
- ReactDOM.findDOMNode(this.refs.input).blur();
- this.context.returnFocus();
- },
- select: function () {
- ReactDOM.findDOMNode(this.refs.input).select();
- },
- render: function () {
- var isValid = this.isValid();
- var icon = "fa fa-fw fa-" + this.props.type;
- var groupClassName = "filter-input input-group" + (isValid ? "" : " has-error");
-
- var popover;
- if (this.state.focus || this.state.mousefocus) {
- popover = (
- <div className="popover bottom" onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
- <div className="arrow"></div>
- <div className="popover-content">
- {this.getDesc()}
- </div>
- </div>
- );
- }
-
- return (
- <div className={groupClassName}>
- <span className="input-group-addon">
- <i className={icon} style={{color: this.props.color}}></i>
- </span>
- <input type="text" placeholder={this.props.placeholder} className="form-control"
- ref="input"
- onChange={this.onChange}
- onFocus={this.onFocus}
- onBlur={this.onBlur}
- onKeyDown={this.onKeyDown}
- value={this.state.value}/>
- {popover}
- </div>
- );
- }
-});
-
-export var MainMenu = React.createClass({
- propTypes: {
- settings: React.PropTypes.object.isRequired,
- },
- statics: {
- title: "Start",
- route: "flows"
- },
- onSearchChange: function (val) {
- var d = {};
- d[Query.SEARCH] = val;
- this.props.updateLocation(undefined, d);
- },
- onHighlightChange: function (val) {
- var d = {};
- d[Query.HIGHLIGHT] = val;
- this.props.updateLocation(undefined, d);
- },
- onInterceptChange: function (val) {
- SettingsActions.update({intercept: val});
- },
- render: function () {
- var search = this.props.query[Query.SEARCH] || "";
- var highlight = this.props.query[Query.HIGHLIGHT] || "";
- var intercept = this.props.settings.intercept || "";
-
- return (
- <div>
- <div className="menu-row">
- <FilterInput
- ref="search"
- placeholder="Search"
- type="search"
- color="black"
- value={search}
- onChange={this.onSearchChange} />
- <FilterInput
- ref="highlight"
- placeholder="Highlight"
- type="tag"
- color="hsl(48, 100%, 50%)"
- value={highlight}
- onChange={this.onHighlightChange}/>
- <FilterInput
- ref="intercept"
- placeholder="Intercept"
- type="pause"
- color="hsl(208, 56%, 53%)"
- value={intercept}
- onChange={this.onInterceptChange}/>
- </div>
- <div className="clearfix"></div>
- </div>
- );
- }
-});
-
-
-var ViewMenu = React.createClass({
- statics: {
- title: "View",
- route: "flows"
- },
- render: function () {
- return (
- <div>
- <div className="menu-row">
- <ToggleEventLog text="Show Event Log"/>
- </div>
- <div className="clearfix"></div>
- </div>
- );
- }
-});
-
-export const OptionMenu = (props) => {
- const {mode, intercept, showhost, no_upstream_cert, rawtcp, http2, anticache, anticomp, stickycookie, stickyauth, stream} = props.settings;
- return (
- <div>
- <div className="menu-row">
- <ToggleButton text="showhost"
- checked={showhost}
- onToggle={() => SettingsActions.update({showhost: !showhost})}
- />
- <ToggleButton text="no_upstream_cert"
- checked={no_upstream_cert}
- onToggle={() => SettingsActions.update({no_upstream_cert: !no_upstream_cert})}
- />
- <ToggleButton text="rawtcp"
- checked={rawtcp}
- onToggle={() => SettingsActions.update({rawtcp: !rawtcp})}
- />
- <ToggleButton text="http2"
- checked={http2}
- onToggle={() => SettingsActions.update({http2: !http2})}
- />
- <ToggleButton text="anticache"
- checked={anticache}
- onToggle={() => SettingsActions.update({anticache: !anticache})}
- />
- <ToggleButton text="anticomp"
- checked={anticomp}
- onToggle={() => SettingsActions.update({anticomp: !anticomp})}
- />
- <ToggleInputButton name="stickyauth" placeholder="Sticky auth filter"
- checked={Boolean(stickyauth)}
- txt={stickyauth || ""}
- onToggleChanged={txt => SettingsActions.update({stickyauth: (!stickyauth ? txt : null)})}
- />
- <ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter"
- checked={Boolean(stickycookie)}
- txt={stickycookie || ""}
- onToggleChanged={txt => SettingsActions.update({stickycookie: (!stickycookie ? txt : null)})}
- />
- <ToggleInputButton name="stream" placeholder="stream..."
- checked={Boolean(stream)}
- txt={stream || ""}
- inputType = "number"
- onToggleChanged={txt => SettingsActions.update({stream: (!stream ? txt : null)})}
- />
- </div>
- <div className="clearfix"/>
- </div>
- );
-};
-OptionMenu.title = "Options";
-
-OptionMenu.propTypes = {
- settings: React.PropTypes.object.isRequired
-};
-
-var ReportsMenu = React.createClass({
- statics: {
- title: "Visualization",
- route: "reports"
- },
- render: function () {
- return <div>Reports Menu</div>;
- }
-});
-
-var FileMenu = React.createClass({
- getInitialState: function () {
- return {
- showFileMenu: false
- };
- },
- handleFileClick: function (e) {
- e.preventDefault();
- if (!this.state.showFileMenu) {
- var close = function () {
- this.setState({showFileMenu: false});
- document.removeEventListener("click", close);
- }.bind(this);
- document.addEventListener("click", close);
-
- this.setState({
- showFileMenu: true
- });
- }
- },
- handleNewClick: function (e) {
- e.preventDefault();
- if (confirm("Delete all flows?")) {
- FlowActions.clear();
- }
- },
- handleOpenClick: function (e) {
- this.fileInput.click();
- e.preventDefault();
- },
- handleOpenFile: function (e) {
- if (e.target.files.length > 0) {
- FlowActions.upload(e.target.files[0]);
- this.fileInput.value = "";
- }
- e.preventDefault();
- },
- handleSaveClick: function (e) {
- e.preventDefault();
- FlowActions.download();
- },
- handleShutdownClick: function (e) {
- e.preventDefault();
- console.error("unimplemented: handleShutdownClick");
- },
- render: function () {
- var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");
-
- return (
- <div className={fileMenuClass}>
- <a href="#" className="special" onClick={this.handleFileClick}> mitmproxy </a>
- <ul className="dropdown-menu" role="menu">
- <li>
- <a href="#" onClick={this.handleNewClick}>
- <i className="fa fa-fw fa-file"></i>
- New
- </a>
- </li>
- <li>
- <a href="#" onClick={this.handleOpenClick}>
- <i className="fa fa-fw fa-folder-open"></i>
- Open...
- </a>
- <input ref={(ref) => this.fileInput = ref} className="hidden" type="file" onChange={this.handleOpenFile}/>
-
- </li>
- <li>
- <a href="#" onClick={this.handleSaveClick}>
- <i className="fa fa-fw fa-floppy-o"></i>
- Save...
- </a>
- </li>
- <li role="presentation" className="divider"></li>
- <li>
- <a href="http://mitm.it/" target="_blank">
- <i className="fa fa-fw fa-external-link"></i>
- Install Certificates...
- </a>
- </li>
- {/*
- <li role="presentation" className="divider"></li>
- <li>
- <a href="#" onClick={this.handleShutdownClick}>
- <i className="fa fa-fw fa-plug"></i>
- Shutdown
- </a>
- </li>
- */}
- </ul>
- </div>
- );
- }
-});
-
-
-var header_entries = [MainMenu, ViewMenu, OptionMenu /*, ReportsMenu */];
-
-
-export var Header = React.createClass({
- propTypes: {
- settings: React.PropTypes.object.isRequired,
- },
- getInitialState: function () {
- return {
- active: header_entries[0]
- };
- },
- handleClick: function (active, e) {
- e.preventDefault();
- this.props.updateLocation(active.route);
- this.setState({active: active});
- },
- render: function () {
- var header = header_entries.map(function (entry, i) {
- var className;
- if (entry === this.state.active) {
- className = "active";
- } else {
- className = "";
- }
- return (
- <a key={i}
- href="#"
- className={className}
- onClick={this.handleClick.bind(this, entry)}>
- {entry.title}
- </a>
- );
- }.bind(this));
-
- return (
- <header>
- <nav className="nav-tabs nav-tabs-lg">
- <FileMenu/>
- {header}
- </nav>
- <div className="menu">
- <this.state.active
- settings={this.props.settings}
- updateLocation={this.props.updateLocation}
- query={this.props.query}
- />
- </div>
- </header>
- );
- }
-});
diff --git a/web/src/js/components/prompt.js b/web/src/js/components/prompt.js
index e324f7d4..5ab26b82 100644
--- a/web/src/js/components/prompt.js
+++ b/web/src/js/components/prompt.js
@@ -42,7 +42,7 @@ var Prompt = React.createClass({
var opts = [];
var keyTaken = function (k) {
- return _.includes(_.pluck(opts, "key"), k);
+ return _.includes(_.map(opts, "key"), k);
};
for (var i = 0; i < this.props.options.length; i++) {
@@ -99,4 +99,4 @@ var Prompt = React.createClass({
}
});
-export default Prompt; \ No newline at end of file
+export default Prompt;
diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js
index 6adde71c..f7a5538a 100644
--- a/web/src/js/ducks/flows.js
+++ b/web/src/js/ducks/flows.js
@@ -2,7 +2,7 @@ import makeList from "./utils/list"
import Filt from "../filt/filt"
import {updateViewFilter, updateViewList, updateViewSort} from "./utils/view"
import {reverseString} from "../utils.js";
-import * as flow_table_columns from "../components/flowtable-columns.js";
+import * as columns from "../components/FlowTable/FlowColumns";
export const UPDATE_FLOWS = "UPDATE_FLOWS"
export const SET_FILTER = "SET_FLOW_FILTER"
@@ -32,7 +32,7 @@ function makeFilterFn(filter) {
function makeSortFn(sort){
- let column = flow_table_columns[sort.sortColumn];
+ let column = columns[sort.sortColumn];
if (!column) return;
let sortKeyFun = column.sortKeyFun;
@@ -108,4 +108,4 @@ export function selectFlow(flowId) {
}
-export {updateList as updateFlows, fetchList as fetchFlows} \ No newline at end of file
+export {updateList as updateFlows, fetchList as fetchFlows}