automation overview page implemeantion initital complete

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-17 08:24:44 +00:00
parent 79398c908d
commit 6b1fa0c1ee
22 changed files with 3789 additions and 178 deletions

View File

@@ -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>
</>
);

View 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;