File size: 5,238 Bytes
c9d42cc cce8120 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 'use client';
import React, { useState, useEffect } from 'react';
import { api } from '../../services/api';
export default function AgentMonitor() {
const [activeBuilds, setActiveBuilds] = useState([]);
const [loading, setLoading] = useState(false);
const triggerNewBuild = async (target) => {
setLoading(true);
try {
const res = await api.startBuild(target);
if (res && res.build_id) {
setActiveBuilds((prev) => [
{ build_id: res.build_id, target, status: 'building', timestamp: new Date().toLocaleTimeString() },
...prev
]);
pollStatus(res.build_id);
}
} catch (err) {
console.error('Failed to trigger build:', err);
} finally {
setLoading(false);
}
};
const pollStatus = (buildId) => {
const interval = setInterval(async () => {
try {
const res = await api.getBuildStatus(buildId);
if (res && res.status) {
setActiveBuilds((prev) =>
prev.map((item) => (item.build_id === buildId ? { ...item, status: res.status, error: res.error } : item))
);
if (res.status === 'success' || res.status === 'failed') {
clearInterval(interval);
}
}
} catch (err) {
clearInterval(interval);
}
}, 2000);
};
return (
<div className="p-6 bg-slate-950 text-slate-200 h-full overflow-y-auto space-y-6">
<div className="border-b border-slate-800 pb-4">
<h2 className="text-lg font-bold text-white">Agent Task Engine & Build Operations</h2>
<p className="text-xs text-slate-400 mt-1">
Trigger production build processes and monitor autonomous agent DAG executions.
</p>
</div>
{/* Action Controls */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => triggerNewBuild('static')}
disabled={loading}
className="p-4 bg-slate-900 border border-slate-800 hover:border-emerald-500/50 rounded-lg text-left transition-all group"
>
<div className="text-emerald-400 font-bold text-sm group-hover:translate-x-1 transition-transform">
π Build Web Static Bundle β
</div>
<div className="text-xs text-slate-400 mt-1">Triggers automated Vite/React/Next site production build.</div>
</button>
<button
onClick={() => triggerNewBuild('docker')}
disabled={loading}
className="p-4 bg-slate-900 border border-slate-800 hover:border-blue-500/50 rounded-lg text-left transition-all group"
>
<div className="text-blue-400 font-bold text-sm group-hover:translate-x-1 transition-transform">
π³ Build Docker Container β
</div>
<div className="text-xs text-slate-400 mt-1">Compiles application image via host Docker engine.</div>
</button>
<button
onClick={() => triggerNewBuild('apk')}
disabled={loading}
className="p-4 bg-slate-900 border border-slate-800 hover:border-purple-500/50 rounded-lg text-left transition-all group"
>
<div className="text-purple-400 font-bold text-sm group-hover:translate-x-1 transition-transform">
π± Package Android APK β
</div>
<div className="text-xs text-slate-400 mt-1">Compiles mobile bundle into installable APK binary.</div>
</button>
</div>
{/* Execution Queue Table */}
<div className="bg-slate-900 border border-slate-800 rounded-lg overflow-hidden">
<div className="px-4 py-3 border-b border-slate-800 font-semibold text-xs text-slate-400 uppercase tracking-wider">
Active Build & Execution Pipeline Jobs
</div>
<div className="divide-y divide-slate-800/60 text-xs">
{activeBuilds.length === 0 ? (
<div className="p-4 text-slate-500 italic text-center">No build jobs initiated in this session.</div>
) : (
activeBuilds.map((job) => (
<div key={job.build_id} className="p-4 flex items-center justify-between">
<div>
<div className="font-mono text-slate-200 font-medium">{job.build_id}</div>
<div className="text-[11px] text-slate-500">Target: {job.target} | Queued: {job.timestamp}</div>
{job.error && <div className="text-rose-400 text-[11px] mt-1">{job.error}</div>}
</div>
<div>
<span
className={`px-2.5 py-1 rounded-full text-[10px] font-bold uppercase tracking-wider ${
job.status === 'success'
? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20'
: job.status === 'failed'
? 'bg-rose-500/10 text-rose-400 border border-rose-500/20'
: 'bg-amber-500/10 text-amber-400 border border-amber-500/20 animate-pulse'
}`}
>
{job.status}
</span>
</div>
</div>
))
)}
</div>
</div>
</div>
);
}
|