From 7afac747a8448ac524774a23c12ab23c9d4675f6 Mon Sep 17 00:00:00 2001 From: Maximilian Hils 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