@aion0/forge 0.2.19 → 0.2.20
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/components/Dashboard.tsx +16 -2
- package/components/SessionView.tsx +1 -59
- package/package.json +1 -1
package/components/Dashboard.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import SessionView from './SessionView';
|
|
|
8
8
|
import NewTaskModal from './NewTaskModal';
|
|
9
9
|
import SettingsModal from './SettingsModal';
|
|
10
10
|
import TunnelToggle from './TunnelToggle';
|
|
11
|
+
import MonitorPanel from './MonitorPanel';
|
|
11
12
|
import type { Task } from '@/src/types';
|
|
12
13
|
import type { WebTerminalHandle } from './WebTerminal';
|
|
13
14
|
|
|
@@ -44,6 +45,7 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
44
45
|
const [activeTaskId, setActiveTaskId] = useState<string | null>(null);
|
|
45
46
|
const [showNewTask, setShowNewTask] = useState(false);
|
|
46
47
|
const [showSettings, setShowSettings] = useState(false);
|
|
48
|
+
const [showMonitor, setShowMonitor] = useState(false);
|
|
47
49
|
const [usage, setUsage] = useState<UsageSummary[]>([]);
|
|
48
50
|
const [providers, setProviders] = useState<ProviderInfo[]>([]);
|
|
49
51
|
const [projects, setProjects] = useState<ProjectInfo[]>([]);
|
|
@@ -200,6 +202,16 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
200
202
|
>
|
|
201
203
|
Pipelines
|
|
202
204
|
</button>
|
|
205
|
+
<button
|
|
206
|
+
onClick={() => setViewMode('sessions')}
|
|
207
|
+
className={`text-[11px] px-2.5 py-0.5 rounded transition-colors ${
|
|
208
|
+
viewMode === 'sessions'
|
|
209
|
+
? 'bg-[var(--bg-secondary)] text-[var(--text-primary)] shadow-sm'
|
|
210
|
+
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]'
|
|
211
|
+
}`}
|
|
212
|
+
>
|
|
213
|
+
Sessions
|
|
214
|
+
</button>
|
|
203
215
|
<button
|
|
204
216
|
onClick={() => setViewMode('preview')}
|
|
205
217
|
className={`text-[11px] px-2.5 py-0.5 rounded transition-colors ${
|
|
@@ -238,8 +250,8 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
238
250
|
</span>
|
|
239
251
|
)}
|
|
240
252
|
<button
|
|
241
|
-
onClick={() =>
|
|
242
|
-
className=
|
|
253
|
+
onClick={() => setShowMonitor(true)}
|
|
254
|
+
className="text-xs text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
|
|
243
255
|
>
|
|
244
256
|
Monitor
|
|
245
257
|
</button>
|
|
@@ -414,6 +426,8 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
414
426
|
/>
|
|
415
427
|
)}
|
|
416
428
|
|
|
429
|
+
{showMonitor && <MonitorPanel onClose={() => setShowMonitor(false)} />}
|
|
430
|
+
|
|
417
431
|
{showSettings && (
|
|
418
432
|
<SettingsModal onClose={() => { setShowSettings(false); fetchData(); }} />
|
|
419
433
|
)}
|
|
@@ -32,16 +32,6 @@ interface Watcher {
|
|
|
32
32
|
createdAt: string;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
interface MonitorData {
|
|
36
|
-
processes: {
|
|
37
|
-
nextjs: { running: boolean; pid: string };
|
|
38
|
-
terminal: { running: boolean; pid: string };
|
|
39
|
-
telegram: { running: boolean; pid: string };
|
|
40
|
-
tunnel: { running: boolean; pid: string; url: string };
|
|
41
|
-
};
|
|
42
|
-
sessions: { name: string; created: string; attached: boolean; windows: number }[];
|
|
43
|
-
uptime: string;
|
|
44
|
-
}
|
|
45
35
|
|
|
46
36
|
export default function SessionView({
|
|
47
37
|
projectName,
|
|
@@ -63,7 +53,6 @@ export default function SessionView({
|
|
|
63
53
|
const [watchers, setWatchers] = useState<Watcher[]>([]);
|
|
64
54
|
const [batchMode, setBatchMode] = useState(false);
|
|
65
55
|
const [selectedIds, setSelectedIds] = useState<Map<string, Set<string>>>(new Map());
|
|
66
|
-
const [monitor, setMonitor] = useState<MonitorData | null>(null);
|
|
67
56
|
const bottomRef = useRef<HTMLDivElement>(null);
|
|
68
57
|
|
|
69
58
|
// Load cached sessions tree
|
|
@@ -91,17 +80,10 @@ export default function SessionView({
|
|
|
91
80
|
} catch {}
|
|
92
81
|
}, []);
|
|
93
82
|
|
|
94
|
-
const refreshMonitor = useCallback(() => {
|
|
95
|
-
fetch('/api/monitor').then(r => r.json()).then(setMonitor).catch(() => {});
|
|
96
|
-
}, []);
|
|
97
|
-
|
|
98
83
|
useEffect(() => {
|
|
99
84
|
loadTree(true);
|
|
100
85
|
loadWatchers();
|
|
101
|
-
|
|
102
|
-
const timer = setInterval(refreshMonitor, 5000);
|
|
103
|
-
return () => clearInterval(timer);
|
|
104
|
-
}, [loadTree, loadWatchers, refreshMonitor]);
|
|
86
|
+
}, [loadTree, loadWatchers]);
|
|
105
87
|
|
|
106
88
|
// Auto-expand project if only one or if pre-selected
|
|
107
89
|
useEffect(() => {
|
|
@@ -347,46 +329,6 @@ export default function SessionView({
|
|
|
347
329
|
</div>
|
|
348
330
|
)}
|
|
349
331
|
|
|
350
|
-
{/* Monitor — always visible */}
|
|
351
|
-
{monitor && (
|
|
352
|
-
<div className="border-b border-[var(--border)] px-2 py-2 space-y-1.5">
|
|
353
|
-
<div className="flex items-center justify-between">
|
|
354
|
-
<span className="text-[9px] font-semibold text-[var(--text-secondary)] uppercase">Processes</span>
|
|
355
|
-
{monitor.uptime && (
|
|
356
|
-
<span className="text-[8px] text-[var(--text-secondary)]">up {monitor.uptime}</span>
|
|
357
|
-
)}
|
|
358
|
-
</div>
|
|
359
|
-
{[
|
|
360
|
-
{ label: 'Next.js', ...monitor.processes.nextjs },
|
|
361
|
-
{ label: 'Terminal', ...monitor.processes.terminal },
|
|
362
|
-
{ label: 'Telegram', ...monitor.processes.telegram },
|
|
363
|
-
{ label: 'Tunnel', ...monitor.processes.tunnel },
|
|
364
|
-
].map(p => (
|
|
365
|
-
<div key={p.label} className="flex items-center gap-1.5 text-[10px]">
|
|
366
|
-
<span className={p.running ? 'text-green-400' : 'text-gray-500'}>●</span>
|
|
367
|
-
<span className="text-[var(--text-primary)]">{p.label}</span>
|
|
368
|
-
<span className="text-[var(--text-secondary)] font-mono ml-auto">{p.running ? `pid:${p.pid}` : 'stopped'}</span>
|
|
369
|
-
</div>
|
|
370
|
-
))}
|
|
371
|
-
{monitor.processes.tunnel.running && monitor.processes.tunnel.url && (
|
|
372
|
-
<div className="text-[9px] text-[var(--accent)] truncate pl-4">{monitor.processes.tunnel.url}</div>
|
|
373
|
-
)}
|
|
374
|
-
|
|
375
|
-
{monitor.sessions.length > 0 && (
|
|
376
|
-
<div className="pt-1">
|
|
377
|
-
<span className="text-[9px] font-semibold text-[var(--text-secondary)] uppercase">Tmux ({monitor.sessions.length})</span>
|
|
378
|
-
{monitor.sessions.map(s => (
|
|
379
|
-
<div key={s.name} className="flex items-center gap-1.5 text-[10px] mt-0.5">
|
|
380
|
-
<span className={s.attached ? 'text-green-400' : 'text-yellow-500'}>●</span>
|
|
381
|
-
<span className="font-mono text-[var(--text-primary)] truncate flex-1">{s.name}</span>
|
|
382
|
-
<span className="text-[8px] text-[var(--text-secondary)]">{s.attached ? 'attached' : 'detached'}</span>
|
|
383
|
-
</div>
|
|
384
|
-
))}
|
|
385
|
-
</div>
|
|
386
|
-
)}
|
|
387
|
-
</div>
|
|
388
|
-
)}
|
|
389
|
-
|
|
390
332
|
{/* Tree */}
|
|
391
333
|
<div className="flex-1 overflow-y-auto">
|
|
392
334
|
{Object.keys(sessionTree).length === 0 && (
|
package/package.json
CHANGED