Skip to content

dotbot/console-web: add undo, arrow nudges and backdrops to the site editor - #327

Open
geonnave wants to merge 55 commits into
DotBots:mainfrom
geonnave:site-editor-p2
Open

geonnave wants to merge 55 commits into
DotBots:mainfrom
geonnave:site-editor-p2

Conversation

@geonnave

@geonnave geonnave commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #326 (calibration placement), which sits on #315 (the site editor) and #343 (the top of the LH2 multi-station stack). Merges after them; until then the diff also carries their commits.

Comfort for the site editor, no file format change:

  • Undo and redo (Ctrl+Z, Ctrl+Shift+Z or Ctrl+Y, and toolbar buttons) over the site model. Consecutive edits sharing a key coalesce into one step: one drag on the canvas, or typing into one field, undoes as one. A save or a reload starts a fresh history, because after a save the file's names are the areas' origins and older steps would no longer match the file. Keys typed into a field are left to the field's own undo.
  • Arrow-key nudges for the selected area (and, with the Calibration tool, the placed calibration): one snap step, Alt one millimetre, Shift ten steps. A run of nudges undoes as one step.
  • Backdrops, read-only and only offered when the site has the files: each LH2 calibration of the site drawn where it was fitted (its placements' hull, or its spin centres for a spin calibration), and each registered camera's still warped onto its area. They are switched on per file in a Backdrops section and never change site.toml. The still is the .jpg that camera-calibrate collect saves beside a registration, warped server side with OpenCV at 5 mm per pixel; without OpenCV or the image, the camera is listed with "no still saved" and nothing is drawn.

Routes: GET /api/backdrops (the site's calibrations and cameras, from the pack's calibrations/ and ~/.dotbot/calibrations/<site>/), GET /api/backdrops/camera/{id8}.png.

Not done: editing an inline [sites.<name>] table, which this phase was planned to include. Inline site tables are gone from the config (sites are packs only), so there is nothing to edit.

Plan: rendered copy https://claude.ai/artifact/LHUXjhx1nMWifC2oGRBayt, source https://github.com/DotBots/dotbot-workspace/blob/main/plans/site-editor/plan.html (both internal).

A calibration or camera file that cannot be read, or a calibration made against another anchor (a free-mode one before it is placed, or one from before an anchor change), is skipped rather than turning the whole listing into a 500 or being drawn in the wrong frame. A camera whose homography is not 3 x 3, or a machine without OpenCV, gets no still. Stills are capped at 4096 px on their long side and their URL carries the image's mtime and the area's rectangle, so the browser fetches a new one when either moves; the listing is read again after every save and reload. A new selection starts a new undo step, an undo that puts another area at the selected index drops the selection, and shortcuts work while a checkbox holds the focus.

Validation. pytest: no backdrop for a site without files; a spin calibration of the site served by its centres; a synthetic camera registration with its still warped onto dev-corner as a 200 x 200 PNG, and a 404 for an unknown camera. vitest: the history (steps, coalescing, the dropped redo branch, the limit), undo and redo of a field edit from the buttons and the keys, nudges by a step, a millimetre and ten steps undone as one, a backdrop offered only when present and drawn when ticked. npm run lint, typecheck and build; pre-commit run --all-files; full pytest 1806 passed, vitest 862 passed; also unreadable and other-frame files skipped, the still's content checked rather than its size, a capped still, a still URL changing with its area, two selections' nudges undone as two steps, keys in a field left to it. By hand, headless, against a copy of a real 2 x 4 m pack with a corner calibration and a camera registration beside it: both backdrops drawn when ticked (the still lands on its area with the markers where they belong), dev-corner nudged and the nudge undone with Ctrl+Z, in both themes.

+ - Files
#315, the LH2 stack to #343, and #326, carried underneath (merge separately) +9143 -390 85
This PR, tests +329 -0 3
This PR, source +506 -26 8
This PR's files + -
dotbot/site_backdrops.py +200 -0
dotbot/tests/test_site_backdrops.py +161 -0
dotbot/console-web/src/siteEditor/SiteEditor.tsx +129 -13
dotbot/console-web/src/siteEditor/siteEditor.test.tsx +122 -0
dotbot/console-web/src/siteEditor/Canvas.tsx +51 -4
dotbot/console-web/src/siteEditor/Inspector.tsx +40 -6
dotbot/console-web/src/siteEditor/history.test.ts +46 -0
dotbot/console-web/src/siteEditor/history.ts +41 -0
3 small files: types.ts, dotbot/site_editor.py, api.ts +45 -3
Total, 11 files +835 -26

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.87675% with 203 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.39%. Comparing base (ddc43f7) to head (84ad3e1).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
dotbot/console-web/src/siteEditor/Canvas.tsx 82.25% 82 Missing ⚠️
dotbot/console-web/src/siteEditor/SiteEditor.tsx 88.23% 62 Missing ⚠️
dotbot/console-web/src/siteEditor/api.ts 81.48% 15 Missing ⚠️
dotbot/console-web/src/siteEditor/Inspector.tsx 96.04% 10 Missing ⚠️
dotbot/console-web/src/siteEditor/main.tsx 0.00% 8 Missing and 1 partial ⚠️
dotbot/cli/swarm_lh2.py 91.80% 5 Missing ⚠️
dotbot/console-web/src/siteEditor/edit.ts 96.59% 5 Missing ⚠️
dotbot/tests/lh2_multi_fixture.py 94.80% 4 Missing ⚠️
dotbot/console-web/dev/fake_swarmit_server.py 0.00% 3 Missing ⚠️
...ot/console-web/src/siteEditor/CalibrationPanel.tsx 97.76% 3 Missing ⚠️
... and 4 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #327      +/-   ##
==========================================
+ Coverage   88.21%   88.39%   +0.18%     
==========================================
  Files         227      239      +12     
  Lines       36147    38534    +2387     
  Branches     2324     2732     +408     
==========================================
+ Hits        31886    34061    +2175     
- Misses       4257     4468     +211     
- Partials        4        5       +1     
Flag Coverage Δ
console 83.02% <89.54%> (+1.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dotbot/cli/main.py 95.83% <ø> (ø)
dotbot/cli/site_cmd.py 91.54% <ø> (-0.04%) ⬇️
dotbot/config.py 98.59% <ø> (-0.29%) ⬇️
dotbot/console-web/src/BotMarker.tsx 100.00% <100.00%> (ø)
dotbot/console-web/src/GridView.tsx 88.20% <100.00%> (-0.22%) ⬇️
dotbot/console-web/src/ListView.tsx 88.78% <100.00%> (+0.64%) ⬆️
dotbot/console-web/src/LocalizationPanel.tsx 86.09% <100.00%> (ø)
dotbot/console-web/src/MapView.tsx 97.54% <100.00%> (+<0.01%) ⬆️
dotbot/console-web/src/botFacts.ts 98.10% <100.00%> (+0.66%) ⬆️
dotbot/console-web/src/heldWaypoints.ts 100.00% <100.00%> (ø)
... and 43 more

... and 3 files with indirect coverage changes

🚀 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.

AI-assisted: Claude Opus 5.5
AI-assisted: Claude Opus 5.5
… page

Any web page in the browser can send requests to 127.0.0.1 with a valid
Host header, and behind a permissive CORS policy read the replies, so the
Host check alone let it save site.toml; a server bound beyond loopback
took any Host. The peer address, Origin and Sec-Fetch-Site are checked.

AI-assisted: Claude Opus 5.5
…ng tables

A patched file is read back and must give the model that was sent, so a
layout the patcher does not follow is refused rather than written.

AI-assisted: Claude Opus 5.5
Breaking: schema 3 calibration files are refused, so a calibration is
collected again. swarmit's own calibration reader still expects schema 3
and needs its matching change before the dashboard reads these files.

AI-assisted: Claude Opus 5.5
…tangle

Breaking, cross-repo: the messages and the config page (magic SWRP, 872
bytes) only match a swarmit bootloader and net core that store stations
by mask, and swarmit's Python must accept mask messages before it relays
them. Robots below device info 4 are refused with a reflash.

AI-assisted: Claude Opus 5.5
Breaking wire change, landing with DotBot-libs' 16-bit calibrated field:
every advertisement field after the mask moves by one byte and the
vendored dotbot_control.wasm is rebuilt at ABI 3 from that change. With
the one-byte mask, a calibration naming station 8 or above read every
sandbox robot as missing it and resent homographies on each advert.

AI-assisted: Claude Opus 5.5
…angles

A station that never sees part of the site yields no sweep pair there,
so the extent drops nothing a station could solve, whereas the box around
its spins dropped areas such as a staging strip the robots never spun in.

AI-assisted: Claude Opus 5.5
A robot with no heading first gets a 40 mm probe move toward its first
point, and its batch once it has a heading and the probe is done. While
waypoints_awaiting_heading is set, the waypoint report and the mode are
the probe's, so a client watching mode alone sees an early arrival.

AI-assisted: Claude Opus 5.5
… a file

A placement's id comes from its stations, not its tag or anchor, so the
same move saved twice, or a move into the source's own site, landed on an
existing path; save_placed keeps that file and refuses the source's id.

AI-assisted: Claude Opus 5.5

This branch has not been deployed

No deployments
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