mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 05:56:38 +08:00
fix(frontend): dynamically import zone dashboard with ssr: false to cure hydration mismatch
- Dynamically import `ZonePageClient` with `ssr: false` in `websites/[zoneId]/page.tsx`. - Remove `generateStaticParams` to prevent dynamic paths from building with inconsistent SSG/ISR outputs. - Remove redundant `mounted` check from `page-client.tsx` since dashboard is client-only. - Add `bytes_sent` to `NodeAccessLog` on both Agent and Master Server. - Create ClickHouse migration `202607120001_add_bytes_sent_to_node_access_logs.sql`. - Refactor duplicate stats structs by centralizing them into `analyticsmodel` package with type aliases. - Simplify access log store delegations and remove redundant mapping loops. - Support full console menu display management in settings other-tab. - Regenerate Swagger documentation. - Update changelog index.md.
This commit is contained in:
@@ -23,7 +23,6 @@ sidebar: false
|
||||
|
||||
### 新增
|
||||
|
||||
- 边缘访问日志 `of_node_access_logs` ClickHouse 表新增 `bytes_sent` 字段并打通 Agent 到 Server 的上报和 Zone 统计显示逻辑。
|
||||
- Zone 概览页新增 Cloudflare 风格流量图:支持 24 小时 / 7 天 / 30 天,展示唯一访问者、请求总数与已提供数据趋势。
|
||||
- 新增第一阶段 Zone 与正规化 Zone 域名数据库表及路由绑定模型,为后续以稳定 ID 管理网站与域名关联提供基础。
|
||||
- 新增 Zone 管理 API 与显式历史域名导入命令,使用公共后缀列表验证注册根域和域名归属。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import {usePathname, useRouter, useSearchParams} from 'next/navigation';
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {useCallback, useMemo, useState} from 'react';
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import {ArrowLeft, Globe, Pencil, Trash2} from 'lucide-react';
|
||||
import {toast} from 'sonner';
|
||||
@@ -41,10 +41,6 @@ function getZonePageTab(value: string | null | undefined): ZonePageTab {
|
||||
}
|
||||
|
||||
export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
@@ -100,13 +96,7 @@ export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
});
|
||||
|
||||
if (!mounted) {
|
||||
return (
|
||||
<div className="py-6 px-1">
|
||||
<LoadingStateWithBorder icon={Globe} description="加载 Zone 详情中..." />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!Number.isInteger(zoneId) || zoneId <= 0) {
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import {Suspense} from 'react'
|
||||
import {Globe} from 'lucide-react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import {LoadingStateWithBorder} from '@/components/layout/loading'
|
||||
import {ZonePageClient} from './page-client'
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return [{zoneId: '1'}];
|
||||
}
|
||||
const ZonePageClient = dynamic(
|
||||
() => import('./page-client').then((mod) => mod.ZonePageClient),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="py-6 px-1">
|
||||
<LoadingStateWithBorder icon={Globe} description="加载 Zone 详情中..." />
|
||||
</div>
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
export default async function ZonePage({params}: PageProps<'/websites/[zoneId]'>) {
|
||||
const {zoneId} = await params
|
||||
|
||||
Reference in New Issue
Block a user