You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
8.3 KiB
TypeScript
225 lines
8.3 KiB
TypeScript
// Copyright (C) 2020-2021 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import './styles.scss';
|
|
import React from 'react';
|
|
import { connect } from 'react-redux';
|
|
import Result from 'antd/lib/result';
|
|
import Text from 'antd/lib/typography/Text';
|
|
import Paragraph from 'antd/lib/typography/Paragraph';
|
|
import Collapse from 'antd/lib/collapse';
|
|
import TextArea from 'antd/lib/input/TextArea';
|
|
import copy from 'copy-to-clipboard';
|
|
import ErrorStackParser from 'error-stack-parser';
|
|
|
|
import { ThunkDispatch } from 'utils/redux';
|
|
import { resetAfterErrorAsync } from 'actions/boundaries-actions';
|
|
import { CombinedState } from 'reducers/interfaces';
|
|
import logger, { LogType } from 'cvat-logger';
|
|
import CVATTooltip from 'components/common/cvat-tooltip';
|
|
import consts from 'consts';
|
|
|
|
interface OwnProps {
|
|
children: JSX.Element;
|
|
}
|
|
|
|
interface StateToProps {
|
|
job: any | null;
|
|
serverVersion: string;
|
|
coreVersion: string;
|
|
canvasVersion: string;
|
|
uiVersion: string;
|
|
}
|
|
|
|
interface DispatchToProps {
|
|
restore(): void;
|
|
}
|
|
|
|
interface State {
|
|
hasError: boolean;
|
|
error: Error | null;
|
|
}
|
|
|
|
function mapStateToProps(state: CombinedState): StateToProps {
|
|
const {
|
|
annotation: {
|
|
job: { instance: job },
|
|
},
|
|
about: { server, packageVersion },
|
|
} = state;
|
|
|
|
return {
|
|
job,
|
|
serverVersion: server.version as string,
|
|
coreVersion: packageVersion.core,
|
|
canvasVersion: packageVersion.canvas,
|
|
uiVersion: packageVersion.ui,
|
|
};
|
|
}
|
|
|
|
function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps {
|
|
return {
|
|
restore(): void {
|
|
dispatch(resetAfterErrorAsync());
|
|
},
|
|
};
|
|
}
|
|
|
|
type Props = StateToProps & DispatchToProps & OwnProps;
|
|
class GlobalErrorBoundary extends React.PureComponent<Props, State> {
|
|
public constructor(props: Props) {
|
|
super(props);
|
|
this.state = {
|
|
hasError: false,
|
|
error: null,
|
|
};
|
|
}
|
|
|
|
static getDerivedStateFromError(error: Error): State {
|
|
return {
|
|
hasError: true,
|
|
error,
|
|
};
|
|
}
|
|
|
|
public componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
|
|
const { job } = this.props;
|
|
const parsed = ErrorStackParser.parse(error);
|
|
|
|
const logPayload = {
|
|
filename: parsed[0].fileName,
|
|
line: parsed[0].lineNumber,
|
|
message: error.message,
|
|
column: parsed[0].columnNumber,
|
|
stack: error.stack,
|
|
componentStack: errorInfo.componentStack,
|
|
};
|
|
|
|
if (job) {
|
|
job.logger.log(LogType.sendException, logPayload);
|
|
} else {
|
|
logger.log(LogType.sendException, logPayload);
|
|
}
|
|
}
|
|
|
|
public render(): React.ReactNode {
|
|
const {
|
|
restore, job, serverVersion, coreVersion, canvasVersion, uiVersion,
|
|
} = this.props;
|
|
|
|
const { hasError, error } = this.state;
|
|
|
|
const restoreGlobalState = (): void => {
|
|
this.setState({
|
|
error: null,
|
|
hasError: false,
|
|
});
|
|
|
|
restore();
|
|
};
|
|
|
|
if (hasError && error) {
|
|
const message = `${error.name}\n${error.message}\n\n${error.stack}`;
|
|
return (
|
|
<div className='cvat-global-boundary'>
|
|
<Result
|
|
status='error'
|
|
title='Oops, something went wrong'
|
|
subTitle='More likely there are some issues with the tool'
|
|
>
|
|
<div>
|
|
<Paragraph>
|
|
<Paragraph strong>What has happened?</Paragraph>
|
|
<Paragraph>Program error has just occurred</Paragraph>
|
|
<Collapse accordion>
|
|
<Collapse.Panel header='Error message' key='errorMessage'>
|
|
<Text type='danger'>
|
|
<TextArea
|
|
className='cvat-global-boundary-error-field'
|
|
autoSize
|
|
value={message}
|
|
/>
|
|
</Text>
|
|
</Collapse.Panel>
|
|
</Collapse>
|
|
</Paragraph>
|
|
|
|
<Paragraph>
|
|
<Text strong>What should I do?</Text>
|
|
</Paragraph>
|
|
<ul>
|
|
<li>
|
|
<CVATTooltip title='Copied!' trigger='click'>
|
|
{/* eslint-disable-next-line */}
|
|
<a
|
|
onClick={() => {
|
|
copy(message);
|
|
}}
|
|
>
|
|
{' '}
|
|
Copy
|
|
{' '}
|
|
</a>
|
|
</CVATTooltip>
|
|
the error message to clipboard
|
|
</li>
|
|
<li>
|
|
Notify an administrator or submit the issue directly on
|
|
<a href={consts.GITHUB_URL}> GitHub. </a>
|
|
Please, provide also:
|
|
<ul>
|
|
<li>Steps to reproduce the issue</li>
|
|
<li>Your operating system and browser version</li>
|
|
<li>CVAT version</li>
|
|
<ul>
|
|
<li>
|
|
<Text strong>Server: </Text>
|
|
{serverVersion}
|
|
</li>
|
|
<li>
|
|
<Text strong>Core: </Text>
|
|
{coreVersion}
|
|
</li>
|
|
<li>
|
|
<Text strong>Canvas: </Text>
|
|
{canvasVersion}
|
|
</li>
|
|
<li>
|
|
<Text strong>UI: </Text>
|
|
{uiVersion}
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
</li>
|
|
{job ? (
|
|
<li>
|
|
Press
|
|
{/* eslint-disable-next-line */}
|
|
<a onClick={restoreGlobalState}> here </a>
|
|
if you wish CVAT tried to restore your annotation progress or
|
|
{/* eslint-disable-next-line */}
|
|
<a onClick={() => window.location.reload()}> update </a>
|
|
the page
|
|
</li>
|
|
) : (
|
|
<li>
|
|
{/* eslint-disable-next-line */}
|
|
<a onClick={() => window.location.reload()}>Update </a>
|
|
the page
|
|
</li>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
</Result>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const { children } = this.props;
|
|
return children;
|
|
}
|
|
}
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(GlobalErrorBoundary);
|