automation overview page implemeantion initital complete
This commit is contained in:
@@ -6,6 +6,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useToast } from '../../components/ui/toast/ToastContainer';
|
||||
import { useSiteStore } from '../../store/siteStore';
|
||||
import { automationService } from '../../services/automationService';
|
||||
import { OverviewStatsResponse } from '../../types/automation';
|
||||
import {
|
||||
fetchKeywords,
|
||||
fetchClusters,
|
||||
@@ -18,6 +19,10 @@ import RunHistory from '../../components/Automation/RunHistory';
|
||||
import PageMeta from '../../components/common/PageMeta';
|
||||
import PageHeader from '../../components/common/PageHeader';
|
||||
import ComponentCard from '../../components/common/ComponentCard';
|
||||
import RunStatisticsSummary from '../../components/Automation/DetailView/RunStatisticsSummary';
|
||||
import PredictiveCostAnalysis from '../../components/Automation/DetailView/PredictiveCostAnalysis';
|
||||
import AttentionItemsAlert from '../../components/Automation/DetailView/AttentionItemsAlert';
|
||||
import EnhancedRunHistory from '../../components/Automation/DetailView/EnhancedRunHistory';
|
||||
import {
|
||||
ListIcon,
|
||||
GroupIcon,
|
||||
@@ -31,7 +36,9 @@ const AutomationOverview: React.FC = () => {
|
||||
const toast = useToast();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [metrics, setMetrics] = useState<any>(null);
|
||||
const [estimate, setEstimate] = useState<any>(null);
|
||||
const [overviewStats, setOverviewStats] = useState<OverviewStatsResponse | null>(null);
|
||||
const [historyPage, setHistoryPage] = useState(1);
|
||||
const [historyData, setHistoryData] = useState<any>(null);
|
||||
|
||||
// Load metrics for the 5 metric cards
|
||||
const loadMetrics = async () => {
|
||||
@@ -89,28 +96,42 @@ const AutomationOverview: React.FC = () => {
|
||||
};
|
||||
|
||||
// Load cost estimate
|
||||
const loadEstimate = async () => {
|
||||
const loadOverviewStats = async () => {
|
||||
if (!activeSite) return;
|
||||
|
||||
try {
|
||||
const estimateData = await automationService.estimate(activeSite.id);
|
||||
setEstimate(estimateData);
|
||||
const stats = await automationService.getOverviewStats(activeSite.id);
|
||||
setOverviewStats(stats);
|
||||
} catch (e) {
|
||||
console.warn('Failed to fetch cost estimate', e);
|
||||
console.warn('Failed to fetch overview stats', e);
|
||||
}
|
||||
};
|
||||
|
||||
// Load enhanced history
|
||||
const loadEnhancedHistory = async (page: number = 1) => {
|
||||
if (!activeSite) return;
|
||||
|
||||
try {
|
||||
const history = await automationService.getEnhancedHistory(activeSite.id, page, 10);
|
||||
setHistoryData(history);
|
||||
} catch (e) {
|
||||
console.warn('Failed to fetch enhanced history', e);
|
||||
// Set to null so fallback component shows
|
||||
setHistoryData(null);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
setLoading(true);
|
||||
await Promise.all([loadMetrics(), loadEstimate()]);
|
||||
await Promise.all([loadMetrics(), loadOverviewStats(), loadEnhancedHistory(historyPage)]);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
if (activeSite) {
|
||||
loadData();
|
||||
}
|
||||
}, [activeSite]);
|
||||
}, [activeSite, historyPage]);
|
||||
|
||||
// Helper to render metric rows
|
||||
const renderMetricRow = (items: Array<{ label: string; value: number; colorCls: string }>) => {
|
||||
@@ -253,34 +274,50 @@ const AutomationOverview: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* Cost Estimation Card */}
|
||||
{estimate && (
|
||||
<ComponentCard
|
||||
title="Ready to Process"
|
||||
>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Estimated Items to Process: <span className="text-lg font-bold text-brand-600">{estimate.estimated_credits || 0}</span>
|
||||
</div>
|
||||
<div className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Current Balance: <span className="text-lg font-bold text-success-600">{estimate.current_balance || 0}</span> credits
|
||||
</div>
|
||||
<div className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Status: {estimate.sufficient ? (
|
||||
<span className="text-success-600 font-bold">✓ Sufficient credits</span>
|
||||
) : (
|
||||
<span className="text-danger-600 font-bold">⚠ Insufficient credits</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{overviewStats ? (
|
||||
<>
|
||||
{/* Attention Items Alert */}
|
||||
{overviewStats.attention_items && (
|
||||
<AttentionItemsAlert items={overviewStats.attention_items} />
|
||||
)}
|
||||
|
||||
{/* Statistics and Predictive Analysis */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{overviewStats.run_statistics && (
|
||||
<RunStatisticsSummary statistics={overviewStats.run_statistics} loading={loading} />
|
||||
)}
|
||||
{overviewStats.predictive_analysis && (
|
||||
<PredictiveCostAnalysis analysis={overviewStats.predictive_analysis} loading={loading} />
|
||||
)}
|
||||
</div>
|
||||
</ComponentCard>
|
||||
</>
|
||||
) : !loading && (
|
||||
<div className="bg-white dark:bg-gray-900 rounded-xl p-6">
|
||||
<p className="text-gray-600 dark:text-gray-400">Loading automation statistics...</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Run History */}
|
||||
{activeSite && <RunHistory siteId={activeSite.id} />}
|
||||
{/* Enhanced Run History */}
|
||||
{historyData && historyData.runs && (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">Run History</h2>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
Click on any run to view detailed analysis
|
||||
</p>
|
||||
</div>
|
||||
<EnhancedRunHistory
|
||||
runs={historyData.runs}
|
||||
loading={loading}
|
||||
currentPage={historyData.pagination?.page || 1}
|
||||
totalPages={historyData.pagination?.total_pages || 1}
|
||||
onPageChange={setHistoryPage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Fallback: Old Run History (if enhanced data not available) */}
|
||||
{!historyData && activeSite && <RunHistory siteId={activeSite.id} />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
120
frontend/src/pages/Automation/AutomationRunDetail.tsx
Normal file
120
frontend/src/pages/Automation/AutomationRunDetail.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user