mirror of
https://github.com/coaidev/coai.git
synced 2025-05-30 02:10:25 +09:00
add error catching feature
This commit is contained in:
parent
a8b3f6cc7c
commit
c65051b1d9
@ -117,3 +117,37 @@ strong {
|
||||
.cent {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
.error-boundary {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: max-content;
|
||||
min-height: calc(100vh - 56px);
|
||||
overflow: hidden;
|
||||
background: hsl(var(--background-container));
|
||||
padding: 2.5rem 5rem;
|
||||
|
||||
@media (max-width: 720px) {
|
||||
& {
|
||||
padding: 2.5rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error-provider {
|
||||
text-align: center;
|
||||
margin: 0.5rem auto;
|
||||
|
||||
p {
|
||||
margin: 0.35rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error-tips {
|
||||
text-align: center;
|
||||
padding: 1rem 2rem;
|
||||
color: hsl(var(--text-secondary));
|
||||
}
|
||||
}
|
||||
|
71
app/src/components/ErrorBoundary.tsx
Normal file
71
app/src/components/ErrorBoundary.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import React from "react";
|
||||
import { AlertCircle, Download } from "lucide-react";
|
||||
import { withTranslation, WithTranslation } from "react-i18next";
|
||||
import { version } from "@/conf.ts";
|
||||
import { getMemoryPerformance } from "@/utils/app.ts";
|
||||
import { Button } from "@/components/ui/button.tsx";
|
||||
import { saveAsFile } from "@/utils/dom.ts";
|
||||
|
||||
type ErrorBoundaryProps = { children: React.ReactNode } & WithTranslation;
|
||||
|
||||
class ErrorBoundary extends React.Component<
|
||||
ErrorBoundaryProps,
|
||||
{ errorCaught: Error | null }
|
||||
> {
|
||||
constructor(props: ErrorBoundaryProps) {
|
||||
super(props);
|
||||
this.state = { errorCaught: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error) {
|
||||
return { errorCaught: error };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const ua = navigator.userAgent || "unknown";
|
||||
const memory = getMemoryPerformance();
|
||||
const time = new Date().toLocaleString();
|
||||
const stamp = new Date().getTime();
|
||||
const path = window.location.pathname;
|
||||
|
||||
const message = `Raised-Path: ${path}\nApp-Version: ${version}\nMemory-Usage: ${
|
||||
!isNaN(memory) ? memory.toFixed(2) + " MB" : "unknown"
|
||||
}\nLocale-Time: ${time}\nError-Message: ${
|
||||
this.state.errorCaught?.message || "unknown"
|
||||
}\nUser-Agent: ${ua}\nStack-Trace: ${
|
||||
this.state.errorCaught?.stack || "unknown"
|
||||
}`;
|
||||
|
||||
return this.state.errorCaught ? (
|
||||
<div className={`error-boundary`}>
|
||||
<AlertCircle className={`h-12 w-12 mt-4 mb-6`} />
|
||||
<p className={`select-none text-2xl mb-4`}>{t("fatal")}</p>
|
||||
<div className={`error-provider`}>
|
||||
<p>Raised-Path: {path}</p>
|
||||
<p>App-Version: {version}</p>
|
||||
<p>
|
||||
Memory-Usage:{" "}
|
||||
{!isNaN(memory) ? memory.toFixed(2) + " MB" : "unknown"}
|
||||
</p>
|
||||
<p>Locale-Time: {time}</p>
|
||||
<p>Error-Message: {this.state.errorCaught.message}</p>
|
||||
<p>User-Agent: {ua}</p>
|
||||
</div>
|
||||
<div className={`error-action mt-4 mb-4`}>
|
||||
<Button onClick={() => saveAsFile(`error-${stamp}.log`, message)}>
|
||||
<Download className={`h-4 w-4 mr-2`} />
|
||||
{t("download-fatal-log")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={`error-tips select-none align-center`}>
|
||||
<p>{t("fatal-tips")}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
this.props.children
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTranslation()(ErrorBoundary);
|
@ -1,6 +1,7 @@
|
||||
import { Message } from "@/api/types.ts";
|
||||
import Markdown from "@/components/Markdown.tsx";
|
||||
import {
|
||||
CircleSlash,
|
||||
Cloud,
|
||||
CloudFog,
|
||||
Copy,
|
||||
@ -77,6 +78,8 @@ function MessageContent({ message, end, onEvent }: MessageProps) {
|
||||
<div className={`message-content`}>
|
||||
{message.content.length ? (
|
||||
<Markdown children={message.content} />
|
||||
) : message.end === true ? (
|
||||
<CircleSlash className={`h-5 w-5 m-1`} />
|
||||
) : (
|
||||
<Loader2 className={`h-5 w-5 m-1 animate-spin`} />
|
||||
)}
|
||||
|
@ -34,6 +34,10 @@ const resources = {
|
||||
unknown: "未知",
|
||||
"scroll-down": "滚至最新",
|
||||
broadcast: "公告",
|
||||
fatal: "应用崩溃",
|
||||
"download-fatal-log": "下载错误日志",
|
||||
"fatal-tips":
|
||||
"请您先检查您的网络,浏览器兼容性,尝试清除浏览器缓存并刷新页面。如果问题仍然存在,请将日志提供给开发者以便我们排查问题。",
|
||||
tag: {
|
||||
free: "免费",
|
||||
official: "官方",
|
||||
@ -370,6 +374,10 @@ const resources = {
|
||||
unknown: "Unknown",
|
||||
"scroll-down": "Scroll to latest",
|
||||
broadcast: "Broadcast",
|
||||
fatal: "App crashed",
|
||||
"download-fatal-log": "Download error log",
|
||||
"fatal-tips":
|
||||
"Please try to check your network, browser compatibility, try to clear the browser cache and refresh the page. If the problem still exists, please provide the log to the developer so that we can troubleshoot the problem.",
|
||||
tag: {
|
||||
free: "Free",
|
||||
official: "Official",
|
||||
@ -722,6 +730,10 @@ const resources = {
|
||||
unknown: "Неизвестный",
|
||||
"scroll-down": "Прокрутите вниз",
|
||||
broadcast: "Объявление",
|
||||
fatal: "Приложение вылетело",
|
||||
"download-fatal-log": "Скачать журнал ошибок",
|
||||
"fatal-tips":
|
||||
"Пожалуйста, попробуйте проверить свою сеть, совместимость браузера, попробуйте очистить кэш браузера и обновить страницу. Если проблема все еще существует, пожалуйста, предоставьте журнал разработчику, чтобы мы могли устранить проблему.",
|
||||
tag: {
|
||||
free: "Бесплатно",
|
||||
official: "Официальный",
|
||||
|
@ -5,15 +5,18 @@ import SideBar from "@/components/home/SideBar.tsx";
|
||||
import { useSelector } from "react-redux";
|
||||
import { selectMarket } from "@/store/chat.ts";
|
||||
import ModelMarket from "@/components/home/ModelMarket.tsx";
|
||||
import ErrorBoundary from "@/components/ErrorBoundary.tsx";
|
||||
|
||||
function Home() {
|
||||
const market = useSelector(selectMarket);
|
||||
|
||||
return (
|
||||
<div className={`main`}>
|
||||
<SideBar />
|
||||
{market ? <ModelMarket /> : <ChatWrapper />}
|
||||
</div>
|
||||
<ErrorBoundary>
|
||||
<div className={`main`}>
|
||||
<SideBar />
|
||||
{market ? <ModelMarket /> : <ChatWrapper />}
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user