Skip to content

Map: latest Next.js and dependencies, working controls, green CI, Cloudflare Pages deploy - #25

Merged
kevinelliott merged 2 commits into
mainfrom
claude/project-thread-xlxhmp
Nov 14, 2026
Merged

kevinelliott merged 2 commits into
mainfrom
claude/project-thread-xlxhmp

Conversation

@kevinelliott

@kevinelliott kevinelliott commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Kevin · project thread

Summary

The map was already on Next.js (16.2.1), so this brings it up to date rather than migrating it, makes the dead controls work, gets Map CI green, and adds a Cloudflare Pages deploy. service/ is untouched here and is being handled in a separate PR.

Dependencies

Package Before After
next / eslint-config-next 16.2.1 16.4.6
react / react-dom 19.2.4 19.3.1
@deck.gl/* 9.2.11 9.4.1
maplibre-gl 5.21.1 5.24.1
tailwindcss / @tailwindcss/postcss 4.2.2 4.3.5
eslint 9.39 10.15
typescript 5.9 6.0.3
zustand, h3-js, react-map-gl, @base-ui/react, lucide-react, geist, tailwind-merge latest
Node (CI and Docker) 22 24

Three things are deliberately not on the newest major:

  • maplibre-gl stays on 5.x. I tried 6.18 and the map crashes: deck.gl 9.4's MapboxOverlay reads map.transform, which MapLibre 6 removed. npm audit flags a critical advisory on maplibre-gl <= 6.4.0 (XSS sanitizer bypass in DOM.sanitize). The map sets attributionControl={false} and only loads CARTO styles, so I do not believe that path is reachable here, but I have not proven it. Dependabot will keep proposing 6.x so it can be taken once deck.gl supports it.
  • TypeScript is 6.0, not 7.0, because typescript-eslint only supports < 6.1.
  • shadcn (a CLI, only needed for its CSS at build time) moved to devDependencies. Its new version no longer pulls in hono, express-rate-limit, qs or js-yaml.

Dependabot PRs superseded

All eight open /map PRs are covered by the regenerated lockfile and can be closed once this merges: #2, #8, #9, #12, #13, #14, #20, #23. The targets are either met (next 16.4.6, fast-uri 3.1.9, protocol-buffers-schema 3.6.1, ip-address 10.7.6) or the package is no longer in the tree (hono, @hono/node-server, express-rate-limit, qs, js-yaml). The /service ones (#1, #19, #21, #22) belong to the service PR.

A new .github/dependabot.yml groups future updates (map, service, GitHub Actions, Docker) so they arrive as a few weekly PRs instead of one per transitive package.

CI

Map CI was failing in the lint job with 4 errors (Date.now() called during render in StatsBar, three anys in CoverageMap). Those are fixed and the 5 warnings are gone too. The workflow now also runs tsc, builds both outputs, and triggers on changes to the workflow file itself.

Local results on this branch:

npm run lint         clean (0 errors, 0 warnings)
npm run typecheck    clean
npm run build        ok (standalone)
npm run build:static ok (out/index.html)

Not verified locally: the Docker build and Node 24 (the sandbox has Node 22 and no Docker). CI on this PR covers both.

Controls that now work

  • ? toolbar button was an empty handler. It now opens the shortcuts dialog (which also closes on backdrop click and Escape).
  • GeoJSON export only contained station points. It now exports what is on the map: H3 cells in hex mode or station coverage polygons in polygon mode, plus stations, with metadata.
  • Source colors were looked up in a transport-keyed table, so stations, the ticker and popups mostly fell back to grey or green. There is now one palette (sourceColor) shared by the legend, markers, lists and popups.
  • "Updated Ns ago" was frozen between refreshes. It ticks every second.
  • NEXT_PUBLIC_MAP_STYLE_URL was documented but ignored. It now sets the default basemap.
  • Escape closes hex and polygon popups, signal levels are rounded, and the time slider labels no longer wrap.
  • Geist is loaded from the geist package instead of Google Fonts, so builds need no network and the font variables actually apply.

Cloudflare Pages

The app is entirely client-rendered, so it deploys as a static export (npm run build:static writes map/out) with wrangler pages deploy. No adapter or Worker is needed. npm run build still produces the standalone server for the Docker image.

.github/workflows/deploy-map.yml deploys production on push to main and a preview on pull requests. It needs:

  • secret CLOUDFLARE_API_TOKEN (Account > Cloudflare Pages > Edit)
  • secret CLOUDFLARE_ACCOUNT_ID
  • optional variable CLOUDFLARE_PAGES_PROJECT (defaults to airframes-coverage; the Pages project must exist)

Until the secrets exist the deploy step is skipped with a warning, so this PR's checks do not fail on it. The deploy itself is therefore untested.

Screenshots

Taken from the static export of this branch in headless Chromium. The sandbox cannot reach coverage-api.airframes.io or the CARTO basemap, so the API responses are generated sample data and the basemap is a plain Natural Earth outline. Station names and numbers are not real.

Hex grid
Hex grid

Help dialog from the ? button
Help

Polygons
Polygons

Station search, fly-to and detail
Station detail

Marine filter
Marine filter

3D pitch with the Light style
3D light

Fullscreen
Fullscreen

The same run downloaded both exports and checked their contents: hex mode gave 11,627 cell polygons plus 36 station points, polygon mode gave 36 coverage polygons plus 36 station points. No console or page errors.

Follow-ups not in this PR

  • NEXT_PUBLIC_WS_URL is still unused; the map polls every 10 seconds and the service has no WebSocket endpoint.
  • Polygon mode fetches one request per station on every refresh.
  • src/components/ui/* (shadcn components) are not used by any screen.

Generated by Claude Code


Note

Medium Risk
Touches production deploy paths, Node 24, and major frontend dependency bumps; Cloudflare deploy is new and untested without repository secrets.

Overview
Upgrades the map stack (Next 16.4.6, React 19.3.1, deck.gl 9.4.1, Node 24 in CI/Docker) and adds Dependabot grouping for map/, service/, Actions, and Docker.

CI & deploy: Map CI now lints, typechecks, builds standalone (Docker) and static export, and verifies out/index.html. A new deploy-map.yml workflow publishes the static build to Cloudflare Pages (production on main, previews on same-repo PRs), skipping deploy when Cloudflare secrets are missing.

Build model: next.config.ts switches between standalone and export via NEXT_OUTPUT=export (npm run build:static); images are unoptimized for static hosting. public/_headers sets cache/security headers for Pages.

Map UX & quality: Fixes previously broken or partial controls—? help is wired through the UI store; GeoJSON export uses buildCoverageGeoJSON for hex/polygon mode plus stations; sourceColor / sourceLabel unify legends, markers, and popups; “updated Ns ago” ticks every second; NEXT_PUBLIC_MAP_STYLE_URL drives the default basemap; Geist loads from the geist package (no Google Fonts). Lint/type issues in CoverageMap and StatsBar are addressed.

Reviewed by Cursor Bugbot for commit 6752045. Bugbot is set up for automated code reviews on this repo. Configure here.

…eploy

- Upgrade map to Next.js 16.4, React 19.3, deck.gl 9.4, Tailwind 4.3,
  ESLint 10, TypeScript 6 and latest of everything else; shadcn CLI moves
  to devDependencies. maplibre-gl stays on latest 5.x because deck.gl 9.4
  does not support maplibre-gl 6 yet.
- Fix the lint errors that were failing Map CI (impure Date.now in render,
  explicit any) and clear all warnings.
- Wire up the toolbar help button, export hex cells and station polygons
  in the GeoJSON export, use one source-type palette everywhere, keep the
  'updated' timer ticking, honor NEXT_PUBLIC_MAP_STYLE_URL, close popups
  on Escape, and format signal levels.
- Load Geist from the geist package instead of Google Fonts at build time.
- Add a static export build and a Cloudflare Pages deploy workflow.
- Add Dependabot config for map, service, actions and Docker.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PS44Q7WRmAzMJLhi44dzdo
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 40 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: da11b799-9937-4a20-9f61-c49d04426d60
Commits

Reviewing files that changed from the base of the PR and between a72027a and 6752045.

Files ignored due to path filters: 8

  • docs/screenshots/01-hexgrid.png is excluded by !**/*.png
  • docs/screenshots/02-help-button.png is excluded by !**/*.png
  • docs/screenshots/03-polygons.png is excluded by !**/*.png
  • docs/screenshots/04-station-detail.png is excluded by !**/*.png
  • docs/screenshots/05-marine-filter.png is excluded by !**/*.png
  • docs/screenshots/06-3d-light-style.png is excluded by !**/*.png
  • docs/screenshots/07-fullscreen.png is excluded by !**/*.png
  • map/package-lock.json is excluded by !**/package-lock.json
Files selected for processing: 31

  • .github/dependabot.yml
  • .github/workflows/deploy-map.yml
  • .github/workflows/map.yml
  • README.md
  • map/.dockerignore
  • map/.nvmrc
  • map/CLAUDE.md
  • map/Dockerfile
  • map/README.md
  • map/next.config.ts
  • map/package.json
  • map/public/_headers
  • map/src/app/globals.css
  • map/src/app/layout.tsx
  • map/src/components/controls/ActivityTicker.tsx
  • map/src/components/controls/ControlPanel.tsx
  • map/src/components/controls/KeyboardHelp.tsx
  • map/src/components/controls/SourceLegend.tsx
  • map/src/components/controls/StatsBar.tsx
  • map/src/components/controls/TopStations.tsx
  • map/src/components/map/CoverageMap.tsx
  • map/src/components/map/HexPopup.tsx
  • map/src/components/map/PolygonPopup.tsx
  • map/src/components/map/layers/station-markers-layer.ts
  • map/src/components/station/StationPopup.tsx
  • map/src/lib/constants/colors.ts
  • map/src/lib/constants/map-styles.ts
  • map/src/lib/constants/time-windows.ts
  • map/src/lib/export-geojson.ts
  • map/src/lib/stores/coverage-store.ts
  • map/src/lib/stores/ui-store.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@kevinelliott kevinelliott self-assigned this Nov 14, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fe21be5. Configure here.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Left a non-blocking comment. Cursor Bugbot reported one unresolved finding, so this automation is not approving. Human review is needed and no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Cursor Bugbot completed successfully with no unresolved findings on the current head, so this automation is approving.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@kevinelliott
kevinelliott merged commit 8317248 into main Nov 14, 2026
9 checks passed
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.

2 participants