@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
|
@@ -1,155 +1,15 @@
|
|
|
1
|
-
import { useReactFlow } from 'reactflow';
|
|
2
1
|
import type { CSSProperties } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import clsx from 'classnames';
|
|
5
|
-
import {
|
|
6
|
-
VscodeContextMenu,
|
|
7
|
-
VscodeContextMenuItem,
|
|
8
|
-
VscodeDivider
|
|
9
|
-
} from '@vscode-elements/react-elements';
|
|
10
|
-
import { useSystem } from '@/system';
|
|
11
|
-
import { hidden, pinned } from '@/annotations';
|
|
2
|
+
import { DynamicContextMenu } from './DynamicContextMenu';
|
|
12
3
|
|
|
13
4
|
export interface INodeContextMenuProps extends CSSProperties {
|
|
14
5
|
nodeID: string;
|
|
15
6
|
}
|
|
16
7
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const isHidden =
|
|
26
|
-
currentNode && 'data' in currentNode
|
|
27
|
-
? (currentNode.data.annotations?.[hidden] ?? false)
|
|
28
|
-
: false;
|
|
29
|
-
const isPinned =
|
|
30
|
-
currentNode && 'data' in currentNode
|
|
31
|
-
? (currentNode.data.annotations?.[pinned] ?? false)
|
|
32
|
-
: false;
|
|
33
|
-
|
|
34
|
-
const focus = useCallback(() => {
|
|
35
|
-
const nodeSearch = sys.nodeStore.getState().nodes;
|
|
36
|
-
const reactFlowInstance = sys.refStore.getState().getRef('reactflow');
|
|
37
|
-
const nodes = nodeID
|
|
38
|
-
? nodeSearch.filter((x) => x.id === nodeID)
|
|
39
|
-
: nodeSearch.filter((x) => x.selected);
|
|
40
|
-
if (nodes) {
|
|
41
|
-
const focalCenter = nodes.reduce(
|
|
42
|
-
(acc, node) => {
|
|
43
|
-
return {
|
|
44
|
-
x: acc.x + node.position.x + (node.width || 0) / 2,
|
|
45
|
-
y: acc.y + node.position.y + (node.height || 0) / 2
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
{ x: 0, y: 0 }
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
reactFlowInstance?.setCenter(focalCenter.x, focalCenter.y, {
|
|
52
|
-
duration: 200,
|
|
53
|
-
zoom: 1
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}, [nodeID]);
|
|
57
|
-
|
|
58
|
-
const onResetTrace = useCallback(() => {
|
|
59
|
-
reactFlowInstance.setNodes((nodes) =>
|
|
60
|
-
nodes.map((x) => {
|
|
61
|
-
//Remove filtering
|
|
62
|
-
return {
|
|
63
|
-
...x,
|
|
64
|
-
className: clsx(x.className, {
|
|
65
|
-
filtered: false
|
|
66
|
-
})
|
|
67
|
-
};
|
|
68
|
-
})
|
|
69
|
-
);
|
|
70
|
-
}, [reactFlowInstance]);
|
|
71
|
-
|
|
72
|
-
const onSelect = useCallback(
|
|
73
|
-
(e: any) => {
|
|
74
|
-
switch (e.detail.value) {
|
|
75
|
-
case 'traceUpstream':
|
|
76
|
-
sys.actionStore.getState().actions.traceUpstream(nodeID);
|
|
77
|
-
break;
|
|
78
|
-
case 'traceDownstream':
|
|
79
|
-
sys.actionStore.getState().actions.traceDownstream(nodeID);
|
|
80
|
-
break;
|
|
81
|
-
case 'resetTrace':
|
|
82
|
-
sys.actionStore.getState().actions.resetTrace();
|
|
83
|
-
break;
|
|
84
|
-
|
|
85
|
-
case 'focus':
|
|
86
|
-
focus();
|
|
87
|
-
break;
|
|
88
|
-
|
|
89
|
-
case 'pin':
|
|
90
|
-
sys.actionStore.getState().actions.toggleNodePinned(nodeID);
|
|
91
|
-
break;
|
|
92
|
-
case 'hide':
|
|
93
|
-
sys.actionStore.getState().actions.toggleNodeHidden(nodeID);
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
[focus, nodeID, sys]
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
<VscodeContextMenu
|
|
102
|
-
show
|
|
103
|
-
onVscContextMenuSelect={onSelect}
|
|
104
|
-
style={{ zIndex: 2000, position: 'absolute', ...rest }}
|
|
105
|
-
data={[
|
|
106
|
-
{
|
|
107
|
-
label: 'Focus',
|
|
108
|
-
keybinding: 'Ctrl+Shift+F',
|
|
109
|
-
value: 'focus'
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
separator: true
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
label: 'Trace Upstream',
|
|
116
|
-
keybinding: 'Ctrl+Shift+R',
|
|
117
|
-
value: 'traceUpstream'
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
label: 'Trace Downstream',
|
|
121
|
-
keybinding: 'Ctrl+Shift+T',
|
|
122
|
-
value: 'traceDownstream'
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
separator: true
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
label: 'Reset Trace',
|
|
129
|
-
keybinding: 'Ctrl+Shift+G',
|
|
130
|
-
value: 'resetTrace'
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
{
|
|
134
|
-
separator: true
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
label: isPinned ? 'Unpin' : 'Pin',
|
|
138
|
-
value: 'pin'
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
label: isHidden ? 'Show' : 'Hide',
|
|
142
|
-
value: 'hide'
|
|
143
|
-
}
|
|
144
|
-
]}
|
|
145
|
-
>
|
|
146
|
-
<VscodeContextMenuItem onClick={focus}>Focus</VscodeContextMenuItem>
|
|
147
|
-
<VscodeDivider />
|
|
148
|
-
|
|
149
|
-
<VscodeContextMenuItem onClick={onResetTrace}>
|
|
150
|
-
Reset Trace
|
|
151
|
-
</VscodeContextMenuItem>
|
|
152
|
-
<VscodeDivider />
|
|
153
|
-
</VscodeContextMenu>
|
|
154
|
-
);
|
|
155
|
-
};
|
|
8
|
+
/**
|
|
9
|
+
* Node context menu. Items come from the editor's contextMenu registry (target
|
|
10
|
+
* 'node') and dispatch through the command registry , see store/contextMenu.ts
|
|
11
|
+
* and store/commands.ts to add or override entries.
|
|
12
|
+
*/
|
|
13
|
+
export const NodeContextMenu = ({ nodeID, ...rest }: INodeContextMenuProps) => (
|
|
14
|
+
<DynamicContextMenu target="node" context={{ nodeId: nodeID }} style={rest} />
|
|
15
|
+
);
|
|
@@ -1,77 +1,11 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
VscodeContextMenu,
|
|
5
|
-
VscodeContextMenuItem,
|
|
6
|
-
VscodeDivider
|
|
7
|
-
} from '@vscode-elements/react-elements';
|
|
8
|
-
import { useSystem } from '@/system';
|
|
2
|
+
import { DynamicContextMenu } from './DynamicContextMenu';
|
|
9
3
|
|
|
10
4
|
export interface ISelectionContextMenuProps extends CSSProperties {}
|
|
11
5
|
|
|
6
|
+
/** Selection context menu , items from the contextMenu registry ('selection'). */
|
|
12
7
|
export const SelectionContextMenu = ({
|
|
13
8
|
...rest
|
|
14
|
-
}: ISelectionContextMenuProps) =>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const onCopy = useCallback(() => {
|
|
18
|
-
sys.actionStore.getState().actions.copySelectionToClipboard();
|
|
19
|
-
}, [sys]);
|
|
20
|
-
|
|
21
|
-
const onPaste = useCallback(async () => {
|
|
22
|
-
await sys.actionStore.getState().actions.pasteFromClipboard();
|
|
23
|
-
}, [sys]);
|
|
24
|
-
|
|
25
|
-
const onGroup = useCallback(() => {
|
|
26
|
-
sys.actionStore.getState().actions.groupNodes();
|
|
27
|
-
}, [sys]);
|
|
28
|
-
|
|
29
|
-
const onSelect = useCallback(
|
|
30
|
-
(e: any) => {
|
|
31
|
-
switch (e.detail.value) {
|
|
32
|
-
case 'copy':
|
|
33
|
-
onCopy();
|
|
34
|
-
break;
|
|
35
|
-
case 'paste':
|
|
36
|
-
void onPaste();
|
|
37
|
-
break;
|
|
38
|
-
case 'group':
|
|
39
|
-
onGroup();
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
[onCopy, onGroup, onPaste]
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<VscodeContextMenu
|
|
48
|
-
show
|
|
49
|
-
onVscContextMenuSelect={onSelect}
|
|
50
|
-
style={{ zIndex: 2000, position: 'absolute', ...rest }}
|
|
51
|
-
data={[
|
|
52
|
-
{
|
|
53
|
-
label: 'Copy',
|
|
54
|
-
keybinding: 'Ctrl+C',
|
|
55
|
-
value: 'copy'
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
label: 'Paste',
|
|
59
|
-
keybinding: 'Ctrl+V',
|
|
60
|
-
value: 'paste'
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
separator: true
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
label: 'Group',
|
|
67
|
-
value: 'group'
|
|
68
|
-
}
|
|
69
|
-
]}
|
|
70
|
-
>
|
|
71
|
-
<VscodeContextMenuItem onClick={onCopy}>Copy</VscodeContextMenuItem>
|
|
72
|
-
<VscodeContextMenuItem onClick={onPaste}>Paste</VscodeContextMenuItem>
|
|
73
|
-
<VscodeDivider />
|
|
74
|
-
<VscodeContextMenuItem onClick={onGroup}>Group</VscodeContextMenuItem>
|
|
75
|
-
</VscodeContextMenu>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
9
|
+
}: ISelectionContextMenuProps) => (
|
|
10
|
+
<DynamicContextMenu target="selection" context={{}} style={rest} />
|
|
11
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ControlProps } from '@/store/controls';
|
|
2
|
+
import { JsonEditor } from 'json-edit-react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The actual `any`-typed value editor. Split into its own module so the heavy
|
|
6
|
+
* `json-edit-react` dependency (~50 kB) is loaded lazily by [`AnyControl`](./index.tsx)
|
|
7
|
+
* only when an `any` control is first rendered, instead of sitting in the
|
|
8
|
+
* editor's first-paint bundle.
|
|
9
|
+
*/
|
|
10
|
+
export const AnyControlImpl = (props: ControlProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<JsonEditor data={props.value} setData={(data) => props.onChange(data)} />
|
|
13
|
+
);
|
|
14
|
+
};
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { lazy, Suspense } from 'react';
|
|
1
2
|
import type { ControlProps } from '@/store/controls';
|
|
2
|
-
|
|
3
|
+
|
|
4
|
+
// `json-edit-react` is a sizeable dependency and this is the *default* control
|
|
5
|
+
// (used whenever a socket has no specific control), so eager-importing it puts
|
|
6
|
+
// it on the editor's first-paint critical path. Load it lazily instead: the
|
|
7
|
+
// node still renders immediately, and the JSON editor swaps in once its chunk
|
|
8
|
+
// arrives.
|
|
9
|
+
const LazyAnyControl = lazy(() =>
|
|
10
|
+
import('./AnyControlImpl').then((m) => ({ default: m.AnyControlImpl }))
|
|
11
|
+
);
|
|
3
12
|
|
|
4
13
|
export const AnyControl = (props: ControlProps) => {
|
|
5
14
|
return (
|
|
6
|
-
<
|
|
15
|
+
<Suspense fallback={null}>
|
|
16
|
+
<LazyAnyControl {...props} />
|
|
17
|
+
</Suspense>
|
|
7
18
|
);
|
|
8
19
|
};
|
|
@@ -17,6 +17,74 @@ interface ControlPoint {
|
|
|
17
17
|
y: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/** The reactflow path builder that backs a given edge type when there are no
|
|
21
|
+
* control points. Unknown types fall back to the better-bezier builder. */
|
|
22
|
+
function edgeFnForType(edgeType: string) {
|
|
23
|
+
switch (edgeType) {
|
|
24
|
+
case EDGE_TYPE.simpleBezier:
|
|
25
|
+
return getSimpleBezierPath;
|
|
26
|
+
case EDGE_TYPE.smoothStep:
|
|
27
|
+
return getSmoothStepPath;
|
|
28
|
+
case EDGE_TYPE.straight:
|
|
29
|
+
return getStraightPath;
|
|
30
|
+
case EDGE_TYPE.bezier:
|
|
31
|
+
default:
|
|
32
|
+
return getBetterBezierPath;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Straight polyline through every point. */
|
|
37
|
+
function straightPathThrough(points: ControlPoint[]): string {
|
|
38
|
+
return points
|
|
39
|
+
.map((p, i) => (i === 0 ? `M ${p.x},${p.y}` : `L ${p.x},${p.y}`))
|
|
40
|
+
.join(' ');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Orthogonal "smooth step" path that jogs at the midpoint of each segment. */
|
|
44
|
+
function smoothStepPathThrough(points: ControlPoint[]): string {
|
|
45
|
+
let path = `M ${points[0]?.x},${points[0]?.y}`;
|
|
46
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
47
|
+
const current = points[i];
|
|
48
|
+
const next = points[i + 1];
|
|
49
|
+
if (!current || !next) continue;
|
|
50
|
+
const midX = (current.x + next.x) / 2;
|
|
51
|
+
path += ` L ${midX},${current.y} L ${midX},${next.y}`;
|
|
52
|
+
}
|
|
53
|
+
path += ` L ${points[points.length - 1]?.x},${points[points.length - 1]?.y}`;
|
|
54
|
+
return path;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Curved path through every point, degrading to line/quadratic for 2/3 points. */
|
|
58
|
+
function bezierPathThrough(points: ControlPoint[]): string {
|
|
59
|
+
if (points.length === 2) {
|
|
60
|
+
return `M ${points[0]?.x},${points[0]?.y} L ${points[1]?.x},${points[1]?.y}`;
|
|
61
|
+
}
|
|
62
|
+
if (points.length === 3) {
|
|
63
|
+
return `M ${points[0]?.x},${points[0]?.y} Q ${points[1]?.x},${points[1]?.y} ${points[2]?.x},${points[2]?.y}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// For multiple control points, chain quadratic segments and finish with a line.
|
|
67
|
+
let path = `M ${points[0]?.x},${points[0]?.y}`;
|
|
68
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
69
|
+
const p1 = points[i + 1];
|
|
70
|
+
if (!p1) continue;
|
|
71
|
+
|
|
72
|
+
if (i === points.length - 2) {
|
|
73
|
+
path += ` L ${p1.x},${p1.y}`;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
path += ` Q ${p1.x},${p1.y}`;
|
|
78
|
+
const p2 = points[i + 2];
|
|
79
|
+
if (p2) {
|
|
80
|
+
const midX = (p1.x + p2.x) / 2;
|
|
81
|
+
const midY = (p1.y + p2.y) / 2;
|
|
82
|
+
path += ` ${midX},${midY}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return path;
|
|
86
|
+
}
|
|
87
|
+
|
|
20
88
|
// Generate path for different edge types with control points
|
|
21
89
|
function generatePathWithControlPoints(
|
|
22
90
|
sourceX: number,
|
|
@@ -29,26 +97,8 @@ function generatePathWithControlPoints(
|
|
|
29
97
|
_targetPosition?: Position
|
|
30
98
|
): string {
|
|
31
99
|
if (controlPoints.length === 0) {
|
|
32
|
-
// No control points, use default edge type
|
|
33
|
-
|
|
34
|
-
switch (edgeType) {
|
|
35
|
-
case EDGE_TYPE.bezier:
|
|
36
|
-
edgeFn = getBetterBezierPath;
|
|
37
|
-
break;
|
|
38
|
-
case EDGE_TYPE.simpleBezier:
|
|
39
|
-
edgeFn = getSimpleBezierPath;
|
|
40
|
-
break;
|
|
41
|
-
case EDGE_TYPE.smoothStep:
|
|
42
|
-
edgeFn = getSmoothStepPath;
|
|
43
|
-
break;
|
|
44
|
-
case EDGE_TYPE.straight:
|
|
45
|
-
edgeFn = getStraightPath;
|
|
46
|
-
break;
|
|
47
|
-
default:
|
|
48
|
-
edgeFn = getBetterBezierPath;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const [path] = edgeFn({
|
|
100
|
+
// No control points, use the default builder for the edge type.
|
|
101
|
+
const [path] = edgeFnForType(edgeType)({
|
|
52
102
|
sourceX,
|
|
53
103
|
sourceY,
|
|
54
104
|
sourcePosition: _sourcePosition,
|
|
@@ -67,56 +117,12 @@ function generatePathWithControlPoints(
|
|
|
67
117
|
];
|
|
68
118
|
|
|
69
119
|
if (edgeType === EDGE_TYPE.straight) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
);
|
|
74
|
-
return pathParts.join(' ');
|
|
75
|
-
} else if (edgeType === EDGE_TYPE.smoothStep) {
|
|
76
|
-
// Smooth step style through control points
|
|
77
|
-
let path = `M ${allPoints[0]?.x},${allPoints[0]?.y}`;
|
|
78
|
-
for (let i = 0; i < allPoints.length - 1; i++) {
|
|
79
|
-
const current = allPoints[i];
|
|
80
|
-
const next = allPoints[i + 1];
|
|
81
|
-
if (!current || !next) continue;
|
|
82
|
-
const midX = (current.x + next.x) / 2;
|
|
83
|
-
// Create smooth step
|
|
84
|
-
path += ` L ${midX},${current.y} L ${midX},${next.y}`;
|
|
85
|
-
}
|
|
86
|
-
path += ` L ${allPoints[allPoints.length - 1]?.x},${allPoints[allPoints.length - 1]?.y}`;
|
|
87
|
-
return path;
|
|
88
|
-
} else {
|
|
89
|
-
// Bezier curve through all points
|
|
90
|
-
if (allPoints.length === 2) {
|
|
91
|
-
return `M ${allPoints[0]?.x},${allPoints[0]?.y} L ${allPoints[1]?.x},${allPoints[1]?.y}`;
|
|
92
|
-
} else if (allPoints.length === 3) {
|
|
93
|
-
return `M ${allPoints[0]?.x},${allPoints[0]?.y} Q ${allPoints[1]?.x},${allPoints[1]?.y} ${allPoints[2]?.x},${allPoints[2]?.y}`;
|
|
94
|
-
} else {
|
|
95
|
-
// For multiple control points, use cubic bezier segments
|
|
96
|
-
let path = `M ${allPoints[0]?.x},${allPoints[0]?.y}`;
|
|
97
|
-
for (let i = 0; i < allPoints.length - 1; i++) {
|
|
98
|
-
const p1 = allPoints[i + 1];
|
|
99
|
-
if (!p1) continue;
|
|
100
|
-
|
|
101
|
-
if (i === allPoints.length - 2) {
|
|
102
|
-
// Last segment
|
|
103
|
-
path += ` L ${p1.x},${p1.y}`;
|
|
104
|
-
} else {
|
|
105
|
-
// Smooth curve using quadratic bezier
|
|
106
|
-
path += ` Q ${p1.x},${p1.y}`;
|
|
107
|
-
if (i < allPoints.length - 2) {
|
|
108
|
-
const p2 = allPoints[i + 2];
|
|
109
|
-
if (p2) {
|
|
110
|
-
const midX = (p1.x + p2.x) / 2;
|
|
111
|
-
const midY = (p1.y + p2.y) / 2;
|
|
112
|
-
path += ` ${midX},${midY}`;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return path;
|
|
118
|
-
}
|
|
120
|
+
return straightPathThrough(allPoints);
|
|
121
|
+
}
|
|
122
|
+
if (edgeType === EDGE_TYPE.smoothStep) {
|
|
123
|
+
return smoothStepPathThrough(allPoints);
|
|
119
124
|
}
|
|
125
|
+
return bezierPathThrough(allPoints);
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
type CustomEdgeProps = EdgeProps & {
|
|
@@ -6,7 +6,12 @@ import { Reduce, Maximize, Xmark } from 'iconoir-react';
|
|
|
6
6
|
import { useSystem } from '@/system/provider.js';
|
|
7
7
|
import { MenuBar } from '../menubar';
|
|
8
8
|
import { useStore } from 'zustand';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
findGraphPanel,
|
|
11
|
+
collectGraphSessionIds,
|
|
12
|
+
isGraphTabId,
|
|
13
|
+
sessionIdFromTabId
|
|
14
|
+
} from './utils';
|
|
10
15
|
|
|
11
16
|
import styles from './index.module.css';
|
|
12
17
|
import { NotificationProvider } from '../notifications';
|
|
@@ -97,7 +102,25 @@ export const LayoutController = (props: {}) => {
|
|
|
97
102
|
if (graphContainer?.activeId) {
|
|
98
103
|
//Get the active Id to find the currently selected graph
|
|
99
104
|
setCurrentPanel(graphContainer.activeId!);
|
|
105
|
+
|
|
106
|
+
// Keep the editor's active graph in sync with the focused graph tab so
|
|
107
|
+
// panels bound via useActiveGraph() rebind to it.
|
|
108
|
+
if (isGraphTabId(graphContainer.activeId)) {
|
|
109
|
+
system.activeGraph
|
|
110
|
+
.getState()
|
|
111
|
+
.setActiveGraph(sessionIdFromTabId(graphContainer.activeId));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Dispose sessions whose tabs were closed in this layout change.
|
|
116
|
+
const before = collectGraphSessionIds(layout);
|
|
117
|
+
const after = collectGraphSessionIds(newLayout);
|
|
118
|
+
for (const id of before) {
|
|
119
|
+
if (!after.has(id)) {
|
|
120
|
+
system.disposeSession(id);
|
|
121
|
+
}
|
|
100
122
|
}
|
|
123
|
+
|
|
101
124
|
setLayout(newLayout);
|
|
102
125
|
};
|
|
103
126
|
|
|
@@ -1,8 +1,51 @@
|
|
|
1
1
|
import type { BoxBase, LayoutBase, PanelBase, TabData } from 'rc-dock';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
)
|
|
3
|
+
/**
|
|
4
|
+
* Tab-id convention for graph tabs. The default graph uses the bare id `graph`
|
|
5
|
+
* (session id `graph`); every other graph uses `graph:<sessionId>`. These three
|
|
6
|
+
* helpers are the single source of truth for the convention.
|
|
7
|
+
*/
|
|
8
|
+
const GRAPH_TAB_PREFIX = 'graph:';
|
|
9
|
+
export const DEFAULT_GRAPH_ID = 'graph';
|
|
10
|
+
|
|
11
|
+
export function isGraphTabId(id: string | undefined): id is string {
|
|
12
|
+
return !!id && (id === DEFAULT_GRAPH_ID || id.startsWith(GRAPH_TAB_PREFIX));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function sessionIdFromTabId(tabId: string): string {
|
|
16
|
+
return tabId === DEFAULT_GRAPH_ID
|
|
17
|
+
? DEFAULT_GRAPH_ID
|
|
18
|
+
: tabId.slice(GRAPH_TAB_PREFIX.length);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function tabIdForSession(sessionId: string): string {
|
|
22
|
+
return sessionId === DEFAULT_GRAPH_ID
|
|
23
|
+
? DEFAULT_GRAPH_ID
|
|
24
|
+
: `${GRAPH_TAB_PREFIX}${sessionId}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Collect the session ids of every graph tab present in a layout. */
|
|
28
|
+
export function collectGraphSessionIds(layout: LayoutBase): Set<string> {
|
|
29
|
+
const ids = new Set<string>();
|
|
30
|
+
const visit = (base?: BoxBase | PanelBase) => {
|
|
31
|
+
if (!base) return;
|
|
32
|
+
const panel = base as PanelBase;
|
|
33
|
+
if (panel.tabs) {
|
|
34
|
+
for (const tab of panel.tabs) {
|
|
35
|
+
if (isGraphTabId(tab.id)) ids.add(sessionIdFromTabId(tab.id!));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const box = base as BoxBase;
|
|
39
|
+
if (box.children) box.children.forEach(visit);
|
|
40
|
+
};
|
|
41
|
+
visit(layout.dockbox);
|
|
42
|
+
visit(layout.floatbox);
|
|
43
|
+
visit(layout.maxbox);
|
|
44
|
+
visit(layout.windowbox);
|
|
45
|
+
return ids;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function recurseFindGraphPanel(base: BoxBase | PanelBase): PanelBase | null {
|
|
6
49
|
if (base.id === 'graphs') {
|
|
7
50
|
return base as PanelBase;
|
|
8
51
|
}
|