@gravito/zenith 1.1.3 → 1.1.6
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/README.md +28 -10
- package/dist/bin.js +43235 -76691
- package/dist/client/index.html +13 -0
- package/dist/server/index.js +43235 -76691
- package/package.json +16 -7
- package/CHANGELOG.md +0 -62
- package/Dockerfile +0 -46
- package/Dockerfile.demo-worker +0 -29
- package/bin/flux-console.ts +0 -2
- package/doc/ECOSYSTEM_EXPANSION_RFC.md +0 -130
- package/docker-compose.yml +0 -40
- package/docs/ALERTING_GUIDE.md +0 -71
- package/docs/DEPLOYMENT.md +0 -157
- package/docs/DOCS_INTERNAL.md +0 -73
- package/docs/LARAVEL_ZENITH_ROADMAP.md +0 -109
- package/docs/QUASAR_MASTER_PLAN.md +0 -140
- package/docs/QUICK_TEST_GUIDE.md +0 -72
- package/docs/ROADMAP.md +0 -85
- package/docs/integrations/LARAVEL.md +0 -207
- package/postcss.config.js +0 -6
- package/scripts/debug_redis_keys.ts +0 -24
- package/scripts/flood-logs.ts +0 -21
- package/scripts/seed.ts +0 -213
- package/scripts/verify-throttle.ts +0 -49
- package/scripts/worker.ts +0 -124
- package/specs/PULSE_SPEC.md +0 -86
- package/src/bin.ts +0 -6
- package/src/client/App.tsx +0 -72
- package/src/client/Layout.tsx +0 -669
- package/src/client/Sidebar.tsx +0 -112
- package/src/client/ThroughputChart.tsx +0 -158
- package/src/client/WorkerStatus.tsx +0 -202
- package/src/client/components/BrandIcons.tsx +0 -168
- package/src/client/components/ConfirmDialog.tsx +0 -134
- package/src/client/components/JobInspector.tsx +0 -487
- package/src/client/components/LogArchiveModal.tsx +0 -432
- package/src/client/components/NotificationBell.tsx +0 -212
- package/src/client/components/PageHeader.tsx +0 -47
- package/src/client/components/Toaster.tsx +0 -90
- package/src/client/components/UserProfileDropdown.tsx +0 -186
- package/src/client/contexts/AuthContext.tsx +0 -105
- package/src/client/contexts/NotificationContext.tsx +0 -128
- package/src/client/index.css +0 -172
- package/src/client/main.tsx +0 -15
- package/src/client/pages/LoginPage.tsx +0 -164
- package/src/client/pages/MetricsPage.tsx +0 -445
- package/src/client/pages/OverviewPage.tsx +0 -519
- package/src/client/pages/PulsePage.tsx +0 -409
- package/src/client/pages/QueuesPage.tsx +0 -378
- package/src/client/pages/SchedulesPage.tsx +0 -535
- package/src/client/pages/SettingsPage.tsx +0 -1001
- package/src/client/pages/WorkersPage.tsx +0 -380
- package/src/client/pages/index.ts +0 -8
- package/src/client/utils.ts +0 -15
- package/src/server/config/ServerConfigManager.ts +0 -90
- package/src/server/index.ts +0 -860
- package/src/server/middleware/auth.ts +0 -127
- package/src/server/services/AlertService.ts +0 -321
- package/src/server/services/CommandService.ts +0 -136
- package/src/server/services/LogStreamProcessor.ts +0 -93
- package/src/server/services/MaintenanceScheduler.ts +0 -78
- package/src/server/services/PulseService.ts +0 -148
- package/src/server/services/QueueMetricsCollector.ts +0 -138
- package/src/server/services/QueueService.ts +0 -924
- package/src/shared/types.ts +0 -223
- package/tailwind.config.js +0 -80
- package/tests/placeholder.test.ts +0 -7
- package/tsconfig.json +0 -29
- package/tsconfig.node.json +0 -10
- package/vite.config.ts +0 -27
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
2
|
-
import { motion } from 'framer-motion'
|
|
3
|
-
import { AlertCircle, Clock, Cpu, Gauge, MemoryStick, RefreshCcw, Server, Zap } from 'lucide-react'
|
|
4
|
-
import { useEffect } from 'react'
|
|
5
|
-
import { cn } from '../utils'
|
|
6
|
-
|
|
7
|
-
interface Worker {
|
|
8
|
-
id: string
|
|
9
|
-
status: string
|
|
10
|
-
pid: number
|
|
11
|
-
uptime: number
|
|
12
|
-
metrics?: {
|
|
13
|
-
cpu: number
|
|
14
|
-
cores?: number
|
|
15
|
-
ram: {
|
|
16
|
-
rss: number
|
|
17
|
-
heapUsed: number
|
|
18
|
-
total?: number
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
queues?: {
|
|
22
|
-
name: string
|
|
23
|
-
size: {
|
|
24
|
-
waiting: number
|
|
25
|
-
active: number
|
|
26
|
-
failed: number
|
|
27
|
-
delayed: number
|
|
28
|
-
}
|
|
29
|
-
}[]
|
|
30
|
-
meta?: {
|
|
31
|
-
laravel?: {
|
|
32
|
-
workerCount: number
|
|
33
|
-
roots: string[]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
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
|
-
*/
|
|
48
|
-
export function WorkersPage() {
|
|
49
|
-
const queryClient = useQueryClient()
|
|
50
|
-
const { isPending, error, data } = useQuery<{ workers: Worker[] }>({
|
|
51
|
-
queryKey: ['workers'],
|
|
52
|
-
queryFn: async () => {
|
|
53
|
-
const res = await fetch('/api/workers')
|
|
54
|
-
return res.json()
|
|
55
|
-
},
|
|
56
|
-
refetchInterval: 5000,
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// Listen to real-time stats updates from SSE
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
const handler = (e: any) => {
|
|
62
|
-
if (e.detail?.workers) {
|
|
63
|
-
// Optimistically update the query cache with fresh worker data from SSE
|
|
64
|
-
queryClient.setQueryData(['workers'], { workers: e.detail.workers })
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
window.addEventListener('flux-stats-update', handler)
|
|
68
|
-
return () => window.removeEventListener('flux-stats-update', handler)
|
|
69
|
-
}, [queryClient])
|
|
70
|
-
|
|
71
|
-
const workers = data?.workers || []
|
|
72
|
-
const onlineWorkers = workers.filter((w) => w.status === 'online')
|
|
73
|
-
const offlineWorkers = workers.filter((w) => w.status !== 'online')
|
|
74
|
-
|
|
75
|
-
const totalCpu = workers.reduce((acc, w) => acc + (w.metrics?.cpu || 0), 0)
|
|
76
|
-
const avgCpu = workers.length > 0 ? totalCpu / workers.length : 0
|
|
77
|
-
const totalRam = workers.reduce((acc, w) => acc + (w.metrics?.ram?.rss || 0), 0)
|
|
78
|
-
|
|
79
|
-
if (isPending) {
|
|
80
|
-
return (
|
|
81
|
-
<div className="flex flex-col items-center justify-center p-20 space-y-6">
|
|
82
|
-
<RefreshCcw className="animate-spin text-primary" size={48} />
|
|
83
|
-
<p className="text-muted-foreground font-bold uppercase tracking-[0.3em] text-xs">
|
|
84
|
-
Loading workers...
|
|
85
|
-
</p>
|
|
86
|
-
</div>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (error) {
|
|
91
|
-
return (
|
|
92
|
-
<div className="text-center p-20">
|
|
93
|
-
<div className="bg-red-500/10 text-red-500 p-10 rounded-3xl border border-red-500/20 max-w-md mx-auto shadow-2xl">
|
|
94
|
-
<AlertCircle size={56} className="mx-auto mb-6 opacity-80" />
|
|
95
|
-
<h3 className="text-2xl font-black mb-2 uppercase tracking-tight">
|
|
96
|
-
Failed to Load Workers
|
|
97
|
-
</h3>
|
|
98
|
-
<p className="text-sm font-medium opacity-70">{error.message}</p>
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<div className="space-y-8">
|
|
106
|
-
{/* Header */}
|
|
107
|
-
<div className="flex justify-between items-end">
|
|
108
|
-
<div>
|
|
109
|
-
<h1 className="text-4xl font-black tracking-tighter">Worker Nodes</h1>
|
|
110
|
-
<p className="text-muted-foreground mt-2 text-sm font-bold opacity-60 uppercase tracking-widest">
|
|
111
|
-
Monitor and manage cluster processing nodes.
|
|
112
|
-
</p>
|
|
113
|
-
</div>
|
|
114
|
-
<div className="flex items-center gap-2 text-[10px] font-black text-green-500 bg-green-500/10 px-4 py-2 rounded-full border border-green-500/20 uppercase tracking-[0.2em]">
|
|
115
|
-
<span className="w-2 h-2 bg-green-500 rounded-full shadow-[0_0_8px_rgba(34,197,94,0.6)] animate-pulse"></span>
|
|
116
|
-
{onlineWorkers.length} Online
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
|
|
120
|
-
{/* Summary Cards */}
|
|
121
|
-
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
|
122
|
-
<div className="card-premium p-5 relative overflow-hidden group border-l-4 border-emerald-500">
|
|
123
|
-
<div className="relative">
|
|
124
|
-
<div className="flex items-center gap-2 mb-3">
|
|
125
|
-
<Server size={14} className="text-emerald-500" />
|
|
126
|
-
<p className="text-[9px] font-black text-muted-foreground/60 uppercase tracking-[0.2em] font-heading">
|
|
127
|
-
Operational Nodes
|
|
128
|
-
</p>
|
|
129
|
-
</div>
|
|
130
|
-
<p className="text-3xl font-black text-white font-mono tracking-tighter">
|
|
131
|
-
{onlineWorkers.length}
|
|
132
|
-
</p>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
<div className="card-premium p-5 relative overflow-hidden group border-l-4 border-white/10">
|
|
136
|
-
<div className="relative">
|
|
137
|
-
<div className="flex items-center gap-2 mb-3">
|
|
138
|
-
<Zap size={14} className="text-white/20" />
|
|
139
|
-
<p className="text-[9px] font-black text-muted-foreground/60 uppercase tracking-[0.2em] font-heading">
|
|
140
|
-
Standby Nodes
|
|
141
|
-
</p>
|
|
142
|
-
</div>
|
|
143
|
-
<p className="text-3xl font-black text-white/40 font-mono tracking-tighter">
|
|
144
|
-
{offlineWorkers.length}
|
|
145
|
-
</p>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
<div className="card-premium p-5 relative overflow-hidden group border-l-4 border-primary/40">
|
|
149
|
-
<div className="relative">
|
|
150
|
-
<div className="flex items-center gap-2 mb-3">
|
|
151
|
-
<Gauge size={14} className="text-primary" />
|
|
152
|
-
<p className="text-[9px] font-black text-muted-foreground/60 uppercase tracking-[0.2em] font-heading">
|
|
153
|
-
Compute Load
|
|
154
|
-
</p>
|
|
155
|
-
</div>
|
|
156
|
-
<p className="text-3xl font-black text-white font-mono tracking-tighter">
|
|
157
|
-
{avgCpu.toFixed(2)}
|
|
158
|
-
</p>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
<div className="card-premium p-5 relative overflow-hidden group border-l-4 border-indigo-500/40">
|
|
162
|
-
<div className="relative">
|
|
163
|
-
<div className="flex items-center gap-2 mb-3">
|
|
164
|
-
<MemoryStick size={14} className="text-indigo-400" />
|
|
165
|
-
<p className="text-[9px] font-black text-muted-foreground/60 uppercase tracking-[0.2em] font-heading">
|
|
166
|
-
Cluster Memory
|
|
167
|
-
</p>
|
|
168
|
-
</div>
|
|
169
|
-
<div className="flex items-baseline gap-1">
|
|
170
|
-
<p className="text-3xl font-black text-white font-mono tracking-tighter">
|
|
171
|
-
{(totalRam / 1024).toFixed(1)}
|
|
172
|
-
</p>
|
|
173
|
-
<span className="text-[10px] font-black text-white/20 uppercase tracking-tighter">
|
|
174
|
-
GB
|
|
175
|
-
</span>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
180
|
-
|
|
181
|
-
{/* Workers Grid */}
|
|
182
|
-
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
|
183
|
-
{workers.length === 0 && (
|
|
184
|
-
<div className="col-span-full py-32 text-center text-muted-foreground/20">
|
|
185
|
-
<Cpu size={48} className="mx-auto mb-4 opacity-30 animate-pulse" />
|
|
186
|
-
<p className="text-[10px] font-black uppercase tracking-[0.3em]">
|
|
187
|
-
Awaiting signal from constellation...
|
|
188
|
-
</p>
|
|
189
|
-
</div>
|
|
190
|
-
)}
|
|
191
|
-
{workers.map((worker, index) => (
|
|
192
|
-
<motion.div
|
|
193
|
-
key={worker.id}
|
|
194
|
-
initial={{ opacity: 0, scale: 0.98 }}
|
|
195
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
196
|
-
transition={{ delay: index * 0.05 }}
|
|
197
|
-
className="card-premium p-6 relative overflow-hidden group border-l-4"
|
|
198
|
-
style={{ borderLeftColor: worker.status === 'online' ? '#10B981' : '#27272A' }}
|
|
199
|
-
>
|
|
200
|
-
{/* Header */}
|
|
201
|
-
<div className="flex items-start justify-between mb-8">
|
|
202
|
-
<div className="flex items-center gap-4">
|
|
203
|
-
<div className="relative">
|
|
204
|
-
<div
|
|
205
|
-
className={cn(
|
|
206
|
-
'w-12 h-12 rounded-xl flex items-center justify-center transition-all border border-white/5',
|
|
207
|
-
worker.status === 'online'
|
|
208
|
-
? 'bg-emerald-500/10 text-emerald-500'
|
|
209
|
-
: 'bg-zinc-800 text-muted-foreground/40'
|
|
210
|
-
)}
|
|
211
|
-
>
|
|
212
|
-
<Cpu size={24} />
|
|
213
|
-
</div>
|
|
214
|
-
{worker.status === 'online' && (
|
|
215
|
-
<div className="absolute -bottom-1 -right-1 w-4 h-4 rounded-full border-4 border-zinc-950 bg-emerald-500 animate-pulse shadow-[0_0_10px_#10B981]" />
|
|
216
|
-
)}
|
|
217
|
-
</div>
|
|
218
|
-
<div>
|
|
219
|
-
<h3 className="font-black tracking-tight text-base group-hover:text-primary transition-colors font-heading uppercase italic">
|
|
220
|
-
{worker.id}
|
|
221
|
-
</h3>
|
|
222
|
-
<p className="text-[9px] font-bold text-muted-foreground/40 uppercase tracking-[0.2em] font-mono mt-1">
|
|
223
|
-
PID: {worker.pid}
|
|
224
|
-
</p>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
<span
|
|
228
|
-
className={cn(
|
|
229
|
-
'px-2 py-1 rounded-md text-[8px] font-black uppercase tracking-widest border transition-all',
|
|
230
|
-
worker.status === 'online'
|
|
231
|
-
? 'bg-emerald-500/10 text-emerald-500 border-emerald-500/20 shadow-[0_0_10px_rgba(16,185,129,0.1)]'
|
|
232
|
-
: 'bg-zinc-800/50 text-muted-foreground/40 border-transparent'
|
|
233
|
-
)}
|
|
234
|
-
>
|
|
235
|
-
{worker.status}
|
|
236
|
-
</span>
|
|
237
|
-
</div>
|
|
238
|
-
|
|
239
|
-
{/* Metrics */}
|
|
240
|
-
{worker.metrics && (
|
|
241
|
-
<div className="space-y-5 font-mono">
|
|
242
|
-
{/* CPU */}
|
|
243
|
-
<div>
|
|
244
|
-
<div className="flex justify-between text-[9px] font-black uppercase tracking-widest mb-2.5">
|
|
245
|
-
<span className="text-muted-foreground/60">CPU Compute Power</span>
|
|
246
|
-
<span
|
|
247
|
-
className={cn(
|
|
248
|
-
worker.metrics.cpu > (worker.metrics.cores || 4)
|
|
249
|
-
? 'text-red-500'
|
|
250
|
-
: worker.metrics.cpu > (worker.metrics.cores || 4) * 0.7
|
|
251
|
-
? 'text-amber-500 font-black'
|
|
252
|
-
: 'text-primary font-black'
|
|
253
|
-
)}
|
|
254
|
-
>
|
|
255
|
-
{worker.metrics.cpu.toFixed(2)}%
|
|
256
|
-
</span>
|
|
257
|
-
</div>
|
|
258
|
-
<div className="h-1.5 w-full bg-black/40 rounded-full overflow-hidden border border-white/5">
|
|
259
|
-
<motion.div
|
|
260
|
-
initial={{ width: 0 }}
|
|
261
|
-
animate={{
|
|
262
|
-
width: `${Math.min(100, (worker.metrics.cpu / (worker.metrics.cores || 1)) * 100)}%`,
|
|
263
|
-
}}
|
|
264
|
-
transition={{ duration: 1 }}
|
|
265
|
-
className={cn(
|
|
266
|
-
'h-full transition-colors relative',
|
|
267
|
-
worker.metrics.cpu > (worker.metrics.cores || 4)
|
|
268
|
-
? 'bg-red-500'
|
|
269
|
-
: worker.metrics.cpu > (worker.metrics.cores || 4) * 0.7
|
|
270
|
-
? 'bg-amber-500'
|
|
271
|
-
: 'bg-primary shadow-[0_0_10px_#00F0FF]'
|
|
272
|
-
)}
|
|
273
|
-
/>
|
|
274
|
-
</div>
|
|
275
|
-
</div>
|
|
276
|
-
|
|
277
|
-
{/* RAM */}
|
|
278
|
-
<div>
|
|
279
|
-
<div className="flex justify-between text-[9px] font-black uppercase tracking-widest mb-2.5">
|
|
280
|
-
<span className="text-muted-foreground/60">Memory Integrity</span>
|
|
281
|
-
<span className="text-white/80 font-black">
|
|
282
|
-
{(worker.metrics.ram.rss / 1024).toFixed(2)} GB
|
|
283
|
-
</span>
|
|
284
|
-
</div>
|
|
285
|
-
<div className="h-1.5 w-full bg-black/40 rounded-full overflow-hidden border border-white/5">
|
|
286
|
-
<motion.div
|
|
287
|
-
initial={{ width: 0 }}
|
|
288
|
-
animate={{
|
|
289
|
-
width: `${Math.min(100, (worker.metrics.ram.rss / (worker.metrics.ram.total || 2048)) * 100)}%`,
|
|
290
|
-
}}
|
|
291
|
-
transition={{ duration: 1 }}
|
|
292
|
-
className="h-full bg-indigo-500 shadow-[0_0_10px_#6366F1]"
|
|
293
|
-
/>
|
|
294
|
-
</div>
|
|
295
|
-
</div>
|
|
296
|
-
</div>
|
|
297
|
-
)}
|
|
298
|
-
|
|
299
|
-
{/* Laravel & Queue Info (New) */}
|
|
300
|
-
<div className="mt-8 space-y-3">
|
|
301
|
-
{/* Monitored Queues */}
|
|
302
|
-
{worker.queues && worker.queues.length > 0 && (
|
|
303
|
-
<div className="bg-white/[0.02] p-4 rounded-xl border border-white/5">
|
|
304
|
-
<div className="flex items-center gap-2 mb-3">
|
|
305
|
-
<div className="w-1.5 h-1.5 bg-primary rounded-full shadow-[0_0_8px_#00F0FF]" />
|
|
306
|
-
<span className="text-[9px] font-black uppercase tracking-[0.2em] text-muted-foreground/60 font-heading">
|
|
307
|
-
Pipeline Access
|
|
308
|
-
</span>
|
|
309
|
-
</div>
|
|
310
|
-
<div className="flex flex-wrap gap-2">
|
|
311
|
-
{worker.queues.map((q, i) => (
|
|
312
|
-
<div
|
|
313
|
-
key={i}
|
|
314
|
-
className="flex items-center gap-2 text-[10px] font-black text-foreground/60 bg-black/40 px-2 py-1 rounded border border-white/5 font-mono"
|
|
315
|
-
>
|
|
316
|
-
<span className="opacity-40">{q.name}</span>
|
|
317
|
-
{(q.size.waiting > 0 || q.size.failed > 0) && (
|
|
318
|
-
<span
|
|
319
|
-
className={cn(
|
|
320
|
-
'px-1 rounded text-[8px] border',
|
|
321
|
-
q.size.failed > 0
|
|
322
|
-
? 'text-red-500 bg-red-500/10 border-red-500/20'
|
|
323
|
-
: 'text-primary bg-primary/10 border-primary/20'
|
|
324
|
-
)}
|
|
325
|
-
>
|
|
326
|
-
{q.size.failed > 0 ? `! FAIL` : `${q.size.waiting}W`}
|
|
327
|
-
</span>
|
|
328
|
-
)}
|
|
329
|
-
</div>
|
|
330
|
-
))}
|
|
331
|
-
</div>
|
|
332
|
-
</div>
|
|
333
|
-
)}
|
|
334
|
-
|
|
335
|
-
{/* Laravel Workers Info */}
|
|
336
|
-
{worker.meta?.laravel && (
|
|
337
|
-
<div className="flex items-center justify-between p-4 bg-red-500/5 border border-red-500/10 rounded-xl">
|
|
338
|
-
<div className="flex items-center gap-2">
|
|
339
|
-
<span className="w-1.5 h-1.5 bg-red-500 rounded-full animate-pulse shadow-[0_0_8px_#EF4444]" />
|
|
340
|
-
<span className="text-[9px] font-black uppercase tracking-[0.2em] text-red-500/80 font-heading">
|
|
341
|
-
Laravel Threading
|
|
342
|
-
</span>
|
|
343
|
-
</div>
|
|
344
|
-
<span className="font-mono text-sm font-black text-red-500 tabular-nums tracking-tighter">
|
|
345
|
-
{worker.meta.laravel.workerCount || 0} PHP
|
|
346
|
-
</span>
|
|
347
|
-
</div>
|
|
348
|
-
)}
|
|
349
|
-
</div>
|
|
350
|
-
|
|
351
|
-
{/* Uptime */}
|
|
352
|
-
<div className="mt-6 pt-5 border-t border-white/5 flex items-center justify-between">
|
|
353
|
-
<div className="flex items-center gap-2 text-muted-foreground/40 font-heading">
|
|
354
|
-
<Clock size={12} />
|
|
355
|
-
<span className="text-[9px] font-black uppercase tracking-[0.2em]">
|
|
356
|
-
Quantum Uptime
|
|
357
|
-
</span>
|
|
358
|
-
</div>
|
|
359
|
-
<span className="font-mono text-[11px] font-black text-white/60 tabular-nums">
|
|
360
|
-
{formatUptime(worker.uptime)}
|
|
361
|
-
</span>
|
|
362
|
-
</div>
|
|
363
|
-
</motion.div>
|
|
364
|
-
))}
|
|
365
|
-
</div>
|
|
366
|
-
</div>
|
|
367
|
-
)
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function formatUptime(seconds: number): string {
|
|
371
|
-
if (seconds < 60) {
|
|
372
|
-
return `${Math.floor(seconds)}s`
|
|
373
|
-
}
|
|
374
|
-
if (seconds < 3600) {
|
|
375
|
-
return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`
|
|
376
|
-
}
|
|
377
|
-
const hours = Math.floor(seconds / 3600)
|
|
378
|
-
const minutes = Math.floor((seconds % 3600) / 60)
|
|
379
|
-
return `${hours}h ${minutes}m`
|
|
380
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export { LoginPage } from './LoginPage'
|
|
2
|
-
export { MetricsPage } from './MetricsPage'
|
|
3
|
-
export { OverviewPage } from './OverviewPage'
|
|
4
|
-
export { PulsePage } from './PulsePage'
|
|
5
|
-
export { QueuesPage } from './QueuesPage'
|
|
6
|
-
export { SchedulesPage } from './SchedulesPage'
|
|
7
|
-
export { SettingsPage } from './SettingsPage'
|
|
8
|
-
export { WorkersPage } from './WorkersPage'
|
package/src/client/utils.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type ClassValue, clsx } from 'clsx'
|
|
2
|
-
import { twMerge } from 'tailwind-merge'
|
|
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
|
-
*/
|
|
13
|
-
export function cn(...inputs: ClassValue[]) {
|
|
14
|
-
return twMerge(clsx(inputs))
|
|
15
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { DB } from '@gravito/atlas'
|
|
2
|
-
import { MySQLPersistence, SQLitePersistence } from '@gravito/stream'
|
|
3
|
-
|
|
4
|
-
export interface ServerConfig {
|
|
5
|
-
port: number
|
|
6
|
-
redisUrl: string
|
|
7
|
-
queuePrefix: string
|
|
8
|
-
dbDriver: 'sqlite' | 'mysql'
|
|
9
|
-
dbConfig: {
|
|
10
|
-
name?: string
|
|
11
|
-
host?: string
|
|
12
|
-
port?: number
|
|
13
|
-
username?: string
|
|
14
|
-
password?: string
|
|
15
|
-
}
|
|
16
|
-
persistence?: {
|
|
17
|
-
adapter: any
|
|
18
|
-
archiveCompleted: boolean
|
|
19
|
-
archiveFailed: boolean
|
|
20
|
-
archiveEnqueued: boolean
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class ServerConfigManager {
|
|
25
|
-
static load(): ServerConfig {
|
|
26
|
-
const dbDriver = (process.env.DB_DRIVER || (process.env.DB_HOST ? 'mysql' : 'sqlite')) as
|
|
27
|
-
| 'sqlite'
|
|
28
|
-
| 'mysql'
|
|
29
|
-
|
|
30
|
-
const dbConfig: ServerConfig['dbConfig'] = {}
|
|
31
|
-
if (dbDriver === 'mysql') {
|
|
32
|
-
dbConfig.host = process.env.DB_HOST
|
|
33
|
-
dbConfig.port = parseInt(process.env.DB_PORT || '3306', 10)
|
|
34
|
-
dbConfig.name = process.env.DB_NAME
|
|
35
|
-
dbConfig.username = process.env.DB_USER
|
|
36
|
-
dbConfig.password = process.env.DB_PASSWORD
|
|
37
|
-
} else {
|
|
38
|
-
dbConfig.name = process.env.DB_NAME || 'flux.sqlite'
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let persistence: ServerConfig['persistence']
|
|
42
|
-
|
|
43
|
-
if (dbDriver === 'sqlite' || process.env.DB_HOST) {
|
|
44
|
-
this.setupDatabase(dbDriver, dbConfig)
|
|
45
|
-
|
|
46
|
-
const adapter =
|
|
47
|
-
dbDriver === 'sqlite'
|
|
48
|
-
? new SQLitePersistence(DB.connection())
|
|
49
|
-
: new MySQLPersistence(DB.connection())
|
|
50
|
-
adapter
|
|
51
|
-
.setupTable()
|
|
52
|
-
.catch((err) => console.error('[FluxConsole] SQL Archive Setup Error:', err))
|
|
53
|
-
|
|
54
|
-
persistence = {
|
|
55
|
-
adapter,
|
|
56
|
-
archiveCompleted: process.env.PERSIST_ARCHIVE_COMPLETED === 'true',
|
|
57
|
-
archiveFailed: process.env.PERSIST_ARCHIVE_FAILED !== 'false',
|
|
58
|
-
archiveEnqueued: process.env.PERSIST_ARCHIVE_ENQUEUED === 'true',
|
|
59
|
-
}
|
|
60
|
-
console.log(`[FluxConsole] SQL Archive enabled via ${dbDriver}`)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
port: parseInt(process.env.PORT || '3000', 10),
|
|
65
|
-
redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
|
|
66
|
-
queuePrefix: process.env.QUEUE_PREFIX || 'queue:',
|
|
67
|
-
dbDriver,
|
|
68
|
-
dbConfig,
|
|
69
|
-
persistence,
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private static setupDatabase(driver: 'sqlite' | 'mysql', config: ServerConfig['dbConfig']): void {
|
|
74
|
-
if (driver === 'sqlite') {
|
|
75
|
-
DB.addConnection('default', {
|
|
76
|
-
driver: 'sqlite',
|
|
77
|
-
database: config.name,
|
|
78
|
-
})
|
|
79
|
-
} else {
|
|
80
|
-
DB.addConnection('default', {
|
|
81
|
-
driver,
|
|
82
|
-
host: config.host,
|
|
83
|
-
port: config.port,
|
|
84
|
-
database: config.name,
|
|
85
|
-
username: config.username,
|
|
86
|
-
password: config.password,
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|