Skip to content

dotbot/console-web: open the site editor as a console panel - #330

Open
geonnave wants to merge 77 commits into
DotBots:mainfrom
geonnave:site-editor-p5
Open

geonnave wants to merge 77 commits into
DotBots:mainfrom
geonnave:site-editor-p5

Conversation

@geonnave

@geonnave geonnave commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #329 (objects), on #328, #327, #326, #315 and the LH2 stack to #343. Merges after them; until then the diff also carries their commits.

The site editor, until now a page of its own behind dotbot site edit, can also be opened inside the console, on the controller's own site, and a save shows on the live map without restarting the controller.

  • Controller: /controller/site-editor/ serves the editor's JSON routes over the controller's site pack (no page; the console carries the component). It answers only when the site was read from a pack, else 404, and only requests from this machine's own browser, with the same guard as site edit: the peer address must be loopback, whatever Host says, and a request whose Origin or Sec-Fetch-Site names another site gets a 403. The controller's API allows any origin over CORS, so without that check any web page open in the operator's browser could read and save the pack. A save that wrote the file reloads the site from the pack on the controller's loop, publishes it as a site stream event, and hands the walls, obstacles and chargers to a running simulator, robots where they are; the calibration session takes the new site too. A pack that no longer reads leaves the site as it was, with a warning, and an anchor or extent that no longer matches the loaded calibration is logged.
  • Console: Layers, Areas shows Edit site when the controller's routes answer, and it opens the editor full screen in the console's theme, with Close in place of Done. The map takes the site event, so every open console redraws. The component is loaded lazily, so the console's first load does not carry it.
  • The editor component takes a base for its routes and an onClose, and is otherwise the same as the standalone page.

Also: an existing proxy test made its own pytest.MonkeyPatch() and never undid it, which left httpx.AsyncClient mocked for every later test in the run; it now uses the fixture.

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

While the editor is open over the console, the console's own keys (G, R, the panel keys, its undo of a queued waypoint, Enter confirming a fleet action) stay off; only the stop key stays live. Camera stills load from the controller's routes.

Validation. pytest, against the real controller and simulator on a stepped clock: the panel loads the controller's pack and a save of a wall reaches /controller/site, the site event and the simulator; a robot driven at a wall drawn while it runs stops at it; another host is refused; a site without a pack has no panel. vitest: the embedded editor talks only to the controller's routes and Close does not stop a server; Edit site is offered only when the routes answer. npm run lint, typecheck and build; pre-commit run --all-files; full pytest 1850 passed, vitest 878 passed; also a remote peer refused whatever its Host, a cross-origin save refused through the console's CORS, the calibration session taking the reloaded site, a pack that no longer reads keeping the site, barriers swapped mid-tick.

By hand, headless: dotbot run simulator --site c405-arena on a copy of a real pack; the routes answer 200 on 127.0.0.1 and 403 for another Host header or another site's Origin; in headless Chrome, Layers, Edit site opens the editor, dev-corner is narrowed to 500 mm and a wall drawn, Save and Close, and the map draws the wall at once while /controller/site serves both changes and the file holds them.

+ - Files
#315, the LH2 stack to #343, #326, #327, #328 and #329, carried underneath (merge separately) +11986 -409 97
This PR, tests +290 -1 5
This PR, source +245 -50 10
This PR's files + -
dotbot/tests/test_site_editor_panel.py +176 -0
dotbot/console-web/src/editSiteButton.test.tsx +55 -0
dotbot/console-web/src/siteEditor/SiteEditor.tsx +34 -17
dotbot/controller.py +47 -0
dotbot/server.py +44 -0
dotbot/console-web/src/App.tsx +33 -10
dotbot/console-web/src/siteEditor/api.ts +23 -17
dotbot/console-web/src/siteEditor/siteEditor.test.tsx +38 -0
7 small files: RightPane.tsx, siteEditorPanel.test.ts, dotbot/dotbot_simulator.py, siteEditorPanel.ts, dotbot/site_editor.py, useFleet.ts, test_server.py +85 -7
Total, 15 files +535 -51

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.09040% with 252 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.46%. Comparing base (ddc43f7) to head (d988689).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
dotbot/console-web/src/siteEditor/Canvas.tsx 83.28% 107 Missing ⚠️
dotbot/console-web/src/siteEditor/SiteEditor.tsx 87.79% 78 Missing ⚠️
dotbot/console-web/src/siteEditor/api.ts 84.21% 15 Missing ⚠️
dotbot/console-web/src/siteEditor/main.tsx 0.00% 8 Missing and 1 partial ⚠️
dotbot/console-web/src/App.tsx 74.07% 7 Missing ⚠️
dotbot/console-web/src/siteEditor/Inspector.tsx 98.45% 7 Missing ⚠️
dotbot/console-web/src/siteEditor/edit.ts 96.58% 7 Missing ⚠️
dotbot/cli/swarm_lh2.py 91.80% 5 Missing ⚠️
dotbot/tests/lh2_multi_fixture.py 94.80% 4 Missing ⚠️
dotbot/console-web/dev/fake_swarmit_server.py 0.00% 3 Missing ⚠️
... and 6 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #330      +/-   ##
==========================================
+ Coverage   88.21%   88.46%   +0.25%     
==========================================
  Files         227      241      +14     
  Lines       36147    39201    +3054     
  Branches     2324     2895     +571     
==========================================
+ Hits        31886    34681    +2795     
- Misses       4257     4515     +258     
- Partials        4        5       +1     
Flag Coverage Δ
console 83.49% <90.46%> (+1.49%) ⬆️

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.63% <100.00%> (+0.09%) ⬆️
dotbot/console-web/src/RightPane.tsx 97.39% <100.00%> (+0.08%) ⬆️
dotbot/console-web/src/botFacts.ts 98.10% <100.00%> (+0.66%) ⬆️
... and 51 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
AI-assisted: Claude Opus 5.5
…leave omitted tables

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