Files
igny8/frontend/src/pages/Automation/AutomationRunDetail.tsx
2026-01-17 08:24:44 +00:00

121 lines
4.1 KiB
TypeScript

/**
* Automation Run Detail Page
* Comprehensive view of a single automation run
*/
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useSiteStore } from '../../store/siteStore';
import { automationService } from '../../services/automationService';
import { RunDetailResponse } from '../../types/automation';
import { useToast } from '../../components/ui/toast/ToastContainer';
import PageMeta from '../../components/common/PageMeta';
import PageHeader from '../../components/common/PageHeader';
import RunSummaryCard from '../../components/Automation/DetailView/RunSummaryCard';
import StageAccordion from '../../components/Automation/DetailView/StageAccordion';
import EfficiencyMetrics from '../../components/Automation/DetailView/EfficiencyMetrics';
import InsightsPanel from '../../components/Automation/DetailView/InsightsPanel';
import CreditBreakdownChart from '../../components/Automation/DetailView/CreditBreakdownChart';
const AutomationRunDetail: React.FC = () => {
const { runId } = useParams<{ runId: string }>();
const navigate = useNavigate();
const { activeSite } = useSiteStore();
const toast = useToast();
const [loading, setLoading] = useState(true);
const [runDetail, setRunDetail] = useState<RunDetailResponse | null>(null);
useEffect(() => {
loadRunDetail();
}, [runId, activeSite]);
const loadRunDetail = async () => {
if (!activeSite || !runId) return;
try {
setLoading(true);
const data = await automationService.getRunDetail(activeSite.id, runId);
setRunDetail(data);
} catch (error: any) {
console.error('Failed to load run detail', error);
toast.error(error.message || 'Failed to load run detail');
} finally {
setLoading(false);
}
};
if (!activeSite) {
return (
<div className="p-6">
<p className="text-gray-600 dark:text-gray-400">Please select a site to view automation run details.</p>
</div>
);
}
if (loading) {
return (
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-gray-500 dark:text-gray-400">Loading run details...</div>
</div>
);
}
if (!runDetail) {
return (
<div className="p-6">
<p className="text-gray-600 dark:text-gray-400">Run not found.</p>
</div>
);
}
return (
<>
<PageMeta
title={`Run Detail - ${runDetail.run?.run_title || 'Automation Run'}`}
description="Detailed automation run analysis"
/>
<div className="space-y-6">
<PageHeader
title={runDetail.run?.run_title || 'Automation Run'}
breadcrumb={`Automation / Runs / ${runDetail.run?.run_title || 'Detail'}`}
description="Comprehensive run analysis with stage breakdown and performance metrics"
/>
{/* Run Summary */}
{runDetail.run && <RunSummaryCard run={runDetail.run} />}
{/* Insights Panel */}
{runDetail.insights && runDetail.insights.length > 0 && (
<InsightsPanel insights={runDetail.insights} />
)}
{/* Two Column Layout */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Left Column - Credit Breakdown & Efficiency */}
<div className="lg:col-span-1 space-y-6">
{runDetail.stages && <CreditBreakdownChart stages={runDetail.stages} />}
{runDetail.efficiency && runDetail.historical_comparison && (
<EfficiencyMetrics
efficiency={runDetail.efficiency}
historicalComparison={runDetail.historical_comparison}
/>
)}
</div>
{/* Right Column - Stage Details */}
<div className="lg:col-span-2">
{runDetail.stages && runDetail.run?.initial_snapshot && (
<StageAccordion
stages={runDetail.stages}
initialSnapshot={runDetail.run.initial_snapshot}
/>
)}
</div>
</div>
</div>
</>
);
};
export default AutomationRunDetail;