diff --git a/web/src/config/sidebarRoutes.jsx b/web/src/config/sidebarRoutes.jsx
index 2bb6ae1..5ed4e16 100644
--- a/web/src/config/sidebarRoutes.jsx
+++ b/web/src/config/sidebarRoutes.jsx
@@ -39,10 +39,10 @@ const routes = [
requiredRole: ['viewer', 'admin', 'manager'],
},
{
- path: '/dashboard/settings',
+ path: '/dashboard/guide',
icon: ,
- name: 'ตั้งค่าระบบ',
- requiredRole: ['admin'],
+ name: 'คู่มือการใช้งาน (Guide)',
+ requiredRole: ['viewer', 'manager', 'admin'],
},
];
diff --git a/web/src/pages/Dashboard.jsx b/web/src/pages/Dashboard.jsx
index b67052c..16c1458 100644
--- a/web/src/pages/Dashboard.jsx
+++ b/web/src/pages/Dashboard.jsx
@@ -1,25 +1,143 @@
import React from 'react';
import TitleCard from '../components/TitleCard';
+import { useModelList } from '../services/modelRegistryApi';
+import { useSystemHealth } from '../services/healthApi';
+import { useInferenceSummary } from '../services/auditApi';
-function Dashboard() {
- const TopButtons = (
-
+import { FaPlay, FaDatabase, FaClock, FaCheckCircle, FaTimesCircle, FaPercent, FaSyncAlt } from 'react-icons/fa';
+import { Link } from 'react-router-dom';
+
+// ----------------------------------------------------
+// Helper Component: สรุปตัวเลขสถิติ (Stats)
+// ----------------------------------------------------
+const StatCard = ({ icon, title, value, unit, colorClass, linkPath, isLoading }) => {
+
+ // แสดง loading spinner ถ้ากำลังโหลดข้อมูล
+ const displayValue = isLoading ? (
+
+ ) : (
+ value
);
return (
-
- {/* ใช้งาน TitleCard พร้อมปุ่มด้านบน */}
-
-
- แสดงสถิติสำคัญและ Model ทั้งหมด
+
+
+
+ {icon}
+
+
{title}
+
{displayValue} {unit}
+ {linkPath && (
+
+
+ ดูรายละเอียด
+
+
+ )}
+
+
+ );
+};
+
+function Dashboard() {
+ // Hooks สำหรับดึงข้อมูลสถานะ
+ const { data: models, isLoading: modelsLoading } = useModelList();
+ const { data: health, isLoading: healthLoading, isFetching: healthFetching } = useSystemHealth();
+ const { data: summary, isLoading: summaryLoading } = useInferenceSummary();
+
+ // --- Logic คำนวณ ---
+ const activeModelCount = models?.filter(m => m.status === 'ACTIVE').length || 0;
+ const totalModelCount = models?.length || 0;
+
+ // Health Status
+ const healthStatus = health?.status || (healthLoading ? 'CHECKING' : 'UNKNOWN');
+ const isHealthy = healthStatus === 'Healthy';
+ const healthIcon = isHealthy ? : ;
+ const healthColor = isHealthy ? 'text-success' : 'text-error';
+
+ // Inference Stats (จาก useInferenceSummary)
+ const totalRuns = summary?.total_runs || 0;
+ const successRate = summary?.success_rate || 0;
+ const avgLatencyMs = summary?.avg_latency_ms || 0;
+
+
+ return (
+
+
แดชบอร์ด/ภาพรวม
+
+ {/* 1. ส่วนแสดงสถิติสำคัญ (KPI Cards) */}
+
+
+ {/* Card 1: Model Active Count */}
+ }
+ title="Model พร้อมรัน (ACTIVE)"
+ value={activeModelCount}
+ unit={`จาก ${totalModelCount}`}
+ colorClass="text-success"
+ linkPath="/dashboard/model-registry"
+ isLoading={modelsLoading}
+ />
+
+ {/* Card 2: Total Inference Runs (Audit Log) */}
+ }
+ title="งานรันทั้งหมด (24 ชม.)"
+ value={totalRuns}
+ unit="ครั้ง"
+ colorClass="text-info"
+ isLoading={summaryLoading}
+ // Note: ต้องมีเมนู Pipeline Logs หรือ Audit Log List
+ />
+
+ {/* Card 3: Success Rate (Audit Log) */}
+ }
+ title="Success Rate (24 ชม.)"
+ value={successRate}
+ unit="%"
+ colorClass={successRate > 90 ? "text-success" : "text-warning"}
+ isLoading={summaryLoading}
+ />
+
+ {/* Card 4: Avg Latency (Audit Log) */}
+ }
+ title="Latency เฉลี่ย (AI)"
+ value={avgLatencyMs}
+ unit="ms"
+ colorClass={avgLatencyMs > 5000 ? "text-error" : "text-warning"}
+ isLoading={summaryLoading}
+ />
+
+
+ {/* 2. ส่วนแสดงสถานะ Infrastructure (Health) */}
+
: null}
+ >
+
+
+
+ ตรวจสอบสถานะของ DB, Redis, MinIO, และ AI Model Endpoints ได้ที่เมนูสถานะระบบ
- {/* เพิ่มส่วนของการแสดง Metric สำคัญ เช่น Stats Component */}
+
+
+ {/* 3. ส่วนแสดง Log ล่าสุด (Audit Log) */}
+
+
+ {summaryLoading ? "กำลังโหลด Log ล่าสุด..." : JSON.stringify(summary?.last_logs || [], null, 2)}
+
);
}
-export default Dashboard;
+export default Dashboard;
\ No newline at end of file
diff --git a/web/src/pages/system/UserGuide.jsx b/web/src/pages/system/UserGuide.jsx
new file mode 100644
index 0000000..c27e90b
--- /dev/null
+++ b/web/src/pages/system/UserGuide.jsx
@@ -0,0 +1,77 @@
+// src/pages/Guide/UserGuide.jsx
+import React from 'react';
+import { FaUpload, FaFlask, FaDatabase, FaServer, FaBook } from 'react-icons/fa';
+import TitleCard from '../../components/TitleCard';
+
+export default function UserGuide() {
+ return (
+ }
+ >
+ {/* SINGLE COLUMN LAYOUT */}
+
+
+
+ {/* ภาพรวม */}
+
+ ภาพรวมระบบ DDO Console
+
+ DDO Console ถูกออกแบบมาเพื่อเป็น MLOps Gateway สำหรับจัดการวงจรชีวิต
+ ของ AI Model ทางการแพทย์ (Medical Imaging AI) โดยเฉพาะ...
+
+
+
+ {/* Model Registry */}
+
+
+ 1. Model Registry & Control
+
+
+
+ - ไปที่เมนู "Model Registry & Control"
+ - การลงทะเบียน: ต้องกรอก Base URL และ Inference Path
+
+
+
+ {/* Inference */}
+
+
+ 2. AI Inference (Run)
+
+
+
+ - เลือก Model: ต้องเลือกเฉพาะ Model ที่เป็น ACTIVE
+ - อัปโหลดไฟล์: รองรับไฟล์ภาพ NIfTI (.nii)
+
+
+
+ {/* การเตรียม Model */}
+
+
+ 3. การเตรียม Model (Deployment)
+
+
+
+ - การจัดเก็บ: ไฟล์โมเดลต้องอยู่ใน MinIO bucket 'models'
+ - FastAPI: ต้องมี Health Check (GET)
+
+
+
+ {/* การตรวจสอบสถานะ */}
+
+
+ 4. การตรวจสอบสถานะระบบ (System Ops)
+
+
+
+ ใช้เมนู "สถานะระบบ (Health)" เพื่อตรวจสอบความพร้อมของ infrastructure และ Model ACTIVE
+
+
+
+
+
+
+ );
+}
diff --git a/web/src/routes/pageRoutes.jsx b/web/src/routes/pageRoutes.jsx
index 2650131..f248ef0 100644
--- a/web/src/routes/pageRoutes.jsx
+++ b/web/src/routes/pageRoutes.jsx
@@ -3,6 +3,7 @@ import BlankPage from '../pages/BlankPage';
import ModelRegistry from '../pages/data/ModelRegistry';
import InferenceRun from '../pages/data/InferenceRun';
import SystemHealth from '../pages/system/Health';
+import UserGuide from '../pages/system/UserGuide';
// Array ของเส้นทางย่อยภายใต้ /dashboard/
const pageRoutes = [
@@ -29,6 +30,12 @@ const pageRoutes = [
path: 'health',
element:
,
},
+ // --- คู่มือการใช้งาน (Guide) ---
+ {
+ // Path: /dashboard/guide
+ path: 'guide',
+ element:
,
+ },
// Fallback สำหรับเส้นทางที่ไม่ตรงกับเมนูใดๆ
{
path: '*',
diff --git a/web/src/services/auditApi.js b/web/src/services/auditApi.js
new file mode 100644
index 0000000..079d331
--- /dev/null
+++ b/web/src/services/auditApi.js
@@ -0,0 +1,21 @@
+import { useQuery } from '@tanstack/react-query';
+import axiosClient from './axiosClient';
+
+const STALE_TIME = 60000; // 1 นาที
+
+/**
+ * Hook สำหรับดึงสรุปสถิติ Inference (Total Runs, Success Rate, Avg Latency)
+ * Endpoint: GET /api/v1/audit/inference-summary/
+ */
+export const useInferenceSummary = () => {
+ return useQuery({
+ queryKey: ['inferenceSummary'],
+ queryFn: async () => {
+ const response = await axiosClient.get('/api/v1/audit/inference-summary/');
+ return response.data;
+ },
+ staleTime: STALE_TIME,
+ // ดึงข้อมูลใหม่ทุก 30 วินาทีเพื่ออัปเดตสถิติ Dashboard
+ refetchInterval: 30000,
+ });
+};
\ No newline at end of file