fix(explorer): gate temporal requests on graph load (#1003)

Explorer was firing temporal requests before the graph even loaded.

When the backend is down, /api/graph/nodes fails but the temporal
bounds and snapshot effects didn't care , they fired anyway, off in
their own corner, ignoring whether the graph actually came up. Every
page load with no backend meant three failed requests instead of one,
and a scrubber that had nothing to scrub.

Added two small predicate functions and gated the temporal effects on
them. Basically: don't ask for time-based data until you know the
graph itself loaded. An empty graph still counts as loaded, so that
case isn't broken.

Confirmed with the backend down, before and after: three failing
requests down to one.

Fixes #982.
This commit is contained in:
Lakshay Saini
2026-08-15 17:47:35 +05:00
committed by GitHub
parent 8639cb9f16
commit 115e7965cd
4 changed files with 175 additions and 4 deletions
@@ -40,6 +40,7 @@ import {
type GraphPluginToolbarItem,
} from "./plugins";
import { explorationEffectsShouldLoad, neighborhoodPanelShouldLoad, temporalOverlayShouldLoad } from "./pluginRegistryPredicates";
import { shouldFetchTemporalBounds, shouldFetchTemporalSnapshot } from "./temporalLifecyclePredicates";
import type { LinkPrediction, PathResponse } from "./GraphInspectorPanel";
import type { GraphSceneHandle, GraphSceneRuntime } from "./scene";
import type {
@@ -1440,7 +1441,18 @@ export function GraphWorkspace({ externalFocusNodeId, externalFocusToken }: Grap
applyGraphReadySummary(summary);
}, [applyGraphReadySummary, graphReady, summary]);
const canFetchTemporalBounds = shouldFetchTemporalBounds(summary);
const canFetchTemporalSnapshot = shouldFetchTemporalSnapshot({
debouncedTime,
isLoading,
summary,
});
useEffect(() => {
if (!canFetchTemporalBounds) {
return;
}
let cancelled = false;
const loadBounds = async () => {
try {
@@ -1460,10 +1472,21 @@ export function GraphWorkspace({ externalFocusNodeId, externalFocusToken }: Grap
return () => {
cancelled = true;
};
}, [summary?.nodeCount, summary?.edgeCount]);
}, [
canFetchTemporalBounds,
summary?.nodeCount,
summary?.edgeCount,
]);
useEffect(() => {
if (!debouncedTime || isLoading) return;
if (!canFetchTemporalSnapshot) {
return;
}
if (!debouncedTime) {
return;
}
let cancelled = false;
const applySnapshot = async () => {
@@ -1505,7 +1528,10 @@ export function GraphWorkspace({ externalFocusNodeId, externalFocusToken }: Grap
return () => {
cancelled = true;
};
}, [debouncedTime, isLoading]);
}, [
canFetchTemporalSnapshot,
debouncedTime,
]);
const resolveNodeIdForFocusedMode = useCallback((
nodeId: string,