aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/components
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2016-06-04 18:53:41 -0700
committerMaximilian Hils <git@maximilianhils.com>2016-06-04 18:53:41 -0700
commitd53a2de0ba69bea6c7aefa87782ad249cfb4ea76 (patch)
tree25e474bf95e4f83022708e84184d8d7d56a6e3ce /web/src/js/components
parente880f532ad3c66ebfded4655b7fa67a367a83cc7 (diff)
downloadmitmproxy-d53a2de0ba69bea6c7aefa87782ad249cfb4ea76.tar.gz
mitmproxy-d53a2de0ba69bea6c7aefa87782ad249cfb4ea76.tar.bz2
mitmproxy-d53a2de0ba69bea6c7aefa87782ad249cfb4ea76.zip
web: completely move flow state to redux
Diffstat (limited to 'web/src/js/components')
-rw-r--r--web/src/js/components/flowtable.js64
-rw-r--r--web/src/js/components/mainview.js149
-rw-r--r--web/src/js/components/proxyapp.js8
3 files changed, 81 insertions, 140 deletions
diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js
index 1a616eee..0241cd78 100644
--- a/web/src/js/components/flowtable.js
+++ b/web/src/js/components/flowtable.js
@@ -8,12 +8,14 @@ import shallowEqual from "shallowequal";
import AutoScroll from "./helpers/AutoScroll";
import {calcVScroll} from "./helpers/VirtualScroll";
import flowtable_columns from "./flowtable-columns.js";
+import Filt from "../filt/filt";
+
FlowRow.propTypes = {
selectFlow: React.PropTypes.func.isRequired,
columns: React.PropTypes.array.isRequired,
flow: React.PropTypes.object.isRequired,
- highlighted: React.PropTypes.bool,
+ highlight: React.PropTypes.string,
selected: React.PropTypes.bool,
};
@@ -22,7 +24,7 @@ function FlowRow(props) {
const className = classNames({
"selected": props.selected,
- "highlighted": props.highlighted,
+ "highlighted": props.highlight && parseFilter(props.highlight)(flow),
"intercepted": flow.intercepted,
"has-request": flow.request,
"has-response": flow.response,
@@ -39,9 +41,12 @@ function FlowRow(props) {
const FlowRowContainer = connect(
(state, ownProps) => ({
- flow: state.flows.all.byId[ownProps.flowId]
+ flow: state.flows.all.byId[ownProps.flowId],
+ highlight: state.flows.highlight,
+ selected: state.flows.selected.indexOf(ownProps.flowId) >= 0
}),
- dispatch => ({
+ (dispatch, ownProps) => ({
+
})
)(FlowRow);
@@ -102,10 +107,6 @@ class FlowTableHead extends React.Component {
class FlowTable extends React.Component {
- static contextTypes = {
- view: React.PropTypes.object.isRequired,
- };
-
static propTypes = {
rowHeight: React.PropTypes.number,
};
@@ -117,26 +118,23 @@ class FlowTable extends React.Component {
constructor(props, context) {
super(props, context);
- this.state = { flows: [], vScroll: calcVScroll() };
+ this.state = { vScroll: calcVScroll() };
- this.onChange = this.onChange.bind(this);
this.onViewportUpdate = this.onViewportUpdate.bind(this);
}
componentWillMount() {
window.addEventListener("resize", this.onViewportUpdate);
- 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() {
window.removeEventListener("resize", this.onViewportUpdate);
- 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);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if(nextProps.selected && nextProps.selected !== this.props.selected){
+ window.setTimeout(() => this.scrollIntoView(nextProps.selected), 1)
+ }
}
componentDidUpdate() {
@@ -150,7 +148,7 @@ class FlowTable extends React.Component {
const vScroll = calcVScroll({
viewportTop,
viewportHeight: viewport.offsetHeight,
- itemCount: this.state.flows.length,
+ itemCount: this.props.flows.length,
rowHeight: this.props.rowHeight,
});
@@ -160,13 +158,9 @@ class FlowTable extends React.Component {
}
}
- onChange() {
- this.setState({ flows: this.context.view.list });
- }
-
scrollIntoView(flow) {
const viewport = ReactDOM.findDOMNode(this);
- const index = this.context.view.indexOf(flow);
+ const index = this.props.flows.indexOf(flow);
const rowHeight = this.props.rowHeight;
const head = ReactDOM.findDOMNode(this.refs.head);
@@ -188,8 +182,7 @@ class FlowTable extends React.Component {
render() {
const vScroll = this.state.vScroll;
- const highlight = this.context.view._highlight;
- const flows = this.state.flows.slice(vScroll.start, vScroll.end);
+ const flows = this.props.flows.slice(vScroll.start, vScroll.end);
const transform = `translate(0,${this.state.viewportTop}px)`;
@@ -206,11 +199,9 @@ class FlowTable extends React.Component {
<tr style={{ height: vScroll.paddingTop }}></tr>
{flows.map(flow => (
<FlowRowContainer
- flowId={flow.id}
key={flow.id}
+ flowId={flow.id}
columns={flowtable_columns}
- selected={flow === this.props.selected}
- highlighted={highlight && highlight[flow.id]}
selectFlow={this.props.selectFlow}
/>
))}
@@ -222,4 +213,17 @@ class FlowTable extends React.Component {
}
}
-export default AutoScroll(FlowTable);
+FlowTable = AutoScroll(FlowTable)
+
+
+const parseFilter = _.memoize(Filt.parse)
+
+const FlowTableContainer = connect(
+ state => ({
+ flows: state.flows.view,
+ }),
+ dispatch => ({
+ })
+)(FlowTable)
+
+export default FlowTableContainer;
diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js
index 964e82db..22895991 100644
--- a/web/src/js/components/mainview.js
+++ b/web/src/js/components/mainview.js
@@ -3,128 +3,59 @@ import React from "react";
import {FlowActions} from "../actions.js";
import {Query} from "../actions.js";
import {Key} from "../utils.js";
-import {StoreView} from "../store/view.js";
-import Filt from "../filt/filt.js";
import {Splitter} from "./common.js"
import FlowTable from "./flowtable.js";
import FlowView from "./flowview/index.js";
+import {connect} from 'react-redux'
+import {selectFlow, setFilter, setHighlight} from "../ducks/flows";
-var MainView = React.createClass({
- 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 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 filtStr = this.props.query[Query.SEARCH];
- var filt = filtStr ? Filt.parse(filtStr) : () => true;
- var highlightStr = this.props.query[Query.HIGHLIGHT];
- var highlight = highlightStr ? Filt.parse(highlightStr) : () => false;
- } catch (e) {
- console.error("Error when processing filter: " + e);
- }
- var fun = function filter_and_highlight(flow) {
- if (!this._highlight) {
- this._highlight = {};
- }
- this._highlight[flow.id] = highlight(flow);
- return filt(flow);
- };
- fun.highlightStr = highlightStr;
- fun.filtStr = filtStr;
- return fun;
- },
+var MainView = React.createClass({
componentWillReceiveProps: function (nextProps) {
- var filterChanged = this.state.view.filt.filtStr !== nextProps.location.query[Query.SEARCH];
- var highlightChanged = this.state.view.filt.highlightStr !== nextProps.location.query[Query.HIGHLIGHT];
- if (filterChanged || highlightChanged) {
- this.state.view.recalculate(this.getViewFilt(), this.state.sortKeyFun);
+ // Update redux store with route changes
+ if(nextProps.routeParams.flowId !== (nextProps.selectedFlow || {}).id) {
+ this.props.selectFlow(nextProps.routeParams.flowId)
}
- },
- onRecalculate: function () {
- this.forceUpdate();
- var selected = this.getSelected();
- if (selected) {
- this.refs.flowTable.scrollIntoView(selected);
+ if(nextProps.location.query[Query.SEARCH] !== nextProps.filter) {
+ this.props.setFilter(nextProps.location.query[Query.SEARCH], false)
}
- },
- onUpdate: function (flow) {
- if (flow.id === this.props.routeParams.flowId) {
- this.forceUpdate();
- }
- },
- onRemove: function (flow_id, index) {
- if (flow_id === this.props.routeParams.flowId) {
- var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length - 1)];
- this.selectFlow(flow_to_select);
+ if (nextProps.location.query[Query.HIGHLIGHT] !== nextProps.highlight) {
+ this.props.setHighlight(nextProps.location.query[Query.HIGHLIGHT], false)
}
},
setSortKeyFun: function (sortKeyFun) {
- this.setState({
- sortKeyFun: sortKeyFun
- });
- this.state.view.recalculate(this.getViewFilt(), sortKeyFun);
+ // FIXME: Move to redux. This requires that sortKeyFun is not a function anymore.
},
selectFlow: function (flow) {
+ // TODO: This belongs into redux
if (flow) {
- var tab = this.props.routeParams.detailTab || "request";
+ let tab = this.props.routeParams.detailTab || "request";
this.props.updateLocation(`/flows/${flow.id}/${tab}`);
- this.refs.flowTable.scrollIntoView(flow);
} else {
this.props.updateLocation("/flows");
}
},
selectFlowRelative: function (shift) {
- var flows = this.state.view.list;
- var index;
+ // TODO: This belongs into redux
+ let flows = this.props.flows,
+ index
if (!this.props.routeParams.flowId) {
if (shift < 0) {
- index = flows.length - 1;
+ index = flows.length - 1
} else {
- index = 0;
+ index = 0
}
} else {
- var currFlowId = this.props.routeParams.flowId;
- var i = flows.length;
- while (i--) {
- if (flows[i].id === currFlowId) {
- index = i;
- break;
- }
- }
+ index = flows.indexOf(this.props.selectedFlow)
index = Math.min(
Math.max(0, index + shift),
- flows.length - 1);
+ flows.length - 1
+ )
}
- this.selectFlow(flows[index]);
+ this.selectFlow(flows[index])
},
onMainKeyDown: function (e) {
- var flow = this.getSelected();
+ var flow = this.props.selectedFlow;
if (e.ctrlKey) {
return;
}
@@ -210,14 +141,10 @@ var MainView = React.createClass({
}
e.preventDefault();
},
- getSelected: function () {
- return this.context.flowStore.get(this.props.routeParams.flowId);
- },
render: function () {
- var selected = this.getSelected();
- var details;
- if (selected) {
+ var details = null;
+ if (this.props.selectedFlow) {
details = [
<Splitter key="splitter"/>,
<FlowView
@@ -226,10 +153,8 @@ var MainView = React.createClass({
tab={this.props.routeParams.detailTab}
query={this.props.query}
updateLocation={this.props.updateLocation}
- flow={selected}/>
- ];
- } else {
- details = null;
+ flow={this.props.selectedFlow}/>
+ ]
}
return (
@@ -237,11 +162,27 @@ var MainView = React.createClass({
<FlowTable ref="flowTable"
selectFlow={this.selectFlow}
setSortKeyFun={this.setSortKeyFun}
- selected={selected} />
+ selected={this.props.selectedFlow} />
{details}
</div>
);
}
});
-export default MainView;
+const MainViewContainer = connect(
+ state => ({
+ flows: state.flows.view,
+ filter: state.flows.filter,
+ highlight: state.flows.highlight,
+ selectedFlow: state.flows.all.byId[state.flows.selected[0]]
+ }),
+ dispatch => ({
+ selectFlow: flowId => dispatch(selectFlow(flowId)),
+ setFilter: filter => dispatch(setFilter(filter)),
+ setHighlight: highlight => dispatch(setHighlight(highlight))
+ }),
+ undefined,
+ {withRef: true}
+)(MainView);
+
+export default MainViewContainer;
diff --git a/web/src/js/components/proxyapp.js b/web/src/js/components/proxyapp.js
index 9e4bd0a4..e4489e18 100644
--- a/web/src/js/components/proxyapp.js
+++ b/web/src/js/components/proxyapp.js
@@ -9,7 +9,7 @@ import MainView from "./mainview.js";
import Footer from "./footer.js";
import {Header, MainMenu} from "./header.js";
import EventLog from "./eventlog.js"
-import {FlowStore, SettingsStore} from "../store/store.js";
+import {SettingsStore} from "../store/store.js";
import {Key} from "../utils.js";
@@ -23,7 +23,6 @@ var Reports = React.createClass({
var ProxyAppMain = React.createClass({
childContextTypes: {
- flowStore: React.PropTypes.object.isRequired,
returnFocus: React.PropTypes.func.isRequired,
location: React.PropTypes.object.isRequired,
},
@@ -61,13 +60,11 @@ var ProxyAppMain = React.createClass({
},
getChildContext: function () {
return {
- flowStore: this.state.flowStore,
returnFocus: this.focus,
location: this.props.location
};
},
getInitialState: function () {
- var flowStore = new FlowStore();
var settingsStore = new SettingsStore();
this.settingsStore = settingsStore;
@@ -75,7 +72,6 @@ var ProxyAppMain = React.createClass({
_.extend(settingsStore.dict, {});
return {
settings: settingsStore.dict,
- flowStore: flowStore,
};
},
focus: function () {
@@ -84,7 +80,7 @@ var ProxyAppMain = React.createClass({
ReactDOM.findDOMNode(this).focus();
},
getMainComponent: function () {
- return this.refs.view;
+ return this.refs.view.getWrappedInstance ? this.refs.view.getWrappedInstance() : this.refs.view;
},
onKeydown: function (e) {