Files
lcbp3/specs/200-fullstacks/240-ai-console-collapsible-cards/plan.md
T
2026-06-19 09:28:29 +07:00

170 lines
8.7 KiB
Markdown

# Implementation Plan: AI Console Collapsible Cards
**Branch**: `[240-ai-console-collapsible-cards]` | **Date**: 2026-06-19 | **Spec**: [spec.md](file:///e:/np-dms/lcbp3/specs/200-fullstacks/240-ai-console-collapsible-cards/spec.md)
**Input**: Feature specification from `/specs/200-fullstacks/240-ai-console-collapsible-cards/spec.md`
## Summary
ปรับปรุงหน้า AI Console (/admin/ai) ให้รองรับการย่อ/ขยาย (Collapsible) สำหรับการ์ดการตรวจติดตามสุขภาพระบบ AI (Monitoring Cards) เพื่อให้ Superadmin สามารถบริหารจัดการพื้นที่หน้าจอได้ดีขึ้นระหว่างการทดสอบระบบ Sandbox:
1. เพิ่มส่วนหัวของกลุ่มการ์ดพร้อมปุ่มย่อ/ขยายระบบตรวจติดตามทั้งหมด (Master Collapse)
2. เพิ่มปุ่มย่อ/ขยายการ์ดแต่ละใบแบบอิสระ (Ollama, Qdrant, OCR Sidecar, BullMQ, VRAM)
3. เก็บสถานะการย่อ/ขยายไว้ใน `localStorage` เพื่อให้คงสถานะไว้เมื่อรีเฟรชหน้าเว็บหรือเปลี่ยนแท็บ
## Technical Context
**Language/Version**: TypeScript 5.x, React, Next.js 16 (Client Components)
**Primary Dependencies**:
- Frontend: `lucide-react` (สำหรับไอคอน `ChevronUp` หรือ `ChevronDown`)
- Tailwind CSS (สำหรับทำ transition: `transition-all duration-300 ease-in-out`, `max-h-0`, `max-h-[500px]`, `rotate-180`)
- `localStorage` (สำหรับ persistence)
**Storage**: `localStorage` ในเบราว์เซอร์
**Testing**: การตรวจสอบสไตล์ UI/UX และการทำงานแบบ Manual เท่านั้น
## Constitution Check
| Gate | Status | Notes |
|------|--------|-------|
| 2 projects max | PASS | เปลี่ยนแปลงเฉพาะหน้า UI บน Frontend |
| Language aligned | PASS | โค้ดภาษาอังกฤษ เอกสารภาษาไทย |
| Storage aligned | PASS | ใช้ localStorage บนฝั่งไคลเอนต์เท่านั้น |
| Test coverage | PASS | UI/UX refactor เน้นการทำ manual validation |
## Project Structure
### Documentation (this feature)
```text
specs/200-fullstacks/240-ai-console-collapsible-cards/
├── plan.md # This file
├── spec.md # Feature specification
└── checklists/
└── requirements.md # Quality checklist
```
### Source Code
```text
frontend/
└── app/(admin)/admin/ai/
└── page.tsx # AI Console page (modify)
```
**Structure Decision**: Web application (frontend only refactor). แก้ไขไฟล์ `frontend/app/(admin)/admin/ai/page.tsx` เพียงไฟล์เดียวเพื่อควบคุมสถานะและการเคลื่อนไหวแบบ Collapsible
## Proposed Changes
### [Component Name] Next.js Frontend Page
#### [MODIFY] [page.tsx](file:///e:/np-dms/lcbp3/frontend/app/(admin)/admin/ai/page.tsx)
1. **Imports**:
- เพิ่มการนำเข้าไอคอน `ChevronUp` (หรือ `ChevronDown`) จาก `lucide-react`
2. **React States & Effects**:
- เพิ่ม `isSectionCollapsed` (boolean) เริ่มต้นเป็น `false`
- เพิ่ม `collapsedCards` (object) สำหรับเก็บสถานะการย่อของการ์ดแต่ละใบ:
```typescript
const [isSectionCollapsed, setIsSectionCollapsed] = useState<boolean>(false);
const [collapsedCards, setCollapsedCards] = useState<{
ollama: boolean;
qdrant: boolean;
ocr: boolean;
bullmq: boolean;
vram: boolean;
}>({
ollama: false,
qdrant: false,
ocr: false,
bullmq: false,
vram: false,
});
```
- เพิ่ม `useEffect` สำหรับโหลดค่าสถานะเหล่านี้จาก `localStorage` ตอนเริ่มต้นโหลดหน้าเว็บ:
```typescript
useEffect(() => {
const savedSection = localStorage.getItem('ai_console_section_collapsed');
if (savedSection !== null) {
setIsSectionCollapsed(savedSection === 'true');
}
const savedCards = localStorage.getItem('ai_console_cards_collapsed');
if (savedCards) {
try {
setCollapsedCards(JSON.parse(savedCards));
} catch (e) {
// เงียบข้อผิดพลาด
}
}
}, []);
```
- เพิ่มฟังก์ชันเพื่อบันทึกสถานะลง `localStorage` ทุกครั้งที่มีการเปลี่ยนค่า:
```typescript
const toggleSection = () => {
const nextVal = !isSectionCollapsed;
setIsSectionCollapsed(nextVal);
localStorage.setItem('ai_console_section_collapsed', String(nextVal));
};
const toggleCard = (cardKey: keyof typeof collapsedCards) => {
const nextCards = { ...collapsedCards, [cardKey]: !collapsedCards[cardKey] };
setCollapsedCards(nextCards);
localStorage.setItem('ai_console_cards_collapsed', JSON.stringify(nextCards));
};
```
3. **Master Section Toggle Header**:
- ด้านบนของกลุ่มการ์ด เพิ่มส่วนหัวของระบบตรวจติดตาม (Monitoring Header):
```tsx
<div className="flex items-center justify-between border-b pb-2 mb-4">
<h2 className="text-lg font-semibold flex items-center gap-2">
<Activity className="h-5 w-5 text-primary" />
AI Engine Infrastructure Monitoring
</h2>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-muted-foreground hover:text-foreground"
onClick={toggleSection}
>
<ChevronUp className={`h-5 w-5 transition-transform duration-300 ${isSectionCollapsed ? 'rotate-180' : ''}`} />
</Button>
</div>
```
4. **Grid Animation Wrapper**:
- ครอบกลุ่มการ์ดด้วยดิฟที่มีคลาสทำ transition:
```tsx
<div className={`grid gap-4 md:grid-cols-3 transition-all duration-300 ease-in-out ${
isSectionCollapsed ? 'max-h-0 opacity-0 overflow-hidden pointer-events-none' : 'max-h-[2000px] opacity-100'
}`}>
```
5. **Individual Card Adjustments**:
- เพิ่มปุ่มย่อ/ขยายถัดจากสถานะในแต่ละการ์ด (Ollama, Qdrant, OCR Sidecar, BullMQ, VRAM)
- ครอบเนื้อหา `<CardContent>` (รวมถึงส่วนข้อมูลเพิ่มเติม) เพื่อย่อ/ขยายด้วย transition:
```tsx
<div className={`transition-all duration-300 ease-in-out ${
collapsedCards.ollama ? 'max-h-0 opacity-0 overflow-hidden' : 'max-h-[500px] opacity-100'
}`}>
<CardContent className="space-y-2">
...
</CardContent>
</div>
```
- สลับไอคอน chevron ตามสถานะการย่อ/ขยาย
## Verification Plan
### Automated Tests
- ตรวจสอบชนิดข้อมูล (Type Checking):
`pnpm --filter lcbp3-frontend exec tsc --noEmit`
- ตรวจสอบรูปแบบโค้ด (Linting):
`pnpm --filter lcbp3-frontend exec eslint .`
### Manual Verification
1. เปิดหน้า AI Console ในแอปพลิเคชัน
2. คลิกปุ่มย่อ/ขยายระบบติดตามตรวจสอบทั้งหมด (Master Collapse) และดูการตอบสนอง
3. คลิกปุ่มย่อ/ขยายในการ์ดแต่ละใบและดูการย่อ/ขยายเฉพาะเนื้อหา
4. โหลดหน้าเว็บซ้ำ (F5) และยืนยันว่าสถานะการย่อ/ขยายในแต่ละปุ่มถูกรักษาไว้ด้วย `localStorage`
5. สลับแท็บไปที่ RAG Playground หรือ 3-Step Pipeline Sandbox และสลับกลับมายืนยันว่าสถานะคงเดิม