From 9eb4196a6da6e5651c633b94aa33b39d0a7a3914 Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Wed, 17 Jun 2015 21:56:27 -0700 Subject: [PATCH 1/4] A debug component --- .eslintrc | 1 + package.json | 1 + src/alt/index.js | 10 +- src/utils/Debugger.js | 30 ++++ src/utils/DispatcherDebugger.js | 196 +++++++++++++++++++++++++++ src/utils/DispatcherRecorder.js | 4 +- src/utils/Inspector.js | 154 +++++++++++++++++++++ src/utils/StoreExplorer.js | 56 ++++++++ src/utils/debug/AltStore.js | 33 +++++ src/utils/debug/DebugActions.js | 16 +++ src/utils/debug/DispatcherStore.js | 135 ++++++++++++++++++ src/utils/debug/FixedDataTableCss.js | 19 +++ src/utils/debug/ViewerStore.js | 25 ++++ src/utils/debug/alt.js | 5 + 14 files changed, 683 insertions(+), 2 deletions(-) create mode 100644 src/utils/Debugger.js create mode 100644 src/utils/DispatcherDebugger.js create mode 100644 src/utils/Inspector.js create mode 100644 src/utils/StoreExplorer.js create mode 100644 src/utils/debug/AltStore.js create mode 100644 src/utils/debug/DebugActions.js create mode 100644 src/utils/debug/DispatcherStore.js create mode 100644 src/utils/debug/FixedDataTableCss.js create mode 100644 src/utils/debug/ViewerStore.js create mode 100644 src/utils/debug/alt.js diff --git a/.eslintrc b/.eslintrc index e35e3c0f..84bc9cbd 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,6 +4,7 @@ "browser": true, "es6": true }, + "parser": "babel-eslint", "ecmaFeatures": { "modules": true, "jsx": true diff --git a/package.json b/package.json index da31853e..097ec1b7 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "babel": "^5.6.6", "babel-core": "^5.6.6", "babel-loader": "^5.1.4", + "babel-eslint": "3.1.18", "chai": "^2.3.0", "coveralls": "^2.11.2", "envify": "^3.4.0", diff --git a/src/alt/index.js b/src/alt/index.js index b397b8da..c586f234 100644 --- a/src/alt/index.js +++ b/src/alt/index.js @@ -24,7 +24,15 @@ class Alt { } dispatch(action, data, details) { - this.batchingFunction(() => this.dispatcher.dispatch({ action, data, details })) + this.batchingFunction(() => { + const id = Math.random().toString(18).substr(2, 16) + return this.dispatcher.dispatch({ + id, + action, + data, + details + }) + }) } createUnsavedStore(StoreModel, ...args) { diff --git a/src/utils/Debugger.js b/src/utils/Debugger.js new file mode 100644 index 00000000..0236d59a --- /dev/null +++ b/src/utils/Debugger.js @@ -0,0 +1,30 @@ +/*eslint-disable */ +import DebugActions from './debug/DebugActions' +import DispatcherDebugger from './DispatcherDebugger' +import React, { Component } from 'react' +import StoreExplorer from './StoreExplorer' + +class Debugger extends Component { + componentDidMount() { + DebugActions.setAlt(this.props.alt) + } + + renderInspectorWindow() { + return this.props.inspector + ? + : null + } + + render() { + return ( +
+

Debug

+ + + {this.renderInspectorWindow()} +
+ ) + } +} + +export default Debugger diff --git a/src/utils/DispatcherDebugger.js b/src/utils/DispatcherDebugger.js new file mode 100644 index 00000000..c9f180dd --- /dev/null +++ b/src/utils/DispatcherDebugger.js @@ -0,0 +1,196 @@ +/*eslint-disable */ +import React, { Component } from 'react' +import { Column, Table } from 'fixed-data-table' +import makeFinalStore from './makeFinalStore' +import connectToStores from './connectToStores' + +import FixedDataTableCss from './debug/FixedDataTableCss' + +import DebugActions from './debug/DebugActions' +import DispatcherStore from './debug/DispatcherStore' + +class DispatcherDebugger extends Component { + constructor() { + super() + + this.getDispatch = this.getDispatch.bind(this) + this.renderName = this.renderName.bind(this) + this.renderReplay = this.renderReplay.bind(this) + this.renderRevert = this.renderRevert.bind(this) + this.view = this.view.bind(this) + } + + componentDidMount() { + const finalStore = makeFinalStore(this.props.alt) + finalStore.listen(state => DebugActions.addDispatch(state.payload)) + DebugActions.setAlt(this.props.alt) + } + + clear() { + DebugActions.clear() + } + + getDispatch(idx) { + const dispatch = this.props.dispatches[idx] + return { + id: dispatch.id, + action: dispatch.action, + data: dispatch.data, + details: dispatch.details, + recorded: dispatch.recorded, + dispatchedStores: dispatch.dispatchedStores, + mtime: this.props.mtime, + } + } + + loadRecording() { + const json = prompt('Give me a serialized recording') + if (json) DebugActions.loadRecording(json) + } + + revert(ev) { + const data = ev.target.dataset + DebugActions.revert(data.dispatchId) + } + + saveRecording() { + DebugActions.saveRecording() + } + + startReplay() { + DebugActions.startReplay() + DebugActions.replay() + } + + stopReplay() { + DebugActions.stopReplay() + } + + toggleLogDispatches() { + DebugActions.toggleLogDispatches() + } + + togglePauseReplay() { + DebugActions.togglePauseReplay() + } + + toggleRecording() { + DebugActions.toggleRecording() + } + + view(ev) { + const data = ev.target.dataset + const dispatch = this.props.dispatches[data.index] + DebugActions.selectData(dispatch) + } + + renderName(name, _, dispatch, idx) { + return ( +
+ {name} +
+ ) + } + + renderReplay() { + if (this.props.inReplayMode) { + return ( + + + {this.props.isReplaying ? 'Pause Replay' : 'Resume Replay'} + + {' | '} + + Stop Replay + + + ) + } + + return ( + + Start Replay + + ) + } + + renderRevert(a, b, dispatch) { + return ( +
+ + Revert + + +
+ ) + } + + render() { + return ( +
+

Dispatches

+ +
+ + {this.props.isRecording ? 'Stop Recording' : 'Record'} + + {' | '} + + Clear + + {' | '} + + Save + + {' | '} + + Load + + {' | '} + {this.renderReplay()} +
+ + + +
+
+ ) + } +} + +export default connectToStores({ + getPropsFromStores() { + return DispatcherStore.getState() + }, + + getStores() { + return [DispatcherStore] + } +}, DispatcherDebugger) diff --git a/src/utils/DispatcherRecorder.js b/src/utils/DispatcherRecorder.js index f887b6f0..0d19f781 100644 --- a/src/utils/DispatcherRecorder.js +++ b/src/utils/DispatcherRecorder.js @@ -110,8 +110,9 @@ DispatcherRecorder.prototype.replay = function (replayTime, done) { DispatcherRecorder.prototype.serializeEvents = function () { const events = this.events.map((event) => { return { + id: event.id, action: event.action, - data: event.data + data: event.data || {} } }) return JSON.stringify(events) @@ -129,6 +130,7 @@ DispatcherRecorder.prototype.loadEvents = function (events) { data: event.data } }) + return parsedEvents } export default DispatcherRecorder diff --git a/src/utils/Inspector.js b/src/utils/Inspector.js new file mode 100644 index 00000000..b844761f --- /dev/null +++ b/src/utils/Inspector.js @@ -0,0 +1,154 @@ +/*eslint-disable */ +import React from 'react' +import ViewerStore from './debug/ViewerStore' +import connectToStores from './connectToStores' + +const Styles = { + root: { + font: '14px/1.4 Consolas, monospace', + }, + + line: { + cursor: 'pointer', + paddingLeft: '1em', + }, + + key: { + color: '#656865', + }, + + string: { + color: '#87af5f', + cursor: 'text', + marginLeft: '0.1em', + }, + + boolean: { + color: '#f55e5f', + cursor: 'text', + marginLeft: '0.1em', + }, + + number: { + color: '#57b3df', + cursor: 'text', + marginLeft: '0.1em', + }, + + helper: { + color: '#b0b0b0', + marginLeft: '0.1em', + }, +} + +class Leaf extends React.Component { + constructor(props) { + super(props) + + this.state = { + hidden: this.props.hidden + } + + this.toggle = this._toggle.bind(this) + } + + renderValue() { + if (typeof this.props.data === 'object' && this.props.data) { + if (this.state.hidden) { + return null + } + + return Object.keys(this.props.data).map((node, i) => { + return ( +