Skip to content

perf(map): skip /info round-trip on small viewports + optimistic revalidate#50

Draft
jsenecal wants to merge 1 commit into
mainfrom
feat/map-skip-info-zoom
Draft

perf(map): skip /info round-trip on small viewports + optimistic revalidate#50
jsenecal wants to merge 1 commit into
mainfrom
feat/map-skip-info-zoom

Conversation

@jsenecal

Copy link
Copy Markdown
Owner

Summary

  • Panning and zooming the infrastructure map no longer block on /info before the GeoJSON layers start loading.
  • At or above SKIP_INFO_ZOOM (default 17) /info is skipped entirely -- the viewport is too small to plausibly cross any hide/cluster threshold.
  • Below the threshold, the cached /info drives the immediate render and /info revalidates in the background with If-None-Match; a 304 leaves the screen untouched, a 200 reconciles only when the per-layer decision actually changes.
  • Configurable via PLUGINS_CONFIG['netbox_pathways']['map_skip_info_zoom'] for deployments with unusual feature density.

Changes

  • netbox_pathways/static/netbox_pathways/src/data-layers.ts: SKIP_INFO_ZOOM, decideSkipInfo, getLastInfo, _resetInfoCache; fetchMapInfo callback now (info, changed) so callers can skip re-render on 304.
  • netbox_pathways/static/netbox_pathways/src/load-strategy.ts (new): exposes chooseLoadStrategy, decisionsDiffer, re-exports decideSkipInfo. Pure dispatch over (zoom, cachedInfo, enabled) -> { below-min-zoom | skip-info | optimistic | gated }.
  • netbox_pathways/static/netbox_pathways/src/pathways-map.ts: _loadData() is now a dispatch over the strategy result; only the gated and optimistic paths touch /info.
  • netbox_pathways/static/netbox_pathways/src/types/netbox.d.ts: PathwaysConfig.skipInfoZoom?: number.
  • netbox_pathways/static/netbox_pathways/src/load-strategy.test.ts + src/fetch-info.test.ts (new): 15 vitest tests covering each strategy branch, decideSkipInfo, decisionsDiffer, and the (info, changed) callback contract.
  • netbox_pathways/views.py: both pathways_config builders (map + route planner) emit skipInfoZoom.
  • netbox_pathways/template_content.py: LeafletHeadExtension.head() also includes skipInfoZoom, so detail-page maps see the configured value.
  • Docs: CHANGELOG [Unreleased] -> Added, new "How the gating performs during panning" section in docs/user-guide/interactive-map.md.

Testing

  • vitest passes (217 passed, 15 new)
  • pytest passes (456 passed)
  • npm run build clean (new dist/load-strategy.min.js about 1.3 KB)
  • manage.py check clean
  • Browser-style smoke test: both window.PATHWAYS_CONFIG injection points (head + body) emit skipInfoZoom: 17; minified bundle contains the new name and no stale trustZoom / TRUST_ZOOM.

Notes

  • No schema change, no migration. Pure frontend perf + a couple of view-layer config plumbing tweaks.
  • Naming chosen for clarity (map_skip_info_zoom describes the mechanism). An earlier draft used map_trust_zoom which read like a security knob.

…lidate

Panning and zooming used to block on a fresh /info round-trip before the
GeoJSON layers could start loading. With ETag revalidation the gate
returns 304 on most pans, but the round-trip itself is what was making
the map feel laggy on slow links.

The frontend now uses a three-band strategy (load-strategy.ts):

  zoom < MIN_DATA_ZOOM (11): render nothing.

  MIN_DATA_ZOOM <= zoom < SKIP_INFO_ZOOM (default 17): if a recent /info
  is cached, render that decision immediately and revalidate in the
  background with If-None-Match. A 304 leaves the screen untouched; a
  200 reconciles only when the per-layer decision actually changes.
  First load with no cache still waits one round-trip.

  zoom >= SKIP_INFO_ZOOM: skip /info entirely. The viewport is too small
  to plausibly cross any hide/cluster threshold, so the gate is
  unhelpful.

Configurable via PLUGINS_CONFIG['netbox_pathways']['map_skip_info_zoom']
if a deployment has unusual feature density.

fetchMapInfo's callback now also signals whether the response was a 200
(fresh) or 304 (unchanged), so callers can skip the reconciliation
render in the common case. The pure decision logic is covered by vitest
(load-strategy.test.ts and fetch-info.test.ts, 15 new tests,
217/217 passing total).
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.40%. Comparing base (3db9c09) to head (2b64fd2).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #50   +/-   ##
=======================================
  Coverage   73.40%   73.40%           
=======================================
  Files          52       52           
  Lines        5189     5189           
=======================================
  Hits         3809     3809           
  Misses       1380     1380           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant