@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/src/store/hotKeys.tsx
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { applyDagreLayout } from '@/layout/dagre';
|
|
2
|
-
import { applyElkLayout } from '@/layout/elk';
|
|
3
1
|
import type { System } from '@/system';
|
|
4
2
|
import { create } from 'zustand';
|
|
5
3
|
|
|
@@ -9,284 +7,317 @@ export type HotkeyStore = {
|
|
|
9
7
|
keymap: Record<string, string | string[]>;
|
|
10
8
|
handlers: Record<string, Handler>;
|
|
11
9
|
descriptions: Record<string, string>;
|
|
10
|
+
/** Reverse map: command id -> keymap action, so any UI surface that runs a
|
|
11
|
+
* command can look up its live shortcut without knowing the action name. */
|
|
12
|
+
commandToAction: Record<string, string>;
|
|
12
13
|
register(val: {
|
|
13
14
|
action: string;
|
|
14
15
|
trigger: string | string[];
|
|
15
16
|
description?: string;
|
|
16
17
|
handler?: Handler;
|
|
18
|
+
/** Command id this binding invokes; enables shortcut hints in menus. */
|
|
19
|
+
command?: string;
|
|
17
20
|
}): void;
|
|
18
21
|
registerDescription(action: string, description: string): void;
|
|
19
22
|
registerHandler(action: string, handler: Handler): void;
|
|
23
|
+
/**
|
|
24
|
+
* Formatted shortcut hint for a command id (e.g. `'Ctrl+Shift+←'`), derived
|
|
25
|
+
* live from the keymap, or undefined if the command has no bound key.
|
|
26
|
+
*/
|
|
27
|
+
getCommandKeybinding(commandId: string): string | undefined;
|
|
20
28
|
};
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
PASTE: ['command+v', 'ctrl+v'],
|
|
33
|
-
DELETE: ['delete', 'del', 'backspace'],
|
|
34
|
-
UNDO: ['command+z', 'ctrl+z'],
|
|
35
|
-
REDO: ['command+shift+z', 'ctrl+shift+z'],
|
|
36
|
-
SAVE_VIEWPORT: [
|
|
37
|
-
'command+1',
|
|
38
|
-
'command+2',
|
|
39
|
-
'command+3',
|
|
40
|
-
'command+4',
|
|
41
|
-
'command+5',
|
|
42
|
-
'command+6',
|
|
43
|
-
'command+7',
|
|
44
|
-
'command+8',
|
|
45
|
-
'command+9',
|
|
46
|
-
'ctrl+1',
|
|
47
|
-
'ctrl+2',
|
|
48
|
-
'ctrl+3',
|
|
49
|
-
'ctrl+4',
|
|
50
|
-
'ctrl+5',
|
|
51
|
-
'ctrl+6',
|
|
52
|
-
'ctrl+7',
|
|
53
|
-
'ctrl+8',
|
|
54
|
-
'ctrl+9'
|
|
55
|
-
],
|
|
56
|
-
RECALL_VIEWPORT: ['1', '2', '3', '4', '5', '6', '7', '8', '9'],
|
|
57
|
-
ZOOM_IN: ['ctrl+plus', 'command+plus'],
|
|
58
|
-
ZOOM_OUT: ['command+-', 'ctrl+-'],
|
|
59
|
-
ZOOM_RESET: 'ctrl+0',
|
|
60
|
-
TOGGLE_GRID: ['command+shift+g', 'ctrl+shift+g'],
|
|
61
|
-
TOGGLE_MINIMAP: ['command+shift+m', 'ctrl+shift+m'],
|
|
62
|
-
TOGGLE_SNAP_GRID: ['command+shift+s', 'ctrl+shift+s'],
|
|
63
|
-
FIT_VIEW: ['f'],
|
|
64
|
-
TRACE_DOWNSTREAM: 'ctrl+shift+right',
|
|
65
|
-
TRACE_UPSTREAM: 'ctrl+shift+left'
|
|
66
|
-
},
|
|
67
|
-
descriptions: {
|
|
68
|
-
TRACE_DOWNSTREAM: 'Trace Downstream',
|
|
69
|
-
TRACE_UPSTREAM: 'Trace Upstream',
|
|
70
|
-
AUTO_LAYOUT: 'Auto Layout',
|
|
71
|
-
COPY: 'Copy',
|
|
72
|
-
PASTE: 'Paste',
|
|
73
|
-
DELETE: 'Delete',
|
|
74
|
-
UNDO: 'Undo',
|
|
75
|
-
REDO: 'Redo',
|
|
76
|
-
SELECT_ALL: 'Select All',
|
|
77
|
-
DUPLICATE: 'Duplicate',
|
|
78
|
-
GROUP: 'Group',
|
|
79
|
-
SAVE: 'Save',
|
|
80
|
-
FIND: 'Find',
|
|
81
|
-
FIT_VIEW: 'Fit View',
|
|
82
|
-
ZOOM_IN: 'Zoom In',
|
|
83
|
-
ZOOM_OUT: 'Zoom Out',
|
|
84
|
-
ZOOM_RESET: 'Zoom Reset',
|
|
85
|
-
TOGGLE_GRID: 'Toggle Grid',
|
|
86
|
-
TOGGLE_MINIMAP: 'Toggle Minimap',
|
|
87
|
-
TOGGLE_SNAP_GRID: 'Toggle Snap Grid',
|
|
88
|
-
SAVE_VIEWPORT: 'Save Viewport',
|
|
89
|
-
RECALL_VIEWPORT: 'Recall Viewport'
|
|
90
|
-
},
|
|
91
|
-
handlers: {
|
|
92
|
-
SAVE: (event) => {
|
|
93
|
-
if (event) {
|
|
94
|
-
event.preventDefault();
|
|
95
|
-
event.stopPropagation();
|
|
96
|
-
}
|
|
97
|
-
sys.actionStore.getState().actions.save();
|
|
98
|
-
},
|
|
30
|
+
const MODIFIER_LABELS: Record<string, string> = {
|
|
31
|
+
ctrl: 'Ctrl',
|
|
32
|
+
control: 'Ctrl',
|
|
33
|
+
cmd: 'Cmd',
|
|
34
|
+
command: 'Cmd',
|
|
35
|
+
meta: 'Cmd',
|
|
36
|
+
shift: 'Shift',
|
|
37
|
+
alt: 'Alt',
|
|
38
|
+
option: 'Alt'
|
|
39
|
+
};
|
|
99
40
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
41
|
+
const KEY_LABELS: Record<string, string> = {
|
|
42
|
+
left: '←',
|
|
43
|
+
right: '→',
|
|
44
|
+
up: '↑',
|
|
45
|
+
down: '↓',
|
|
46
|
+
plus: '+',
|
|
47
|
+
minus: '-',
|
|
48
|
+
esc: 'Esc',
|
|
49
|
+
escape: 'Esc',
|
|
50
|
+
del: 'Del',
|
|
51
|
+
delete: 'Del',
|
|
52
|
+
backspace: 'Backspace',
|
|
53
|
+
enter: 'Enter',
|
|
54
|
+
return: 'Enter',
|
|
55
|
+
space: 'Space',
|
|
56
|
+
tab: 'Tab'
|
|
57
|
+
};
|
|
103
58
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
PASTE: async (event) => {
|
|
112
|
-
if (event) {
|
|
113
|
-
event.preventDefault();
|
|
114
|
-
event.stopPropagation();
|
|
115
|
-
}
|
|
59
|
+
const formatKeyPart = (part: string): string => {
|
|
60
|
+
const lower = part.toLowerCase();
|
|
61
|
+
if (MODIFIER_LABELS[lower]) return MODIFIER_LABELS[lower];
|
|
62
|
+
if (KEY_LABELS[lower]) return KEY_LABELS[lower];
|
|
63
|
+
if (part.length === 1) return part.toUpperCase();
|
|
64
|
+
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
65
|
+
};
|
|
116
66
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
FIT_VIEW: (event) => {
|
|
142
|
-
if (event) {
|
|
143
|
-
event.preventDefault();
|
|
144
|
-
const reactFlowInstance = sys.refStore.getState().getRef('reactflow');
|
|
145
|
-
reactFlowInstance?.fitView({
|
|
146
|
-
padding: 0.2,
|
|
147
|
-
includeHiddenNodes: true
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
},
|
|
67
|
+
/**
|
|
68
|
+
* Format a keymap trigger into a human-readable hint, e.g. `'ctrl+shift+left'`
|
|
69
|
+
* -> `'Ctrl+Shift+←'`. When several triggers are bound (cross-platform), prefer
|
|
70
|
+
* the `ctrl` variant so menus show one stable shortcut. Returns undefined for an
|
|
71
|
+
* empty/unset trigger.
|
|
72
|
+
*/
|
|
73
|
+
export const formatTrigger = (
|
|
74
|
+
trigger: string | string[] | undefined
|
|
75
|
+
): string | undefined => {
|
|
76
|
+
let chosen: string | undefined;
|
|
77
|
+
if (Array.isArray(trigger)) {
|
|
78
|
+
chosen =
|
|
79
|
+
trigger.find((t) => t.toLowerCase().includes('ctrl')) ?? trigger[0];
|
|
80
|
+
} else {
|
|
81
|
+
chosen = trigger;
|
|
82
|
+
}
|
|
83
|
+
if (!chosen) return undefined;
|
|
84
|
+
return chosen
|
|
85
|
+
.split('+')
|
|
86
|
+
.map((p) => formatKeyPart(p.trim()))
|
|
87
|
+
.join('+');
|
|
88
|
+
};
|
|
151
89
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const key = event.key; // Get pressed key (e.g., '1', '2', etc.)
|
|
174
|
-
const viewportIndex = parseInt(key) - 1; // Calculate 0-based index
|
|
90
|
+
/**
|
|
91
|
+
* Declarative default hotkey bindings. One table is the single source of truth
|
|
92
|
+
* for the keymap, descriptions, and handlers (previously three objects that had
|
|
93
|
+
* to be kept in sync). Most bindings just dispatch a registered command by id;
|
|
94
|
+
* the few that need key-specific context (the pressed node / number key) use a
|
|
95
|
+
* custom `handler`.
|
|
96
|
+
*/
|
|
97
|
+
type HotkeyBinding = {
|
|
98
|
+
action: string;
|
|
99
|
+
trigger: string | string[];
|
|
100
|
+
description: string;
|
|
101
|
+
/** Dispatch this command id (with preventDefault/stopPropagation). */
|
|
102
|
+
command?: string;
|
|
103
|
+
/**
|
|
104
|
+
* For handler-based bindings, the command id this key maps to. Used only to
|
|
105
|
+
* surface the shortcut hint in menus; does not affect what the key does.
|
|
106
|
+
*/
|
|
107
|
+
hintCommand?: string;
|
|
108
|
+
/** Or run custom key-specific logic. */
|
|
109
|
+
handler?: (sys: System, e?: KeyboardEvent) => void;
|
|
110
|
+
};
|
|
175
111
|
|
|
176
|
-
|
|
177
|
-
graph.setViewport(viewportIndex, currentViewport);
|
|
178
|
-
sys.notifications.info(`Saved viewport ${viewportIndex + 1}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
RECALL_VIEWPORT: (event) => {
|
|
184
|
-
if (event) {
|
|
185
|
-
event.preventDefault();
|
|
186
|
-
const key = event.key;
|
|
187
|
-
const graph = sys.graph;
|
|
188
|
-
const reactFlowInstance = sys.refStore.getState().getRef('reactflow');
|
|
112
|
+
const NUMBER_TRIGGERS = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
189
113
|
|
|
190
|
-
|
|
114
|
+
const traceFromSelection =
|
|
115
|
+
(commandId: string) => (sys: System, e?: KeyboardEvent) => {
|
|
116
|
+
e?.preventDefault();
|
|
117
|
+
e?.stopPropagation();
|
|
118
|
+
const selection = sys.selectionStore.getState().selectedNodeId;
|
|
119
|
+
if (selection) sys.runCommand(commandId, { nodeId: selection });
|
|
120
|
+
};
|
|
191
121
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
122
|
+
const defaultBindings: HotkeyBinding[] = [
|
|
123
|
+
{
|
|
124
|
+
action: 'SAVE',
|
|
125
|
+
trigger: 'ctrl+s',
|
|
126
|
+
description: 'Save',
|
|
127
|
+
command: 'editor.save'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
action: 'GROUP',
|
|
131
|
+
trigger: 'ctrl+g',
|
|
132
|
+
description: 'Group',
|
|
133
|
+
command: 'selection.group'
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
action: 'COPY',
|
|
137
|
+
trigger: ['command+c', 'ctrl+c'],
|
|
138
|
+
description: 'Copy',
|
|
139
|
+
command: 'selection.copy'
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
action: 'PASTE',
|
|
143
|
+
trigger: ['command+v', 'ctrl+v'],
|
|
144
|
+
description: 'Paste',
|
|
145
|
+
command: 'selection.paste'
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
action: 'SELECT_ALL',
|
|
149
|
+
trigger: 'ctrl+a',
|
|
150
|
+
description: 'Select All',
|
|
151
|
+
command: 'selection.selectAll'
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
action: 'UNDO',
|
|
155
|
+
trigger: ['command+z', 'ctrl+z'],
|
|
156
|
+
description: 'Undo',
|
|
157
|
+
command: 'editor.undo'
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
action: 'REDO',
|
|
161
|
+
trigger: ['command+shift+z', 'ctrl+shift+z'],
|
|
162
|
+
description: 'Redo',
|
|
163
|
+
command: 'editor.redo'
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
action: 'FIND',
|
|
167
|
+
trigger: ['ctrl+f', 'command+f'],
|
|
168
|
+
description: 'Find',
|
|
169
|
+
command: 'editor.find'
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
action: 'AUTO_LAYOUT',
|
|
173
|
+
trigger: 'shift+alt+f',
|
|
174
|
+
description: 'Auto Layout',
|
|
175
|
+
command: 'editor.autoLayout'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
action: 'FIT_VIEW',
|
|
179
|
+
trigger: ['f'],
|
|
180
|
+
description: 'Fit View',
|
|
181
|
+
command: 'view.fit'
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
action: 'ZOOM_IN',
|
|
185
|
+
trigger: ['ctrl+plus', 'command+plus'],
|
|
186
|
+
description: 'Zoom In',
|
|
187
|
+
command: 'view.zoomIn'
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
action: 'ZOOM_OUT',
|
|
191
|
+
trigger: ['command+-', 'ctrl+-'],
|
|
192
|
+
description: 'Zoom Out',
|
|
193
|
+
command: 'view.zoomOut'
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
action: 'ZOOM_RESET',
|
|
197
|
+
trigger: 'ctrl+0',
|
|
198
|
+
description: 'Zoom Reset',
|
|
199
|
+
command: 'view.zoomReset'
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
action: 'TOGGLE_GRID',
|
|
203
|
+
trigger: ['command+shift+g', 'ctrl+shift+g'],
|
|
204
|
+
description: 'Toggle Grid',
|
|
205
|
+
command: 'view.toggleGrid'
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
action: 'TOGGLE_MINIMAP',
|
|
209
|
+
trigger: ['command+shift+m', 'ctrl+shift+m'],
|
|
210
|
+
description: 'Toggle Minimap',
|
|
211
|
+
command: 'view.toggleMinimap'
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
action: 'TOGGLE_SNAP_GRID',
|
|
215
|
+
trigger: ['command+shift+s', 'ctrl+shift+s'],
|
|
216
|
+
description: 'Toggle Snap Grid',
|
|
217
|
+
command: 'view.toggleSnapGrid'
|
|
218
|
+
},
|
|
219
|
+
// Bound for the keymap UI; behaviour handled elsewhere or not yet implemented.
|
|
220
|
+
{
|
|
221
|
+
action: 'DUPLICATE',
|
|
222
|
+
trigger: ['command+d', 'ctrl+d'],
|
|
223
|
+
description: 'Duplicate'
|
|
224
|
+
},
|
|
225
|
+
// Deletion is handled natively by reactflow; listed here for the keymap UI.
|
|
226
|
+
{
|
|
227
|
+
action: 'DELETE',
|
|
228
|
+
trigger: ['delete', 'del', 'backspace'],
|
|
229
|
+
description: 'Delete'
|
|
230
|
+
},
|
|
231
|
+
// Context-aware handlers.
|
|
232
|
+
{
|
|
233
|
+
action: 'TRACE_UPSTREAM',
|
|
234
|
+
trigger: 'ctrl+shift+left',
|
|
235
|
+
description: 'Trace Upstream',
|
|
236
|
+
hintCommand: 'node.traceUpstream',
|
|
237
|
+
handler: traceFromSelection('node.traceUpstream')
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
action: 'TRACE_DOWNSTREAM',
|
|
241
|
+
trigger: 'ctrl+shift+right',
|
|
242
|
+
description: 'Trace Downstream',
|
|
243
|
+
hintCommand: 'node.traceDownstream',
|
|
244
|
+
handler: traceFromSelection('node.traceDownstream')
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
action: 'SAVE_VIEWPORT',
|
|
248
|
+
trigger: [
|
|
249
|
+
...NUMBER_TRIGGERS.map((n) => `command+${n}`),
|
|
250
|
+
...NUMBER_TRIGGERS.map((n) => `ctrl+${n}`)
|
|
251
|
+
],
|
|
252
|
+
description: 'Save Viewport',
|
|
253
|
+
handler: (sys, event) => {
|
|
254
|
+
event?.preventDefault();
|
|
255
|
+
const reactFlowInstance = sys.refStore.getState().getRef('reactflow');
|
|
256
|
+
if (!event || !reactFlowInstance) return;
|
|
257
|
+
const viewportIndex = parseInt(event.key) - 1;
|
|
258
|
+
if (viewportIndex >= 0 && viewportIndex < 9) {
|
|
259
|
+
sys.graph.setViewport(viewportIndex, reactFlowInstance.getViewport());
|
|
260
|
+
sys.notifications.info(`Saved viewport ${viewportIndex + 1}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
action: 'RECALL_VIEWPORT',
|
|
266
|
+
trigger: NUMBER_TRIGGERS,
|
|
267
|
+
description: 'Recall Viewport',
|
|
268
|
+
handler: (sys, event) => {
|
|
269
|
+
event?.preventDefault();
|
|
270
|
+
const reactFlowInstance = sys.refStore.getState().getRef('reactflow');
|
|
271
|
+
if (!event || !reactFlowInstance) return;
|
|
272
|
+
const viewportIndex = parseInt(event.key) - 1;
|
|
273
|
+
if (viewportIndex < 0 || viewportIndex >= 9) return;
|
|
274
|
+
const viewport = sys.graph.viewports[viewportIndex];
|
|
275
|
+
if (!viewport) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
reactFlowInstance.setViewport(viewport);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
];
|
|
243
282
|
|
|
244
|
-
|
|
283
|
+
const buildDefaults = (sys: System) => {
|
|
284
|
+
const keymap: Record<string, string | string[]> = {};
|
|
285
|
+
const descriptions: Record<string, string> = {};
|
|
286
|
+
const handlers: Record<string, Handler> = {};
|
|
287
|
+
const commandToAction: Record<string, string> = {};
|
|
245
288
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
},
|
|
250
|
-
AUTO_LAYOUT: (event) => {
|
|
251
|
-
if (event) {
|
|
252
|
-
event.preventDefault();
|
|
253
|
-
event.stopPropagation();
|
|
289
|
+
for (const binding of defaultBindings) {
|
|
290
|
+
keymap[binding.action] = binding.trigger;
|
|
291
|
+
descriptions[binding.action] = binding.description;
|
|
254
292
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
FIND: (event) => {
|
|
284
|
-
if (event) {
|
|
285
|
-
event.preventDefault();
|
|
286
|
-
sys.tabStore.getState().openTab('find');
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
},
|
|
293
|
+
const hintTarget = binding.command ?? binding.hintCommand;
|
|
294
|
+
if (hintTarget) commandToAction[hintTarget] = binding.action;
|
|
295
|
+
|
|
296
|
+
if (binding.command) {
|
|
297
|
+
const commandId = binding.command;
|
|
298
|
+
handlers[binding.action] = (event) => {
|
|
299
|
+
event?.preventDefault();
|
|
300
|
+
event?.stopPropagation();
|
|
301
|
+
void sys.runCommand(commandId);
|
|
302
|
+
};
|
|
303
|
+
} else if (binding.handler) {
|
|
304
|
+
const handler = binding.handler;
|
|
305
|
+
handlers[binding.action] = (event) => handler(sys, event);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return { keymap, descriptions, handlers, commandToAction };
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export const hotKeyStoreFactory = (sys: System) => {
|
|
313
|
+
const { keymap, descriptions, handlers, commandToAction } =
|
|
314
|
+
buildDefaults(sys);
|
|
315
|
+
|
|
316
|
+
return create<HotkeyStore>((set, get) => ({
|
|
317
|
+
keymap,
|
|
318
|
+
descriptions,
|
|
319
|
+
handlers,
|
|
320
|
+
commandToAction,
|
|
290
321
|
|
|
291
322
|
register(val) {
|
|
292
323
|
set((s) => ({
|
|
@@ -301,6 +332,10 @@ export const hotKeyStoreFactory = (sys: System) =>
|
|
|
301
332
|
descriptions: {
|
|
302
333
|
...s.descriptions,
|
|
303
334
|
...(val.description ? { [val.action]: val.description } : {})
|
|
335
|
+
},
|
|
336
|
+
commandToAction: {
|
|
337
|
+
...s.commandToAction,
|
|
338
|
+
...(val.command ? { [val.command]: val.action } : {})
|
|
304
339
|
}
|
|
305
340
|
}));
|
|
306
341
|
},
|
|
@@ -319,5 +354,11 @@ export const hotKeyStoreFactory = (sys: System) =>
|
|
|
319
354
|
[name]: desc
|
|
320
355
|
}
|
|
321
356
|
}));
|
|
357
|
+
},
|
|
358
|
+
getCommandKeybinding(commandId) {
|
|
359
|
+
const action = get().commandToAction[commandId];
|
|
360
|
+
if (!action) return undefined;
|
|
361
|
+
return formatTrigger(get().keymap[action]);
|
|
322
362
|
}
|
|
323
363
|
}));
|
|
364
|
+
};
|
package/src/store/layers.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
2
2
|
import { create } from 'zustand';
|
|
3
3
|
|
|
4
4
|
const DEFAULT_LAYER_ID = 'default';
|
|
@@ -51,7 +51,7 @@ const createLayerId = (): string => {
|
|
|
51
51
|
return `layer-${Date.now()}-${suffix}`;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
export const layerStoreFactory = (
|
|
54
|
+
export const layerStoreFactory = (session: GraphSession) => {
|
|
55
55
|
const store = create<LayerStore>((set, get) => ({
|
|
56
56
|
defaultLayerId: DEFAULT_LAYER_ID,
|
|
57
57
|
layers: {
|
|
@@ -250,7 +250,7 @@ export const layerStoreFactory = (system: System) => {
|
|
|
250
250
|
}
|
|
251
251
|
}));
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
session.nodeStore.subscribe((nodeState) => {
|
|
254
254
|
const nodeIds = nodeState.nodes.map((node) => node.id);
|
|
255
255
|
store.getState().pruneNodeAssignments(nodeIds);
|
|
256
256
|
});
|
package/src/store/registry.ts
CHANGED
|
@@ -26,10 +26,18 @@ export const registryStoreFactory = () =>
|
|
|
26
26
|
},
|
|
27
27
|
|
|
28
28
|
updateRegistry: (registry: INodeRegistry) =>
|
|
29
|
-
set((x) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
set((x) => {
|
|
30
|
+
// Merge specs by type (additive) so layering multiple profiles/plugins
|
|
31
|
+
// (core + image + ai + ...) doesn't clobber previously-registered node
|
|
32
|
+
// types. Later registrations override an existing type. Use updateSpecs
|
|
33
|
+
// for a full replacement.
|
|
34
|
+
const byType = new Map(x.specs.map((spec) => [spec.type, spec]));
|
|
35
|
+
for (const spec of registry.specs) byType.set(spec.type, spec);
|
|
36
|
+
return {
|
|
37
|
+
values: { ...x.values, ...registry.values },
|
|
38
|
+
specs: Array.from(byType.values())
|
|
39
|
+
};
|
|
40
|
+
}),
|
|
33
41
|
|
|
34
42
|
updateValues: (values: Record<string, ValueTypeMetadata>) =>
|
|
35
43
|
set((x) => ({
|
package/src/store/selection.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
2
2
|
import { create } from 'zustand';
|
|
3
3
|
|
|
4
4
|
export type SelectionStore = {
|
|
@@ -6,14 +6,14 @@ export type SelectionStore = {
|
|
|
6
6
|
setSelectedNodeId: (nodeId: string | null) => void;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export const selectionStoreFactory = (
|
|
9
|
+
export const selectionStoreFactory = (session: GraphSession) => {
|
|
10
10
|
const store = create<SelectionStore>((set) => ({
|
|
11
11
|
selectedNodeId: null,
|
|
12
12
|
setSelectedNodeId: (selectedNodeId: string | null) =>
|
|
13
13
|
set(() => ({ selectedNodeId }))
|
|
14
14
|
}));
|
|
15
15
|
//Track side effect of selected node in the node store
|
|
16
|
-
|
|
16
|
+
session.nodeStore.subscribe((state) => {
|
|
17
17
|
const selectedNode = state.nodes.find((n) => n.selected);
|
|
18
18
|
store.getState().setSelectedNodeId(selectedNode?.id ?? null);
|
|
19
19
|
});
|