mirror of
https://github.com/coleam00/Archon.git
synced 2025-12-23 18:29:18 -05:00
- Add WorkOrderLogsPanel with SSE streaming support - Add RealTimeStats component for live metrics - Add useWorkOrderLogs hook for SSE log streaming - Add useLogStats hook for real-time statistics - Update WorkOrderDetailView to display logs panel - Add comprehensive tests for new components - Configure Vite test environment
126 lines
3.3 KiB
TypeScript
126 lines
3.3 KiB
TypeScript
import { useMemo } from "react";
|
|
import type { LogEntry } from "../types";
|
|
|
|
export interface LogStats {
|
|
/** Current step being executed */
|
|
currentStep: string | null;
|
|
|
|
/** Current step number (e.g., 2 from "2/5") */
|
|
currentStepNumber: number | null;
|
|
|
|
/** Total steps */
|
|
totalSteps: number | null;
|
|
|
|
/** Progress percentage (0-100) */
|
|
progressPct: number | null;
|
|
|
|
/** Elapsed time in seconds */
|
|
elapsedSeconds: number | null;
|
|
|
|
/** Last activity timestamp */
|
|
lastActivity: string | null;
|
|
|
|
/** Current substep activity description */
|
|
currentActivity: string | null;
|
|
|
|
/** Whether workflow has started */
|
|
hasStarted: boolean;
|
|
|
|
/** Whether workflow has completed */
|
|
hasCompleted: boolean;
|
|
|
|
/** Whether workflow has failed */
|
|
hasFailed: boolean;
|
|
}
|
|
|
|
/**
|
|
* Extract real-time metrics from log entries
|
|
*
|
|
* Analyzes logs to derive current execution status, progress, and activity.
|
|
* Uses memoization to avoid recomputing on every render.
|
|
*/
|
|
export function useLogStats(logs: LogEntry[]): LogStats {
|
|
return useMemo(() => {
|
|
if (logs.length === 0) {
|
|
return {
|
|
currentStep: null,
|
|
currentStepNumber: null,
|
|
totalSteps: null,
|
|
progressPct: null,
|
|
elapsedSeconds: null,
|
|
lastActivity: null,
|
|
currentActivity: null,
|
|
hasStarted: false,
|
|
hasCompleted: false,
|
|
hasFailed: false,
|
|
};
|
|
}
|
|
|
|
// Find most recent log entry
|
|
const latestLog = logs[logs.length - 1];
|
|
|
|
// Find most recent step_started event
|
|
let currentStep: string | null = null;
|
|
let currentStepNumber: number | null = null;
|
|
let totalSteps: number | null = null;
|
|
|
|
for (let i = logs.length - 1; i >= 0; i--) {
|
|
const log = logs[i];
|
|
if (log.event === "step_started" && log.step) {
|
|
currentStep = log.step;
|
|
currentStepNumber = log.step_number ?? null;
|
|
totalSteps = log.total_steps ?? null;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find most recent progress data
|
|
let progressPct: number | null = null;
|
|
for (let i = logs.length - 1; i >= 0; i--) {
|
|
const log = logs[i];
|
|
if (log.progress_pct !== undefined && log.progress_pct !== null) {
|
|
progressPct = log.progress_pct;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find most recent elapsed time
|
|
let elapsedSeconds: number | null = null;
|
|
for (let i = logs.length - 1; i >= 0; i--) {
|
|
const log = logs[i];
|
|
if (log.elapsed_seconds !== undefined && log.elapsed_seconds !== null) {
|
|
elapsedSeconds = log.elapsed_seconds;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Current activity is the latest event description
|
|
const currentActivity = latestLog.event || null;
|
|
|
|
// Last activity timestamp
|
|
const lastActivity = latestLog.timestamp;
|
|
|
|
// Check for workflow lifecycle events
|
|
const hasStarted = logs.some((log) => log.event === "workflow_started" || log.event === "step_started");
|
|
|
|
const hasCompleted = logs.some((log) => log.event === "workflow_completed" || log.event === "agent_work_order_completed");
|
|
|
|
const hasFailed = logs.some(
|
|
(log) => log.event === "workflow_failed" || log.event === "agent_work_order_failed" || log.level === "error",
|
|
);
|
|
|
|
return {
|
|
currentStep,
|
|
currentStepNumber,
|
|
totalSteps,
|
|
progressPct,
|
|
elapsedSeconds,
|
|
lastActivity,
|
|
currentActivity,
|
|
hasStarted,
|
|
hasCompleted,
|
|
hasFailed,
|
|
};
|
|
}, [logs]);
|
|
}
|