import { Button, Flex, Heading, Image, Link, Text } from '@invoke-ai/ui-library'; import { createSelector } from '@reduxjs/toolkit'; import { useAppSelector } from 'app/store/storeHooks'; import { useClipboard } from 'common/hooks/useClipboard'; import { selectConfigSlice } from 'features/system/store/configSlice'; import { toast } from 'features/toast/toast'; import newGithubIssueUrl from 'new-github-issue-url'; import InvokeLogoYellow from 'public/assets/images/invoke-symbol-ylw-lrg.svg'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { PiArrowCounterClockwiseBold, PiArrowSquareOutBold, PiCopyBold } from 'react-icons/pi'; import { serializeError } from 'serialize-error'; type Props = { error: Error; resetErrorBoundary: () => void; }; const selectIsLocal = createSelector(selectConfigSlice, (config) => config.isLocal); const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => { const { t } = useTranslation(); const isLocal = useAppSelector(selectIsLocal); const clipboard = useClipboard(); const handleCopy = useCallback(() => { const text = JSON.stringify(serializeError(error), null, 2); clipboard.writeText(`\`\`\`\n${text}\n\`\`\``, () => { toast({ id: 'ERROR_COPIED', title: t('toast.errorCopied'), }); }); }, [clipboard, error, t]); const url = useMemo(() => { if (isLocal) { return newGithubIssueUrl({ user: 'invoke-ai', repo: 'InvokeAI', template: 'BUG_REPORT.yml', title: `[bug]: ${error.name}: ${error.message}`, }); } else { return 'https://support.invoke.ai/support/tickets/new'; } }, [error.message, error.name, isLocal]); return ( invoke-logo {t('common.somethingWentWrong')} {error.name}: {error.message} ); }; export default memo(AppErrorBoundaryFallback);