redux-devtools/packages/redux-devtools-inspector-monitor-trace-tab/src/StackTraceTab.tsx

157 lines
4.3 KiB
TypeScript
Raw Normal View History

2019-01-10 20:23:33 +03:00
import React, { Component } from 'react';
2019-01-10 21:51:14 +03:00
import { getStackFrames } from './react-error-overlay/utils/getStackFrames';
2018-12-12 19:34:22 +03:00
import StackTrace from './react-error-overlay/containers/StackTrace';
2018-12-15 04:04:34 +03:00
import openFile from './openFile';
import { Action } from 'redux';
import { TabComponentProps } from '@redux-devtools/inspector-monitor';
import StackFrame from './react-error-overlay/utils/stack-frame';
import { ErrorLocation } from './react-error-overlay/utils/parseCompileError';
2019-01-10 21:51:14 +03:00
const rootStyle = { padding: '5px 10px' };
interface Props<S, A extends Action<unknown>> extends TabComponentProps<S, A> {
openFile: (
fileName: string,
lineNumber: number,
stackFrame: StackFrame
) => void;
}
interface State {
stackFrames: StackFrame[];
currentError?: Error;
showDocsLink?: boolean;
}
export default class StackTraceTab<
S,
A extends Action<unknown>
> extends Component<Props<S, A>, State> {
static defaultProps = {
openFile,
2019-02-07 03:10:24 +03:00
};
2018-12-12 19:34:22 +03:00
state: State = {
stackFrames: [],
};
2018-12-12 19:34:22 +03:00
componentDidMount() {
2018-12-12 23:45:37 +03:00
// console.log("StackTraceTab mounted");
2018-12-12 19:34:22 +03:00
this.checkForStackTrace();
}
componentDidUpdate(prevProps: Props<S, A>) {
2019-01-10 21:51:14 +03:00
const { action, actions } = prevProps;
2019-01-10 21:51:14 +03:00
if (action !== this.props.action || actions !== this.props.actions) {
2018-12-12 19:34:22 +03:00
this.checkForStackTrace();
}
2018-12-12 19:34:22 +03:00
}
2018-12-12 19:34:22 +03:00
checkForStackTrace() {
2019-01-10 21:51:14 +03:00
const { action, actions: liftedActionsById } = this.props;
2019-01-10 21:51:14 +03:00
if (!action) {
2018-12-12 19:34:22 +03:00
return;
}
2018-12-12 19:34:22 +03:00
const liftedActions = Object.values(liftedActionsById);
2019-01-10 21:51:14 +03:00
const liftedAction = liftedActions.find(
(liftedAction) => liftedAction.action === action
2019-01-10 21:51:14 +03:00
);
if (liftedAction && typeof liftedAction.stack === 'string') {
const deserializedError = Object.assign(new Error(), {
stack: liftedAction.stack,
2019-01-10 21:51:14 +03:00
});
getStackFrames(deserializedError)
.then((stackFrames) => {
/* eslint-disable no-console */
if (process.env.NODE_ENV === 'development')
console.log('Stack frames: ', stackFrames);
/* eslint-enable no-console */
this.setState({
stackFrames: stackFrames!,
currentError: deserializedError,
});
})
.catch(() => {
// noop
});
2019-01-10 21:51:14 +03:00
} else {
this.setState({
stackFrames: [],
2019-01-10 21:51:14 +03:00
showDocsLink:
liftedAction!.action &&
liftedAction!.action.type &&
liftedAction!.action.type !== '@@INIT',
});
2018-12-12 19:34:22 +03:00
}
}
onStackLocationClicked = (fileLocation: Partial<ErrorLocation> = {}) => {
2018-12-12 23:45:37 +03:00
// console.log("Stack location args: ", ...args);
2019-01-10 21:51:14 +03:00
const { fileName, lineNumber } = fileLocation;
2019-01-10 21:51:14 +03:00
if (fileName && lineNumber) {
const matchingStackFrame = this.state.stackFrames.find((stackFrame) => {
2019-01-10 21:51:14 +03:00
const matches =
(stackFrame._originalFileName === fileName &&
stackFrame._originalLineNumber === lineNumber) ||
(stackFrame.fileName === fileName &&
stackFrame.lineNumber === lineNumber);
2018-12-12 19:34:22 +03:00
return matches;
});
2018-12-12 23:45:37 +03:00
// console.log("Matching stack frame: ", matchingStackFrame);
2019-01-10 21:51:14 +03:00
if (matchingStackFrame) {
2018-12-12 23:45:37 +03:00
/*
const frameIndex = this.state.stackFrames.indexOf(matchingStackFrame);
const originalStackFrame = parsedFramesNoSourcemaps[frameIndex];
console.log("Original stack frame: ", originalStackFrame);
*/
this.props.openFile(fileName, lineNumber, matchingStackFrame);
2018-12-12 19:34:22 +03:00
}
}
2019-01-10 21:51:14 +03:00
};
openDocs: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
e.stopPropagation();
2019-01-10 21:51:14 +03:00
window.open(
'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/Features/Trace.md'
);
};
2018-12-12 19:34:22 +03:00
render() {
2019-01-10 21:51:14 +03:00
const { stackFrames, showDocsLink } = this.state;
if (showDocsLink) {
return (
<div style={rootStyle}>
2019-01-10 21:51:14 +03:00
To enable tracing action calls, you should set `trace` option to
`true` for Redux DevTools enhancer. Refer to{' '}
<a href="#" onClick={this.openDocs}>
this page
</a>{' '}
for more details.
</div>
);
}
2018-12-12 19:34:22 +03:00
return (
2019-01-10 21:51:14 +03:00
<div style={rootStyle}>
<StackTrace
stackFrames={stackFrames}
errorName="N/A"
contextSize={3}
editorHandler={this.onStackLocationClicked}
/>
</div>
);
2018-12-12 19:34:22 +03:00
}
}