From 9a76e31f2fb77367d6632b6b03cdfeabfadf0caf Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 1 Jun 2016 18:34:12 -0700 Subject: add redux as dependency --- web/package.json | 2 ++ 1 file changed, 2 insertions(+) (limited to 'web') diff --git a/web/package.json b/web/package.json index 2eaac445..02af2666 100644 --- a/web/package.json +++ b/web/package.json @@ -23,7 +23,9 @@ "lodash": "^4.11.2", "react": "^15.0.2", "react-dom": "^15.0.2", + "react-redux": "^4.4.5", "react-router": "^2.4.0", + "redux": "^3.5.2", "shallowequal": "^0.2.2" }, "devDependencies": { -- cgit v1.2.3 From 9e3591e3c225c51d5a5b80eb331719d20d14dc48 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 2 Jun 2016 00:04:10 -0700 Subject: add basic redux architecture, convert eventlog to redux --- web/package.json | 1 + web/src/js/app.js | 16 +++++++++--- web/src/js/components/eventlog.js | 54 ++++++++++++++++++++++++--------------- web/src/js/components/proxyapp.js | 2 +- web/src/js/reducers/eventLog.js | 30 ++++++++++++++++++++++ web/src/js/reducers/index.js | 8 ++++++ web/src/js/reduxActions.js | 13 ++++++++++ 7 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 web/src/js/reducers/eventLog.js create mode 100644 web/src/js/reducers/index.js create mode 100644 web/src/js/reduxActions.js (limited to 'web') diff --git a/web/package.json b/web/package.json index 02af2666..4b58422c 100644 --- a/web/package.json +++ b/web/package.json @@ -30,6 +30,7 @@ }, "devDependencies": { "babel-core": "^6.7.7", + "babel-eslint": "^6.0.4", "babel-jest": "^12.0.2", "babel-plugin-transform-class-properties": "^6.6.0", "babel-preset-es2015": "^6.6.0", diff --git a/web/src/js/app.js b/web/src/js/app.js index e21fa499..30897686 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -1,9 +1,15 @@ import React from "react" -import { render } from 'react-dom' +import {render} from 'react-dom' +import {createStore} from 'redux' +import {Provider} from 'react-redux' +import mitmproxyApp from './reducers' + import $ from "jquery" import Connection from "./connection" -import {app} from "./components/proxyapp.js" -import { EventLogActions } from "./actions.js" +import {App} from "./components/proxyapp.js" +import {EventLogActions} from "./actions.js" + +let store = createStore(mitmproxyApp); $(function () { window.ws = new Connection("/updates"); @@ -12,6 +18,8 @@ $(function () { EventLogActions.add_event(msg); }; - render(app, document.getElementById("mitmproxy")); + render( + {App}, + document.getElementById("mitmproxy")); }); diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index 6e4f9096..687c5265 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -1,11 +1,12 @@ import React from "react" import ReactDOM from "react-dom" +import { connect } from 'react-redux' import shallowEqual from "shallowequal" import {Query} from "../actions.js" +import {toggleEventLogFilter} from "../reduxActions" import AutoScroll from "./helpers/AutoScroll"; import {calcVScroll} from "./helpers/VirtualScroll" import {StoreView} from "../store/view.js" -import _ from "lodash" class EventLogContents extends React.Component { @@ -127,7 +128,7 @@ function ToggleFilter ({ name, active, toggleLevel }) { function onClick(event) { event.preventDefault(); - toggleLevel(name); + toggleLevel(); } return ( @@ -140,42 +141,55 @@ function ToggleFilter ({ name, active, toggleLevel }) { ); } +const mapStateToProps = (state, ownProps) => { + return { + active: state.eventLog.visibilityFilter[ownProps.name] + } +}; + +const mapDispatchToProps = (dispatch, ownProps) => { + return { + toggleLevel: () => { + dispatch(toggleEventLogFilter(ownProps.name)) + } + } +}; + +const ToggleEventLogFilter = connect( + mapStateToProps, + mapDispatchToProps +)(ToggleFilter); + + const AutoScrollEventLog = AutoScroll(EventLogContents); + +const VisibleAutoScrollEventLog = connect( + function mapStateToProps(state, ownProps) { + return {filter: state.eventLog.visibilityFilter} + })(AutoScrollEventLog); + + var EventLog = React.createClass({ - getInitialState() { - return { - filter: { - "debug": false, - "info": true, - "web": true - } - }; - }, close() { var d = {}; d[Query.SHOW_EVENTLOG] = undefined; this.props.updateLocation(undefined, d); }, - toggleLevel(level) { - var filter = _.extend({}, this.state.filter); - filter[level] = !filter[level]; - this.setState({filter: filter}); - }, render() { return (
Eventlog
- - - + + +
- +
); } diff --git a/web/src/js/components/proxyapp.js b/web/src/js/components/proxyapp.js index f47c5bb4..4c790d3d 100644 --- a/web/src/js/components/proxyapp.js +++ b/web/src/js/components/proxyapp.js @@ -145,7 +145,7 @@ var ProxyAppMain = React.createClass({ import { Route, Router as ReactRouter, hashHistory, Redirect} from "react-router"; -export var app = ( +export var App = ( diff --git a/web/src/js/reducers/eventLog.js b/web/src/js/reducers/eventLog.js new file mode 100644 index 00000000..169cd306 --- /dev/null +++ b/web/src/js/reducers/eventLog.js @@ -0,0 +1,30 @@ +import {combineReducers} from 'redux' +import {TOGGLE_EVENTLOG_FILTER} from "../reduxActions" + +const defaultVisibility = { + "debug": false, + "info": true, + "web": true +}; + +const visibilityFilter = (state = defaultVisibility, action) => { + switch (action.type) { + case TOGGLE_EVENTLOG_FILTER: + return Object.assign({}, state, { + [action.filter]: !state[action.filter] + }); + default: + return state; + } +}; + +const entries = (state = [], action) => { + return state; +}; + +const eventLog = combineReducers({ + visibilityFilter, + entries +}); + +export default eventLog diff --git a/web/src/js/reducers/index.js b/web/src/js/reducers/index.js new file mode 100644 index 00000000..a8b2edbf --- /dev/null +++ b/web/src/js/reducers/index.js @@ -0,0 +1,8 @@ +import {combineReducers} from 'redux'; +import eventLog from './eventlog' + +const mitmproxyApp = combineReducers({ + eventLog +}); + +export default mitmproxyApp diff --git a/web/src/js/reduxActions.js b/web/src/js/reduxActions.js new file mode 100644 index 00000000..c5902f80 --- /dev/null +++ b/web/src/js/reduxActions.js @@ -0,0 +1,13 @@ +export const TOGGLE_EVENTLOG_FILTER = 'TOGGLE_EVENTLOG_FILTER'; +export const HIDE_EVENTLOG = 'HIDE_EVENTLOG'; +export const SHOW_EVENTLOG = 'SHOW_EVENTLOG'; + +export const EventLogFilters = { + DEBUG: 'debug', + INFO: 'info', + WEB: 'web' +}; + +export function toggleEventLogFilter(filter) { + return {type: TOGGLE_EVENTLOG_FILTER, filter} +} -- cgit v1.2.3 From 7a388560d7d3ef22be0bdef1811414ad18ff2484 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 2 Jun 2016 09:51:39 -0700 Subject: use object spread operator While the spread operator is not part of ES6, React also uses it for JSX. It makes sense for us to keep it in other parts of the codebase as well. --- web/.babelrc | 2 +- web/src/js/reducers/eventLog.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'web') diff --git a/web/.babelrc b/web/.babelrc index 5dd7708c..e2d67e33 100644 --- a/web/.babelrc +++ b/web/.babelrc @@ -1,4 +1,4 @@ { "presets": ["es2015", "react"], - "plugins": ["transform-class-properties"] + "plugins": ["transform-class-properties", "transform-object-rest-spread"] } \ No newline at end of file diff --git a/web/src/js/reducers/eventLog.js b/web/src/js/reducers/eventLog.js index 169cd306..9d078c14 100644 --- a/web/src/js/reducers/eventLog.js +++ b/web/src/js/reducers/eventLog.js @@ -10,9 +10,10 @@ const defaultVisibility = { const visibilityFilter = (state = defaultVisibility, action) => { switch (action.type) { case TOGGLE_EVENTLOG_FILTER: - return Object.assign({}, state, { + return { + ...state, [action.filter]: !state[action.filter] - }); + }; default: return state; } -- cgit v1.2.3 From 698d38b28e43ce0685ce8ce8c119926af2083cbc Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 2 Jun 2016 17:46:18 -0700 Subject: web: :hatching_chick: --- web/src/css/eventlog.less | 8 +++ web/src/css/header.less | 17 ----- web/src/js/app.js | 4 +- web/src/js/components/common.js | 17 +++-- web/src/js/components/eventlog.js | 146 +++++++++++++++----------------------- web/src/js/components/header.js | 19 +---- web/src/js/components/proxyapp.js | 15 ++-- web/src/js/ducks/README.md | 1 + web/src/js/ducks/eventLog.js | 39 ++++++++++ web/src/js/ducks/index.js | 8 +++ web/src/js/reducers/eventLog.js | 31 -------- web/src/js/reduxActions.js | 13 ---- 12 files changed, 138 insertions(+), 180 deletions(-) create mode 100644 web/src/js/ducks/README.md create mode 100644 web/src/js/ducks/eventLog.js create mode 100644 web/src/js/ducks/index.js delete mode 100644 web/src/js/reducers/eventLog.js delete mode 100644 web/src/js/reduxActions.js (limited to 'web') diff --git a/web/src/css/eventlog.less b/web/src/css/eventlog.less index 26dea3cc..908312cd 100644 --- a/web/src/css/eventlog.less +++ b/web/src/css/eventlog.less @@ -33,6 +33,14 @@ } } + .btn-toggle { + margin-top: -2px; + margin-left: 3px; + padding: 2px 2px; + font-size: 10px; + line-height: 10px; + border-radius: 2px; + } .label { cursor: pointer; vertical-align: middle; diff --git a/web/src/css/header.less b/web/src/css/header.less index b1bd9c04..4813b933 100644 --- a/web/src/css/header.less +++ b/web/src/css/header.less @@ -32,20 +32,3 @@ header { overflow-y: auto; } } - -.menu .toggle-btn { - .make-xs-column(4, @menu-row-gutter-width); - .make-sm-column(3, @menu-row-gutter-width); - .make-lg-column(2, @menu-row-gutter-width); - margin-bottom:5px; -} - -.menu .toggle-btn .btn { - width: 100%; -} - -.menu .toggle-input-btn { - .make-sm-column(6, @menu-row-gutter-width); - .make-lg-column(4, @menu-row-gutter-width); - margin-bottom:5px; -} \ No newline at end of file diff --git a/web/src/js/app.js b/web/src/js/app.js index 30897686..5b5d1fc8 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -2,14 +2,14 @@ import React from "react" import {render} from 'react-dom' import {createStore} from 'redux' import {Provider} from 'react-redux' -import mitmproxyApp from './reducers' import $ from "jquery" import Connection from "./connection" import {App} from "./components/proxyapp.js" import {EventLogActions} from "./actions.js" +import rootReducer from './ducks/index'; -let store = createStore(mitmproxyApp); +let store = createStore(rootReducer); $(function () { window.ws = new Connection("/updates"); diff --git a/web/src/js/components/common.js b/web/src/js/components/common.js index 87c34ffc..3496f1de 100644 --- a/web/src/js/components/common.js +++ b/web/src/js/components/common.js @@ -108,18 +108,17 @@ export var Splitter = React.createClass({ } }); -export const ToggleButton = (props) => -
-
-  {props.name} -
+export const ToggleButton = ({checked, onToggle, text}) => +
+ +   + {text}
; ToggleButton.propTypes = { - name: React.PropTypes.string.isRequired, - onToggleChanged: React.PropTypes.func.isRequired + checked: React.PropTypes.bool.isRequired, + onToggle: React.PropTypes.func.isRequired, + text: React.PropTypes.string.isRequired }; export class ToggleInputButton extends React.Component { diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index 687c5265..a2e6a0c1 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -1,12 +1,12 @@ import React from "react" import ReactDOM from "react-dom" -import { connect } from 'react-redux' +import {connect} from 'react-redux' import shallowEqual from "shallowequal" -import {Query} from "../actions.js" -import {toggleEventLogFilter} from "../reduxActions" +import {toggleEventLogFilter, toggleEventLogVisibility} from "../ducks/eventLog" import AutoScroll from "./helpers/AutoScroll"; import {calcVScroll} from "./helpers/VirtualScroll" import {StoreView} from "../store/view.js" +import {ToggleButton} from "./common"; class EventLogContents extends React.Component { @@ -27,7 +27,7 @@ class EventLogContents extends React.Component { ); this.heights = {}; - this.state = { entries: this.view.list, vScroll: calcVScroll() }; + this.state = {entries: this.view.list, vScroll: calcVScroll()}; this.onChange = this.onChange.bind(this); this.onViewportUpdate = this.onViewportUpdate.bind(this); @@ -71,12 +71,12 @@ class EventLogContents extends React.Component { }); if (!shallowEqual(this.state.vScroll, vScroll)) { - this.setState({ vScroll }); + this.setState({vScroll}); } } onChange() { - this.setState({ entries: this.view.list }); + this.setState({entries: this.view.list}); } setHeight(id, ref) { @@ -90,7 +90,7 @@ class EventLogContents extends React.Component { } getIcon(level) { - return { web: "html5", debug: "bug" }[level] || "info"; + return {web: "html5", debug: "bug"}[level] || "info"; } render() { @@ -112,87 +112,59 @@ class EventLogContents extends React.Component { } } -ToggleFilter.propTypes = { - name: React.PropTypes.string.isRequired, - toggleLevel: React.PropTypes.func.isRequired, - active: React.PropTypes.bool, -}; - -function ToggleFilter ({ name, active, toggleLevel }) { - let className = "label "; - if (active) { - className += "label-primary"; - } else { - className += "label-default"; - } - - function onClick(event) { - event.preventDefault(); - toggleLevel(); - } - - return ( - - {name} - - ); -} - -const mapStateToProps = (state, ownProps) => { - return { - active: state.eventLog.visibilityFilter[ownProps.name] - } -}; +EventLogContents = AutoScroll(EventLogContents); + + +const EventLogContentsContainer = connect( + state => ({ + filter: state.eventLog.filter + }) +)(EventLogContents); + + +export const ToggleEventLog = connect( + state => ({ + checked: state.eventLog.visible + }), + dispatch => ({ + onToggle: () => dispatch(toggleEventLogVisibility()) + }) +)(ToggleButton); + + +const ToggleFilter = connect( + (state, ownProps) => ({ + checked: state.eventLog.filter[ownProps.text] + }), + (dispatch, ownProps) => ({ + onToggle: () => dispatch(toggleEventLogFilter(ownProps.text)) + }) +)(ToggleButton); + + +const EventLog = ({close}) => +
+
+ Eventlog +
+ + + + +
+
+ +
; -const mapDispatchToProps = (dispatch, ownProps) => { - return { - toggleLevel: () => { - dispatch(toggleEventLogFilter(ownProps.name)) - } - } +EventLog.propTypes = { + close: React.PropTypes.func.isRequired }; -const ToggleEventLogFilter = connect( - mapStateToProps, - mapDispatchToProps -)(ToggleFilter); - - -const AutoScrollEventLog = AutoScroll(EventLogContents); - - -const VisibleAutoScrollEventLog = connect( - function mapStateToProps(state, ownProps) { - return {filter: state.eventLog.visibilityFilter} - })(AutoScrollEventLog); - - -var EventLog = React.createClass({ - close() { - var d = {}; - d[Query.SHOW_EVENTLOG] = undefined; - this.props.updateLocation(undefined, d); - }, - render() { - return ( -
-
- Eventlog -
- - - - -
- -
- -
- ); - } -}); +const EventLogContainer = connect( + undefined, + dispatch => ({ + close: () => dispatch(toggleEventLogVisibility()) + }) +)(EventLog); -export default EventLog; +export default EventLogContainer; diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js index 643659c3..76c4744a 100644 --- a/web/src/js/components/header.js +++ b/web/src/js/components/header.js @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from 'react-dom'; import $ from "jquery"; +import {connect} from 'react-redux' import Filt from "../filt/filt.js"; import {Key} from "../utils.js"; @@ -8,6 +9,7 @@ import {ToggleInputButton, ToggleButton} from "./common.js"; import {SettingsActions, FlowActions} from "../actions.js"; import {Query} from "../actions.js"; import {SettingsState} from "./common.js"; +import {ToggleEventLog} from "./eventlog" var FilterDocs = React.createClass({ statics: { @@ -224,26 +226,11 @@ var ViewMenu = React.createClass({ title: "View", route: "flows" }, - toggleEventLog: function () { - var d = {}; - if (this.props.query[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.props.updateLocation(undefined, d); - console.log('toggleevent'); - }, render: function () { - var showEventLog = this.props.query[Query.SHOW_EVENTLOG]; return (
- +
diff --git a/web/src/js/components/proxyapp.js b/web/src/js/components/proxyapp.js index 4c790d3d..99b64580 100644 --- a/web/src/js/components/proxyapp.js +++ b/web/src/js/components/proxyapp.js @@ -1,6 +1,8 @@ import React from "react"; import ReactDOM from "react-dom"; import _ from "lodash"; +import {connect} from 'react-redux' +import { Route, Router as ReactRouter, hashHistory, Redirect} from "react-router" import {Splitter} from "./common.js" import MainView from "./mainview.js"; @@ -8,7 +10,6 @@ import Footer from "./footer.js"; import {Header, MainMenu} from "./header.js"; import EventLog from "./eventlog.js" import {EventLogStore, FlowStore, SettingsStore} from "../store/store.js"; -import {Query} from "../actions.js"; import {Key} from "../utils.js"; @@ -120,10 +121,10 @@ var ProxyAppMain = React.createClass({ render: function () { var query = this.getQuery(); var eventlog; - if (this.props.location.query[Query.SHOW_EVENTLOG]) { + if (this.props.showEventLog) { eventlog = [ , - + ]; } else { eventlog = null; @@ -142,13 +143,17 @@ var ProxyAppMain = React.createClass({ } }); +const AppContainer = connect( + state => ({ + showEventLog: state.eventLog.visible + }) +)(ProxyAppMain); -import { Route, Router as ReactRouter, hashHistory, Redirect} from "react-router"; export var App = ( - + diff --git a/web/src/js/ducks/README.md b/web/src/js/ducks/README.md new file mode 100644 index 00000000..9d005f35 --- /dev/null +++ b/web/src/js/ducks/README.md @@ -0,0 +1 @@ +https://github.com/erikras/ducks-modular-redux \ No newline at end of file diff --git a/web/src/js/ducks/eventLog.js b/web/src/js/ducks/eventLog.js new file mode 100644 index 00000000..5bae252a --- /dev/null +++ b/web/src/js/ducks/eventLog.js @@ -0,0 +1,39 @@ +const TOGGLE_FILTER = 'TOGGLE_EVENTLOG_FILTER' +const TOGGLE_VISIBILITY = 'TOGGLE_EVENTLOG_VISIBILITY' + + +const defaultState = { + visible: false, + filter: { + "debug": false, + "info": true, + "web": true + } +} +export default function reducer(state = defaultState, action) { + switch (action.type) { + case TOGGLE_FILTER: + return { + ...state, + filter: { + ...state.filter, + [action.filter]: !state.filter[action.filter] + } + } + case TOGGLE_VISIBILITY: + return { + ...state, + visible: !state.visible + } + default: + return state + } +} + + +export function toggleEventLogFilter(filter) { + return {type: TOGGLE_FILTER, filter} +} +export function toggleEventLogVisibility() { + return {type: TOGGLE_VISIBILITY} +} \ No newline at end of file diff --git a/web/src/js/ducks/index.js b/web/src/js/ducks/index.js new file mode 100644 index 00000000..c82d42bb --- /dev/null +++ b/web/src/js/ducks/index.js @@ -0,0 +1,8 @@ +import {combineReducers} from 'redux' +import eventLog from './eventLog.js'; + +const rootReducer = combineReducers({ + eventLog +}) + +export default rootReducer \ No newline at end of file diff --git a/web/src/js/reducers/eventLog.js b/web/src/js/reducers/eventLog.js deleted file mode 100644 index 9d078c14..00000000 --- a/web/src/js/reducers/eventLog.js +++ /dev/null @@ -1,31 +0,0 @@ -import {combineReducers} from 'redux' -import {TOGGLE_EVENTLOG_FILTER} from "../reduxActions" - -const defaultVisibility = { - "debug": false, - "info": true, - "web": true -}; - -const visibilityFilter = (state = defaultVisibility, action) => { - switch (action.type) { - case TOGGLE_EVENTLOG_FILTER: - return { - ...state, - [action.filter]: !state[action.filter] - }; - default: - return state; - } -}; - -const entries = (state = [], action) => { - return state; -}; - -const eventLog = combineReducers({ - visibilityFilter, - entries -}); - -export default eventLog diff --git a/web/src/js/reduxActions.js b/web/src/js/reduxActions.js deleted file mode 100644 index c5902f80..00000000 --- a/web/src/js/reduxActions.js +++ /dev/null @@ -1,13 +0,0 @@ -export const TOGGLE_EVENTLOG_FILTER = 'TOGGLE_EVENTLOG_FILTER'; -export const HIDE_EVENTLOG = 'HIDE_EVENTLOG'; -export const SHOW_EVENTLOG = 'SHOW_EVENTLOG'; - -export const EventLogFilters = { - DEBUG: 'debug', - INFO: 'info', - WEB: 'web' -}; - -export function toggleEventLogFilter(filter) { - return {type: TOGGLE_EVENTLOG_FILTER, filter} -} -- cgit v1.2.3 From 6a91ab166f4479eb50846fed184aa197dd018bfe Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 2 Jun 2016 19:29:03 -0700 Subject: remove reducers directory --- web/src/js/reducers/index.js | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 web/src/js/reducers/index.js (limited to 'web') diff --git a/web/src/js/reducers/index.js b/web/src/js/reducers/index.js deleted file mode 100644 index a8b2edbf..00000000 --- a/web/src/js/reducers/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import {combineReducers} from 'redux'; -import eventLog from './eventlog' - -const mitmproxyApp = combineReducers({ - eventLog -}); - -export default mitmproxyApp -- cgit v1.2.3 From 7c63aa3708a09b997575cb85cb6dfaaa41082fab Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 2 Jun 2016 21:12:59 -0700 Subject: web: reduxify WebSocket --- web/src/js/app.js | 10 +++++----- web/src/js/components/header.js | 24 ++++++++++++------------ web/src/js/connection.js | 16 +++++++++------- web/src/js/ducks/flows.js | 15 +++++++++++++++ web/src/js/ducks/index.js | 8 ++++++-- web/src/js/ducks/websocket.js | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 web/src/js/ducks/flows.js create mode 100644 web/src/js/ducks/websocket.js (limited to 'web') diff --git a/web/src/js/app.js b/web/src/js/app.js index 5b5d1fc8..f631b2c5 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -3,7 +3,6 @@ import {render} from 'react-dom' import {createStore} from 'redux' import {Provider} from 'react-redux' -import $ from "jquery" import Connection from "./connection" import {App} from "./components/proxyapp.js" import {EventLogActions} from "./actions.js" @@ -11,8 +10,8 @@ import rootReducer from './ducks/index'; let store = createStore(rootReducer); -$(function () { - window.ws = new Connection("/updates"); +document.addEventListener('DOMContentLoaded', () => { + window.ws = new Connection("/updates", store.dispatch); window.onerror = function (msg) { EventLogActions.add_event(msg); @@ -20,6 +19,7 @@ $(function () { render( {App}, - document.getElementById("mitmproxy")); -}); + document.getElementById("mitmproxy") + ); +}); diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js index 76c4744a..e329b3f5 100644 --- a/web/src/js/components/header.js +++ b/web/src/js/components/header.js @@ -243,29 +243,29 @@ export const OptionMenu = (props) => { return (
- SettingsActions.update({showhost: !showhost})} + onToggle={() => SettingsActions.update({showhost: !showhost})} /> - SettingsActions.update({no_upstream_cert: !no_upstream_cert})} + onToggle={() => SettingsActions.update({no_upstream_cert: !no_upstream_cert})} /> - SettingsActions.update({rawtcp: !rawtcp})} + onToggle={() => SettingsActions.update({rawtcp: !rawtcp})} /> - SettingsActions.update({http2: !http2})} + onToggle={() => SettingsActions.update({http2: !http2})} /> - SettingsActions.update({anticache: !anticache})} + onToggle={() => SettingsActions.update({anticache: !anticache})} /> - SettingsActions.update({anticomp: !anticomp})} + onToggle={() => SettingsActions.update({anticomp: !anticomp})} /> Date: Thu, 2 Jun 2016 23:40:30 -0700 Subject: web: reduxify event log store --- web/package.json | 1 + web/src/js/app.js | 17 ++++++---- web/src/js/components/eventlog.js | 69 ++++++++++++++------------------------- web/src/js/connection.js | 4 +-- web/src/js/ducks/eventLog.js | 32 +++++++++++++++--- web/src/js/ducks/flows.js | 15 --------- web/src/js/ducks/index.js | 2 -- web/src/js/ducks/list.js | 21 ++++++++++++ web/src/js/ducks/websocket.js | 4 --- 9 files changed, 85 insertions(+), 80 deletions(-) delete mode 100644 web/src/js/ducks/flows.js create mode 100644 web/src/js/ducks/list.js (limited to 'web') diff --git a/web/package.json b/web/package.json index 4b58422c..b7f6ab2a 100644 --- a/web/package.json +++ b/web/package.json @@ -26,6 +26,7 @@ "react-redux": "^4.4.5", "react-router": "^2.4.0", "redux": "^3.5.2", + "redux-logger": "^2.6.1", "shallowequal": "^0.2.2" }, "devDependencies": { diff --git a/web/src/js/app.js b/web/src/js/app.js index f631b2c5..fc99f1d2 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -1,22 +1,25 @@ import React from "react" import {render} from 'react-dom' -import {createStore} from 'redux' +import {applyMiddleware, createStore} from 'redux' import {Provider} from 'react-redux' +import createLogger from 'redux-logger'; import Connection from "./connection" import {App} from "./components/proxyapp.js" -import {EventLogActions} from "./actions.js" import rootReducer from './ducks/index'; +import {addLogEntry} from "./ducks/eventLog"; -let store = createStore(rootReducer); +// logger must be last +const logger = createLogger(); +const store = createStore(rootReducer, applyMiddleware(logger)); + +window.onerror = function (msg) { + store.dispatch(addLogEntry(msg)); +}; document.addEventListener('DOMContentLoaded', () => { window.ws = new Connection("/updates", store.dispatch); - window.onerror = function (msg) { - EventLogActions.add_event(msg); - }; - render( {App}, document.getElementById("mitmproxy") diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index a2e6a0c1..0857056c 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -5,69 +5,57 @@ import shallowEqual from "shallowequal" import {toggleEventLogFilter, toggleEventLogVisibility} from "../ducks/eventLog" import AutoScroll from "./helpers/AutoScroll"; import {calcVScroll} from "./helpers/VirtualScroll" -import {StoreView} from "../store/view.js" import {ToggleButton} from "./common"; -class EventLogContents extends React.Component { +function LogIcon({entry}) { + let icon = {web: "html5", debug: "bug"}[entry.level] || "info"; + return +} - static contextTypes = { - eventStore: React.PropTypes.object.isRequired, - }; +function LogEntry({entry}) { + return
+ + {entry.message} +
; +} + +class EventLogContents extends React.Component { static defaultProps = { rowHeight: 18, }; - constructor(props, context) { - super(props, context); - - this.view = new StoreView( - this.context.eventStore, - entry => this.props.filter[entry.level] - ); + constructor(props) { + super(props); this.heights = {}; - this.state = {entries: this.view.list, vScroll: calcVScroll()}; + this.state = {vScroll: calcVScroll()}; - this.onChange = this.onChange.bind(this); this.onViewportUpdate = this.onViewportUpdate.bind(this); } componentDidMount() { window.addEventListener("resize", this.onViewportUpdate); - this.view.addListener("add", this.onChange); - this.view.addListener("recalculate", this.onChange); this.onViewportUpdate(); } componentWillUnmount() { window.removeEventListener("resize", this.onViewportUpdate); - this.view.removeListener("add", this.onChange); - this.view.removeListener("recalculate", this.onChange); - this.view.close(); } componentDidUpdate() { this.onViewportUpdate(); } - componentWillReceiveProps(nextProps) { - if (nextProps.filter !== this.props.filter) { - this.view.recalculate( - entry => nextProps.filter[entry.level] - ); - } - } - onViewportUpdate() { const viewport = ReactDOM.findDOMNode(this); const vScroll = calcVScroll({ - itemCount: this.state.entries.length, + itemCount: this.props.events.length, rowHeight: this.props.rowHeight, viewportTop: viewport.scrollTop, viewportHeight: viewport.offsetHeight, - itemHeights: this.state.entries.map(entry => this.heights[entry.id]), + itemHeights: this.props.events.map(entry => this.heights[entry.id]), }); if (!shallowEqual(this.state.vScroll, vScroll)) { @@ -75,10 +63,6 @@ class EventLogContents extends React.Component { } } - onChange() { - this.setState({entries: this.view.list}); - } - setHeight(id, ref) { if (ref && !this.heights[id]) { const height = ReactDOM.findDOMNode(ref).offsetHeight; @@ -89,23 +73,18 @@ class EventLogContents extends React.Component { } } - getIcon(level) { - return {web: "html5", debug: "bug"}[level] || "info"; - } - render() { const vScroll = this.state.vScroll; - const entries = this.state.entries.slice(vScroll.start, vScroll.end); + const events = this.props.events + .slice(vScroll.start, vScroll.end) + .map(entry => + + ); return (
                 
- {entries.map((entry, index) => ( -
- - {entry.message} -
- ))} + {events}
); @@ -117,7 +96,7 @@ EventLogContents = AutoScroll(EventLogContents); const EventLogContentsContainer = connect( state => ({ - filter: state.eventLog.filter + events: state.eventLog.filteredEvents }) )(EventLogContents); diff --git a/web/src/js/connection.js b/web/src/js/connection.js index 71d20f46..75c2cf25 100644 --- a/web/src/js/connection.js +++ b/web/src/js/connection.js @@ -1,4 +1,3 @@ - import {ConnectionActions, EventLogActions} from "./actions.js"; import {AppDispatcher} from "./dispatcher.js"; import * as websocketActions from "./ducks/websocket" @@ -12,11 +11,12 @@ export default function Connection(url, dispatch) { ws.onopen = function () { dispatch(websocketActions.connected()); ConnectionActions.open(); + //TODO: fetch stuff! }; ws.onmessage = function (m) { var message = JSON.parse(m.data); AppDispatcher.dispatchServerAction(message); - dispatch(websocketActions.receiveMessage(message)); + dispatch(message); }; ws.onerror = function () { ConnectionActions.error(); diff --git a/web/src/js/ducks/eventLog.js b/web/src/js/ducks/eventLog.js index 5bae252a..2040711c 100644 --- a/web/src/js/ducks/eventLog.js +++ b/web/src/js/ducks/eventLog.js @@ -1,5 +1,7 @@ +import getList, {ADD} from "./list" const TOGGLE_FILTER = 'TOGGLE_EVENTLOG_FILTER' const TOGGLE_VISIBILITY = 'TOGGLE_EVENTLOG_VISIBILITY' +const UPDATE_LIST = "UPDATE_EVENTLOG" const defaultState = { @@ -8,23 +10,35 @@ const defaultState = { "debug": false, "info": true, "web": true - } + }, + events: getList(), + filteredEvents: [], } + export default function reducer(state = defaultState, action) { switch (action.type) { case TOGGLE_FILTER: + const filter = { + ...state.filter, + [action.filter]: !state.filter[action.filter] + } return { ...state, - filter: { - ...state.filter, - [action.filter]: !state.filter[action.filter] - } + filter, + filteredEvents: state.events.list.filter(x => filter[x.level]) } case TOGGLE_VISIBILITY: return { ...state, visible: !state.visible } + case UPDATE_LIST: + const events = getList(state.events, action) + return { + ...state, + events, + filteredEvents: events.list.filter(x => state.filter[x.level]) + } default: return state } @@ -36,4 +50,12 @@ export function toggleEventLogFilter(filter) { } export function toggleEventLogVisibility() { return {type: TOGGLE_VISIBILITY} +} +let id = 0; +export function addLogEntry(message, level = "web") { + return { + type: UPDATE_LIST, + cmd: ADD, + data: {message, level, id: `log-${id++}`} + } } \ No newline at end of file diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js deleted file mode 100644 index c4077f7a..00000000 --- a/web/src/js/ducks/flows.js +++ /dev/null @@ -1,15 +0,0 @@ -const defaultState = { - list: [], - isFetching: false, - updateBeforeFetch: [], - byId: {}, - indexOf: {}, - views: {} -} - -export default function reducer(state = defaultState, action) { - switch (action.type) { - default: - return state - } -} diff --git a/web/src/js/ducks/index.js b/web/src/js/ducks/index.js index 0074bda4..3043344c 100644 --- a/web/src/js/ducks/index.js +++ b/web/src/js/ducks/index.js @@ -1,11 +1,9 @@ import {combineReducers} from 'redux' import eventLog from './eventLog.js' import websocket from './websocket.js' -import flows from './flows.js' const rootReducer = combineReducers({ eventLog, - flows, websocket, }) diff --git a/web/src/js/ducks/list.js b/web/src/js/ducks/list.js new file mode 100644 index 00000000..0b3771e2 --- /dev/null +++ b/web/src/js/ducks/list.js @@ -0,0 +1,21 @@ +export const ADD = 'add' + +const defaultState = { + list: [], + //isFetching: false, + //updateBeforeFetch: [], + indexOf: {}, + //views: {} +}; + +export default function getList(state = defaultState, action = {}) { + switch (action.cmd) { + case ADD: + return { + list: [...state.list, action.data], + indexOf: {...state.indexOf, [action.data.id]: state.list.length}, + } + default: + return state + } +} \ No newline at end of file diff --git a/web/src/js/ducks/websocket.js b/web/src/js/ducks/websocket.js index 281d1f2c..3999dbcf 100644 --- a/web/src/js/ducks/websocket.js +++ b/web/src/js/ducks/websocket.js @@ -1,6 +1,5 @@ const CONNECTED = 'WEBSOCKET_CONNECTED' const DISCONNECTED = 'WEBSOCKET_DISCONNECTED' -const RECEIVE_MESSAGE = 'RECEIVE_WEBSOCKET_MESSAGE' const defaultState = { @@ -28,7 +27,4 @@ export function connected() { } export function disconnected() { return {type: DISCONNECTED} -} -export function receiveMessage(message) { - return {type: RECEIVE_MESSAGE, message} } \ No newline at end of file -- cgit v1.2.3 From 5321f15defcef641bf5b7ba39e5c9057d562c5f8 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 2 Jun 2016 23:41:32 -0700 Subject: web: fix eventlog height registration --- web/src/js/components/eventlog.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'web') diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index 0857056c..95889a66 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -7,15 +7,15 @@ import AutoScroll from "./helpers/AutoScroll"; import {calcVScroll} from "./helpers/VirtualScroll" import {ToggleButton} from "./common"; -function LogIcon({entry}) { - let icon = {web: "html5", debug: "bug"}[entry.level] || "info"; +function LogIcon({event}) { + let icon = {web: "html5", debug: "bug"}[event.level] || "info"; return } -function LogEntry({entry}) { - return
- - {entry.message} +function LogEntry({event, registerHeight}) { + return
+ + {event.message}
; } @@ -63,9 +63,10 @@ class EventLogContents extends React.Component { } } - setHeight(id, ref) { - if (ref && !this.heights[id]) { - const height = ReactDOM.findDOMNode(ref).offsetHeight; + setHeight(id, node) { + console.log("setHeight", id, node); + if (node && !this.heights[id]) { + const height = node.offsetHeight; if (this.heights[id] !== height) { this.heights[id] = height; this.onViewportUpdate(); @@ -77,8 +78,12 @@ class EventLogContents extends React.Component { const vScroll = this.state.vScroll; const events = this.props.events .slice(vScroll.start, vScroll.end) - .map(entry => - + .map(event => + this.setHeight(event.id, node)} + /> ); return ( -- cgit v1.2.3