Files
pybricks-code/src/alerts/UnexpectedErrorAlert.tsx
T
David Lechner dd322b5aac tree-wide: use noopener instead of noreferrer for target="_blank"
This will allow us to see when users click links to the pybricks.com
website from the app.
2022-12-20 12:09:04 -06:00

89 lines
2.8 KiB
TypeScript

// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import './UnexpectedErrorAlert.scss';
import {
AnchorButton,
Button,
ButtonGroup,
Collapse,
Intent,
Pre,
} from '@blueprintjs/core';
import React, { useState } from 'react';
import { useId } from 'react-aria';
import type { CreateToast } from '../toasterTypes';
import { useI18n } from './i18n';
type UnexpectedErrorAlertProps = {
error: Error;
};
const UnexpectedErrorAlert: React.VoidFunctionComponent<UnexpectedErrorAlertProps> = ({
error,
}) => {
const i18n = useI18n();
const [isExpanded, setIsExpanded] = useState(false);
const labelId = useId();
return (
<>
<p>{i18n.translate('message')}</p>
<p>{error.message}</p>
{error.stack && (
<>
<span>
<Button
aria-labelledby={labelId}
minimal={true}
small={true}
icon={isExpanded ? 'chevron-down' : 'chevron-right'}
onClick={() => setIsExpanded((v) => !v)}
/>
<span id={labelId}>{i18n.translate('technicalInfo')}</span>
</span>
<Collapse isOpen={isExpanded}>
<Pre className="pb-alerts-stack-trace">{error.stack}</Pre>
</Collapse>
</>
)}
<div>
<ButtonGroup minimal={true} fill={true}>
<Button
intent={Intent.DANGER}
icon="duplicate"
onClick={() =>
navigator.clipboard.writeText(
`\`\`\`\n${error.stack || error.message}\n\`\`\``,
)
}
>
{i18n.translate('copyErrorMessage')}
</Button>
<AnchorButton
intent={Intent.DANGER}
icon="virus"
href={`https://github.com/pybricks/support/issues?q=${encodeURIComponent(
'is:issue',
)}+${encodeURIComponent(error.message)}`}
target="_blank"
rel="noopener"
>
{i18n.translate('reportBug')}
</AnchorButton>
</ButtonGroup>
</div>
</>
);
};
export const unexpectedError: CreateToast<{ error: Error }> = (
onAction,
{ error },
) => ({
message: <UnexpectedErrorAlert error={error} />,
icon: 'error',
intent: Intent.DANGER,
onDismiss: () => onAction('dismiss'),
});