Pathbuilder import, frontend: by code, paste, file or sheet PDF (#958) #1363

Merged
claude-bot merged 4 commits from feat/958-pathbuilder-import-frontend into main 2026-11-07 02:31:03 +00:00
Collaborator

Frontend for the Pathbuilder import (#958, IS-429); the backend is #1361.

What it does

"Import from Pathbuilder…" opens one dialog with three ways in: Code (default; the browser fetches https://pathbuilder2e.com/json.php?id=<code>, 15 s timeout, digits-only check first), Paste or file (pasted JSON or a .json file), Character sheet PDF. A fetch that fails for any reason (network, CORS, challenge page, success:false) shows the link, switches to Paste and keeps the code as provenance. The preview saves nothing: name, class, level, what will happen (create / update / replace, the last behind a checkbox), Not read (always shown, with reasons), warnings, matched vs kept-as-text entries, numbers that differ from Pathbuilder's, and for update/replace the changes. Import saves with commit=1&expected_version=<previewed version>; a stale 409 hands the page the current sheet and previews again; 503 says busy with Try again; success closes the dialog and the sheet shows an "Imported from Pathbuilder" banner.

Entry points

  • A Pathfinder 2e character's sheet: More menu, after Export and Print (only for someone who can edit that sheet).
  • A player character's page with no sheet: a button beside Make a sheet (SheetPage.jsx, the no-sheet branch).

Where the drawing and the brief differ: the drawing (lane9.html pathbuilder()) shows only a paste box and a one-line summary; the code, PDF, report and confirm flow follow the brief. The server's warning about differing numbers is not repeated under Warnings, since "Numbers that differ" lists the same figures.

CSP

webapp/frontend/nginx.conf: connect-src 'self' becomes connect-src 'self' https://pathbuilder2e.com; nothing else changed. No test or e2e file asserts the header. docs/API.md said the origin must be allowed; its sentence now says it is. I built the frontend-prod image and ran it; curl -I returns
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; connect-src 'self' https://pathbuilder2e.com; font-src 'self'; frame-ancestors 'none'.

Wording for review

  • Import from Pathbuilder… (menu item, button); Import from Pathbuilder (dialog title); banner title "Imported from Pathbuilder"
  • Tabs: Code · Paste or file · Character sheet PDF
  • Pathbuilder code; hint: "In Pathbuilder: Menu, Export, Export JSON. It gives a code of six digits."
  • Paste the JSON · Or choose a .json file · Character sheet PDF; hint: "The PDF Pathbuilder fills in for the official Pathfinder 2e sheet."
  • Buttons: Read it · Cancel · Back · Import · Update the sheet · Replace the sheet · Dismiss
  • Fallback: "Couldn’t fetch it from Pathbuilder. Open this link, then paste what it shows."
  • Errors: "Enter the code as digits only, like 484225." · "Paste the JSON first." · "That isn't valid JSON. Paste all of it, from the first { to the last }." · "Choose the PDF first." · "Quest Board is busy reading other files. Try again in a moment." · other server messages shown as sent
  • Preview: "This page has no sheet yet. Importing makes it from this build." · "This sheet came from this Pathbuilder character. Importing updates it; the earlier state stays in its history." · "This page’s sheet didn’t come from this Pathbuilder character. Importing replaces what the build covers; the earlier state stays in the sheet’s history." · checkbox "Replace this page’s sheet" · disabled reason "Confirm replacing the sheet first."
  • Sections: Not read (n) · Warning / Warnings · Numbers that differ ("AC: Pathbuilder 23, Quest Board 21"; "Differences usually mean rules content Quest Board doesn’t have.") · What changes (n) ("Level: 5 → 6") · Feats, items and spells ("n matched to the loaded content, m kept as text.", "See all n") · "Read: n field(s)"
  • "The sheet changed while you were looking. This is what the import would change now."
  • Banner body: " is on this sheet now."
  • Screen-reader status: "Reading…"; "What you typed is not saved yet. Save it first, then import."

Checks (docker-test, committed code via git archive)

  • eslint: 0 errors (48 existing warnings, none in these files)
  • vitest: new ImportPathbuilder.test.jsx (28 tests) plus 2 new and 1 updated in SheetPage.test.jsx; full suite with --maxWorkers=3: 294 files, 5792 passed, 1 skipped
  • build suite: frontend-prod image built; CSP header checked as above
  • Render check on the seeded journeys stack (desktop project, canned Pathbuilder and import responses through Playwright routes, so the browser fetch went through the built CSP): dark and light at 1280 and 390; code, bad code, fallback, preview and the Read list open. The preview heading took focus, and neither the page nor the dialog overflowed sideways. Screenshots are not attached; someone should look at them.

Not covered: a real Pathbuilder fetch (their server was mocked), a real PDF upload through the stack, and the replace flow on the built stack (unit-tested only).

Also: CATALOGUE IS-429 row extended; changelog fragment changelog.d/958-pathbuilder-import-frontend.added.md.

🤖 Generated with Claude Code

Frontend for the Pathbuilder import (#958, IS-429); the backend is #1361. ## What it does "Import from Pathbuilder…" opens one dialog with three ways in: **Code** (default; the browser fetches `https://pathbuilder2e.com/json.php?id=<code>`, 15 s timeout, digits-only check first), **Paste or file** (pasted JSON or a .json file), **Character sheet PDF**. A fetch that fails for any reason (network, CORS, challenge page, `success:false`) shows the link, switches to Paste and keeps the code as provenance. The preview saves nothing: name, class, level, what will happen (create / update / replace, the last behind a checkbox), Not read (always shown, with reasons), warnings, matched vs kept-as-text entries, numbers that differ from Pathbuilder's, and for update/replace the changes. Import saves with `commit=1&expected_version=<previewed version>`; a stale 409 hands the page the current sheet and previews again; 503 says busy with Try again; success closes the dialog and the sheet shows an "Imported from Pathbuilder" banner. ## Entry points - A Pathfinder 2e character's sheet: **More** menu, after Export and Print (only for someone who can edit that sheet). - A player character's page with no sheet: a button beside **Make a sheet** (`SheetPage.jsx`, the no-sheet branch). Where the drawing and the brief differ: the drawing (lane9.html `pathbuilder()`) shows only a paste box and a one-line summary; the code, PDF, report and confirm flow follow the brief. The server's warning about differing numbers is not repeated under Warnings, since "Numbers that differ" lists the same figures. ## CSP `webapp/frontend/nginx.conf`: `connect-src 'self'` becomes `connect-src 'self' https://pathbuilder2e.com`; nothing else changed. No test or e2e file asserts the header. `docs/API.md` said the origin must be allowed; its sentence now says it is. I built the `frontend-prod` image and ran it; `curl -I` returns `Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; connect-src 'self' https://pathbuilder2e.com; font-src 'self'; frame-ancestors 'none'`. ## Wording for review - Import from Pathbuilder… (menu item, button); Import from Pathbuilder (dialog title); banner title "Imported from Pathbuilder" - Tabs: Code · Paste or file · Character sheet PDF - Pathbuilder code; hint: "In Pathbuilder: Menu, Export, Export JSON. It gives a code of six digits." - Paste the JSON · Or choose a .json file · Character sheet PDF; hint: "The PDF Pathbuilder fills in for the official Pathfinder 2e sheet." - Buttons: Read it · Cancel · Back · Import · Update the sheet · Replace the sheet · Dismiss - Fallback: "Couldn’t fetch it from Pathbuilder. Open this link, then paste what it shows." - Errors: "Enter the code as digits only, like 484225." · "Paste the JSON first." · "That isn't valid JSON. Paste all of it, from the first { to the last }." · "Choose the PDF first." · "Quest Board is busy reading other files. Try again in a moment." · other server messages shown as sent - Preview: "This page has no sheet yet. Importing makes it from this build." · "This sheet came from this Pathbuilder character. Importing updates it; the earlier state stays in its history." · "This page’s sheet didn’t come from this Pathbuilder character. Importing replaces what the build covers; the earlier state stays in the sheet’s history." · checkbox "Replace this page’s sheet" · disabled reason "Confirm replacing the sheet first." - Sections: Not read (n) · Warning / Warnings · Numbers that differ ("AC: Pathbuilder 23, Quest Board 21"; "Differences usually mean rules content Quest Board doesn’t have.") · What changes (n) ("Level: 5 → 6") · Feats, items and spells ("n matched to the loaded content, m kept as text.", "See all n") · "Read: n field(s)" - "The sheet changed while you were looking. This is what the import would change now." - Banner body: "<name> is on this sheet now." - Screen-reader status: "Reading…"; "What you typed is not saved yet. Save it first, then import." ## Checks (docker-test, committed code via git archive) - eslint: 0 errors (48 existing warnings, none in these files) - vitest: new `ImportPathbuilder.test.jsx` (28 tests) plus 2 new and 1 updated in `SheetPage.test.jsx`; full suite with `--maxWorkers=3`: 294 files, 5792 passed, 1 skipped - `build` suite: frontend-prod image built; CSP header checked as above - Render check on the seeded journeys stack (desktop project, canned Pathbuilder and import responses through Playwright routes, so the browser fetch went through the built CSP): dark and light at 1280 and 390; code, bad code, fallback, preview and the Read list open. The preview heading took focus, and neither the page nor the dialog overflowed sideways. Screenshots are not attached; someone should look at them. Not covered: a real Pathbuilder fetch (their server was mocked), a real PDF upload through the stack, and the replace flow on the built stack (unit-tested only). Also: CATALOGUE `IS-429` row extended; changelog fragment `changelog.d/958-pathbuilder-import-frontend.added.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(webapp): a dash before each not-read reason (#958)
Some checks failed
CI / Does this change touch the recording path? (pull_request) Successful in 18s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Bot/backend version sync (pull_request) Successful in 24s
CI / Which journeys does this change need? (pull_request) Successful in 20s
CI / Backend lint (ruff) (pull_request) Successful in 1m15s
CI / Feedback site tests (pull_request) Successful in 1m29s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 2m10s
CI / Docker image build (pull_request) Successful in 2m13s
CI / Bot tests and audit (pull_request) Successful in 3m29s
CI / End-to-end journeys (desktop) (pull_request) Has been cancelled
CI / Frontend (shard 1/2) (pull_request) Has been cancelled
CI / Frontend (shard 2/2) (pull_request) Has been cancelled
CI / End-to-end journeys (keyboard) (pull_request) Has been cancelled
CI / End-to-end journeys (phone) (pull_request) Has been cancelled
CI / Backend migration, tests, and audit (pull_request) Has been cancelled
19a36786ff
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(webapp): the import preview doesn't list a value that reads the same as a change (#958)
All checks were successful
CI / Does this change touch the recording path? (pull_request) Successful in 20s
CI / Docker image build (pull_request) Successful in 22s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Which journeys does this change need? (pull_request) Successful in 27s
CI / Bot/backend version sync (pull_request) Successful in 51s
CI / Backend lint (ruff) (pull_request) Successful in 58s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m9s
CI / Bot tests and audit (pull_request) Successful in 2m28s
CI / Feedback site tests (pull_request) Successful in 2m40s
CI / Frontend (shard 2/2) (pull_request) Successful in 9m42s
CI / Frontend (shard 1/2) (pull_request) Successful in 12m27s
CI / End-to-end journeys (phone) (pull_request) Successful in 14m43s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 15m37s
CI / End-to-end journeys (desktop) (pull_request) Successful in 20m53s
CI / Backend migration, tests, and audit (pull_request) Successful in 46m27s
7d036073ed
A value whose stored form differs but which shows the same (5 and "5",
None and "") appeared as "Rogue → Rogue". The Changes list now
compares what it prints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign in to join this conversation.
No description provided.