@gravito/zenith 1.1.2 → 1.1.3
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 +15 -0
- package/README.md +77 -22
- package/README.zh-TW.md +88 -0
- package/dist/bin.js +64681 -15842
- package/dist/client/assets/index-C80c1frR.css +1 -0
- package/dist/client/assets/index-CrWem9u3.js +434 -0
- package/dist/server/index.js +64681 -15842
- package/package.json +9 -7
- package/postcss.config.js +4 -4
- package/src/client/Layout.tsx +36 -39
- package/src/client/Sidebar.tsx +7 -7
- package/src/client/ThroughputChart.tsx +31 -17
- package/src/client/WorkerStatus.tsx +56 -80
- package/src/client/components/ConfirmDialog.tsx +22 -14
- package/src/client/components/JobInspector.tsx +95 -162
- package/src/client/index.css +29 -31
- package/src/client/pages/LoginPage.tsx +33 -31
- package/src/client/pages/MetricsPage.tsx +65 -37
- package/src/client/pages/OverviewPage.tsx +30 -28
- package/src/client/pages/PulsePage.tsx +111 -190
- package/src/client/pages/QueuesPage.tsx +82 -83
- package/src/client/pages/SchedulesPage.tsx +56 -61
- package/src/client/pages/SettingsPage.tsx +118 -137
- package/src/client/pages/WorkersPage.tsx +101 -115
- package/src/server/services/CommandService.ts +8 -9
- package/src/server/services/PulseService.ts +61 -4
- package/src/server/services/QueueService.ts +293 -0
- package/src/shared/types.ts +38 -13
- package/tailwind.config.js +75 -68
- package/tsconfig.json +28 -37
- package/tsconfig.node.json +9 -11
- package/dist/client/assets/index-BSMp8oq_.js +0 -436
- package/dist/client/assets/index-BwxlHx-_.css +0 -1
- package/dist/client/index.html +0 -13
- package/src/client/index.html +0 -12
- /package/{ECOSYSTEM_EXPANSION_RFC.md → doc/ECOSYSTEM_EXPANSION_RFC.md} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravito/zenith",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Gravito Zenith: Zero-config control plane for Gravito Flux & Stream",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,13 +17,15 @@
|
|
|
17
17
|
"test": "bun test",
|
|
18
18
|
"typecheck": "bun tsc -p tsconfig.json --noEmit --skipLibCheck",
|
|
19
19
|
"seed": "bun scripts/seed.ts",
|
|
20
|
-
"worker": "bun scripts/worker.ts"
|
|
20
|
+
"worker": "bun scripts/worker.ts",
|
|
21
|
+
"test:unit": "bun test",
|
|
22
|
+
"test:integration": "test $(find tests -name '*.integration.test.ts' 2>/dev/null | wc -l) -gt 0 && find tests -name '*.integration.test.ts' -print0 | xargs -0 bun test --timeout=10000 || echo 'No integration tests found'"
|
|
21
23
|
},
|
|
22
24
|
"dependencies": {
|
|
23
|
-
"@gravito/atlas": "
|
|
24
|
-
"@gravito/photon": "
|
|
25
|
-
"@gravito/quasar": "
|
|
26
|
-
"@gravito/stream": "
|
|
25
|
+
"@gravito/atlas": "^1.6.0",
|
|
26
|
+
"@gravito/photon": "^1.0.1",
|
|
27
|
+
"@gravito/quasar": "^1.3.0",
|
|
28
|
+
"@gravito/stream": "^2.0.2",
|
|
27
29
|
"@tanstack/react-query": "^5.0.0",
|
|
28
30
|
"clsx": "^2.1.1",
|
|
29
31
|
"date-fns": "^4.1.0",
|
|
@@ -51,4 +53,4 @@
|
|
|
51
53
|
"publishConfig": {
|
|
52
54
|
"access": "public"
|
|
53
55
|
}
|
|
54
|
-
}
|
|
56
|
+
}
|
package/postcss.config.js
CHANGED
package/src/client/Layout.tsx
CHANGED
|
@@ -379,20 +379,20 @@ export function Layout({ children }: LayoutProps) {
|
|
|
379
379
|
animate={{ width: isSidebarOpen ? 260 : 80 }}
|
|
380
380
|
className="border-r border-border/40 bg-card/50 backdrop-blur-xl flex flex-col z-50 transition-all duration-300 ease-[0.22, 1, 0.36, 1]"
|
|
381
381
|
>
|
|
382
|
-
<div className="h-16 flex items-center px-6 border-b border-
|
|
382
|
+
<div className="h-16 flex items-center px-6 border-b border-white/5 bg-black/40">
|
|
383
383
|
<div className="flex items-center gap-3 overflow-hidden">
|
|
384
|
-
<div className="w-
|
|
385
|
-
<Zap className="text-
|
|
384
|
+
<div className="w-9 h-9 rounded-xl bg-primary flex items-center justify-center shrink-0 shadow-[0_0_20px_rgba(0,240,255,0.3)]">
|
|
385
|
+
<Zap className="text-black fill-current" size={20} />
|
|
386
386
|
</div>
|
|
387
387
|
<motion.div
|
|
388
388
|
animate={{ opacity: isSidebarOpen ? 1 : 0 }}
|
|
389
389
|
className="flex flex-col min-w-[140px]"
|
|
390
390
|
>
|
|
391
|
-
<span className="font-
|
|
391
|
+
<span className="font-black text-xl tracking-tighter leading-none text-white font-heading italic uppercase">
|
|
392
392
|
Zenith
|
|
393
393
|
</span>
|
|
394
|
-
<span className="text-[
|
|
395
|
-
Control
|
|
394
|
+
<span className="text-[8px] font-black text-primary uppercase tracking-[0.3em] mt-0.5">
|
|
395
|
+
Quantum Control
|
|
396
396
|
</span>
|
|
397
397
|
</motion.div>
|
|
398
398
|
</div>
|
|
@@ -430,17 +430,17 @@ export function Layout({ children }: LayoutProps) {
|
|
|
430
430
|
</button>
|
|
431
431
|
|
|
432
432
|
{/* System Integrity Indicator */}
|
|
433
|
-
<div className="hidden lg:flex items-center gap-3 px-4 py-
|
|
433
|
+
<div className="hidden lg:flex items-center gap-3 px-4 py-2 rounded-xl bg-primary/5 border border-primary/20 transition-all hover:bg-primary/10 cursor-default group shadow-[inset_0_0_20px_rgba(0,240,255,0.02)]">
|
|
434
434
|
<div className="relative flex items-center justify-center">
|
|
435
|
-
<ShieldCheck size={
|
|
436
|
-
<div className="absolute w-
|
|
435
|
+
<ShieldCheck size={16} className="text-primary z-10" />
|
|
436
|
+
<div className="absolute w-4 h-4 bg-primary/20 rounded-full glow-pulse"></div>
|
|
437
437
|
</div>
|
|
438
438
|
<div className="flex flex-col">
|
|
439
|
-
<span className="text-[
|
|
440
|
-
|
|
439
|
+
<span className="text-[8px] font-black uppercase tracking-[0.2em] text-primary/60 leading-none">
|
|
440
|
+
Quantum Core
|
|
441
441
|
</span>
|
|
442
|
-
<span className="text-[11px] font-black tracking-tight leading-none">
|
|
443
|
-
{health.toFixed(
|
|
442
|
+
<span className="text-[11px] font-black tracking-tight leading-none text-white mt-0.5 font-mono">
|
|
443
|
+
{health.toFixed(2)}% NOMINAL
|
|
444
444
|
</span>
|
|
445
445
|
</div>
|
|
446
446
|
</div>
|
|
@@ -452,6 +452,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
452
452
|
onClick={toggleTheme}
|
|
453
453
|
className="p-2.5 hover:bg-muted rounded-xl text-muted-foreground hover:text-primary transition-all duration-300 active:scale-95 group relative"
|
|
454
454
|
title={theme === 'light' ? 'Switch to Dark Mode' : 'Switch to Light Mode'}
|
|
455
|
+
aria-label={theme === 'light' ? 'Switch to Dark Mode' : 'Switch to Light Mode'}
|
|
455
456
|
>
|
|
456
457
|
{theme === 'light' ? (
|
|
457
458
|
<Moon size={20} className="group-hover:rotate-[15deg] transition-transform" />
|
|
@@ -483,45 +484,41 @@ export function Layout({ children }: LayoutProps) {
|
|
|
483
484
|
</div>
|
|
484
485
|
|
|
485
486
|
{/* Dynamic Status Bar (Ambient) */}
|
|
486
|
-
<footer className="h-
|
|
487
|
+
<footer className="h-8 border-t border-white/5 bg-black/60 backdrop-blur-xl flex items-center justify-between px-6 z-10 transition-colors">
|
|
487
488
|
<div className="flex items-center gap-6 overflow-hidden">
|
|
488
|
-
<div className="flex items-center gap-2 border-r border-
|
|
489
|
-
<span className="w-1.5 h-1.5 rounded-full bg-
|
|
490
|
-
<span className="text-[
|
|
491
|
-
|
|
489
|
+
<div className="flex items-center gap-2 border-r border-white/10 pr-4">
|
|
490
|
+
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 shadow-[0_0_8px_#10B981]"></span>
|
|
491
|
+
<span className="text-[9px] font-black text-white/40 uppercase tracking-[0.2em] whitespace-nowrap font-mono">
|
|
492
|
+
{systemStatus?.env || 'QUANTUM-1'}
|
|
492
493
|
</span>
|
|
493
494
|
</div>
|
|
494
|
-
<div className="flex items-center gap-4 text-[9px] font-black text-
|
|
495
|
-
<span className="flex items-center gap-1.5">
|
|
496
|
-
<Activity size={10} className="text-primary
|
|
495
|
+
<div className="flex items-center gap-4 text-[9px] font-black text-white/20 uppercase tracking-[0.3em] animate-in fade-in slide-in-from-left duration-1000">
|
|
496
|
+
<span className="flex items-center gap-1.5 text-primary/60">
|
|
497
|
+
<Activity size={10} className="text-primary" /> 4MS
|
|
497
498
|
</span>
|
|
498
|
-
<span className="hidden sm:inline border-l border-
|
|
499
|
-
|
|
500
|
-
{systemStatus?.memory?.total || '4.00 GB'}
|
|
499
|
+
<span className="hidden sm:inline border-l border-white/5 pl-4 text-white/40">
|
|
500
|
+
MEM: {systemStatus?.memory?.rss || '...'}
|
|
501
501
|
</span>
|
|
502
|
-
<span className="hidden md:inline border-l border-
|
|
503
|
-
|
|
504
|
-
</span>
|
|
505
|
-
<span className="hidden lg:inline border-l border-border/30 pl-4 lowercase">
|
|
506
|
-
v: {systemStatus?.node || '...'}
|
|
502
|
+
<span className="hidden md:inline border-l border-white/5 pl-4 text-white/40">
|
|
503
|
+
ENGINE: {systemStatus?.engine || 'V2.4.1'}
|
|
507
504
|
</span>
|
|
508
505
|
</div>
|
|
509
506
|
</div>
|
|
510
|
-
<div className="flex items-center gap-4 pl-4 bg-gradient-to-l from-
|
|
511
|
-
<div className="flex items-center gap-
|
|
512
|
-
<div className="w-
|
|
507
|
+
<div className="flex items-center gap-4 pl-4 bg-gradient-to-l from-black via-black to-transparent text-right">
|
|
508
|
+
<div className="flex items-center gap-3">
|
|
509
|
+
<div className="w-12 h-1 bg-white/5 rounded-full overflow-hidden">
|
|
513
510
|
<motion.div
|
|
514
|
-
animate={{ x: [-
|
|
515
|
-
transition={{ duration:
|
|
516
|
-
className="w-
|
|
511
|
+
animate={{ x: [-48, 48] }}
|
|
512
|
+
transition={{ duration: 3, repeat: Infinity, ease: 'linear' }}
|
|
513
|
+
className="w-6 h-full bg-primary/40 shadow-[0_0_10px_#00F0FF]"
|
|
517
514
|
/>
|
|
518
515
|
</div>
|
|
519
|
-
<span className="text-[
|
|
520
|
-
|
|
516
|
+
<span className="text-[8px] font-black text-primary uppercase tracking-[0.3em]">
|
|
517
|
+
SYNCING
|
|
521
518
|
</span>
|
|
522
519
|
</div>
|
|
523
|
-
<span className="font-mono text-[
|
|
524
|
-
{new Date().toISOString().split('T')[1]?.split('.')[0] || ''}
|
|
520
|
+
<span className="font-mono text-[9px] text-white/30 tabular-nums uppercase">
|
|
521
|
+
{new Date().toISOString().split('T')[1]?.split('.')[0] || ''} Z
|
|
525
522
|
</span>
|
|
526
523
|
</div>
|
|
527
524
|
</footer>
|
package/src/client/Sidebar.tsx
CHANGED
|
@@ -56,17 +56,17 @@ export function Sidebar({ className, collapsed, toggleCollapse }: SidebarProps)
|
|
|
56
56
|
key={i}
|
|
57
57
|
to={item.path}
|
|
58
58
|
className={cn(
|
|
59
|
-
'w-full flex items-center gap-4 px-4 py-3 rounded-xl transition-all text-muted-foreground group/item relative overflow-hidden',
|
|
59
|
+
'w-full flex items-center gap-4 px-4 py-3 rounded-xl transition-all text-muted-foreground/60 group/item relative overflow-hidden font-heading',
|
|
60
60
|
isActive
|
|
61
|
-
? 'bg-primary text-primary
|
|
62
|
-
: 'hover:bg-
|
|
61
|
+
? 'bg-primary/10 text-primary shadow-[0_0_20px_rgba(0,240,255,0.1)] border border-primary/20'
|
|
62
|
+
: 'hover:bg-white/[0.03] font-medium hover:text-foreground active:scale-95'
|
|
63
63
|
)}
|
|
64
64
|
>
|
|
65
65
|
<item.icon
|
|
66
|
-
size={
|
|
66
|
+
size={20}
|
|
67
67
|
className={cn(
|
|
68
68
|
'transition-all shrink-0',
|
|
69
|
-
isActive ? 'scale-110' : 'group-hover/item:scale-110'
|
|
69
|
+
isActive ? 'scale-110 text-primary' : 'group-hover/item:scale-110'
|
|
70
70
|
)}
|
|
71
71
|
/>
|
|
72
72
|
<motion.span
|
|
@@ -75,14 +75,14 @@ export function Sidebar({ className, collapsed, toggleCollapse }: SidebarProps)
|
|
|
75
75
|
opacity: collapsed ? 0 : 1,
|
|
76
76
|
display: collapsed ? 'none' : 'block',
|
|
77
77
|
}}
|
|
78
|
-
className="font-
|
|
78
|
+
className="font-black whitespace-nowrap tracking-tight uppercase text-[11px]"
|
|
79
79
|
>
|
|
80
80
|
{item.label}
|
|
81
81
|
</motion.span>
|
|
82
82
|
{isActive && (
|
|
83
83
|
<motion.div
|
|
84
84
|
layoutId="active-pill"
|
|
85
|
-
className="absolute left-0 w-1 h-
|
|
85
|
+
className="absolute left-0 w-1 h-5 bg-primary rounded-r-full shadow-[0_0_10px_#00F0FF]"
|
|
86
86
|
/>
|
|
87
87
|
)}
|
|
88
88
|
</NavLink>
|
|
@@ -70,21 +70,23 @@ export function ThroughputChart() {
|
|
|
70
70
|
<div className="flex justify-between items-start mb-6 z-10">
|
|
71
71
|
<div>
|
|
72
72
|
<div className="flex items-center gap-2">
|
|
73
|
-
<h3 className="text-xl font-
|
|
74
|
-
<div className="flex items-center gap-1.5 px-2 py-0.5 bg-
|
|
75
|
-
<span className="w-1 h-1 bg-
|
|
73
|
+
<h3 className="text-xl font-black tracking-tight font-heading">System Throughput</h3>
|
|
74
|
+
<div className="flex items-center gap-1.5 px-2 py-0.5 bg-primary/10 text-primary text-[8px] font-black uppercase tracking-widest rounded-full border border-primary/20">
|
|
75
|
+
<span className="w-1 h-1 bg-primary rounded-full animate-ping"></span>
|
|
76
76
|
Live
|
|
77
77
|
</div>
|
|
78
78
|
</div>
|
|
79
|
-
<p className="text-[10px] text-muted-foreground uppercase tracking-[0.2em] font-
|
|
79
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-[0.2em] font-black mt-1">
|
|
80
80
|
Jobs processed per minute
|
|
81
81
|
</p>
|
|
82
82
|
</div>
|
|
83
83
|
<div className="text-right">
|
|
84
|
-
<p className="text-
|
|
84
|
+
<p className="text-3xl font-black text-foreground font-mono">
|
|
85
85
|
{chartData[chartData.length - 1]?.value || 0}
|
|
86
86
|
</p>
|
|
87
|
-
<p className="text-[8px] text-muted-foreground uppercase font-
|
|
87
|
+
<p className="text-[8px] text-muted-foreground uppercase font-black tracking-tighter">
|
|
88
|
+
Current Rate
|
|
89
|
+
</p>
|
|
88
90
|
</div>
|
|
89
91
|
</div>
|
|
90
92
|
|
|
@@ -93,7 +95,7 @@ export function ThroughputChart() {
|
|
|
93
95
|
<AreaChart data={chartData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
|
94
96
|
<defs>
|
|
95
97
|
<linearGradient id="colorValue" x1="0" y1="0" x2="0" y2="1">
|
|
96
|
-
<stop offset="5%" stopColor="hsl(var(--primary))" stopOpacity={0.
|
|
98
|
+
<stop offset="5%" stopColor="hsl(var(--primary))" stopOpacity={0.5} />
|
|
97
99
|
<stop offset="50%" stopColor="hsl(var(--primary))" stopOpacity={0.1} />
|
|
98
100
|
<stop offset="95%" stopColor="hsl(var(--primary))" stopOpacity={0} />
|
|
99
101
|
</linearGradient>
|
|
@@ -102,38 +104,50 @@ export function ThroughputChart() {
|
|
|
102
104
|
strokeDasharray="3 3"
|
|
103
105
|
vertical={false}
|
|
104
106
|
stroke="hsl(var(--border))"
|
|
105
|
-
opacity={0.
|
|
107
|
+
opacity={0.3}
|
|
106
108
|
/>
|
|
107
109
|
<XAxis
|
|
108
110
|
dataKey="time"
|
|
109
111
|
axisLine={false}
|
|
110
112
|
tickLine={false}
|
|
111
|
-
tick={{
|
|
113
|
+
tick={{
|
|
114
|
+
fontSize: 9,
|
|
115
|
+
fill: 'hsl(var(--muted-foreground))',
|
|
116
|
+
fontWeight: 700,
|
|
117
|
+
fontFamily: 'Fira Code',
|
|
118
|
+
}}
|
|
112
119
|
dy={10}
|
|
113
120
|
/>
|
|
114
121
|
<YAxis
|
|
115
122
|
axisLine={false}
|
|
116
123
|
tickLine={false}
|
|
117
|
-
tick={{
|
|
124
|
+
tick={{
|
|
125
|
+
fontSize: 9,
|
|
126
|
+
fill: 'hsl(var(--muted-foreground))',
|
|
127
|
+
fontWeight: 700,
|
|
128
|
+
fontFamily: 'Fira Code',
|
|
129
|
+
}}
|
|
118
130
|
/>
|
|
119
131
|
<Tooltip
|
|
120
132
|
cursor={{ stroke: 'hsl(var(--primary))', strokeWidth: 1, strokeDasharray: '4 4' }}
|
|
121
133
|
contentStyle={{
|
|
122
|
-
backgroundColor: '
|
|
123
|
-
border: '1px solid
|
|
124
|
-
borderRadius: '
|
|
125
|
-
fontSize: '
|
|
126
|
-
|
|
134
|
+
backgroundColor: 'rgba(9, 9, 11, 0.9)',
|
|
135
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
136
|
+
borderRadius: '12px',
|
|
137
|
+
fontSize: '11px',
|
|
138
|
+
fontFamily: 'Fira Code',
|
|
139
|
+
boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.5)',
|
|
140
|
+
backdropFilter: 'blur(8px)',
|
|
127
141
|
}}
|
|
128
142
|
itemStyle={{ fontWeight: 'bold', color: 'hsl(var(--primary))' }}
|
|
129
143
|
/>
|
|
130
144
|
<Area
|
|
131
|
-
type="
|
|
145
|
+
type="monotone"
|
|
132
146
|
dataKey="value"
|
|
133
147
|
stroke="hsl(var(--primary))"
|
|
134
148
|
fillOpacity={1}
|
|
135
149
|
fill="url(#colorValue)"
|
|
136
|
-
strokeWidth={
|
|
150
|
+
strokeWidth={3}
|
|
137
151
|
animationDuration={1500}
|
|
138
152
|
/>
|
|
139
153
|
</AreaChart>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ClassValue, clsx } from 'clsx'
|
|
2
|
-
import { Activity, Cpu
|
|
2
|
+
import { Activity, Cpu } from 'lucide-react'
|
|
3
3
|
import { twMerge } from 'tailwind-merge'
|
|
4
4
|
|
|
5
5
|
function cn(...inputs: ClassValue[]) {
|
|
@@ -73,28 +73,28 @@ export function WorkerStatus({
|
|
|
73
73
|
|
|
74
74
|
return (
|
|
75
75
|
<div className="card-premium h-full flex flex-col overflow-hidden">
|
|
76
|
-
<div className="p-
|
|
77
|
-
<div className="flex justify-between items-center mb-
|
|
76
|
+
<div className="p-5 pb-0 flex-none">
|
|
77
|
+
<div className="flex justify-between items-center mb-5">
|
|
78
78
|
<div>
|
|
79
|
-
<h3 className="text-
|
|
80
|
-
<Cpu size={
|
|
79
|
+
<h3 className="text-base font-black flex items-center gap-2 tracking-tight font-heading">
|
|
80
|
+
<Cpu size={18} className="text-primary" />
|
|
81
81
|
Cluster Nodes
|
|
82
82
|
</h3>
|
|
83
|
-
<p className="text-[
|
|
84
|
-
|
|
83
|
+
<p className="text-[9px] text-muted-foreground uppercase font-black tracking-[0.2em] opacity-50 mt-0.5">
|
|
84
|
+
Live Infrastructure
|
|
85
85
|
</p>
|
|
86
86
|
</div>
|
|
87
|
-
<span className="text-[
|
|
87
|
+
<span className="text-[9px] font-black text-emerald-500 bg-emerald-500/10 px-2 py-1 rounded-md uppercase tracking-widest border border-emerald-500/20">
|
|
88
88
|
{onlineCount} ACTIVE
|
|
89
89
|
</span>
|
|
90
90
|
</div>
|
|
91
91
|
</div>
|
|
92
92
|
|
|
93
|
-
<div className="flex-1 overflow-y-auto min-h-0 px-
|
|
93
|
+
<div className="flex-1 overflow-y-auto min-h-0 px-5 space-y-2 scrollbar-thin pb-5">
|
|
94
94
|
{workers.length === 0 && (
|
|
95
|
-
<div className="py-12 text-center text-muted-foreground/
|
|
96
|
-
<Activity size={24} className="opacity-
|
|
97
|
-
<p className="text-[
|
|
95
|
+
<div className="py-12 text-center text-muted-foreground/20 flex flex-col items-center gap-2">
|
|
96
|
+
<Activity size={24} className="opacity-30 animate-pulse" />
|
|
97
|
+
<p className="text-[9px] font-black uppercase tracking-[0.3em]">Awaiting signals...</p>
|
|
98
98
|
</div>
|
|
99
99
|
)}
|
|
100
100
|
|
|
@@ -102,52 +102,41 @@ export function WorkerStatus({
|
|
|
102
102
|
<div
|
|
103
103
|
key={worker.id}
|
|
104
104
|
className={cn(
|
|
105
|
-
'relative flex items-center gap-
|
|
105
|
+
'relative flex items-center gap-3 p-3 rounded-xl border transition-all group overflow-hidden shrink-0',
|
|
106
106
|
worker.id === highlightedWorkerId
|
|
107
|
-
? 'bg-primary/
|
|
108
|
-
: 'bg-
|
|
107
|
+
? 'bg-primary/10 border-primary/40 shadow-[0_0_20px_rgba(0,240,255,0.1)] -translate-x-1 z-10'
|
|
108
|
+
: 'bg-black/20 hover:bg-white/[0.03] border-white/5 hover:border-primary/20'
|
|
109
109
|
)}
|
|
110
110
|
>
|
|
111
111
|
{/* Status bar */}
|
|
112
112
|
<div
|
|
113
113
|
className={cn(
|
|
114
114
|
'absolute left-0 top-0 bottom-0 w-1 transition-all',
|
|
115
|
-
worker.status === 'online'
|
|
115
|
+
worker.status === 'online'
|
|
116
|
+
? 'bg-emerald-500 shadow-[0_0_10px_#10B981]'
|
|
117
|
+
: 'bg-muted-foreground/20'
|
|
116
118
|
)}
|
|
117
119
|
/>
|
|
118
120
|
|
|
119
|
-
{/* Icon/Dot */}
|
|
120
|
-
<div className="relative shrink-0 ml-1">
|
|
121
|
-
<div
|
|
122
|
-
className={cn(
|
|
123
|
-
'w-3 h-3 rounded-full',
|
|
124
|
-
worker.status === 'online'
|
|
125
|
-
? 'bg-green-500 animate-pulse shadow-[0_0_12px_rgba(34,197,94,0.6)]'
|
|
126
|
-
: 'bg-muted-foreground/40'
|
|
127
|
-
)}
|
|
128
|
-
/>
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
121
|
{/* Main Info */}
|
|
132
|
-
<div className="flex-1 min-w-0 flex flex-col justify-center
|
|
122
|
+
<div className="flex-1 min-w-0 flex flex-col justify-center">
|
|
133
123
|
{worker.service && (
|
|
134
|
-
<span className="text-[
|
|
124
|
+
<span className="text-[8px] font-black text-primary uppercase tracking-widest mb-0.5 whitespace-nowrap opacity-80">
|
|
135
125
|
{worker.service}
|
|
136
126
|
</span>
|
|
137
127
|
)}
|
|
138
128
|
<h4
|
|
139
|
-
className="text-
|
|
129
|
+
className="text-xs font-black tracking-tight text-foreground/90 truncate font-heading"
|
|
140
130
|
title={worker.id}
|
|
141
131
|
>
|
|
142
132
|
{getWorkerName(worker.id, worker.pid) || worker.id}
|
|
143
133
|
</h4>
|
|
144
|
-
<div className="flex items-center gap-2 mt-
|
|
145
|
-
<span className="text-[
|
|
146
|
-
PID
|
|
134
|
+
<div className="flex items-center gap-2 mt-0.5">
|
|
135
|
+
<span className="text-[8px] font-bold text-muted-foreground/40 uppercase font-mono">
|
|
136
|
+
PID:{worker.pid}
|
|
147
137
|
</span>
|
|
148
138
|
{worker.meta?.laravel && worker.meta.laravel.workerCount > 0 && (
|
|
149
|
-
<span className="inline-flex items-center gap-1 text-[
|
|
150
|
-
<Terminal size={8} />
|
|
139
|
+
<span className="inline-flex items-center gap-1 text-[8px] font-black text-white bg-red-500/80 px-1 rounded shadow-sm uppercase tracking-tighter leading-none whitespace-nowrap">
|
|
151
140
|
{worker.meta.laravel.workerCount} PHP
|
|
152
141
|
</span>
|
|
153
142
|
)}
|
|
@@ -155,57 +144,44 @@ export function WorkerStatus({
|
|
|
155
144
|
</div>
|
|
156
145
|
|
|
157
146
|
{/* Metrics (Right Side) */}
|
|
158
|
-
<div className="flex items-center gap-
|
|
147
|
+
<div className="flex items-center gap-4 text-right shrink-0">
|
|
159
148
|
{worker.metrics && (
|
|
160
149
|
<>
|
|
161
|
-
<div className="hidden sm:
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
<div
|
|
174
|
-
className="h-full bg-foreground transition-all duration-700"
|
|
175
|
-
style={{ width: `${Math.min(100, worker.metrics.cpu)}%` }}
|
|
176
|
-
></div>
|
|
177
|
-
</div>
|
|
150
|
+
<div className="hidden sm:flex flex-col items-end gap-1 w-10">
|
|
151
|
+
<span className="text-[8px] font-black text-muted-foreground/40 uppercase font-mono">
|
|
152
|
+
CPU
|
|
153
|
+
</span>
|
|
154
|
+
<span
|
|
155
|
+
className={cn(
|
|
156
|
+
'text-[10px] font-black font-mono tracking-tighter',
|
|
157
|
+
worker.metrics.cpu > 80 ? 'text-red-500' : 'text-primary'
|
|
158
|
+
)}
|
|
159
|
+
>
|
|
160
|
+
{worker.metrics.cpu.toFixed(0)}%
|
|
161
|
+
</span>
|
|
178
162
|
</div>
|
|
179
163
|
|
|
180
|
-
<div className="hidden sm:
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
</
|
|
187
|
-
<div className="h-1 w-full bg-muted rounded-full overflow-hidden">
|
|
188
|
-
<div
|
|
189
|
-
className="h-full bg-indigo-500 transition-all duration-700"
|
|
190
|
-
style={{
|
|
191
|
-
width: `${Math.min(100, (worker.metrics.ram.rss / 2000000000) * 100)}%`,
|
|
192
|
-
}}
|
|
193
|
-
></div>
|
|
194
|
-
</div>
|
|
164
|
+
<div className="hidden sm:flex flex-col items-end gap-1 w-12">
|
|
165
|
+
<span className="text-[8px] font-black text-muted-foreground/40 uppercase font-mono">
|
|
166
|
+
RAM
|
|
167
|
+
</span>
|
|
168
|
+
<span className="text-[10px] font-black font-mono tracking-tighter text-white/80">
|
|
169
|
+
{formatBytes(worker.metrics.ram.rss).split(' ')[0]}
|
|
170
|
+
</span>
|
|
195
171
|
</div>
|
|
196
172
|
</>
|
|
197
173
|
)}
|
|
198
174
|
|
|
199
|
-
<div className="w-
|
|
200
|
-
<
|
|
175
|
+
<div className="flex flex-col items-end gap-1 w-10">
|
|
176
|
+
<span className="text-[8px] font-black text-muted-foreground/40 uppercase font-mono">
|
|
177
|
+
UP
|
|
178
|
+
</span>
|
|
179
|
+
<p className="text-[10px] font-black tracking-tighter font-mono text-foreground/60 tabular-nums">
|
|
201
180
|
{worker.uptime > 3600
|
|
202
|
-
? `${(worker.uptime / 3600).toFixed(1)}
|
|
181
|
+
? `${(worker.uptime / 3600).toFixed(1)}H`
|
|
203
182
|
: worker.uptime > 60
|
|
204
|
-
? `${(worker.uptime / 60).toFixed(0)}
|
|
205
|
-
: `${worker.uptime.toFixed(0)}
|
|
206
|
-
</p>
|
|
207
|
-
<p className="text-[8px] text-muted-foreground uppercase font-black tracking-widest opacity-50">
|
|
208
|
-
UP
|
|
183
|
+
? `${(worker.uptime / 60).toFixed(0)}M`
|
|
184
|
+
: `${worker.uptime.toFixed(0)}S`}
|
|
209
185
|
</p>
|
|
210
186
|
</div>
|
|
211
187
|
</div>
|
|
@@ -213,12 +189,12 @@ export function WorkerStatus({
|
|
|
213
189
|
))}
|
|
214
190
|
</div>
|
|
215
191
|
|
|
216
|
-
<div className="p-
|
|
192
|
+
<div className="p-5 pt-0 flex-none">
|
|
217
193
|
<button
|
|
218
194
|
type="button"
|
|
219
|
-
className="w-full py-
|
|
195
|
+
className="w-full py-2.5 bg-muted/50 text-[9px] font-black rounded-lg hover:bg-primary hover:text-primary-foreground transition-all uppercase tracking-[0.2em] border border-white/5 hover:border-primary/50 active:scale-95 shadow-lg shadow-transparent hover:shadow-primary/10 font-heading"
|
|
220
196
|
>
|
|
221
|
-
|
|
197
|
+
Node Orchestration
|
|
222
198
|
</button>
|
|
223
199
|
</div>
|
|
224
200
|
</div>
|
|
@@ -60,16 +60,21 @@ export function ConfirmDialog({
|
|
|
60
60
|
onKeyDown={(e) => e.stopPropagation()}
|
|
61
61
|
>
|
|
62
62
|
<motion.div
|
|
63
|
-
initial={{ scale: 0.
|
|
64
|
-
animate={{ scale: 1, opacity: 1 }}
|
|
65
|
-
exit={{ scale: 0.
|
|
66
|
-
transition={{ type: 'spring', damping: 25, stiffness:
|
|
67
|
-
className="bg-
|
|
63
|
+
initial={{ scale: 0.95, opacity: 0, y: 20 }}
|
|
64
|
+
animate={{ scale: 1, opacity: 1, y: 0 }}
|
|
65
|
+
exit={{ scale: 0.95, opacity: 0, y: 20 }}
|
|
66
|
+
transition={{ type: 'spring', damping: 25, stiffness: 300 }}
|
|
67
|
+
className="bg-zinc-900 border border-white/10 rounded-3xl p-8 max-w-md shadow-[0_0_50px_rgba(0,0,0,0.8)] scanline overflow-hidden"
|
|
68
68
|
onClick={(e) => e.stopPropagation()}
|
|
69
69
|
>
|
|
70
|
-
<h3 className="text-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
<h3 className="text-2xl font-black mb-3 font-heading tracking-tight text-white uppercase italic italic">
|
|
71
|
+
{title}
|
|
72
|
+
</h3>
|
|
73
|
+
<div className="h-px w-full bg-white/5 mb-6" />
|
|
74
|
+
<p className="text-[13px] font-bold text-muted-foreground mb-8 leading-relaxed uppercase tracking-wide opacity-80">
|
|
75
|
+
{message}
|
|
76
|
+
</p>
|
|
77
|
+
<div className="flex gap-4 justify-end">
|
|
73
78
|
<button
|
|
74
79
|
type="button"
|
|
75
80
|
onClick={(e) => {
|
|
@@ -77,7 +82,7 @@ export function ConfirmDialog({
|
|
|
77
82
|
onCancel()
|
|
78
83
|
}}
|
|
79
84
|
disabled={isProcessing}
|
|
80
|
-
className="px-
|
|
85
|
+
className="px-6 py-3 bg-zinc-800 text-white/60 rounded-xl hover:bg-zinc-700 transition-all disabled:opacity-20 disabled:cursor-not-allowed text-[10px] font-black uppercase tracking-[0.2em] font-heading border border-white/5"
|
|
81
86
|
>
|
|
82
87
|
{cancelText}
|
|
83
88
|
</button>
|
|
@@ -89,10 +94,13 @@ export function ConfirmDialog({
|
|
|
89
94
|
}}
|
|
90
95
|
disabled={isProcessing}
|
|
91
96
|
className={cn(
|
|
92
|
-
'px-
|
|
93
|
-
variant === 'danger' &&
|
|
94
|
-
|
|
95
|
-
variant === '
|
|
97
|
+
'px-6 py-3 rounded-xl text-black transition-all disabled:opacity-20 disabled:cursor-not-allowed flex items-center gap-2 text-[10px] font-black uppercase tracking-[0.2em] font-heading shadow-lg',
|
|
98
|
+
variant === 'danger' &&
|
|
99
|
+
'bg-red-500 shadow-[0_0_20px_rgba(239,68,68,0.3)] hover:bg-red-400',
|
|
100
|
+
variant === 'warning' &&
|
|
101
|
+
'bg-amber-500 shadow-[0_0_20px_rgba(245,158,11,0.3)] hover:bg-amber-400',
|
|
102
|
+
variant === 'info' &&
|
|
103
|
+
'bg-primary shadow-[0_0_20px_rgba(0,240,255,0.3)] hover:bg-primary/80'
|
|
96
104
|
)}
|
|
97
105
|
>
|
|
98
106
|
{isProcessing && (
|
|
@@ -114,7 +122,7 @@ export function ConfirmDialog({
|
|
|
114
122
|
/>
|
|
115
123
|
</svg>
|
|
116
124
|
)}
|
|
117
|
-
{isProcessing ? '
|
|
125
|
+
{isProcessing ? 'Executing...' : confirmText}
|
|
118
126
|
</button>
|
|
119
127
|
</div>
|
|
120
128
|
</motion.div>
|