Skip to content

FE-1500: Add URL navigation to every Petrinaut website demo - #9491

Open
kube wants to merge 6 commits into
mainfrom
claude/petrinaut-website-navigation
Open

FE-1500: Add URL navigation to every Petrinaut website demo#9491
kube wants to merge 6 commits into
mainfrom
claude/petrinaut-website-navigation

Conversation

@kube

@kube kube commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Before this PR, only the example pages at /examples/<slug> and /embed/examples/<slug> mirrored Petrinaut's location to the URL. The editable demo at /, the optimization demo, and the Brunch stream kept scenario, subnet, and selection in memory. A link to one of those pages opened the default location, and Back and Forward moved between pages only.

Every page on demo.petrinaut.org that mounts Petrinaut now speaks the shared contract: scenario, subnet, itemType, itemId.

9491.mp4

Links

Changes

  • / and /optimization validate the shared search and pass it to the demo app

    LocalStorageDemoApp takes search and onSearchChange, builds a controller with useSharedSearchNavigation, and hands it to Petrinaut.
    Switching nets keeps the controller. Petrinaut drops a location the new net cannot resolve.

  • /brunch validates its stream keys together with the shared contract

    validateBrunchSearch merges sse and runId with the four shared keys.
    A location change keeps the stream keys and replaces the contract part, so the run stays open.

  • The URL carries the editor's mode, its Simulate section and the open overlay, alongside the scenario, the subnet and the focused item

    Without them Back walked straight past an open create-experiment form and undid the selection behind it. A field the URL leaves out means "whatever this page starts from", so Back onto an entry that names neither closes the form and returns the mode. simulateResource stays out: it names a record inside the open document rather than a place in the app.

  • The mode and Simulate-section vocabularies are exported from @hashintel/petrinaut/react

    The website spells both in its own contract and maps them with plain assignments, so adding a member to either fails the website's type check until the contract decides whether the URL should carry it.

Review fixes

  • The hook no longer mistakes the echo of its own URL write for an external change

    The projection is lossy, so re-merging it cleared a selection of any size but one. The echo is suppressed once, and a later Back or Forward onto the same location still merges.

  • /brunch opens in Actual mode

    A controlled controller replaces the navigation provider's initial state, including the Actual-mode default it applies when a stream is available, so the route opened in Edit and the execution frame read the local simulation. initialState seeds the fields the URL does not own, and accepts only those.

  • Switching nets in the editable demo clears the location

    Petrinaut resets its own location per document by keying on the handle id, which covers only an uncontrolled location.

  • Switching nets clears the in-memory location, not only the URL

    A selection of more than one item projects to an empty search, so writing {} changed no prop, the hook's merge never ran, and the old net's selection survived into the next one.

  • The editable demo leaves history to the library default, so a discrete selection pushes

    A review round made selections replace instead. That removed every entry the page can produce, and the first Back press then left the site rather than retracing the net. The default already replaces while an intent continues, so a drag-select still records one entry rather than one per intermediate selection.

  • The Brunch stream-key carry-over moved out of the route into withBrunchStreamKeys

    Applied to the router's own previous search, so two navigations in one event compose.

Test coverage

  • brunch-search.test.ts:

    Stream keys survive, non-string values drop to undefined, shared keys ride alongside the stream keys, and withBrunchStreamKeys carries them over a navigation.

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

    A multi-item selection survives the echo of its own write, and a seeded field survives an external change.

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

    The page adds no history policy of its own, and the library default pushes a discrete selection while replacing a continuing one.

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

    The controller reaches the editor, an editor navigation reaches the URL, a net switch clears the location, and Brunch opens in Actual mode.

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

    Back onto an entry that names neither the mode nor the overlay closes the form and returns the mode to the page's baseline, and the one field the URL cannot carry survives an external change.

  • use-shared-search-navigation.test.tsx, example-search.test.ts, navigation-search.test.ts:

    Existing contract and controller laws, unchanged.

How to test

Location and history

  • Open Petrinaut preview on Vercel
  • Menu > Load example > any model
  • Select a place

    Expect ?itemType=place&itemId=<id> in the URL

  • Switch to Simulate

    Expect mode=simulate in the URL

  • Press Create

    Expect overlay=create-experiment in the URL

  • Press Back three times

    Expect form closed, mode back to Edit, nothing selected

  • Press Forward once

    Expect the place selected again

Invalid and foreign params

  • Open /?itemType=place&itemId=bogus&scenario=none&junk=1

    Expect URL to settle on ?scenario=none

Brunch stream keys

  • Open /brunch?sse=<endpoint>&scenario=<id>
  • Change scenario

    Expect sse preserved

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

vercel Bot commented Sep 2, 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 Sep 3, 2026 11:09pm UTC
petrinaut Ready Ready Preview Sep 3, 2026 11:09pm UTC
petrinaut-docs Ready Ready Preview Sep 3, 2026 11:09pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 3, 2026 11:09pm UTC

Request Review

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches browser history, URL↔state sync, and controlled navigation across all demos; regressions could break shareable links, Back/Forward, or Brunch live mode, though behavior is heavily tested.

Overview
Extends the shared example URL contract beyond scenario, subnet, and selection to include mode, view (Simulate section), and overlay, with baseline semantics so omitted params mean “this page’s starting location” and browser Back can undo mode/overlay changes. simulateResource stays in-memory only.

Wires useSharedSearchNavigation through /, /optimization, and /brunch: TanStack Router validates search, navigates on editor changes, suppresses lossy URL echo (e.g. multi-select), supports initialState (Brunch seeds actual mode), and withClearedSharedLocation when switching nets in the local-storage demo. Brunch merges stream keys via validateBrunchSearch / withBrunchStreamKeys.

Exports EditorGlobalMode and SimulateViewMode from @hashintel/petrinaut/react for type-safe host mapping; updates router/host docs and tests (oEmbed now preserves mode).

Reviewed by Cursor Bugbot for commit 0f0ce0c. 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 controlled Brunch navigation defaults to Edit mode, preventing the editor from using the live Actual-mode stream.

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

Pull request overview

Adds shared URL navigation to Petrinaut’s editable, optimization, and Brunch demos.

Changes:

  • Connects shared search state to Petrinaut navigation.
  • Preserves Brunch stream parameters during navigation.
  • Updates validation, tests, and architecture documentation.
File summaries
File Description
libs/@local/petrinaut-arch-docs/content/website/router-integration.mdx Documents supported routes and Brunch behavior.
apps/petrinaut-website/src/routes/optimization.tsx Adds search-driven optimization navigation.
apps/petrinaut-website/src/routes/index.tsx Adds search-driven editable-demo navigation.
apps/petrinaut-website/src/routes/brunch.tsx Preserves stream keys while navigating.
apps/petrinaut-website/src/main/app/optimization-demo/optimization-demo-app.tsx Forwards navigation props.
apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx Supplies a navigation controller to Petrinaut.
apps/petrinaut-website/src/main/app/brunch-demo/brunch-search.ts Combines stream and shared-search validation.
apps/petrinaut-website/src/main/app/brunch-demo/brunch-search.test.ts Tests combined search validation.
apps/petrinaut-website/src/main/app/brunch-demo/brunch-petrinaut.tsx Passes navigation into Petrinaut.
apps/petrinaut-website/src/main/app/brunch-demo/brunch-demo-app.tsx Creates Brunch navigation state.
apps/petrinaut-website/src/main/app/brunch-demo/brunch-actual-mode-route.tsx Threads navigation through the Brunch route.
Review details
  • Files reviewed: 11/11 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 thread apps/petrinaut-website/src/main/app/brunch-demo/brunch-demo-app.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.

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 2f23b50. Configure here.

kube added 4 commits September 4, 2026 00:10
A controlled navigation controller replaces PetrinautNavigationProvider's
initial state, including the Actual-mode default it applies when a live
stream is available, so the Brunch route opened in Edit mode and the
execution frame read the local simulation instead of the stream.

useSharedSearchNavigation takes an initialState option for the fields the
URL does not carry, and the Brunch demo seeds mode: actual. The URL still
wins for the fields it owns.
The hook mistook the echo of its own URL write for an external change and
merged the lossy projection back over the in-memory location, so selecting
a second node cleared the selection. The echo is now suppressed once, and
a later Back or Forward onto the same location still merges.

Switching nets in the editable demo carried the previous net's location:
Petrinaut resets its own location per document by keying on the handle id,
which only covers an uncontrolled location. The demo clears the URL on a
net switch instead.

Selection changes no longer push a browser history entry on the editable
demo, where Back would otherwise take dozens of presses to leave the page.

The stream-key carry-over moves out of the route into withBrunchStreamKeys
and is applied to the router's own previous search. initialState accepts
only the fields the URL does not own, rather than discarding the rest.
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 > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

2 participants