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 | 63x 63x 63x 63x 2x 2092x 2092x 5694x 56956x 30438x 30438x 30438x 24912x 24912x 24912x 11220x 5694x 2730x 7x 16x 2964x 2964x 13x 10x 2092x 2092x 347x 347x 16x 10x 2102x 347x 5406x 6x 347x 10x 2092x 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
}
|