AgentIC / web /src /pages /Dashboard.tsx
vxkyyy's picture
add changes for pip package , and improve the frontend ui
33e7e31
import { useState, useEffect } from 'react';
import { api } from '../api';
import { Gauge, Zap, Maximize2, Hash, Cpu, Users, RefreshCw, CheckCircle2, XCircle } from 'lucide-react';
interface DashboardProps {
selectedDesign: string;
}
export const Dashboard = ({ selectedDesign }: DashboardProps) => {
const [metrics, setMetrics] = useState<any>({
wns: 'N/A', power: 'N/A', area: 'N/A', gate_count: 'N/A'
});
const [signoffData, setSignoffData] = useState<{ report: string, pass: boolean | null }>({ report: 'Fetching sign-off analysis...', pass: null });
const [loading, setLoading] = useState(false);
const [recentJobs, setRecentJobs] = useState<any[]>([]);
useEffect(() => {
if (!selectedDesign) return;
setLoading(true);
api.get(`/metrics/${selectedDesign}`)
.then(res => {
if (res.data.metrics) setMetrics(res.data.metrics);
})
.catch(() => {
setMetrics({ wns: 'N/A', power: 'N/A', area: 'N/A', gate_count: 'N/A' });
});
api.get(`/signoff/${selectedDesign}`)
.then(res => {
setSignoffData({ report: res.data.report, pass: res.data.success });
})
.catch(() => {
setSignoffData({ report: 'Failed to retrieve Signoff Report. Has the device been fully hardened via OpenLane yet?', pass: false });
})
.finally(() => setLoading(false));
api.get(`/jobs`)
.then(res => {
const jobs = (res.data?.jobs || [])
.filter((j: any) => j.design_name === selectedDesign)
.slice(0, 5);
setRecentJobs(jobs);
})
.catch(() => setRecentJobs([]));
}, [selectedDesign]);
const statusColor = (status: string) => {
if (status === 'done') return 'var(--success)';
if (status === 'failed') return 'var(--fail)';
if (status === 'running') return 'var(--accent)';
return 'var(--text-dim)';
};
const METRICS_CONFIG = [
{ key: 'wns', label: 'Worst Negative Slack', tag: 'Timing', icon: <Gauge size={16} /> },
{ key: 'power', label: 'Total Power', tag: 'Energy', icon: <Zap size={16} /> },
{ key: 'area', label: 'Die Area', tag: 'Footprint', icon: <Maximize2 size={16} /> },
{ key: 'gate_count', label: 'Gate Count', tag: 'Logic', icon: <Hash size={16} /> },
];
return (
<div className="dash-page">
<div className="dash-header">
<h2 className="dash-title">{selectedDesign || 'No Design Selected'}</h2>
<p className="dash-subtitle">Silicon metrics, signoff analysis, and build history.</p>
</div>
{loading ? (
<div className="dash-loader">
<div className="premium-loader">
<span className="premium-loader-dot" />
<span className="premium-loader-dot" />
<span className="premium-loader-dot" />
</div>
Loading metrics...
</div>
) : (
<div className="dash-metrics-grid">
{METRICS_CONFIG.map((m) => (
<div className="dash-metric-card" key={m.key}>
<div className="dash-metric-icon">{m.icon}</div>
<div className="dash-metric-body">
<span className="dash-metric-label">{m.label}</span>
<span className="dash-metric-value">{metrics[m.key]}</span>
<span className="dash-metric-tag">{m.tag}</span>
</div>
</div>
))}
</div>
)}
{/* Agent Architecture */}
<div className="dash-card">
<h3 className="dash-card-title">Agent Architecture</h3>
<div className="dash-insight-grid">
{[
{ icon: <Cpu size={16} />, title: 'Spec Decomposition', value: 'SID/JSON Contract', detail: 'ArchitectModule — validated ports, FSMs, sub-modules' },
{ icon: <Users size={16} />, title: 'Collaborative RTL', value: 'Designer + Reviewer', detail: '2-agent Crew with syntax_check and read_file tools' },
{ icon: <RefreshCw size={16} />, title: 'Self-Healing', value: 'Convergence-Aware', detail: 'SelfReflectPipeline with fingerprinting + stagnation detection' },
].map((item, i) => (
<div key={i} className="dash-insight-item">
<div className="dash-insight-icon">{item.icon}</div>
<div className="dash-insight-content">
<span className="dash-insight-title">{item.title}</span>
<span className="dash-insight-value">{item.value}</span>
<span className="dash-insight-detail">{item.detail}</span>
</div>
</div>
))}
</div>
</div>
{/* Signoff Report */}
<div className="dash-card">
<h3 className="dash-card-title">
Signoff Report
{signoffData.pass === true && (
<span className="dash-signoff-pass"><CheckCircle2 size={14} /> Passed</span>
)}
{signoffData.pass === false && (
<span className="dash-signoff-fail"><XCircle size={14} /> Failed</span>
)}
</h3>
<pre className="dash-report-pre">{signoffData.report}</pre>
</div>
{/* Recent Builds */}
{recentJobs.length > 0 && (
<div className="dash-card">
<h3 className="dash-card-title">Recent Builds</h3>
<div className="dash-table-wrap">
<table className="dash-table">
<thead>
<tr>
<th>Job ID</th>
<th>Status</th>
<th>Stage</th>
<th>Events</th>
</tr>
</thead>
<tbody>
{recentJobs.map((job: any) => (
<tr key={job.job_id}>
<td className="dash-job-id">{job.job_id.substring(0, 8)}…</td>
<td>
<span className="dash-status" style={{ color: statusColor(job.status) }}>
{job.status}
</span>
</td>
<td>{job.current_state}</td>
<td>{job.event_count}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
);
};