mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-14 02:46:37 +08:00
feat(web): improve zone domain list and detail navigation
合并 Zone 域名与路由展示,上游地址多行显示并支持路由详情跳转; 域名列表对齐用户管理页样式;Zone 页支持 ?tab= 定位;反代详情返回 使用浏览器历史上一级。
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import {useState} from 'react';
|
||||
import {usePathname, useRouter, useSearchParams} from 'next/navigation';
|
||||
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';
|
||||
@@ -20,21 +21,53 @@ import {Button} from '@/components/ui/button';
|
||||
import {EmptyStateWithBorder} from '@/components/layout/empty';
|
||||
import {LoadingStateWithBorder} from '@/components/layout/loading';
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs';
|
||||
import {TlsCertificateService, ZoneService, zoneQueryKey} from '@/lib/services/openflare';
|
||||
import {
|
||||
ProxyRouteService,
|
||||
TlsCertificateService,
|
||||
ZoneService,
|
||||
zoneQueryKey,
|
||||
} from '@/lib/services/openflare';
|
||||
|
||||
import {getErrorMessage} from '../components/website-utils';
|
||||
import {ZoneCertificatesPanel} from './components/zone-certificates';
|
||||
import {ZoneDomainsTable} from './components/zone-domains-table';
|
||||
import {ZoneEditorDialog} from './components/zone-editor-dialog';
|
||||
import {ZoneOverviewPanel} from './components/zone-overview';
|
||||
import {ZoneRouteSummary} from './components/zone-route-summary';
|
||||
|
||||
const zoneTabs = ['overview', 'domains', 'certificates', 'settings'] as const;
|
||||
export type ZonePageTab = (typeof zoneTabs)[number];
|
||||
|
||||
function getZonePageTab(value: string | null | undefined): ZonePageTab {
|
||||
return zoneTabs.includes(value as ZonePageTab) ? (value as ZonePageTab) : 'overview';
|
||||
}
|
||||
|
||||
export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const queryClient = useQueryClient();
|
||||
const [activeTab, setActiveTab] = useState('overview');
|
||||
const activeTab = useMemo(
|
||||
() => getZonePageTab(searchParams.get('tab')),
|
||||
[searchParams],
|
||||
);
|
||||
const [editZone, setEditZone] = useState(false);
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
|
||||
const setActiveTab = useCallback(
|
||||
(tab: string) => {
|
||||
const next = getZonePageTab(tab);
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (next === 'overview') {
|
||||
params.delete('tab');
|
||||
} else {
|
||||
params.set('tab', next);
|
||||
}
|
||||
const query = params.toString();
|
||||
router.replace(query ? `${pathname}?${query}` : pathname, {scroll: false});
|
||||
},
|
||||
[pathname, router, searchParams],
|
||||
);
|
||||
|
||||
const overviewQuery = useQuery({
|
||||
queryKey: [...zoneQueryKey, zoneId],
|
||||
queryFn: () => ZoneService.getOverview(zoneId),
|
||||
@@ -47,6 +80,12 @@ export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
enabled: overviewQuery.isSuccess,
|
||||
});
|
||||
|
||||
const routesQuery = useQuery({
|
||||
queryKey: ['openflare', 'proxy-routes'],
|
||||
queryFn: () => ProxyRouteService.list(),
|
||||
enabled: overviewQuery.isSuccess,
|
||||
});
|
||||
|
||||
const deleteZone = useMutation({
|
||||
mutationFn: () => ZoneService.deleteById(zoneId),
|
||||
onSuccess: async () => {
|
||||
@@ -95,6 +134,7 @@ export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
|
||||
const overview = overviewQuery.data;
|
||||
const certificates = certificatesQuery.data ?? [];
|
||||
const routes = routesQuery.data ?? [];
|
||||
const boundCertCount = new Set(
|
||||
overview.domains.map((domain) => domain.cert_id).filter((id): id is number => id != null),
|
||||
).size;
|
||||
@@ -145,9 +185,6 @@ export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
<TabsTrigger value="domains" className="px-0 pb-2 text-xs font-semibold">
|
||||
域名 ({overview.domains.length})
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="routes" className="px-0 pb-2 text-xs font-semibold">
|
||||
路由
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="certificates" className="px-0 pb-2 text-xs font-semibold">
|
||||
证书 ({boundCertCount})
|
||||
</TabsTrigger>
|
||||
@@ -164,12 +201,11 @@ export function ZonePageClient({zoneId}: {zoneId: number}) {
|
||||
zoneId={zoneId}
|
||||
domains={overview.domains}
|
||||
certificates={certificates}
|
||||
routes={routes}
|
||||
routesLoading={routesQuery.isLoading}
|
||||
onChanged={() => overviewQuery.refetch()}
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="routes">
|
||||
<ZoneRouteSummary domains={overview.domains} />
|
||||
</TabsContent>
|
||||
<TabsContent value="certificates">
|
||||
<ZoneCertificatesPanel domains={overview.domains} certificates={certificates} />
|
||||
</TabsContent>
|
||||
|
||||
Reference in New Issue
Block a user