111 lines
3.4 KiB
TypeScript
111 lines
3.4 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useMemo, useState } from 'react'
|
|
|
|
import type { AwoooPStatusChain } from '@/components/awooop/status-chain'
|
|
import { API_V1_URL } from '@/lib/config'
|
|
|
|
interface UseIncidentStatusChainsOptions {
|
|
incidentIds: string[]
|
|
limit?: number
|
|
concurrency?: number
|
|
projectId?: string
|
|
refreshKey?: string | number | Date | null
|
|
timeoutMs?: number
|
|
}
|
|
|
|
interface UseIncidentStatusChainsResult {
|
|
statusChains: Record<string, AwoooPStatusChain | null>
|
|
requestedIncidentIds: string[]
|
|
isLoading: boolean
|
|
}
|
|
|
|
export function useIncidentStatusChains({
|
|
incidentIds,
|
|
limit = 25,
|
|
concurrency = 4,
|
|
projectId = 'awoooi',
|
|
refreshKey = null,
|
|
timeoutMs = 12000,
|
|
}: UseIncidentStatusChainsOptions): UseIncidentStatusChainsResult {
|
|
const incidentIdsKey = incidentIds.filter(Boolean).join('|')
|
|
const requestedIncidentIds = useMemo(() => {
|
|
return Array.from(new Set(incidentIdsKey ? incidentIdsKey.split('|') : [])).slice(0, limit)
|
|
}, [incidentIdsKey, limit])
|
|
const incidentKey = requestedIncidentIds.join('|')
|
|
const [statusChains, setStatusChains] = useState<Record<string, AwoooPStatusChain | null>>({})
|
|
const [isLoading, setIsLoading] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (requestedIncidentIds.length === 0) {
|
|
setStatusChains({})
|
|
setIsLoading(false)
|
|
return
|
|
}
|
|
|
|
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])))
|
|
|
|
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()
|
|
}
|
|
}, [concurrency, incidentKey, projectId, requestedIncidentIds, refreshKey, timeoutMs])
|
|
|
|
return { statusChains, requestedIncidentIds, isLoading }
|
|
}
|
|
|
|
export type { UseIncidentStatusChainsOptions, UseIncidentStatusChainsResult }
|