diff --git a/apps/web/src/app/[locale]/automation/page.tsx b/apps/web/src/app/[locale]/automation/page.tsx new file mode 100644 index 00000000..b8a3e5cc --- /dev/null +++ b/apps/web/src/app/[locale]/automation/page.tsx @@ -0,0 +1,37 @@ +'use client' + +/** + * 自動化 (/automation) — Sprint 5 整合頁面 + * 整合: 自動修復 + 神經指揮 + Drift 偵測 + * 零假數據: 全部載入現有頁面內容 + * 建立時間: 2026-04-08 (台北時區) + */ + +import { lazy, Suspense } from 'react' +import { useTranslations } from 'next-intl' +import { AppLayout } from '@/components/layout' +import { PageTabs, type TabConfig } from '@/components/layout/page-tabs' + +const AutoRepairContent = lazy(() => import('@/app/[locale]/auto-repair/page')) +const NeuralCommandContent = lazy(() => import('@/app/[locale]/neural-command/page')) +const DriftContent = lazy(() => import('@/app/[locale]/drift/page')) + +function Loading() { + return
載入中...
+} + +export default function AutomationPage({ params }: { params: { locale: string } }) { + const t = useTranslations('nav') + + const tabs: TabConfig[] = [ + { id: 'repair', label: t('autoRepair'), content: }> }, + { id: 'neural', label: t('neuralCommand'), content: }> }, + { id: 'drift', label: t('drift'), content: }> }, + ] + + return ( + + + + ) +} diff --git a/apps/web/src/app/[locale]/knowledge/page.tsx b/apps/web/src/app/[locale]/knowledge/page.tsx new file mode 100644 index 00000000..4770f8fc --- /dev/null +++ b/apps/web/src/app/[locale]/knowledge/page.tsx @@ -0,0 +1,23 @@ +'use client' + +/** + * 知識 (/knowledge) — Sprint 5 整合頁面 + * 直接載入現有 knowledge-base 內容 + * 零假數據: 原封不動使用現有頁面 + * 建立時間: 2026-04-08 (台北時區) + */ + +import { lazy, Suspense } from 'react' +import { AppLayout } from '@/components/layout' + +const KnowledgeBaseContent = lazy(() => import('@/app/[locale]/knowledge-base/page')) + +export default function KnowledgePage({ params }: { params: { locale: string } }) { + return ( + + 載入中...}> + + + + ) +} diff --git a/apps/web/src/app/[locale]/observability/page.tsx b/apps/web/src/app/[locale]/observability/page.tsx new file mode 100644 index 00000000..0a18b5bb --- /dev/null +++ b/apps/web/src/app/[locale]/observability/page.tsx @@ -0,0 +1,92 @@ +'use client' + +/** + * 可觀測性 (/observability) — Sprint 5 整合頁面 + * ================================================ + * 整合: 服務監控 + APM + 錯誤追蹤 + 應用 + 服務目錄 + * 使用 PageTabs 共用元件,每個 Tab 載入對應的現有頁面內容 + * + * 零假數據: 所有 Tab 內容串接現有真實 API + * + * 建立時間: 2026-04-08 (台北時區) + * 建立者: Claude Code (Sprint 5 Phase 3) + */ + +import { lazy, Suspense } from 'react' +import { useTranslations } from 'next-intl' +import { AppLayout } from '@/components/layout' +import { PageTabs, type TabConfig } from '@/components/layout/page-tabs' + +// 延遲載入現有頁面內容 (避免一次載入所有 Tab) +// 注意: 這些直接 import 現有頁面的內部邏輯,不是 Mock +const MonitoringContent = lazy(() => import('@/app/[locale]/monitoring/page').then(m => ({ default: m.default }))) +const APMContent = lazy(() => import('@/app/[locale]/apm/page').then(m => ({ default: m.default }))) +const ErrorsContent = lazy(() => import('@/app/[locale]/errors/page').then(m => ({ default: m.default }))) +const AppsContent = lazy(() => import('@/app/[locale]/apps/page').then(m => ({ default: m.default }))) +const ServicesContent = lazy(() => import('@/app/[locale]/services/page').then(m => ({ default: m.default }))) + +function TabSkeleton() { + return ( +
+ 載入中... +
+ ) +} + +export default function ObservabilityPage({ params }: { params: { locale: string } }) { + const t = useTranslations('nav') + + const tabs: TabConfig[] = [ + { + id: 'monitoring', + label: t('monitoring'), + content: ( + }> + + + ), + }, + { + id: 'apm', + label: t('apm'), + content: ( + }> + + + ), + }, + { + id: 'errors', + label: t('errors'), + content: ( + }> + + + ), + }, + { + id: 'apps', + label: t('apps'), + content: ( + }> + + + ), + }, + { + id: 'services', + label: t('services'), + content: ( + }> + + + ), + }, + ] + + return ( + + + + ) +} diff --git a/apps/web/src/app/[locale]/operations/page.tsx b/apps/web/src/app/[locale]/operations/page.tsx new file mode 100644 index 00000000..3f28c4ab --- /dev/null +++ b/apps/web/src/app/[locale]/operations/page.tsx @@ -0,0 +1,41 @@ +'use client' + +/** + * 營運 (/operations) — Sprint 5 整合頁面 + * 整合: 部署管理 + 工單 + 成本分析 + 行動日誌 + 計費 + * 零假數據: 全部載入現有頁面內容 + * 建立時間: 2026-04-08 (台北時區) + */ + +import { lazy, Suspense } from 'react' +import { useTranslations } from 'next-intl' +import { AppLayout } from '@/components/layout' +import { PageTabs, type TabConfig } from '@/components/layout/page-tabs' + +const DeploymentsContent = lazy(() => import('@/app/[locale]/deployments/page')) +const TicketsContent = lazy(() => import('@/app/[locale]/tickets/page')) +const CostContent = lazy(() => import('@/app/[locale]/cost/page')) +const ActionLogsContent = lazy(() => import('@/app/[locale]/action-logs/page')) +const BillingContent = lazy(() => import('@/app/[locale]/billing/page')) + +function Loading() { + return
載入中...
+} + +export default function OperationsPage({ params }: { params: { locale: string } }) { + const t = useTranslations('nav') + + const tabs: TabConfig[] = [ + { id: 'deployments', label: t('deployments'), content: }> }, + { id: 'tickets', label: t('tickets'), content: }> }, + { id: 'cost', label: t('cost'), content: }> }, + { id: 'logs', label: t('actions'), content: }> }, + { id: 'billing', label: t('billing'), content: }> }, + ] + + return ( + + + + ) +} diff --git a/apps/web/src/app/[locale]/security-compliance/page.tsx b/apps/web/src/app/[locale]/security-compliance/page.tsx new file mode 100644 index 00000000..721d8139 --- /dev/null +++ b/apps/web/src/app/[locale]/security-compliance/page.tsx @@ -0,0 +1,35 @@ +'use client' + +/** + * 安全合規 (/security-compliance) — Sprint 5 整合頁面 + * 整合: 安全掃描 + 合規報告 + * 零假數據: 全部載入現有頁面內容 + * 建立時間: 2026-04-08 (台北時區) + */ + +import { lazy, Suspense } from 'react' +import { useTranslations } from 'next-intl' +import { AppLayout } from '@/components/layout' +import { PageTabs, type TabConfig } from '@/components/layout/page-tabs' + +const SecurityContent = lazy(() => import('@/app/[locale]/security/page')) +const ComplianceContent = lazy(() => import('@/app/[locale]/compliance/page')) + +function Loading() { + return
載入中...
+} + +export default function SecurityCompliancePage({ params }: { params: { locale: string } }) { + const t = useTranslations('nav') + + const tabs: TabConfig[] = [ + { id: 'security', label: t('security'), content: }> }, + { id: 'compliance', label: t('compliance'), content: }> }, + ] + + return ( + + + + ) +} diff --git a/apps/web/src/components/layout/sidebar.tsx b/apps/web/src/components/layout/sidebar.tsx index 0dcf7337..7a53adcd 100644 --- a/apps/web/src/components/layout/sidebar.tsx +++ b/apps/web/src/components/layout/sidebar.tsx @@ -80,12 +80,12 @@ const NAV_SECTIONS: NavSection[] = [ sectionKey: 'main', sectionLabel: '', items: [ - { id: 'command-center', href: '/', labelKey: 'commandCenter', Icon: LayoutDashboard }, - { id: 'observability', href: '/monitoring', labelKey: 'observability', Icon: Monitor }, - { id: 'automation', href: '/auto-repair', labelKey: 'automation', Icon: Wrench }, - { id: 'operations', href: '/deployments', labelKey: 'operations', Icon: Package }, - { id: 'security-compliance', href: '/security', labelKey: 'securityCompliance',Icon: Shield }, - { id: 'knowledge', href: '/knowledge-base', labelKey: 'knowledge', Icon: BookOpen }, + { id: 'command-center', href: '/', labelKey: 'commandCenter', Icon: LayoutDashboard }, + { id: 'observability', href: '/observability', labelKey: 'observability', Icon: Monitor }, + { id: 'automation', href: '/automation', labelKey: 'automation', Icon: Wrench }, + { id: 'operations', href: '/operations', labelKey: 'operations', Icon: Package }, + { id: 'security-compliance', href: '/security-compliance', labelKey: 'securityCompliance',Icon: Shield }, + { id: 'knowledge', href: '/knowledge', labelKey: 'knowledge', Icon: BookOpen }, ], }, {