connect eventlog events to ui

This commit is contained in:
Maximilian Hils 2014-09-17 15:22:42 +02:00
parent b4ecd96beb
commit 8245dd19f4
15 changed files with 89 additions and 103 deletions

View File

@ -220,7 +220,6 @@ def mitmweb(): # pragma: nocover
from . import web
check_versions()
assert_utf8_env()
web_options, proxy_config = mitmweb_cmdline()
server = get_server(web_options.no_server, proxy_config)

View File

@ -101,7 +101,7 @@ class WebMaster(flow.FlowMaster):
def handle_log(self, l):
app.ClientConnection.broadcast(
"event", {
"add_event", {
"message": l.msg,
"level": l.level
}

View File

@ -69,22 +69,11 @@ header .menu {
}
.eventlog {
flex: 0 0 auto;
}
.eventlog pre {
margin: 0;
border-radius: 0;
height: 200px;
overflow: auto;
}
.eventlog .close-button {
float: right;
margin: -9px;
padding: 4px;
cursor: pointer;
color: grey;
}
.eventlog .close-button:hover {
color: black;
overflow-y: scroll;
}
footer {
box-shadow: 0 -1px 3px #d3d3d3;

View File

@ -1,6 +1,20 @@
// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
var AutoScrollMixin = {
componentWillUpdate: function () {
var node = this.getDOMNode();
this._shouldScrollBottom = node.scrollTop + node.clientHeight === node.scrollHeight;
},
componentDidUpdate: function () {
if (this._shouldScrollBottom) {
var node = this.getDOMNode();
node.scrollTop = node.scrollHeight;
}
},
};
const PayloadSources = {
VIEW_ACTION: "VIEW_ACTION",
SERVER_ACTION: "SERVER_ACTION"
VIEW: "view",
SERVER: "server"
};
@ -26,17 +40,17 @@ Dispatcher.prototype.dispatch = function (payload) {
AppDispatcher = new Dispatcher();
AppDispatcher.dispatchViewAction = function (action) {
action.actionSource = PayloadSources.VIEW_ACTION;
action.source = PayloadSources.VIEW;
this.dispatch(action);
};
AppDispatcher.dispatchServerAction = function (action) {
action.actionSource = PayloadSources.SERVER_ACTION;
action.source = PayloadSources.SERVER;
this.dispatch(action);
};
var ActionTypes = {
SETTINGS_UPDATE: "SETTINGS_UPDATE",
EVENTLOG_ADD: "EVENTLOG_ADD"
UPDATE_SETTINGS: "update_settings",
ADD_EVENT: "add_event"
};
var SettingsActions = {
@ -46,7 +60,7 @@ var SettingsActions = {
//Facebook Flux: We do an optimistic update on the client already.
AppDispatcher.dispatchViewAction({
actionType: ActionTypes.SETTINGS_UPDATE,
type: ActionTypes.UPDATE_SETTINGS,
settings: settings
});
}
@ -59,8 +73,9 @@ EventEmitter.prototype.emit = function (event) {
if (!(event in this.listeners)) {
return;
}
var args = Array.prototype.slice.call(arguments, 1);
this.listeners[event].forEach(function (listener) {
listener.apply(this, arguments);
listener.apply(this, args);
}.bind(this));
};
EventEmitter.prototype.addListener = function (event, f) {
@ -92,8 +107,8 @@ _.extend(_SettingsStore.prototype, EventEmitter.prototype, {
return this.settings;
},
handle: function (action) {
switch (action.actionType) {
case ActionTypes.SETTINGS_UPDATE:
switch (action.type) {
case ActionTypes.UPDATE_SETTINGS:
this.settings = action.settings;
this.emit("change");
break;
@ -115,19 +130,19 @@ AppDispatcher.register(SettingsStore.handle.bind(SettingsStore));
// See also: components/EventLog.react.js
function EventLogView(store, live) {
EventEmitter.call(this);
this.$EventLogView_store = store;
this._store = store;
this.live = live;
this.log = [];
this.add = this.add.bind(this);
if (live) {
this.$EventLogView_store.addListener("new_entry", this.add);
this._store.addListener(ActionTypes.ADD_EVENT, this.add);
}
}
_.extend(EventLogView.prototype, EventEmitter.prototype, {
close: function () {
this.$EventLogView_store.removeListener("new_entry", this.add);
this._store.removeListener(ActionTypes.ADD_EVENT, this.add);
},
getAll: function () {
return this.log;
@ -154,7 +169,8 @@ function _EventLogStore() {
_.extend(_EventLogStore.prototype, EventEmitter.prototype, {
getView: function (since) {
var view = new EventLogView(this, !since);
return view;
/*
//TODO: Really do bulk retrieval of last messages.
window.setTimeout(function () {
view.add_bulk([
@ -185,11 +201,12 @@ _.extend(_EventLogStore.prototype, EventEmitter.prototype, {
});
}, 1000);
return view;
*/
},
handle: function (action) {
switch (action.actionType) {
case ActionTypes.EVENTLOG_ADD:
this.emit("new_message", action.message);
switch (action.type) {
case ActionTypes.ADD_EVENT:
this.emit(ActionTypes.ADD_EVENT, action.data);
break;
default:
return;
@ -222,14 +239,7 @@ _Connection.prototype.onopen = function (open) {
_Connection.prototype.onmessage = function (message) {
//AppDispatcher.dispatchServerAction(...);
var m = JSON.parse(message.data);
switch (m.type){
case "flow":
console.log("flow", m.data);
break;
case "event":
console.log("event", m.data.message)
break;
}
AppDispatcher.dispatchServerAction(m);
};
_Connection.prototype.onerror = function (error) {
console.log("onerror", this, arguments);
@ -368,6 +378,7 @@ var TrafficTable = React.createClass({displayName: 'TrafficTable',
/** @jsx React.DOM */
var EventLog = React.createClass({displayName: 'EventLog',
mixins:[AutoScrollMixin],
getInitialState: function () {
return {
log: []
@ -392,16 +403,10 @@ var EventLog = React.createClass({displayName: 'EventLog',
});
},
render: function () {
//var messages = this.state.log.map(row => (<div key={row.id}>{row.message}</div>));
var messages = [];
return (
React.DOM.div({className: "eventlog"},
React.DOM.pre(null,
React.DOM.i({className: "fa fa-close close-button", onClick: this.close}),
messages
)
)
);
var messages = this.state.log.map(function(row) {
return (React.DOM.div({key: row.id}, row.message));
});
return React.DOM.pre({className: "eventlog"}, messages);
}
});
@ -447,7 +452,7 @@ var ProxyAppMain = React.createClass({displayName: 'ProxyAppMain',
React.DOM.div({id: "container"},
Header({settings: this.state.settings}),
React.DOM.div({id: "main"}, this.props.activeRouteHandler(null)),
this.state.settings.showEventLog ? EventLog(null) : null,
this.state.settings.showEventLog ? EventLog(null) : null,
Footer({settings: this.state.settings})
)
);

View File

@ -32,6 +32,7 @@ var path = {
'vendor/react-bootstrap/react-bootstrap.js'
],
app: [
'js/utils.js',
'js/dispatcher.js',
'js/actions.js',
'js/stores/base.js',

View File

@ -2,21 +2,9 @@
flex: 0 0 auto;
pre {
margin: 0;
border-radius: 0;
height: 200px;
overflow: auto;
}
.close-button {
float: right;
margin: -9px;
padding: 4px;
cursor: pointer;
color: grey;
&:hover {
color: black;
}
}
margin: 0;
border-radius: 0;
height: 200px;
overflow: auto;
overflow-y: scroll;
}

View File

@ -1,6 +1,6 @@
var ActionTypes = {
SETTINGS_UPDATE: "SETTINGS_UPDATE",
EVENTLOG_ADD: "EVENTLOG_ADD"
UPDATE_SETTINGS: "update_settings",
ADD_EVENT: "add_event"
};
var SettingsActions = {
@ -10,7 +10,7 @@ var SettingsActions = {
//Facebook Flux: We do an optimistic update on the client already.
AppDispatcher.dispatchViewAction({
actionType: ActionTypes.SETTINGS_UPDATE,
type: ActionTypes.UPDATE_SETTINGS,
settings: settings
});
}

View File

@ -1,6 +1,7 @@
/** @jsx React.DOM */
var EventLog = React.createClass({
mixins:[AutoScrollMixin],
getInitialState: function () {
return {
log: []
@ -25,15 +26,9 @@ var EventLog = React.createClass({
});
},
render: function () {
//var messages = this.state.log.map(row => (<div key={row.id}>{row.message}</div>));
var messages = [];
return (
<div className="eventlog">
<pre>
<i className="fa fa-close close-button" onClick={this.close}></i>
{messages}
</pre>
</div>
);
var messages = this.state.log.map(function(row) {
return (<div key={row.id}>{row.message}</div>);
});
return <pre className="eventlog">{messages}</pre>;
}
});

View File

@ -27,7 +27,7 @@ var ProxyAppMain = React.createClass({
<div id="container">
<Header settings={this.state.settings}/>
<div id="main"><this.props.activeRouteHandler/></div>
{this.state.settings.showEventLog ? <EventLog/> : null}
{this.state.settings.showEventLog ? <EventLog/> : null}
<Footer settings={this.state.settings}/>
</div>
);

View File

@ -19,14 +19,7 @@ _Connection.prototype.onopen = function (open) {
_Connection.prototype.onmessage = function (message) {
//AppDispatcher.dispatchServerAction(...);
var m = JSON.parse(message.data);
switch (m.type){
case "flow":
console.log("flow", m.data);
break;
case "event":
console.log("event", m.data.message)
break;
}
AppDispatcher.dispatchServerAction(m);
};
_Connection.prototype.onerror = function (error) {
console.log("onerror", this, arguments);

View File

@ -1,6 +1,6 @@
const PayloadSources = {
VIEW_ACTION: "VIEW_ACTION",
SERVER_ACTION: "SERVER_ACTION"
VIEW: "view",
SERVER: "server"
};
@ -26,10 +26,10 @@ Dispatcher.prototype.dispatch = function (payload) {
AppDispatcher = new Dispatcher();
AppDispatcher.dispatchViewAction = function (action) {
action.actionSource = PayloadSources.VIEW_ACTION;
action.source = PayloadSources.VIEW;
this.dispatch(action);
};
AppDispatcher.dispatchServerAction = function (action) {
action.actionSource = PayloadSources.SERVER_ACTION;
action.source = PayloadSources.SERVER;
this.dispatch(action);
};

View File

@ -5,8 +5,9 @@ EventEmitter.prototype.emit = function (event) {
if (!(event in this.listeners)) {
return;
}
var args = Array.prototype.slice.call(arguments, 1);
this.listeners[event].forEach(function (listener) {
listener.apply(this, arguments);
listener.apply(this, args);
}.bind(this));
};
EventEmitter.prototype.addListener = function (event, f) {

View File

@ -7,19 +7,19 @@
// See also: components/EventLog.react.js
function EventLogView(store, live) {
EventEmitter.call(this);
this.$EventLogView_store = store;
this._store = store;
this.live = live;
this.log = [];
this.add = this.add.bind(this);
if (live) {
this.$EventLogView_store.addListener("new_entry", this.add);
this._store.addListener(ActionTypes.ADD_EVENT, this.add);
}
}
_.extend(EventLogView.prototype, EventEmitter.prototype, {
close: function () {
this.$EventLogView_store.removeListener("new_entry", this.add);
this._store.removeListener(ActionTypes.ADD_EVENT, this.add);
},
getAll: function () {
return this.log;
@ -46,7 +46,8 @@ function _EventLogStore() {
_.extend(_EventLogStore.prototype, EventEmitter.prototype, {
getView: function (since) {
var view = new EventLogView(this, !since);
return view;
/*
//TODO: Really do bulk retrieval of last messages.
window.setTimeout(function () {
view.add_bulk([
@ -77,11 +78,12 @@ _.extend(_EventLogStore.prototype, EventEmitter.prototype, {
});
}, 1000);
return view;
*/
},
handle: function (action) {
switch (action.actionType) {
case ActionTypes.EVENTLOG_ADD:
this.emit("new_message", action.message);
switch (action.type) {
case ActionTypes.ADD_EVENT:
this.emit(ActionTypes.ADD_EVENT, action.data);
break;
default:
return;

View File

@ -13,8 +13,8 @@ _.extend(_SettingsStore.prototype, EventEmitter.prototype, {
return this.settings;
},
handle: function (action) {
switch (action.actionType) {
case ActionTypes.SETTINGS_UPDATE:
switch (action.type) {
case ActionTypes.UPDATE_SETTINGS:
this.settings = action.settings;
this.emit("change");
break;

13
web/src/js/utils.js Normal file
View File

@ -0,0 +1,13 @@
// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
var AutoScrollMixin = {
componentWillUpdate: function () {
var node = this.getDOMNode();
this._shouldScrollBottom = node.scrollTop + node.clientHeight === node.scrollHeight;
},
componentDidUpdate: function () {
if (this._shouldScrollBottom) {
var node = this.getDOMNode();
node.scrollTop = node.scrollHeight;
}
},
};