From ed8249023fb7c0d429b9278c63b51ac071700987 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 26 Nov 2014 04:18:21 +0100 Subject: introduce revised views, port over changes from multiple_views branch --- web/src/js/components/mainview.jsx.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index 795b8136..f0dfb59a 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -7,8 +7,14 @@ var MainView = React.createClass({ }; }, componentDidMount: function () { - this.flowStore = FlowStore.getView(); - this.flowStore.addListener("change",this.onFlowChange); + //FIXME: The store should be global, move out of here. + window.flowstore = new LiveFlowStore(); + + this.flowStore = window.flowstore.open_view(); + this.flowStore.addListener("add",this.onFlowChange); + this.flowStore.addListener("update",this.onFlowChange); + this.flowStore.addListener("remove",this.onFlowChange); + this.flowStore.addListener("recalculate",this.onFlowChange); }, componentWillUnmount: function () { this.flowStore.removeListener("change",this.onFlowChange); @@ -16,7 +22,7 @@ var MainView = React.createClass({ }, onFlowChange: function () { this.setState({ - flows: this.flowStore.getAll() + flows: this.flowStore.flows }); }, selectDetailTab: function(panel) { -- cgit v1.2.3 From 38bf34ebd9826c6f69d97906282632fbd5cff06b Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 27 Nov 2014 01:38:30 +0100 Subject: web++ --- web/src/js/components/eventlog.jsx.js | 6 +- web/src/js/components/flowdetail.jsx.js | 148 ++++++++++++++----------- web/src/js/components/flowtable-columns.jsx.js | 3 - web/src/js/components/flowtable.jsx.js | 6 +- web/src/js/components/footer.jsx.js | 2 - web/src/js/components/header.jsx.js | 9 +- web/src/js/components/mainview.jsx.js | 120 +++++++++++--------- web/src/js/components/proxyapp.jsx.js | 31 +++--- web/src/js/components/utils.jsx.js | 2 - 9 files changed, 171 insertions(+), 156 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/eventlog.jsx.js b/web/src/js/components/eventlog.jsx.js index 08a6dfb4..34d84cdf 100644 --- a/web/src/js/components/eventlog.jsx.js +++ b/web/src/js/components/eventlog.jsx.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var LogMessage = React.createClass({ render: function(){ var entry = this.props.entry; @@ -57,7 +55,8 @@ var EventLogContents = React.createClass({ }); var ToggleFilter = React.createClass({ - toggle: function(){ + toggle: function(e){ + e.preventDefault(); return this.props.toggleLevel(this.props.name); }, render: function(){ @@ -97,7 +96,6 @@ var EventLog = React.createClass({ var filter = this.state.filter; filter[level] = !filter[level]; this.setState({filter: filter}); - return false; }, render: function () { return ( diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js index 3ba025a9..5c4168a9 100644 --- a/web/src/js/components/flowdetail.jsx.js +++ b/web/src/js/components/flowdetail.jsx.js @@ -1,34 +1,32 @@ -/** @jsx React.DOM */ - var FlowDetailNav = React.createClass({ - render: function(){ + render: function () { - var items = this.props.tabs.map(function(e){ + var items = 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(){ + var onClick = function (e) { this.props.selectTab(e); - return false; + e.preventDefault(); }.bind(this); return {str}; + href="#" + className={className} + onClick={onClick}>{str}; }.bind(this)); return ( ); - } + } }); var Headers = React.createClass({ - render: function(){ - var rows = this.props.message.headers.map(function(header, i){ + render: function () { + var rows = this.props.message.headers.map(function (header, i) { return ( - {header[0]+":"} + {header[0] + ":"} {header[1]} ); @@ -44,16 +42,16 @@ var Headers = React.createClass({ }); var FlowDetailRequest = React.createClass({ - render: function(){ + render: function () { var flow = this.props.flow; var first_line = [ - flow.request.method, - RequestUtils.pretty_url(flow.request), - "HTTP/"+ flow.response.httpversion.join(".") - ].join(" "); + flow.request.method, + RequestUtils.pretty_url(flow.request), + "HTTP/" + flow.response.httpversion.join(".") + ].join(" "); var content = null; - if(flow.request.contentLength > 0){ - content = "Request Content Size: "+ formatSize(flow.request.contentLength); + if (flow.request.contentLength > 0) { + content = "Request Content Size: " + formatSize(flow.request.contentLength); } else { content =
No Content
; } @@ -72,16 +70,16 @@ var FlowDetailRequest = React.createClass({ }); var FlowDetailResponse = React.createClass({ - render: function(){ + render: function () { var flow = this.props.flow; var first_line = [ - "HTTP/"+ flow.response.httpversion.join("."), - flow.response.code, - flow.response.msg - ].join(" "); + "HTTP/" + flow.response.httpversion.join("."), + flow.response.code, + flow.response.msg + ].join(" "); var content = null; - if(flow.response.contentLength > 0){ - content = "Response Content Size: "+ formatSize(flow.response.contentLength); + if (flow.response.contentLength > 0) { + content = "Response Content Size: " + formatSize(flow.response.contentLength); } else { content =
No Content
; } @@ -100,42 +98,53 @@ var FlowDetailResponse = React.createClass({ }); var TimeStamp = React.createClass({ - render: function() { + render: function () { - if(!this.props.t){ + if (!this.props.t) { //should be return null, but that triggers a React bug. return ; } var ts = (new Date(this.props.t * 1000)).toISOString(); - ts = ts.replace("T", " ").replace("Z",""); + ts = ts.replace("T", " ").replace("Z", ""); var delta; - if(this.props.deltaTo){ - delta = formatTimeDelta(1000 * (this.props.t-this.props.deltaTo)); + if (this.props.deltaTo) { + delta = formatTimeDelta(1000 * (this.props.t - this.props.deltaTo)); delta = {"(" + delta + ")"}; } else { delta = null; } - return {this.props.title + ":"}{ts} {delta}; + return + {this.props.title + ":"} + {ts} {delta} + ; } }); var ConnectionInfo = React.createClass({ - render: function() { + 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}; + if (conn.sni) { + sni = + + TLS SNI: + + {conn.sni} + ; } return ( - + + + + {sni}
Address:{address}
Address:{address}
@@ -144,7 +153,7 @@ var ConnectionInfo = React.createClass({ }); var CertificateInfo = React.createClass({ - render: function(){ + render: function () { //TODO: We should fetch human-readable certificate representation // from the server var flow = this.props.flow; @@ -165,7 +174,7 @@ var CertificateInfo = React.createClass({ }); var Timing = React.createClass({ - render: function(){ + render: function () { var flow = this.props.flow; var sc = flow.server_conn; var cc = flow.client_conn; @@ -218,46 +227,46 @@ var Timing = React.createClass({ } //Add unique key for each row. - timestamps.forEach(function(e){ + timestamps.forEach(function (e) { e.key = e.title; }); timestamps = _.sortBy(timestamps, 't'); - var rows = timestamps.map(function(e){ - return TimeStamp(e); + var rows = timestamps.map(function (e) { + return ; }); return (
-

Timing

- - +

Timing

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

Client Connection

- +

Client Connection

+ -

Server Connection

- +

Server Connection

+ - + - +
); @@ -271,29 +280,38 @@ var tabs = { }; var FlowDetail = React.createClass({ - getDefaultProps: function(){ + getDefaultProps: function () { return { - tabs: ["request","response", "details"] + tabs: ["request", "response", "details"] }; }, - mixins: [StickyHeadMixin], - nextTab: function(i) { + mixins: [StickyHeadMixin, ReactRouter.Navigation, ReactRouter.State], + nextTab: function (i) { var currentIndex = this.props.tabs.indexOf(this.props.active); // JS modulo operator doesn't correct negative numbers, make sure that we are positive. var nextIndex = (currentIndex + i + this.props.tabs.length) % this.props.tabs.length; - this.props.selectTab(this.props.tabs[nextIndex]); + this.selectTab(this.props.tabs[nextIndex]); + }, + selectTab: function (panel) { + this.replaceWith( + "flow", + { + flowId: this.getParams().flowId, + detailTab: panel + } + ); }, - render: function(){ + render: function () { var flow = JSON.stringify(this.props.flow, null, 2); var Tab = tabs[this.props.active]; return (
+ tabs={this.props.tabs} + active={this.props.active} + selectTab={this.selectTab}/>
- ); - } + ); + } }); \ No newline at end of file diff --git a/web/src/js/components/flowtable-columns.jsx.js b/web/src/js/components/flowtable-columns.jsx.js index b7db71b7..8a44c072 100644 --- a/web/src/js/components/flowtable-columns.jsx.js +++ b/web/src/js/components/flowtable-columns.jsx.js @@ -1,6 +1,3 @@ -/** @jsx React.DOM */ - - var TLSColumn = React.createClass({ statics: { renderTitle: function(){ diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index fc4d8fbc..2baf728f 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -1,10 +1,8 @@ -/** @jsx React.DOM */ - var FlowRow = React.createClass({ render: function(){ var flow = this.props.flow; - var columns = this.props.columns.map(function(column){ - return ; + var columns = this.props.columns.map(function(Column){ + return ; }.bind(this)); var className = ""; if(this.props.selected){ diff --git a/web/src/js/components/footer.jsx.js b/web/src/js/components/footer.jsx.js index 9bcbbc2a..6ba253bf 100644 --- a/web/src/js/components/footer.jsx.js +++ b/web/src/js/components/footer.jsx.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var Footer = React.createClass({ render: function () { var mode = this.props.settings.mode; diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js index 994bc759..5c905889 100644 --- a/web/src/js/components/header.jsx.js +++ b/web/src/js/components/header.jsx.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var MainMenu = React.createClass({ statics: { title: "Traffic", @@ -48,15 +46,16 @@ var header_entries = [MainMenu, ToolsMenu, ReportsMenu]; var Header = React.createClass({ + mixins: [ReactRouter.Navigation], getInitialState: function () { return { active: header_entries[0] }; }, - handleClick: function (active) { - ReactRouter.transitionTo(active.route); + handleClick: function (active, e) { + e.preventDefault(); + this.transitionTo(active.route); this.setState({active: active}); - return false; }, handleFileClick: function () { console.log("File click"); diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index f0dfb59a..799bd0d2 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -1,71 +1,82 @@ -/** @jsx React.DOM */ - var MainView = React.createClass({ - getInitialState: function() { + mixins: [ReactRouter.Navigation, ReactRouter.State], + getInitialState: function () { return { - flows: [], + flows: [] }; }, + componentWillReceiveProps: function (nextProps) { + if (nextProps.flowStore !== this.props.flowStore) { + this.closeView(); + this.openView(nextProps.flowStore); + } + }, + openView: function (store) { + var view = new FlowView(store); + this.setState({ + view: view + }); + view.addListener("add", this.onFlowChange); + view.addListener("update", this.onFlowChange); + view.addListener("remove", this.onFlowChange); + view.addListener("recalculate", this.onFlowChange); + }, + closeView: function () { + this.state.view.close(); + }, componentDidMount: function () { - //FIXME: The store should be global, move out of here. - window.flowstore = new LiveFlowStore(); - - this.flowStore = window.flowstore.open_view(); - this.flowStore.addListener("add",this.onFlowChange); - this.flowStore.addListener("update",this.onFlowChange); - this.flowStore.addListener("remove",this.onFlowChange); - this.flowStore.addListener("recalculate",this.onFlowChange); + this.openView(this.props.flowStore); }, componentWillUnmount: function () { - this.flowStore.removeListener("change",this.onFlowChange); - this.flowStore.close(); + this.closeView(); }, onFlowChange: function () { + console.warn("onFlowChange is deprecated"); this.setState({ - flows: this.flowStore.flows + flows: this.state.view.flows }); }, - selectDetailTab: function(panel) { - ReactRouter.replaceWith( - "flow", - { - flowId: this.props.params.flowId, - detailTab: panel - } - ); - }, - selectFlow: function(flow) { - if(flow){ - ReactRouter.replaceWith( - "flow", + selectFlow: function (flow) { + if (flow) { + this.replaceWith( + "flow", { flowId: flow.id, - detailTab: this.props.params.detailTab || "request" + detailTab: this.getParams().detailTab || "request" } ); - this.refs.flowTable.scrollIntoView(flow); + console.log("TODO: Scroll into view"); + //this.refs.flowTable.scrollIntoView(flow); } else { - ReactRouter.replaceWith("flows"); + this.replaceWith("flows"); } }, - selectFlowRelative: function(i){ + selectFlowRelative: function (i) { + var flows = this.state.view.flows; var index; - if(!this.props.params.flowId){ - if(i > 0){ - index = this.state.flows.length-1; + if (!this.getParams().flowId) { + if (i > 0) { + index = flows.length - 1; } else { index = 0; } } else { - index = _.findIndex(this.state.flows, function(f){ - return f.id === this.props.params.flowId; - }.bind(this)); - index = Math.min(Math.max(0, index+i), this.state.flows.length-1); + i = flows.length; + var currFlowId = this.getParams().flowId; + while (i--) { + if (flows[i].id === currFlowId) { + index = i; + break; + } + } + index = Math.min( + Math.max(0, index + i), + flows.length - 1); } - this.selectFlow(this.state.flows[index]); + this.selectFlow(flows[index]); }, - onKeyDown: function(e){ - switch(e.keyCode){ + onKeyDown: function (e) { + switch (e.keyCode) { case Key.K: case Key.UP: this.selectFlowRelative(-1); @@ -86,14 +97,14 @@ var MainView = React.createClass({ break; case Key.H: case Key.LEFT: - if(this.refs.flowDetails){ + if (this.refs.flowDetails) { this.refs.flowDetails.nextTab(-1); } break; case Key.L: case Key.TAB: case Key.RIGHT: - if(this.refs.flowDetails){ + if (this.refs.flowDetails) { this.refs.flowDetails.nextTab(+1); } break; @@ -101,18 +112,17 @@ var MainView = React.createClass({ console.debug("keydown", e.keyCode); return; } - return false; + e.preventDefault(); }, - render: function() { - var selected = _.find(this.state.flows, { id: this.props.params.flowId }); + render: function () { + var selected = this.props.flowStore.get(this.getParams().flowId); var details; - if(selected){ + if (selected) { details = ( - + ); } else { details = null; @@ -121,9 +131,9 @@ var MainView = React.createClass({ return (
+ flows={this.state.view ? this.state.view.flows : []} + selectFlow={this.selectFlow} + selected={selected} /> { details ? : null } {details}
diff --git a/web/src/js/components/proxyapp.jsx.js b/web/src/js/components/proxyapp.jsx.js index ff6e8da1..3545cfe0 100644 --- a/web/src/js/components/proxyapp.jsx.js +++ b/web/src/js/components/proxyapp.jsx.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - //TODO: Move out of here, just a stub. var Reports = React.createClass({ render: function () { @@ -10,7 +8,10 @@ var Reports = React.createClass({ var ProxyAppMain = React.createClass({ getInitialState: function () { - return { settings: SettingsStore.getAll() }; + return { + settings: SettingsStore.getAll(), + flowStore: new LiveFlowStore() + }; }, componentDidMount: function () { SettingsStore.addListener("change", this.onSettingsChange); @@ -25,30 +26,28 @@ var ProxyAppMain = React.createClass({ return (
- + {this.state.settings.showEventLog ? : null} {this.state.settings.showEventLog ? : null}
- ); + ); } }); -var Routes = ReactRouter.Routes; var Route = ReactRouter.Route; +var RouteHandler = ReactRouter.RouteHandler; var Redirect = ReactRouter.Redirect; var DefaultRoute = ReactRouter.DefaultRoute; var NotFoundRoute = ReactRouter.NotFoundRoute; -var ProxyApp = ( - - - - - - - - - ); \ No newline at end of file +var routes = ( + + + + + + +); \ No newline at end of file diff --git a/web/src/js/components/utils.jsx.js b/web/src/js/components/utils.jsx.js index 91cb8458..22aca577 100644 --- a/web/src/js/components/utils.jsx.js +++ b/web/src/js/components/utils.jsx.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - //React utils. For other utilities, see ../utils.js var Splitter = React.createClass({ -- cgit v1.2.3 From e41c0be293502619b6a072fb9bcd8bbd8694b86a Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 27 Nov 2014 01:40:26 +0100 Subject: format code --- web/src/js/components/eventlog.jsx.js | 24 +++++------ web/src/js/components/flowtable-columns.jsx.js | 50 ++++++++++++----------- web/src/js/components/flowtable.jsx.js | 56 +++++++++++++------------- web/src/js/components/footer.jsx.js | 2 +- web/src/js/components/header.jsx.js | 23 ++++++----- web/src/js/components/utils.jsx.js | 52 ++++++++++++------------ 6 files changed, 106 insertions(+), 101 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/eventlog.jsx.js b/web/src/js/components/eventlog.jsx.js index 34d84cdf..4d61a39c 100644 --- a/web/src/js/components/eventlog.jsx.js +++ b/web/src/js/components/eventlog.jsx.js @@ -1,8 +1,8 @@ var LogMessage = React.createClass({ - render: function(){ + render: function () { var entry = this.props.entry; var indicator; - switch(entry.level){ + switch (entry.level) { case "web": indicator = ; break; @@ -18,13 +18,13 @@ var LogMessage = React.createClass({ ); }, - shouldComponentUpdate: function(){ + shouldComponentUpdate: function () { return false; // log entries are immutable. } }); var EventLogContents = React.createClass({ - mixins:[AutoScrollMixin], + mixins: [AutoScrollMixin], getInitialState: function () { return { log: [] @@ -44,8 +44,8 @@ var EventLogContents = React.createClass({ }); }, render: function () { - var messages = this.state.log.map(function(row) { - if(!this.props.filter[row.level]){ + var messages = this.state.log.map(function (row) { + if (!this.props.filter[row.level]) { return null; } return ; @@ -55,11 +55,11 @@ var EventLogContents = React.createClass({ }); var ToggleFilter = React.createClass({ - toggle: function(e){ + toggle: function (e) { e.preventDefault(); return this.props.toggleLevel(this.props.name); }, - render: function(){ + render: function () { var className = "label "; if (this.props.active) { className += "label-primary"; @@ -74,11 +74,11 @@ var ToggleFilter = React.createClass({ {this.props.name} ); - } + } }); var EventLog = React.createClass({ - getInitialState: function(){ + getInitialState: function () { return { filter: { "debug": false, @@ -92,7 +92,7 @@ var EventLog = React.createClass({ showEventLog: false }); }, - toggleLevel: function(level){ + toggleLevel: function (level) { var filter = this.state.filter; filter[level] = !filter[level]; this.setState({filter: filter}); @@ -101,7 +101,7 @@ var EventLog = React.createClass({ return (
- Eventlog + Eventlog
diff --git a/web/src/js/components/flowtable-columns.jsx.js b/web/src/js/components/flowtable-columns.jsx.js index 8a44c072..1aa256c4 100644 --- a/web/src/js/components/flowtable-columns.jsx.js +++ b/web/src/js/components/flowtable-columns.jsx.js @@ -1,14 +1,14 @@ var TLSColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return ; } }, - render: function(){ + render: function () { var flow = this.props.flow; var ssl = (flow.request.scheme == "https"); var classes; - if(ssl){ + if (ssl) { classes = "col-tls col-tls-https"; } else { classes = "col-tls col-tls-http"; @@ -20,23 +20,23 @@ var TLSColumn = React.createClass({ var IconColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return ; } }, - render: function(){ + render: function () { var flow = this.props.flow; var icon; - if(flow.response){ + if (flow.response) { var contentType = ResponseUtils.getContentType(flow.response); //TODO: We should assign a type to the flow somewhere else. - if(flow.response.code == 304) { + if (flow.response.code == 304) { icon = "resource-icon-not-modified"; - } else if(300 <= flow.response.code && flow.response.code < 400) { + } else if (300 <= flow.response.code && flow.response.code < 400) { icon = "resource-icon-redirect"; - } else if(contentType && contentType.indexOf("image") >= 0) { + } else if (contentType && contentType.indexOf("image") >= 0) { icon = "resource-icon-image"; } else if (contentType && contentType.indexOf("javascript") >= 0) { icon = "resource-icon-js"; @@ -46,23 +46,25 @@ var IconColumn = React.createClass({ icon = "resource-icon-document"; } } - if(!icon){ + if (!icon) { icon = "resource-icon-plain"; } icon += " resource-icon"; - return
; + return +
+ ; } }); var PathColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return Path; } }, - render: function(){ + render: function () { var flow = this.props.flow; return {flow.request.scheme + "://" + flow.request.host + flow.request.path}; } @@ -71,11 +73,11 @@ var PathColumn = React.createClass({ var MethodColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return Method; } }, - render: function(){ + render: function () { var flow = this.props.flow; return {flow.request.method}; } @@ -84,14 +86,14 @@ var MethodColumn = React.createClass({ var StatusColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return Status; } }, - render: function(){ + render: function () { var flow = this.props.flow; var status; - if(flow.response){ + if (flow.response) { status = flow.response.code; } else { status = null; @@ -103,15 +105,15 @@ var StatusColumn = React.createClass({ var SizeColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return Size; } }, - render: function(){ + render: function () { var flow = this.props.flow; var total = flow.request.contentLength; - if(flow.response){ + if (flow.response) { total += flow.response.contentLength || 0; } var size = formatSize(total); @@ -122,14 +124,14 @@ var SizeColumn = React.createClass({ var TimeColumn = React.createClass({ statics: { - renderTitle: function(){ + renderTitle: function () { return Time; } }, - render: function(){ + render: function () { var flow = this.props.flow; var time; - if(flow.response){ + if (flow.response) { time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)); } else { time = "..."; diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index 2baf728f..6b56e512 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -1,11 +1,11 @@ var FlowRow = React.createClass({ - render: function(){ + render: function () { var flow = this.props.flow; - var columns = this.props.columns.map(function(Column){ + var columns = this.props.columns.map(function (Column) { return ; }.bind(this)); var className = ""; - if(this.props.selected){ + if (this.props.selected) { className += "selected"; } return ( @@ -13,35 +13,37 @@ var FlowRow = React.createClass({ {columns} ); }, - shouldComponentUpdate: function(nextProps){ + shouldComponentUpdate: function (nextProps) { var isEqual = ( - this.props.columns.length === nextProps.columns.length && - this.props.selected === nextProps.selected && - this.props.flow.response === nextProps.flow.response); + this.props.columns.length === nextProps.columns.length && + this.props.selected === nextProps.selected && + this.props.flow.response === nextProps.flow.response); return !isEqual; } }); var FlowTableHead = React.createClass({ - render: function(){ - var columns = this.props.columns.map(function(column){ + render: function () { + var columns = this.props.columns.map(function (column) { return column.renderTitle(); }.bind(this)); - return {columns}; + return + {columns} + ; } }); var FlowTableBody = React.createClass({ - render: function(){ - var rows = this.props.flows.map(function(flow){ + render: function () { + var rows = this.props.flows.map(function (flow) { var selected = (flow == this.props.selected); return ; + ref={flow.id} + flow={flow} + columns={this.props.columns} + selected={selected} + selectFlow={this.props.selectFlow} + />; }.bind(this)); return {rows}; } @@ -55,7 +57,7 @@ var FlowTable = React.createClass({ columns: all_columns }; }, - scrollIntoView: function(flow){ + scrollIntoView: function (flow) { // Now comes the fun part: Scroll the flow into the view. var viewport = this.getDOMNode(); var flowNode = this.refs.body.refs[flow.id].getDOMNode(); @@ -68,9 +70,9 @@ var FlowTable = React.createClass({ // -thead_height pixel earlier. flowNode_top -= this.refs.body.getDOMNode().offsetTop; - if(flowNode_top < viewport_top){ + if (flowNode_top < viewport_top) { viewport.scrollTop = flowNode_top; - } else if(flowNode_bottom > viewport_bottom) { + } else if (flowNode_bottom > viewport_bottom) { viewport.scrollTop = flowNode_bottom - viewport.offsetHeight; } }, @@ -79,14 +81,14 @@ var FlowTable = React.createClass({
+ columns={this.state.columns}/> + flows={this.props.flows} + selected={this.props.selected} + selectFlow={this.props.selectFlow} + columns={this.state.columns}/>
- ); + ); } }); diff --git a/web/src/js/components/footer.jsx.js b/web/src/js/components/footer.jsx.js index 6ba253bf..73fadef2 100644 --- a/web/src/js/components/footer.jsx.js +++ b/web/src/js/components/footer.jsx.js @@ -5,6 +5,6 @@ var Footer = React.createClass({
{mode != "regular" ? {mode} mode : null}
- ); + ); } }); diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js index 5c905889..e50c4274 100644 --- a/web/src/js/components/header.jsx.js +++ b/web/src/js/components/header.jsx.js @@ -12,10 +12,11 @@ var MainMenu = React.createClass({ return (
- ); + ); } }); @@ -61,25 +62,25 @@ var Header = React.createClass({ console.log("File click"); }, render: function () { - var header = header_entries.map(function(entry, i){ + var header = header_entries.map(function (entry, i) { var classes = React.addons.classSet({ active: entry == this.state.active }); return ( - { entry.title} - ); + ); }.bind(this)); - + return (
- mitmproxy { this.props.settings.version } + mitmproxy { this.props.settings.version }
- ); + ); } }); diff --git a/web/src/js/components/utils.jsx.js b/web/src/js/components/utils.jsx.js index 22aca577..b1d9a006 100644 --- a/web/src/js/components/utils.jsx.js +++ b/web/src/js/components/utils.jsx.js @@ -6,85 +6,85 @@ var Splitter = React.createClass({ axis: "x" }; }, - getInitialState: function(){ + getInitialState: function () { return { applied: false, startX: false, startY: false }; }, - onMouseDown: function(e){ + onMouseDown: function (e) { this.setState({ startX: e.pageX, startY: e.pageY }); - window.addEventListener("mousemove",this.onMouseMove); - window.addEventListener("mouseup",this.onMouseUp); + 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); + 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); + onDragEnd: function () { + this.getDOMNode().style.transform = ""; + window.removeEventListener("dragend", this.onDragEnd); + window.removeEventListener("mouseup", this.onMouseUp); + window.removeEventListener("mousemove", this.onMouseMove); }, - onMouseUp: function(e){ + 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 dX = e.pageX - this.state.startX; + var dY = e.pageY - this.state.startY; var flexBasis; - if(this.props.axis === "x"){ + if (this.props.axis === "x") { flexBasis = prev.offsetWidth + dX; } else { flexBasis = prev.offsetHeight + dY; } - prev.style.flex = "0 0 "+Math.max(0, flexBasis)+"px"; + prev.style.flex = "0 0 " + Math.max(0, flexBasis) + "px"; next.style.flex = "1 1 auto"; this.setState({ applied: true }); }, - onMouseMove: function(e){ + onMouseMove: function (e) { var dX = 0, dY = 0; - if(this.props.axis === "x"){ - dX = e.pageX-this.state.startX; + if (this.props.axis === "x") { + dX = e.pageX - this.state.startX; } else { - dY = e.pageY-this.state.startY; + dY = e.pageY - this.state.startY; } - this.getDOMNode().style.transform = "translate("+dX+"px,"+dY+"px)"; + this.getDOMNode().style.transform = "translate(" + dX + "px," + dY + "px)"; }, - reset: function(willUnmount) { + 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){ + if (!willUnmount) { this.setState({ applied: false }); } }, - componentWillUnmount: function(){ + componentWillUnmount: function () { this.reset(true); }, - render: function(){ + render: function () { var className = "splitter"; - if(this.props.axis === "x"){ + if (this.props.axis === "x") { className += " splitter-x"; } else { className += " splitter-y"; -- cgit v1.2.3 From 9eecc8d6e237022b328f6eaee48b64287336b258 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 27 Nov 2014 02:34:03 +0100 Subject: web: fixes --- web/src/js/components/mainview.jsx.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index 799bd0d2..a1c9772e 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -51,18 +51,18 @@ var MainView = React.createClass({ this.replaceWith("flows"); } }, - selectFlowRelative: function (i) { + selectFlowRelative: function (shift) { var flows = this.state.view.flows; var index; if (!this.getParams().flowId) { - if (i > 0) { + if (shift > 0) { index = flows.length - 1; } else { index = 0; } } else { - i = flows.length; var currFlowId = this.getParams().flowId; + var i = flows.length; while (i--) { if (flows[i].id === currFlowId) { index = i; @@ -70,7 +70,7 @@ var MainView = React.createClass({ } } index = Math.min( - Math.max(0, index + i), + Math.max(0, index + shift), flows.length - 1); } this.selectFlow(flows[index]); -- cgit v1.2.3 From 7ca1ac0f3b7856c0ae44bfbf3b27ae4a424a1cc2 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 28 Nov 2014 16:03:56 +0100 Subject: web: virtual scrolling --- web/src/js/components/flowtable.jsx.js | 107 ++++++++++++++++++++++++--------- web/src/js/components/mainview.jsx.js | 14 +---- 2 files changed, 82 insertions(+), 39 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index 6b56e512..76ceea41 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -14,11 +14,13 @@ var FlowRow = React.createClass({ ); }, shouldComponentUpdate: function (nextProps) { - var isEqual = ( - this.props.columns.length === nextProps.columns.length && - this.props.selected === nextProps.selected && - this.props.flow.response === nextProps.flow.response); - return !isEqual; + 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) + //); } }); @@ -33,30 +35,51 @@ var FlowTableHead = React.createClass({ } }); -var FlowTableBody = React.createClass({ - render: function () { - var rows = this.props.flows.map(function (flow) { - var selected = (flow == this.props.selected); - return ; - }.bind(this)); - return {rows}; - } -}); +var ROW_HEIGHT = 32; var FlowTable = React.createClass({ mixins: [StickyHeadMixin, AutoScrollMixin], getInitialState: function () { return { - columns: all_columns + columns: all_columns, + start: 0, + stop: 0 }; }, + componentWillMount: function () { + if (this.props.view) { + this.props.view.addListener("add update remove recalculate", this.onChange); + } + }, + componentWillReceiveProps: function (nextProps) { + if (nextProps.view !== this.props.view) { + if (this.props.view) { + this.props.view.removeListener("add update remove recalculate"); + } + nextProps.view.addListener("add update remove recalculate", this.onChange); + } + }, + componentDidMount: function () { + this.onScroll(); + }, + onScroll: function () { + this.adjustHead(); + + var viewport = this.getDOMNode(); + var top = viewport.scrollTop; + var height = viewport.offsetHeight; + var start = Math.floor(top / ROW_HEIGHT); + var stop = start + Math.ceil(height / ROW_HEIGHT); + this.setState({ + start: start, + stop: stop + }); + }, + onChange: function () { + console.log("onChange"); + this.forceUpdate(); + }, scrollIntoView: function (flow) { // Now comes the fun part: Scroll the flow into the view. var viewport = this.getDOMNode(); @@ -77,16 +100,46 @@ var FlowTable = React.createClass({ } }, render: function () { + var space_top = 0, space_bottom = 0, fix_nth_row = null; + var rows = []; + if (this.props.view) { + var flows = this.props.view.flows; + var max = Math.min(flows.length, this.state.stop); + console.log("render", this.props.view.flows.length, this.state.start, max - this.state.start, flows.length - this.state.stop); + + for (var i = this.state.start; i < max; i++) { + var flow = flows[i]; + var selected = (flow === this.props.selected); + rows.push( + + ); + } + + space_top = this.state.start * ROW_HEIGHT; + space_bottom = Math.max(0, flows.length - this.state.stop) * ROW_HEIGHT; + if(this.state.start % 2 === 1){ + fix_nth_row = ; + } + } + + return ( -
+
- + + + { fix_nth_row } + {rows} + +
); diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index a1c9772e..fd9fdb8d 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -16,26 +16,16 @@ var MainView = React.createClass({ this.setState({ view: view }); - view.addListener("add", this.onFlowChange); - view.addListener("update", this.onFlowChange); - view.addListener("remove", this.onFlowChange); - view.addListener("recalculate", this.onFlowChange); }, closeView: function () { this.state.view.close(); }, - componentDidMount: function () { + componentWillMount: function () { this.openView(this.props.flowStore); }, componentWillUnmount: function () { this.closeView(); }, - onFlowChange: function () { - console.warn("onFlowChange is deprecated"); - this.setState({ - flows: this.state.view.flows - }); - }, selectFlow: function (flow) { if (flow) { this.replaceWith( @@ -131,7 +121,7 @@ var MainView = React.createClass({ return (
{ details ? : null } -- cgit v1.2.3 From c39b6e4277357c9da1dfd5e3e8c41b5b3427e0ce Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 28 Nov 2014 19:16:47 +0100 Subject: web: various fixes, add clear button --- web/src/js/components/flowdetail.jsx.js | 5 ++--- web/src/js/components/flowtable.jsx.js | 25 ++++++++++++++----------- web/src/js/components/header.jsx.js | 9 +++++++-- web/src/js/components/mainview.jsx.js | 3 +-- web/src/js/components/utils.jsx.js | 17 +++++++++++++++++ 5 files changed, 41 insertions(+), 18 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js index 5c4168a9..74522f57 100644 --- a/web/src/js/components/flowdetail.jsx.js +++ b/web/src/js/components/flowdetail.jsx.js @@ -4,9 +4,9 @@ var FlowDetailNav = React.createClass({ var items = 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 (e) { + var onClick = function (event) { this.props.selectTab(e); - e.preventDefault(); + event.preventDefault(); }.bind(this); return diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index 76ceea41..6d0f5ee7 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -83,20 +83,23 @@ var FlowTable = React.createClass({ scrollIntoView: function (flow) { // Now comes the fun part: Scroll the flow into the view. var viewport = this.getDOMNode(); - var flowNode = this.refs.body.refs[flow.id].getDOMNode(); + var thead_height = this.refs.body.getDOMNode().offsetTop; + + var flow_top = (this.props.view.index(flow) * ROW_HEIGHT) + thead_height; + var viewport_top = viewport.scrollTop; var viewport_bottom = viewport_top + viewport.offsetHeight; - var flowNode_top = flowNode.offsetTop; - var flowNode_bottom = flowNode_top + flowNode.offsetHeight; + var flow_bottom = flow_top + ROW_HEIGHT; + + // Account for pinned thead + - // Account for pinned thead by pretending that the flowNode starts - // -thead_height pixel earlier. - flowNode_top -= this.refs.body.getDOMNode().offsetTop; + console.log("scrollInto", flow_top, flow_bottom, viewport_top, viewport_bottom, thead_height); - if (flowNode_top < viewport_top) { - viewport.scrollTop = flowNode_top; - } else if (flowNode_bottom > viewport_bottom) { - viewport.scrollTop = flowNode_bottom - viewport.offsetHeight; + if (flow_top - thead_height < viewport_top) { + viewport.scrollTop = flow_top - thead_height; + } else if (flow_bottom > viewport_bottom) { + viewport.scrollTop = flow_bottom - viewport.offsetHeight; } }, render: function () { @@ -134,7 +137,7 @@ var FlowTable = React.createClass({ - + { fix_nth_row } {rows} diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js index e50c4274..a3fe4d51 100644 --- a/web/src/js/components/header.jsx.js +++ b/web/src/js/components/header.jsx.js @@ -8,12 +8,17 @@ var MainMenu = React.createClass({ showEventLog: !this.props.settings.showEventLog }); }, + clearFlows: function(){ + $.post("/flows/clear"); + }, render: function () { return (
  +
); diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index fd9fdb8d..fe5d1c7c 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -35,8 +35,7 @@ var MainView = React.createClass({ detailTab: this.getParams().detailTab || "request" } ); - console.log("TODO: Scroll into view"); - //this.refs.flowTable.scrollIntoView(flow); + this.refs.flowTable.scrollIntoView(flow); } else { this.replaceWith("flows"); } diff --git a/web/src/js/components/utils.jsx.js b/web/src/js/components/utils.jsx.js index b1d9a006..12775adc 100644 --- a/web/src/js/components/utils.jsx.js +++ b/web/src/js/components/utils.jsx.js @@ -95,4 +95,21 @@ var Splitter = React.createClass({ ); } +}); + +function getCookie(name) { + var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); + return r ? r[1] : undefined; +} +var xsrf = $.param({_xsrf: getCookie("_xsrf")}); + +//Tornado XSRF Protection. +$.ajaxPrefilter(function(options){ + if(options.type === "post" && options.url[0] === "/"){ + if(options.data){ + options.data += ("&" + xsrf); + } else { + options.data = xsrf; + } + } }); \ No newline at end of file -- cgit v1.2.3 From dd1a45140c8a6cb3f6c5d7247120c05fa37cdf24 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 28 Nov 2014 20:03:04 +0100 Subject: web: add virtualscroll mixin --- web/src/js/components/flowtable.jsx.js | 65 ++++++++---------------------- web/src/js/components/virtualscroll.jsx.js | 54 +++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 web/src/js/components/virtualscroll.jsx.js (limited to 'web/src/js/components') diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index 6d0f5ee7..f608f41d 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -39,12 +39,10 @@ var FlowTableHead = React.createClass({ var ROW_HEIGHT = 32; var FlowTable = React.createClass({ - mixins: [StickyHeadMixin, AutoScrollMixin], + mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin], getInitialState: function () { return { - columns: all_columns, - start: 0, - stop: 0 + columns: all_columns }; }, componentWillMount: function () { @@ -61,46 +59,26 @@ var FlowTable = React.createClass({ } }, componentDidMount: function () { - this.onScroll(); + this.onScroll2(); }, - onScroll: function () { + getDefaultProps: function () { + return { + rowHeight: ROW_HEIGHT + }; + }, + onScroll2: function () { this.adjustHead(); - - var viewport = this.getDOMNode(); - var top = viewport.scrollTop; - var height = viewport.offsetHeight; - var start = Math.floor(top / ROW_HEIGHT); - var stop = start + Math.ceil(height / ROW_HEIGHT); - this.setState({ - start: start, - stop: stop - }); + this.onScroll(); }, onChange: function () { console.log("onChange"); this.forceUpdate(); }, scrollIntoView: function (flow) { - // Now comes the fun part: Scroll the flow into the view. - var viewport = this.getDOMNode(); - var thead_height = this.refs.body.getDOMNode().offsetTop; - - var flow_top = (this.props.view.index(flow) * ROW_HEIGHT) + thead_height; - - var viewport_top = viewport.scrollTop; - var viewport_bottom = viewport_top + viewport.offsetHeight; - var flow_bottom = flow_top + ROW_HEIGHT; - - // Account for pinned thead - - - console.log("scrollInto", flow_top, flow_bottom, viewport_top, viewport_bottom, thead_height); - - if (flow_top - thead_height < viewport_top) { - viewport.scrollTop = flow_top - thead_height; - } else if (flow_bottom > viewport_bottom) { - viewport.scrollTop = flow_bottom - viewport.offsetHeight; - } + this.scrollRowIntoView( + this.props.view.index(flow), + this.refs.body.getDOMNode().offsetTop + ); }, render: function () { var space_top = 0, space_bottom = 0, fix_nth_row = null; @@ -108,7 +86,6 @@ var FlowTable = React.createClass({ if (this.props.view) { var flows = this.props.view.flows; var max = Math.min(flows.length, this.state.stop); - console.log("render", this.props.view.flows.length, this.state.start, max - this.state.start, flows.length - this.state.stop); for (var i = this.state.start; i < max; i++) { var flow = flows[i]; @@ -123,25 +100,17 @@ var FlowTable = React.createClass({ /> ); } - - space_top = this.state.start * ROW_HEIGHT; - space_bottom = Math.max(0, flows.length - this.state.stop) * ROW_HEIGHT; - if(this.state.start % 2 === 1){ - fix_nth_row = ; - } } - return ( -
+
- - { fix_nth_row } + { this.getPlaceholderTop() } {rows} - + { this.getPlaceholderBottom(flows.length) }
diff --git a/web/src/js/components/virtualscroll.jsx.js b/web/src/js/components/virtualscroll.jsx.js new file mode 100644 index 00000000..ec3daa41 --- /dev/null +++ b/web/src/js/components/virtualscroll.jsx.js @@ -0,0 +1,54 @@ +var VirtualScrollMixin = { + getInitialState: function () { + return { + start: 0, + stop: 0 + } + }, + getPlaceholderTop: function () { + var style = { + height: this.state.start * this.props.rowHeight + }; + var spacer = ; + + if (this.state.start % 2 === 1) { + // fix even/odd rows + return [spacer, ]; + } else { + return spacer; + } + }, + getPlaceholderBottom: function (total) { + var style = { + height: Math.max(0, total - this.state.stop) * this.props.rowHeight + }; + return ; + }, + 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.rowHeight); + this.setState({ + start: start, + stop: stop + }); + }, + 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; + } + }, +}; \ No newline at end of file -- cgit v1.2.3 From f6c0e000da504a68ecd41a8f7ce59e2f71e0a218 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 28 Nov 2014 20:54:52 +0100 Subject: event log: virtual scrolling --- web/src/js/components/eventlog.jsx.js | 39 ++++++++++++++++++++++-------- web/src/js/components/flowtable.jsx.js | 34 +++++++++----------------- web/src/js/components/virtualscroll.jsx.js | 30 ++++++++++++++++++++--- 3 files changed, 67 insertions(+), 36 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/eventlog.jsx.js b/web/src/js/components/eventlog.jsx.js index 4d61a39c..708432d0 100644 --- a/web/src/js/components/eventlog.jsx.js +++ b/web/src/js/components/eventlog.jsx.js @@ -24,7 +24,7 @@ var LogMessage = React.createClass({ }); var EventLogContents = React.createClass({ - mixins: [AutoScrollMixin], + mixins: [AutoScrollMixin, VirtualScrollMixin], getInitialState: function () { return { log: [] @@ -39,18 +39,37 @@ var EventLogContents = React.createClass({ this.log.close(); }, onEventLogChange: function () { + var log = this.log.getAll().filter(function (entry) { + return this.props.filter[entry.level]; + }.bind(this)); this.setState({ - log: this.log.getAll() + log: log }); }, + componentWillReceiveProps: function () { + if (this.log) { + this.onEventLogChange(); + } + + }, + getDefaultProps: function () { + return { + rowHeight: 45, + rowHeightMin: 15, + placeholderTagName: "div" + }; + }, + renderRow: function(elem){ + return ; + }, render: function () { - var messages = this.state.log.map(function (row) { - if (!this.props.filter[row.level]) { - return null; - } - return ; - }.bind(this)); - return
{messages}
; + var rows = this.renderRows(this.state.log); + + return
+            { this.getPlaceholderTop() }
+            {rows}
+            { this.getPlaceholderBottom(this.state.log.length) }
+        
; } }); @@ -101,7 +120,7 @@ var EventLog = React.createClass({ return (
- Eventlog + Eventlog
diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index f608f41d..9eeddbaa 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -58,9 +58,6 @@ var FlowTable = React.createClass({ nextProps.view.addListener("add update remove recalculate", this.onChange); } }, - componentDidMount: function () { - this.onScroll2(); - }, getDefaultProps: function () { return { rowHeight: ROW_HEIGHT @@ -80,27 +77,20 @@ var FlowTable = React.createClass({ this.refs.body.getDOMNode().offsetTop ); }, + renderRow: function (flow) { + var selected = (flow === this.props.selected); + return ; + }, render: function () { - var space_top = 0, space_bottom = 0, fix_nth_row = null; - var rows = []; - if (this.props.view) { - var flows = this.props.view.flows; - var max = Math.min(flows.length, this.state.stop); + var flows = this.props.view ? this.props.view.flows : []; - for (var i = this.state.start; i < max; i++) { - var flow = flows[i]; - var selected = (flow === this.props.selected); - rows.push( - - ); - } - } + var rows = this.renderRows(flows); return (
diff --git a/web/src/js/components/virtualscroll.jsx.js b/web/src/js/components/virtualscroll.jsx.js index ec3daa41..ebbf13f3 100644 --- a/web/src/js/components/virtualscroll.jsx.js +++ b/web/src/js/components/virtualscroll.jsx.js @@ -5,35 +5,57 @@ var VirtualScrollMixin = { stop: 0 } }, + componentWillMount: function(){ + if(!this.props.rowHeight){ + console.warn("VirtualScrollMixin: No rowHeight specified", this); + } + }, getPlaceholderTop: function () { + var Tag = this.props.placeholderTagName || "tr"; var style = { height: this.state.start * this.props.rowHeight }; - var spacer = ; + var spacer = ; if (this.state.start % 2 === 1) { // fix even/odd rows - return [spacer, ]; + 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 ; + return ; + }, + componentDidMount: function () { + 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.rowHeight); + var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight)); + this.setState({ start: start, stop: stop }); + console.log(start, 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){ -- cgit v1.2.3 From 096a3af273ccb309820351b466e62382f62a2c36 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 29 Nov 2014 03:25:07 +0100 Subject: web: various improvements --- web/src/js/components/flowdetail.jsx.js | 67 +++++++++++++++++++++++------- web/src/js/components/flowtable.jsx.js | 6 +-- web/src/js/components/mainview.jsx.js | 30 +++++++++---- web/src/js/components/virtualscroll.jsx.js | 3 +- 4 files changed, 78 insertions(+), 28 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js index 74522f57..2bda5b80 100644 --- a/web/src/js/components/flowdetail.jsx.js +++ b/web/src/js/components/flowdetail.jsx.js @@ -47,7 +47,7 @@ var FlowDetailRequest = React.createClass({ var first_line = [ flow.request.method, RequestUtils.pretty_url(flow.request), - "HTTP/" + flow.response.httpversion.join(".") + "HTTP/" + flow.request.httpversion.join(".") ].join(" "); var content = null; if (flow.request.contentLength > 0) { @@ -97,6 +97,20 @@ var FlowDetailResponse = React.createClass({ } }); +var FlowDetailError = React.createClass({ + render: function () { + var flow = this.props.flow; + return ( +
+
+ {flow.error.msg} +
{ formatTimeStamp(flow.error.timestamp) }
+
+
+ ); + } +}); + var TimeStamp = React.createClass({ render: function () { @@ -105,8 +119,7 @@ var TimeStamp = React.createClass({ return ; } - var ts = (new Date(this.props.t * 1000)).toISOString(); - ts = ts.replace("T", " ").replace("Z", ""); + var ts = formatTimeStamp(this.props.t); var delta; if (this.props.deltaTo) { @@ -273,24 +286,31 @@ var FlowDetailConnectionInfo = React.createClass({ } }); -var tabs = { +var allTabs = { request: FlowDetailRequest, response: FlowDetailResponse, + error: FlowDetailError, details: FlowDetailConnectionInfo }; var FlowDetail = React.createClass({ - getDefaultProps: function () { - return { - tabs: ["request", "response", "details"] - }; - }, mixins: [StickyHeadMixin, ReactRouter.Navigation, ReactRouter.State], + 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 currentIndex = this.props.tabs.indexOf(this.props.active); + var tabs = this.getTabs(); + var currentIndex = tabs.indexOf(this.getParams().detailTab); // JS modulo operator doesn't correct negative numbers, make sure that we are positive. - var nextIndex = (currentIndex + i + this.props.tabs.length) % this.props.tabs.length; - this.selectTab(this.props.tabs[nextIndex]); + var nextIndex = (currentIndex + i + tabs.length) % tabs.length; + this.selectTab(tabs[nextIndex]); }, selectTab: function (panel) { this.replaceWith( @@ -302,14 +322,29 @@ var FlowDetail = React.createClass({ ); }, render: function () { - var Tab = tabs[this.props.active]; + var flow = this.props.flow; + var tabs = this.getTabs(flow); + var active = this.getParams().detailTab; + + 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 Tab = allTabs[active]; return (
- +
); } diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index 9eeddbaa..1a4efe89 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -63,12 +63,11 @@ var FlowTable = React.createClass({ rowHeight: ROW_HEIGHT }; }, - onScroll2: function () { + onScrollFlowTable: function () { this.adjustHead(); this.onScroll(); }, onChange: function () { - console.log("onChange"); this.forceUpdate(); }, scrollIntoView: function (flow) { @@ -88,12 +87,13 @@ var FlowTable = React.createClass({ />; }, render: function () { + //console.log("render flowtable", this.state.start, this.state.stop, this.props.selected); var flows = this.props.view ? this.props.view.flows : []; var rows = this.renderRows(flows); return ( -
+
diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index fe5d1c7c..d5066b1a 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -16,6 +16,21 @@ var MainView = React.createClass({ this.setState({ view: view }); + + view.addListener("recalculate", this.onRecalculate); + view.addListener("add update remove", this.onUpdate); + }, + onRecalculate: function(){ + this.forceUpdate(); + var selected = this.getSelected(); + if(selected){ + this.refs.flowTable.scrollIntoView(); + } + }, + onUpdate: function (flow) { + if (flow.id === this.getParams().flowId) { + this.forceUpdate(); + } }, closeView: function () { this.state.view.close(); @@ -103,16 +118,18 @@ var MainView = React.createClass({ } e.preventDefault(); }, + getSelected: function(){ + return this.props.flowStore.get(this.getParams().flowId); + }, render: function () { - var selected = this.props.flowStore.get(this.getParams().flowId); + var selected = this.getSelected(); var details; if (selected) { - details = ( - - ); + details = [ + , + + ]; } else { details = null; } @@ -123,7 +140,6 @@ var MainView = React.createClass({ view={this.state.view} selectFlow={this.selectFlow} selected={selected} /> - { details ? : null } {details} ); diff --git a/web/src/js/components/virtualscroll.jsx.js b/web/src/js/components/virtualscroll.jsx.js index ebbf13f3..5a67bbf5 100644 --- a/web/src/js/components/virtualscroll.jsx.js +++ b/web/src/js/components/virtualscroll.jsx.js @@ -3,7 +3,7 @@ var VirtualScrollMixin = { return { start: 0, stop: 0 - } + }; }, componentWillMount: function(){ if(!this.props.rowHeight){ @@ -45,7 +45,6 @@ var VirtualScrollMixin = { start: start, stop: stop }); - console.log(start, stop); }, renderRows: function(elems){ var rows = []; -- cgit v1.2.3 From 14a8d2f5b83a1ea28abbb490f6c94c43b4e1f960 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Tue, 9 Dec 2014 18:18:14 +0100 Subject: always use the app dispatcher --- web/src/js/components/flowdetail.jsx.js | 2 +- web/src/js/components/mainview.jsx.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js index 2bda5b80..6d46cd2e 100644 --- a/web/src/js/components/flowdetail.jsx.js +++ b/web/src/js/components/flowdetail.jsx.js @@ -306,7 +306,7 @@ var FlowDetail = React.createClass({ return tabs; }, nextTab: function (i) { - var tabs = this.getTabs(); + var tabs = this.getTabs(this.props.flow); var currentIndex = tabs.indexOf(this.getParams().detailTab); // JS modulo operator doesn't correct negative numbers, make sure that we are positive. var nextIndex = (currentIndex + i + tabs.length) % tabs.length; diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index d5066b1a..c7c9ee9b 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -24,7 +24,7 @@ var MainView = React.createClass({ this.forceUpdate(); var selected = this.getSelected(); if(selected){ - this.refs.flowTable.scrollIntoView(); + this.refs.flowTable.scrollIntoView(selected); } }, onUpdate: function (flow) { -- cgit v1.2.3 From e12bf19e35867f3ea69f45054decb024a75fc2b4 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 10 Dec 2014 00:47:05 +0100 Subject: web: add event store, fix all those bugs --- web/src/js/components/eventlog.jsx.js | 35 +++++++++++++++--------------- web/src/js/components/flowtable.jsx.js | 4 ++-- web/src/js/components/mainview.jsx.js | 2 +- web/src/js/components/proxyapp.jsx.js | 2 +- web/src/js/components/virtualscroll.jsx.js | 14 +++++++----- 5 files changed, 30 insertions(+), 27 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/eventlog.jsx.js b/web/src/js/components/eventlog.jsx.js index 708432d0..3bd188ea 100644 --- a/web/src/js/components/eventlog.jsx.js +++ b/web/src/js/components/eventlog.jsx.js @@ -25,32 +25,33 @@ var LogMessage = React.createClass({ var EventLogContents = React.createClass({ mixins: [AutoScrollMixin, VirtualScrollMixin], - getInitialState: function () { + getInitialState: function(){ + var store = new EventLogStore(); + var view = new StoreView(store, function(entry){ + return this.props.filter[entry.level]; + }.bind(this)); + view.addListener("add recalculate", this.onEventLogChange); return { + store: store, + view: view, log: [] }; }, - componentDidMount: function () { - this.log = EventLogStore.getView(); - this.log.addListener("change", this.onEventLogChange); - }, componentWillUnmount: function () { - this.log.removeListener("change", this.onEventLogChange); - this.log.close(); + this.state.view.removeListener("add recalculate", this.onEventLogChange); + this.state.view.close(); + this.state.store.close(); }, onEventLogChange: function () { - var log = this.log.getAll().filter(function (entry) { - return this.props.filter[entry.level]; - }.bind(this)); this.setState({ - log: log + log: this.state.view.list }); }, - componentWillReceiveProps: function () { - if (this.log) { - this.onEventLogChange(); + 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(this.state.store._list); } - }, getDefaultProps: function () { return { @@ -66,7 +67,7 @@ var EventLogContents = React.createClass({ var rows = this.renderRows(this.state.log); return
-            { this.getPlaceholderTop() }
+            { this.getPlaceholderTop(this.state.log.length) }
             {rows}
             { this.getPlaceholderBottom(this.state.log.length) }
         
; @@ -112,7 +113,7 @@ var EventLog = React.createClass({ }); }, toggleLevel: function (level) { - var filter = this.state.filter; + var filter = _.extend({}, this.state.filter); filter[level] = !filter[level]; this.setState({filter: filter}); }, diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index 1a4efe89..4b72dd29 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -88,7 +88,7 @@ var FlowTable = React.createClass({ }, render: function () { //console.log("render flowtable", this.state.start, this.state.stop, this.props.selected); - var flows = this.props.view ? this.props.view.flows : []; + var flows = this.props.view ? this.props.view.list : []; var rows = this.renderRows(flows); @@ -98,7 +98,7 @@ var FlowTable = React.createClass({
- { this.getPlaceholderTop() } + { this.getPlaceholderTop(flows.length) } {rows} { this.getPlaceholderBottom(flows.length) } diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index c7c9ee9b..570962e0 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -12,7 +12,7 @@ var MainView = React.createClass({ } }, openView: function (store) { - var view = new FlowView(store); + var view = new StoreView(store); this.setState({ view: view }); diff --git a/web/src/js/components/proxyapp.jsx.js b/web/src/js/components/proxyapp.jsx.js index 3545cfe0..e03b1a57 100644 --- a/web/src/js/components/proxyapp.jsx.js +++ b/web/src/js/components/proxyapp.jsx.js @@ -10,7 +10,7 @@ var ProxyAppMain = React.createClass({ getInitialState: function () { return { settings: SettingsStore.getAll(), - flowStore: new LiveFlowStore() + flowStore: new FlowStore() }; }, componentDidMount: function () { diff --git a/web/src/js/components/virtualscroll.jsx.js b/web/src/js/components/virtualscroll.jsx.js index 5a67bbf5..b1924949 100644 --- a/web/src/js/components/virtualscroll.jsx.js +++ b/web/src/js/components/virtualscroll.jsx.js @@ -5,15 +5,17 @@ var VirtualScrollMixin = { stop: 0 }; }, - componentWillMount: function(){ - if(!this.props.rowHeight){ + componentWillMount: function () { + if (!this.props.rowHeight) { console.warn("VirtualScrollMixin: No rowHeight specified", this); } }, - getPlaceholderTop: function () { + 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: this.state.start * this.props.rowHeight + height: Math.min(this.state.start, total) * this.props.rowHeight }; var spacer = ; @@ -46,7 +48,7 @@ var VirtualScrollMixin = { stop: stop }); }, - renderRows: function(elems){ + renderRows: function (elems) { var rows = []; var max = Math.min(elems.length, this.state.stop); @@ -56,7 +58,7 @@ var VirtualScrollMixin = { } return rows; }, - scrollRowIntoView: function(index, head_height){ + scrollRowIntoView: function (index, head_height) { var row_top = (index * this.props.rowHeight) + head_height; var row_bottom = row_top + this.props.rowHeight; -- cgit v1.2.3 From d2feaf5d84820e75e3931522d889748563972c75 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 10 Dec 2014 02:48:04 +0100 Subject: web: take viewport resize into account --- web/src/js/components/proxyapp.jsx.js | 14 ++++++++++++-- web/src/js/components/utils.jsx.js | 16 ++++++++++++---- web/src/js/components/virtualscroll.jsx.js | 4 ++++ 3 files changed, 28 insertions(+), 6 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/proxyapp.jsx.js b/web/src/js/components/proxyapp.jsx.js index e03b1a57..e2b32e55 100644 --- a/web/src/js/components/proxyapp.jsx.js +++ b/web/src/js/components/proxyapp.jsx.js @@ -23,12 +23,22 @@ var ProxyAppMain = React.createClass({ this.setState({settings: SettingsStore.getAll()}); }, render: function () { + + var eventlog; + if (this.state.settings.showEventLog) { + eventlog = [ + , + + ]; + } else { + eventlog = null; + } + return (
- {this.state.settings.showEventLog ? : null} - {this.state.settings.showEventLog ? : null} + {eventlog}
); diff --git a/web/src/js/components/utils.jsx.js b/web/src/js/components/utils.jsx.js index 12775adc..81ba6b4d 100644 --- a/web/src/js/components/utils.jsx.js +++ b/web/src/js/components/utils.jsx.js @@ -51,6 +51,7 @@ var Splitter = React.createClass({ this.setState({ applied: true }); + this.onResize(); }, onMouseMove: function (e) { var dX = 0, dY = 0; @@ -61,6 +62,13 @@ var Splitter = React.createClass({ } 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; @@ -77,7 +85,7 @@ var Splitter = React.createClass({ applied: false }); } - + this.onResize(); }, componentWillUnmount: function () { this.reset(true); @@ -104,9 +112,9 @@ function getCookie(name) { var xsrf = $.param({_xsrf: getCookie("_xsrf")}); //Tornado XSRF Protection. -$.ajaxPrefilter(function(options){ - if(options.type === "post" && options.url[0] === "/"){ - if(options.data){ +$.ajaxPrefilter(function (options) { + if (options.type === "post" && options.url[0] === "/") { + if (options.data) { options.data += ("&" + xsrf); } else { options.data = xsrf; diff --git a/web/src/js/components/virtualscroll.jsx.js b/web/src/js/components/virtualscroll.jsx.js index b1924949..4f946cb4 100644 --- a/web/src/js/components/virtualscroll.jsx.js +++ b/web/src/js/components/virtualscroll.jsx.js @@ -35,6 +35,10 @@ var VirtualScrollMixin = { }, componentDidMount: function () { this.onScroll(); + window.addEventListener('resize', this.onScroll); + }, + componentWillUnmount: function(){ + window.removeEventListener('resize', this.onScroll); }, onScroll: function () { var viewport = this.getDOMNode(); -- cgit v1.2.3 From 7e40b8ab09d6d605307342fbfa21129ca15ff055 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 10 Dec 2014 15:25:40 +0100 Subject: web: implement settings store, modularize store --- web/src/js/components/eventlog.jsx.js | 39 ++++++++++++++++++++++------------- web/src/js/components/mainview.jsx.js | 2 +- web/src/js/components/proxyapp.jsx.js | 33 +++++++++++++++++++---------- 3 files changed, 48 insertions(+), 26 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/eventlog.jsx.js b/web/src/js/components/eventlog.jsx.js index 3bd188ea..7ef369f8 100644 --- a/web/src/js/components/eventlog.jsx.js +++ b/web/src/js/components/eventlog.jsx.js @@ -25,22 +25,29 @@ var LogMessage = React.createClass({ var EventLogContents = React.createClass({ mixins: [AutoScrollMixin, VirtualScrollMixin], - getInitialState: function(){ - var store = new EventLogStore(); - var view = new StoreView(store, function(entry){ - return this.props.filter[entry.level]; - }.bind(this)); - view.addListener("add recalculate", this.onEventLogChange); + getInitialState: function () { return { - store: store, - view: view, log: [] }; }, + componentWillMount: function () { + this.openView(this.props.eventStore); + }, componentWillUnmount: function () { - this.state.view.removeListener("add recalculate", this.onEventLogChange); + this.closeView(); + }, + openView: function (store) { + var view = new StoreView(store, function (entry) { + return this.props.filter[entry.level]; + }.bind(this)); + this.setState({ + view: view + }); + + view.addListener("add recalculate", this.onEventLogChange); + }, + closeView: function () { this.state.view.close(); - this.state.store.close(); }, onEventLogChange: function () { this.setState({ @@ -48,9 +55,13 @@ var EventLogContents = React.createClass({ }); }, componentWillReceiveProps: function (nextProps) { - if(nextProps.filter !== this.props.filter){ + if (nextProps.filter !== this.props.filter) { this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update. - this.state.view.recalculate(this.state.store._list); + this.state.view.recalculate(this.props.eventStore.list); + } + if (nextProps.eventStore !== this.props.eventStore) { + this.closeView(); + this.openView(nextProps.eventStore); } }, getDefaultProps: function () { @@ -60,7 +71,7 @@ var EventLogContents = React.createClass({ placeholderTagName: "div" }; }, - renderRow: function(elem){ + renderRow: function (elem) { return ; }, render: function () { @@ -130,7 +141,7 @@ var EventLog = React.createClass({ - + ); } diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index 570962e0..17a024ee 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -56,7 +56,7 @@ var MainView = React.createClass({ } }, selectFlowRelative: function (shift) { - var flows = this.state.view.flows; + var flows = this.state.view.list; var index; if (!this.getParams().flowId) { if (shift > 0) { diff --git a/web/src/js/components/proxyapp.jsx.js b/web/src/js/components/proxyapp.jsx.js index e2b32e55..20162ad1 100644 --- a/web/src/js/components/proxyapp.jsx.js +++ b/web/src/js/components/proxyapp.jsx.js @@ -8,27 +8,38 @@ var Reports = React.createClass({ var ProxyAppMain = React.createClass({ getInitialState: function () { + var eventStore = new EventLogStore(); + var flowStore = new FlowStore(); + var settings = new SettingsStore(); + + // Default Settings before fetch + _.extend(settings.dict,{ + showEventLog: true + }); return { - settings: SettingsStore.getAll(), - flowStore: new FlowStore() + settings: settings, + flowStore: flowStore, + eventStore: eventStore }; }, componentDidMount: function () { - SettingsStore.addListener("change", this.onSettingsChange); + this.state.settings.addListener("recalculate", this.onSettingsChange); }, componentWillUnmount: function () { - SettingsStore.removeListener("change", this.onSettingsChange); + this.state.settings.removeListener("recalculate", this.onSettingsChange); }, - onSettingsChange: function () { - this.setState({settings: SettingsStore.getAll()}); + onSettingsChange: function(){ + this.setState({ + settings: this.state.settings + }); }, render: function () { var eventlog; - if (this.state.settings.showEventLog) { + if (this.state.settings.dict.showEventLog) { eventlog = [ , - + ]; } else { eventlog = null; @@ -36,10 +47,10 @@ var ProxyAppMain = React.createClass({ return (
-
- +
+ {eventlog} -
+
); } -- cgit v1.2.3 From 93e928dec4d1004d4f983ff343569f6966db9675 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 10 Dec 2014 17:44:45 +0100 Subject: web: add file menu stub --- web/src/js/components/header.jsx.js | 92 +++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 9 deletions(-) (limited to 'web/src/js/components') diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js index a3fe4d51..a23afa9b 100644 --- a/web/src/js/components/header.jsx.js +++ b/web/src/js/components/header.jsx.js @@ -8,17 +8,20 @@ var MainMenu = React.createClass({ showEventLog: !this.props.settings.showEventLog }); }, - clearFlows: function(){ + clearFlows: function () { $.post("/flows/clear"); }, render: function () { return (
  + +  Display Event Log + +  
); @@ -47,6 +50,80 @@ var ReportsMenu = React.createClass({ } }); +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(); + console.error("unimplemented: handleNewClick"); + }, + 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, ToolsMenu, ReportsMenu]; @@ -63,9 +140,6 @@ var Header = React.createClass({ this.transitionTo(active.route); this.setState({active: active}); }, - handleFileClick: function () { - console.log("File click"); - }, render: function () { var header = header_entries.map(function (entry, i) { var classes = React.addons.classSet({ @@ -85,10 +159,10 @@ var Header = React.createClass({ return (
- mitmproxy { this.props.settings.version } + mitmproxy { this.props.settings.version }
-- cgit v1.2.3