Import-Export States to your DevTools

This commit is contained in:
pabloalonso 2015-09-18 17:57:32 -04:00
parent 0a1458cdbd
commit 38158191ce
3 changed files with 87 additions and 3 deletions

View File

@ -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()]
};
@ -121,6 +124,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 = {};
@ -258,6 +280,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 };
},

View File

@ -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'
@ -118,6 +122,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);
}
@ -184,8 +196,10 @@ export default class LogMonitor extends Component {
<LogMonitorButton theme={theme} onClick={::this.handleRollback} enabled={computedStates.length}>Revert</LogMonitorButton>
<LogMonitorButton theme={theme} onClick={::this.handleSweep} enabled={Object.keys(skippedActions).some(key => skippedActions[key])}>Sweep</LogMonitorButton>
<LogMonitorButton theme={theme} onClick={::this.handleCommit} enabled={computedStates.length > 1}>Commit</LogMonitorButton>
<LogMonitorButton theme={theme} onClick={::this.handleExport} enabled={computedStates.length}>Export</LogMonitorButton>
</div>
<div style={styles.elements} ref="elements">
<LogMonitorTextarea theme={theme} handleImport={::this.handleImport} currentState={this.props.store.getState()} />
<div style={{...styles.elements, top: monitorState.exportMode ? EXPORT_CONTAINER_HEIGHT : ELEMENTS_CONTAINER_TOP }} ref="elements">
{elements}
</div>
</div>

View File

@ -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 ? (
<div style={{...styles.exportContainer, backgroundColor: theme.base00}}>
<textarea style={styles.exportArea} value={JSON.stringify(currentState)} onChange={::this.parseInput} />
</div>
) : null;
}
}