diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx
index b558a7f4..8cf26c0c 100644
--- a/apps/web/src/app/[locale]/page.tsx
+++ b/apps/web/src/app/[locale]/page.tsx
@@ -26,6 +26,7 @@ import { HostGrid, type HostInfo, type HostService } from '@/components/infra/ho
import { AppLayout } from '@/components/layout'
import { PageTabs, type TabConfig } from '@/components/layout/page-tabs'
import { LobsterLoading } from '@/components/shared/lobster-loading'
+import { ServiceTopology } from '@/components/topology'
const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? ''
@@ -736,6 +737,7 @@ export default function Home({ params }: { params: { locale: string } }) {
// Sprint 5: 從 URL 讀取當前 Tab
const [activeTabId, setActiveTabId] = useState('overview')
+ const [infraView, setInfraView] = useState<'host' | 'topo'>('host')
// 每 100ms 檢查 URL query 變化(PageTabs 用 router.push 更新)
useEffect(() => {
@@ -964,7 +966,7 @@ export default function Home({ params }: { params: { locale: string } }) {
/>
- {/* 基礎架構 Grid */}
+ {/* 基礎架構 — Toggle: 拓撲圖 / 主機網格 */}
{tDashboard('infrastructure')}
+ {/* Toggle 切換 */}
+
+
+
+
- {
- const apiHosts = hosts.map(h =>
- buildHostInfo(h.ip, h.name, h.metrics?.cpu_percent ?? null, h.metrics?.memory_percent ?? null, h.services)
- )
- // K3s #2 (121) 若 API 未回傳,補靜態卡
- const has121 = apiHosts.some(h => h.ip === '192.168.0.121')
- if (!has121) {
- apiHosts.push(buildHostInfo('192.168.0.121', 'K3s Server #2', null, null, []))
- }
- return apiHosts
- })()} />
+ {/* 主機網格 (預設) */}
+ {infraView === 'host' && (
+ {
+ const apiHosts = hosts.map(h =>
+ buildHostInfo(h.ip, h.name, h.metrics?.cpu_percent ?? null, h.metrics?.memory_percent ?? null, h.services)
+ )
+ const has121 = apiHosts.some(h => h.ip === '192.168.0.121')
+ if (!has121) {
+ apiHosts.push(buildHostInfo('192.168.0.121', 'K3s Server #2', null, null, []))
+ }
+ return apiHosts
+ })()} />
+ )}
+ {/* 拓撲圖 (React Flow) */}
+ {infraView === 'topo' && (
+
+
+
+ )}
{/* 監控工具 — figma-v2 style: 左彩色條 + 可點擊 + meta行 */}