persist network plugin state
Summary: This saved the state of the network plugin even when switching between plugins using persistedState. A bug in the Android implementation didn't clear the events that were already sent to the desktop. Reviewed By: jknoxville Differential Revision: D8752098 fbshipit-source-id: 152ec5da83958ad8124686f780d39983cbce563f
This commit is contained in:
committed by
Facebook Github Bot
parent
f5dcaf02a4
commit
c239fcac01
@@ -49,9 +49,10 @@ public abstract class BufferingSonarPlugin implements SonarPlugin {
|
||||
if (mEventQueue == null) {
|
||||
mEventQueue = new RingBuffer<>(BUFFER_SIZE);
|
||||
}
|
||||
mEventQueue.enqueue(new CachedSonarEvent(method, sonarObject));
|
||||
if (mConnection != null) {
|
||||
mConnection.send(method, sonarObject);
|
||||
} else {
|
||||
mEventQueue.enqueue(new CachedSonarEvent(method, sonarObject));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +61,7 @@ public abstract class BufferingSonarPlugin implements SonarPlugin {
|
||||
for (CachedSonarEvent cachedSonarEvent : mEventQueue.asList()) {
|
||||
mConnection.send(cachedSonarEvent.method, cachedSonarEvent.sonarObject);
|
||||
}
|
||||
mEventQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ final class RingBuffer<T> {
|
||||
mBuffer.add(item);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
mBuffer.clear();
|
||||
}
|
||||
|
||||
List<T> asList() {
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,11 @@ export class SonarBasePlugin<
|
||||
}
|
||||
}
|
||||
|
||||
export class SonarDevicePlugin<S = *, A = *> extends SonarBasePlugin<S, A> {
|
||||
export class SonarDevicePlugin<S = *, A = *, P = *> extends SonarBasePlugin<
|
||||
S,
|
||||
A,
|
||||
P,
|
||||
> {
|
||||
device: BaseDevice;
|
||||
|
||||
_setup(target: PluginTarget) {
|
||||
@@ -100,7 +104,7 @@ export class SonarDevicePlugin<S = *, A = *> extends SonarBasePlugin<S, A> {
|
||||
}
|
||||
}
|
||||
|
||||
export class SonarPlugin<S = *, A = *> extends SonarBasePlugin<S, A> {
|
||||
export class SonarPlugin<S = *, A = *, P = *> extends SonarBasePlugin<S, A, P> {
|
||||
constructor() {
|
||||
super();
|
||||
this.subscriptions = [];
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TableHighlightedRows, TableRows} from 'sonar';
|
||||
import type {TableHighlightedRows, TableRows, TableBodyRow} from 'sonar';
|
||||
|
||||
import {
|
||||
ContextMenu,
|
||||
@@ -17,19 +17,18 @@ import {
|
||||
PureComponent,
|
||||
SonarSidebar,
|
||||
} from 'sonar';
|
||||
|
||||
import {SonarPlugin, SearchableTable} from 'sonar';
|
||||
import RequestDetails from './RequestDetails.js';
|
||||
|
||||
import {URL} from 'url';
|
||||
// $FlowFixMe
|
||||
import sortBy from 'lodash.sortby';
|
||||
|
||||
type RequestId = string;
|
||||
|
||||
type State = {|
|
||||
type PersistedState = {|
|
||||
requests: {[id: RequestId]: Request},
|
||||
responses: {[id: RequestId]: Response},
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
selectedIds: Array<RequestId>,
|
||||
|};
|
||||
|
||||
@@ -109,7 +108,7 @@ const TextEllipsis = Text.extends({
|
||||
paddingTop: 4,
|
||||
});
|
||||
|
||||
export default class extends SonarPlugin<State> {
|
||||
export default class extends SonarPlugin<State, *, PersistedState> {
|
||||
static title = 'Network';
|
||||
static id = 'Network';
|
||||
static icon = 'internet';
|
||||
@@ -122,53 +121,39 @@ export default class extends SonarPlugin<State> {
|
||||
};
|
||||
|
||||
state = {
|
||||
requests: {},
|
||||
responses: {},
|
||||
selectedIds: [],
|
||||
};
|
||||
|
||||
init() {
|
||||
this.client.subscribe('newRequest', (request: Request) => {
|
||||
this.dispatchAction({request, type: 'NewRequest'});
|
||||
this.props.setPersistedState({
|
||||
requests: {
|
||||
...this.props.persistedState.requests,
|
||||
[request.id]: request,
|
||||
},
|
||||
});
|
||||
});
|
||||
this.client.subscribe('newResponse', (response: Response) => {
|
||||
this.dispatchAction({response, type: 'NewResponse'});
|
||||
this.props.setPersistedState({
|
||||
responses: {
|
||||
...this.props.persistedState.responses,
|
||||
[response.id]: response,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
reducers = {
|
||||
NewRequest(state: State, {request}: {request: Request}) {
|
||||
return {
|
||||
requests: {...state.requests, [request.id]: request},
|
||||
responses: state.responses,
|
||||
};
|
||||
},
|
||||
|
||||
NewResponse(state: State, {response}: {response: Response}) {
|
||||
return {
|
||||
requests: state.requests,
|
||||
responses: {...state.responses, [response.id]: response},
|
||||
};
|
||||
},
|
||||
|
||||
Clear(state: State) {
|
||||
return {
|
||||
requests: {},
|
||||
responses: {},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
onRowHighlighted = (selectedIds: Array<RequestId>) =>
|
||||
this.setState({selectedIds});
|
||||
|
||||
clearLogs = () => {
|
||||
this.setState({selectedIds: []});
|
||||
this.dispatchAction({type: 'Clear'});
|
||||
this.props.setPersistedState({responses: {}, requests: {}});
|
||||
};
|
||||
|
||||
renderSidebar = () => {
|
||||
const {selectedIds, requests, responses} = this.state;
|
||||
const {requests, responses} = this.props.persistedState;
|
||||
const {selectedIds} = this.state;
|
||||
const selectedId = selectedIds.length === 1 ? selectedIds[0] : null;
|
||||
|
||||
return selectedId != null ? (
|
||||
@@ -181,11 +166,13 @@ export default class extends SonarPlugin<State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {requests, responses} = this.props.persistedState;
|
||||
|
||||
return (
|
||||
<FlexColumn fill={true}>
|
||||
<NetworkTable
|
||||
requests={this.state.requests}
|
||||
responses={this.state.responses}
|
||||
requests={requests || {}}
|
||||
responses={responses || {}}
|
||||
clear={this.clearLogs}
|
||||
onRowHighlighted={this.onRowHighlighted}
|
||||
/>
|
||||
@@ -195,53 +182,18 @@ export default class extends SonarPlugin<State> {
|
||||
}
|
||||
}
|
||||
|
||||
type NetworkTableProps = {|
|
||||
type NetworkTableProps = {
|
||||
requests: {[id: RequestId]: Request},
|
||||
responses: {[id: RequestId]: Response},
|
||||
clear: () => void,
|
||||
onRowHighlighted: (keys: TableHighlightedRows) => void,
|
||||
|};
|
||||
};
|
||||
|
||||
type NetworkTableState = {|
|
||||
sortedRows: TableRows,
|
||||
|};
|
||||
|
||||
class NetworkTable extends PureComponent<NetworkTableProps, NetworkTableState> {
|
||||
static ContextMenu = ContextMenu.extends({
|
||||
flex: 1,
|
||||
});
|
||||
|
||||
state = {
|
||||
sortedRows: [],
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps: NetworkTableProps) {
|
||||
if (Object.keys(nextProps.requests).length === 0) {
|
||||
// cleared
|
||||
this.setState({sortedRows: []});
|
||||
} else if (this.props.requests !== nextProps.requests) {
|
||||
// new request
|
||||
for (const requestId in nextProps.requests) {
|
||||
if (this.props.requests[requestId] == null) {
|
||||
this.buildRow(nextProps.requests[requestId], null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (this.props.responses !== nextProps.responses) {
|
||||
// new response
|
||||
for (const responseId in nextProps.responses) {
|
||||
if (this.props.responses[responseId] == null) {
|
||||
this.buildRow(
|
||||
nextProps.requests[responseId],
|
||||
nextProps.responses[responseId],
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildRow(request: Request, response: ?Response) {
|
||||
function buildRow(request: Request, response: ?Response): ?TableBodyRow {
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
@@ -249,7 +201,7 @@ class NetworkTable extends PureComponent<NetworkTableProps, NetworkTableState> {
|
||||
const domain = url.host + url.pathname;
|
||||
const friendlyName = getHeaderValue(request.headers, 'X-FB-Friendly-Name');
|
||||
|
||||
const newRow = {
|
||||
return {
|
||||
columns: {
|
||||
domain: {
|
||||
value: (
|
||||
@@ -263,9 +215,7 @@ class NetworkTable extends PureComponent<NetworkTableProps, NetworkTableState> {
|
||||
},
|
||||
status: {
|
||||
value: (
|
||||
<StatusColumn>
|
||||
{response ? response.status : undefined}
|
||||
</StatusColumn>
|
||||
<StatusColumn>{response ? response.status : undefined}</StatusColumn>
|
||||
),
|
||||
isFilterable: true,
|
||||
},
|
||||
@@ -282,21 +232,78 @@ class NetworkTable extends PureComponent<NetworkTableProps, NetworkTableState> {
|
||||
copyText: request.url,
|
||||
highlightOnHover: true,
|
||||
};
|
||||
}
|
||||
|
||||
let rows;
|
||||
if (response == null) {
|
||||
rows = [...this.state.sortedRows, newRow];
|
||||
} else {
|
||||
const index = this.state.sortedRows.findIndex(r => r.key === request.id);
|
||||
if (index > -1) {
|
||||
rows = [...this.state.sortedRows];
|
||||
function calculateState(
|
||||
props: {
|
||||
requests: {[id: RequestId]: Request},
|
||||
responses: {[id: RequestId]: Response},
|
||||
},
|
||||
nextProps: NetworkTableProps,
|
||||
rows: TableRows = [],
|
||||
): NetworkTableState {
|
||||
rows = [...rows];
|
||||
|
||||
if (Object.keys(nextProps.requests).length === 0) {
|
||||
// cleared
|
||||
rows = [];
|
||||
} else if (props.requests !== nextProps.requests) {
|
||||
// new request
|
||||
for (const requestId in nextProps.requests) {
|
||||
if (props.requests[requestId] == null) {
|
||||
const newRow = buildRow(
|
||||
nextProps.requests[requestId],
|
||||
nextProps.responses[requestId],
|
||||
);
|
||||
if (newRow) {
|
||||
rows.push(newRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (props.responses !== nextProps.responses) {
|
||||
// new response
|
||||
for (const responseId in nextProps.responses) {
|
||||
if (props.responses[responseId] == null) {
|
||||
const newRow = buildRow(
|
||||
nextProps.requests[responseId],
|
||||
nextProps.responses[responseId],
|
||||
);
|
||||
const index = rows.findIndex(
|
||||
r => r.key === nextProps.requests[responseId].id,
|
||||
);
|
||||
if (index > -1 && newRow) {
|
||||
rows[index] = newRow;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
sortedRows: sortBy(rows, x => x.sortKey),
|
||||
rows.sort((a, b) => (String(a.sortKey) > String(b.sortKey) ? 1 : -1));
|
||||
|
||||
return {
|
||||
sortedRows: rows,
|
||||
};
|
||||
}
|
||||
|
||||
class NetworkTable extends PureComponent<NetworkTableProps, NetworkTableState> {
|
||||
static ContextMenu = ContextMenu.extends({
|
||||
flex: 1,
|
||||
});
|
||||
|
||||
constructor(props: NetworkTableProps) {
|
||||
super(props);
|
||||
this.state = calculateState(
|
||||
{
|
||||
requests: {},
|
||||
responses: {},
|
||||
},
|
||||
props,
|
||||
);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: NetworkTableProps) {
|
||||
this.setState(calculateState(this.props, nextProps, this.state.sortedRows));
|
||||
}
|
||||
|
||||
contextMenuItems = [
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash.sortby": "^4.7.0",
|
||||
"pako": "^1.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
|
||||
pako@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
|
||||
|
||||
Reference in New Issue
Block a user