修复codereview复核确认的多选/转发/收藏页/资料页等前端bug
- 多选模式下Drafty链接、名片消息不再意外触发跳转/开新标签页 - 语音/视频消息在多选模式下点击可正常冒泡选中该行 - 转发排除未确认/发送失败消息,识别uncertain转发结果并单独提示 - 群文件"更多操作"菜单竞态、群成员移出状态竞态 - 收藏页链接卡片new URL()崩溃点加防御,并给登录后应用区域加错误边界 - 个人资料页乐观锁版本冲突时清空草稿避免静默覆盖并发修改 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e3eed8bdd4
commit
9abae5030b
+27
-1
@@ -1,9 +1,10 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { Navigate, createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
import { Navigate, createBrowserRouter, RouterProvider, useRouteError } from 'react-router-dom';
|
||||
|
||||
import { AppShell } from '@/app/AppShell';
|
||||
import { ConfirmDialogRoot } from '@/app/ConfirmDialogRoot';
|
||||
import { GlobalToastRoot } from '@/app/GlobalToastRoot';
|
||||
import { Icon } from '@/app/Icon';
|
||||
import { KickedNoticeRoot } from '@/app/KickedNoticeRoot';
|
||||
import { RequireAuth } from '@/app/RequireAuth';
|
||||
import { SecurityChallengeModal } from '@/app/SecurityChallengeModal';
|
||||
@@ -34,6 +35,30 @@ import { SystemMessagesView } from '@/features/system/SystemMessagesView';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
/**
|
||||
* Without this, an uncaught render-time exception ANYWHERE under `<AppShell>` (any page, any one
|
||||
* bad field in server data) falls through to react-router's own built-in default error boundary --
|
||||
* real, not hypothetical (confirmed live: `node_modules/react-router` DOES implicitly wrap the
|
||||
* outermost matched route the way this codebase never configured one to). That default shows
|
||||
* "Unexpected Application Error!" plus the raw error message/stack to the end user and replaces the
|
||||
* WHOLE logged-in shell, sidebar included, with no way back except a full page reload. Attached to
|
||||
* AppShell (not each leaf route) so it covers every authenticated page with one component, and low
|
||||
* enough that `RequireAuth`/login/tenant-entry are never affected by a bug in, say, 收藏.
|
||||
*/
|
||||
function RouteErrorBoundary() {
|
||||
const error = useRouteError();
|
||||
if (import.meta.env.DEV) console.error(error);
|
||||
return (
|
||||
<div className="flex h-dvh w-full flex-col items-center justify-center gap-3 bg-surface-page px-6 text-center">
|
||||
<Icon name="error_outline" className="text-[40px] text-text-tertiary-3" />
|
||||
<p className="text-sm text-text-secondary">页面出现异常,请刷新重试</p>
|
||||
<button type="button" onClick={() => window.location.reload()} className="rounded-lg bg-accent px-4 py-2 text-sm text-white">
|
||||
刷新页面
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{ path: 'tenant', element: <TenantEntryPage /> },
|
||||
{ path: 'login', element: <LoginPage /> },
|
||||
@@ -45,6 +70,7 @@ const router = createBrowserRouter([
|
||||
children: [
|
||||
{
|
||||
element: <AppShell />,
|
||||
errorElement: <RouteErrorBoundary />,
|
||||
children: [
|
||||
{ index: true, element: <Navigate to="/messages" replace /> },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user