Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 73x 73x 73x 73x 2x 2192x 2192x 6015x 63857x 31846x 31846x 31846x 26027x 26027x 26027x 11834x 6015x 2999x 7x 16x 3016x 3016x 13x 10x 2192x 2192x 374x 374x 16x 10x 2202x 374x 5697x 6x 374x 10x 2192x 7x 7x 5x 1x 5x 7x 5x 10x 5x 7x | /**
* @see frontend/docs/UX/layer-contracts/L1-data-layer.md §3.7
*
* Data-age -tarkistus non-SSE-näkymille. Palauttaa datan iän
* millisekunteina ja binäärin stale-tilan.
*
* Ikäkynnys = gcTime - retention_margin = 30 min - 5 min = 25 min
*
* Ei renderöi mitään — puhdas hook.
*/
import { useState, useEffect } from 'react'
import { useQueryClient } from '@tanstack/react-query'
import type { EntityPath } from './contracts'
import type { QueryParams } from '../interfaces'
import { normalizeFilters } from './mutationQueue'
const GC_TIME_MS = 30 * 60 * 1000
const RETENTION_MARGIN_MS = 5 * 60 * 1000
const AGE_THRESHOLD_MS = GC_TIME_MS - RETENTION_MARGIN_MS
const TICK_INTERVAL_MS = 60_000
expIort interface DataAgeResult {
ageMs: number
isStale: boolean
}
export function useDataAge(
entityPath: EntityPath,
normalizedParams?: QueryParams,
): DataAgeResult {
const queryClient = useQueryClient()
const normParams = normalizedParams ? normalizeFilters(normalizedParams) : null
function compute(): DataAgeResult {
const queries = queryClient
.getQueryCache()
.getAll()
.filter((q) => {
if (q.queryKey[0] !== entityPath) return false
Eif (!normParams) return true
const keyParams = q.queryKey[1] as QueryParams | undefined
if (!keyParams) return true
const normJson = JSON.stringify(normParams)
const keyJson = JSON.stringify(keyParams)
return normJson === keyJson
})
const timestamps = queries
.map((q) => q.state.dataUpdatedAt)
.filter((t): t is number => t > 0)
if (timestamps.length === 0) {
return { ageMs: Infinity, isStale: true }
}
const ageMs = Date.now() - Math.max(...timestamps)
return { ageMs, isStale: ageMs > AGE_THRESHOLD_MS }
}
const [result, setResult] = useState<DataAgeResult>(compute)
useEffect(() => {
const id = setInterval(() => {
setResult(compute())
}, TICK_INTERVAL_MS)
return () => clearInterval(id)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [entityPath, normalizedParams])
useEffect(() => {
const unsubscribe = queryClient.getQueryCache().subscribe(() => {
setResult(compute())
})
return unsubscribe
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [entityPath, normalizedParams])
return result
}
|