Skip to content

Commit 1aa79fc

Browse files
committed
feat: surface autonomous ops execution summaries in cockpit
1 parent 3155a68 commit 1aa79fc

File tree

1 file changed

+178
-11
lines changed

1 file changed

+178
-11
lines changed

src/app/page.tsx

Lines changed: 178 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,41 @@ interface AuthConfigData {
288288
readOnly: boolean;
289289
}
290290

291+
interface AutonomousVerifySummaryData {
292+
operationId: string;
293+
passed: boolean;
294+
resultCount: number;
295+
totalChecks: number;
296+
failedChecks: number;
297+
verifiedAt: string | null;
298+
}
299+
300+
interface AutonomousPlanSummaryData {
301+
planId: string;
302+
intent: AutonomousIntentData;
303+
stepCount: number;
304+
generatedAt: string | null;
305+
}
306+
307+
interface AutonomousExecuteSummaryData {
308+
operationId: string;
309+
success: boolean;
310+
totalSteps: number;
311+
completedSteps: number;
312+
failedSteps: number;
313+
skippedSteps: number;
314+
completedAt: string | null;
315+
}
316+
317+
interface AutonomousRollbackSummaryData {
318+
operationId: string;
319+
success: boolean;
320+
totalSteps: number;
321+
completedSteps: number;
322+
failedSteps: number;
323+
executedAt: string;
324+
}
325+
291326
type AutonomousIntentData =
292327
| 'stabilize_throughput'
293328
| 'recover_sequencer_path'
@@ -511,6 +546,10 @@ export default function Dashboard() {
511546
const [autonomousPlanId, setAutonomousPlanId] = useState<string | null>(null);
512547
const [autonomousOperationId, setAutonomousOperationId] = useState<string | null>(null);
513548
const [autonomousPlanSteps, setAutonomousPlanSteps] = useState<Array<{ title: string; risk: string }> | null>(null);
549+
const [autonomousVerifySummary, setAutonomousVerifySummary] = useState<AutonomousVerifySummaryData | null>(null);
550+
const [autonomousPlanSummary, setAutonomousPlanSummary] = useState<AutonomousPlanSummaryData | null>(null);
551+
const [autonomousExecuteSummary, setAutonomousExecuteSummary] = useState<AutonomousExecuteSummaryData | null>(null);
552+
const [autonomousRollbackSummary, setAutonomousRollbackSummary] = useState<AutonomousRollbackSummaryData | null>(null);
514553
const [authConfig, setAuthConfig] = useState<AuthConfigData | null>(null);
515554
const [autonomyActionFeedback, setAutonomyActionFeedback] = useState<{
516555
type: 'success' | 'error';
@@ -747,6 +786,10 @@ export default function Dashboard() {
747786
setAutonomousPlanId(null);
748787
setAutonomousOperationId(null);
749788
setAutonomousPlanSteps(null);
789+
setAutonomousVerifySummary(null);
790+
setAutonomousPlanSummary(null);
791+
setAutonomousExecuteSummary(null);
792+
setAutonomousRollbackSummary(null);
750793
setAutonomyActionFeedback({
751794
type: 'success',
752795
message: goalManagerEnabled
@@ -818,11 +861,23 @@ export default function Dashboard() {
818861
const message = typeof body.error === 'string' ? body.error : 'Failed to create autonomous plan.';
819862
throw new Error(message);
820863
}
821-
const plan = (body as { plan?: { planId?: string; steps?: unknown[] } }).plan;
864+
const plan = (body as { plan?: { planId?: string; steps?: unknown[]; generatedAt?: string } }).plan;
822865
if (plan?.planId) {
823866
setAutonomousPlanId(plan.planId);
824867
}
868+
setAutonomousOperationId(null);
869+
setAutonomousVerifySummary(null);
870+
setAutonomousExecuteSummary(null);
871+
setAutonomousRollbackSummary(null);
825872
const rawSteps = Array.isArray(plan?.steps) ? plan.steps : [];
873+
if (plan?.planId) {
874+
setAutonomousPlanSummary({
875+
planId: plan.planId,
876+
intent: autonomousIntent,
877+
stepCount: rawSteps.length,
878+
generatedAt: typeof plan.generatedAt === 'string' ? plan.generatedAt : null,
879+
});
880+
}
826881
setAutonomousPlanSteps(
827882
rawSteps.map((s) => {
828883
const step = s as { title?: string; risk?: string };
@@ -849,11 +904,35 @@ export default function Dashboard() {
849904
const message = typeof body.error === 'string' ? body.error : 'Failed to execute autonomous operation.';
850905
throw new Error(message);
851906
}
852-
const result = (body as { result?: { operationId?: string; steps?: unknown[]; success?: boolean } }).result;
907+
const result = (body as {
908+
result?: {
909+
operationId?: string;
910+
steps?: Array<{ status?: 'completed' | 'failed' | 'skipped' }>;
911+
success?: boolean;
912+
completedAt?: string;
913+
};
914+
}).result;
853915
if (result?.operationId) {
854916
setAutonomousOperationId(result.operationId);
855917
}
856-
const stepCount = Array.isArray(result?.steps) ? result.steps.length : 0;
918+
setAutonomousVerifySummary(null);
919+
const steps = Array.isArray(result?.steps) ? result.steps : [];
920+
const stepCount = steps.length;
921+
const completedSteps = steps.filter((step) => step.status === 'completed').length;
922+
const failedSteps = steps.filter((step) => step.status === 'failed').length;
923+
const skippedSteps = steps.filter((step) => step.status === 'skipped').length;
924+
if (result?.operationId) {
925+
setAutonomousExecuteSummary({
926+
operationId: result.operationId,
927+
success: result.success === true,
928+
totalSteps: stepCount,
929+
completedSteps,
930+
failedSteps,
931+
skippedSteps,
932+
completedAt: typeof result.completedAt === 'string' ? result.completedAt : new Date().toISOString(),
933+
});
934+
setAutonomousRollbackSummary(null);
935+
}
857936
setAutonomyActionFeedback({
858937
type: 'success',
859938
message: `Autonomous execute completed (${stepCount} steps, success=${result?.success === true ? 'true' : 'false'}).`,
@@ -876,8 +955,37 @@ export default function Dashboard() {
876955
const message = typeof body.error === 'string' ? body.error : 'Failed to verify autonomous operation.';
877956
throw new Error(message);
878957
}
879-
const result = (body as { result?: { passed?: boolean; results?: unknown[] } }).result;
880-
const checks = Array.isArray(result?.results) ? result.results.length : 0;
958+
const result = (body as {
959+
result?: {
960+
operationId?: string;
961+
passed?: boolean;
962+
results?: Array<{
963+
checks?: Array<{ passed?: boolean }>;
964+
verifiedAt?: string;
965+
}>;
966+
};
967+
}).result;
968+
const verifications = Array.isArray(result?.results) ? result.results : [];
969+
const checks = verifications.length;
970+
const totalChecks = verifications.reduce((sum, item) => {
971+
return sum + (Array.isArray(item.checks) ? item.checks.length : 0);
972+
}, 0);
973+
const failedChecks = verifications.reduce((sum, item) => {
974+
if (!Array.isArray(item.checks)) return sum;
975+
return sum + item.checks.filter((check) => check?.passed === false).length;
976+
}, 0);
977+
const latestVerifiedAtMs = verifications.reduce((max, item) => {
978+
const ms = item.verifiedAt ? new Date(item.verifiedAt).getTime() : 0;
979+
return Number.isFinite(ms) ? Math.max(max, ms) : max;
980+
}, 0);
981+
setAutonomousVerifySummary({
982+
operationId: result?.operationId || autonomousOperationId,
983+
passed: result?.passed === true,
984+
resultCount: checks,
985+
totalChecks,
986+
failedChecks,
987+
verifiedAt: latestVerifiedAtMs > 0 ? new Date(latestVerifiedAtMs).toISOString() : null,
988+
});
881989
setAutonomyActionFeedback({
882990
type: 'success',
883991
message: `Autonomous verify completed (passed=${result?.passed === true ? 'true' : 'false'}, checks=${checks}).`,
@@ -899,8 +1007,24 @@ export default function Dashboard() {
8991007
const message = typeof body.error === 'string' ? body.error : 'Failed to execute autonomous rollback.';
9001008
throw new Error(message);
9011009
}
902-
const result = (body as { result?: { success?: boolean; rollbackSteps?: unknown[] } }).result;
903-
const rollbackCount = Array.isArray(result?.rollbackSteps) ? result.rollbackSteps.length : 0;
1010+
const result = (body as {
1011+
result?: {
1012+
success?: boolean;
1013+
rollbackSteps?: Array<{ status?: 'completed' | 'failed' | 'skipped' }>;
1014+
};
1015+
}).result;
1016+
const rollbackSteps = Array.isArray(result?.rollbackSteps) ? result.rollbackSteps : [];
1017+
const rollbackCount = rollbackSteps.length;
1018+
const rollbackCompleted = rollbackSteps.filter((step) => step.status === 'completed').length;
1019+
const rollbackFailed = rollbackSteps.filter((step) => step.status === 'failed').length;
1020+
setAutonomousRollbackSummary({
1021+
operationId: autonomousOperationId,
1022+
success: result?.success === true,
1023+
totalSteps: rollbackCount,
1024+
completedSteps: rollbackCompleted,
1025+
failedSteps: rollbackFailed,
1026+
executedAt: new Date().toISOString(),
1027+
});
9041028
setAutonomyActionFeedback({
9051029
type: 'success',
9061030
message: `Autonomous rollback completed (success=${result?.success === true ? 'true' : 'false'}, steps=${rollbackCount}).`,
@@ -1883,9 +2007,52 @@ export default function Dashboard() {
18832007
</button>
18842008
</div>
18852009

1886-
<p className="mt-2 text-[10px] text-gray-500 break-all">
1887-
planId: <span className="font-mono text-gray-700">{autonomousPlanId || '-'}</span> · operationId: <span className="font-mono text-gray-700">{autonomousOperationId || '-'}</span>
1888-
</p>
2010+
<div className="mt-2 space-y-0.5">
2011+
<p className="text-[10px] text-gray-500">planId: <span className="font-mono text-gray-700 break-all">{autonomousPlanId || '-'}</span></p>
2012+
<p className="text-[10px] text-gray-500">operationId: <span className="font-mono text-gray-700 break-all">{autonomousOperationId || '-'}</span></p>
2013+
</div>
2014+
{(autonomousPlanSummary || autonomousExecuteSummary || autonomousRollbackSummary) && (
2015+
<div className="mt-2 border border-gray-200 rounded-lg bg-white px-2.5 py-2 space-y-1.5">
2016+
<p className="text-[10px] text-gray-500 font-semibold uppercase">Latest Autonomous Ops</p>
2017+
{autonomousPlanSummary && (
2018+
<p className="text-[11px] text-gray-600 break-all">
2019+
plan <span className="font-mono text-gray-700">{autonomousPlanSummary.planId}</span> · steps {autonomousPlanSummary.stepCount}
2020+
{autonomousPlanSummary.generatedAt ? ` · ${new Date(autonomousPlanSummary.generatedAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })}` : ''}
2021+
</p>
2022+
)}
2023+
{autonomousExecuteSummary && (
2024+
<p className="text-[11px] text-gray-600 break-all">
2025+
execute <span className="font-mono text-gray-700">{autonomousExecuteSummary.operationId}</span> · {autonomousExecuteSummary.success ? 'success' : 'failed'} · total {autonomousExecuteSummary.totalSteps} / done {autonomousExecuteSummary.completedSteps} / fail {autonomousExecuteSummary.failedSteps} / skip {autonomousExecuteSummary.skippedSteps}
2026+
</p>
2027+
)}
2028+
{autonomousRollbackSummary && (
2029+
<p className="text-[11px] text-gray-600 break-all">
2030+
rollback <span className="font-mono text-gray-700">{autonomousRollbackSummary.operationId}</span> · {autonomousRollbackSummary.success ? 'success' : 'failed'} · total {autonomousRollbackSummary.totalSteps} / done {autonomousRollbackSummary.completedSteps} / fail {autonomousRollbackSummary.failedSteps}
2031+
</p>
2032+
)}
2033+
</div>
2034+
)}
2035+
{autonomousVerifySummary && (
2036+
<div className="mt-2 border border-gray-200 rounded-lg bg-white px-2.5 py-2">
2037+
<div className="flex items-center justify-between gap-2">
2038+
<p className="text-[10px] text-gray-500 font-semibold uppercase">Latest Verify Result</p>
2039+
<span className={`text-[10px] font-bold px-1.5 py-0.5 rounded ${
2040+
autonomousVerifySummary.passed ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
2041+
}`}>
2042+
{autonomousVerifySummary.passed ? 'PASS' : 'FAIL'}
2043+
</span>
2044+
</div>
2045+
<p className="mt-1 text-[11px] text-gray-600">
2046+
operation: <span className="font-mono text-gray-700 break-all">{autonomousVerifySummary.operationId}</span>
2047+
</p>
2048+
<p className="text-[11px] text-gray-600">
2049+
results {autonomousVerifySummary.resultCount} · checks {autonomousVerifySummary.totalChecks} · failed {autonomousVerifySummary.failedChecks}
2050+
</p>
2051+
<p className="text-[10px] text-gray-500">
2052+
verified at {autonomousVerifySummary.verifiedAt ? new Date(autonomousVerifySummary.verifiedAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }) : 'N/A'}
2053+
</p>
2054+
</div>
2055+
)}
18892056
{autonomousPlanSteps && autonomousPlanSteps.length > 0 && (
18902057
<div className="mt-2 border border-gray-200 rounded-lg overflow-hidden">
18912058
{autonomousPlanSteps.map((step, i) => (
@@ -2190,7 +2357,7 @@ export default function Dashboard() {
21902357
direction = '↓';
21912358
} else {
21922359
// Fallback: use the cleaned reason as-is
2193-
reasonSummary = cleanReason.length > 20 ? cleanReason.substring(0, 17) + '...' : cleanReason;
2360+
reasonSummary = cleanReason;
21942361
direction = scaling.targetVcpu > scaling.currentVcpu ? '↑' : scaling.targetVcpu < scaling.currentVcpu ? '↓' : '→';
21952362
}
21962363

0 commit comments

Comments
 (0)