mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-02-27 08:50:37 +03:00
Import-Export States to your DevTools
This commit is contained in:
parent
0a1458cdbd
commit
38158191ce
|
@ -3,6 +3,8 @@ const ActionTypes = {
|
||||||
RESET: 'RESET',
|
RESET: 'RESET',
|
||||||
ROLLBACK: 'ROLLBACK',
|
ROLLBACK: 'ROLLBACK',
|
||||||
COMMIT: 'COMMIT',
|
COMMIT: 'COMMIT',
|
||||||
|
EXPORT: 'EXPORT',
|
||||||
|
IMPORT: 'IMPORT',
|
||||||
SWEEP: 'SWEEP',
|
SWEEP: 'SWEEP',
|
||||||
TOGGLE_ACTION: 'TOGGLE_ACTION',
|
TOGGLE_ACTION: 'TOGGLE_ACTION',
|
||||||
JUMP_TO_STATE: 'JUMP_TO_STATE',
|
JUMP_TO_STATE: 'JUMP_TO_STATE',
|
||||||
|
@ -86,7 +88,8 @@ function liftReducer(reducer, initialState) {
|
||||||
skippedActions: {},
|
skippedActions: {},
|
||||||
currentStateIndex: 0,
|
currentStateIndex: 0,
|
||||||
monitorState: {
|
monitorState: {
|
||||||
isVisible: true
|
isVisible: true,
|
||||||
|
exportMode: false
|
||||||
},
|
},
|
||||||
timestamps: [Date.now()]
|
timestamps: [Date.now()]
|
||||||
};
|
};
|
||||||
|
@ -121,6 +124,25 @@ function liftReducer(reducer, initialState) {
|
||||||
currentStateIndex = 0;
|
currentStateIndex = 0;
|
||||||
timestamps = [liftedAction.timestamp];
|
timestamps = [liftedAction.timestamp];
|
||||||
break;
|
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:
|
case ActionTypes.ROLLBACK:
|
||||||
stagedActions = [INIT_ACTION];
|
stagedActions = [INIT_ACTION];
|
||||||
skippedActions = {};
|
skippedActions = {};
|
||||||
|
@ -258,6 +280,12 @@ export const ActionCreators = {
|
||||||
commit() {
|
commit() {
|
||||||
return { type: ActionTypes.COMMIT, timestamp: Date.now() };
|
return { type: ActionTypes.COMMIT, timestamp: Date.now() };
|
||||||
},
|
},
|
||||||
|
export() {
|
||||||
|
return { type: ActionTypes.EXPORT };
|
||||||
|
},
|
||||||
|
import(newState) {
|
||||||
|
return { type: ActionTypes.IMPORT, newState };
|
||||||
|
},
|
||||||
sweep() {
|
sweep() {
|
||||||
return { type: ActionTypes.SWEEP };
|
return { type: ActionTypes.SWEEP };
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import React, { PropTypes, findDOMNode, Component } from 'react';
|
import React, { PropTypes, findDOMNode, Component } from 'react';
|
||||||
import LogMonitorEntry from './LogMonitorEntry';
|
import LogMonitorEntry from './LogMonitorEntry';
|
||||||
import LogMonitorButton from './LogMonitorButton';
|
import LogMonitorButton from './LogMonitorButton';
|
||||||
|
import LogMonitorTextarea from './LogMonitorTextarea';
|
||||||
import * as themes from './themes';
|
import * as themes from './themes';
|
||||||
|
|
||||||
|
const EXPORT_CONTAINER_HEIGHT = 150;
|
||||||
|
const ELEMENTS_CONTAINER_TOP = 38;
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
container: {
|
container: {
|
||||||
fontFamily: 'monaco, Consolas, Lucida Console, monospace',
|
fontFamily: 'monaco, Consolas, Lucida Console, monospace',
|
||||||
|
@ -25,7 +29,7 @@ const styles = {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
top: 38,
|
top: ELEMENTS_CONTAINER_TOP,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
overflowY: 'auto'
|
overflowY: 'auto'
|
||||||
|
@ -118,6 +122,14 @@ export default class LogMonitor extends Component {
|
||||||
this.props.commit();
|
this.props.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleExport() {
|
||||||
|
this.props.export();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleImport(newState) {
|
||||||
|
this.props.import(newState);
|
||||||
|
}
|
||||||
|
|
||||||
handleToggleAction(index) {
|
handleToggleAction(index) {
|
||||||
this.props.toggleAction(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.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.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.handleCommit} enabled={computedStates.length > 1}>Commit</LogMonitorButton>
|
||||||
|
<LogMonitorButton theme={theme} onClick={::this.handleExport} enabled={computedStates.length}>Export</LogMonitorButton>
|
||||||
</div>
|
</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}
|
{elements}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
42
src/react/LogMonitorTextarea.js
Normal file
42
src/react/LogMonitorTextarea.js
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user