@gravito/zenith 0.1.0-beta.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/bin.js +38846 -27303
  3. package/dist/client/assets/index-C332gZ-J.css +1 -0
  4. package/dist/client/assets/index-D4HibwTK.js +436 -0
  5. package/dist/client/index.html +2 -2
  6. package/dist/server/index.js +38846 -27303
  7. package/docs/ALERTING_GUIDE.md +71 -0
  8. package/docs/LARAVEL_ZENITH_ROADMAP.md +109 -0
  9. package/docs/QUASAR_MASTER_PLAN.md +140 -0
  10. package/package.json +52 -48
  11. package/scripts/debug_redis_keys.ts +24 -0
  12. package/specs/PULSE_SPEC.md +86 -0
  13. package/src/client/App.tsx +2 -0
  14. package/src/client/Layout.tsx +18 -0
  15. package/src/client/Sidebar.tsx +2 -1
  16. package/src/client/WorkerStatus.tsx +121 -76
  17. package/src/client/components/BrandIcons.tsx +138 -0
  18. package/src/client/components/ConfirmDialog.tsx +0 -1
  19. package/src/client/components/JobInspector.tsx +18 -6
  20. package/src/client/components/PageHeader.tsx +38 -0
  21. package/src/client/pages/OverviewPage.tsx +17 -20
  22. package/src/client/pages/PulsePage.tsx +478 -0
  23. package/src/client/pages/QueuesPage.tsx +1 -3
  24. package/src/client/pages/SettingsPage.tsx +640 -78
  25. package/src/client/pages/WorkersPage.tsx +71 -3
  26. package/src/client/pages/index.ts +1 -0
  27. package/src/server/index.ts +311 -11
  28. package/src/server/services/AlertService.ts +189 -41
  29. package/src/server/services/CommandService.ts +137 -0
  30. package/src/server/services/PulseService.ts +80 -0
  31. package/src/server/services/QueueService.ts +63 -6
  32. package/src/shared/types.ts +99 -0
  33. package/tsconfig.json +2 -2
  34. package/ARCHITECTURE.md +0 -88
  35. package/BATCH_OPERATIONS_IMPLEMENTATION.md +0 -159
  36. package/EVOLUTION_BLUEPRINT.md +0 -112
  37. package/JOBINSPECTOR_SCROLL_FIX.md +0 -152
  38. package/PULSE_IMPLEMENTATION_PLAN.md +0 -111
  39. package/TESTING_BATCH_OPERATIONS.md +0 -252
  40. package/dist/client/assets/index-DGYEwTDL.css +0 -1
  41. package/dist/client/assets/index-oyTdySX0.js +0 -421
  42. /package/{DEPLOYMENT.md → docs/DEPLOYMENT.md} +0 -0
  43. /package/{DOCS_INTERNAL.md → docs/DOCS_INTERNAL.md} +0 -0
  44. /package/{QUICK_TEST_GUIDE.md → docs/QUICK_TEST_GUIDE.md} +0 -0
  45. /package/{ROADMAP.md → docs/ROADMAP.md} +0 -0
@@ -0,0 +1,99 @@
1
+ export interface PulseCpu {
2
+ system: number // Percentage 0-100
3
+ process: number // Percentage 0-100
4
+ cores: number
5
+ }
6
+
7
+ export interface PulseMemory {
8
+ system: {
9
+ total: number // bytes
10
+ free: number // bytes
11
+ used: number // bytes
12
+ }
13
+ process: {
14
+ rss: number // bytes
15
+ heapTotal: number // bytes
16
+ heapUsed: number // bytes
17
+ }
18
+ }
19
+
20
+ export interface PulseRuntime {
21
+ uptime: number // seconds
22
+ framework: string // e.g. "Node 20.1", "Laravel 10.0"
23
+ status?: string
24
+ errors?: string[]
25
+ }
26
+
27
+ export interface QueueSnapshot {
28
+ name: string
29
+ driver: 'redis' | 'sqs' | 'rabbitmq'
30
+ size: {
31
+ waiting: number
32
+ active: number
33
+ failed: number
34
+ delayed: number
35
+ }
36
+ throughput?: {
37
+ in: number // jobs/min
38
+ out: number // jobs/min
39
+ }
40
+ }
41
+
42
+ export interface PulseNode {
43
+ id: string // Unique Instance ID
44
+ service: string // Group name
45
+ language: 'node' | 'bun' | 'deno' | 'php' | 'go' | 'python' | 'other'
46
+ version: string // App Version
47
+ pid: number
48
+ hostname: string
49
+ platform: string
50
+ cpu: PulseCpu
51
+ memory: PulseMemory
52
+ queues?: QueueSnapshot[]
53
+ runtime: PulseRuntime
54
+ meta?: any // Extra metadata like Laravel workers
55
+ timestamp: number // Last heartbeat
56
+ }
57
+ export interface AlertRule {
58
+ id: string
59
+ name: string
60
+ type: 'backlog' | 'failure' | 'worker_lost' | 'node_cpu' | 'node_ram'
61
+ threshold: number
62
+ queue?: string // Optional: specific queue or all
63
+ cooldownMinutes: number
64
+ }
65
+
66
+ export interface AlertEvent {
67
+ ruleId: string
68
+ timestamp: number
69
+ message: string
70
+ severity: 'warning' | 'critical'
71
+ }
72
+
73
+ export interface AlertConfig {
74
+ channels: {
75
+ slack?: {
76
+ enabled: boolean
77
+ webhookUrl: string
78
+ }
79
+ discord?: {
80
+ enabled: boolean
81
+ webhookUrl: string
82
+ }
83
+ email?: {
84
+ enabled: boolean
85
+ smtpHost: string
86
+ smtpPort: number
87
+ smtpUser: string
88
+ smtpPass: string
89
+ from: string
90
+ to: string // Comma separated list
91
+ }
92
+ }
93
+ }
94
+
95
+ export interface MaintenanceConfig {
96
+ autoCleanup: boolean
97
+ retentionDays: number
98
+ lastRun?: number // Timestamp
99
+ }
package/tsconfig.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "extends": "../../tsconfig.json",
3
3
  "compilerOptions": {
4
- "target": "ES2020",
4
+ "target": "ESNext",
5
5
  "useDefineForClassFields": true,
6
6
  "lib": [
7
- "ES2020",
7
+ "ESNext",
8
8
  "DOM",
9
9
  "DOM.Iterable"
10
10
  ],
package/ARCHITECTURE.md DELETED
@@ -1,88 +0,0 @@
1
-
2
- # 🏗️ Gravito Flux Console Architecture
3
-
4
- > The official, standalone visualization and management console for Gravito Flux & Stream.
5
-
6
- ## 1. Project Manifesto
7
-
8
- - **Dogfooding First**: Uses `@gravito/photon` for HTTP serving and `@gravito/stream` for queue interaction.
9
- - **Zero-Config**: Should work out-of-the-box via `npx` with minimal arguments.
10
- - **Stateless**: The console itself holds no long-term state; Redis is the source of truth.
11
- - **Micro-Frontend Ready**: Built with React, matching the Gravito Admin ecosystem, but capable of running standalone.
12
-
13
- ## 2. System Architecture
14
-
15
- ```mermaid
16
- graph TD
17
- CLI[CLI Entry (bin)] --> Boot[Bootstrapper]
18
- Boot -->|Init| Server[Photon Server (Node/Bun)]
19
-
20
- subgraph "Backend Layer"
21
- Server -->|Serve| API[Management API]
22
- Server -->|Serve| Static[Frontend Assets]
23
-
24
- API -->|Command| QM[QueueManager (@gravito/stream)]
25
- QM -->|Protocol| Redis[(Redis)]
26
- end
27
-
28
- subgraph "Frontend Layer (React/Vite)"
29
- UI[Dashboard UI] -->|Fetch| API
30
- end
31
- ```
32
-
33
- ## 3. Technical Stack
34
-
35
- ### Backend
36
- - **Runtime**: Bun / Node.js (Compat)
37
- - **Framework**: **`@gravito/photon`** (Hono wrapper)
38
- - **Data Access**: **`@gravito/stream`** (Directly uses QueueDrivers)
39
- - **Persistence**: **`MySQLPersistence`** / **`SQLitePersistence`** for long-term auditing.
40
-
41
- ### Frontend
42
- - **Framework**: React 19
43
- - **Build Tool**: Vite
44
- - **Styling**: TailwindCSS (keeping consistent with `admin-shell`)
45
- - **State Management**: React Query (TanStack Query) for real-time polling.
46
-
47
- ## 4. Key Features (Phase 1 MVP)
48
-
49
- ### A. Dashboard
50
- - **System Overview**: Connection status, Driver type (Redis/Rabbit/Kafka).
51
- - **Throughput Metrics**: Jobs processed per second (calculated window).
52
-
53
- ### B. Queue Management
54
- - **List Queues**: Show all active queues with counts (Waiting, Active, Failed).
55
- - **Inspect Queue**: View jobs in a paginated list.
56
- - **Job Detail**: View JSON payload and stack trace.
57
-
58
- ### C. Actions
59
- - **Retry Job**: Move job from `failed` to `waiting`.
60
- - **Delete Job**: Remove job permanently.
61
-
62
- ### D. Persistence & Auditing
63
- - **Job Archive**: Completed and Failed jobs move to SQL storage.
64
- - **Operational Log Archiving**: Persistent storage for system events and worker activities with history search.
65
- - **Hybrid Search**: Query both Redis (Live) and SQL (Archive) simultaneously.
66
- - **Retention Management**: Configurable auto-cleanup for historical data.
67
-
68
- ### E. Alerting System
69
- - **Real-time Checks**: Monitoring for failure spikes and worker loss.
70
- - **Notifications**: Slack integration via Webhooks.
71
- - **Cool-down Logic**: Prevents duplicated alerts for the same event.
72
-
73
- ## 5. Deployment Strategy
74
-
75
- The package is published as a standard NPM package. It contains a `bin` entry point.
76
-
77
- ### Usage Scenarios
78
- 1. **Local Ad-hoc**: `npx @gravito/flux-console start --url redis://...`
79
- 2. **Project Integration**: Add to `package.json` scripts.
80
- 3. **Docker**: Official image wrapping the CLI.
81
-
82
- ## 6. Development Workflow
83
-
84
- Since this is a monolithic package (Backend + Frontend):
85
- - `npm run dev` should start:
86
- 1. Vite Dev Server (Frontend)
87
- 2. Photon Watch Mode (Backend)
88
- - Backend should proxy `/` requests to Vite during development.
@@ -1,159 +0,0 @@
1
- # Batch Operations Implementation Summary
2
-
3
- ## ✅ Completed Features
4
-
5
- ### 1. Backend Enhancements
6
-
7
- #### New Service Methods (`QueueService.ts`)
8
- - **`getJobCount(queueName, type)`**: Get total count of jobs by type (waiting/delayed/failed)
9
- - **`deleteAllJobs(queueName, type)`**: Delete ALL jobs of a specific type from a queue
10
- - **`retryAllJobs(queueName, type)`**: Retry ALL jobs of a specific type (delayed or failed)
11
-
12
- #### New API Endpoints (`server/index.ts`)
13
- - **`GET /api/queues/:name/jobs/count`**: Returns total count of jobs by type
14
- - **`POST /api/queues/:name/jobs/bulk-delete-all`**: Deletes ALL jobs of a specific type
15
- - **`POST /api/queues/:name/jobs/bulk-retry-all`**: Retries ALL jobs of a specific type
16
-
17
- ### 2. Frontend Enhancements
18
-
19
- #### New Component: `ConfirmDialog.tsx`
20
- - Reusable confirmation dialog with:
21
- - Animated entrance/exit (Framer Motion)
22
- - Loading state support
23
- - Variant support (danger/warning/info)
24
- - Customizable messages and buttons
25
-
26
- #### Enhanced `JobInspector` Component
27
- **State Management:**
28
- - `totalCount`: Tracks total jobs matching current view
29
- - `isProcessing`: Loading state for bulk operations
30
- - `confirmDialog`: Manages confirmation dialog state
31
-
32
- **New Features:**
33
- 1. **Total Count Display**
34
- - Fetches and displays total job count for non-archive views
35
- - Shows "X of Y total" in the selection bar
36
-
37
- 2. **"Select All Matching Query" UI**
38
- - Warning banner when showing partial results
39
- - "Delete All X" and "Retry All X" buttons
40
- - Only shown when total count exceeds visible jobs
41
-
42
- 3. **Confirmation Dialogs**
43
- - Replaces browser `confirm()` with custom modal
44
- - Shows job counts and queue names
45
- - Warning emoji for destructive "ALL" operations
46
- - Loading spinner during processing
47
-
48
- 4. **Keyboard Shortcuts**
49
- - **Ctrl+A / Cmd+A**: Select all visible jobs on current page
50
- - **Escape**: Clear selection → Close dialog → Close inspector (cascading)
51
-
52
- 5. **Improved UX**
53
- - "Select All (Page)" label clarifies scope
54
- - Total count shown next to checkbox
55
- - Disabled state for processing operations
56
- - Error handling with user-friendly messages
57
-
58
- ### 3. Visual Enhancements
59
-
60
- - **Amber warning banner** for "Select All Matching" feature
61
- - **AlertCircle icon** for visual emphasis
62
- - **Loading spinners** in confirmation buttons
63
- - **Disabled states** prevent double-clicks
64
- - **Color-coded buttons**:
65
- - Red for delete operations
66
- - Amber for retry operations
67
- - Primary color for standard actions
68
-
69
- ## 🎯 User Workflows
70
-
71
- ### Workflow 1: Bulk Delete Selected Jobs
72
- 1. User opens JobInspector for a queue
73
- 2. Clicks checkboxes to select specific jobs
74
- 3. Clicks "Delete Selected" button
75
- 4. Confirms in dialog
76
- 5. Jobs are deleted, UI refreshes
77
-
78
- ### Workflow 2: Delete ALL Jobs of a Type
79
- 1. User opens JobInspector for a queue
80
- 2. Switches to "failed" view (for example)
81
- 3. Sees warning banner: "Showing 50 of 1,234 total failed jobs"
82
- 4. Clicks "Delete All 1,234" button
83
- 5. Sees strong warning dialog with ⚠️ emoji
84
- 6. Confirms action
85
- 7. ALL 1,234 failed jobs are deleted
86
-
87
- ### Workflow 3: Keyboard Power User
88
- 1. User opens JobInspector
89
- 2. Presses **Ctrl+A** to select all visible jobs
90
- 3. Presses **Delete** button
91
- 4. Presses **Escape** to cancel dialog
92
- 5. Presses **Escape** again to close inspector
93
-
94
- ## 🔧 Technical Details
95
-
96
- ### Backend Implementation
97
- - **Redis Operations**: Uses `LLEN`, `ZCARD` for counts; `DEL` for bulk deletion
98
- - **Atomic Operations**: Existing `retryDelayedJob()` and `retryAllFailedJobs()` reused
99
- - **Type Safety**: Full TypeScript support with proper type guards
100
-
101
- ### Frontend Implementation
102
- - **React Hooks**: `useState`, `useEffect`, `useQuery` for state management
103
- - **TanStack Query**: Automatic cache invalidation after bulk operations
104
- - **Framer Motion**: Smooth animations for dialog entrance/exit
105
- - **Event Handling**: Keyboard event listeners with proper cleanup
106
-
107
- ### Error Handling
108
- - Try-catch blocks around all API calls
109
- - User-friendly error messages
110
- - Console logging for debugging
111
- - Graceful degradation if API fails
112
-
113
- ## 📊 Performance Considerations
114
-
115
- - **Lazy Loading**: Total count fetched only when needed
116
- - **Debouncing**: Could be added for rapid selection changes (future enhancement)
117
- - **Pagination**: Archive view supports pagination for large datasets
118
- - **Redis Efficiency**: Uses pipelined commands where possible
119
-
120
- ## 🧪 Testing Recommendations
121
-
122
- - [ ] Test with 10, 100, 1,000+ jobs
123
- - [ ] Test keyboard shortcuts across browsers
124
- - [ ] Test confirmation dialog cancellation
125
- - [ ] Test error scenarios (network failures, Redis errors)
126
- - [ ] Test archive view (should not show "Delete All" buttons)
127
- - [ ] Test concurrent bulk operations
128
- - [ ] Test UI responsiveness during long operations
129
-
130
- ## 📝 Documentation Updates
131
-
132
- - ✅ Updated `ROADMAP.md` to mark feature as completed
133
- - ✅ Added detailed task checklist
134
- - ✅ Included keyboard shortcuts in documentation
135
-
136
- ## 🚀 Future Enhancements
137
-
138
- 1. **Progress Indicators**: Show "Deleting 500/1000..." for large batches
139
- 2. **Undo Functionality**: Temporary recovery window for accidental deletions
140
- 3. **Bulk Edit**: Modify job data in bulk
141
- 4. **Export/Import**: Export selected jobs to JSON, import later
142
- 5. **Advanced Filters**: Select jobs by date range, error type, etc.
143
- 6. **Bulk Scheduling**: Reschedule multiple delayed jobs at once
144
-
145
- ## 🎉 Summary
146
-
147
- The Batch Operations feature is now **fully implemented** and **production-ready**. Users can:
148
- - Select multiple jobs with checkboxes
149
- - Perform bulk delete/retry on selected jobs
150
- - Delete/retry ALL jobs of a specific type with a single click
151
- - Use keyboard shortcuts for faster workflows
152
- - Get clear confirmation dialogs with loading states
153
- - See total counts and visual feedback throughout
154
-
155
- **Estimated Implementation Time**: ~3 hours
156
- **Actual Implementation Time**: ~2.5 hours
157
- **Lines of Code Added**: ~350 lines
158
- **Files Modified**: 4 files
159
- **New Files Created**: 2 files
@@ -1,112 +0,0 @@
1
- # Gravito Zenith Evolution Blueprint
2
- **Target**: Zenith v2.0 - The Universal Application Control Plane
3
- **Core Philosophy**: Lightweight, Redis-Native, Language-Agnostic.
4
-
5
- ## 🧭 Strategic Vision
6
-
7
- We aim to evolve Zenith from a **Queue Manager** into a **Lightweight Application Control Plane**. We will absorb the best features from industry leaders (Laravel Pulse, Sidekiq, BullMQ) while strictly avoiding their architectural pitfalls (heavy deps, SQL locks, language coupling).
8
-
9
- ---
10
-
11
- ## 📅 Roadmap Structure
12
-
13
- ### Phase 1: Deep Visibility (Queue Insights)
14
- **Focus**: Enhance the depth of information for the current Queue System.
15
- **Benchmarks**: Sidekiq, BullMQ.
16
-
17
- #### 1.1 Worker "X-Ray" Vision (The "Busy" State)
18
- - **Concept**: Instead of just showing "Busy", show *what* the worker is doing.
19
- - **Implementation**: Update Heartbeat Protocol to include `currentJobId` and `jobName`.
20
- - **UI**: Workers table shows "Processing: Order #1024 (SendEmail)".
21
- - **Benefit**: Instantly identify which job is hogging a worker.
22
- - **Difference**: Unlike Sidekiq which uses expensive extensive locking, we use ephemeral keys.
23
-
24
- #### 1.2 Enhanced Payload Inspector
25
- - **Concept**: Developer-friendly data inspection.
26
- - **Implementation**:
27
- - Syntax-highlighted JSON viewer with folding.
28
- - "Copy as cURL" or "Copy to Clipboard" actions.
29
- - Display stack traces with click-to-open (if local) potential.
30
- - **UX Rule**: Always lazy-load heavy payloads. Never fetch them in the list view.
31
-
32
- #### 1.3 Timeline Visualization (Gantt-lite)
33
- - **Concept**: Visualize concurrency.
34
- - **Implementation**: A canvas-based timeline showing job execution durations overlapping in time.
35
- - **Benefit**: Spot resource contention or gaps in processing.
36
-
37
- ---
38
-
39
- ## Phase 2: System Pulse (Resource Monitoring)
40
- **Focus**: Lightweight APM (Application Performance Monitoring).
41
- **Benchmarks**: Laravel Pulse, PM2.
42
-
43
- #### 2.1 Gravito Pulse Protocol (GPP)
44
- - **Concept**: A standardized JSON structure for services to report health.
45
- - **Structure**: `pulse:{service}:{id}` (TTL 30s).
46
- - **Metrics**: CPU%, RAM (RSS/Heap), Disk Usage, Uptime, Event Loop Lag.
47
- - **Avoidance**: Do NOT store historical time-series data in SQL. Use Redis Lists/Streams with aggressive trimming (e.g., keep last 1 hour).
48
-
49
- #### 2.2 Grid Dashboard
50
- - **Concept**: Customizable "Mission Control" view.
51
- - **UI**: Drag-and-drop grid system.
52
- - **Widgets**:
53
- - Host Health (CPU/RAM guages).
54
- - Queue Backlog (Sparklines).
55
- - Exception Rate (Counter).
56
- - Slowest Routes (List).
57
-
58
- #### 2.3 Cross-Language Recorders
59
- - **Goal**: Provide simple SDKs.
60
- - `@gravito/recorder-node`: For Express/Hono/Nest.
61
- - `@gravito/recorder-php`: For Laravel/Symfony.
62
- - `@gravito/recorder-python`: For Django/FastAPI.
63
-
64
- ---
65
-
66
- ## Phase 3: Intelligent Operations (Proactive Ops)
67
- **Focus**: Alerting and Anomaly Detection.
68
- **Benchmarks**: New Relic (Lite), Oban.
69
-
70
- #### 3.1 Outlier Detection (The "Slow" & "Error" Trap)
71
- - **Concept**: Only capture interesting data.
72
- - **Logic**:
73
- - If `duration > threshold`: Push to `pulse:slow_jobs`.
74
- - If `status >= 500`: Push to `pulse:exceptions`.
75
- - **Benefit**: Zero overhead for successful, fast requests.
76
-
77
- #### 3.2 Smart Alerting Engine
78
- - **Concept**: "Don't spam me."
79
- - **Features**:
80
- - **Thresholds**: "CPU > 90% for 5 minutes".
81
- - **Cooldown**: "Alert once per hour per rule".
82
- - **Channels**: Slack, Discord, Email, Webhook.
83
-
84
- ---
85
-
86
- ## 🎨 UI/UX Unification Strategy
87
-
88
- To prevent "Feature Bloat" (UI Clutter), we will enforce strict design rules:
89
-
90
- ### 1. Navigation Hierarchy
91
- Refactor Sidebar into logical groups:
92
- - **Dashboards** (Overview, System Pulse)
93
- - **Queues** (Active, Waiting, Delayed, Failed)
94
- - **Infrastructure** (Workers, Databases, Redis)
95
- - **Settings** (Alerts, API Keys)
96
-
97
- ### 2. Contextual Density
98
- - **List View**: Minimal info (ID, Name, Status, Time).
99
- - **Detail Panel**: Slide-over panel for deep inspection (Payloads, Stack Traces, Logs).
100
- - **Avoidance**: Don't try to cram everything into the table rows.
101
-
102
- ### 3. Unified Filters
103
- - Create a shared "Filter Bar" component (Date Range, Status, Queue Name) that works consistently across Logs, Jobs, and Pulse views.
104
-
105
- ---
106
-
107
- ## ✅ Implementation Checklist (Next Steps)
108
-
109
- 1. **[ ] Protocol Definition**: Document `GPP` (Gravito Pulse Protocol).
110
- 2. **[ ] Backend Core**: Implement `SystemMonitor` service in Zenith.
111
- 3. **[ ] Frontend Core**: Create the `GridDashboard` component layout.
112
- 4. **[ ] Feature**: Implement `Worker X-Ray` (easiest win from Phase 1).
@@ -1,152 +0,0 @@
1
- # JobInspector 滾動修復
2
-
3
- ## 🐛 問題描述
4
-
5
- 當佇列中有大量工作(例如 100+ 個)時,JobInspector 側邊欄會被撐得很高,導致:
6
- - 整個側邊欄超出螢幕高度
7
- - 無法看到底部的 "Dismiss" 按鈕
8
- - 需要滾動整個頁面才能查看所有內容
9
- - UX 體驗很差
10
-
11
- ## ✅ 修復方案
12
-
13
- ### 修改的 CSS 類別
14
-
15
- #### 1. 主容器 (`motion.div`)
16
- ```tsx
17
- // 修改前
18
- className="bg-card border-l h-full w-full max-w-2xl shadow-2xl flex flex-col"
19
-
20
- // 修改後
21
- className="bg-card border-l h-screen max-h-screen w-full max-w-2xl shadow-2xl flex flex-col overflow-hidden"
22
- ```
23
-
24
- **變更說明:**
25
- - `h-full` → `h-screen max-h-screen`: 明確限制高度為視窗高度
26
- - 新增 `overflow-hidden`: 防止內容溢出
27
-
28
- #### 2. 頂部標題區域
29
- ```tsx
30
- // 修改前
31
- className="p-6 border-b flex justify-between items-center bg-muted/20"
32
-
33
- // 修改後
34
- className="p-6 border-b flex justify-between items-center bg-muted/20 flex-shrink-0"
35
- ```
36
-
37
- **變更說明:**
38
- - 新增 `flex-shrink-0`: 防止標題區域被壓縮
39
-
40
- #### 3. 內容滾動區域
41
- ```tsx
42
- // 修改前
43
- className="p-0 overflow-y-auto flex-1 bg-muted/5"
44
-
45
- // 修改後
46
- className="flex-1 overflow-y-auto bg-muted/5 min-h-0"
47
- ```
48
-
49
- **變更說明:**
50
- - 移除 `p-0`(padding 由內部元素控制)
51
- - 新增 `min-h-0`: 允許 flex 子元素縮小到 0,確保滾動正常運作
52
-
53
- #### 4. 底部按鈕區域
54
- ```tsx
55
- // 修改前
56
- className="p-4 border-t bg-card text-right"
57
-
58
- // 修改後
59
- className="p-4 border-t bg-card text-right flex-shrink-0"
60
- ```
61
-
62
- **變更說明:**
63
- - 新增 `flex-shrink-0`: 防止按鈕區域被壓縮
64
-
65
- ## 🎯 修復效果
66
-
67
- ### 修復前
68
- ```
69
- ┌─────────────────────────────┐
70
- │ Header (標題區) │ ← 正常
71
- ├─────────────────────────────┤
72
- │ Job 1 │
73
- │ Job 2 │
74
- │ Job 3 │
75
- │ ... │
76
- │ Job 98 │
77
- │ Job 99 │
78
- │ Job 100 │ ← 超出螢幕
79
- ├─────────────────────────────┤
80
- │ [Dismiss] 按鈕 │ ← 看不到
81
- └─────────────────────────────┘
82
- ```
83
-
84
- ### 修復後
85
- ```
86
- ┌─────────────────────────────┐
87
- │ Header (標題區) │ ← 固定在頂部
88
- ├─────────────────────────────┤
89
- │ Job 1 │ ↕️
90
- │ Job 2 │ ↕️
91
- │ Job 3 │ ↕️ 可滾動區域
92
- │ ... │ ↕️
93
- │ Job 50 │ ↕️
94
- ├─────────────────────────────┤
95
- │ [Dismiss] 按鈕 │ ← 固定在底部
96
- └─────────────────────────────┘
97
- ```
98
-
99
- ## 📊 技術細節
100
-
101
- ### Flexbox 佈局結構
102
- ```
103
- motion.div (h-screen, flex flex-col, overflow-hidden)
104
- ├─ Header (flex-shrink-0) ← 不會被壓縮
105
- ├─ Content (flex-1, overflow-y-auto, min-h-0) ← 可滾動,佔據剩餘空間
106
- └─ Footer (flex-shrink-0) ← 不會被壓縮
107
- ```
108
-
109
- ### 關鍵 CSS 屬性
110
-
111
- 1. **`h-screen max-h-screen`**: 限制容器高度為視窗高度
112
- 2. **`overflow-hidden`**: 防止容器本身滾動
113
- 3. **`flex-shrink-0`**: 防止 header 和 footer 被壓縮
114
- 4. **`flex-1`**: 讓內容區域佔據所有剩餘空間
115
- 5. **`overflow-y-auto`**: 只在內容區域啟用垂直滾動
116
- 6. **`min-h-0`**: 允許 flex 子元素縮小(CSS flexbox 的特殊行為)
117
-
118
- ## 🧪 測試驗證
119
-
120
- ### 測試案例
121
- 1. ✅ 打開有 100+ 工作的佇列
122
- 2. ✅ 側邊欄高度固定為螢幕高度
123
- 3. ✅ 工作列表可以滾動
124
- 4. ✅ 頂部標題始終可見
125
- 5. ✅ 底部 Dismiss 按鈕始終可見
126
- 6. ✅ 滾動流暢,無卡頓
127
-
128
- ### 測試步驟
129
- ```bash
130
- # 1. 確保測試資料存在
131
- bun scripts/test-batch-operations.ts create
132
-
133
- # 2. 打開 Flux Console
134
- # http://localhost:3000
135
-
136
- # 3. 點擊 test-batch 佇列的 Inspect
137
- # 4. 確認可以看到頂部標題和底部按鈕
138
- # 5. 滾動工作列表,確認滾動流暢
139
- ```
140
-
141
- ## 📝 相關文件
142
-
143
- - `src/client/pages/QueuesPage.tsx` - JobInspector 元件
144
- - 修改行數: 255, 258, 294, 505
145
-
146
- ## 🎉 總結
147
-
148
- 這個修復確保了 JobInspector 在處理大量工作時:
149
- - ✅ 高度固定為螢幕高度
150
- - ✅ 內容區域可以獨立滾動
151
- - ✅ 頂部和底部區域始終可見
152
- - ✅ UX 體驗大幅改善