From 33fa49277a821b9d38e8c9bf0bcf2adcfa2f6f04 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Mon, 15 Feb 2016 14:58:46 +0100 Subject: move mitmproxy --- web/src/js/components/common.js | 219 -------------- web/src/js/components/editor.js | 240 ---------------- web/src/js/components/eventlog.js | 150 ---------- web/src/js/components/flowtable-columns.js | 201 ------------- web/src/js/components/flowtable.js | 187 ------------ web/src/js/components/flowview/contentview.js | 237 --------------- web/src/js/components/flowview/details.js | 181 ------------ web/src/js/components/flowview/index.js | 127 -------- web/src/js/components/flowview/messages.js | 326 --------------------- web/src/js/components/flowview/nav.js | 61 ---- web/src/js/components/footer.js | 19 -- web/src/js/components/header.js | 399 -------------------------- web/src/js/components/mainview.js | 244 ---------------- web/src/js/components/prompt.js | 100 ------- web/src/js/components/proxyapp.js | 129 --------- web/src/js/components/virtualscroll.js | 85 ------ 16 files changed, 2905 deletions(-) delete mode 100644 web/src/js/components/common.js delete mode 100644 web/src/js/components/editor.js delete mode 100644 web/src/js/components/eventlog.js delete mode 100644 web/src/js/components/flowtable-columns.js delete mode 100644 web/src/js/components/flowtable.js delete mode 100644 web/src/js/components/flowview/contentview.js delete mode 100644 web/src/js/components/flowview/details.js delete mode 100644 web/src/js/components/flowview/index.js delete mode 100644 web/src/js/components/flowview/messages.js delete mode 100644 web/src/js/components/flowview/nav.js delete mode 100644 web/src/js/components/footer.js delete mode 100644 web/src/js/components/header.js delete mode 100644 web/src/js/components/mainview.js delete mode 100644 web/src/js/components/prompt.js delete mode 100644 web/src/js/components/proxyapp.js delete mode 100644 web/src/js/components/virtualscroll.js (limited to 'web/src/js/components') diff --git a/web/src/js/components/common.js b/web/src/js/components/common.js deleted file mode 100644 index 965ae9a7..00000000 --- a/web/src/js/components/common.js +++ /dev/null @@ -1,219 +0,0 @@ -var React = require("react"); -var ReactRouter = require("react-router"); -var _ = require("lodash"); - -// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example) -var AutoScrollMixin = { - componentWillUpdate: function () { - var node = this.getDOMNode(); - this._shouldScrollBottom = ( - node.scrollTop !== 0 && - node.scrollTop + node.clientHeight === node.scrollHeight - ); - }, - componentDidUpdate: function () { - if (this._shouldScrollBottom) { - var node = this.getDOMNode(); - node.scrollTop = node.scrollHeight; - } - }, -}; - - -var StickyHeadMixin = { - adjustHead: function () { - // Abusing CSS transforms to set the element - // referenced as head into some kind of position:sticky. - var head = this.refs.head.getDOMNode(); - head.style.transform = "translate(0," + this.getDOMNode().scrollTop + "px)"; - } -}; - -var SettingsState = { - contextTypes: { - settingsStore: React.PropTypes.object.isRequired - }, - getInitialState: function () { - return { - settings: this.context.settingsStore.dict - }; - }, - componentDidMount: function () { - this.context.settingsStore.addListener("recalculate", this.onSettingsChange); - }, - componentWillUnmount: function () { - this.context.settingsStore.removeListener("recalculate", this.onSettingsChange); - }, - onSettingsChange: function () { - this.setState({ - settings: this.context.settingsStore.dict - }); - }, -}; - - -var ChildFocus = { - contextTypes: { - returnFocus: React.PropTypes.func - }, - returnFocus: function(){ - React.findDOMNode(this).blur(); - window.getSelection().removeAllRanges(); - this.context.returnFocus(); - } -}; - - -var Navigation = _.extend({}, ReactRouter.Navigation, { - setQuery: function (dict) { - var q = this.context.router.getCurrentQuery(); - for (var i in dict) { - if (dict.hasOwnProperty(i)) { - q[i] = dict[i] || undefined; //falsey values shall be removed. - } - } - this.replaceWith(this.context.router.getCurrentPath(), this.context.router.getCurrentParams(), q); - }, - replaceWith: function (routeNameOrPath, params, query) { - if (routeNameOrPath === undefined) { - routeNameOrPath = this.context.router.getCurrentPath(); - } - if (params === undefined) { - params = this.context.router.getCurrentParams(); - } - if (query === undefined) { - query = this.context.router.getCurrentQuery(); - } - - this.context.router.replaceWith(routeNameOrPath, params, query); - } -}); - -// react-router is fairly good at changing its API regularly. -// We keep the old method for now - if it should turn out that their changes are permanent, -// we may remove this mixin and access react-router directly again. -var RouterState = _.extend({}, ReactRouter.State, { - getQuery: function () { - // For whatever reason, react-router always returns the same object, which makes comparing - // the current props with nextProps impossible. As a workaround, we just clone the query object. - return _.clone(this.context.router.getCurrentQuery()); - }, - getParams: function () { - return _.clone(this.context.router.getCurrentParams()); - } -}); - -var Splitter = React.createClass({ - getDefaultProps: function () { - return { - axis: "x" - }; - }, - getInitialState: function () { - return { - applied: false, - startX: false, - startY: false - }; - }, - onMouseDown: function (e) { - this.setState({ - startX: e.pageX, - startY: e.pageY - }); - window.addEventListener("mousemove", this.onMouseMove); - window.addEventListener("mouseup", this.onMouseUp); - // Occasionally, only a dragEnd event is triggered, but no mouseUp. - window.addEventListener("dragend", this.onDragEnd); - }, - onDragEnd: function () { - this.getDOMNode().style.transform = ""; - window.removeEventListener("dragend", this.onDragEnd); - window.removeEventListener("mouseup", this.onMouseUp); - window.removeEventListener("mousemove", this.onMouseMove); - }, - onMouseUp: function (e) { - this.onDragEnd(); - - var node = this.getDOMNode(); - var prev = node.previousElementSibling; - var next = node.nextElementSibling; - - var dX = e.pageX - this.state.startX; - var dY = e.pageY - this.state.startY; - var flexBasis; - if (this.props.axis === "x") { - flexBasis = prev.offsetWidth + dX; - } else { - flexBasis = prev.offsetHeight + dY; - } - - prev.style.flex = "0 0 " + Math.max(0, flexBasis) + "px"; - next.style.flex = "1 1 auto"; - - this.setState({ - applied: true - }); - this.onResize(); - }, - onMouseMove: function (e) { - var dX = 0, dY = 0; - if (this.props.axis === "x") { - dX = e.pageX - this.state.startX; - } else { - dY = e.pageY - this.state.startY; - } - this.getDOMNode().style.transform = "translate(" + dX + "px," + dY + "px)"; - }, - onResize: function () { - // Trigger a global resize event. This notifies components that employ virtual scrolling - // that their viewport may have changed. - window.setTimeout(function () { - window.dispatchEvent(new CustomEvent("resize")); - }, 1); - }, - reset: function (willUnmount) { - if (!this.state.applied) { - return; - } - var node = this.getDOMNode(); - var prev = node.previousElementSibling; - var next = node.nextElementSibling; - - prev.style.flex = ""; - next.style.flex = ""; - - if (!willUnmount) { - this.setState({ - applied: false - }); - } - this.onResize(); - }, - componentWillUnmount: function () { - this.reset(true); - }, - render: function () { - var className = "splitter"; - if (this.props.axis === "x") { - className += " splitter-x"; - } else { - className += " splitter-y"; - } - return ( -
-
-
- ); - } -}); - -module.exports = { - ChildFocus: ChildFocus, - RouterState: RouterState, - Navigation: Navigation, - StickyHeadMixin: StickyHeadMixin, - AutoScrollMixin: AutoScrollMixin, - Splitter: Splitter, - SettingsState: SettingsState -}; \ No newline at end of file diff --git a/web/src/js/components/editor.js b/web/src/js/components/editor.js deleted file mode 100644 index f2d44566..00000000 --- a/web/src/js/components/editor.js +++ /dev/null @@ -1,240 +0,0 @@ -var React = require("react"); -var common = require("./common.js"); -var utils = require("../utils.js"); - -var contentToHtml = function (content) { - return _.escape(content); -}; -var nodeToContent = function (node) { - return node.textContent; -}; - -/* - Basic Editor Functionality - */ -var EditorBase = React.createClass({ - propTypes: { - content: React.PropTypes.string.isRequired, - onDone: React.PropTypes.func.isRequired, - contentToHtml: React.PropTypes.func, - nodeToContent: React.PropTypes.func, // content === nodeToContent( Node ) - onStop: React.PropTypes.func, - submitOnEnter: React.PropTypes.bool, - className: React.PropTypes.string, - tag: React.PropTypes.string - }, - getDefaultProps: function () { - return { - contentToHtml: contentToHtml, - nodeToContent: nodeToContent, - submitOnEnter: true, - className: "", - tag: "div" - }; - }, - getInitialState: function () { - return { - editable: false - }; - }, - render: function () { - var className = "inline-input " + this.props.className; - var html = {__html: this.props.contentToHtml(this.props.content)}; - var Tag = this.props.tag; - return ; - }, - onPaste: function (e) { - e.preventDefault(); - var content = e.clipboardData.getData("text/plain"); - document.execCommand("insertHTML", false, content); - }, - onMouseDown: function (e) { - this._mouseDown = true; - window.addEventListener("mouseup", this.onMouseUp); - this.props.onMouseDown && this.props.onMouseDown(e); - }, - onMouseUp: function () { - if (this._mouseDown) { - this._mouseDown = false; - window.removeEventListener("mouseup", this.onMouseUp) - } - }, - onClick: function (e) { - this.onMouseUp(); - this.onFocus(e); - }, - onFocus: function (e) { - console.log("onFocus", this._mouseDown, this._ignore_events, this.state.editable); - if (this._mouseDown || this._ignore_events || this.state.editable) { - return; - } - - //contenteditable in FireFox is more or less broken. - // - we need to blur() and then focus(), otherwise the caret is not shown. - // - blur() + focus() == we need to save the caret position before - // Firefox sometimes just doesn't set a caret position => use caretPositionFromPoint - var sel = window.getSelection(); - var range; - if (sel.rangeCount > 0) { - range = sel.getRangeAt(0); - } else if (document.caretPositionFromPoint && e.clientX && e.clientY) { - var pos = document.caretPositionFromPoint(e.clientX, e.clientY); - range = document.createRange(); - range.setStart(pos.offsetNode, pos.offset); - } else if (document.caretRangeFromPoint && e.clientX && e.clientY) { - range = document.caretRangeFromPoint(e.clientX, e.clientY); - } else { - range = document.createRange(); - range.selectNodeContents(React.findDOMNode(this)); - } - - this._ignore_events = true; - this.setState({editable: true}, function () { - var node = React.findDOMNode(this); - node.blur(); - node.focus(); - this._ignore_events = false; - //sel.removeAllRanges(); - //sel.addRange(range); - - - }); - }, - stop: function () { - // a stop would cause a blur as a side-effect. - // but a blur event must trigger a stop as well. - // to fix this, make stop = blur and do the actual stop in the onBlur handler. - React.findDOMNode(this).blur(); - this.props.onStop && this.props.onStop(); - }, - _stop: function (e) { - if (this._ignore_events) { - return; - } - console.log("_stop", _.extend({}, e)); - window.getSelection().removeAllRanges(); //make sure that selection is cleared on blur - var node = React.findDOMNode(this); - var content = this.props.nodeToContent(node); - this.setState({editable: false}); - this.props.onDone(content); - this.props.onBlur && this.props.onBlur(e); - }, - reset: function () { - React.findDOMNode(this).innerHTML = this.props.contentToHtml(this.props.content); - }, - onKeyDown: function (e) { - e.stopPropagation(); - switch (e.keyCode) { - case utils.Key.ESC: - e.preventDefault(); - this.reset(); - this.stop(); - break; - case utils.Key.ENTER: - if (this.props.submitOnEnter && !e.shiftKey) { - e.preventDefault(); - this.stop(); - } - break; - default: - break; - } - }, - onInput: function () { - var node = React.findDOMNode(this); - var content = this.props.nodeToContent(node); - this.props.onInput && this.props.onInput(content); - } -}); - -/* - Add Validation to EditorBase - */ -var ValidateEditor = React.createClass({ - propTypes: { - content: React.PropTypes.string.isRequired, - onDone: React.PropTypes.func.isRequired, - onInput: React.PropTypes.func, - isValid: React.PropTypes.func, - className: React.PropTypes.string, - }, - getInitialState: function () { - return { - currentContent: this.props.content - }; - }, - componentWillReceiveProps: function () { - this.setState({currentContent: this.props.content}); - }, - onInput: function (content) { - this.setState({currentContent: content}); - this.props.onInput && this.props.onInput(content); - }, - render: function () { - var className = this.props.className || ""; - if (this.props.isValid) { - if (this.props.isValid(this.state.currentContent)) { - className += " has-success"; - } else { - className += " has-warning" - } - } - return ; - }, - onDone: function (content) { - if (this.props.isValid && !this.props.isValid(content)) { - this.refs.editor.reset(); - content = this.props.content; - } - this.props.onDone(content); - } -}); - -/* - Text Editor with mitmweb-specific convenience features - */ -var ValueEditor = React.createClass({ - mixins: [common.ChildFocus], - propTypes: { - content: React.PropTypes.string.isRequired, - onDone: React.PropTypes.func.isRequired, - inline: React.PropTypes.bool, - }, - render: function () { - var tag = this.props.inline ? "span" : "div"; - return ; - }, - focus: function () { - React.findDOMNode(this).focus(); - }, - onStop: function () { - this.returnFocus(); - } -}); - -module.exports = { - ValueEditor: ValueEditor -}; \ No newline at end of file diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js deleted file mode 100644 index fea7b247..00000000 --- a/web/src/js/components/eventlog.js +++ /dev/null @@ -1,150 +0,0 @@ -var React = require("react"); -var common = require("./common.js"); -var Query = require("../actions.js").Query; -var VirtualScrollMixin = require("./virtualscroll.js"); -var views = require("../store/view.js"); -var _ = require("lodash"); - -var LogMessage = React.createClass({ - render: function () { - var entry = this.props.entry; - var indicator; - switch (entry.level) { - case "web": - indicator = ; - break; - case "debug": - indicator = ; - break; - default: - indicator = ; - } - return ( -
- { indicator } {entry.message} -
- ); - }, - shouldComponentUpdate: function () { - return false; // log entries are immutable. - } -}); - -var EventLogContents = React.createClass({ - contextTypes: { - eventStore: React.PropTypes.object.isRequired - }, - mixins: [common.AutoScrollMixin, VirtualScrollMixin], - getInitialState: function () { - var filterFn = function (entry) { - return this.props.filter[entry.level]; - }; - var view = new views.StoreView(this.context.eventStore, filterFn.bind(this)); - view.addListener("add", this.onEventLogChange); - view.addListener("recalculate", this.onEventLogChange); - - return { - view: view - }; - }, - componentWillUnmount: function () { - this.state.view.close(); - }, - filter: function (entry) { - return this.props.filter[entry.level]; - }, - onEventLogChange: function () { - this.forceUpdate(); - }, - componentWillReceiveProps: function (nextProps) { - if (nextProps.filter !== this.props.filter) { - this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update. - this.state.view.recalculate(); - } - }, - getDefaultProps: function () { - return { - rowHeight: 45, - rowHeightMin: 15, - placeholderTagName: "div" - }; - }, - renderRow: function (elem) { - return ; - }, - render: function () { - var entries = this.state.view.list; - var rows = this.renderRows(entries); - - return
-            { this.getPlaceholderTop(entries.length) }
-            {rows}
-            { this.getPlaceholderBottom(entries.length) }
-        
; - } -}); - -var ToggleFilter = React.createClass({ - toggle: function (e) { - e.preventDefault(); - return this.props.toggleLevel(this.props.name); - }, - render: function () { - var className = "label "; - if (this.props.active) { - className += "label-primary"; - } else { - className += "label-default"; - } - return ( - - {this.props.name} - - ); - } -}); - -var EventLog = React.createClass({ - mixins: [common.Navigation], - getInitialState: function () { - return { - filter: { - "debug": false, - "info": true, - "web": true - } - }; - }, - close: function () { - var d = {}; - d[Query.SHOW_EVENTLOG] = undefined; - this.setQuery(d); - }, - toggleLevel: function (level) { - var filter = _.extend({}, this.state.filter); - filter[level] = !filter[level]; - this.setState({filter: filter}); - }, - render: function () { - return ( -
-
- Eventlog -
- - - - -
- -
- -
- ); - } -}); - -module.exports = EventLog; \ No newline at end of file diff --git a/web/src/js/components/flowtable-columns.js b/web/src/js/components/flowtable-columns.js deleted file mode 100644 index 74d96216..00000000 --- a/web/src/js/components/flowtable-columns.js +++ /dev/null @@ -1,201 +0,0 @@ -var React = require("react"); -var RequestUtils = require("../flow/utils.js").RequestUtils; -var ResponseUtils = require("../flow/utils.js").ResponseUtils; -var utils = require("../utils.js"); - -var TLSColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return ; - } - }), - sortKeyFun: function(flow){ - return flow.request.scheme; - } - }, - render: function () { - var flow = this.props.flow; - var ssl = (flow.request.scheme === "https"); - var classes; - if (ssl) { - classes = "col-tls col-tls-https"; - } else { - classes = "col-tls col-tls-http"; - } - return ; - } -}); - - -var IconColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return ; - } - }) - }, - render: function () { - var flow = this.props.flow; - - var 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 -
- ; - } -}); - -var PathColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Path; - } - }), - sortKeyFun: function(flow){ - return RequestUtils.pretty_url(flow.request); - } - }, - render: function () { - var flow = this.props.flow; - return - {flow.request.is_replay ? : null} - {flow.intercepted ? : null} - { RequestUtils.pretty_url(flow.request) } - ; - } -}); - - -var MethodColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Method; - } - }), - sortKeyFun: function(flow){ - return flow.request.method; - } - }, - render: function () { - var flow = this.props.flow; - return {flow.request.method}; - } -}); - - -var StatusColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Status; - } - }), - sortKeyFun: function(flow){ - return flow.response ? flow.response.status_code : undefined; - } - }, - render: function () { - var flow = this.props.flow; - var status; - if (flow.response) { - status = flow.response.status_code; - } else { - status = null; - } - return {status}; - } -}); - - -var SizeColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Size; - } - }), - sortKeyFun: function(flow){ - var total = flow.request.contentLength; - if (flow.response) { - total += flow.response.contentLength || 0; - } - return total; - } - }, - render: function () { - var flow = this.props.flow; - - var total = flow.request.contentLength; - if (flow.response) { - total += flow.response.contentLength || 0; - } - var size = utils.formatSize(total); - return {size}; - } -}); - - -var TimeColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Time; - } - }), - sortKeyFun: function(flow){ - if(flow.response) { - return flow.response.timestamp_end - flow.request.timestamp_start; - } - } - }, - render: function () { - var flow = this.props.flow; - var time; - if (flow.response) { - time = utils.formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)); - } else { - time = "..."; - } - return {time}; - } -}); - - -var all_columns = [ - TLSColumn, - IconColumn, - PathColumn, - MethodColumn, - StatusColumn, - SizeColumn, - TimeColumn -]; - -module.exports = all_columns; diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js deleted file mode 100644 index 609034f6..00000000 --- a/web/src/js/components/flowtable.js +++ /dev/null @@ -1,187 +0,0 @@ -var React = require("react"); -var common = require("./common.js"); -var utils = require("../utils.js"); -var _ = require("lodash"); - -var VirtualScrollMixin = require("./virtualscroll.js"); -var flowtable_columns = require("./flowtable-columns.js"); - -var FlowRow = React.createClass({ - render: function () { - var flow = this.props.flow; - var columns = this.props.columns.map(function (Column) { - return ; - }.bind(this)); - var className = ""; - if (this.props.selected) { - className += " selected"; - } - if (this.props.highlighted) { - className += " highlighted"; - } - if (flow.intercepted) { - className += " intercepted"; - } - if (flow.request) { - className += " has-request"; - } - if (flow.response) { - className += " has-response"; - } - - return ( - - {columns} - ); - }, - shouldComponentUpdate: function (nextProps) { - return true; - // Further optimization could be done here - // by calling forceUpdate on flow updates, selection changes and column changes. - //return ( - //(this.props.columns.length !== nextProps.columns.length) || - //(this.props.selected !== nextProps.selected) - //); - } -}); - -var FlowTableHead = React.createClass({ - getInitialState: function(){ - return { - sortColumn: undefined, - sortDesc: false - }; - }, - onClick: function(Column){ - var sortDesc = this.state.sortDesc; - var hasSort = Column.sortKeyFun; - if(Column === this.state.sortColumn){ - sortDesc = !sortDesc; - this.setState({ - sortDesc: sortDesc - }); - } else { - this.setState({ - sortColumn: hasSort && Column, - sortDesc: false - }) - } - var sortKeyFun; - if(!sortDesc){ - sortKeyFun = Column.sortKeyFun; - } else { - sortKeyFun = hasSort && function(){ - var k = Column.sortKeyFun.apply(this, arguments); - if(_.isString(k)){ - return utils.reverseString(""+k); - } else { - return -k; - } - } - } - this.props.setSortKeyFun(sortKeyFun); - }, - render: function () { - var columns = this.props.columns.map(function (Column) { - var onClick = this.onClick.bind(this, Column); - var className; - if(this.state.sortColumn === Column) { - if(this.state.sortDesc){ - className = "sort-desc"; - } else { - className = "sort-asc"; - } - } - return ; - }.bind(this)); - return - {columns} - ; - } -}); - - -var ROW_HEIGHT = 32; - -var FlowTable = React.createClass({ - mixins: [common.StickyHeadMixin, common.AutoScrollMixin, VirtualScrollMixin], - contextTypes: { - view: React.PropTypes.object.isRequired - }, - getInitialState: function () { - return { - columns: flowtable_columns - }; - }, - componentWillMount: function () { - this.context.view.addListener("add", this.onChange); - this.context.view.addListener("update", this.onChange); - this.context.view.addListener("remove", this.onChange); - this.context.view.addListener("recalculate", this.onChange); - }, - componentWillUnmount: function(){ - this.context.view.removeListener("add", this.onChange); - this.context.view.removeListener("update", this.onChange); - this.context.view.removeListener("remove", this.onChange); - this.context.view.removeListener("recalculate", this.onChange); - }, - getDefaultProps: function () { - return { - rowHeight: ROW_HEIGHT - }; - }, - onScrollFlowTable: function () { - this.adjustHead(); - this.onScroll(); - }, - onChange: function () { - this.forceUpdate(); - }, - scrollIntoView: function (flow) { - this.scrollRowIntoView( - this.context.view.index(flow), - this.refs.body.getDOMNode().offsetTop - ); - }, - renderRow: function (flow) { - var selected = (flow === this.props.selected); - var highlighted = - ( - this.context.view._highlight && - this.context.view._highlight[flow.id] - ); - - return ; - }, - render: function () { - var flows = this.context.view.list; - var rows = this.renderRows(flows); - - return ( -
- - - - { this.getPlaceholderTop(flows.length) } - {rows} - { this.getPlaceholderBottom(flows.length) } - -
-
- ); - } -}); - -module.exports = FlowTable; diff --git a/web/src/js/components/flowview/contentview.js b/web/src/js/components/flowview/contentview.js deleted file mode 100644 index 63d22c1c..00000000 --- a/web/src/js/components/flowview/contentview.js +++ /dev/null @@ -1,237 +0,0 @@ -var React = require("react"); -var _ = require("lodash"); - -var MessageUtils = require("../../flow/utils.js").MessageUtils; -var utils = require("../../utils.js"); - -var image_regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i; -var ViewImage = React.createClass({ - statics: { - matches: function (message) { - return image_regex.test(MessageUtils.getContentType(message)); - } - }, - render: function () { - var url = MessageUtils.getContentURL(this.props.flow, this.props.message); - return
- preview -
; - } -}); - -var RawMixin = { - getInitialState: function () { - return { - content: undefined, - request: undefined - } - }, - requestContent: function (nextProps) { - if (this.state.request) { - this.state.request.abort(); - } - var request = MessageUtils.getContent(nextProps.flow, nextProps.message); - this.setState({ - content: undefined, - request: request - }); - request.done(function (data) { - this.setState({content: data}); - }.bind(this)).fail(function (jqXHR, textStatus, errorThrown) { - if (textStatus === "abort") { - return; - } - this.setState({content: "AJAX Error: " + textStatus + "\r\n" + errorThrown}); - }.bind(this)).always(function () { - this.setState({request: undefined}); - }.bind(this)); - - }, - componentWillMount: function () { - this.requestContent(this.props); - }, - componentWillReceiveProps: function (nextProps) { - if (nextProps.message !== this.props.message) { - this.requestContent(nextProps); - } - }, - componentWillUnmount: function () { - if (this.state.request) { - this.state.request.abort(); - } - }, - render: function () { - if (!this.state.content) { - return
- -
; - } - return this.renderContent(); - } -}; - -var ViewRaw = React.createClass({ - mixins: [RawMixin], - statics: { - matches: function (message) { - return true; - } - }, - renderContent: function () { - return
{this.state.content}
; - } -}); - -var json_regex = /^application\/json$/i; -var ViewJSON = React.createClass({ - mixins: [RawMixin], - statics: { - matches: function (message) { - return json_regex.test(MessageUtils.getContentType(message)); - } - }, - renderContent: function () { - var json = this.state.content; - try { - json = JSON.stringify(JSON.parse(json), null, 2); - } catch (e) { - } - return
{json}
; - } -}); - -var ViewAuto = React.createClass({ - statics: { - matches: function () { - return false; // don't match itself - }, - findView: function (message) { - for (var i = 0; i < all.length; i++) { - if (all[i].matches(message)) { - return all[i]; - } - } - return all[all.length - 1]; - } - }, - render: function () { - var View = ViewAuto.findView(this.props.message); - return ; - } -}); - -var all = [ViewAuto, ViewImage, ViewJSON, ViewRaw]; - - -var ContentEmpty = React.createClass({ - render: function () { - var message_name = this.props.flow.request === this.props.message ? "request" : "response"; - return
No {message_name} content.
; - } -}); - -var ContentMissing = React.createClass({ - render: function () { - var message_name = this.props.flow.request === this.props.message ? "Request" : "Response"; - return
{message_name} content missing.
; - } -}); - -var TooLarge = React.createClass({ - statics: { - isTooLarge: function (message) { - var max_mb = ViewImage.matches(message) ? 10 : 0.2; - return message.contentLength > 1024 * 1024 * max_mb; - } - }, - render: function () { - var size = utils.formatSize(this.props.message.contentLength); - return
- - {size} content size. -
; - } -}); - -var ViewSelector = React.createClass({ - render: function () { - var views = []; - for (var i = 0; i < all.length; i++) { - var view = all[i]; - var className = "btn btn-default"; - if (view === this.props.active) { - className += " active"; - } - var text; - if (view === ViewAuto) { - text = "auto: " + ViewAuto.findView(this.props.message).displayName.toLowerCase().replace("view", ""); - } else { - text = view.displayName.toLowerCase().replace("view", ""); - } - views.push( - - ); - } - - return
{views}
; - } -}); - -var ContentView = React.createClass({ - getInitialState: function () { - return { - displayLarge: false, - View: ViewAuto - }; - }, - propTypes: { - // It may seem a bit weird at the first glance: - // Every view takes the flow and the message as props, e.g. - // - flow: React.PropTypes.object.isRequired, - message: React.PropTypes.object.isRequired, - }, - selectView: function (view) { - this.setState({ - View: view - }); - }, - displayLarge: function () { - this.setState({displayLarge: true}); - }, - componentWillReceiveProps: function (nextProps) { - if (nextProps.message !== this.props.message) { - this.setState(this.getInitialState()); - } - }, - render: function () { - var message = this.props.message; - if (message.contentLength === 0) { - return ; - } else if (message.contentLength === null) { - return ; - } else if (!this.state.displayLarge && TooLarge.isTooLarge(message)) { - return ; - } - - var downloadUrl = MessageUtils.getContentURL(this.props.flow, message); - - return
- -
- -   - - - -
-
; - } -}); - -module.exports = ContentView; \ No newline at end of file diff --git a/web/src/js/components/flowview/details.js b/web/src/js/components/flowview/details.js deleted file mode 100644 index 00e0116c..00000000 --- a/web/src/js/components/flowview/details.js +++ /dev/null @@ -1,181 +0,0 @@ -var React = require("react"); -var _ = require("lodash"); - -var utils = require("../../utils.js"); - -var TimeStamp = React.createClass({ - render: function () { - - if (!this.props.t) { - //should be return null, but that triggers a React bug. - return ; - } - - var ts = utils.formatTimeStamp(this.props.t); - - var delta; - if (this.props.deltaTo) { - delta = utils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo)); - delta = {"(" + delta + ")"}; - } else { - delta = null; - } - - return - {this.props.title + ":"} - {ts} {delta} - ; - } -}); - -var ConnectionInfo = React.createClass({ - - render: function () { - var conn = this.props.conn; - var address = conn.address.address.join(":"); - - var sni = ; //should be null, but that triggers a React bug. - if (conn.sni) { - sni = - - TLS SNI: - - {conn.sni} - ; - } - return ( - - - - - - - {sni} - -
Address:{address}
- ); - } -}); - -var CertificateInfo = React.createClass({ - render: function () { - //TODO: We should fetch human-readable certificate representation - // from the server - var flow = this.props.flow; - var client_conn = flow.client_conn; - var server_conn = flow.server_conn; - - var preStyle = {maxHeight: 100}; - return ( -
- {client_conn.cert ?

Client Certificate

: null} - {client_conn.cert ?
{client_conn.cert}
: null} - - {server_conn.cert ?

Server Certificate

: null} - {server_conn.cert ?
{server_conn.cert}
: null} -
- ); - } -}); - -var Timing = React.createClass({ - render: function () { - var flow = this.props.flow; - var sc = flow.server_conn; - var cc = flow.client_conn; - var req = flow.request; - var resp = flow.response; - - var timestamps = [ - { - title: "Server conn. initiated", - t: sc.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Server conn. TCP handshake", - t: sc.timestamp_tcp_setup, - deltaTo: req.timestamp_start - }, { - title: "Server conn. SSL handshake", - t: sc.timestamp_ssl_setup, - deltaTo: req.timestamp_start - }, { - title: "Client conn. established", - t: cc.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Client conn. SSL handshake", - t: cc.timestamp_ssl_setup, - deltaTo: req.timestamp_start - }, { - title: "First request byte", - t: req.timestamp_start, - }, { - title: "Request complete", - t: req.timestamp_end, - deltaTo: req.timestamp_start - } - ]; - - if (flow.response) { - timestamps.push( - { - title: "First response byte", - t: resp.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Response complete", - t: resp.timestamp_end, - deltaTo: req.timestamp_start - } - ); - } - - //Add unique key for each row. - timestamps.forEach(function (e) { - e.key = e.title; - }); - - timestamps = _.sortBy(timestamps, 't'); - - var rows = timestamps.map(function (e) { - return ; - }); - - return ( -
-

Timing

- - - {rows} - -
-
- ); - } -}); - -var Details = React.createClass({ - render: function () { - var flow = this.props.flow; - var client_conn = flow.client_conn; - var server_conn = flow.server_conn; - return ( -
- -

Client Connection

- - -

Server Connection

- - - - - - -
- ); - } -}); - -module.exports = Details; \ No newline at end of file diff --git a/web/src/js/components/flowview/index.js b/web/src/js/components/flowview/index.js deleted file mode 100644 index 739a46dc..00000000 --- a/web/src/js/components/flowview/index.js +++ /dev/null @@ -1,127 +0,0 @@ -var React = require("react"); -var _ = require("lodash"); - -var common = require("../common.js"); -var Nav = require("./nav.js"); -var Messages = require("./messages.js"); -var Details = require("./details.js"); -var Prompt = require("../prompt.js"); - - -var allTabs = { - request: Messages.Request, - response: Messages.Response, - error: Messages.Error, - details: Details -}; - -var FlowView = React.createClass({ - mixins: [common.StickyHeadMixin, common.Navigation, common.RouterState], - getInitialState: function () { - return { - prompt: false - }; - }, - getTabs: function (flow) { - var tabs = []; - ["request", "response", "error"].forEach(function (e) { - if (flow[e]) { - tabs.push(e); - } - }); - tabs.push("details"); - return tabs; - }, - nextTab: function (i) { - var tabs = this.getTabs(this.props.flow); - var currentIndex = tabs.indexOf(this.getActive()); - // JS modulo operator doesn't correct negative numbers, make sure that we are positive. - var nextIndex = (currentIndex + i + tabs.length) % tabs.length; - this.selectTab(tabs[nextIndex]); - }, - selectTab: function (panel) { - this.replaceWith( - "flow", - { - flowId: this.getParams().flowId, - detailTab: panel - } - ); - }, - getActive: function(){ - return this.getParams().detailTab; - }, - promptEdit: function () { - var options; - switch(this.getActive()){ - case "request": - options = [ - "method", - "url", - {text:"http version", key:"v"}, - "header" - /*, "content"*/]; - break; - case "response": - options = [ - {text:"http version", key:"v"}, - "code", - "message", - "header" - /*, "content"*/]; - break; - case "details": - return; - default: - throw "Unknown tab for edit: " + this.getActive(); - } - - this.setState({ - prompt: { - done: function (k) { - this.setState({prompt: false}); - if(k){ - this.refs.tab.edit(k); - } - }.bind(this), - options: options - } - }); - }, - render: function () { - var flow = this.props.flow; - var tabs = this.getTabs(flow); - var active = this.getActive(); - - if (!_.contains(tabs, active)) { - if (active === "response" && flow.error) { - active = "error"; - } else if (active === "error" && flow.response) { - active = "response"; - } else { - active = tabs[0]; - } - this.selectTab(active); - } - - var prompt = null; - if (this.state.prompt) { - prompt = ; - } - - var Tab = allTabs[active]; - return ( -
-
- ); - } -}); - -module.exports = FlowView; \ No newline at end of file diff --git a/web/src/js/components/flowview/messages.js b/web/src/js/components/flowview/messages.js deleted file mode 100644 index 7ac95d85..00000000 --- a/web/src/js/components/flowview/messages.js +++ /dev/null @@ -1,326 +0,0 @@ -var React = require("react"); -var _ = require("lodash"); - -var common = require("../common.js"); -var actions = require("../../actions.js"); -var flowutils = require("../../flow/utils.js"); -var utils = require("../../utils.js"); -var ContentView = require("./contentview.js"); -var ValueEditor = require("../editor.js").ValueEditor; - -var Headers = React.createClass({ - propTypes: { - onChange: React.PropTypes.func.isRequired, - message: React.PropTypes.object.isRequired - }, - onChange: function (row, col, val) { - var nextHeaders = _.cloneDeep(this.props.message.headers); - nextHeaders[row][col] = val; - if (!nextHeaders[row][0] && !nextHeaders[row][1]) { - // do not delete last row - if (nextHeaders.length === 1) { - nextHeaders[0][0] = "Name"; - nextHeaders[0][1] = "Value"; - } else { - nextHeaders.splice(row, 1); - // manually move selection target if this has been the last row. - if (row === nextHeaders.length) { - this._nextSel = (row - 1) + "-value"; - } - } - } - this.props.onChange(nextHeaders); - }, - edit: function () { - this.refs["0-key"].focus(); - }, - onTab: function (row, col, e) { - var headers = this.props.message.headers; - if (row === headers.length - 1 && col === 1) { - e.preventDefault(); - - var nextHeaders = _.cloneDeep(this.props.message.headers); - nextHeaders.push(["Name", "Value"]); - this.props.onChange(nextHeaders); - this._nextSel = (row + 1) + "-key"; - } - }, - componentDidUpdate: function () { - if (this._nextSel && this.refs[this._nextSel]) { - this.refs[this._nextSel].focus(); - this._nextSel = undefined; - } - }, - onRemove: function (row, col, e) { - if (col === 1) { - e.preventDefault(); - this.refs[row + "-key"].focus(); - } else if (row > 0) { - e.preventDefault(); - this.refs[(row - 1) + "-value"].focus(); - } - }, - render: function () { - - var rows = this.props.message.headers.map(function (header, i) { - - var kEdit = ; - var vEdit = ; - return ( - - {kEdit}: - {vEdit} - - ); - }.bind(this)); - return ( - - - {rows} - -
- ); - } -}); - -var HeaderEditor = React.createClass({ - render: function () { - return ; - }, - focus: function () { - this.getDOMNode().focus(); - }, - onKeyDown: function (e) { - switch (e.keyCode) { - case utils.Key.BACKSPACE: - var s = window.getSelection().getRangeAt(0); - if (s.startOffset === 0 && s.endOffset === 0) { - this.props.onRemove(e); - } - break; - case utils.Key.TAB: - if (!e.shiftKey) { - this.props.onTab(e); - } - break; - } - } -}); - -var RequestLine = React.createClass({ - render: function () { - var flow = this.props.flow; - var url = flowutils.RequestUtils.pretty_url(flow.request); - var httpver = flow.request.http_version; - - return
- -   - -   - -
- }, - isValidUrl: function (url) { - var u = flowutils.parseUrl(url); - return !!u.host; - }, - onMethodChange: function (nextMethod) { - actions.FlowActions.update( - this.props.flow, - {request: {method: nextMethod}} - ); - }, - onUrlChange: function (nextUrl) { - var props = flowutils.parseUrl(nextUrl); - props.path = props.path || ""; - actions.FlowActions.update( - this.props.flow, - {request: props} - ); - }, - onHttpVersionChange: function (nextVer) { - var ver = flowutils.parseHttpVersion(nextVer); - actions.FlowActions.update( - this.props.flow, - {request: {http_version: ver}} - ); - } -}); - -var ResponseLine = React.createClass({ - render: function () { - var flow = this.props.flow; - var httpver = flow.response.http_version; - return
- -   - -   - -
; - }, - isValidCode: function (code) { - return /^\d+$/.test(code); - }, - onHttpVersionChange: function (nextVer) { - var ver = flowutils.parseHttpVersion(nextVer); - actions.FlowActions.update( - this.props.flow, - {response: {http_version: ver}} - ); - }, - onMsgChange: function (nextMsg) { - actions.FlowActions.update( - this.props.flow, - {response: {msg: nextMsg}} - ); - }, - onCodeChange: function (nextCode) { - nextCode = parseInt(nextCode); - actions.FlowActions.update( - this.props.flow, - {response: {code: nextCode}} - ); - } -}); - -var Request = React.createClass({ - render: function () { - var flow = this.props.flow; - return ( -
- - {/**/} - -
- -
- ); - }, - edit: function (k) { - switch (k) { - 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: " + k; - } - }, - onHeaderChange: function (nextHeaders) { - actions.FlowActions.update(this.props.flow, { - request: { - headers: nextHeaders - } - }); - } -}); - -var Response = React.createClass({ - render: function () { - var flow = this.props.flow; - return ( -
- {/**/} - - -
- -
- ); - }, - edit: function (k) { - switch (k) { - 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: " + k; - } - }, - onHeaderChange: function (nextHeaders) { - actions.FlowActions.update(this.props.flow, { - response: { - headers: nextHeaders - } - }); - } -}); - -var Error = React.createClass({ - render: function () { - var flow = this.props.flow; - return ( -
-
- {flow.error.msg} -
- { utils.formatTimeStamp(flow.error.timestamp) } -
-
-
- ); - } -}); - -module.exports = { - Request: Request, - Response: Response, - Error: Error -}; diff --git a/web/src/js/components/flowview/nav.js b/web/src/js/components/flowview/nav.js deleted file mode 100644 index 46eda707..00000000 --- a/web/src/js/components/flowview/nav.js +++ /dev/null @@ -1,61 +0,0 @@ -var React = require("react"); - -var actions = require("../../actions.js"); - -var NavAction = React.createClass({ - onClick: function (e) { - e.preventDefault(); - this.props.onClick(); - }, - render: function () { - return ( - - - - ); - } -}); - -var Nav = React.createClass({ - render: function () { - var flow = this.props.flow; - - var tabs = this.props.tabs.map(function (e) { - var str = e.charAt(0).toUpperCase() + e.slice(1); - var className = this.props.active === e ? "active" : ""; - var onClick = function (event) { - this.props.selectTab(e); - event.preventDefault(); - }.bind(this); - return {str}; - }.bind(this)); - - var acceptButton = null; - if(flow.intercepted){ - acceptButton = ; - } - var revertButton = null; - if(flow.modified){ - revertButton = ; - } - - return ( - - ); - } -}); - -module.exports = Nav; \ No newline at end of file diff --git a/web/src/js/components/footer.js b/web/src/js/components/footer.js deleted file mode 100644 index 229d691b..00000000 --- a/web/src/js/components/footer.js +++ /dev/null @@ -1,19 +0,0 @@ -var React = require("react"); -var common = require("./common.js"); - -var Footer = React.createClass({ - mixins: [common.SettingsState], - render: function () { - var mode = this.state.settings.mode; - var intercept = this.state.settings.intercept; - return ( -
- {mode && mode != "regular" ? {mode} mode : null} -   - {intercept ? Intercept: {intercept} : null} -
- ); - } -}); - -module.exports = Footer; \ No newline at end of file diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js deleted file mode 100644 index 998a41df..00000000 --- a/web/src/js/components/header.js +++ /dev/null @@ -1,399 +0,0 @@ -var React = require("react"); -var $ = require("jquery"); - -var Filt = require("../filt/filt.js"); -var utils = require("../utils.js"); -var common = require("./common.js"); -var actions = require("../actions.js"); -var Query = require("../actions.js").Query; - -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 ; - } else { - var commands = FilterDocs.doc.commands.map(function (c) { - return - {c[0].replace(" ", '\u00a0')} - {c[1]} - ; - }); - commands.push( - - - -   mitmproxy docs - - ); - return - {commands} -
; - } - } -}); -var FilterInput = React.createClass({ - mixins: [common.ChildFocus], - 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 { - Filt.parse(filt || this.state.value); - return true; - } catch (e) { - return false; - } - }, - getDesc: function () { - var desc; - try { - desc = Filt.parse(this.state.value).desc; - } catch (e) { - desc = "" + e; - } - if (desc !== "true") { - return desc; - } else { - return ( - - ); - } - }, - 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 === utils.Key.ESC || e.keyCode === utils.Key.ENTER) { - this.blur(); - // If closed using ESC/ENTER, hide the tooltip. - this.setState({mousefocus: false}); - } - e.stopPropagation(); - }, - blur: function () { - this.refs.input.getDOMNode().blur(); - this.returnFocus(); - }, - select: function () { - this.refs.input.getDOMNode().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 = ( -
-
-
- {this.getDesc()} -
-
- ); - } - - return ( -
- - - - - {popover} -
- ); - } -}); - -var MainMenu = React.createClass({ - mixins: [common.Navigation, common.RouterState, common.SettingsState], - statics: { - title: "Start", - route: "flows" - }, - onSearchChange: function (val) { - var d = {}; - d[Query.SEARCH] = val; - this.setQuery(d); - }, - onHighlightChange: function (val) { - var d = {}; - d[Query.HIGHLIGHT] = val; - this.setQuery(d); - }, - onInterceptChange: function (val) { - actions.SettingsActions.update({intercept: val}); - }, - render: function () { - var search = this.getQuery()[Query.SEARCH] || ""; - var highlight = this.getQuery()[Query.HIGHLIGHT] || ""; - var intercept = this.state.settings.intercept || ""; - - return ( -
-
- - - -
-
-
- ); - } -}); - - -var ViewMenu = React.createClass({ - statics: { - title: "View", - route: "flows" - }, - mixins: [common.Navigation, common.RouterState], - toggleEventLog: function () { - var d = {}; - - if (this.getQuery()[Query.SHOW_EVENTLOG]) { - d[Query.SHOW_EVENTLOG] = undefined; - } else { - d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short - } - - this.setQuery(d); - }, - render: function () { - var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG]; - return ( -
- - -
- ); - } -}); - - -var ReportsMenu = React.createClass({ - statics: { - title: "Visualization", - route: "reports" - }, - render: function () { - return
Reports Menu
; - } -}); - -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?")) { - actions.FlowActions.clear(); - } - }, - handleOpenClick: function (e) { - e.preventDefault(); - console.error("unimplemented: handleOpenClick"); - }, - handleSaveClick: function (e) { - e.preventDefault(); - console.error("unimplemented: handleSaveClick"); - }, - handleShutdownClick: function (e) { - e.preventDefault(); - console.error("unimplemented: handleShutdownClick"); - }, - render: function () { - var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : ""); - - return ( - - ); - } -}); - - -var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */]; - - -var Header = React.createClass({ - mixins: [common.Navigation], - getInitialState: function () { - return { - active: header_entries[0] - }; - }, - handleClick: function (active, e) { - e.preventDefault(); - this.replaceWith(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 ( - - { entry.title} - - ); - }.bind(this)); - - return ( -
- -
- -
-
- ); - } -}); - - -module.exports = { - Header: Header, - MainMenu: MainMenu -}; \ No newline at end of file diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js deleted file mode 100644 index 9ff51dfa..00000000 --- a/web/src/js/components/mainview.js +++ /dev/null @@ -1,244 +0,0 @@ -var React = require("react"); - -var actions = require("../actions.js"); -var Query = require("../actions.js").Query; -var utils = require("../utils.js"); -var views = require("../store/view.js"); -var Filt = require("../filt/filt.js"); - -var common = require("./common.js"); -var FlowTable = require("./flowtable.js"); -var FlowView = require("./flowview/index.js"); - -var MainView = React.createClass({ - mixins: [common.Navigation, common.RouterState], - contextTypes: { - flowStore: React.PropTypes.object.isRequired, - }, - childContextTypes: { - view: React.PropTypes.object.isRequired, - }, - getChildContext: function () { - return { - view: this.state.view - }; - }, - getInitialState: function () { - var sortKeyFun = false; - var view = new views.StoreView(this.context.flowStore, this.getViewFilt(), sortKeyFun); - view.addListener("recalculate", this.onRecalculate); - view.addListener("add", this.onUpdate); - view.addListener("update", this.onUpdate); - view.addListener("remove", this.onUpdate); - view.addListener("remove", this.onRemove); - - return { - view: view, - sortKeyFun: sortKeyFun - }; - }, - componentWillUnmount: function () { - this.state.view.close(); - }, - getViewFilt: function () { - try { - var filt = Filt.parse(this.getQuery()[Query.SEARCH] || ""); - var highlightStr = this.getQuery()[Query.HIGHLIGHT]; - var highlight = highlightStr ? Filt.parse(highlightStr) : false; - } catch (e) { - console.error("Error when processing filter: " + e); - } - - return function filter_and_highlight(flow) { - if (!this._highlight) { - this._highlight = {}; - } - this._highlight[flow.id] = highlight && highlight(flow); - return filt(flow); - }; - }, - componentWillReceiveProps: function (nextProps) { - var filterChanged = (this.props.query[Query.SEARCH] !== nextProps.query[Query.SEARCH]); - var highlightChanged = (this.props.query[Query.HIGHLIGHT] !== nextProps.query[Query.HIGHLIGHT]); - if (filterChanged || highlightChanged) { - this.state.view.recalculate(this.getViewFilt(), this.state.sortKeyFun); - } - }, - onRecalculate: function () { - this.forceUpdate(); - var selected = this.getSelected(); - if (selected) { - this.refs.flowTable.scrollIntoView(selected); - } - }, - onUpdate: function (flow) { - if (flow.id === this.getParams().flowId) { - this.forceUpdate(); - } - }, - onRemove: function (flow_id, index) { - if (flow_id === this.getParams().flowId) { - var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length - 1)]; - this.selectFlow(flow_to_select); - } - }, - setSortKeyFun: function (sortKeyFun) { - this.setState({ - sortKeyFun: sortKeyFun - }); - this.state.view.recalculate(this.getViewFilt(), sortKeyFun); - }, - selectFlow: function (flow) { - if (flow) { - this.replaceWith( - "flow", - { - flowId: flow.id, - detailTab: this.getParams().detailTab || "request" - } - ); - this.refs.flowTable.scrollIntoView(flow); - } else { - this.replaceWith("flows", {}); - } - }, - selectFlowRelative: function (shift) { - var flows = this.state.view.list; - var index; - if (!this.getParams().flowId) { - if (shift < 0) { - index = flows.length - 1; - } else { - index = 0; - } - } else { - var currFlowId = this.getParams().flowId; - var i = flows.length; - while (i--) { - if (flows[i].id === currFlowId) { - index = i; - break; - } - } - index = Math.min( - Math.max(0, index + shift), - flows.length - 1); - } - this.selectFlow(flows[index]); - }, - onMainKeyDown: function (e) { - var flow = this.getSelected(); - if (e.ctrlKey) { - return; - } - 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: - if (this.refs.flowDetails) { - this.refs.flowDetails.nextTab(-1); - } - break; - case utils.Key.L: - case utils.Key.TAB: - case utils.Key.RIGHT: - if (this.refs.flowDetails) { - this.refs.flowDetails.nextTab(+1); - } - break; - case utils.Key.C: - if (e.shiftKey) { - actions.FlowActions.clear(); - } - break; - case utils.Key.D: - if (flow) { - if (e.shiftKey) { - actions.FlowActions.duplicate(flow); - } else { - actions.FlowActions.delete(flow); - } - } - break; - case utils.Key.A: - if (e.shiftKey) { - actions.FlowActions.accept_all(); - } else if (flow && flow.intercepted) { - actions.FlowActions.accept(flow); - } - break; - case utils.Key.R: - if (!e.shiftKey && flow) { - actions.FlowActions.replay(flow); - } - break; - case utils.Key.V: - if (e.shiftKey && flow && flow.modified) { - actions.FlowActions.revert(flow); - } - break; - case utils.Key.E: - if (this.refs.flowDetails) { - this.refs.flowDetails.promptEdit(); - } - break; - case utils.Key.SHIFT: - break; - default: - console.debug("keydown", e.keyCode); - return; - } - e.preventDefault(); - }, - getSelected: function () { - return this.context.flowStore.get(this.getParams().flowId); - }, - render: function () { - var selected = this.getSelected(); - - var details; - if (selected) { - details = [ - , - - ]; - } else { - details = null; - } - - return ( -
- - {details} -
- ); - } -}); - -module.exports = MainView; diff --git a/web/src/js/components/prompt.js b/web/src/js/components/prompt.js deleted file mode 100644 index 121a1170..00000000 --- a/web/src/js/components/prompt.js +++ /dev/null @@ -1,100 +0,0 @@ -var React = require("react"); -var _ = require("lodash"); - -var utils = require("../utils.js"); -var common = require("./common.js"); - -var Prompt = React.createClass({ - mixins: [common.ChildFocus], - propTypes: { - options: React.PropTypes.array.isRequired, - done: React.PropTypes.func.isRequired, - prompt: React.PropTypes.string - }, - componentDidMount: function () { - React.findDOMNode(this).focus(); - }, - onKeyDown: function (e) { - e.stopPropagation(); - e.preventDefault(); - var opts = this.getOptions(); - for (var i = 0; i < opts.length; i++) { - var k = opts[i].key; - if (utils.Key[k.toUpperCase()] === e.keyCode) { - this.done(k); - return; - } - } - if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) { - this.done(false); - } - }, - onClick: function (e) { - this.done(false); - }, - done: function (ret) { - this.props.done(ret); - this.returnFocus(); - }, - getOptions: function () { - var opts = []; - - var keyTaken = function (k) { - return _.includes(_.pluck(opts, "key"), k); - }; - - for (var i = 0; i < this.props.options.length; i++) { - var opt = this.props.options[i]; - if (_.isString(opt)) { - var str = opt; - while (str.length > 0 && keyTaken(str[0])) { - str = str.substr(1); - } - opt = { - text: opt, - key: str[0] - }; - } - if (!opt.text || !opt.key || keyTaken(opt.key)) { - throw "invalid options"; - } else { - opts.push(opt); - } - } - return opts; - }, - render: function () { - var opts = this.getOptions(); - opts = _.map(opts, function (o) { - var prefix, suffix; - var idx = o.text.indexOf(o.key); - if (idx !== -1) { - prefix = o.text.substring(0, idx); - suffix = o.text.substring(idx + 1); - - } else { - prefix = o.text + " ("; - suffix = ")"; - } - var onClick = function (e) { - this.done(o.key); - e.stopPropagation(); - }.bind(this); - return - {prefix} - {o.key}{suffix} - ; - }.bind(this)); - return
-
- {this.props.prompt || Select: } - {opts} -
-
; - } -}); - -module.exports = Prompt; \ No newline at end of file diff --git a/web/src/js/components/proxyapp.js b/web/src/js/components/proxyapp.js deleted file mode 100644 index e766d6e6..00000000 --- a/web/src/js/components/proxyapp.js +++ /dev/null @@ -1,129 +0,0 @@ -var React = require("react"); -var ReactRouter = require("react-router"); -var _ = require("lodash"); - -var common = require("./common.js"); -var MainView = require("./mainview.js"); -var Footer = require("./footer.js"); -var header = require("./header.js"); -var EventLog = require("./eventlog.js"); -var store = require("../store/store.js"); -var Query = require("../actions.js").Query; -var Key = require("../utils.js").Key; - - -//TODO: Move out of here, just a stub. -var Reports = React.createClass({ - render: function () { - return
ReportEditor
; - } -}); - - -var ProxyAppMain = React.createClass({ - mixins: [common.RouterState], - childContextTypes: { - settingsStore: React.PropTypes.object.isRequired, - flowStore: React.PropTypes.object.isRequired, - eventStore: React.PropTypes.object.isRequired, - returnFocus: React.PropTypes.func.isRequired, - }, - componentDidMount: function () { - this.focus(); - }, - getChildContext: function () { - return { - settingsStore: this.state.settingsStore, - flowStore: this.state.flowStore, - eventStore: this.state.eventStore, - returnFocus: this.focus, - }; - }, - getInitialState: function () { - var eventStore = new store.EventLogStore(); - var flowStore = new store.FlowStore(); - var settingsStore = new store.SettingsStore(); - - // Default Settings before fetch - _.extend(settingsStore.dict, {}); - return { - settingsStore: settingsStore, - flowStore: flowStore, - eventStore: eventStore - }; - }, - focus: function () { - React.findDOMNode(this).focus(); - }, - getMainComponent: function () { - return this.refs.view.refs.__routeHandler__; - }, - onKeydown: function (e) { - - var selectFilterInput = function (name) { - var headerComponent = this.refs.header; - headerComponent.setState({active: header.MainMenu}, function () { - headerComponent.refs.active.refs[name].select(); - }); - }.bind(this); - - switch (e.keyCode) { - case Key.I: - selectFilterInput("intercept"); - break; - case Key.L: - selectFilterInput("search"); - break; - case Key.H: - selectFilterInput("highlight"); - break; - default: - var main = this.getMainComponent(); - if (main.onMainKeyDown) { - main.onMainKeyDown(e); - } - return; // don't prevent default then - } - e.preventDefault(); - }, - render: function () { - var eventlog; - if (this.getQuery()[Query.SHOW_EVENTLOG]) { - eventlog = [ - , - - ]; - } else { - eventlog = null; - } - return ( -
- - - {eventlog} -
-
- ); - } -}); - - -var Route = ReactRouter.Route; -var RouteHandler = ReactRouter.RouteHandler; -var Redirect = ReactRouter.Redirect; -var DefaultRoute = ReactRouter.DefaultRoute; -var NotFoundRoute = ReactRouter.NotFoundRoute; - - -var routes = ( - - - - - - -); - -module.exports = { - routes: routes -}; \ No newline at end of file diff --git a/web/src/js/components/virtualscroll.js b/web/src/js/components/virtualscroll.js deleted file mode 100644 index 956e1a0b..00000000 --- a/web/src/js/components/virtualscroll.js +++ /dev/null @@ -1,85 +0,0 @@ -var React = require("react"); - -var VirtualScrollMixin = { - getInitialState: function () { - return { - start: 0, - stop: 0 - }; - }, - componentWillMount: function () { - if (!this.props.rowHeight) { - console.warn("VirtualScrollMixin: No rowHeight specified", this); - } - }, - getPlaceholderTop: function (total) { - var Tag = this.props.placeholderTagName || "tr"; - // When a large trunk of elements is removed from the button, start may be far off the viewport. - // To make this issue less severe, limit the top placeholder to the total number of rows. - var style = { - height: Math.min(this.state.start, total) * this.props.rowHeight - }; - var spacer = ; - - if (this.state.start % 2 === 1) { - // fix even/odd rows - return [spacer, ]; - } else { - return spacer; - } - }, - getPlaceholderBottom: function (total) { - var Tag = this.props.placeholderTagName || "tr"; - var style = { - height: Math.max(0, total - this.state.stop) * this.props.rowHeight - }; - return ; - }, - componentDidMount: function () { - this.onScroll(); - window.addEventListener('resize', this.onScroll); - }, - componentWillUnmount: function(){ - window.removeEventListener('resize', this.onScroll); - }, - onScroll: function () { - var viewport = this.getDOMNode(); - var top = viewport.scrollTop; - var height = viewport.offsetHeight; - var start = Math.floor(top / this.props.rowHeight); - var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight)); - - this.setState({ - start: start, - stop: stop - }); - }, - renderRows: function (elems) { - var rows = []; - var max = Math.min(elems.length, this.state.stop); - - for (var i = this.state.start; i < max; i++) { - var elem = elems[i]; - rows.push(this.renderRow(elem)); - } - return rows; - }, - scrollRowIntoView: function (index, head_height) { - - var row_top = (index * this.props.rowHeight) + head_height; - var row_bottom = row_top + this.props.rowHeight; - - var viewport = this.getDOMNode(); - var viewport_top = viewport.scrollTop; - var viewport_bottom = viewport_top + viewport.offsetHeight; - - // Account for pinned thead - if (row_top - head_height < viewport_top) { - viewport.scrollTop = row_top - head_height; - } else if (row_bottom > viewport_bottom) { - viewport.scrollTop = row_bottom - viewport.offsetHeight; - } - }, -}; - -module.exports = VirtualScrollMixin; \ No newline at end of file -- cgit v1.2.3