H-5655: Refactor selection logic and migrate to @xyflow/react v12#8523
H-5655: Refactor selection logic and migrate to @xyflow/react v12#8523
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
a4cb46c to
4043333
Compare
4043333 to
47518e4
Compare
47518e4 to
4a51729
Compare
PR SummaryMedium Risk Overview Refactors selection into a typed Adds new properties UI for arcs ( Adjusts layout/drag position math to consistently treat SDCPN positions as center coordinates (dims-aware) and commits drag-end updates atomically; adds a user setting for partial box selection and highlights selected nodes in the minimap. Written by Cursor Bugbot for commit 0b08c25. This will update automatically on new commits. Configure here. |
- Extract selection state into dedicated module with SelectionMap type - Add arc selection and multi-selection support in properties panel - Migrate from reactflow v11 to @xyflow/react v12 - Fix node centering by offsetting positions in mapper instead of CSS transforms - Add measured dimensions to nodes to fix arc invisibility after large moves - Add browser tests for SDCPNView with vitest-browser-playwright - Update node dimensions to match actual visual sizes for classic/compact modes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tests Remove dual selection management between onNodeClick/onEdgeClick and ReactFlow's internal handleNodeClick. Selection now flows exclusively through ReactFlow → onNodesChange → useApplyNodeChanges → setSelection, fixing meta+click multi-select which was broken by conflicting handlers. Fix multi-node drag position commit by reading change.position directly from ReactFlow events instead of stale draggingStateByNodeId closure. Add integration test file using real EditorProvider + controlled SDCPNContext covering click selection, meta+click toggle, pane clear, single/multi-node drag, and keyboard delete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation Previously each dragged node's position was committed via a separate mutatePetriNetDefinition call, causing a visual snap-back glitch when the dragging state was cleared before all positions were flushed. Now all position updates are applied in one mutatePetriNetDefinition call. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…only - setSelection now accepts a functional updater so concurrent onNodesChange/onEdgesChange calls chain against latest state instead of clobbering each other via stale closures. - Arcs are excluded from drag-to-select; a dedicated onEdgeClick handler makes them selectable only by direct click. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a `partialSelection` user setting (default true) that controls whether drag-to-select picks up partially intersected nodes. Refactor the viewport settings dialog to use a reusable SettingRow grid component. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove FocusNodeRegistrar and all focusNode/registerFocusNode plumbing from the editor context. Viewport centering on node selection will be revisited as a dedicated feature. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Selected nodes render with a light blue fill and stroke in the MiniMap. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move deletion keyboard handling from SDCPNView's onKeyDown to the global keyboard shortcuts hook using useEffectEvent, so Delete/Backspace works from anywhere in Petrinaut. Extend deleteItemsByIds to also handle types, differential equations, and parameters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…temsByIds Expose `isSelected(id)` and `hasSelection` from EditorContext so consumers no longer need direct access to the SelectionMap for simple lookups. Change `deleteItemsByIds` to accept typed SelectionMap, enabling it to partition by item type and skip irrelevant collections. Migrate all 12 UI consumers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e test deps - Convert ELK top-left positions to center coordinates in calculateGraphLayout, matching the convention used by useSdcpnToReactFlow and useApplyNodeChanges - Accept dims parameter instead of using deprecated nodeDimensions alias, so layout uses correct dimensions for compact vs classic mode - Fix selection guards to check base map instead of prevSelection, preventing previously-selected canvas nodes from being dropped during box-select when non-canvas items are selected - Re-add @testing-library/dom and @testing-library/react devDependencies needed by unit tests that were incorrectly removed with browser test cleanup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
52a1e41 to
11b1e8b
Compare
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1001 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1526 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 51 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 107 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 25 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |

🌟 What is the purpose of this PR?
Refactor the selection logic in Petrinaut and migrate to
@xyflow/reactv12. This centralizes selection state inEditorContext, adds multi-selection support, and improves keyboard shortcut handling.🔗 Related links
🔍 What does this change?
@xyflow/reactv12 with updated APIs and typesEditorContextwithisSelected/hasSelectionhelpersPre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
EditorContextand ReactFlow's internal state still needs enhancements🐾 Next steps
🛡 What tests cover this?
❓ How to test this?