use react-dock for debug panel docking

This commit is contained in:
Kuzya 2015-09-13 04:21:49 +03:00
parent 22011114f5
commit 602fc7f59d
6 changed files with 77 additions and 87 deletions

View File

@ -47,6 +47,7 @@
"redux": "^2.0.0"
},
"dependencies": {
"react-dock": "0.0.2",
"react-json-tree": "^0.1.8",
"react-mixin": "^1.7.0",
"react-redux": "^2.0.0",

View File

@ -1,5 +1,6 @@
import createAll from 'react-redux/lib/components/createAll';
import { ActionCreators } from './devTools';
import DebugPanel from './react/DebugPanel';
export default function createDevTools(React) {
const { PropTypes, Component } = React;
@ -11,8 +12,13 @@ export default function createDevTools(React) {
)
class DevTools extends Component {
render() {
const { monitor: Monitor } = this.props;
return <Monitor {...this.props} />;
const { monitor: Monitor, panelState, setPanelState,
visibleOnLoad, position, ...props } = this.props;
return (
<DebugPanel {...{ panelState, setPanelState, visibleOnLoad, position }}>
<Monitor {...props} />
</DebugPanel>
);
}
}
@ -37,9 +43,9 @@ export default function createDevTools(React) {
}
render() {
const { store: { devToolsStore }, ...props } = this.props;
return (
<DevTools {...this.props}
store={this.props.store.devToolsStore} />
<DevTools {...props} store={devToolsStore} />
);
}
};

View File

@ -6,7 +6,7 @@ const ActionTypes = {
SWEEP: 'SWEEP',
TOGGLE_ACTION: 'TOGGLE_ACTION',
JUMP_TO_STATE: 'JUMP_TO_STATE',
SET_MONITOR_STATE: 'SET_MONITOR_STATE',
SET_PANEL_STATE: 'SET_PANEL_STATE',
RECOMPUTE_STATES: 'RECOMPUTE_STATES'
};
@ -85,7 +85,8 @@ function liftReducer(reducer, initialState) {
stagedActions: [INIT_ACTION],
skippedActions: {},
currentStateIndex: 0,
monitorState: {
panelState: {
position: 'right',
isVisible: true
},
timestamps: [Date.now()]
@ -101,7 +102,7 @@ function liftReducer(reducer, initialState) {
skippedActions,
computedStates,
currentStateIndex,
monitorState,
panelState,
timestamps
} = liftedState;
@ -145,8 +146,8 @@ function liftReducer(reducer, initialState) {
stagedActions = [...stagedActions, liftedAction.action];
timestamps = [...timestamps, liftedAction.timestamp];
break;
case ActionTypes.SET_MONITOR_STATE:
monitorState = liftedAction.monitorState;
case ActionTypes.SET_PANEL_STATE:
panelState = liftedAction.panelState;
break;
case ActionTypes.RECOMPUTE_STATES:
stagedActions = liftedAction.stagedActions;
@ -172,7 +173,7 @@ function liftReducer(reducer, initialState) {
skippedActions,
computedStates,
currentStateIndex,
monitorState,
panelState,
timestamps
};
};
@ -244,8 +245,8 @@ export const ActionCreators = {
jumpToState(index) {
return { type: ActionTypes.JUMP_TO_STATE, index };
},
setMonitorState(monitorState) {
return { type: ActionTypes.SET_MONITOR_STATE, monitorState };
setPanelState(panelState) {
return { type: ActionTypes.SET_PANEL_STATE, panelState };
},
recomputeStates(committedState, stagedActions) {
return {

View File

@ -1,51 +1,71 @@
import React, { PropTypes, Component } from 'react';
import Dock from 'react-dock';
export function getDefaultStyle(props) {
let { left, right, bottom, top } = props;
if (typeof left === 'undefined' && typeof right === 'undefined') {
right = true;
}
if (typeof top === 'undefined' && typeof bottom === 'undefined') {
bottom = true;
}
return {
position: 'fixed',
zIndex: 10000,
fontSize: 17,
overflow: 'hidden',
opacity: 1,
color: 'white',
left: left ? 0 : undefined,
right: right ? 0 : undefined,
top: top ? 0 : undefined,
bottom: bottom ? 0 : undefined,
maxHeight: (bottom && top) ? '100%' : '30%',
maxWidth: (left && right) ? '100%' : '30%',
wordWrap: 'break-word',
boxSizing: 'border-box',
boxShadow: '-2px 0 7px 0 rgba(0, 0, 0, 0.5)'
};
}
const POSITIONS = ['left', 'top', 'right', 'bottom'];
export default class DebugPanel extends Component {
static propTypes = {
left: PropTypes.bool,
right: PropTypes.bool,
bottom: PropTypes.bool,
top: PropTypes.bool,
getStyle: PropTypes.func.isRequired
};
static defaultProps = {
getStyle: getDefaultStyle
getStyle: () => ({}),
panelState: {
position: 'right',
isVisible: true
},
visibleOnLoad: true,
position: 'right',
dimMode: 'none'
};
componentWillMount() {
const { panelState, visibleOnLoad, position } = this.props;
this.props.setPanelState({
...panelState,
isVisible: visibleOnLoad,
position: position
});
}
componentDidMount() {
if (typeof window !== 'undefined') {
window.addEventListener('keydown', this.handleKeyPress);
}
}
componentWillUnmount() {
if (typeof window !== 'undefined') {
window.removeEventListener('keydown', this.handleKeyPress);
}
}
render() {
const { getStyle, dimMode, panelState: { position, isVisible } } = this.props;
return (
<div style={{...this.props.getStyle(this.props), ...this.props.style}}>
<Dock style={{...getStyle(this.props)}}
{...{ dimMode, position, isVisible }}>
{this.props.children}
</div>
</Dock>
);
}
handleKeyPress = event => {
const { panelState } = this.props;
if (event.ctrlKey && event.keyCode === 72) { // Ctrl+H
event.preventDefault();
this.props.setPanelState({
...panelState,
isVisible: !panelState.isVisible
});
} else if (event.ctrlKey && event.keyCode === 68) { // Ctrl+D
event.preventDefault();
const positionIdx = POSITIONS.indexOf(panelState.position);
this.props.setPanelState({
...panelState,
position: POSITIONS[(positionIdx + 1) % POSITIONS.length]
});
}
}
}

View File

@ -33,17 +33,9 @@ const styles = {
};
export default class LogMonitor extends Component {
constructor(props) {
super(props);
if (typeof window !== 'undefined') {
window.addEventListener('keydown', ::this.handleKeyPress);
}
}
static propTypes = {
computedStates: PropTypes.array.isRequired,
currentStateIndex: PropTypes.number.isRequired,
monitorState: PropTypes.object.isRequired,
stagedActions: PropTypes.array.isRequired,
skippedActions: PropTypes.object.isRequired,
reset: PropTypes.func.isRequired,
@ -52,16 +44,12 @@ export default class LogMonitor extends Component {
sweep: PropTypes.func.isRequired,
toggleAction: PropTypes.func.isRequired,
jumpToState: PropTypes.func.isRequired,
setMonitorState: PropTypes.func.isRequired,
select: PropTypes.func.isRequired,
visibleOnLoad: PropTypes.bool
select: PropTypes.func.isRequired
};
static defaultProps = {
select: (state) => state,
monitorState: { isVisible: true },
theme: 'nicinabox',
visibleOnLoad: true
theme: 'nicinabox'
};
componentWillReceiveProps(nextProps) {
@ -93,15 +81,6 @@ export default class LogMonitor extends Component {
}
}
componentWillMount() {
let visibleOnLoad = this.props.visibleOnLoad;
const { monitorState } = this.props;
this.props.setMonitorState({
...monitorState,
isVisible: visibleOnLoad
});
}
handleRollback() {
this.props.rollback();
}
@ -122,21 +101,9 @@ export default class LogMonitor extends Component {
this.props.reset();
}
handleKeyPress(event) {
const { monitorState } = this.props;
if (event.ctrlKey && event.keyCode === 72) { // Ctrl+H
event.preventDefault();
this.props.setMonitorState({
...monitorState,
isVisible: !monitorState.isVisible
});
}
}
render() {
const elements = [];
const { monitorState, skippedActions, stagedActions, computedStates, select } = this.props;
const { skippedActions, stagedActions, computedStates, select } = this.props;
let theme;
if (typeof this.props.theme === 'string') {
if (typeof themes[this.props.theme] !== 'undefined') {
@ -148,10 +115,6 @@ export default class LogMonitor extends Component {
} else {
theme = this.props.theme;
}
if (!monitorState.isVisible) {
return null;
}
for (let i = 0; i < stagedActions.length; i++) {
const action = stagedActions[i];
const { state, error } = computedStates[i];

View File

@ -3,4 +3,3 @@ import createDevTools from '../createDevTools';
export const DevTools = createDevTools(React);
export { default as LogMonitor } from './LogMonitor';
export { default as DebugPanel } from './DebugPanel';