@kiberon-labs/behave-graph-flow 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/manager.ts +6 -0
- package/.storybook/preview.ts +49 -1
- package/.storybook/styles.css +9 -3
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +368 -0
- package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
- package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
- package/dist/index.css +36 -33
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1865 -550
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14357 -11221
- package/dist/index.js.map +1 -1
- package/dist/noteImpl-KkrrWgJd.js +242 -0
- package/dist/noteImpl-KkrrWgJd.js.map +1 -0
- package/dist/styles.module-CvmpDkZj.css +3 -0
- package/dist/styles.module-CvmpDkZj.css.map +1 -0
- package/dist/styles.module-DZxg8aW9.js +271 -0
- package/dist/styles.module-DZxg8aW9.js.map +1 -0
- package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
- package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
- package/docs/protocol.md +43 -20
- package/package.json +5 -9
- package/src/components/FloatingToolbar/index.module.css +5 -13
- package/src/components/FloatingToolbar/index.tsx +9 -9
- package/src/components/Flow.tsx +34 -23
- package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
- package/src/components/contextMenus/NodePicker.module.css +13 -13
- package/src/components/contextMenus/edge.tsx +9 -95
- package/src/components/contextMenus/node.tsx +9 -149
- package/src/components/contextMenus/selection.tsx +5 -71
- package/src/components/controls/any/AnyControlImpl.tsx +14 -0
- package/src/components/controls/any/index.tsx +13 -2
- package/src/components/edges/index.tsx +75 -69
- package/src/components/layoutController/index.module.css +3 -0
- package/src/components/layoutController/index.tsx +24 -1
- package/src/components/layoutController/utils.ts +46 -3
- package/src/components/menubar/defaults.tsx +55 -19
- package/src/components/menubar/menuItem.module.css +18 -3
- package/src/components/menubar/menuItem.tsx +34 -1
- package/src/components/nodes/behave/NodeContainer.module.css +26 -25
- package/src/components/nodes/group/index.tsx +3 -3
- package/src/components/nodes/wrapper/styles.module.css +6 -32
- package/src/components/panels/alignment/index.module.css +0 -10
- package/src/components/panels/alignment/index.tsx +4 -4
- package/src/components/panels/base/styles.module.css +2 -2
- package/src/components/panels/common/PanelHeader.module.css +24 -0
- package/src/components/panels/common/PanelHeader.tsx +22 -0
- package/src/components/panels/common/SectionTitle.module.css +13 -0
- package/src/components/panels/common/SectionTitle.tsx +10 -0
- package/src/components/panels/events/EditEventPanel.tsx +14 -5
- package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
- package/src/components/panels/events/styles.module.css +6 -64
- package/src/components/panels/graphProperties/index.tsx +125 -0
- package/src/components/panels/history/index.tsx +2 -2
- package/src/components/panels/history/styles.module.css +0 -9
- package/src/components/panels/keymaps/index.module.css +3 -13
- package/src/components/panels/keymaps/index.tsx +1 -2
- package/src/components/panels/layers/index.tsx +20 -15
- package/src/components/panels/layers/styles.module.css +9 -12
- package/src/components/panels/legend/index.tsx +1 -1
- package/src/components/panels/logs/index.module.css +25 -19
- package/src/components/panels/logs/index.tsx +7 -7
- package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
- package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
- package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
- package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
- package/src/components/panels/nodeInputs/index.module.css +99 -75
- package/src/components/panels/nodeInputs/index.tsx +21 -11
- package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
- package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
- package/src/components/panels/nodePicker/index.tsx +8 -8
- package/src/components/panels/panel/index.module.css +7 -7
- package/src/components/panels/search/index.module.css +0 -50
- package/src/components/panels/search/index.tsx +2 -2
- package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
- package/src/components/panels/systemSettings/index.tsx +221 -176
- package/src/components/panels/systemSettings/styles.module.css +135 -8
- package/src/components/panels/traces/GridLines.tsx +1 -1
- package/src/components/panels/traces/TimeGrid.tsx +3 -3
- package/src/components/panels/traces/TraceLane.tsx +1 -1
- package/src/components/panels/traces/index.module.css +1 -8
- package/src/components/panels/traces/index.tsx +8 -4
- package/src/components/panels/traces/useDerivedSpans.ts +241 -146
- package/src/components/panels/traces/utils.ts +8 -0
- package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
- package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
- package/src/components/panels/variables/index.tsx +2 -2
- package/src/components/panels/variables/styles.module.css +4 -91
- package/src/components/primitives/icon.module.css +4 -4
- package/src/components/sockets/input/index.tsx +9 -2
- package/src/components/sockets/input/styles.module.css +2 -3
- package/src/components/sockets/output/index.tsx +10 -3
- package/src/components/sockets/output/styles.module.css +1 -6
- package/src/css/notes.css +135 -0
- package/src/css/prosemirror.css +3 -3
- package/src/css/rc-dock.css +143 -43
- package/src/css/rc-menu.css +56 -55
- package/src/css/themes/kiberon.css +127 -0
- package/src/css/vars.css +197 -13
- package/src/css/vscode-elements.css +124 -0
- package/src/generators/CallSubgraphGenerator.tsx +136 -0
- package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
- package/src/generators/GraphBoundaryGenerator.module.css +32 -0
- package/src/generators/GraphBoundaryGenerator.tsx +193 -0
- package/src/generators/SequenceGenerator.tsx +2 -2
- package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
- package/src/generators/SwitchOnStringGenerator.tsx +2 -2
- package/src/generators/callSubgraphSync.ts +126 -0
- package/src/generators/registerDefaultGenerators.ts +21 -0
- package/src/generators/registerDefaults.ts +26 -0
- package/src/hooks/useBehaveGraphFlow.ts +2 -2
- package/src/hooks/useFlowHandlers.ts +47 -9
- package/src/hooks/useWasdPan.ts +26 -4
- package/src/index.css +4 -16
- package/src/index.ts +17 -0
- package/src/manifest/contributionRegistry.ts +93 -0
- package/src/manifest/index.ts +4 -0
- package/src/manifest/loadManifest.ts +82 -0
- package/src/manifest/manifestPlugin.ts +29 -0
- package/src/manifest/passthroughValueType.ts +40 -0
- package/src/plugin/alignment/index.ts +22 -12
- package/src/plugin/autosave/controller.ts +366 -0
- package/src/plugin/autosave/index.tsx +114 -0
- package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
- package/src/plugin/autosave/panel/index.tsx +1 -0
- package/src/plugin/autosave/panel/styles.module.css +56 -0
- package/src/plugin/autosave/settings.ts +65 -0
- package/src/plugin/autosave/storage.ts +147 -0
- package/src/plugin/docs/index.tsx +2 -4
- package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
- package/src/plugin/docs/panel/index.tsx +15 -194
- package/src/plugin/docs/panel/styles.module.css +8 -8
- package/src/plugin/graphrunner/actions.ts +258 -185
- package/src/plugin/graphrunner/buttons.tsx +34 -26
- package/src/plugin/graphrunner/client.ts +4 -1
- package/src/plugin/graphrunner/index.tsx +29 -100
- package/src/plugin/graphrunner/panel.tsx +2 -2
- package/src/plugin/graphrunner/runController.ts +283 -0
- package/src/plugin/graphrunner/runner.ts +21 -192
- package/src/plugin/graphrunner/store.ts +14 -24
- package/src/plugin/graphrunner/styles.module.css +17 -57
- package/src/plugin/graphrunner/transport.ts +26 -0
- package/src/plugin/graphrunner/types.ts +21 -0
- package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
- package/src/plugin/graphrunner-local/index.tsx +8 -2
- package/src/plugin/graphrunner-local/panel.tsx +131 -175
- package/src/plugin/graphrunner-local/styles.module.css +57 -76
- package/src/plugin/graphrunner-local/transport.ts +151 -184
- package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
- package/src/plugin/graphrunner-webworker/index.tsx +4 -10
- package/src/plugin/graphrunner-webworker/store.ts +9 -0
- package/src/plugin/kitchen-sink/index.ts +38 -0
- package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
- package/src/{layout → plugin/layout}/elk.ts +22 -6
- package/src/plugin/layout/index.ts +80 -0
- package/src/plugin/notes/FormatToolbar.tsx +200 -0
- package/src/plugin/notes/index.tsx +191 -0
- package/src/plugin/notes/nodeActions.ts +100 -0
- package/src/plugin/notes/note.tsx +20 -0
- package/src/plugin/notes/noteImpl.tsx +89 -0
- package/src/plugin/realtime/realtimeRunner.ts +58 -4
- package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
- package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
- package/src/specifics/VariableGetSpecific.tsx +2 -2
- package/src/specifics/VariableSetSpecific.tsx +2 -2
- package/src/store/actions.tsx +5 -5
- package/src/store/commands.ts +278 -0
- package/src/store/contextMenu.ts +192 -0
- package/src/store/conversions.ts +47 -0
- package/src/store/flow.tsx +23 -38
- package/src/store/graphMeta.ts +39 -0
- package/src/store/hotKeys.tsx +301 -260
- package/src/store/layers.ts +3 -3
- package/src/store/registry.ts +12 -4
- package/src/store/selection.ts +3 -3
- package/src/store/settings.ts +82 -82
- package/src/store/settingsSchema.ts +210 -0
- package/src/store/tabs.ts +5 -1
- package/src/store/traces.ts +3 -3
- package/src/system/graph.ts +11 -14
- package/src/system/graphSession.ts +172 -0
- package/src/system/index.ts +3 -0
- package/src/system/notifications.ts +13 -0
- package/src/system/persistence.ts +82 -0
- package/src/system/plugin.ts +28 -0
- package/src/system/provider.tsx +64 -0
- package/src/system/system.ts +518 -88
- package/src/system/tabLoader.tsx +70 -32
- package/src/system/undoRedo.ts +1 -1
- package/src/transformers/Uigraph.ts +5 -4
- package/src/transformers/contract.ts +87 -0
- package/src/transformers/flowToBehave.ts +13 -5
- package/src/types/nodes.ts +8 -3
- package/src/types.ts +2 -0
- package/src/util/autoConvert.ts +200 -0
- package/src/util/isValidConnection.ts +23 -2
- package/stories/defaults/defaultStoryProvider.tsx +17 -14
- package/stories/defaults/systemGenerator.ts +6 -1
- package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
- package/tests/autoConvert.test.ts +329 -0
- package/tests/autosavePlugin.test.ts +204 -0
- package/tests/callSubgraphSync.test.ts +148 -0
- package/tests/commandRegistry.test.ts +137 -0
- package/tests/contract.test.ts +51 -0
- package/tests/contractSerialize.test.ts +62 -0
- package/tests/deriveSpans.test.ts +71 -0
- package/tests/flowToBehave.test.ts +2 -1
- package/tests/hotkeys.test.ts +79 -0
- package/tests/keepAliveLifecycle.test.ts +167 -0
- package/tests/loadManifest.test.ts +113 -0
- package/tests/noteMarkdown.test.ts +65 -0
- package/tests/notesPlugin.test.ts +162 -0
- package/tests/persistence.test.ts +51 -0
- package/tests/saveLoad.test.ts +7 -6
- package/tests/settings.test.ts +178 -0
- package/tests/traceStore.test.ts +46 -0
- package/tests/visual/README.md +2 -2
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
- package/tests/visual/panels.visual.test.tsx +3 -3
- package/tests/wasdPan.test.ts +71 -0
- package/vitest.config.ts +1 -1
- package/vitest.visual.config.ts +7 -0
- package/.storybook/vscode.css +0 -814
- package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
- package/src/components/nodes/comment/comment.tsx +0 -103
- package/src/components/nodes/comment/styles.module.css +0 -150
- package/src/components/panels/conversation/index.module.css +0 -151
- package/src/components/panels/conversation/index.tsx +0 -162
- package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
- package/src/css/vscode.css +0 -13
- package/src/hooks/useDetachNodes.ts +0 -39
- package/src/plugin/graphrunner-webworker/types.ts +0 -17
- package/src/specifics/registerDefaultSpecifics.ts +0 -5
- package/src/store/chat.ts +0 -73
- package/src/store/graphRunnerClient.ts +0 -110
package/docs/protocol.md
CHANGED
|
@@ -36,9 +36,9 @@ This protocol defines a WebSocket-based interface for decoupled execution of beh
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
**Authentication Types:**
|
|
39
|
-
- `bearer`
|
|
40
|
-
- `apiKey`
|
|
41
|
-
- `none`
|
|
39
|
+
- `bearer` , Bearer token (JWT or API key)
|
|
40
|
+
- `apiKey` , Simple API key
|
|
41
|
+
- `none` , No authentication (development only)
|
|
42
42
|
|
|
43
43
|
**Example with API Key:**
|
|
44
44
|
```json
|
|
@@ -371,7 +371,9 @@ Get metadata about all available node types and their sockets.
|
|
|
371
371
|
"trace": true,
|
|
372
372
|
"eventFilter": { "variables": ["score", "health"], "events": ["onDeath"] },
|
|
373
373
|
"maxExecutionTimeMs": 30000,
|
|
374
|
-
// Whether the
|
|
374
|
+
// Whether the run finalizes once no fibres are pending. Defaults to
|
|
375
|
+
// false: the run stays alive (servicing event-node subscriptions such
|
|
376
|
+
// as ai/onToolCall) until stopGraph.
|
|
375
377
|
"autoEnd":true
|
|
376
378
|
}
|
|
377
379
|
}
|
|
@@ -546,6 +548,27 @@ Get metadata about all available node types and their sockets.
|
|
|
546
548
|
}
|
|
547
549
|
```
|
|
548
550
|
|
|
551
|
+
#### Trace Batch Event
|
|
552
|
+
Servers should prefer `traceBatch` over per-event `trace` messages: node
|
|
553
|
+
execution produces two events per node (start and end), so a graph ticking at
|
|
554
|
+
display rate emits hundreds of events per frame. Buffering them and flushing
|
|
555
|
+
one batch per flush window (roughly one frame, ~16ms) keeps the message
|
|
556
|
+
pipeline off the hot path. Clients accept both; single `trace` messages remain
|
|
557
|
+
valid for servers that predate batching. Timestamps are run-relative
|
|
558
|
+
milliseconds, stamped when the event occurred (not when the batch flushed).
|
|
559
|
+
|
|
560
|
+
```json
|
|
561
|
+
{
|
|
562
|
+
"type": "traceBatch",
|
|
563
|
+
"runId": "abc123",
|
|
564
|
+
"graphId": "main-graph-1",
|
|
565
|
+
"events": [
|
|
566
|
+
{ "nodeId": "node42", "event": "start", "data": { "typeName": "flow/branch" }, "timestamp": 1200 },
|
|
567
|
+
{ "nodeId": "node42", "event": "end", "data": { "typeName": "flow/branch" }, "timestamp": 1201 }
|
|
568
|
+
]
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
549
572
|
#### Log Event
|
|
550
573
|
```json
|
|
551
574
|
{
|
|
@@ -559,7 +582,7 @@ Get metadata about all available node types and their sockets.
|
|
|
559
582
|
```
|
|
560
583
|
|
|
561
584
|
### Variable Change Events
|
|
562
|
-
- `variableChanged`
|
|
585
|
+
- `variableChanged` , Emitted when a variable's value changes during execution.
|
|
563
586
|
- Includes: `runId`, `graphId`, `variableName`, `oldValue`, `newValue`, and optionally `nodeId` (if the change was triggered by a node).
|
|
564
587
|
|
|
565
588
|
#### Example Variable Change Event
|
|
@@ -576,7 +599,7 @@ Get metadata about all available node types and their sockets.
|
|
|
576
599
|
```
|
|
577
600
|
|
|
578
601
|
### Event Emission
|
|
579
|
-
- `eventEmitted`
|
|
602
|
+
- `eventEmitted` , Emitted when an event is triggered during graph execution.
|
|
580
603
|
- Includes: `runId`, `graphId`, `eventName`, `payload`, and optionally `nodeId` (if the event was triggered by a specific node).
|
|
581
604
|
|
|
582
605
|
#### Example Event Emission
|
|
@@ -592,7 +615,7 @@ Get metadata about all available node types and their sockets.
|
|
|
592
615
|
```
|
|
593
616
|
|
|
594
617
|
### Node Addition Events
|
|
595
|
-
- `nodeAdded`
|
|
618
|
+
- `nodeAdded` , Emitted when a node is added to a graph during execution.
|
|
596
619
|
- Includes: `runId`, `graphId`, `nodeId`, `nodeType`, and optionally `nodeData` with the full node configuration.
|
|
597
620
|
|
|
598
621
|
#### Example Node Addition Event
|
|
@@ -617,19 +640,19 @@ Get metadata about all available node types and their sockets.
|
|
|
617
640
|
## 10. Error Handling
|
|
618
641
|
|
|
619
642
|
### Error Codes
|
|
620
|
-
- `PROTOCOL_VERSION_MISMATCH`
|
|
621
|
-
- `PROTOCOL_VIOLATION`
|
|
622
|
-
- `AUTHENTICATION_FAILED`
|
|
623
|
-
- `AUTHENTICATION_REQUIRED`
|
|
624
|
-
- `SESSION_NOT_FOUND`
|
|
625
|
-
- `SESSION_EXPIRED`
|
|
626
|
-
- `INVALID_GRAPH`
|
|
627
|
-
- `VALIDATION_FAILED`
|
|
628
|
-
- `RUN_NOT_FOUND`
|
|
629
|
-
- `NODE_EXECUTION_ERROR`
|
|
630
|
-
- `TIMEOUT`
|
|
631
|
-
- `CONCURRENT_LIMIT_EXCEEDED`
|
|
632
|
-
- `PERMISSION_DENIED`
|
|
643
|
+
- `PROTOCOL_VERSION_MISMATCH` , Incompatible protocol versions
|
|
644
|
+
- `PROTOCOL_VIOLATION` , Protocol rules violated (e.g., hello not sent first)
|
|
645
|
+
- `AUTHENTICATION_FAILED` , Invalid or missing authentication credentials
|
|
646
|
+
- `AUTHENTICATION_REQUIRED` , Authentication is required but not provided
|
|
647
|
+
- `SESSION_NOT_FOUND` , Session does not exist or expired
|
|
648
|
+
- `SESSION_EXPIRED` , Session timed out
|
|
649
|
+
- `INVALID_GRAPH` , Graph definition is malformed
|
|
650
|
+
- `VALIDATION_FAILED` , Graph failed validation
|
|
651
|
+
- `RUN_NOT_FOUND` , Run ID does not exist
|
|
652
|
+
- `NODE_EXECUTION_ERROR` , Error during node execution
|
|
653
|
+
- `TIMEOUT` , Execution exceeded max time
|
|
654
|
+
- `CONCURRENT_LIMIT_EXCEEDED` , Too many concurrent runs
|
|
655
|
+
- `PERMISSION_DENIED` , Unauthorized operation
|
|
633
656
|
|
|
634
657
|
### Error Response Format
|
|
635
658
|
```json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiberon-labs/behave-graph-flow",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@bosh-code/tsdown-plugin-inject-css": "^2.0.0",
|
|
22
|
-
"@bosh-code/tsdown-plugin-tailwindcss": "^1.0.1",
|
|
23
21
|
"@storybook/addon-a11y": "^10.0.8",
|
|
24
22
|
"@storybook/addon-docs": "^10.0.8",
|
|
25
23
|
"@storybook/addon-vitest": "^10.0.8",
|
|
@@ -41,14 +39,13 @@
|
|
|
41
39
|
"react-dom": "19.2.3",
|
|
42
40
|
"reactflow": "^11.11.4",
|
|
43
41
|
"storybook": "^10.0.8",
|
|
44
|
-
"tailwindcss": "^4.1.17",
|
|
45
42
|
"tsdown": "^0.16.5",
|
|
46
43
|
"unplugin-lightningcss": "^0.4.3",
|
|
47
44
|
"vite": "^7.2.4",
|
|
48
45
|
"vite-tsconfig-paths": "^5.1.4",
|
|
49
46
|
"vitest": "^4.0.10",
|
|
50
47
|
"vitest-browser-react": "^2.2.0",
|
|
51
|
-
"@kiberon-labs/behave-graph": "1.
|
|
48
|
+
"@kiberon-labs/behave-graph": "1.2.0"
|
|
52
49
|
},
|
|
53
50
|
"repository": {
|
|
54
51
|
"type": "git",
|
|
@@ -60,6 +57,7 @@
|
|
|
60
57
|
"dependencies": {
|
|
61
58
|
"@radix-ui/react-popover": "^1.1.15",
|
|
62
59
|
"@reactflow/node-resizer": "^2.2.14",
|
|
60
|
+
"@tiptap/extension-youtube": "^3.27.1",
|
|
63
61
|
"@tiptap/react": "^3.19.0",
|
|
64
62
|
"@tiptap/starter-kit": "^3.19.0",
|
|
65
63
|
"@vscode-elements/react-elements": "^2.4.0",
|
|
@@ -67,9 +65,7 @@
|
|
|
67
65
|
"clsx": "^2.1.1",
|
|
68
66
|
"copy-to-clipboard": "^3.3.3",
|
|
69
67
|
"dagre": "^0.8.5",
|
|
70
|
-
"dockview": "^4.11.0",
|
|
71
68
|
"elkjs": "^0.11.0",
|
|
72
|
-
"fastify": "^5.7.4",
|
|
73
69
|
"fuse.js": "^7.1.0",
|
|
74
70
|
"graphlib": "^2.1.8",
|
|
75
71
|
"iconoir-react": "^7.11.0",
|
|
@@ -82,17 +78,17 @@
|
|
|
82
78
|
"react-hotkeys": "^2.0.0",
|
|
83
79
|
"tiptap-markdown": "^0.9.0",
|
|
84
80
|
"uuid": "^8.3.2",
|
|
85
|
-
"zod": "^4.1.13",
|
|
86
81
|
"zustand": "^5.0.8"
|
|
87
82
|
},
|
|
88
83
|
"peerDependencies": {
|
|
89
84
|
"reactflow": "^11.1.1",
|
|
90
|
-
"@kiberon-labs/behave-graph": "1.
|
|
85
|
+
"@kiberon-labs/behave-graph": "1.2.0"
|
|
91
86
|
},
|
|
92
87
|
"scripts": {
|
|
93
88
|
"audit": "fallow",
|
|
94
89
|
"dev": "tsdown --watch src",
|
|
95
90
|
"build": "tsdown",
|
|
91
|
+
"release": "npm publish --dry-run",
|
|
96
92
|
"test": "vitest",
|
|
97
93
|
"test:visual": "vitest run --config vitest.visual.config.ts",
|
|
98
94
|
"test:visual:update": "vitest run --config vitest.visual.config.ts --update",
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
display: flex;
|
|
8
8
|
gap: 0.5rem;
|
|
9
9
|
padding: 0.25rem;
|
|
10
|
-
background: var(--
|
|
11
|
-
border: 1px solid var(--
|
|
10
|
+
background: var(--ds-widget-bg, #292929);
|
|
11
|
+
border: 1px solid var(--ds-border-subtle, #454545);
|
|
12
12
|
border-radius: 0.375rem;
|
|
13
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.
|
|
13
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.36);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.buttonGroup {
|
|
@@ -28,18 +28,10 @@
|
|
|
28
28
|
display: flex;
|
|
29
29
|
align-items: center;
|
|
30
30
|
padding: 0 0.5rem;
|
|
31
|
-
font-size: 0.
|
|
31
|
+
font-size: var(--fs-label, 0.8rem);
|
|
32
32
|
font-weight: 500;
|
|
33
|
-
color: var(--
|
|
33
|
+
color: var(--ds-fg);
|
|
34
34
|
user-select: none;
|
|
35
35
|
min-width: 3rem;
|
|
36
36
|
justify-content: center;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.contextMenu {
|
|
40
|
-
position: absolute;
|
|
41
|
-
top: 100%;
|
|
42
|
-
left: 0;
|
|
43
|
-
margin-top: 0.25rem;
|
|
44
|
-
z-index: 1000;
|
|
45
37
|
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
VscodeContextMenu
|
|
6
6
|
} from '@vscode-elements/react-elements';
|
|
7
7
|
import { ZoomIn, ZoomOut, AlignLeft, LayoutRight } from 'iconoir-react';
|
|
8
|
-
import {
|
|
8
|
+
import { useGraph } from '@/system/provider';
|
|
9
9
|
import { useStore } from 'zustand';
|
|
10
10
|
import styles from './index.module.css';
|
|
11
11
|
import { useRefFromStore } from '@/system';
|
|
@@ -13,10 +13,10 @@ import type { ToolbarButton } from '@/store/toolbar';
|
|
|
13
13
|
import type { AlignmentAxis, AlignmentType } from '@/plugin/alignment';
|
|
14
14
|
|
|
15
15
|
export const FloatingToolbar: React.FC = () => {
|
|
16
|
-
const
|
|
17
|
-
const visible = useStore(
|
|
18
|
-
const customGroups = useStore(
|
|
19
|
-
const reactFlowInstance = useRefFromStore(
|
|
16
|
+
const session = useGraph();
|
|
17
|
+
const visible = useStore(session.editor.toolbarStore, (x) => x.visible);
|
|
18
|
+
const customGroups = useStore(session.editor.toolbarStore, (x) => x.groups);
|
|
19
|
+
const reactFlowInstance = useRefFromStore(session.refStore, 'reactflow');
|
|
20
20
|
const { zoom } = useViewport();
|
|
21
21
|
const currentZoom = Math.round(zoom * 100);
|
|
22
22
|
const [alignMenuOpen, setAlignMenuOpen] = useState(false);
|
|
@@ -27,16 +27,16 @@ export const FloatingToolbar: React.FC = () => {
|
|
|
27
27
|
|
|
28
28
|
const publishAlignment = useCallback(
|
|
29
29
|
(type: AlignmentType, axis: AlignmentAxis) => {
|
|
30
|
-
|
|
30
|
+
session.pubsub.publishSync('alignment:align', { type, axis });
|
|
31
31
|
},
|
|
32
|
-
[
|
|
32
|
+
[session]
|
|
33
33
|
);
|
|
34
34
|
|
|
35
35
|
const publishDistribution = useCallback(
|
|
36
36
|
(type: AlignmentType, axis: AlignmentAxis) => {
|
|
37
|
-
|
|
37
|
+
session.pubsub.publishSync('alignment:distribute', { type, axis });
|
|
38
38
|
},
|
|
39
|
-
[
|
|
39
|
+
[session]
|
|
40
40
|
);
|
|
41
41
|
|
|
42
42
|
const handleZoomIn = useCallback(() => {
|
package/src/components/Flow.tsx
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { useBehaveGraphFlow } from '../hooks/useBehaveGraphFlow.js';
|
|
19
19
|
import { useFlowHandlers } from '../hooks/useFlowHandlers.js';
|
|
20
20
|
import { useWasdPan } from '../hooks/useWasdPan.js';
|
|
21
|
-
import {
|
|
21
|
+
import { useGraph } from '@/system/provider.js';
|
|
22
22
|
import { useStore } from 'zustand';
|
|
23
23
|
import {
|
|
24
24
|
NodeContextMenu,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
SelectionContextMenu,
|
|
33
33
|
type ISelectionContextMenuProps
|
|
34
34
|
} from './contextMenus/selection.js';
|
|
35
|
-
import {
|
|
35
|
+
import { registerDefaults } from '@/generators/registerDefaults';
|
|
36
36
|
import { FloatingToolbar } from './FloatingToolbar';
|
|
37
37
|
import { layerId } from '@/annotations';
|
|
38
38
|
|
|
@@ -63,25 +63,36 @@ const isNodeVisibleInLayers = (
|
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
export const Flow: React.FC = () => {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
66
|
+
const session = useGraph();
|
|
67
|
+
const editor = session.editor;
|
|
68
|
+
const getGraphJson = useStore(session.flowStore, (x) => x.getGraph);
|
|
69
|
+
const specJson = useStore(editor.specStore, (x) => x.specs);
|
|
70
|
+
const showGrid = useStore(editor.systemSettings, (x) => x.showGrid);
|
|
71
|
+
const showMinimap = useStore(editor.systemSettings, (x) => x.showMinimap);
|
|
72
|
+
const snapToGrid = useStore(editor.systemSettings, (x) => x.snapGrid);
|
|
73
|
+
const gridSize = useStore(editor.systemSettings, (x) => x.gridSize);
|
|
74
|
+
const edgeTypes = useStore(session.flowStore, (x) => x.edgeTypes);
|
|
75
|
+
const nodeTypes = useStore(session.flowStore, (x) => x.nodeTypes);
|
|
76
|
+
const layers = useStore(session.layerStore, (x) => x.layers);
|
|
77
|
+
const nodeLayers = useStore(session.layerStore, (x) => x.nodeLayers);
|
|
78
|
+
const defaultLayerId = useStore(session.layerStore, (x) => x.defaultLayerId);
|
|
78
79
|
|
|
79
80
|
const ref = useRef<HTMLDivElement>(null);
|
|
80
|
-
const setRef = useStore(
|
|
81
|
+
const setRef = useStore(session.refStore, (x) => x.setRef);
|
|
82
|
+
|
|
83
|
+
// When this canvas is interacted with, mark its graph as focused so the shared
|
|
84
|
+
// side-panels (Variables, Traces, ...) bind to it. Lets two graphs be open at
|
|
85
|
+
// once without a singular "active graph" , focus simply follows interaction.
|
|
86
|
+
const focusThisGraph = useCallback(() => {
|
|
87
|
+
const active = editor.activeGraph.getState();
|
|
88
|
+
if (active.activeGraphId !== session.id) {
|
|
89
|
+
active.setActiveGraph(session.id);
|
|
90
|
+
}
|
|
91
|
+
}, [editor, session.id]);
|
|
81
92
|
|
|
82
93
|
const getReactFlowInstance = useCallback(
|
|
83
|
-
() =>
|
|
84
|
-
[
|
|
94
|
+
() => session.refStore.getState().getRef('reactflow'),
|
|
95
|
+
[session.refStore]
|
|
85
96
|
);
|
|
86
97
|
|
|
87
98
|
useWasdPan({ getReactFlowInstance });
|
|
@@ -98,13 +109,11 @@ export const Flow: React.FC = () => {
|
|
|
98
109
|
|
|
99
110
|
const graph = useMemo(() => getGraphJson(), []);
|
|
100
111
|
|
|
112
|
+
// Editor-level built-in content. Idempotent per editor, so opening multiple
|
|
113
|
+
// graph tabs (each a Flow canvas) registers it once rather than per mount.
|
|
101
114
|
useEffect(() => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return () => {
|
|
105
|
-
cleanupGenerators();
|
|
106
|
-
};
|
|
107
|
-
}, [system]);
|
|
115
|
+
registerDefaults(editor);
|
|
116
|
+
}, [editor]);
|
|
108
117
|
|
|
109
118
|
const { nodes, edges, onNodesChange, onEdgesChange } = useBehaveGraphFlow({
|
|
110
119
|
initialGraphJson: graph,
|
|
@@ -253,8 +262,10 @@ export const Flow: React.FC = () => {
|
|
|
253
262
|
return (
|
|
254
263
|
<>
|
|
255
264
|
<ReactFlow
|
|
265
|
+
id={session.id}
|
|
256
266
|
style={{ flex: 1 }}
|
|
257
267
|
ref={ref}
|
|
268
|
+
onPointerDownCapture={focusThisGraph}
|
|
258
269
|
onInit={setReactflowRef}
|
|
259
270
|
nodeTypes={nodeTypes}
|
|
260
271
|
edgeTypes={edgeTypes}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import { useStore } from 'zustand';
|
|
3
|
+
import { VscodeContextMenu } from '@vscode-elements/react-elements';
|
|
4
|
+
import { useGraph } from '@/system';
|
|
5
|
+
import type { CommandContext } from '@/store/commands';
|
|
6
|
+
import type { ContextMenuTarget } from '@/store/contextMenu';
|
|
7
|
+
|
|
8
|
+
type MenuData =
|
|
9
|
+
| { separator: true }
|
|
10
|
+
| { label: string; value: string; keybinding?: string };
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renders a context menu for a target from the editor's contextMenu registry,
|
|
14
|
+
* dispatching selections through the command registry. The three concrete menus
|
|
15
|
+
* (node/edge/selection) are thin wrappers that supply the target + context.
|
|
16
|
+
*/
|
|
17
|
+
export const DynamicContextMenu = ({
|
|
18
|
+
target,
|
|
19
|
+
context,
|
|
20
|
+
style
|
|
21
|
+
}: {
|
|
22
|
+
target: ContextMenuTarget;
|
|
23
|
+
context: Omit<CommandContext, 'editor' | 'session'>;
|
|
24
|
+
style?: CSSProperties;
|
|
25
|
+
}) => {
|
|
26
|
+
const session = useGraph();
|
|
27
|
+
const editor = session.editor;
|
|
28
|
+
|
|
29
|
+
// Subscribe so the menu re-renders when items/commands/keymap change.
|
|
30
|
+
useStore(editor.contextMenuStore, (s) => s.items);
|
|
31
|
+
useStore(editor.commandStore, (s) => s.commands);
|
|
32
|
+
useStore(editor.hotKeyStore, (s) => s.keymap);
|
|
33
|
+
|
|
34
|
+
const hotKeys = editor.hotKeyStore.getState();
|
|
35
|
+
|
|
36
|
+
const ctx: CommandContext = { editor, session, ...context };
|
|
37
|
+
|
|
38
|
+
const items = editor.contextMenuStore
|
|
39
|
+
.getState()
|
|
40
|
+
.getItems(target)
|
|
41
|
+
.filter((i) => !i.when || i.when(ctx));
|
|
42
|
+
|
|
43
|
+
const data: MenuData[] = [];
|
|
44
|
+
let lastGroup: unknown;
|
|
45
|
+
for (const item of items) {
|
|
46
|
+
if (data.length > 0 && item.group !== lastGroup) {
|
|
47
|
+
data.push({ separator: true });
|
|
48
|
+
}
|
|
49
|
+
lastGroup = item.group;
|
|
50
|
+
// Auto-detect the shortcut from the command's live keymap binding; fall
|
|
51
|
+
// back to a static hint only when the command has no bound key.
|
|
52
|
+
const derived = item.commandId
|
|
53
|
+
? hotKeys.getCommandKeybinding(item.commandId)
|
|
54
|
+
: undefined;
|
|
55
|
+
data.push({
|
|
56
|
+
label: typeof item.label === 'function' ? item.label(ctx) : item.label,
|
|
57
|
+
value: item.id,
|
|
58
|
+
keybinding: derived ?? item.keybinding
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (data.length === 0) return null;
|
|
63
|
+
|
|
64
|
+
const onSelect = (e: any) => {
|
|
65
|
+
const id = e?.detail?.value as string | undefined;
|
|
66
|
+
const item = items.find((i) => i.id === id);
|
|
67
|
+
if (!item) return;
|
|
68
|
+
if (item.onSelect) {
|
|
69
|
+
item.onSelect(ctx);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (item.commandId) {
|
|
73
|
+
void editor.commandStore.getState().run(item.commandId, ctx);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<VscodeContextMenu
|
|
79
|
+
show
|
|
80
|
+
onVscContextMenuSelect={onSelect}
|
|
81
|
+
style={{ zIndex: 2000, position: 'absolute', ...style }}
|
|
82
|
+
data={data}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.sidebar {
|
|
19
|
-
border-right: 1px solid var(--
|
|
19
|
+
border-right: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
20
20
|
background: var(--colors-bgPanel);
|
|
21
21
|
display: flex;
|
|
22
22
|
flex-direction: column;
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
.sidebarItem:hover {
|
|
44
|
-
background: var(--
|
|
44
|
+
background: var(--ds-button-hover-bg, #026ec1);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
.sidebarItemActive {
|
|
48
|
-
background: var(--
|
|
49
|
-
color: var(--
|
|
48
|
+
background: var(--ds-button-secondary-bg, #313131);
|
|
49
|
+
color: var(--ds-list-active-fg);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.main {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
align-items: center;
|
|
62
62
|
gap: 0.5rem;
|
|
63
63
|
padding: 0.5rem;
|
|
64
|
-
border-bottom: 1px solid var(--
|
|
64
|
+
border-bottom: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
.search {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
.nodeRow:hover {
|
|
113
|
-
background: var(--
|
|
113
|
+
background: var(--ds-button-hover-bg, #026ec1);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
.infoButton {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
.infoButton:hover {
|
|
131
|
-
background: var(--
|
|
131
|
+
background: var(--ds-button-secondary-bg, #313131);
|
|
132
132
|
opacity: 1 !important;
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
width: 28px;
|
|
146
146
|
height: 28px;
|
|
147
147
|
border-radius: 0.25rem;
|
|
148
|
-
border: 1px solid var(--
|
|
148
|
+
border: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
149
149
|
background: var(--colors-bgCanvas);
|
|
150
150
|
overflow: hidden;
|
|
151
151
|
display: flex;
|
|
@@ -210,8 +210,8 @@
|
|
|
210
210
|
font-size: 0.65rem;
|
|
211
211
|
padding: 0.1rem 0.35rem;
|
|
212
212
|
border-radius: 0.25rem;
|
|
213
|
-
background: var(--
|
|
214
|
-
color: var(--
|
|
213
|
+
background: var(--ds-badge-bg, #4d4d4d);
|
|
214
|
+
color: var(--ds-badge-fg, #ffffff);
|
|
215
215
|
opacity: 0.85;
|
|
216
216
|
}
|
|
217
217
|
|
|
@@ -223,7 +223,7 @@
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
.card:hover {
|
|
226
|
-
background: var(--
|
|
226
|
+
background: var(--ds-button-hover-bg, #026ec1);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
.cardInner {
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
width: 56px;
|
|
246
246
|
height: 56px;
|
|
247
247
|
border-radius: 0.25rem;
|
|
248
|
-
border: 1px solid var(--
|
|
248
|
+
border: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
249
249
|
overflow: hidden;
|
|
250
250
|
display: flex;
|
|
251
251
|
align-items: center;
|
|
@@ -260,7 +260,7 @@
|
|
|
260
260
|
|
|
261
261
|
.footer {
|
|
262
262
|
padding: 0.35rem 0.5rem;
|
|
263
|
-
border-top: 1px solid var(--
|
|
263
|
+
border-top: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
264
264
|
font-size: 0.75rem;
|
|
265
265
|
opacity: 0.8;
|
|
266
266
|
display: flex;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import type { EdgeChange } from 'reactflow';
|
|
4
|
-
import {
|
|
5
|
-
VscodeContextMenu,
|
|
6
|
-
VscodeContextMenuItem,
|
|
7
|
-
VscodeDivider
|
|
8
|
-
} from '@vscode-elements/react-elements';
|
|
9
|
-
import { useSystem } from '@/system';
|
|
2
|
+
import { DynamicContextMenu } from './DynamicContextMenu';
|
|
10
3
|
|
|
11
4
|
export interface IEdgeContextMenuProps extends CSSProperties {
|
|
12
5
|
edgeID: string;
|
|
@@ -14,95 +7,16 @@ export interface IEdgeContextMenuProps extends CSSProperties {
|
|
|
14
7
|
targetID: string;
|
|
15
8
|
}
|
|
16
9
|
|
|
10
|
+
/** Edge context menu , items from the contextMenu registry (target 'edge'). */
|
|
17
11
|
export const EdgeContextMenu = ({
|
|
18
12
|
edgeID,
|
|
19
13
|
sourceID,
|
|
20
14
|
targetID,
|
|
21
15
|
...rest
|
|
22
|
-
}: IEdgeContextMenuProps) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const x = node.position.x + (node.width ?? 0) / 2;
|
|
31
|
-
const y = node.position.y + (node.height ?? 0) / 2;
|
|
32
|
-
|
|
33
|
-
sys.refStore.getState().getRef('reactflow')?.setCenter(x, y, {
|
|
34
|
-
duration: 200,
|
|
35
|
-
zoom: 1
|
|
36
|
-
});
|
|
37
|
-
},
|
|
38
|
-
[sys]
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const findSource = useCallback(
|
|
42
|
-
() => centerOnNode(sourceID),
|
|
43
|
-
[centerOnNode, sourceID]
|
|
44
|
-
);
|
|
45
|
-
const findTarget = useCallback(
|
|
46
|
-
() => centerOnNode(targetID),
|
|
47
|
-
[centerOnNode, targetID]
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
const deleteEdge = useCallback(() => {
|
|
51
|
-
const change: EdgeChange = {
|
|
52
|
-
id: edgeID,
|
|
53
|
-
type: 'remove'
|
|
54
|
-
};
|
|
55
|
-
sys.edgeStore.getState().applyEdgeChanges([change]);
|
|
56
|
-
}, [edgeID, sys.edgeStore]);
|
|
57
|
-
|
|
58
|
-
const onSelect = useCallback(
|
|
59
|
-
(e: any) => {
|
|
60
|
-
switch (e.detail.value) {
|
|
61
|
-
case 'findSource':
|
|
62
|
-
findSource();
|
|
63
|
-
break;
|
|
64
|
-
case 'findTarget':
|
|
65
|
-
findTarget();
|
|
66
|
-
break;
|
|
67
|
-
case 'delete':
|
|
68
|
-
deleteEdge();
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
[deleteEdge, findSource, findTarget]
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<VscodeContextMenu
|
|
77
|
-
show
|
|
78
|
-
onVscContextMenuSelect={onSelect}
|
|
79
|
-
style={{ zIndex: 2000, position: 'absolute', ...rest }}
|
|
80
|
-
data={[
|
|
81
|
-
{
|
|
82
|
-
label: 'Find Source',
|
|
83
|
-
value: 'findSource'
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
label: 'Find Target',
|
|
87
|
-
value: 'findTarget'
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
separator: true
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
label: 'Delete',
|
|
94
|
-
value: 'delete'
|
|
95
|
-
}
|
|
96
|
-
]}
|
|
97
|
-
>
|
|
98
|
-
<VscodeContextMenuItem onClick={findSource}>
|
|
99
|
-
Find Source
|
|
100
|
-
</VscodeContextMenuItem>
|
|
101
|
-
<VscodeContextMenuItem onClick={findTarget}>
|
|
102
|
-
Find Target
|
|
103
|
-
</VscodeContextMenuItem>
|
|
104
|
-
<VscodeDivider />
|
|
105
|
-
<VscodeContextMenuItem onClick={deleteEdge}>Delete</VscodeContextMenuItem>
|
|
106
|
-
</VscodeContextMenu>
|
|
107
|
-
);
|
|
108
|
-
};
|
|
16
|
+
}: IEdgeContextMenuProps) => (
|
|
17
|
+
<DynamicContextMenu
|
|
18
|
+
target="edge"
|
|
19
|
+
context={{ edgeId: edgeID, sourceId: sourceID, targetId: targetID }}
|
|
20
|
+
style={rest}
|
|
21
|
+
/>
|
|
22
|
+
);
|