refresh visible charts without force refresh
This commit is contained in:
@@ -62,7 +62,7 @@ const PEAK_GLOW_BADGE_CLASS = {
|
||||
|
||||
const PROBABILITY_REFRESH_AFTER_PATCH_MS = DASHBOARD_REFRESH_POLICY_MS.metar;
|
||||
const FOREGROUND_FULL_DETAIL_REFRESH_DEDUP_MS = 90_000;
|
||||
const NO_PATCH_FULL_DETAIL_FALLBACK_MS = DASHBOARD_REFRESH_POLICY_MS.metar;
|
||||
const NO_PATCH_CACHED_DETAIL_REFRESH_MS = DASHBOARD_REFRESH_POLICY_MS.observation;
|
||||
const DETAIL_LOAD_BATCH_DELAY_MS = 0;
|
||||
const INITIAL_DETAIL_LOAD_SLOTS = 3;
|
||||
const DEFERRED_DETAIL_LOAD_DELAY_MS = 1_200;
|
||||
@@ -913,17 +913,17 @@ export function LiveTemperatureThresholdChart({
|
||||
};
|
||||
}, [resyncVersion, city, targetResolution, markDetailDegraded, markDetailRequest, applySuccessfulHourlyDetail]);
|
||||
|
||||
// ── SSE fallback: only full-fetch if a visible chart has seen no patch for one METAR cadence ──
|
||||
// ── SSE fallback: visible charts refresh cached detail at observation cadence if patches stop. ──
|
||||
useEffect(() => {
|
||||
if (!shouldPollLiveChart({ city, compact, isActive, isMaximized })) return;
|
||||
let cancelled = false;
|
||||
|
||||
const refreshFullDetail = () => {
|
||||
const refreshCachedDetail = () => {
|
||||
const now = Date.now();
|
||||
lastPatchAtRef.current = now;
|
||||
markDetailRequest("force_refresh");
|
||||
markDetailRequest("network");
|
||||
|
||||
fetchHourlyForecastForCity(city, { ignoreCache: true, resolution: targetResolution })
|
||||
fetchHourlyForecastForCity(city, { resolution: targetResolution })
|
||||
.then((data) => {
|
||||
if (cancelled) return;
|
||||
if (!data) {
|
||||
@@ -944,9 +944,9 @@ export function LiveTemperatureThresholdChart({
|
||||
|
||||
const checkFallback = () => {
|
||||
if (typeof document !== "undefined" && document.visibilityState === "hidden") return;
|
||||
if (Date.now() - lastPatchAtRef.current < NO_PATCH_FULL_DETAIL_FALLBACK_MS) return;
|
||||
if (Date.now() - lastPatchAtRef.current < NO_PATCH_CACHED_DETAIL_REFRESH_MS) return;
|
||||
|
||||
refreshFullDetail();
|
||||
refreshCachedDetail();
|
||||
};
|
||||
|
||||
const id = setInterval(checkFallback, 60_000);
|
||||
|
||||
@@ -74,7 +74,13 @@ export async function runTests() {
|
||||
chartSource.includes("latestPatch") &&
|
||||
chartSource.includes("DASHBOARD_REFRESH_POLICY_MS.metar") &&
|
||||
!chartSource.includes("2 * 60_000"),
|
||||
"selected city chart should consume SSE patches and use a METAR-cadence no-patch fallback instead of a 2-minute forced refresh",
|
||||
"selected city chart should consume SSE patches and keep METAR cadence for heavy probability refreshes instead of a 2-minute forced refresh",
|
||||
);
|
||||
assert(
|
||||
chartSource.includes("NO_PATCH_CACHED_DETAIL_REFRESH_MS = DASHBOARD_REFRESH_POLICY_MS.observation") &&
|
||||
chartSource.includes("refreshCachedDetail") &&
|
||||
chartSource.includes("fetchHourlyForecastForCity(city, { resolution: targetResolution })"),
|
||||
"visible charts should do a lightweight cached detail refresh every observation cadence when no SSE patch arrives",
|
||||
);
|
||||
assert(
|
||||
chartSource.includes("preloadTemperatureChartCanvas"),
|
||||
|
||||
@@ -194,7 +194,11 @@ export function runTests() {
|
||||
assert(
|
||||
chart.includes("DASHBOARD_REFRESH_POLICY_MS.metar") &&
|
||||
!chart.includes("2 * 60_000"),
|
||||
"temperature chart must wait one METAR cadence without patches before full-fetch fallback",
|
||||
"temperature chart must keep METAR cadence for heavy patch-triggered probability refreshes",
|
||||
);
|
||||
assert(
|
||||
chart.includes("NO_PATCH_CACHED_DETAIL_REFRESH_MS = DASHBOARD_REFRESH_POLICY_MS.observation"),
|
||||
"temperature chart must use observation cadence for lightweight cached no-patch refreshes",
|
||||
);
|
||||
assert(chart.includes("TemperatureChartCanvas"), "temperature chart shell must compose the extracted chart canvas");
|
||||
assert(chart.includes("TemperatureStatsBars"), "temperature chart shell must compose the extracted stat bars");
|
||||
@@ -225,10 +229,12 @@ export function runTests() {
|
||||
chart.includes("ignoreCache: true") && chart.includes("currentCityLocalDate !== loadedLocalDate"),
|
||||
"temperature chart must background-refresh full city detail when the city-local day rolls over",
|
||||
);
|
||||
const fallbackRefreshBlock = chart.match(/const refreshFullDetail = \(\) => \{[\s\S]*?\n \};/)?.[0] || "";
|
||||
const fallbackRefreshBlock = chart.match(/const refreshCachedDetail = \(\) => \{[\s\S]*?\n \};/)?.[0] || "";
|
||||
assert(
|
||||
!fallbackRefreshBlock.includes("setIsHourlyLoading(true)"),
|
||||
"no-patch fallback refresh should update the chart in the background without showing the loading overlay",
|
||||
fallbackRefreshBlock.includes("fetchHourlyForecastForCity(city, { resolution: targetResolution })") &&
|
||||
!fallbackRefreshBlock.includes("ignoreCache: true") &&
|
||||
!fallbackRefreshBlock.includes("setIsHourlyLoading(true)"),
|
||||
"no-patch fallback refresh should update the chart through cached batch detail without force-refreshing or showing the loading overlay",
|
||||
);
|
||||
const resyncBlock = chart.match(/useEffect\(\(\) => \{\s*if \(!resyncVersion \|\| !city\) return;[\s\S]*?\}, \[resyncVersion, city, targetResolution, applySuccessfulHourlyDetail\]\);/)?.[0] || "";
|
||||
assert(
|
||||
|
||||
Reference in New Issue
Block a user