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 | 51x 51x 51x 51x 2x 1470x 1470x 3221x 29265x 14826x 14826x 14826x 11753x 11753x 11753x 6294x 3221x 1821x 7x 16x 1400x 1400x 13x 10x 1470x 1470x 241x 241x 16x 10x 1480x 241x 2997x 6x 241x 10x 1470x 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
}
|