Skip to content

FE-1509: Add the notebook cell list as an experimental mode - #9407

Open
kube wants to merge 1 commit into
claude/fe-1509-notebook-analysesfrom
claude/fe-1509-notebook-cells
Open

FE-1509: Add the notebook cell list as an experimental mode#9407
kube wants to merge 1 commit into
claude/fe-1509-notebook-analysesfrom
claude/fe-1509-notebook-cells

Conversation

@kube

@kube kube commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

The Notebook view itself, stacked on #9406: the Notebook itself, as an experimental read-only mode that renders the net as a list of one-line expandable cells. Off by default behind a new Notebook view toggle in the viewport settings dialog.

🔗 Related links

🔍 What does this change?

  • A fourth global mode in the top bar, present only while enableNotebookView is on. The view is read-only, including for the AI assistant (notebook-mode joins ReadOnlyReason).
  • Cells read like declarations: kind keyword, name, one-line summary, direct → transitive dependent counts, an initial badge on places the net cannot seed itself,. Expanding shows the full definition, with code in read-only Monaco editors that reuse the LSP document URIs.
  • Keyboard navigation (↑/↓ select, →/← expand and collapse), / fuzzy name search with per-character match highlighting, kind filter chips, and a Document/Topological order toggle where seed places are hoisted to the front of the flow.
  • Selecting a cell draws angled gutter connector lines to its dependencies (left) and dependents (right), measured from the DOM and re-measured when rows move.
  • The list rides the worksheet keyboard-flow layer (useFocusStops): every navigable row is a full-width stop, so vertical arrows walk exactly the rows a search leaves navigable, the whole list is one roving tab stop instead of a tab stop per row, and selection follows row focus. Rows own the horizontal arrows for expand/collapse; the search box's arrows still step the selection without leaving the input. Per the worksheet contract, edge moves stay put instead of wrapping.
  • While a cell is expanded, its body parts join the flow as stops. A line with several values — an arc's place, weight and kind, a type field's name and type — is a sparse multi-column stop: horizontal arrows walk its cells one value at a time, vertical moves keep the column, and the focused thing is the cell, not the line. Enter acts on the focused value: buttons and checkboxes activate immediately (an arc's place jumps to its cell), text fields, selects and code editors follow the ARIA grid interaction-mode pattern — Enter engages the widget, its keys stay its own, Escape steps back out.
  • The Notebook option sits directly after Edit in the mode selector.
  • The effective global mode is derived in one shared hook (useEffectiveGlobalMode) used by both the editor view and useReadOnlyReason, so turning the flag off while the stored mode is "notebook" falls back to Edit consistently.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing
    • one patch changeset for the whole stack ships in the top PR

📜 Does this require a change to the docs?

The changes in this PR:

  • are in a state where docs changes are not yet required but will be
    • this is tracked in: the user-docs PR at the top of this stack

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Cell rows use role="button" with a nested caret button rather than listbox/option semantics — FE-1539.
  • Expanded cells mount their Monaco editors with no cap — FE-1540.
  • Subnets and component instances are not rendered as cells.

🐾 Next steps

  • Component extraction and prop bundling — FE-1542.

🛡 What tests cover this?

The pure logic is covered by the layer below's suites; this layer's own behaviour (keyboard navigation, search, filters, gutter measurement) is exercised manually per the steps below.

❓ How to test this?

  1. Run the Petrinaut storybook and open a story with a non-empty net (e.g. the SIR example).
  2. Open the viewport settings dialog (gear button in the canvas controls), enable Notebook view, and pick Notebook in the top bar.
  3. Try expanding cells (→/←), arrow-key navigation, / plus a fuzzy query, the kind filter chips, and the Document/Topological toggle.
  4. Select cells and check the gutter lines track them, including after switching the order.

📹 Demo

Screenshot pending — to be added before review.

@kube kube self-assigned this Aug 28, 2026
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 30, 2026 5:03am
petrinaut Ready Ready Preview Aug 30, 2026 5:03am
petrinaut-docs Ready Ready Preview Aug 30, 2026 5:03am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 30, 2026 5:03am

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 labels Aug 28, 2026
@kube
kube force-pushed the claude/fe-1509-notebook-cells branch from 0aaaa79 to ac2faa0 Compare August 28, 2026 18:34
@kube
kube force-pushed the claude/fe-1509-notebook-cells branch from ac2faa0 to f96ccab Compare August 28, 2026 18:44
@kube kube changed the title FE-1509: Add the notebook cell list as an experimental read-only mode FE-1509: Add the notebook cell list as an experimental mode Aug 28, 2026
@cursor

cursor Bot commented Aug 29, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Large new editing surface that commits net mutations and mounts multiple Monaco instances, though the feature is experimental and gated behind a default-off setting.

Overview
Adds an experimental Notebook global mode (off by default via a new Notebook view toggle in viewport settings) that lists the net as expandable one-line cells for places, transitions, types, equations, and parameters.

Editor integration: EditorGlobalMode gains "notebook"; the top-bar mode selector shows Notebook after Edit when the flag is on; EditorView renders NotebookView instead of the canvas and uses useEffectiveGlobalMode so disabling the flag while still stored as notebook falls back to Edit consistently (including useReadOnlyReason). The main content row uses flex sizing so scrollIntoView does not push the top bar away.

Notebook UX: Toolbar fuzzy name search, kind filter chips, and Document vs topological ordering; gutter SVG connectors from the selected cell to upstream/downstream dependencies; worksheet-style keyboard focus (useFocusStops) with in-cell editing via existing usePetrinautMutations (names, arcs, Monaco code with LSP URIs). useUndoRedoShortcuts replaces the canvas BottomBar shortcuts in this mode.

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

Comment thread libs/@hashintel/petrinaut/src/ui/views/Notebook/notebook-cell.tsx
Comment thread libs/@hashintel/petrinaut/src/ui/views/Editor/editor-view.tsx
Comment thread libs/@hashintel/petrinaut/src/ui/views/Notebook/notebook-cell.tsx Outdated
);
if (firstMatch) {
selectCell(firstMatch, { focus: true });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Search Enter ignores current selection

Medium Severity

Enter in the search box always focuses the first name match, even after arrow keys have already moved the selection to another match. That discards the current selection instead of moving focus to the selected cell.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4f3dde5. Configure here.

),
);
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Filter drops the list tab stop

Medium Severity

useFocusStops keeps the last focused stop even after kind filters, search, or collapse remove that stop from rowStops. Remaining rows then all get tabIndex={-1}, so the list loses its roving tab stop and vertical arrows no-op until a row is clicked.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4f3dde5. Configure here.

if (target) {
selectCell(target, { focus: true });
}
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Arc jump ignores kind filters

Low Severity

navigateToCell resolves targets from the full cell list, not visibleCells. Jumping to a place whose kind is filtered out updates selection and connection state, but the row is not mounted, so focus and gutter lines fail and the highlight disappears.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4f3dde5. Configure here.

A new global mode behind an enableNotebookView user setting, toggled
in the viewport settings dialog and placed directly after Edit. The
net renders as a list of one-line expandable cells with keyboard
navigation on the worksheet focus flow (one roving tab stop, no edge
wrap), fuzzy name search, kind filters, document/topological ordering,
per-row dependent counts, and gutter connector lines from the selected
cell to its dependencies and dependents.

Everything an expanded cell shows edits in place through the same
guarded mutations as the properties panel: names, fields, arc weights,
type assignments, and code. Body parts join the focus flow — Enter
engages a part's widgets or code editor, Tab cycles them, Escape
reverts drafts and steps back out. Code edits only commit while the
editor has focus, so programmatic model resets can never write back.

The effective global mode is derived in one shared hook used by both
the editor view and useReadOnlyReason, so the rendered view and the
mutation rules never disagree when the flag is off.

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

There are 4 total unresolved issues (including 3 from previous reviews).

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 f3879ca. Configure here.

: { id: stopId, kind: "full" };
})
: []),
]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Roving focus leaves navigable rows

Medium Severity

rowStops only includes search matches, but every visible row still receives tabIndexFor / onNavigate. A dimmed or kind-filtered cell can remain the roving tab stop, so Tab lands on a non-match and Up/Down no-op after stopIndexOf misses.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f3879ca. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

1 participant