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 | 37x 37x 37x 37x 3x 920x 920x 2089x 17877x 11158x 11158x 11158x 9161x 9161x 9161x 4086x 2089x 1345x 11x 20x 744x 744x 13x 10x 920x 920x 149x 149x 20x 10x 930x 149x 1953x 10x 149x 10x 920x 11x 11x 9x 1x 9x 11x 9x 10x 9x 11x | /**
* @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
}
|