Skip to content

FE-1659: Give local Petrinaut documents UUID URLs and copy examples - #9661

Open
kube wants to merge 3 commits into
mainfrom
codex/fe-1659-local-document-urls
Open

kube wants to merge 3 commits into
mainfrom
codex/fe-1659-local-document-urls

Conversation

@kube

@kube kube commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Before this PR, the website editor opened at / with no document in the URL. Reloads, bookmarks and Back returned to whichever net was edited last. Published examples could not be edited.

Each saved net now opens at /local/<net id>, so bookmarks, reloads and browser history reopen the same net. / and /new redirect there. Published examples offer Make a local copy, which saves an editable copy and opens it at its own URL.

9661.mp4

Links

Changes

Routes

  • /local/$netId opens a saved net

    Net ids are lowercase UUIDs already, so the URL needs no separate key or migration.
    An id the browser does not hold shows "Local document not found".

  • / redirects to the most recently edited net

    A browser with no saved nets gets a new empty one.
    Search parameters carry over to the redirect.

  • /new saves a separate empty net on each visit and redirects to it
  • Both redirects replace the history entry and show an error page when storage refuses the write

    saveNetInStorage calls setItem directly, so a refused write throws.

Website editor

  • URL decides which net is open

    LocalStorageDemoApp takes netId and asks the route to open another net through onOpenNet.
    Switching nets pushes a history entry and keeps the editor mounted.

  • useSharedSearchNavigation takes a resetKey

    A new key starts the location over from the URL, so a multi-item selection never reaches the next net.
    It replaces withClearedSharedLocation.

  • Repository takes the open document from its host

    Its default in-memory document and its own selection state are gone.

  • Empty nets stay saved when the visitor switches away, so their URLs keep working

Examples

  • Make a local copy in the example top bar

    Saves a copy titled after the example and opens it with the current view.
    A refused write shows an inline message and keeps the example open.

Review fixes

  • No @hashintel/petrinaut changeset or user-guide section for website features

    Local URLs and example copies are documented in the website README.
    The guide's storage sentence now says it describes the live site.

  • Route test named after its route

    -local.$netId.test.tsx mirrors local.$netId.tsx, as -new.test.ts mirrors new.tsx.
    The leading dash keeps test files out of the route tree.

Test coverage

  • -local.$netId.test.tsx:

    URL selects the net, Back and Forward, home redirect, first-visit save, storage error page.

  • -new.test.ts:

    Redirect target, separate net per visit, thrown storage failure.

  • use-local-storage-sdcpns.test.ts:

    Refused save, latest or new net, empty nets kept.

  • use-local-document-repository.test.ts:

    Host-owned document id, open requests, unknown ids, create without opening.

  • use-shared-search-navigation.test.tsx:

    Reset key clears a multi-item selection.

  • local-storage-demo-app.test.tsx:

    New net opens at its own URL, not-found page.
    Existing suites run through a harness that plays the route.

  • Verified in a browser against the dev server:

    Redirects, new net URL, Back and Forward, not-found page, example copy and its failure message.

How to test

  • Open Petrinaut preview on Vercel

    Expect redirect to /local/<id>

  • Menu > New

    Expect a new /local/<id> URL

  • Press Back

    Expect previous net

  • Reload

    Expect same net

  • Open /local/550e8400-e29b-41d4-a716-446655440000

    Expect "Local document not found"

  • Open /examples/sir-epidemic-model
  • Make a local copy

    Expect editable copy at a new /local/<id> URL

@kube kube self-assigned this Sep 11, 2026
@vercel

vercel Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Oct 9, 2026 8:28pm UTC
petrinaut Ready Ready Preview Oct 9, 2026 8:28pm UTC
petrinaut-docs Ready Ready Preview Oct 9, 2026 8:28pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Oct 9, 2026 8:28pm UTC

Request Review

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/apps labels Sep 11, 2026
@kube
kube added this pull request to stack #9663 September 11, 2026 02:41
@kube
kube marked this pull request as ready for review September 11, 2026 03:04
Copilot AI balanced review requested due to automatic review settings September 11, 2026 03:04
@cursor

cursor Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Routing and local-storage persistence behavior change how users open, bookmark, and switch nets; incorrect navigation or reset logic could leak editor state between documents or drop saves on quota errors.

Overview
Local nets are addressable by URL instead of always opening “whatever was edited last” at /.

Each saved net opens at /local/<net id> (the Petrinaut document id). / redirects to the most recently edited net (creating an empty one if needed), and /new creates a new empty net on every visit and redirects to its URL. Both use replace navigation and show a storage error page when localStorage refuses the write, rather than linking to an unsaved net.

The editor shell is URL-driven: LocalStorageDemoApp receives netId and onOpenNet; switching nets updates the route (with history). Missing ids show “Local document not found”. Empty nets are no longer pruned when switching away, so their /local/... links keep working.

Published examples add Make a local copy, which saves an editable copy (preserving the current view in search params) or shows an inline error if storage fails.

useSharedSearchNavigation gains a resetKey (wired to netId) so editor location state resets when the document changes—replacing manual withClearedSharedLocation clears. The local document repository no longer picks “newest” or owns selection; create no longer auto-opens unless the host navigates.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The central editor-to-UUID navigation workflow lacks integration coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds persistent UUID routes for browser-local Petrinaut documents and enables editable copies of published examples.

Changes:

  • Adds UUID migration, creation, routing, and navigation.
  • Adds example copying and missing-document recovery.
  • Updates tests, documentation, and release metadata.
File summaries
File Description
.changeset/local-document-urls.md Adds the Petrinaut patch changeset.
apps/petrinaut-website/README.md Documents local UUID routes and copies.
apps/petrinaut-website/src/examples/full-example-page.tsx Adds the copy action and error alert.
apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx Connects document selection to routing.
apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts Adds UUID data to the fixture.
apps/petrinaut-website/src/main/app/local-storage-demo/use-local-storage-sdcpns.test.ts Tests UUID migration and copies.
apps/petrinaut-website/src/main/app/local-storage-demo/use-local-storage-sdcpns.ts Implements UUID persistence and migration.
apps/petrinaut-website/src/routes/-local.test.tsx Tests local routes and history.
apps/petrinaut-website/src/routes/-new.test.ts Tests distinct /new documents.
apps/petrinaut-website/src/routes/-not-found-page.tsx Supports customized recovery messages.
apps/petrinaut-website/src/routes/__root.tsx Adapts root not-found rendering.
apps/petrinaut-website/src/routes/examples.$slug.tsx Saves and opens example copies.
apps/petrinaut-website/src/routes/index.tsx Redirects home to the latest document.
apps/petrinaut-website/src/routes/local.$uuid.tsx Adds the local-document route.
apps/petrinaut-website/src/routes/new.tsx Redirects new documents to UUID URLs.
libs/@hashintel/petrinaut/docs/drawing-a-net.md Documents local URLs and example copies.
Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +479 to +480
if (onNetChange) onNetChange(newNet);
else clearSharedLocation();

@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 Bugbot comment from a previous run.

Comment thread apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx Outdated
Comment thread apps/petrinaut-website/src/routes/index.tsx Outdated

@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 Bugbot comment from a previous run.

Saved nets open at /local/<net id>. Net ids are already UUIDs, so the URL
needs no separate key or migration. The URL owns the open document: the demo
app takes it as a prop and asks the route to open another, so Back and Forward
move between nets without remounting the editor.

/ redirects to the most recently edited net and /new to a new one; both throw
to an error page when the browser refuses the write. Published examples offer
Make a local copy.
@kube
kube removed this pull request from stack #9732 October 9, 2026 02:33
@kube
kube changed the base branch from codex/fe-601-code-editor-variations to main October 9, 2026 02:33
@kube
kube requested review from a team as code owners October 9, 2026 02:33
@github-actions github-actions Bot added the area/apps > hash.design Affects the `hash.design` design site (app) label Oct 9, 2026
@kube
kube force-pushed the codex/fe-1659-local-document-urls branch from 859581a to 369dac4 Compare October 9, 2026 02:34
@kube
kube added this pull request to stack #9974 October 9, 2026 02:34
@github-actions github-actions Bot removed the area/apps > hash.design Affects the `hash.design` design site (app) label Oct 9, 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 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 369dac4. Configure here.

readonly controller: DocumentController;
} => {
const { repository } = useLocalDocumentRepository({
documentId: input.documentId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Create navigates after failed persist

Medium Severity

In-app createAndOpen still writes through setStoredSDCPNs, which swallows storage errors, then open navigates to /local/<new-id>. /new and Make a local copy refuse that path when the write fails, but Menu > New and import do not, so a full or blocked store still assigns a bookmarkable URL that reloads as Local document not found and drops the new net.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 369dac4. Configure here.

CiaranMn
CiaranMn previously approved these changes Oct 9, 2026
kube added 2 commits October 9, 2026 22:04
Local document URLs and example copies are demo-website features, so they
belong in the website README rather than a @hashintel/petrinaut patch note
or its user guide. The guide's storage sentence now says it describes the
live site.
Route tests mirror the route file they cover, as -new.test.ts does for
new.tsx; the leading dash keeps them out of the route tree.

This branch was successfully deployed

3 active deployments
Preview – hash — 6c1621aa Deployed Oct 9, 2026 by vercel[bot]
Preview – petrinaut-docs — 6c1621aa Deployed Oct 9, 2026 by vercel[bot]
Preview – petrinaut — 6c1621aa Deployed Oct 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants