121 lines
4.1 KiB
TypeScript
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;
|