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 | 67x 67x 67x 67x 2x 2202x 2202x 5998x 63680x 31809x 31809x 31809x 26003x 26003x 26003x 11804x 5998x 2955x 7x 16x 3043x 3043x 13x 10x 2202x 2202x 371x 371x 16x 10x 2212x 371x 5686x 6x 371x 10x 2202x 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
}
|