From da5e3766468d25da554c50879a0c4865971d6922 Mon Sep 17 00:00:00 2001 From: pabloalonso Date: Fri, 18 Sep 2015 17:57:32 -0400 Subject: [PATCH] Import-Export States to your DevTools --- src/devTools.js | 30 ++++++++++++++++++++++- src/react/LogMonitor.js | 18 ++++++++++++-- src/react/LogMonitorTextarea.js | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 src/react/LogMonitorTextarea.js diff --git a/src/devTools.js b/src/devTools.js index f57e9bc179..9208964d3e 100644 --- a/src/devTools.js +++ b/src/devTools.js @@ -3,6 +3,8 @@ const ActionTypes = { RESET: 'RESET', ROLLBACK: 'ROLLBACK', COMMIT: 'COMMIT', + EXPORT: 'EXPORT', + IMPORT: 'IMPORT', SWEEP: 'SWEEP', TOGGLE_ACTION: 'TOGGLE_ACTION', JUMP_TO_STATE: 'JUMP_TO_STATE', @@ -86,7 +88,8 @@ function liftReducer(reducer, initialState) { skippedActions: {}, currentStateIndex: 0, monitorState: { - isVisible: true + isVisible: true, + exportMode: false }, timestamps: [Date.now()] }; @@ -120,6 +123,25 @@ function liftReducer(reducer, initialState) { currentStateIndex = 0; timestamps = [liftedAction.timestamp]; break; + case ActionTypes.EXPORT: + monitorState = Object.assign( + {}, + monitorState, + { exportMode: !monitorState.exportMode } + ); + break; + case ActionTypes.IMPORT: + ( + { + stagedActions, + skippedActions, + computedStates, + currentStateIndex, + monitorState, + timestamps + } = liftedAction.newState + ); + break; case ActionTypes.ROLLBACK: stagedActions = [INIT_ACTION]; skippedActions = {}; @@ -235,6 +257,12 @@ export const ActionCreators = { commit() { return { type: ActionTypes.COMMIT, timestamp: Date.now() }; }, + export() { + return { type: ActionTypes.EXPORT }; + }, + import(newState) { + return { type: ActionTypes.IMPORT, newState }; + }, sweep() { return { type: ActionTypes.SWEEP }; }, diff --git a/src/react/LogMonitor.js b/src/react/LogMonitor.js index d960f4608c..230af55af0 100644 --- a/src/react/LogMonitor.js +++ b/src/react/LogMonitor.js @@ -1,8 +1,12 @@ import React, { PropTypes, findDOMNode, Component } from 'react'; import LogMonitorEntry from './LogMonitorEntry'; import LogMonitorButton from './LogMonitorButton'; +import LogMonitorTextarea from './LogMonitorTextarea'; import * as themes from './themes'; +const EXPORT_CONTAINER_HEIGHT = 150; +const ELEMENTS_CONTAINER_TOP = 38; + const styles = { container: { fontFamily: 'monaco, Consolas, Lucida Console, monospace', @@ -25,7 +29,7 @@ const styles = { position: 'absolute', left: 0, right: 0, - top: 38, + top: ELEMENTS_CONTAINER_TOP, bottom: 0, overflowX: 'hidden', overflowY: 'auto' @@ -114,6 +118,14 @@ export default class LogMonitor extends Component { this.props.commit(); } + handleExport() { + this.props.export(); + } + + handleImport(newState) { + this.props.import(newState); + } + handleToggleAction(index) { this.props.toggleAction(index); } @@ -180,8 +192,10 @@ export default class LogMonitor extends Component { Revert skippedActions[key])}>Sweep 1}>Commit + Export -
+ +
{elements}
diff --git a/src/react/LogMonitorTextarea.js b/src/react/LogMonitorTextarea.js new file mode 100644 index 0000000000..94efde80d6 --- /dev/null +++ b/src/react/LogMonitorTextarea.js @@ -0,0 +1,42 @@ +import React, { PropTypes, findDOMNode, Component } from 'react'; + +const EXPORT_CONTAINER_HEIGHT = 150; +const ELEMENTS_CONTAINER_TOP = 38; + +var styles = { + exportContainer: { + width: '100%', + height: EXPORT_CONTAINER_HEIGHT + }, + exportArea: { + position: 'relative', + resize: 'none', + width: '100%', + height: 112, + backgroundColor: '#4F5A66', + color: 'white' + } +}; + +export default class LogMonitorTextarea extends Component { + constructor(props) { + super(props); + } + + parseInput(event) { + try { + this.props.handleImport(JSON.parse(event.target.value)) + } catch(err) { + console.warn('There was an error parsing the new state. Please enter a valid schema.'); + } + } + + render() { + let { handleImport, currentState, theme } = this.props; + return currentState.monitorState.exportMode ? ( +
+