From 01c6cb29410b57480b563659ae1930ea33bb759f Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 26 May 2026 11:45:48 +0800 Subject: [PATCH] fix(web): stream homepage evidence sources independently --- apps/web/src/app/[locale]/page.tsx | 96 ++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 32 deletions(-) diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx index 9e305b63..5baf9207 100644 --- a/apps/web/src/app/[locale]/page.tsx +++ b/apps/web/src/app/[locale]/page.tsx @@ -769,62 +769,94 @@ export default function Home({ params }: { params: { locale: string } }) { useEffect(() => { const controller = new AbortController() const encodedProjectId = encodeURIComponent('awoooi') - Promise.all([ + let isCancelled = false + let pendingRequests = 8 + const finishRequest = () => { + pendingRequests -= 1 + if (pendingRequests <= 0 && !isCancelled) { + setAutomationBriefLoaded(true) + } + } + const loadBriefPart = ( + key: K, + request: Promise + ) => { + request + .then(value => { + if (!isCancelled) { + setAutomationBrief(previous => ({ ...previous, [key]: value })) + } + }) + .catch(() => { + if (!isCancelled) { + setAutomationBrief(previous => ({ ...previous, [key]: null })) + } + }) + .finally(finishRequest) + } + + setAutomationBrief({}) + setAutomationBriefLoaded(false) + loadBriefPart( + 'callbackReplies', fetchHomepageJson( `${API_BASE}/api/v1/platform/runs/callback-replies?project_id=${encodedProjectId}&per_page=20`, controller.signal - ), + ) + ) + loadBriefPart( + 'aiRouteStatus', fetchHomepageJson( `${API_BASE}/api/v1/platform/ai-route-status?workload_type=deep_rca`, controller.signal - ), + ) + ) + loadBriefPart( + 'kmStaleCandidates', fetchHomepageJson( `${API_BASE}/api/v1/ai/governance/km-stale-candidates?project_id=${encodedProjectId}&limit=5`, controller.signal - ), + ) + ) + loadBriefPart( + 'dossierCoverage', fetchHomepageJson( `${API_BASE}/api/v1/platform/events/dossier/coverage?project_id=${encodedProjectId}&limit=100`, controller.signal - ), + ) + ) + loadBriefPart( + 'eventRecurrence', fetchHomepageJson( `${API_BASE}/api/v1/platform/events/dossier/recurrence?project_id=${encodedProjectId}&limit=100`, controller.signal - ), + ) + ) + loadBriefPart( + 'runsList', fetchHomepageJson( `${API_BASE}/api/v1/platform/runs/list?project_id=${encodedProjectId}&per_page=25`, controller.signal - ), + ) + ) + loadBriefPart( + 'cicdEvents', fetchHomepageJson( `${API_BASE}/api/v1/platform/cicd/events?project_id=${encodedProjectId}&limit=12`, controller.signal - ), + ) + ) + loadBriefPart( + 'kmOwnerReviewBurndown', fetchHomepageJson( `${API_BASE}/api/v1/ai/governance/km-stale-owner-review-burndown?project_id=${encodedProjectId}&limit=5`, controller.signal - ), - ]).then(([ - callbackReplies, - aiRouteStatus, - kmStaleCandidates, - dossierCoverage, - eventRecurrence, - runsList, - cicdEvents, - kmOwnerReviewBurndown, - ]) => { - setAutomationBrief({ - callbackReplies, - aiRouteStatus, - kmStaleCandidates, - dossierCoverage, - eventRecurrence, - runsList, - cicdEvents, - kmOwnerReviewBurndown, - }) - }).catch(() => {}) - .finally(() => setAutomationBriefLoaded(true)) - return () => controller.abort() + ) + ) + return () => { + isCancelled = true + controller.abort() + } }, []) // 自動處置率 — 首頁 KPI 使用 24h truth-chain 驗證率,避免把歷史 disposition 總表誤讀成今日閉環。