-
Notifications
You must be signed in to change notification settings - Fork 18
Add ability to filter by socket id #34
Changes from all commits
3e527d2
13dccd9
08e4c4e
e23a592
e5951be
d80f055
11df4f0
339c72c
2d281be
3316838
01c7d46
7fc4d0e
4a1cdd6
0142712
c7eb869
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* See license.txt for terms of usage */ | ||
|
||
define(function(require, exports/*, module*/) { | ||
|
||
"use strict"; | ||
|
||
// Dependencies | ||
const React = require("react"); | ||
|
||
// WebSockets Monitor | ||
const { filterFrames } = require("../actions/frames"); | ||
|
||
// Shortcuts | ||
const { span, select, option } = React.DOM; | ||
|
||
/** | ||
* This component renders a select element when unique | ||
* webSocket connections > 1. Using this dropdown, the | ||
* user can select the connection ID they are interested | ||
* in seeing, and a reducer should filter out all other | ||
* connections. | ||
*/ | ||
var ConnectionFilter = React.createClass({ | ||
/** @lends ConnectionFilter */ | ||
|
||
displayName: "ConnectionFilter", | ||
|
||
getInitialState() { | ||
return { | ||
uniqueConnections: [] | ||
}; | ||
}, | ||
|
||
handleChange(e) { | ||
const { value } = e.target; | ||
const currentFilter = this.props.frames.filter; | ||
|
||
// Dispatch new filter, merging with old filter to | ||
// retain text filter alongside this filter. | ||
this.props.dispatch(filterFrames( | ||
Object.assign({}, currentFilter, { | ||
webSocketSerialID: value !== null ? Number(value) : null | ||
}) | ||
)); | ||
}, | ||
|
||
// When the platform API supports it, this should be replaced | ||
// with some API call listing only the current connections on | ||
// the page. | ||
componentWillReceiveProps({ frames }) { | ||
frames.frames.forEach(frame => { | ||
const { uniqueConnections } = this.state; | ||
|
||
if (!uniqueConnections.includes(frame.webSocketSerialID)) { | ||
this.setState({ | ||
uniqueConnections: [...uniqueConnections, frame.webSocketSerialID] | ||
}); | ||
} | ||
}) | ||
}, | ||
|
||
render() { | ||
const { uniqueConnections } = this.state; | ||
return ( | ||
uniqueConnections.length > 1 ? | ||
select({ | ||
className: "ConnectionFilter", | ||
value: this.props.frames.filter.webSocketSerialID, | ||
onChange: this.handleChange | ||
}, option({ value: null }, Locale.$STR("websocketmonitor.ConnectionFilter.NoFilter")), | ||
uniqueConnections.map((id, i) => { | ||
return option({key: i, value: id}, id); | ||
}) | ||
) : | ||
// else, no-op | ||
span() | ||
); | ||
} | ||
}); | ||
|
||
// Exports from this module | ||
exports.ConnectionFilter = ConnectionFilter; | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,8 @@ const { Toolbar, ToolbarButton } = createFactories(require("reps/toolbar")); | |
|
||
// WebSockets Monitor | ||
const { clear } = require("../actions/frames"); | ||
const { SearchBox } = require("./search-box"); | ||
const { SearchBox } = createFactories(require("./search-box")); | ||
const { ConnectionFilter } = createFactories(require("./connection-filter")); | ||
|
||
/** | ||
* @template This object is responsible for rendering the toolbar | ||
|
@@ -31,16 +32,6 @@ var MainToolbar = React.createClass({ | |
} | ||
}, | ||
|
||
componentDidMount: function() { | ||
var toolbar = ReactDOM.findDOMNode(this.refs.toolbar); | ||
SearchBox.create(toolbar); | ||
}, | ||
|
||
componentWillUnmount: function() { | ||
var toolbar = ReactDOM.findDOMNode(this.refs.toolbar); | ||
SearchBox.destroy(toolbar); | ||
}, | ||
|
||
// Commands | ||
|
||
onTogglePause: function() { | ||
|
@@ -89,7 +80,9 @@ var MainToolbar = React.createClass({ | |
), | ||
ToolbarButton({bsSize: "xsmall", onClick: this.onSwitchPerspective}, | ||
perspectiveLabel | ||
) | ||
), | ||
SearchBox(this.props), | ||
ConnectionFilter(this.props) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My guess is that we may rather put the connection filter on the left of the SearchBox. Otherwise, the appearance of the dropdown list moves the search box and may disturb the user. Also I am a bit curious why the SearchBox is in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I agree. It would be better if the dropdown appeared to the left of the search box. I assume SearchBox is in Because they (SearchBox and ConnectionFilter) are both |
||
) | ||
); | ||
}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* See license.txt for terms of usage */ | ||
|
||
/******************************************************************************/ | ||
/* Connection Filter Dropdown */ | ||
|
||
.theme-dark .ConnectionFilter { | ||
color: var(--theme-content-color1); | ||
border: none; | ||
background: rgba(170, 170, 170, .3); | ||
} | ||
|
||
.theme-firebug .ConnectionFilter { | ||
color: #333; | ||
border-radius: 2px; | ||
} | ||
|
||
.ConnectionFilter { | ||
float: right; | ||
height: 22px; | ||
border: 1px solid rgb(204, 204, 204); | ||
|
||
background: rgb(255, 255, 255) none repeat scroll 0% 0%; | ||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset; | ||
color: rgb(85, 85, 85); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,51 +95,76 @@ function addFrames(state, newFrames) { | |
}); | ||
|
||
// Apply filter on incoming frames. | ||
if (newState.filter.text) { | ||
return filterFrames(newState, newState.filter); | ||
} | ||
|
||
return newState; | ||
return filterFrames(newState, newState.filter); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fixed an issue of new frames not showing up when switching back to "No socket ID filter". I was not able to see any adverse effects of doing this, so I left it in. |
||
} | ||
|
||
function filterFrames(state, filter) { | ||
var frames; | ||
|
||
var summary = { | ||
totalSize: 0, | ||
startTime: 0, | ||
endTime: 0, | ||
frameCount: 0 | ||
}; | ||
var { frames } = state; | ||
var summary = null; | ||
|
||
if (filter.text) { | ||
frames = state.frames.filter(frame => { | ||
summary = { | ||
totalSize: 0, | ||
startTime: 0, | ||
endTime: 0, | ||
frameCount: 0 | ||
}; | ||
|
||
frames = frames.filter(frame => { | ||
var data = frame.data; | ||
if (data.payload && data.payload.indexOf(filter.text) != -1) { | ||
|
||
// Exclude where data is null (events). Events have no payload | ||
if (data && data.payload && data.payload.indexOf(filter.text) != -1) { | ||
summary.totalSize += data.payload.length; | ||
summary.startTime = summary.startTime ? summary.startTime : data.timeStamp; | ||
summary.endTime = data.timeStamp; | ||
summary.frameCount++; | ||
return true; | ||
} | ||
}); | ||
} else { | ||
summary = null; | ||
} | ||
|
||
if (filter.webSocketSerialID) { | ||
summary = { | ||
totalSize: 0, | ||
startTime: 0, | ||
endTime: 0, | ||
frameCount: 0 | ||
}; | ||
|
||
frames = frames.filter(frame => { | ||
var data = frame.data; | ||
if (frame.webSocketSerialID === filter.webSocketSerialID) { | ||
|
||
// If data is null, this is not an actual frame, but an event | ||
// like "connect" or "disconnect". We still want to keep it | ||
// in the list, though. | ||
if (data) { | ||
summary.totalSize += data.payload.length; | ||
summary.startTime = summary.startTime ? summary.startTime : data.timeStamp; | ||
summary.endTime = data.timeStamp; | ||
summary.frameCount++; | ||
} | ||
return true; | ||
} | ||
}); | ||
} | ||
|
||
return Object.assign({}, state, { | ||
filter: { | ||
text: filter.text, | ||
webSocketSerialID: filter.webSocketSerialID, | ||
frames: frames, | ||
summary: summary, | ||
} | ||
}); | ||
} | ||
|
||
function clear(state) { | ||
// All data are cleared except of the current filter. | ||
// All data is cleared except for the current filters. | ||
var newState = getInitialState(); | ||
newState.filter.text = state.filter.text; | ||
newState.filter.webSocketSerialID = state.filter.webSocketSerialID; | ||
return newState; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Not sure if the key attribute is useful here (and standard for the option element)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because we are mapping over
uniqueConnections
and generating children. it is necessary to avoid React complain aboutWarning: Each child in an array or iterator should have a unique "key" prop
:)See https://facebook.github.io/react/docs/multiple-components.html#dynamic-children
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. Thanks for pointing me out this good practice :).
Florent