@gravito/zenith 1.0.1 → 1.1.1
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.
- package/CHANGELOG.md +25 -0
- package/ECOSYSTEM_EXPANSION_RFC.md +130 -0
- package/dist/bin.js +11945 -4241
- package/dist/client/assets/index-BSMp8oq_.js +436 -0
- package/dist/client/assets/index-BwxlHx-_.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +11945 -4241
- package/package.json +1 -1
- package/scripts/verify-throttle.ts +6 -2
- package/scripts/worker.ts +2 -1
- package/src/client/Layout.tsx +10 -0
- package/src/client/Sidebar.tsx +9 -0
- package/src/client/ThroughputChart.tsx +9 -0
- package/src/client/WorkerStatus.tsx +14 -3
- package/src/client/components/BrandIcons.tsx +30 -0
- package/src/client/components/ConfirmDialog.tsx +24 -0
- package/src/client/components/JobInspector.tsx +18 -0
- package/src/client/components/LogArchiveModal.tsx +51 -2
- package/src/client/components/NotificationBell.tsx +9 -0
- package/src/client/components/PageHeader.tsx +9 -0
- package/src/client/components/Toaster.tsx +10 -0
- package/src/client/components/UserProfileDropdown.tsx +9 -0
- package/src/client/contexts/AuthContext.tsx +12 -0
- package/src/client/contexts/NotificationContext.tsx +25 -0
- package/src/client/pages/LoginPage.tsx +9 -0
- package/src/client/pages/MetricsPage.tsx +9 -0
- package/src/client/pages/OverviewPage.tsx +9 -0
- package/src/client/pages/PulsePage.tsx +10 -0
- package/src/client/pages/QueuesPage.tsx +9 -0
- package/src/client/pages/SchedulesPage.tsx +9 -0
- package/src/client/pages/SettingsPage.tsx +9 -0
- package/src/client/pages/WorkersPage.tsx +10 -0
- package/src/client/utils.ts +9 -0
- package/src/server/config/ServerConfigManager.ts +87 -0
- package/src/server/index.ts +19 -18
- package/src/server/services/AlertService.ts +16 -3
- package/src/server/services/LogStreamProcessor.ts +93 -0
- package/src/server/services/MaintenanceScheduler.ts +78 -0
- package/src/server/services/PulseService.ts +12 -1
- package/src/server/services/QueueMetricsCollector.ts +138 -0
- package/src/server/services/QueueService.ts +29 -283
- package/src/shared/types.ts +126 -27
- package/vite.config.ts +1 -1
- package/DEMO.md +0 -156
- package/dist/client/assets/index-C332gZ-J.css +0 -1
- package/dist/client/assets/index-D4HibwTK.js +0 -436
package/package.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
console.log('🎧 Connecting to log stream...')
|
|
2
2
|
const req = await fetch('http://localhost:3000/api/logs/stream')
|
|
3
|
-
if (!req.body)
|
|
3
|
+
if (!req.body) {
|
|
4
|
+
throw new Error('No body')
|
|
5
|
+
}
|
|
4
6
|
|
|
5
7
|
const reader = req.body.getReader()
|
|
6
8
|
const decoder = new TextDecoder()
|
|
@@ -16,7 +18,9 @@ console.log(`⏳ Measuring received logs for ${DURATION}ms...`)
|
|
|
16
18
|
async function readStream() {
|
|
17
19
|
while (true) {
|
|
18
20
|
const { done, value } = await reader.read()
|
|
19
|
-
if (done)
|
|
21
|
+
if (done) {
|
|
22
|
+
break
|
|
23
|
+
}
|
|
20
24
|
|
|
21
25
|
const chunk = decoder.decode(value)
|
|
22
26
|
// SSE format: event: log\ndata: ...\n\n
|
package/scripts/worker.ts
CHANGED
|
@@ -53,7 +53,8 @@ if (queuesRaw === 'all') {
|
|
|
53
53
|
|
|
54
54
|
const failRate = parseFloat(process.argv.find((a) => a.startsWith('--fail='))?.split('=')[1] || '0')
|
|
55
55
|
const processDelay = parseInt(
|
|
56
|
-
process.argv.find((a) => a.startsWith('--delay='))?.split('=')[1] || '100'
|
|
56
|
+
process.argv.find((a) => a.startsWith('--delay='))?.split('=')[1] || '100',
|
|
57
|
+
10
|
|
57
58
|
)
|
|
58
59
|
|
|
59
60
|
// Simple Job class for testing
|
package/src/client/Layout.tsx
CHANGED
|
@@ -42,6 +42,16 @@ interface CommandItem {
|
|
|
42
42
|
category: 'Navigation' | 'System' | 'Action'
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The main layout wrapper for the Zenith dashboard.
|
|
47
|
+
*
|
|
48
|
+
* It manages global state for the dashboard, including theme switching,
|
|
49
|
+
* the command palette (Ctrl+K), real-time event streaming (SSE),
|
|
50
|
+
* and the overall responsive structure.
|
|
51
|
+
*
|
|
52
|
+
* @public
|
|
53
|
+
* @since 3.0.0
|
|
54
|
+
*/
|
|
45
55
|
export function Layout({ children }: LayoutProps) {
|
|
46
56
|
const navigate = useNavigate()
|
|
47
57
|
const queryClient = useQueryClient()
|
package/src/client/Sidebar.tsx
CHANGED
|
@@ -18,6 +18,15 @@ interface SidebarProps {
|
|
|
18
18
|
toggleCollapse: () => void
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Sidebar navigation component for the Zenith dashboard.
|
|
23
|
+
*
|
|
24
|
+
* Provides links to various sections of the dashboard and supports
|
|
25
|
+
* a collapsible state to maximize screen space.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
* @since 3.0.0
|
|
29
|
+
*/
|
|
21
30
|
export function Sidebar({ className, collapsed, toggleCollapse }: SidebarProps) {
|
|
22
31
|
const location = useLocation()
|
|
23
32
|
|
|
@@ -15,6 +15,15 @@ interface ThroughputPoint {
|
|
|
15
15
|
count: number
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Real-time throughput visualization component.
|
|
20
|
+
*
|
|
21
|
+
* Displays a live-updating area chart of the number of jobs processed
|
|
22
|
+
* per minute across the system.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
* @since 3.0.0
|
|
26
|
+
*/
|
|
18
27
|
export function ThroughputChart() {
|
|
19
28
|
// Initial fetch via React Query
|
|
20
29
|
const { data: initialData } = useQuery({
|
|
@@ -7,18 +7,20 @@ function cn(...inputs: ClassValue[]) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function formatBytes(bytes: number) {
|
|
10
|
-
if (bytes === 0)
|
|
10
|
+
if (bytes === 0) {
|
|
11
|
+
return '0 B'
|
|
12
|
+
}
|
|
11
13
|
const k = 1024
|
|
12
14
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
13
15
|
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
14
|
-
return parseFloat((bytes / k ** i).toFixed(1))
|
|
16
|
+
return `${parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
function getWorkerName(id: string, pid: number) {
|
|
18
20
|
// If ID contains Hostname+PID, try to simplify it
|
|
19
21
|
// Example: CarldeMacBook-Air.local-99401
|
|
20
22
|
const complexIdMatch = id.match(/^(.*)-(\d+)$/)
|
|
21
|
-
if (complexIdMatch && parseInt(complexIdMatch[2]) === pid) {
|
|
23
|
+
if (complexIdMatch && parseInt(complexIdMatch[2], 10) === pid) {
|
|
22
24
|
// Return just the hostname part, and maybe truncate if too long
|
|
23
25
|
let hostname = complexIdMatch[1]
|
|
24
26
|
if (hostname.endsWith('.local')) {
|
|
@@ -51,6 +53,15 @@ interface WorkerInfo {
|
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Real-time worker node status visualization component.
|
|
58
|
+
*
|
|
59
|
+
* Displays a list of active worker nodes with their CPU, RAM, uptime metrics,
|
|
60
|
+
* and highlights a specific worker if provided.
|
|
61
|
+
*
|
|
62
|
+
* @public
|
|
63
|
+
* @since 3.0.0
|
|
64
|
+
*/
|
|
54
65
|
export function WorkerStatus({
|
|
55
66
|
highlightedWorkerId,
|
|
56
67
|
workers = [],
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { SVGProps } from 'react'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* SVG icon for Node.js runtime.
|
|
5
|
+
* @public
|
|
6
|
+
* @since 3.0.0
|
|
7
|
+
*/
|
|
3
8
|
export function NodeIcon(props: SVGProps<SVGSVGElement>) {
|
|
4
9
|
return (
|
|
5
10
|
<svg
|
|
@@ -19,6 +24,11 @@ export function NodeIcon(props: SVGProps<SVGSVGElement>) {
|
|
|
19
24
|
)
|
|
20
25
|
}
|
|
21
26
|
|
|
27
|
+
/**
|
|
28
|
+
* SVG icon for Bun runtime.
|
|
29
|
+
* @public
|
|
30
|
+
* @since 3.0.0
|
|
31
|
+
*/
|
|
22
32
|
export function BunIcon(props: SVGProps<SVGSVGElement>) {
|
|
23
33
|
return (
|
|
24
34
|
<svg
|
|
@@ -49,6 +59,11 @@ export function BunIcon(props: SVGProps<SVGSVGElement>) {
|
|
|
49
59
|
)
|
|
50
60
|
}
|
|
51
61
|
|
|
62
|
+
/**
|
|
63
|
+
* SVG icon for Deno runtime.
|
|
64
|
+
* @public
|
|
65
|
+
* @since 3.0.0
|
|
66
|
+
*/
|
|
52
67
|
export function DenoIcon(props: SVGProps<SVGSVGElement>) {
|
|
53
68
|
return (
|
|
54
69
|
<svg
|
|
@@ -69,6 +84,11 @@ export function DenoIcon(props: SVGProps<SVGSVGElement>) {
|
|
|
69
84
|
)
|
|
70
85
|
}
|
|
71
86
|
|
|
87
|
+
/**
|
|
88
|
+
* SVG icon for PHP runtime.
|
|
89
|
+
* @public
|
|
90
|
+
* @since 3.0.0
|
|
91
|
+
*/
|
|
72
92
|
export function PhpIcon(props: SVGProps<SVGSVGElement>) {
|
|
73
93
|
return (
|
|
74
94
|
<svg
|
|
@@ -95,6 +115,11 @@ export function PhpIcon(props: SVGProps<SVGSVGElement>) {
|
|
|
95
115
|
)
|
|
96
116
|
}
|
|
97
117
|
|
|
118
|
+
/**
|
|
119
|
+
* SVG icon for Go runtime.
|
|
120
|
+
* @public
|
|
121
|
+
* @since 3.0.0
|
|
122
|
+
*/
|
|
98
123
|
export function GoIcon(props: SVGProps<SVGSVGElement>) {
|
|
99
124
|
return (
|
|
100
125
|
<svg
|
|
@@ -115,6 +140,11 @@ export function GoIcon(props: SVGProps<SVGSVGElement>) {
|
|
|
115
140
|
)
|
|
116
141
|
}
|
|
117
142
|
|
|
143
|
+
/**
|
|
144
|
+
* SVG icon for Python runtime.
|
|
145
|
+
* @public
|
|
146
|
+
* @since 3.0.0
|
|
147
|
+
*/
|
|
118
148
|
export function PythonIcon(props: SVGProps<SVGSVGElement>) {
|
|
119
149
|
return (
|
|
120
150
|
<svg
|
|
@@ -2,18 +2,42 @@ import { AnimatePresence, motion } from 'framer-motion'
|
|
|
2
2
|
import { createPortal } from 'react-dom'
|
|
3
3
|
import { cn } from '../utils'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Props for the ConfirmDialog component.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
* @since 3.0.0
|
|
10
|
+
*/
|
|
5
11
|
export interface ConfirmDialogProps {
|
|
12
|
+
/** Whether the dialog is visible. */
|
|
6
13
|
open: boolean
|
|
14
|
+
/** Dialog title text. */
|
|
7
15
|
title: string
|
|
16
|
+
/** Detailed confirmation message. */
|
|
8
17
|
message: string
|
|
18
|
+
/** Text for the confirmation button. @default 'Confirm' */
|
|
9
19
|
confirmText?: string
|
|
20
|
+
/** Text for the cancel button. @default 'Cancel' */
|
|
10
21
|
cancelText?: string
|
|
22
|
+
/** Callback triggered when user confirms the action. */
|
|
11
23
|
onConfirm: () => void
|
|
24
|
+
/** Callback triggered when user cancels the action. */
|
|
12
25
|
onCancel: () => void
|
|
26
|
+
/** Visual style of the confirmation button. @default 'danger' */
|
|
13
27
|
variant?: 'danger' | 'warning' | 'info'
|
|
28
|
+
/** Whether an action is currently in progress (shows a spinner). @default false */
|
|
14
29
|
isProcessing?: boolean
|
|
15
30
|
}
|
|
16
31
|
|
|
32
|
+
/**
|
|
33
|
+
* A modal dialog used for user confirmation before performing sensitive actions.
|
|
34
|
+
*
|
|
35
|
+
* It provides a consistent UI for confirmations across the Zenith dashboard
|
|
36
|
+
* and supports different visual variants.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
* @since 3.0.0
|
|
40
|
+
*/
|
|
17
41
|
export function ConfirmDialog({
|
|
18
42
|
open,
|
|
19
43
|
title,
|
|
@@ -21,11 +21,29 @@ interface Job {
|
|
|
21
21
|
_archivedAt?: string
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Props for the JobInspector component.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
* @since 3.0.0
|
|
29
|
+
*/
|
|
24
30
|
export interface JobInspectorProps {
|
|
31
|
+
/** The name of the queue to inspect. */
|
|
25
32
|
queueName: string
|
|
33
|
+
/** Callback triggered when the inspector is closed. */
|
|
26
34
|
onClose: () => void
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
/**
|
|
38
|
+
* A detailed view for inspecting jobs within a specific queue.
|
|
39
|
+
*
|
|
40
|
+
* It provides tabs for viewing waiting, delayed, and failed jobs,
|
|
41
|
+
* as well as an archive search. Users can perform bulk actions like
|
|
42
|
+
* deleting or retrying jobs.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
* @since 3.0.0
|
|
46
|
+
*/
|
|
29
47
|
export function JobInspector({ queueName, onClose }: JobInspectorProps) {
|
|
30
48
|
const [view, setView] = React.useState<'waiting' | 'delayed' | 'failed' | 'archive'>('waiting')
|
|
31
49
|
const [page, setPage] = React.useState(1)
|
|
@@ -17,6 +17,15 @@ interface LogArchiveModalProps {
|
|
|
17
17
|
onClose: () => void
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* A modal for exploring and searching historical application logs and job events.
|
|
22
|
+
*
|
|
23
|
+
* It provides advanced filtering by search query, time range, and severity level.
|
|
24
|
+
* Users can trace specific events across time and export the audit trail.
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
* @since 3.0.0
|
|
28
|
+
*/
|
|
20
29
|
export function LogArchiveModal({ isOpen, onClose }: LogArchiveModalProps) {
|
|
21
30
|
const [page, setPage] = React.useState(1)
|
|
22
31
|
const [search, setSearch] = React.useState('')
|
|
@@ -329,9 +338,49 @@ export function LogArchiveModal({ isOpen, onClose }: LogArchiveModalProps) {
|
|
|
329
338
|
|
|
330
339
|
{/* Footer / Pagination */}
|
|
331
340
|
<div className="p-4 border-t bg-muted/5 flex flex-col sm:flex-row justify-between items-center gap-4 text-[10px] uppercase font-bold text-muted-foreground">
|
|
332
|
-
<div>
|
|
333
|
-
|
|
341
|
+
<div className="flex items-center gap-4">
|
|
342
|
+
<span>
|
|
343
|
+
Scanning {total.toLocaleString()} events • Page {page} of {totalPages || 1}
|
|
344
|
+
</span>
|
|
345
|
+
|
|
346
|
+
<div className="h-4 w-px bg-border/50 hidden sm:block"></div>
|
|
347
|
+
|
|
348
|
+
{/* Export Controls */}
|
|
349
|
+
<div className="flex items-center gap-2">
|
|
350
|
+
<select
|
|
351
|
+
className="bg-background border border-border/50 rounded-lg px-2 py-1 outline-none focus:ring-1 focus:ring-primary/30"
|
|
352
|
+
onChange={(e) => {
|
|
353
|
+
// Trigger export
|
|
354
|
+
const format = e.target.value
|
|
355
|
+
const url = new URL('/api/logs/export', window.location.href)
|
|
356
|
+
if (search) {
|
|
357
|
+
url.searchParams.set('search', search)
|
|
358
|
+
}
|
|
359
|
+
if (status !== 'all') {
|
|
360
|
+
url.searchParams.set('status', status)
|
|
361
|
+
}
|
|
362
|
+
if (dateRange.start) {
|
|
363
|
+
url.searchParams.set('startTime', dateRange.start)
|
|
364
|
+
}
|
|
365
|
+
if (dateRange.end) {
|
|
366
|
+
url.searchParams.set('endTime', dateRange.end)
|
|
367
|
+
}
|
|
368
|
+
url.searchParams.set('format', format)
|
|
369
|
+
|
|
370
|
+
// For now, just open in new tab to trigger download
|
|
371
|
+
window.open(url.toString(), '_blank')
|
|
372
|
+
}}
|
|
373
|
+
defaultValue=""
|
|
374
|
+
>
|
|
375
|
+
<option value="" disabled>
|
|
376
|
+
Export As...
|
|
377
|
+
</option>
|
|
378
|
+
<option value="json">JSON</option>
|
|
379
|
+
<option value="csv">CSV</option>
|
|
380
|
+
</select>
|
|
381
|
+
</div>
|
|
334
382
|
</div>
|
|
383
|
+
|
|
335
384
|
<div className="flex items-center gap-2">
|
|
336
385
|
<button
|
|
337
386
|
type="button"
|
|
@@ -13,6 +13,15 @@ import { useEffect, useRef, useState } from 'react'
|
|
|
13
13
|
import { type Notification, useNotifications } from '../contexts/NotificationContext'
|
|
14
14
|
import { cn } from '../utils'
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A notification bell icon component with a dropdown panel.
|
|
18
|
+
*
|
|
19
|
+
* Displays the unread notification count and provides a list view of recent
|
|
20
|
+
* system notifications with mark-as-read and clear-all functionality.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
* @since 3.0.0
|
|
24
|
+
*/
|
|
16
25
|
export function NotificationBell() {
|
|
17
26
|
const [isOpen, setIsOpen] = useState(false)
|
|
18
27
|
const { notifications, unreadCount, markAsRead, markAllAsRead, clearAll, removeNotification } =
|
|
@@ -10,6 +10,15 @@ interface PageHeaderProps {
|
|
|
10
10
|
className?: string
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Reusable header component for Zenith dashboard pages.
|
|
15
|
+
*
|
|
16
|
+
* Provides a consistent layout for the page title, icon, description,
|
|
17
|
+
* and optional action buttons.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
* @since 3.0.0
|
|
21
|
+
*/
|
|
13
22
|
export function PageHeader({
|
|
14
23
|
icon: Icon,
|
|
15
24
|
title,
|
|
@@ -4,6 +4,16 @@ import { useEffect, useState } from 'react'
|
|
|
4
4
|
import { useNotifications } from '../contexts/NotificationContext'
|
|
5
5
|
import { cn } from '../utils'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Global toast notification container for Zenith.
|
|
9
|
+
*
|
|
10
|
+
* Renders an animated stack of floating notifications in the corner of the
|
|
11
|
+
* screen. It integrates with the `NotificationContext` to display real-time
|
|
12
|
+
* alerts and messages.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
* @since 3.0.0
|
|
16
|
+
*/
|
|
7
17
|
export function Toaster() {
|
|
8
18
|
const { notifications, removeNotification } = useNotifications()
|
|
9
19
|
const [activeIds, setActiveIds] = useState<Set<string>>(new Set())
|
|
@@ -5,6 +5,15 @@ import { useEffect, useRef, useState } from 'react'
|
|
|
5
5
|
import { useNavigate } from 'react-router-dom'
|
|
6
6
|
import { useAuth } from '../contexts/AuthContext'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* A user profile dropdown component for the Zenith dashboard.
|
|
10
|
+
*
|
|
11
|
+
* Displays current user information, system uptime, and provides access
|
|
12
|
+
* to settings and logout functionality.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
* @since 3.0.0
|
|
16
|
+
*/
|
|
8
17
|
export function UserProfileDropdown() {
|
|
9
18
|
const [isOpen, setIsOpen] = useState(false)
|
|
10
19
|
const { isAuthEnabled, logout } = useAuth()
|
|
@@ -11,6 +11,12 @@ interface AuthContextType {
|
|
|
11
11
|
|
|
12
12
|
const AuthContext = createContext<AuthContextType | null>(null)
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* React hook to access authentication state and methods.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
* @since 3.0.0
|
|
19
|
+
*/
|
|
14
20
|
export function useAuth() {
|
|
15
21
|
const context = useContext(AuthContext)
|
|
16
22
|
if (!context) {
|
|
@@ -23,6 +29,12 @@ interface AuthProviderProps {
|
|
|
23
29
|
children: ReactNode
|
|
24
30
|
}
|
|
25
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Provider component for managing global authentication state in Zenith.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
* @since 3.0.0
|
|
37
|
+
*/
|
|
26
38
|
export function AuthProvider({ children }: AuthProviderProps) {
|
|
27
39
|
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
|
28
40
|
const [isAuthEnabled, setIsAuthEnabled] = useState(false)
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import { createContext, type ReactNode, useCallback, useContext, useEffect, useState } from 'react'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Represents a system notification in the Zenith dashboard.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
* @since 3.0.0
|
|
8
|
+
*/
|
|
3
9
|
export interface Notification {
|
|
10
|
+
/** Unique notification ID. */
|
|
4
11
|
id: string
|
|
12
|
+
/** The severity type of the notification. */
|
|
5
13
|
type: 'info' | 'success' | 'warning' | 'error'
|
|
14
|
+
/** Short title for the notification. */
|
|
6
15
|
title: string
|
|
16
|
+
/** Detailed notification message. */
|
|
7
17
|
message: string
|
|
18
|
+
/** Epoch timestamp when the notification was created. */
|
|
8
19
|
timestamp: number
|
|
20
|
+
/** Whether the notification has been read by the user. */
|
|
9
21
|
read: boolean
|
|
22
|
+
/** Optional source identifier (e.g., a queue name). */
|
|
10
23
|
source?: string
|
|
11
24
|
}
|
|
12
25
|
|
|
@@ -22,6 +35,12 @@ interface NotificationContextType {
|
|
|
22
35
|
|
|
23
36
|
const NotificationContext = createContext<NotificationContextType | null>(null)
|
|
24
37
|
|
|
38
|
+
/**
|
|
39
|
+
* React hook to access the notification system.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
* @since 3.0.0
|
|
43
|
+
*/
|
|
25
44
|
export function useNotifications() {
|
|
26
45
|
const context = useContext(NotificationContext)
|
|
27
46
|
if (!context) {
|
|
@@ -34,6 +53,12 @@ interface NotificationProviderProps {
|
|
|
34
53
|
children: ReactNode
|
|
35
54
|
}
|
|
36
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Provider component for managing global notifications in Zenith.
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
* @since 3.0.0
|
|
61
|
+
*/
|
|
37
62
|
export function NotificationProvider({ children }: NotificationProviderProps) {
|
|
38
63
|
const [notifications, setNotifications] = useState<Notification[]>([])
|
|
39
64
|
|
|
@@ -4,6 +4,15 @@ import { useState } from 'react'
|
|
|
4
4
|
import { useAuth } from '../contexts/AuthContext'
|
|
5
5
|
import { cn } from '../utils'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* The login page for the Zenith dashboard.
|
|
9
|
+
*
|
|
10
|
+
* Provides a secure, password-protected entry point to the administration
|
|
11
|
+
* console with modern UI effects and smooth animations.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
* @since 3.0.0
|
|
15
|
+
*/
|
|
7
16
|
export function LoginPage() {
|
|
8
17
|
const { login } = useAuth()
|
|
9
18
|
const [password, setPassword] = useState('')
|
|
@@ -25,6 +25,15 @@ import {
|
|
|
25
25
|
} from 'recharts'
|
|
26
26
|
import { cn } from '../utils'
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* System Metrics Page.
|
|
30
|
+
*
|
|
31
|
+
* Displays detailed performance analytics, throughput trends, and queue
|
|
32
|
+
* distribution charts using interactive visualizations.
|
|
33
|
+
*
|
|
34
|
+
* @public
|
|
35
|
+
* @since 3.0.0
|
|
36
|
+
*/
|
|
28
37
|
export function MetricsPage() {
|
|
29
38
|
const [timeRange, setTimeRange] = React.useState<'15m' | '1h' | '6h' | '24h'>('15m')
|
|
30
39
|
|
|
@@ -347,6 +347,15 @@ function QueueList({
|
|
|
347
347
|
)
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
/**
|
|
351
|
+
* System Overview Dashboard Page.
|
|
352
|
+
*
|
|
353
|
+
* Provides a high-level, real-time view of all processing pipelines,
|
|
354
|
+
* including job counts, worker status, and live operational logs.
|
|
355
|
+
*
|
|
356
|
+
* @public
|
|
357
|
+
* @since 3.0.0
|
|
358
|
+
*/
|
|
350
359
|
export function OverviewPage() {
|
|
351
360
|
const [selectedQueue, setSelectedQueue] = React.useState<string | null>(null)
|
|
352
361
|
const [hoveredWorkerId, setHoveredWorkerId] = React.useState<string | null>(null)
|
|
@@ -394,6 +394,16 @@ function ServiceGroup({ service, nodes }: { service: string; nodes: PulseNode[]
|
|
|
394
394
|
)
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
+
/**
|
|
398
|
+
* System Pulse Dashboard Page.
|
|
399
|
+
*
|
|
400
|
+
* Provides real-time resource monitoring (CPU, RAM) and service discovery
|
|
401
|
+
* for all connected Quasar agents. It also allows remote management of
|
|
402
|
+
* connected worker nodes.
|
|
403
|
+
*
|
|
404
|
+
* @public
|
|
405
|
+
* @since 3.0.0
|
|
406
|
+
*/
|
|
397
407
|
export function PulsePage() {
|
|
398
408
|
const { data: initialData, isLoading } = useQuery<{ nodes: Record<string, PulseNode[]> }>({
|
|
399
409
|
queryKey: ['pulse-nodes'],
|
|
@@ -26,6 +26,15 @@ interface QueueStats {
|
|
|
26
26
|
paused?: boolean
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Queue Management Page.
|
|
31
|
+
*
|
|
32
|
+
* Provides detailed monitoring and management controls for message queues,
|
|
33
|
+
* including job inspection, pausing/resuming queues, and bulk retry/purge actions.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
* @since 3.0.0
|
|
37
|
+
*/
|
|
29
38
|
export function QueuesPage() {
|
|
30
39
|
const [selectedQueue, setSelectedQueue] = React.useState<string | null>(null)
|
|
31
40
|
const [searchQuery, setSearchQuery] = React.useState('')
|
|
@@ -45,6 +45,15 @@ interface QueueListItem {
|
|
|
45
45
|
paused: boolean
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Task Schedules Page.
|
|
50
|
+
*
|
|
51
|
+
* View and manage all recurring jobs and cron tasks. Users can register new
|
|
52
|
+
* schedules, manually trigger execution, or delete existing schedules.
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
* @since 3.0.0
|
|
56
|
+
*/
|
|
48
57
|
export function SchedulesPage() {
|
|
49
58
|
const queryClient = useQueryClient()
|
|
50
59
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
@@ -17,6 +17,15 @@ import {
|
|
|
17
17
|
import React from 'react'
|
|
18
18
|
import { cn } from '../utils'
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* System Settings Page.
|
|
22
|
+
*
|
|
23
|
+
* Allows administrators to configure dashboard appearance, monitoring alerts,
|
|
24
|
+
* and data retention policies. It also provides system-level information.
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
* @since 3.0.0
|
|
28
|
+
*/
|
|
20
29
|
export function SettingsPage() {
|
|
21
30
|
const queryClient = useQueryClient()
|
|
22
31
|
const [showAddRule, setShowAddRule] = React.useState(false)
|
|
@@ -35,6 +35,16 @@ interface Worker {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Worker Nodes Dashboard Page.
|
|
40
|
+
*
|
|
41
|
+
* Provides a detailed view of all active and inactive worker nodes in the
|
|
42
|
+
* cluster, including their resource usage, monitored queues, and Laravel
|
|
43
|
+
* worker status.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
* @since 3.0.0
|
|
47
|
+
*/
|
|
38
48
|
export function WorkersPage() {
|
|
39
49
|
const queryClient = useQueryClient()
|
|
40
50
|
const { isPending, error, data } = useQuery<{ workers: Worker[] }>({
|
package/src/client/utils.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type ClassValue, clsx } from 'clsx'
|
|
2
2
|
import { twMerge } from 'tailwind-merge'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Conditionally join class names and merge Tailwind CSS classes.
|
|
6
|
+
*
|
|
7
|
+
* @param inputs - A list of class values to be merged.
|
|
8
|
+
* @returns The merged class string.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
* @since 3.0.0
|
|
12
|
+
*/
|
|
4
13
|
export function cn(...inputs: ClassValue[]) {
|
|
5
14
|
return twMerge(clsx(inputs))
|
|
6
15
|
}
|