fix(web): speed up homepage live evidence loading
All checks were successful
CD Pipeline / tests (push) Successful in 1m39s
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / build-and-deploy (push) Successful in 4m52s
CD Pipeline / post-deploy-checks (push) Successful in 3m18s

This commit is contained in:
Your Name
2026-05-29 10:28:31 +08:00
parent 5f69416eec
commit 1b28dcf3f9
2 changed files with 119 additions and 80 deletions

View File

@@ -33,8 +33,10 @@ import { FlywheelKPICard } from '@/components/dashboard/flywheel-kpi-card'
import { AutomationEvidenceCard } from '@/components/dashboard/automation-evidence-card'
const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? ''
const STATUS_CHAIN_PREFETCH_LIMIT = 25
const HOMEPAGE_INCIDENT_LIMIT = STATUS_CHAIN_PREFETCH_LIMIT
const HOMEPAGE_STATUS_CHAIN_PREFETCH_LIMIT = 8
const HOMEPAGE_STATUS_CHAIN_CONCURRENCY = 2
const HOMEPAGE_STATUS_CHAIN_TIMEOUT_MS = 6000
const HOMEPAGE_INCIDENT_LIMIT = HOMEPAGE_STATUS_CHAIN_PREFETCH_LIMIT
const HOMEPAGE_BLUEPRINT_STAGE_KEYS = ['signal', 'intake', 'ai', 'mcp', 'playbook', 'ansible', 'approval', 'verify'] as const
type HomepageBlueprintStageKey = typeof HOMEPAGE_BLUEPRINT_STAGE_KEYS[number]
@@ -712,7 +714,9 @@ export default function Home({ params }: { params: { locale: string } }) {
isLoading: isStatusChainsLoading,
} = useIncidentStatusChains({
incidentIds: incidents?.map(incident => incident.incident_id) ?? [],
limit: STATUS_CHAIN_PREFETCH_LIMIT,
limit: HOMEPAGE_STATUS_CHAIN_PREFETCH_LIMIT,
concurrency: HOMEPAGE_STATUS_CHAIN_CONCURRENCY,
timeoutMs: HOMEPAGE_STATUS_CHAIN_TIMEOUT_MS,
refreshKey: incidentsLastUpdated?.toISOString() ?? null,
})
@@ -864,8 +868,19 @@ export default function Home({ params }: { params: { locale: string } }) {
const unavailableValue = tDashboard('automationDelivery.unavailableValue')
const loadingStatus = tDashboard('automationDelivery.status.loading')
const unavailableStatus = tDashboard('automationDelivery.status.unavailable')
const formatLiveEvidenceTime = (value: string | null | undefined) => {
if (!value) return automationBriefLoaded ? unavailableValue : loadingStatus
const hasAutomationBriefPart = (key: keyof HomepageAutomationBriefSnapshot) => (
Object.prototype.hasOwnProperty.call(automationBrief, key)
)
const callbackRepliesLoaded = hasAutomationBriefPart('callbackReplies')
const aiRouteStatusLoaded = hasAutomationBriefPart('aiRouteStatus')
const kmStaleCandidatesLoaded = hasAutomationBriefPart('kmStaleCandidates')
const dossierCoverageLoaded = hasAutomationBriefPart('dossierCoverage')
const eventRecurrenceLoaded = hasAutomationBriefPart('eventRecurrence')
const runsListLoaded = hasAutomationBriefPart('runsList')
const cicdEventsLoaded = hasAutomationBriefPart('cicdEvents')
const kmOwnerReviewBurndownLoaded = hasAutomationBriefPart('kmOwnerReviewBurndown')
const formatLiveEvidenceTime = (value: string | null | undefined, loaded = automationBriefLoaded) => {
if (!value) return loaded ? unavailableValue : loadingStatus
const date = new Date(value)
if (Number.isNaN(date.getTime())) return unavailableValue
return date.toLocaleString(locale === 'en' ? 'en-US' : 'zh-TW', {
@@ -917,7 +932,7 @@ export default function Home({ params }: { params: { locale: string } }) {
const callbackTraceSummary = automationBrief.callbackReplies?.summary ?? null
const missingTraceRecent24h = callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_24h_total ?? 0
const traceRecoveryStatus = callbackTraceSummary?.outbound_reply_markup_trace_ref_gap_recovery_status
?? (automationBriefLoaded ? unavailableValue : loadingStatus)
?? (callbackRepliesLoaded ? unavailableValue : loadingStatus)
const traceRecoveryCount = callbackTraceSummary?.outbound_reply_markup_trace_ref_after_gap_total
const aiRouteSelectedProvider = automationBrief.aiRouteStatus?.selected_provider ?? '--'
const aiRouteLaneMode = automationBrief.aiRouteStatus?.lane_mode ?? '--'
@@ -986,7 +1001,7 @@ export default function Home({ params }: { params: { locale: string } }) {
const kmBurndownSnapshot = kmOwnerReviewBurndown?.current_snapshot ?? null
const staleRatioLabel = typeof kmBurndownSnapshot?.stale_ratio === 'number'
? `${(kmBurndownSnapshot.stale_ratio * 100).toFixed(1)}%`
: automationBriefLoaded ? unavailableValue : loadingStatus
: kmOwnerReviewBurndownLoaded ? unavailableValue : loadingStatus
const automationWorkToneStyle: Record<HomepageWorkTone, { bg: string; border: string; color: string }> = {
live: { bg: '#f0faf2', border: '#9bc7a4', color: '#17602a' },
progress: { bg: '#fff7e8', border: '#d9b36f', color: '#8a5a08' },
@@ -1019,11 +1034,11 @@ export default function Home({ params }: { params: { locale: string } }) {
title: tDashboard('automationDelivery.delivered.callbackEvidence.title'),
status: hasCallbackEvidence
? tDashboard('automationDelivery.status.live')
: automationBriefLoaded
: callbackRepliesLoaded
? unavailableStatus
: loadingStatus,
detail: tDashboard('automationDelivery.delivered.callbackEvidence.detail', {
total: formatAutomationNumber(automationBrief.callbackReplies?.total, automationBriefLoaded),
total: formatAutomationNumber(automationBrief.callbackReplies?.total, callbackRepliesLoaded),
}),
href: `/${locale}/awooop/runs?project_id=awoooi#tg-callback-evidence`,
tone: hasCallbackEvidence ? 'live' : 'watching',
@@ -1033,15 +1048,15 @@ export default function Home({ params }: { params: { locale: string } }) {
title: tDashboard('automationDelivery.delivered.callbackTrace.title'),
status: callbackTraceSummary && traceRecoveryStatus === 'recovered_after_gap'
? tDashboard('automationDelivery.status.progress')
: !automationBriefLoaded
: !callbackRepliesLoaded
? loadingStatus
: callbackTraceSummary
? tDashboard('automationDelivery.status.watching')
: unavailableStatus,
detail: tDashboard('automationDelivery.delivered.callbackTrace.detail', {
status: traceRecoveryStatus,
recovered: formatAutomationNumber(traceRecoveryCount, automationBriefLoaded),
recent24h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_24h_total, automationBriefLoaded),
recovered: formatAutomationNumber(traceRecoveryCount, callbackRepliesLoaded),
recent24h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_24h_total, callbackRepliesLoaded),
}),
href: `/${locale}/awooop/work-items?project_id=awoooi`,
tone: traceRecoveryStatus === 'recovered_after_gap' ? 'progress' : 'watching',
@@ -1118,7 +1133,7 @@ export default function Home({ params }: { params: { locale: string } }) {
{
key: 'kmGovernance',
title: tDashboard('automationDelivery.remaining.kmGovernance.title'),
status: !automationBriefLoaded
status: !kmStaleCandidatesLoaded
? loadingStatus
: typeof kmStaleTotal === 'number' && kmStaleTotal > 0
? tDashboard('automationDelivery.status.progress')
@@ -1126,8 +1141,8 @@ export default function Home({ params }: { params: { locale: string } }) {
? tDashboard('automationDelivery.status.live')
: unavailableStatus,
detail: tDashboard('automationDelivery.remaining.kmGovernance.detail', {
stale: formatAutomationNumber(kmStaleTotal, automationBriefLoaded),
days: formatAutomationNumber(kmStaleThreshold, automationBriefLoaded),
stale: formatAutomationNumber(kmStaleTotal, kmStaleCandidatesLoaded),
days: formatAutomationNumber(kmStaleThreshold, kmStaleCandidatesLoaded),
}),
href: `/${locale}/awooop/work-items?project_id=awoooi`,
tone: typeof kmStaleTotal === 'number' && kmStaleTotal > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching',
@@ -1135,7 +1150,7 @@ export default function Home({ params }: { params: { locale: string } }) {
{
key: 'callbackBacklogDecay',
title: tDashboard('automationDelivery.remaining.callbackBacklogDecay.title'),
status: !automationBriefLoaded
status: !callbackRepliesLoaded
? loadingStatus
: callbackTraceSummary && missingTraceRecent24h > 0
? tDashboard('automationDelivery.status.progress')
@@ -1143,9 +1158,9 @@ export default function Home({ params }: { params: { locale: string } }) {
? tDashboard('automationDelivery.status.live')
: unavailableStatus,
detail: tDashboard('automationDelivery.remaining.callbackBacklogDecay.detail', {
recent1h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_1h_total, automationBriefLoaded),
recent24h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_24h_total, automationBriefLoaded),
missing: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_total, automationBriefLoaded),
recent1h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_1h_total, callbackRepliesLoaded),
recent24h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_24h_total, callbackRepliesLoaded),
missing: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_total, callbackRepliesLoaded),
}),
href: `/${locale}/awooop/runs?project_id=awoooi#tg-callback-evidence`,
tone: callbackTraceSummary && missingTraceRecent24h > 0 ? 'progress' : callbackTraceSummary ? 'live' : 'watching',
@@ -1210,10 +1225,9 @@ export default function Home({ params }: { params: { locale: string } }) {
key: 'signal',
title: tDashboard('automationDiagrams.workspace.flow.stages.signal'),
status: tDashboard('automationDelivery.status.live'),
detail: tDashboard('automationDiagrams.workspace.values.callback', {
missing: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_total, automationBriefLoaded),
recent1h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_1h_total, automationBriefLoaded),
recent24h: formatAutomationNumber(callbackTraceSummary?.outbound_reply_markup_missing_trace_ref_recent_24h_total, automationBriefLoaded),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.signal.metric', {
sources: formatAutomationNumber(dossierCoverageSummary?.source_count, dossierCoverageLoaded),
refs: formatAutomationNumber(dossierCoverageSummary?.source_ref_total, dossierCoverageLoaded),
}),
href: `/${locale}/awooop/runs?project_id=awoooi#tg-callback-evidence`,
tone: 'live',
@@ -1222,18 +1236,18 @@ export default function Home({ params }: { params: { locale: string } }) {
nextAction: tDashboard('automationDiagrams.workspace.inspector.stages.signal.nextAction'),
liveEvidence: {
metric: tDashboard('automationDiagrams.workspace.liveEvidence.signal.metric', {
sources: formatAutomationNumber(dossierCoverageSummary?.source_count, automationBriefLoaded),
refs: formatAutomationNumber(dossierCoverageSummary?.source_ref_total, automationBriefLoaded),
sources: formatAutomationNumber(dossierCoverageSummary?.source_count, dossierCoverageLoaded),
refs: formatAutomationNumber(dossierCoverageSummary?.source_ref_total, dossierCoverageLoaded),
}),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.signal.detail', {
missing: formatAutomationNumber(dossierCoverageSummary?.missing_source_refs_total, automationBriefLoaded),
duplicates: formatAutomationNumber(dossierCoverageSummary?.duplicate_total, automationBriefLoaded),
alert: formatAutomationNumber(dossierCoverageSummary?.alert_ref_total, automationBriefLoaded),
sentry: formatAutomationNumber(dossierCoverageSummary?.sentry_ref_total, automationBriefLoaded),
signoz: formatAutomationNumber(dossierCoverageSummary?.signoz_ref_total, automationBriefLoaded),
missing: formatAutomationNumber(dossierCoverageSummary?.missing_source_refs_total, dossierCoverageLoaded),
duplicates: formatAutomationNumber(dossierCoverageSummary?.duplicate_total, dossierCoverageLoaded),
alert: formatAutomationNumber(dossierCoverageSummary?.alert_ref_total, dossierCoverageLoaded),
sentry: formatAutomationNumber(dossierCoverageSummary?.sentry_ref_total, dossierCoverageLoaded),
signoz: formatAutomationNumber(dossierCoverageSummary?.signoz_ref_total, dossierCoverageLoaded),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.dossierCoverage'),
updated: formatLiveEvidenceTime(dossierCoverageSummary?.latest_received_at),
updated: formatLiveEvidenceTime(dossierCoverageSummary?.latest_received_at, dossierCoverageLoaded),
},
},
{
@@ -1248,17 +1262,17 @@ export default function Home({ params }: { params: { locale: string } }) {
nextAction: tDashboard('automationDiagrams.workspace.inspector.stages.intake.nextAction'),
liveEvidence: {
metric: tDashboard('automationDiagrams.workspace.liveEvidence.intake.metric', {
runs: formatAutomationNumber(automationBrief.runsList?.total, automationBriefLoaded),
linked: formatAutomationNumber(recurrenceSummary?.linked_run_total, automationBriefLoaded),
runs: formatAutomationNumber(automationBrief.runsList?.total, runsListLoaded),
linked: formatAutomationNumber(recurrenceSummary?.linked_run_total, eventRecurrenceLoaded),
}),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.intake.detail', {
stage: latestCicdEvent?.stage ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
status: latestCicdEvent?.status ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
commit: latestCicdEvent?.commit_sha?.slice(0, 7) ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
attention: formatAutomationNumber(cicdNeedsAttention, automationBriefLoaded),
stage: latestCicdEvent?.stage ?? (cicdEventsLoaded ? unavailableValue : loadingStatus),
status: latestCicdEvent?.status ?? (cicdEventsLoaded ? unavailableValue : loadingStatus),
commit: latestCicdEvent?.commit_sha?.slice(0, 7) ?? (cicdEventsLoaded ? unavailableValue : loadingStatus),
attention: formatAutomationNumber(cicdNeedsAttention, cicdEventsLoaded),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.runsAndCicd'),
updated: formatLiveEvidenceTime(latestCicdEvent?.created_at ?? latestRun?.created_at),
updated: formatLiveEvidenceTime(latestCicdEvent?.created_at ?? latestRun?.created_at, cicdEventsLoaded || runsListLoaded),
},
},
{
@@ -1280,12 +1294,12 @@ export default function Home({ params }: { params: { locale: string } }) {
provider: aiRouteSelectedProvider,
}),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.ai.detail', {
skipped: formatAutomationNumber(automationBrief.aiRouteStatus?.skipped_lanes?.length, automationBriefLoaded),
action: automationBrief.aiRouteStatus?.operator_action?.action ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
reason: automationBrief.aiRouteStatus?.operator_action?.reason ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
skipped: formatAutomationNumber(automationBrief.aiRouteStatus?.skipped_lanes?.length, aiRouteStatusLoaded),
action: automationBrief.aiRouteStatus?.operator_action?.action ?? (aiRouteStatusLoaded ? unavailableValue : loadingStatus),
reason: automationBrief.aiRouteStatus?.operator_action?.reason ?? (aiRouteStatusLoaded ? unavailableValue : loadingStatus),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.aiRouteStatus'),
updated: automationBriefLoaded ? tDashboard('automationDiagrams.workspace.liveEvidence.realtime') : loadingStatus,
updated: aiRouteStatusLoaded ? tDashboard('automationDiagrams.workspace.liveEvidence.realtime') : loadingStatus,
},
},
{
@@ -1295,7 +1309,7 @@ export default function Home({ params }: { params: { locale: string } }) {
? tDashboard('automationDelivery.status.live')
: tDashboard('automationDelivery.status.watching'),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.mcp.metric', {
observations: formatAutomationNumber(runEvidenceSummary.mcpTotal, automationBriefLoaded),
observations: formatAutomationNumber(runEvidenceSummary.mcpTotal, runsListLoaded),
gateway: formatAutomationNumber(statusChainEvidenceSummary.mcpGateway, true),
}),
href: `/${locale}/awooop/runs?project_id=awoooi`,
@@ -1305,17 +1319,17 @@ export default function Home({ params }: { params: { locale: string } }) {
nextAction: tDashboard('automationDiagrams.workspace.inspector.stages.mcp.nextAction'),
liveEvidence: {
metric: tDashboard('automationDiagrams.workspace.liveEvidence.mcp.metric', {
observations: formatAutomationNumber(runEvidenceSummary.mcpTotal, automationBriefLoaded),
observations: formatAutomationNumber(runEvidenceSummary.mcpTotal, runsListLoaded),
gateway: formatAutomationNumber(statusChainEvidenceSummary.mcpGateway, true),
}),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.mcp.detail', {
success: formatAutomationNumber(runEvidenceSummary.mcpSuccess + statusChainEvidenceSummary.mcpGatewaySuccess, automationBriefLoaded),
failed: formatAutomationNumber(runEvidenceSummary.mcpFailed + statusChainEvidenceSummary.mcpGatewayFailed, automationBriefLoaded),
server: runEvidenceSummary.latestMcpServer ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
route: runEvidenceSummary.latestRoute ?? (automationBriefLoaded ? unavailableValue : loadingStatus),
success: formatAutomationNumber(runEvidenceSummary.mcpSuccess + statusChainEvidenceSummary.mcpGatewaySuccess, runsListLoaded),
failed: formatAutomationNumber(runEvidenceSummary.mcpFailed + statusChainEvidenceSummary.mcpGatewayFailed, runsListLoaded),
server: runEvidenceSummary.latestMcpServer ?? (runsListLoaded ? unavailableValue : loadingStatus),
route: runEvidenceSummary.latestRoute ?? (runsListLoaded ? unavailableValue : loadingStatus),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.runsAndStatusChain'),
updated: formatLiveEvidenceTime(latestRun?.created_at),
updated: formatLiveEvidenceTime(latestRun?.created_at, runsListLoaded),
},
},
{
@@ -1406,8 +1420,8 @@ export default function Home({ params }: { params: { locale: string } }) {
title: tDashboard('automationDiagrams.workspace.flow.stages.verify'),
status: typeof kmStaleTotal === 'number' && kmStaleTotal > 0 ? tDashboard('automationDelivery.status.progress') : tDashboard('automationDelivery.status.live'),
detail: tDashboard('automationDiagrams.workspace.values.km', {
stale: formatAutomationNumber(kmStaleTotal, automationBriefLoaded),
days: formatAutomationNumber(kmStaleThreshold, automationBriefLoaded),
stale: formatAutomationNumber(kmStaleTotal, kmStaleCandidatesLoaded),
days: formatAutomationNumber(kmStaleThreshold, kmStaleCandidatesLoaded),
}),
href: `/${locale}/knowledge-base`,
tone: typeof kmStaleTotal === 'number' && kmStaleTotal > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching',
@@ -1416,16 +1430,16 @@ export default function Home({ params }: { params: { locale: string } }) {
nextAction: tDashboard('automationDiagrams.workspace.inspector.stages.verify.nextAction'),
liveEvidence: {
metric: tDashboard('automationDiagrams.workspace.liveEvidence.verify.metric', {
stale: formatAutomationNumber(kmBurndownSnapshot?.stale_count ?? kmStaleTotal, automationBriefLoaded),
stale: formatAutomationNumber(kmBurndownSnapshot?.stale_count ?? kmStaleTotal, kmOwnerReviewBurndownLoaded || kmStaleCandidatesLoaded),
ratio: staleRatioLabel,
}),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.verify.detail', {
pending: formatAutomationNumber(kmOwnerReviewBurndown?.pending_owner_reviews, automationBriefLoaded),
completed: formatAutomationNumber(kmOwnerReviewBurndown?.completed_owner_reviews, automationBriefLoaded),
remaining: formatAutomationNumber(kmOwnerReviewBurndown?.entries_to_threshold, automationBriefLoaded),
pending: formatAutomationNumber(kmOwnerReviewBurndown?.pending_owner_reviews, kmOwnerReviewBurndownLoaded),
completed: formatAutomationNumber(kmOwnerReviewBurndown?.completed_owner_reviews, kmOwnerReviewBurndownLoaded),
remaining: formatAutomationNumber(kmOwnerReviewBurndown?.entries_to_threshold, kmOwnerReviewBurndownLoaded),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.kmBurndown'),
updated: formatLiveEvidenceTime(kmOwnerReviewBurndown?.generated_at),
updated: formatLiveEvidenceTime(kmOwnerReviewBurndown?.generated_at, kmOwnerReviewBurndownLoaded),
},
},
]

View File

@@ -8,6 +8,7 @@ import { API_V1_URL } from '@/lib/config'
interface UseIncidentStatusChainsOptions {
incidentIds: string[]
limit?: number
concurrency?: number
projectId?: string
refreshKey?: string | number | Date | null
timeoutMs?: number
@@ -22,6 +23,7 @@ interface UseIncidentStatusChainsResult {
export function useIncidentStatusChains({
incidentIds,
limit = 25,
concurrency = 4,
projectId = 'awoooi',
refreshKey = null,
timeoutMs = 12000,
@@ -44,40 +46,63 @@ export function useIncidentStatusChains({
let active = true
const controller = new AbortController()
const timeout = window.setTimeout(() => controller.abort(), timeoutMs)
const requestConcurrency = Math.max(1, Math.min(concurrency, requestedIncidentIds.length))
let nextIndex = 0
let activeRequests = 0
let completedRequests = 0
setIsLoading(true)
setStatusChains(Object.fromEntries(requestedIncidentIds.map(incidentId => [incidentId, null])))
Promise.all(
requestedIncidentIds.map(async (incidentId): Promise<[string, AwoooPStatusChain | null]> => {
const params = new URLSearchParams({ project_id: projectId, incident_id: incidentId })
try {
const response = await fetch(`${API_V1_URL}/platform/status-chain?${params.toString()}`, {
cache: 'no-store',
signal: controller.signal,
})
if (!response.ok) return [incidentId, null]
return [incidentId, await response.json() as AwoooPStatusChain]
} catch {
return [incidentId, null]
}
})
)
.then(entries => {
if (active) setStatusChains(Object.fromEntries(entries))
})
.catch(() => {
if (active) setStatusChains({})
})
.finally(() => {
const fetchStatusChain = async (incidentId: string): Promise<AwoooPStatusChain | null> => {
const params = new URLSearchParams({ project_id: projectId, incident_id: incidentId })
try {
const response = await fetch(`${API_V1_URL}/platform/status-chain?${params.toString()}`, {
cache: 'no-store',
signal: controller.signal,
})
if (!response.ok) return null
return await response.json() as AwoooPStatusChain
} catch {
return null
}
}
const finish = () => {
completedRequests += 1
if (completedRequests >= requestedIncidentIds.length) {
window.clearTimeout(timeout)
if (active) setIsLoading(false)
})
}
}
const pump = () => {
if (!active) return
while (activeRequests < requestConcurrency && nextIndex < requestedIncidentIds.length) {
const incidentId = requestedIncidentIds[nextIndex]
nextIndex += 1
activeRequests += 1
fetchStatusChain(incidentId)
.then(statusChain => {
if (active) {
setStatusChains(previous => ({ ...previous, [incidentId]: statusChain }))
}
})
.finally(() => {
activeRequests -= 1
finish()
pump()
})
}
}
pump()
return () => {
active = false
window.clearTimeout(timeout)
controller.abort()
}
}, [incidentKey, projectId, requestedIncidentIds, refreshKey, timeoutMs])
}, [concurrency, incidentKey, projectId, requestedIncidentIds, refreshKey, timeoutMs])
return { statusChains, requestedIncidentIds, isLoading }
}