n8n-editor-ui 1.93.0 → 1.94.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.
Files changed (119) hide show
  1. package/dist/assets/{AnimatedSpinner-hbTZDd93.js → AnimatedSpinner-CY5xYI5m.js} +1 -1
  2. package/dist/assets/{AnnotationTagsDropdown.ee.vue_vue_type_script_setup_true_lang-CYzc5StE.js → AnnotationTagsDropdown.ee.vue_vue_type_script_setup_true_lang-BOrzkwPH.js} +1 -1
  3. package/dist/assets/{AuthView-8SLMP0H_.js → AuthView-BTzGYAnY.js} +2 -2
  4. package/dist/assets/{CanvasChatSwitch-Dt8TgNJg.js → CanvasChatSwitch-CwpjFCL0.js} +17 -18
  5. package/dist/assets/{ChangePasswordView-DIRyDp89.js → ChangePasswordView-BKR2UFVI.js} +3 -3
  6. package/dist/assets/CollectionParameter-BJtiV9En.js +4 -0
  7. package/dist/assets/{CredentialsView-B6-VxAJ6.js → CredentialsView-DVgxfnNi.js} +7 -7
  8. package/dist/assets/{DemoFooter-CIHwH5PG.js → DemoFooter-C1T3Q0NX.js} +7 -8
  9. package/dist/assets/{ErrorView-C7i0TZwT.js → ErrorView-Cf2Yb8Ea.js} +1 -1
  10. package/dist/assets/{ExecutionsTime.vue_vue_type_script_setup_true_lang--2G21NNR.js → ExecutionsTime.vue_vue_type_script_setup_true_lang-DUu0UMcW.js} +2 -2
  11. package/dist/assets/{ExecutionsView-C_YtciAr.js → ExecutionsView-DjNkfnDh.js} +19 -18
  12. package/dist/assets/{FileSaver.min-bgn7Q9Gt.js → FileSaver.min-C1p9Eies.js} +1 -1
  13. package/dist/assets/{FixedCollectionParameter-BPCJ5aaq.js → FixedCollectionParameter-DN_uJhpe.js} +1 -1
  14. package/dist/assets/{ForgotMyPasswordView-DyUaGd6Z.js → ForgotMyPasswordView-BMQBDIrq.js} +3 -3
  15. package/dist/assets/{InsightsChartAverageRuntime-BB2I2vpV.js → InsightsChartAverageRuntime-JzBkV6Rc.js} +4 -4
  16. package/dist/assets/{InsightsChartFailed-CN_Rl3Bl.js → InsightsChartFailed-DMD3c7zM.js} +4 -4
  17. package/dist/assets/{InsightsChartFailureRate-CHKlg6tg.js → InsightsChartFailureRate-D_qeZo4f.js} +4 -4
  18. package/dist/assets/{InsightsChartTimeSaved-Cd05cM8q.js → InsightsChartTimeSaved-Cw2T-Wvp.js} +4 -4
  19. package/dist/assets/{InsightsChartTotal-ChAO7myf.js → InsightsChartTotal-DlF47gob.js} +4 -4
  20. package/dist/assets/{InsightsDashboard-Bx4vx9gz.css → InsightsDashboard-BSrakbzr.css} +42 -8
  21. package/dist/assets/{InsightsDashboard-BeCfBVUz.js → InsightsDashboard-CxQ9H296.js} +40 -41
  22. package/dist/assets/{InsightsPaywall-Chz8CDc3.js → InsightsPaywall-hRkAfeHz.js} +1 -1
  23. package/dist/assets/InsightsSummary-BcXd-3nU.js +209 -0
  24. package/dist/assets/{InsightsSummary-CdlaUpAt.css → InsightsSummary-DzGQpM5h.css} +27 -24
  25. package/dist/assets/{InsightsTableWorkflows-Blv_GPUj.css → InsightsTableWorkflows-DfTZQkWL.css} +3 -4
  26. package/dist/assets/{InsightsTableWorkflows-5rpYY7YT.js → InsightsTableWorkflows-ybloXdDn.js} +5 -6
  27. package/dist/assets/{Logo-DUDCllkm.js → Logo-BGe7-2Vd.js} +1 -1
  28. package/dist/assets/{LogsPanel-D9r5AcQH.js → LogsPanel-DtTp6kY0.js} +331 -336
  29. package/dist/assets/{MainHeader-CEMGASqv.css → MainHeader-Y95RcfHb.css} +18 -18
  30. package/dist/assets/{MainHeader-DkKOOZ_D.js → MainHeader-h2DV-VuD.js} +13 -13
  31. package/dist/assets/{MainSidebar-ZUBIWeXm.js → MainSidebar-AAHHRXFA.js} +2 -2
  32. package/dist/assets/{NodeCreation-DCfAFuL5.js → NodeCreation-nHiG-Lhi.js} +3 -4
  33. package/dist/assets/{NodeCreator-a0YVv1IE.js → NodeCreator-weAzsmlU.js} +2 -3
  34. package/dist/assets/{NodeDetailsView-C5_hVJzj.js → NodeDetailsView-BsXbcyfb.js} +20 -11
  35. package/dist/assets/{NodeDetailsView-pYP-34nS.css → NodeDetailsView-DpO8nTmN.css} +16 -16
  36. package/dist/assets/{NodeView-Bk9h8GYy.js → NodeView-BY1O3wWl.js} +81 -38
  37. package/dist/assets/{ProjectCardBadge-DRlDZx3d.js → ProjectCardBadge-3xpk5Z4e.js} +1 -1
  38. package/dist/assets/{ProjectHeader-DNm605Kk.js → ProjectHeader-CpoOisjf.js} +2 -2
  39. package/dist/assets/{ProjectSettings-Dge_6KaR.js → ProjectSettings-B__3XaPY.js} +14 -4
  40. package/dist/assets/{PushConnectionTracker.vue_vue_type_script_setup_true_lang-CUf0LkWR.js → PushConnectionTracker.vue_vue_type_script_setup_true_lang-DaoPdG_5.js} +1 -1
  41. package/dist/assets/{ResourcesListLayout-Bbl-1i4l.js → ResourcesListLayout-DAxou314.js} +2 -2
  42. package/dist/assets/{RunData-DQeENuzG.css → RunData-CE5FsU6k.css} +2 -2
  43. package/dist/assets/{RunData-b0RE2JWc.js → RunData-fnd-jejc.js} +233 -92
  44. package/dist/assets/{RunDataAi-DnWcCR_0.js → RunDataAi-Ck3VGKP_.js} +3 -4
  45. package/dist/assets/{RunDataJson-CptVuHuA.js → RunDataJson-B80Z4URL.js} +7 -7
  46. package/dist/assets/{RunDataJsonActions-3jjDztw7.js → RunDataJsonActions-CdZi1Qul.js} +1 -1
  47. package/dist/assets/{RunDataParsedAiContent-BbXv-NPD.js → RunDataParsedAiContent-BczxQ63H.js} +5 -5
  48. package/dist/assets/{RunDataSearch-B90wjsDA.js → RunDataSearch-C4KmCz4c.js} +1 -1
  49. package/dist/assets/{RunDataTable-CpS78GlT.js → RunDataTable-CsLCZIWp.js} +3 -3
  50. package/dist/assets/{SamlOnboarding-Ch9K5rRW.js → SamlOnboarding-DkhjCrPa.js} +3 -3
  51. package/dist/assets/{SettingsApiView-9GU5n_rm.js → SettingsApiView-Ci2-rEpm.js} +1 -1
  52. package/dist/assets/{SettingsCommunityNodesView-CPnVRzNX.js → SettingsCommunityNodesView-_UOppuqS.js} +4 -4
  53. package/dist/assets/{SettingsExternalSecrets-D7xTMV9h.js → SettingsExternalSecrets-DHIkKr53.js} +1 -1
  54. package/dist/assets/{SettingsLdapView-OfrjGKkt.js → SettingsLdapView-B8ezgdqP.js} +1 -1
  55. package/dist/assets/{SettingsLogStreamingView-C_VnOaeX.js → SettingsLogStreamingView-YP6Xy7Fe.js} +1 -1
  56. package/dist/assets/{SettingsPersonalView-Dm24akPV.js → SettingsPersonalView-BmbFyWPb.js} +1 -1
  57. package/dist/assets/{SettingsSourceControl-DDCmL82j.js → SettingsSourceControl-DwaOdDke.js} +1 -1
  58. package/dist/assets/{SettingsSso-BGGQ0Cpg.js → SettingsSso-DOC-P2wt.js} +1 -1
  59. package/dist/assets/{SettingsUsageAndPlan-BzO_zdkH.js → SettingsUsageAndPlan-DVOLlEkG.js} +1 -1
  60. package/dist/assets/{SettingsUsersView-DHQUqhqB.js → SettingsUsersView-CN_KLeIm.js} +1 -1
  61. package/dist/assets/{SettingsView-CbtAqjOX.js → SettingsView-DiAhLyco.js} +1 -1
  62. package/dist/assets/{SetupView-BME1OE6U.js → SetupView-OE_yCNOU.js} +3 -3
  63. package/dist/assets/{SetupWorkflowCredentialsButton-DZr4TCPC.js → SetupWorkflowCredentialsButton-Dx1IkZgW.js} +1 -1
  64. package/dist/assets/{SetupWorkflowFromTemplateView-CPkKEY04.js → SetupWorkflowFromTemplateView-lQXKgIuL.js} +3 -3
  65. package/dist/assets/{SigninView-DUeRvOiY.js → SigninView-BWSrzbF7.js} +3 -3
  66. package/dist/assets/{SignoutView-BC7SBunZ.js → SignoutView-DxGgFxt2.js} +1 -1
  67. package/dist/assets/{SignupView-B5ecYJ2q.js → SignupView-Dtu5bMqF.js} +3 -3
  68. package/dist/assets/{TemplateDetails-DjanZgC1.js → TemplateDetails-CQ7TYqsP.js} +1 -1
  69. package/dist/assets/{TemplateList-8TyNGxY-.js → TemplateList-Cxmv-0p-.js} +1 -1
  70. package/dist/assets/{TemplatesCollectionView-BkH4pJCv.js → TemplatesCollectionView-xvV6FXib.js} +5 -5
  71. package/dist/assets/{TemplatesSearchView-Bcdhi1SL.js → TemplatesSearchView-CsECyZ52.js} +3 -3
  72. package/dist/assets/{TemplatesView-De2XB6We.js → TemplatesView-DrEKpZTU.js} +1 -1
  73. package/dist/assets/{TemplatesWorkflowView-BVnwtrMa.js → TemplatesWorkflowView-iSAL_yol.js} +5 -5
  74. package/dist/assets/{TestDefinitionEditView-DjmPnrTk.js → TestDefinitionEditView-C3ohfu_r.js} +6 -7
  75. package/dist/assets/{TestDefinitionListView-BL2s_qBZ.js → TestDefinitionListView-Dwto0jxH.js} +1 -1
  76. package/dist/assets/{TestDefinitionNewView-B9BqJZST.js → TestDefinitionNewView-9xVUm2ZJ.js} +2 -2
  77. package/dist/assets/{TestDefinitionRootView-AlWyxbc0.js → TestDefinitionRootView-DLurQ4xl.js} +1 -1
  78. package/dist/assets/{VariablesView-BZCvPfan.js → VariablesView-Cg2WSt_e.js} +4 -4
  79. package/dist/assets/{WorkerView-CigxqnWi.js → WorkerView-BG-Dl0Ej.js} +6 -6
  80. package/dist/assets/{WorkflowActivator-B7jRy4L1.js → WorkflowActivator-e7wvW1kJ.js} +11 -9
  81. package/dist/assets/{WorkflowExecutionsInfoAccordion-C_ZycbsF.js → WorkflowExecutionsInfoAccordion-CijtfO0l.js} +1 -1
  82. package/dist/assets/{WorkflowExecutionsLandingPage-DOqrfKlC.js → WorkflowExecutionsLandingPage-Do4y1yOx.js} +2 -2
  83. package/dist/assets/{WorkflowExecutionsPreview-B4Cj2gXW.js → WorkflowExecutionsPreview-Bqo_3PXl.js} +6 -6
  84. package/dist/assets/{WorkflowExecutionsView-RXfP7zkJ.js → WorkflowExecutionsView-C1gS45nc.js} +10 -10
  85. package/dist/assets/{WorkflowHistory-DrXrRwIS.js → WorkflowHistory-CypQw7rC.js} +3 -3
  86. package/dist/assets/{WorkflowOnboardingView-CXH1vCW2.js → WorkflowOnboardingView-DoKXpaNj.js} +1 -1
  87. package/dist/assets/{WorkflowPreview-B_MuFEV8.js → WorkflowPreview-Bxs5XzBX.js} +1 -1
  88. package/dist/assets/{WorkflowsView-D90hfJ35.js → WorkflowsView-BlvgD3xI.js} +9 -9
  89. package/dist/assets/{chartjs.utils-DalQn9bk.js → chartjs.utils-CuWcgqCr.js} +2 -2
  90. package/dist/assets/{dateFormatter-BPfJSa6q.js → dateFormatter-LbucaaRt.js} +1 -1
  91. package/dist/assets/{easyAiWorkflowUtils-kgtpBx2h.js → easyAiWorkflowUtils-_kvYb5hw.js} +1 -1
  92. package/dist/assets/{global-link-actions-CnWOMvqA.js → global-link-actions-DG0SjhQE.js} +1 -1
  93. package/dist/assets/{import-curl-BvX_O56D.js → import-curl-DQ6uPzZ1.js} +1 -1
  94. package/dist/assets/{index-yNaoC3fo.css → index-BA8d2DN9.css} +72 -418
  95. package/dist/assets/{index-DZ6VpjNj.js → index-hdsPF3tl.js} +60325 -57677
  96. package/dist/assets/{index-Bb2NNknG.js → index-vIybYvt3.js} +1 -1
  97. package/dist/assets/{pickBy-B_HGYyxS.js → pickBy-DmKUpB7M.js} +1 -1
  98. package/dist/assets/{polyfills-CLZ4X0Ad.js → polyfills-J2x06Gdp.js} +157 -224
  99. package/dist/assets/{templateActions-DQfZ3ni5.js → templateActions-DxoxchKp.js} +1 -1
  100. package/dist/assets/{typescript.worker-BsxN2afA.js → typescript.worker-B1loTpxy.js} +1 -1
  101. package/dist/assets/{useBeforeUnload-Cu0LPVWe.js → useBeforeUnload-B7JAQiE8.js} +1 -1
  102. package/dist/assets/{useCanvasMapping-VtpW_QZA.css → useCanvasMapping-CFf4cwnq.css} +6 -6
  103. package/dist/assets/{useCanvasMapping-CTTq6x8X.js → useCanvasMapping-CvcOHj5p.js} +56 -31
  104. package/dist/assets/{useClearExecutionButtonVisible-Dwc1_eG9.js → useClearExecutionButtonVisible-DFNEJves.js} +1 -2
  105. package/dist/assets/{useExecutionDebugging-rc72wLIp.js → useExecutionDebugging-DsRIfE0y.js} +1 -1
  106. package/dist/assets/{useExecutionHelpers-DqwMonFW.js → useExecutionHelpers-CEOL8_vt.js} +3 -3
  107. package/dist/assets/{useImportCurlCommand-D_onuFvo.js → useImportCurlCommand-DdIN4YaF.js} +2 -2
  108. package/dist/assets/{useProjectPages-e8b03-5_.js → useProjectPages-OGc-GAxb.js} +1 -1
  109. package/dist/assets/{usePushConnection-wm-7Id6Q.js → usePushConnection-DNGIaS0A.js} +16 -111
  110. package/dist/assets/{useTestDefinitionForm-DlUOnNC0.js → useTestDefinitionForm-Bi6EgFVm.js} +1 -1
  111. package/dist/assets/{useWorkflowActivate-65xML23U.js → useWorkflowActivate-CJ1hLmv2.js} +1 -1
  112. package/dist/assets/{useWorkflowSaving-CUel20JA.js → useWorkflowSaving-BuokdhTC.js} +1 -1
  113. package/dist/index.html +3 -3
  114. package/package.json +1 -1
  115. package/tsconfig.json +1 -0
  116. package/vite.config.mts +4 -0
  117. package/dist/assets/CollectionParameter-Cj4t6-hd.js +0 -4
  118. package/dist/assets/InsightsSummary-MECenLJQ.js +0 -207
  119. package/dist/assets/useCanvasOperations-u8oSDa_u.js +0 -2834
@@ -1,2834 +0,0 @@
1
- import { bF as upperFirst, et as toString, eu as createCompounder, ev as SetCache, ew as arrayIncludes, ex as cacheHas, ey as baseRest, ez as isArrayLikeObject, eA as baseFlatten, eB as AI_CATEGORY_DOCUMENT_LOADERS, eC as AI_CATEGORY_LANGUAGE_MODELS, eD as AI_CATEGORY_MEMORY, eE as AI_CATEGORY_OUTPUTPARSER, eF as AI_CATEGORY_RETRIEVERS, eG as AI_CATEGORY_TEXT_SPLITTERS, eH as AI_WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE, eI as AI_CODE_TOOL_LANGCHAIN_NODE_TYPE, c as useI18n, eJ as AI_CATEGORY_TOOLS, e4 as CORE_NODES_CATEGORY, eK as AI_CATEGORY_EMBEDDING, eL as AI_CATEGORY_VECTOR_STORES, eM as AI_UNCATEGORIZED_CATEGORY, eN as AI_OTHERS_NODE_CREATOR_VIEW, bm as NodeConnectionTypes, bz as useNodeTypesStore, aN as useTemplatesStore, p as useSettingsStore, eO as AI_TRANSFORM_NODE_TYPE, eP as AI_NODE_CREATOR_VIEW, eQ as RSS_READ_NODE_TYPE, eR as EMAIL_SEND_NODE_TYPE, eS as DEFAULT_SUBCATEGORY, eT as SET_NODE_TYPE, eU as CODE_NODE_TYPE, eV as DATETIME_NODE_TYPE, eW as FILTER_NODE_TYPE, eX as REMOVE_DUPLICATES_NODE_TYPE, eY as SPLIT_OUT_NODE_TYPE, eZ as LIMIT_NODE_TYPE, e_ as SUMMARIZE_NODE_TYPE, e$ as AGGREGATE_NODE_TYPE, f0 as MERGE_NODE_TYPE, ec as HTML_NODE_TYPE, f1 as MARKDOWN_NODE_TYPE, f2 as XML_NODE_TYPE, f3 as CRYPTO_NODE_TYPE, f4 as EXTRACT_FROM_FILE_NODE_TYPE, f5 as CONVERT_TO_FILE_NODE_TYPE, f6 as COMPRESSION_NODE_TYPE, f7 as EDIT_IMAGE_NODE_TYPE, f8 as TRANSFORM_DATA_SUBCATEGORY, f9 as IF_NODE_TYPE, fa as SPLIT_IN_BATCHES_NODE_TYPE, fb as FLOWS_CONTROL_SUBCATEGORY, fc as HTTP_REQUEST_NODE_TYPE, fd as WEBHOOK_NODE_TYPE, fe as HELPERS_SUBCATEGORY, ff as HITL_SUBCATEGORY, fg as HUMAN_IN_THE_LOOP_CATEGORY, bs as AI_SUBCATEGORY, fh as TRIGGER_NODE_CREATOR_VIEW, fi as REGULAR_NODE_CREATOR_VIEW, fj as MANUAL_TRIGGER_NODE_TYPE, fk as EMAIL_IMAP_NODE_TYPE, fl as SCHEDULE_TRIGGER_NODE_TYPE, fm as FORM_TRIGGER_NODE_TYPE, dK as EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE, bk as CHAT_TRIGGER_NODE_TYPE, fn as OTHER_TRIGGER_NODES_SUBCATEGORY, bt as AI_CATEGORY_AGENTS, bu as AI_CATEGORY_CHAINS, O as defineStore, r as ref, q as computed, fo as extendItemsWithUUID, $ as useCanvasStore, fp as flattenCreateElements, fq as searchNodes, fr as transformNodeType, fs as subcategorizeItems, ft as isAINode, fu as AI_CATEGORY_ROOT_NODES, fv as AI_CATEGORY_MCP_NODES, fw as groupItemsInSections, z as nextTick, fx as getThemedValue, H as useUIStore, bn as v4, bv as AI_CODE_NODE_TYPE, fy as AI_TRANSFORM_NODE_TYPE$1, fz as sortNodeCreateElements, fA as isValidCanvasConnectionMode, c9 as CanvasConnectionMode, c8 as isValidNodeConnectionType, Q as useWorkflowsStore, as as useNDVStore, aP as useExternalHooks, fB as isVueFlowConnection, bw as getNodeInputs, fC as CUSTOM_API_CALL_KEY, T as STORES, cc as NODE_CREATOR_OPEN_SOURCES, ag as useTelemetry, Z as useRootStore, bS as useCredentialsStore, bV as useHistoryStore, E as useTagsStore, at as useExecutionsStore, a1 as useProjectsStore, a as useToast, a5 as useWorkflowHelpers, bA as useNodeHelpers, bf as useClipboard, fD as getSubworkflowId, fE as MCP_TRIGGER_NODE_TYPE, fF as UPDATE_WEBHOOK_ID_NODE_TYPES, dA as generateNodesGraph, fG as getNewNodePosition, fH as AddConnectionCommand, ay as STICKY_NODE_TYPE, by as getNodeOutputs, fI as RemoveConnectionCommand, aa as EnterpriseEditionFeature, cn as deepCopy, el as isPresent, fJ as RemoveNodeCommand, fK as RenameNodeCommand, bq as usePinnedData, fL as useDataSchema, fM as MoveNodeCommand, fN as DEFAULT_NODE_SIZE, fO as CONFIGURATION_NODE_SIZE, bx as getConnectionTypes, fP as generateOffsets, fQ as CONFIGURABLE_NODE_SIZE, fR as PUSH_NODES_OFFSET, fS as AddNodeCommand, fT as NODE_SIZE, fU as GRID_SIZE, fV as getNodeParameters } from "./index-DZ6VpjNj.js";
2
- function capitalize(string) {
3
- return upperFirst(toString(string).toLowerCase());
4
- }
5
- var camelCase = createCompounder(function(result, word, index) {
6
- word = word.toLowerCase();
7
- return result + (index ? capitalize(word) : word);
8
- });
9
- var LARGE_ARRAY_SIZE = 200;
10
- function baseDifference(array, values, iteratee, comparator) {
11
- var index = -1, includes = arrayIncludes, isCommon = true, length = array.length, result = [], valuesLength = values.length;
12
- if (!length) {
13
- return result;
14
- }
15
- if (values.length >= LARGE_ARRAY_SIZE) {
16
- includes = cacheHas;
17
- isCommon = false;
18
- values = new SetCache(values);
19
- }
20
- outer:
21
- while (++index < length) {
22
- var value = array[index], computed2 = value;
23
- value = value !== 0 ? value : 0;
24
- if (isCommon && computed2 === computed2) {
25
- var valuesIndex = valuesLength;
26
- while (valuesIndex--) {
27
- if (values[valuesIndex] === computed2) {
28
- continue outer;
29
- }
30
- }
31
- result.push(value);
32
- } else if (!includes(values, computed2, comparator)) {
33
- result.push(value);
34
- }
35
- }
36
- return result;
37
- }
38
- var difference = baseRest(function(array, values) {
39
- return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) : [];
40
- });
41
- function getNodeView(node) {
42
- return {
43
- key: node.name,
44
- type: "node",
45
- properties: {
46
- group: [],
47
- name: node.name,
48
- displayName: node.displayName,
49
- title: node.displayName,
50
- description: node.description,
51
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
52
- icon: node.icon,
53
- iconUrl: node.iconUrl
54
- }
55
- };
56
- }
57
- function getAiNodesBySubcategory(nodes, subcategory) {
58
- return nodes.filter(
59
- (node) => !node.hidden && node.codex?.subcategories?.[AI_SUBCATEGORY]?.includes(subcategory)
60
- ).map(getNodeView).sort((a, b) => a.properties.displayName.localeCompare(b.properties.displayName));
61
- }
62
- function AIView(_nodes) {
63
- const i18n = useI18n();
64
- const nodeTypesStore = useNodeTypesStore();
65
- const templatesStore = useTemplatesStore();
66
- const chainNodes = getAiNodesBySubcategory(nodeTypesStore.allLatestNodeTypes, AI_CATEGORY_CHAINS);
67
- const agentNodes = getAiNodesBySubcategory(nodeTypesStore.allLatestNodeTypes, AI_CATEGORY_AGENTS);
68
- const websiteCategoryURLParams = templatesStore.websiteTemplateRepositoryParameters;
69
- websiteCategoryURLParams.append("utm_user_role", "AdvancedAI");
70
- const websiteCategoryURL = templatesStore.constructTemplateRepositoryURL(websiteCategoryURLParams);
71
- const askAiEnabled = useSettingsStore().isAskAiEnabled;
72
- const aiTransformNode = nodeTypesStore.getNodeType(AI_TRANSFORM_NODE_TYPE);
73
- const transformNode = askAiEnabled && aiTransformNode ? [getNodeView(aiTransformNode)] : [];
74
- return {
75
- value: AI_NODE_CREATOR_VIEW,
76
- title: i18n.baseText("nodeCreator.aiPanel.aiNodes"),
77
- subtitle: i18n.baseText("nodeCreator.aiPanel.selectAiNode"),
78
- items: [
79
- {
80
- key: "ai_templates_root",
81
- type: "link",
82
- properties: {
83
- title: i18n.baseText("nodeCreator.aiPanel.linkItem.title"),
84
- icon: "box-open",
85
- description: i18n.baseText("nodeCreator.aiPanel.linkItem.description"),
86
- name: "ai_templates_root",
87
- url: websiteCategoryURL,
88
- tag: {
89
- type: "info",
90
- text: i18n.baseText("nodeCreator.triggerHelperPanel.manualTriggerTag")
91
- }
92
- }
93
- },
94
- ...agentNodes,
95
- ...chainNodes,
96
- ...transformNode,
97
- {
98
- key: AI_OTHERS_NODE_CREATOR_VIEW,
99
- type: "view",
100
- properties: {
101
- title: i18n.baseText("nodeCreator.aiPanel.aiOtherNodes"),
102
- icon: "robot",
103
- description: i18n.baseText("nodeCreator.aiPanel.aiOtherNodesDescription")
104
- }
105
- }
106
- ]
107
- };
108
- }
109
- function AINodesView(_nodes) {
110
- const i18n = useI18n();
111
- function getAISubcategoryProperties(nodeConnectionType) {
112
- return {
113
- connectionType: nodeConnectionType,
114
- iconProps: {
115
- color: `var(--node-type-${nodeConnectionType}-color)`
116
- },
117
- panelClass: `nodes-list-panel-${nodeConnectionType}`
118
- };
119
- }
120
- function getSubcategoryInfo(subcategory) {
121
- const localeKey = `nodeCreator.subcategoryInfos.${camelCase(subcategory)}`;
122
- const info = i18n.baseText(localeKey);
123
- if (info === localeKey) return void 0;
124
- return info;
125
- }
126
- return {
127
- value: AI_OTHERS_NODE_CREATOR_VIEW,
128
- title: i18n.baseText("nodeCreator.aiPanel.aiOtherNodes"),
129
- subtitle: i18n.baseText("nodeCreator.aiPanel.selectAiNode"),
130
- items: [
131
- {
132
- key: AI_CATEGORY_DOCUMENT_LOADERS,
133
- type: "subcategory",
134
- properties: {
135
- title: AI_CATEGORY_DOCUMENT_LOADERS,
136
- info: getSubcategoryInfo(AI_CATEGORY_DOCUMENT_LOADERS),
137
- icon: "file-import",
138
- ...getAISubcategoryProperties(NodeConnectionTypes.AiDocument)
139
- }
140
- },
141
- {
142
- key: AI_CATEGORY_LANGUAGE_MODELS,
143
- type: "subcategory",
144
- properties: {
145
- title: AI_CATEGORY_LANGUAGE_MODELS,
146
- info: getSubcategoryInfo(AI_CATEGORY_LANGUAGE_MODELS),
147
- icon: "language",
148
- ...getAISubcategoryProperties(NodeConnectionTypes.AiLanguageModel)
149
- }
150
- },
151
- {
152
- key: AI_CATEGORY_MEMORY,
153
- type: "subcategory",
154
- properties: {
155
- title: AI_CATEGORY_MEMORY,
156
- info: getSubcategoryInfo(AI_CATEGORY_MEMORY),
157
- icon: "brain",
158
- ...getAISubcategoryProperties(NodeConnectionTypes.AiMemory)
159
- }
160
- },
161
- {
162
- key: AI_CATEGORY_OUTPUTPARSER,
163
- type: "subcategory",
164
- properties: {
165
- title: AI_CATEGORY_OUTPUTPARSER,
166
- info: getSubcategoryInfo(AI_CATEGORY_OUTPUTPARSER),
167
- icon: "list",
168
- ...getAISubcategoryProperties(NodeConnectionTypes.AiOutputParser)
169
- }
170
- },
171
- {
172
- key: AI_CATEGORY_RETRIEVERS,
173
- type: "subcategory",
174
- properties: {
175
- title: AI_CATEGORY_RETRIEVERS,
176
- info: getSubcategoryInfo(AI_CATEGORY_RETRIEVERS),
177
- icon: "search",
178
- ...getAISubcategoryProperties(NodeConnectionTypes.AiRetriever)
179
- }
180
- },
181
- {
182
- key: AI_CATEGORY_TEXT_SPLITTERS,
183
- type: "subcategory",
184
- properties: {
185
- title: AI_CATEGORY_TEXT_SPLITTERS,
186
- info: getSubcategoryInfo(AI_CATEGORY_TEXT_SPLITTERS),
187
- icon: "grip-lines-vertical",
188
- ...getAISubcategoryProperties(NodeConnectionTypes.AiTextSplitter)
189
- }
190
- },
191
- {
192
- type: "subcategory",
193
- key: AI_CATEGORY_TOOLS,
194
- category: CORE_NODES_CATEGORY,
195
- properties: {
196
- title: AI_CATEGORY_TOOLS,
197
- info: getSubcategoryInfo(AI_CATEGORY_TOOLS),
198
- icon: "tools",
199
- ...getAISubcategoryProperties(NodeConnectionTypes.AiTool),
200
- sections: [
201
- {
202
- key: "popular",
203
- title: i18n.baseText("nodeCreator.sectionNames.popular"),
204
- items: [AI_WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE, AI_CODE_TOOL_LANGCHAIN_NODE_TYPE]
205
- }
206
- ]
207
- }
208
- },
209
- {
210
- key: AI_CATEGORY_EMBEDDING,
211
- type: "subcategory",
212
- properties: {
213
- title: AI_CATEGORY_EMBEDDING,
214
- info: getSubcategoryInfo(AI_CATEGORY_EMBEDDING),
215
- icon: "vector-square",
216
- ...getAISubcategoryProperties(NodeConnectionTypes.AiEmbedding)
217
- }
218
- },
219
- {
220
- key: AI_CATEGORY_VECTOR_STORES,
221
- type: "subcategory",
222
- properties: {
223
- title: AI_CATEGORY_VECTOR_STORES,
224
- info: getSubcategoryInfo(AI_CATEGORY_VECTOR_STORES),
225
- icon: "project-diagram",
226
- ...getAISubcategoryProperties(NodeConnectionTypes.AiVectorStore)
227
- }
228
- },
229
- {
230
- key: AI_UNCATEGORIZED_CATEGORY,
231
- type: "subcategory",
232
- properties: {
233
- title: AI_UNCATEGORIZED_CATEGORY,
234
- icon: "code"
235
- }
236
- }
237
- ]
238
- };
239
- }
240
- function TriggerView() {
241
- const i18n = useI18n();
242
- const view = {
243
- value: TRIGGER_NODE_CREATOR_VIEW,
244
- title: i18n.baseText("nodeCreator.triggerHelperPanel.selectATrigger"),
245
- subtitle: i18n.baseText("nodeCreator.triggerHelperPanel.selectATriggerDescription"),
246
- items: [
247
- {
248
- key: MANUAL_TRIGGER_NODE_TYPE,
249
- type: "node",
250
- category: [CORE_NODES_CATEGORY],
251
- properties: {
252
- group: [],
253
- name: MANUAL_TRIGGER_NODE_TYPE,
254
- displayName: i18n.baseText("nodeCreator.triggerHelperPanel.manualTriggerDisplayName"),
255
- description: i18n.baseText("nodeCreator.triggerHelperPanel.manualTriggerDescription"),
256
- icon: "fa:mouse-pointer"
257
- }
258
- },
259
- {
260
- key: DEFAULT_SUBCATEGORY,
261
- type: "subcategory",
262
- properties: {
263
- forceIncludeNodes: [WEBHOOK_NODE_TYPE, EMAIL_IMAP_NODE_TYPE],
264
- title: "App Trigger Nodes",
265
- icon: "satellite-dish"
266
- }
267
- },
268
- {
269
- key: SCHEDULE_TRIGGER_NODE_TYPE,
270
- type: "node",
271
- category: [CORE_NODES_CATEGORY],
272
- properties: {
273
- group: [],
274
- name: SCHEDULE_TRIGGER_NODE_TYPE,
275
- displayName: i18n.baseText("nodeCreator.triggerHelperPanel.scheduleTriggerDisplayName"),
276
- description: i18n.baseText("nodeCreator.triggerHelperPanel.scheduleTriggerDescription"),
277
- icon: "fa:clock"
278
- }
279
- },
280
- {
281
- key: WEBHOOK_NODE_TYPE,
282
- type: "node",
283
- category: [CORE_NODES_CATEGORY],
284
- properties: {
285
- group: [],
286
- name: WEBHOOK_NODE_TYPE,
287
- displayName: i18n.baseText("nodeCreator.triggerHelperPanel.webhookTriggerDisplayName"),
288
- description: i18n.baseText("nodeCreator.triggerHelperPanel.webhookTriggerDescription"),
289
- iconData: {
290
- type: "file",
291
- fileBuffer: "/static/webhook-icon.svg"
292
- }
293
- }
294
- },
295
- {
296
- key: FORM_TRIGGER_NODE_TYPE,
297
- type: "node",
298
- category: [CORE_NODES_CATEGORY],
299
- properties: {
300
- group: [],
301
- name: FORM_TRIGGER_NODE_TYPE,
302
- displayName: i18n.baseText("nodeCreator.triggerHelperPanel.formTriggerDisplayName"),
303
- description: i18n.baseText("nodeCreator.triggerHelperPanel.formTriggerDescription"),
304
- iconData: {
305
- type: "file",
306
- fileBuffer: "/static/form-grey.svg"
307
- }
308
- }
309
- },
310
- {
311
- key: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
312
- type: "node",
313
- category: [CORE_NODES_CATEGORY],
314
- properties: {
315
- group: [],
316
- name: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
317
- displayName: i18n.baseText("nodeCreator.triggerHelperPanel.workflowTriggerDisplayName"),
318
- description: i18n.baseText("nodeCreator.triggerHelperPanel.workflowTriggerDescription"),
319
- icon: "fa:sign-out-alt"
320
- }
321
- },
322
- {
323
- key: CHAT_TRIGGER_NODE_TYPE,
324
- type: "node",
325
- category: [CORE_NODES_CATEGORY],
326
- properties: {
327
- group: [],
328
- name: CHAT_TRIGGER_NODE_TYPE,
329
- displayName: i18n.baseText("nodeCreator.triggerHelperPanel.chatTriggerDisplayName"),
330
- description: i18n.baseText("nodeCreator.triggerHelperPanel.chatTriggerDescription"),
331
- icon: "fa:comments"
332
- }
333
- },
334
- {
335
- type: "subcategory",
336
- key: OTHER_TRIGGER_NODES_SUBCATEGORY,
337
- category: CORE_NODES_CATEGORY,
338
- properties: {
339
- title: OTHER_TRIGGER_NODES_SUBCATEGORY,
340
- icon: "folder-open"
341
- }
342
- }
343
- ]
344
- };
345
- return view;
346
- }
347
- function RegularView(nodes) {
348
- const i18n = useI18n();
349
- const popularItemsSubcategory = [
350
- SET_NODE_TYPE,
351
- CODE_NODE_TYPE,
352
- DATETIME_NODE_TYPE,
353
- AI_TRANSFORM_NODE_TYPE
354
- ];
355
- const getSendAndWaitNodes = (nodes2) => {
356
- return (nodes2 ?? []).filter((node) => node.codex?.categories?.includes(HUMAN_IN_THE_LOOP_CATEGORY)).map((node) => node.name);
357
- };
358
- const view = {
359
- value: REGULAR_NODE_CREATOR_VIEW,
360
- title: i18n.baseText("nodeCreator.triggerHelperPanel.whatHappensNext"),
361
- items: [
362
- {
363
- key: DEFAULT_SUBCATEGORY,
364
- type: "subcategory",
365
- properties: {
366
- title: "App Regular Nodes",
367
- icon: "globe",
368
- forceIncludeNodes: [RSS_READ_NODE_TYPE, EMAIL_SEND_NODE_TYPE]
369
- }
370
- },
371
- {
372
- type: "subcategory",
373
- key: TRANSFORM_DATA_SUBCATEGORY,
374
- category: CORE_NODES_CATEGORY,
375
- properties: {
376
- title: TRANSFORM_DATA_SUBCATEGORY,
377
- icon: "pen",
378
- sections: [
379
- {
380
- key: "popular",
381
- title: i18n.baseText("nodeCreator.sectionNames.popular"),
382
- items: popularItemsSubcategory
383
- },
384
- {
385
- key: "addOrRemove",
386
- title: i18n.baseText("nodeCreator.sectionNames.transform.addOrRemove"),
387
- items: [
388
- FILTER_NODE_TYPE,
389
- REMOVE_DUPLICATES_NODE_TYPE,
390
- SPLIT_OUT_NODE_TYPE,
391
- LIMIT_NODE_TYPE
392
- ]
393
- },
394
- {
395
- key: "combine",
396
- title: i18n.baseText("nodeCreator.sectionNames.transform.combine"),
397
- items: [SUMMARIZE_NODE_TYPE, AGGREGATE_NODE_TYPE, MERGE_NODE_TYPE]
398
- },
399
- {
400
- key: "convert",
401
- title: i18n.baseText("nodeCreator.sectionNames.transform.convert"),
402
- items: [
403
- HTML_NODE_TYPE,
404
- MARKDOWN_NODE_TYPE,
405
- XML_NODE_TYPE,
406
- CRYPTO_NODE_TYPE,
407
- EXTRACT_FROM_FILE_NODE_TYPE,
408
- CONVERT_TO_FILE_NODE_TYPE,
409
- COMPRESSION_NODE_TYPE,
410
- EDIT_IMAGE_NODE_TYPE
411
- ]
412
- }
413
- ]
414
- }
415
- },
416
- {
417
- type: "subcategory",
418
- key: FLOWS_CONTROL_SUBCATEGORY,
419
- category: CORE_NODES_CATEGORY,
420
- properties: {
421
- title: FLOWS_CONTROL_SUBCATEGORY,
422
- icon: "code-branch",
423
- sections: [
424
- {
425
- key: "popular",
426
- title: i18n.baseText("nodeCreator.sectionNames.popular"),
427
- items: [FILTER_NODE_TYPE, IF_NODE_TYPE, SPLIT_IN_BATCHES_NODE_TYPE, MERGE_NODE_TYPE]
428
- }
429
- ]
430
- }
431
- },
432
- {
433
- type: "subcategory",
434
- key: HELPERS_SUBCATEGORY,
435
- category: CORE_NODES_CATEGORY,
436
- properties: {
437
- title: HELPERS_SUBCATEGORY,
438
- icon: "toolbox",
439
- sections: [
440
- {
441
- key: "popular",
442
- title: i18n.baseText("nodeCreator.sectionNames.popular"),
443
- items: [HTTP_REQUEST_NODE_TYPE, WEBHOOK_NODE_TYPE, CODE_NODE_TYPE]
444
- }
445
- ]
446
- }
447
- },
448
- // To add node to this subcategory:
449
- // - add "HITL" to the "categories" property of the node's codex
450
- // - add "HITL": ["Human in the Loop"] to the "subcategories" property of the node's codex
451
- // node has to have the "sendAndWait" operation, if a new operation needs to be included here:
452
- // - update getHumanInTheLoopActions in packages/frontend/editor-ui/src/components/Node/NodeCreator/Modes/NodesMode.vue
453
- {
454
- type: "subcategory",
455
- key: HITL_SUBCATEGORY,
456
- category: HUMAN_IN_THE_LOOP_CATEGORY,
457
- properties: {
458
- title: HITL_SUBCATEGORY,
459
- icon: "user-check",
460
- sections: [
461
- {
462
- key: "sendAndWait",
463
- title: i18n.baseText("nodeCreator.sectionNames.sendAndWait"),
464
- items: getSendAndWaitNodes(nodes)
465
- }
466
- ]
467
- }
468
- }
469
- ]
470
- };
471
- const hasAINodes = (nodes ?? []).some((node) => node.codex?.categories?.includes(AI_SUBCATEGORY));
472
- if (hasAINodes)
473
- view.items.unshift({
474
- key: AI_NODE_CREATOR_VIEW,
475
- type: "view",
476
- properties: {
477
- title: i18n.baseText("nodeCreator.aiPanel.langchainAiNodes"),
478
- icon: "robot",
479
- description: i18n.baseText("nodeCreator.aiPanel.nodesForAi"),
480
- borderless: true
481
- }
482
- });
483
- view.items.push({
484
- key: TRIGGER_NODE_CREATOR_VIEW,
485
- type: "view",
486
- properties: {
487
- title: i18n.baseText("nodeCreator.triggerHelperPanel.addAnotherTrigger"),
488
- icon: "bolt",
489
- description: i18n.baseText("nodeCreator.triggerHelperPanel.addAnotherTriggerDescription")
490
- }
491
- });
492
- return view;
493
- }
494
- const KEYBOARD_ID_ATTR = "data-keyboard-nav-id";
495
- const WATCHED_KEYS = [
496
- "ArrowUp",
497
- "ArrowDown",
498
- "ArrowLeft",
499
- "ArrowRight",
500
- "Enter",
501
- "Escape",
502
- "Tab"
503
- ];
504
- const useKeyboardNavigation = defineStore("nodeCreatorKeyboardNavigation", () => {
505
- const selectableItems = ref([]);
506
- const activeItemId = ref(null);
507
- const keysHooks = ref({});
508
- function getItemType(element) {
509
- return element?.getAttribute("data-keyboard-nav-type");
510
- }
511
- function getElementId(element) {
512
- return element?.getAttribute(KEYBOARD_ID_ATTR) || void 0;
513
- }
514
- async function refreshSelectableItems() {
515
- return await new Promise((resolve) => {
516
- cleanupSelectableItems();
517
- setTimeout(() => {
518
- selectableItems.value = Array.from(
519
- document.querySelectorAll("[data-keyboard-nav-type]")
520
- ).map((el) => new WeakRef(el));
521
- resolve();
522
- }, 0);
523
- });
524
- }
525
- function executeKeyHooks(keyboardKey, activeItem) {
526
- const flatHooks = Object.values(keysHooks.value);
527
- const hooks = flatHooks.filter((hook) => hook.keyboardKeys.includes(keyboardKey));
528
- hooks.forEach((hook) => {
529
- if (!activeItemId.value) return;
530
- const conditionPassed = hook.condition === void 0 || hook.condition(getItemType(activeItem) || "", activeItemId.value);
531
- if (conditionPassed && activeItemId.value) {
532
- hook.handler(activeItemId.value, keyboardKey);
533
- }
534
- });
535
- }
536
- async function onKeyDown(e) {
537
- if (e.target instanceof Element && e.target.classList.contains("ignore-key-press-node-creator")) {
538
- return;
539
- }
540
- const pressedKey = e.key;
541
- if (!WATCHED_KEYS.includes(pressedKey)) return;
542
- e.preventDefault();
543
- e.stopPropagation();
544
- await refreshSelectableItems();
545
- const activeItemIndex = selectableItems.value.findIndex(
546
- (item) => getElementId(item?.deref()) === activeItemId.value
547
- );
548
- const activeItem = selectableItems.value[activeItemIndex]?.deref();
549
- const isArrowDown = pressedKey === "ArrowDown";
550
- const isArrowUp = pressedKey === "ArrowUp";
551
- if (!activeItem) return;
552
- if (isArrowDown) {
553
- const nextItemIndex = activeItemIndex < selectableItems.value.length - 1 ? activeItemIndex + 1 : 0;
554
- setActiveItem(selectableItems.value[nextItemIndex]?.deref());
555
- }
556
- if (isArrowUp) {
557
- const previousIndex = activeItemIndex > 0 ? activeItemIndex - 1 : selectableItems.value.length - 1;
558
- setActiveItem(selectableItems.value[previousIndex]?.deref());
559
- }
560
- executeKeyHooks(pressedKey, activeItem);
561
- }
562
- function setActiveItemId(id) {
563
- activeItemId.value = id;
564
- }
565
- function setActiveItem(item) {
566
- const itemId = getElementId(item);
567
- if (!itemId) return;
568
- setActiveItemId(itemId);
569
- if (item?.scrollIntoView) {
570
- item?.scrollIntoView({ block: "center" });
571
- }
572
- }
573
- async function setActiveItemIndex(index) {
574
- await refreshSelectableItems();
575
- setActiveItem(selectableItems.value[index]?.deref());
576
- }
577
- function attachKeydownEvent() {
578
- document.addEventListener("keydown", onKeyDown, { capture: true });
579
- }
580
- function detachKeydownEvent() {
581
- cleanupSelectableItems();
582
- document.removeEventListener("keydown", onKeyDown, { capture: true });
583
- }
584
- function registerKeyHook(name, hook) {
585
- hook.keyboardKeys.forEach((keyboardKey) => {
586
- if (WATCHED_KEYS.includes(keyboardKey)) {
587
- keysHooks.value = { ...keysHooks.value, [name]: hook };
588
- } else {
589
- throw new Error(`Key ${keyboardKey} is not supported`);
590
- }
591
- });
592
- }
593
- function cleanupSelectableItems() {
594
- selectableItems.value = [];
595
- }
596
- function getActiveItemIndex() {
597
- return selectableItems.value.findIndex(
598
- (item) => getElementId(item?.deref()) === activeItemId.value
599
- );
600
- }
601
- return {
602
- activeItemId,
603
- attachKeydownEvent,
604
- refreshSelectableItems,
605
- detachKeydownEvent,
606
- registerKeyHook,
607
- getActiveItemIndex,
608
- setActiveItemId,
609
- setActiveItemIndex
610
- };
611
- });
612
- const useViewStacks = defineStore("nodeCreatorViewStacks", () => {
613
- const nodeCreatorStore = useNodeCreatorStore();
614
- const { getActiveItemIndex } = useKeyboardNavigation();
615
- const i18n = useI18n();
616
- const settingsStore = useSettingsStore();
617
- const viewStacks = ref([]);
618
- const activeStackItems = computed(() => {
619
- const stack = getLastActiveStack();
620
- if (!stack?.baselineItems) {
621
- return stack.items ? extendItemsWithUUID(stack.items) : [];
622
- }
623
- if (stack.search && searchBaseItems.value) {
624
- let searchBase = searchBaseItems.value;
625
- const canvasHasAINodes = useCanvasStore().aiNodes.length > 0;
626
- if (searchBaseItems.value.length === 0) {
627
- searchBase = flattenCreateElements(stack.baselineItems ?? []);
628
- }
629
- if (
630
- // Filter-out AI sub-nodes if canvas has no AI nodes and the root view is not AI
631
- !(isAiRootView(stack) || canvasHasAINodes) || // or if the source is a plus endpoint or a node connection drop and the root view is not AI subcategory
632
- ["plus_endpoint", "node_connection_drop"].includes(nodeCreatorStore.openSource) && !isAiSubcategoryView(stack)
633
- ) {
634
- searchBase = filterOutAiNodes(searchBase);
635
- }
636
- const searchResults = extendItemsWithUUID(searchNodes(stack.search || "", searchBase));
637
- const groupedNodes = groupIfAiNodes(searchResults, false) ?? searchResults;
638
- stack.activeIndex = groupedNodes.some((node) => node.type === "section") ? 1 : 0;
639
- return groupedNodes;
640
- }
641
- return extendItemsWithUUID(groupIfAiNodes(stack.baselineItems, true));
642
- });
643
- const activeViewStack = computed(() => {
644
- const stack = getLastActiveStack();
645
- if (!stack) return {};
646
- const flatBaselineItems = flattenCreateElements(stack.baselineItems ?? []);
647
- return {
648
- ...stack,
649
- items: activeStackItems.value,
650
- hasSearch: flatBaselineItems.length > 8 || stack?.hasSearch
651
- };
652
- });
653
- const activeViewStackMode = computed(
654
- () => activeViewStack.value.mode || TRIGGER_NODE_CREATOR_VIEW
655
- );
656
- const searchBaseItems = computed(() => {
657
- const stack = getLastActiveStack();
658
- if (!stack?.searchItems) return [];
659
- return stack.searchItems.map((item) => transformNodeType(item, stack.subcategory));
660
- });
661
- function isAiSubcategoryView(stack) {
662
- return stack.rootView === AI_OTHERS_NODE_CREATOR_VIEW;
663
- }
664
- function getLastActiveStack() {
665
- return viewStacks.value[viewStacks.value.length - 1];
666
- }
667
- function getAllNodeCreateElements() {
668
- return nodeCreatorStore.mergedNodes.map(
669
- (item) => transformNodeType(item)
670
- );
671
- }
672
- const globalSearchItemsDiff = computed(() => {
673
- const stack = getLastActiveStack();
674
- if (!stack?.search || isAiSubcategoryView(stack)) return [];
675
- const allNodes = getAllNodeCreateElements();
676
- const filteredNodes = isAiRootView(stack) ? allNodes : filterOutAiNodes(allNodes);
677
- let globalSearchResult = extendItemsWithUUID(
678
- searchNodes(stack.search || "", filteredNodes)
679
- );
680
- if (isAiRootView(stack)) {
681
- globalSearchResult = groupIfAiNodes(globalSearchResult);
682
- }
683
- const filteredItems = globalSearchResult.filter((item) => {
684
- return !activeStackItems.value.find((activeItem) => {
685
- if (activeItem.type === "section") {
686
- const matchingSectionItem = activeItem.children.some(
687
- (sectionItem) => sectionItem.key === item.key
688
- );
689
- return matchingSectionItem;
690
- }
691
- return activeItem.key === item.key;
692
- });
693
- });
694
- const filteredSections = filteredItems.filter((item) => {
695
- if (item.type === "section") {
696
- const hasVisibleChildren = item.children.some(
697
- (child) => activeStackItems.value.some((filteredItem) => filteredItem.key === child.key)
698
- );
699
- return hasVisibleChildren;
700
- }
701
- return true;
702
- });
703
- return filteredSections;
704
- });
705
- const itemsBySubcategory = computed(() => subcategorizeItems(nodeCreatorStore.mergedNodes));
706
- function isAiRootView(stack) {
707
- return stack.rootView === AI_NODE_CREATOR_VIEW;
708
- }
709
- function filterAiRootNodes(items) {
710
- return items.filter((node) => {
711
- if (node.type !== "node") return false;
712
- const subcategories = node.properties.codex?.subcategories?.[AI_SUBCATEGORY] ?? [];
713
- return subcategories.includes(AI_CATEGORY_ROOT_NODES) && !subcategories?.includes(AI_CATEGORY_TOOLS);
714
- });
715
- }
716
- function groupIfAiNodes(items, sortAlphabetically = true) {
717
- const aiNodes = items.filter((node) => isAINode(node));
718
- const canvasHasAINodes = useCanvasStore().aiNodes.length > 0;
719
- if (aiNodes.length > 0 && (canvasHasAINodes || isAiRootView(getLastActiveStack()))) {
720
- const sectionsMap = /* @__PURE__ */ new Map();
721
- const aiRootNodes = filterAiRootNodes(aiNodes);
722
- const aiSubNodes = difference(aiNodes, aiRootNodes);
723
- aiSubNodes.forEach((node) => {
724
- const subcategories = node.properties.codex?.subcategories ?? {};
725
- const section = subcategories[AI_SUBCATEGORY]?.[0];
726
- if (section) {
727
- const subSection = subcategories[section]?.[0];
728
- const sectionKey = subSection ?? section;
729
- const currentItems = sectionsMap.get(sectionKey)?.items ?? [];
730
- const isSubnodesSection = !(subcategories[AI_SUBCATEGORY].includes(AI_CATEGORY_ROOT_NODES) || subcategories[AI_SUBCATEGORY].includes(AI_CATEGORY_MCP_NODES));
731
- let title = section;
732
- if (isSubnodesSection) {
733
- title = `${section} (${i18n.baseText("nodeCreator.subnodes")})`;
734
- }
735
- if (subSection) {
736
- title = subSection;
737
- }
738
- sectionsMap.set(sectionKey, {
739
- key: sectionKey,
740
- title,
741
- items: [...currentItems, node.key]
742
- });
743
- }
744
- });
745
- const nonAiNodes = difference(items, aiNodes);
746
- const sections = Array.from(sectionsMap.values());
747
- return [
748
- ...nonAiNodes,
749
- ...aiRootNodes,
750
- ...groupItemsInSections(aiSubNodes, sections, sortAlphabetically)
751
- ];
752
- }
753
- return items;
754
- }
755
- function filterOutAiNodes(items) {
756
- const filteredSearchBase = items.filter((item) => {
757
- if (item.type === "node") {
758
- const isAICategory = item.properties.codex?.categories?.includes(AI_SUBCATEGORY) === true;
759
- if (!isAICategory) return true;
760
- const isRootNodeSubcategory = item.properties.codex?.subcategories?.[AI_SUBCATEGORY]?.includes(AI_CATEGORY_ROOT_NODES);
761
- return isRootNodeSubcategory;
762
- }
763
- return true;
764
- });
765
- return filteredSearchBase;
766
- }
767
- async function gotoCompatibleConnectionView(connectionType, isOutput, filter) {
768
- let nodesByConnectionType;
769
- let relatedAIView;
770
- if (isOutput === true) {
771
- nodesByConnectionType = useNodeTypesStore().visibleNodeTypesByInputConnectionTypeNames;
772
- relatedAIView = {
773
- properties: {
774
- title: i18n.baseText("nodeCreator.aiPanel.aiNodes"),
775
- icon: "robot"
776
- }
777
- };
778
- } else {
779
- nodesByConnectionType = useNodeTypesStore().visibleNodeTypesByOutputConnectionTypeNames;
780
- relatedAIView = AINodesView().items.find(
781
- (item) => item.properties.connectionType === connectionType
782
- );
783
- }
784
- let extendedInfo = {};
785
- if (!filter?.nodes?.length && relatedAIView?.properties.info) {
786
- extendedInfo = { info: relatedAIView?.properties.info };
787
- }
788
- await nextTick();
789
- const iconName = getThemedValue(relatedAIView?.properties.icon, useUIStore().appliedTheme);
790
- pushViewStack(
791
- {
792
- title: relatedAIView?.properties.title,
793
- ...extendedInfo,
794
- rootView: AI_OTHERS_NODE_CREATOR_VIEW,
795
- mode: "nodes",
796
- items: nodeCreatorStore.allNodeCreatorNodes,
797
- nodeIcon: iconName ? {
798
- type: "icon",
799
- name: iconName,
800
- color: relatedAIView?.properties.iconProps?.color
801
- } : void 0,
802
- panelClass: relatedAIView?.properties.panelClass,
803
- baseFilter: (i) => {
804
- if (i.key === AI_CODE_NODE_TYPE) return false;
805
- const displayNode = nodesByConnectionType[connectionType].includes(i.key);
806
- if (displayNode && filter?.nodes?.length) {
807
- return filter.nodes.includes(i.key);
808
- }
809
- return displayNode;
810
- },
811
- itemsMapper(item) {
812
- return {
813
- ...item,
814
- subcategory: connectionType
815
- };
816
- },
817
- actionsFilter: (items) => {
818
- if (items.some((item) => item.outputConnectionType)) {
819
- return items.filter((item) => item.outputConnectionType === connectionType);
820
- }
821
- return items;
822
- },
823
- hideActions: true,
824
- preventBack: true
825
- },
826
- { resetStacks: true }
827
- );
828
- }
829
- function setStackBaselineItems() {
830
- const stack = getLastActiveStack();
831
- if (!stack || !activeViewStack.value.uuid) return;
832
- let stackItems = stack?.items ?? [];
833
- if (!stack?.items) {
834
- const subcategory = stack?.subcategory ?? DEFAULT_SUBCATEGORY;
835
- let itemsInSubcategory = itemsBySubcategory.value[subcategory];
836
- const isAskAiEnabled = settingsStore.isAskAiEnabled;
837
- if (!isAskAiEnabled) {
838
- itemsInSubcategory = itemsInSubcategory.filter(
839
- (item) => item.key !== AI_TRANSFORM_NODE_TYPE$1
840
- );
841
- }
842
- const sections = stack.sections;
843
- if (sections) {
844
- stackItems = groupItemsInSections(itemsInSubcategory, sections);
845
- } else {
846
- stackItems = itemsInSubcategory;
847
- }
848
- }
849
- if ((stack.forceIncludeNodes ?? []).length > 0) {
850
- const matchedNodes = nodeCreatorStore.mergedNodes.filter((item) => stack.forceIncludeNodes?.includes(item.name)).map((item) => transformNodeType(item, stack.subcategory));
851
- stackItems.push(...matchedNodes);
852
- }
853
- if (stack.baseFilter) {
854
- stackItems = stackItems.filter(stack.baseFilter);
855
- }
856
- if (stack.itemsMapper) {
857
- stackItems = stackItems.map(stack.itemsMapper);
858
- }
859
- if (!stack.items) {
860
- stackItems = sortNodeCreateElements(stackItems);
861
- }
862
- updateCurrentViewStack({ baselineItems: stackItems });
863
- }
864
- function pushViewStack(stack, options = {}) {
865
- if (options.resetStacks) {
866
- resetViewStacks();
867
- }
868
- if (activeViewStack.value.uuid) {
869
- updateCurrentViewStack({ activeIndex: getActiveItemIndex() });
870
- }
871
- const newStackUuid = v4();
872
- viewStacks.value.push({
873
- ...stack,
874
- uuid: newStackUuid,
875
- transitionDirection: options.transitionDirection ?? "in",
876
- activeIndex: 0
877
- });
878
- setStackBaselineItems();
879
- }
880
- function popViewStack() {
881
- if (activeViewStack.value.uuid) {
882
- viewStacks.value.pop();
883
- updateCurrentViewStack({ transitionDirection: "out" });
884
- }
885
- }
886
- function updateCurrentViewStack(stack) {
887
- const currentStack = getLastActiveStack();
888
- const matchedIndex = viewStacks.value.findIndex((s) => s.uuid === currentStack.uuid);
889
- if (!currentStack) return;
890
- Object.keys(stack).forEach((key) => {
891
- const typedKey = key;
892
- viewStacks.value[matchedIndex] = {
893
- ...viewStacks.value[matchedIndex],
894
- [key]: stack[typedKey]
895
- };
896
- });
897
- }
898
- function resetViewStacks() {
899
- viewStacks.value = [];
900
- }
901
- return {
902
- viewStacks,
903
- activeViewStack,
904
- activeViewStackMode,
905
- globalSearchItemsDiff,
906
- isAiSubcategoryView,
907
- gotoCompatibleConnectionView,
908
- resetViewStacks,
909
- updateCurrentViewStack,
910
- pushViewStack,
911
- popViewStack,
912
- getAllNodeCreateElements
913
- };
914
- });
915
- function mapLegacyConnectionsToCanvasConnections(legacyConnections, nodes) {
916
- const mappedConnections = [];
917
- Object.keys(legacyConnections).forEach((fromNodeName) => {
918
- const fromId = nodes.find((node) => node.name === fromNodeName)?.id ?? "";
919
- const fromConnectionTypes = Object.keys(
920
- legacyConnections[fromNodeName]
921
- );
922
- fromConnectionTypes.forEach((fromConnectionType) => {
923
- const fromPorts = legacyConnections[fromNodeName][fromConnectionType];
924
- fromPorts?.forEach((toPorts, fromIndex) => {
925
- toPorts?.forEach((toPort) => {
926
- const toNodeName = toPort.node;
927
- const toId = nodes.find((node) => node.name === toNodeName)?.id ?? "";
928
- const toConnectionType = toPort.type;
929
- const toIndex = toPort.index;
930
- const sourceHandle = createCanvasConnectionHandleString({
931
- mode: CanvasConnectionMode.Output,
932
- type: fromConnectionType,
933
- index: fromIndex
934
- });
935
- const targetHandle = createCanvasConnectionHandleString({
936
- mode: CanvasConnectionMode.Input,
937
- type: toConnectionType,
938
- index: toIndex
939
- });
940
- const connectionId = createCanvasConnectionId({
941
- source: fromId,
942
- sourceHandle,
943
- target: toId,
944
- targetHandle
945
- });
946
- if (fromId && toId) {
947
- mappedConnections.push({
948
- id: connectionId,
949
- source: fromId,
950
- target: toId,
951
- sourceHandle,
952
- targetHandle,
953
- data: {
954
- source: {
955
- node: fromNodeName,
956
- index: fromIndex,
957
- type: fromConnectionType
958
- },
959
- target: {
960
- node: toNodeName,
961
- index: toIndex,
962
- type: toConnectionType
963
- }
964
- }
965
- });
966
- }
967
- });
968
- });
969
- });
970
- });
971
- return mappedConnections;
972
- }
973
- function mapLegacyConnectionToCanvasConnection(sourceNode, targetNode, legacyConnection) {
974
- const source = sourceNode.id;
975
- const sourceHandle = createCanvasConnectionHandleString({
976
- mode: CanvasConnectionMode.Output,
977
- type: legacyConnection[0].type,
978
- index: legacyConnection[0].index
979
- });
980
- const target = targetNode.id;
981
- const targetHandle = createCanvasConnectionHandleString({
982
- mode: CanvasConnectionMode.Input,
983
- type: legacyConnection[1].type,
984
- index: legacyConnection[1].index
985
- });
986
- return {
987
- source,
988
- sourceHandle,
989
- target,
990
- targetHandle
991
- };
992
- }
993
- function parseCanvasConnectionHandleString(handle) {
994
- const [mode, type, index] = (handle ?? "").split("/");
995
- const resolvedMode = isValidCanvasConnectionMode(mode) ? mode : CanvasConnectionMode.Output;
996
- const resolvedType = isValidNodeConnectionType(type) ? type : NodeConnectionTypes.Main;
997
- let resolvedIndex = parseInt(index, 10);
998
- if (isNaN(resolvedIndex)) {
999
- resolvedIndex = 0;
1000
- }
1001
- return {
1002
- mode: resolvedMode,
1003
- type: resolvedType,
1004
- index: resolvedIndex
1005
- };
1006
- }
1007
- function createCanvasConnectionHandleString({
1008
- mode,
1009
- type = NodeConnectionTypes.Main,
1010
- index = 0
1011
- }) {
1012
- return `${mode}/${type}/${index}`;
1013
- }
1014
- function createCanvasConnectionId(connection) {
1015
- return `[${connection.source}/${connection.sourceHandle}][${connection.target}/${connection.targetHandle}]`;
1016
- }
1017
- function mapCanvasConnectionToLegacyConnection(sourceNode, targetNode, connection) {
1018
- const sourceNodeName = sourceNode?.name ?? "";
1019
- const { type: sourceType, index: sourceIndex } = parseCanvasConnectionHandleString(
1020
- connection.sourceHandle
1021
- );
1022
- const targetNodeName = targetNode?.name ?? "";
1023
- const { type: targetType, index: targetIndex } = parseCanvasConnectionHandleString(
1024
- connection.targetHandle
1025
- );
1026
- return [
1027
- {
1028
- node: sourceNodeName,
1029
- type: sourceType,
1030
- index: sourceIndex
1031
- },
1032
- {
1033
- node: targetNodeName,
1034
- type: targetType,
1035
- index: targetIndex
1036
- }
1037
- ];
1038
- }
1039
- function mapLegacyEndpointsToCanvasConnectionPort(endpoints, endpointNames = []) {
1040
- if (typeof endpoints === "string") {
1041
- console.warn("Node endpoints have not been evaluated", endpoints);
1042
- return [];
1043
- }
1044
- return endpoints.map((endpoint, endpointIndex) => {
1045
- const typeValue = typeof endpoint === "string" ? endpoint : endpoint.type;
1046
- const type = isValidNodeConnectionType(typeValue) ? typeValue : NodeConnectionTypes.Main;
1047
- const label = typeof endpoint === "string" ? endpointNames[endpointIndex] : endpoint.displayName;
1048
- const index = endpoints.slice(0, endpointIndex + 1).filter((e) => (typeof e === "string" ? e : e.type) === type).length - 1;
1049
- const required = typeof endpoint === "string" ? false : endpoint.required;
1050
- const maxConnections = typeof endpoint === "string" ? void 0 : endpoint.maxConnections;
1051
- return {
1052
- type,
1053
- index,
1054
- label,
1055
- ...maxConnections ? { maxConnections } : {},
1056
- ...required ? { required } : {}
1057
- };
1058
- });
1059
- }
1060
- function checkOverlap(node1, node2) {
1061
- return !// node1 is completely to the left of node2
1062
- (node1.x + node1.width <= node2.x || // node2 is completely to the left of node1
1063
- node2.x + node2.width <= node1.x || // node1 is completely above node2
1064
- node1.y + node1.height <= node2.y || // node2 is completely above node1
1065
- node2.y + node2.height <= node1.y);
1066
- }
1067
- function insertSpacersBetweenEndpoints(endpoints, requiredEndpointsCount = 0, minEndpointsCount = 4) {
1068
- const endpointsWithSpacers = [...endpoints];
1069
- const optionalNonMainInputsCount = endpointsWithSpacers.length - requiredEndpointsCount;
1070
- const spacerCount = minEndpointsCount - requiredEndpointsCount - optionalNonMainInputsCount;
1071
- if (endpointsWithSpacers.length < minEndpointsCount) {
1072
- for (let i = 0; i < spacerCount; i++) {
1073
- endpointsWithSpacers.splice(requiredEndpointsCount + i, 0, null);
1074
- }
1075
- }
1076
- return endpointsWithSpacers;
1077
- }
1078
- const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, () => {
1079
- const workflowsStore = useWorkflowsStore();
1080
- const ndvStore = useNDVStore();
1081
- const uiStore = useUIStore();
1082
- const nodeTypesStore = useNodeTypesStore();
1083
- const telemetry = useTelemetry();
1084
- const externalHooks = useExternalHooks();
1085
- const selectedView = ref(TRIGGER_NODE_CREATOR_VIEW);
1086
- const mergedNodes = ref([]);
1087
- const actions = ref({});
1088
- const showScrim = ref(false);
1089
- const openSource = ref("");
1090
- const isCreateNodeActive = ref(false);
1091
- const nodePanelSessionId = ref("");
1092
- const allNodeCreatorNodes = computed(
1093
- () => Object.values(mergedNodes.value).map((i) => transformNodeType(i))
1094
- );
1095
- function setMergeNodes(nodes) {
1096
- mergedNodes.value = nodes;
1097
- }
1098
- function removeNodeFromMergedNodes(nodeName) {
1099
- mergedNodes.value = mergedNodes.value.filter((n) => n.name !== nodeName);
1100
- }
1101
- function setActions(nodes) {
1102
- actions.value = nodes;
1103
- }
1104
- function setShowScrim(isVisible) {
1105
- showScrim.value = isVisible;
1106
- }
1107
- function setSelectedView(view) {
1108
- selectedView.value = view;
1109
- }
1110
- function setOpenSource(view) {
1111
- openSource.value = view;
1112
- }
1113
- function openSelectiveNodeCreator({
1114
- connectionType,
1115
- node,
1116
- creatorView
1117
- }) {
1118
- const nodeName = node ?? ndvStore.activeNodeName;
1119
- const nodeData = nodeName ? workflowsStore.getNodeByName(nodeName) : null;
1120
- ndvStore.activeNodeName = null;
1121
- setTimeout(() => {
1122
- if (creatorView) {
1123
- setNodeCreatorState({
1124
- createNodeActive: true,
1125
- nodeCreatorView: creatorView
1126
- });
1127
- } else if (connectionType && nodeData) {
1128
- openNodeCreatorForConnectingNode({
1129
- connection: {
1130
- source: nodeData.id,
1131
- sourceHandle: createCanvasConnectionHandleString({
1132
- mode: "inputs",
1133
- type: connectionType,
1134
- index: 0
1135
- })
1136
- },
1137
- eventSource: NODE_CREATOR_OPEN_SOURCES.NOTICE_ERROR_MESSAGE
1138
- });
1139
- }
1140
- });
1141
- }
1142
- function setNodeCreatorState({
1143
- source,
1144
- createNodeActive,
1145
- nodeCreatorView
1146
- }) {
1147
- if (!nodeCreatorView) {
1148
- nodeCreatorView = workflowsStore.workflowTriggerNodes.length > 0 ? REGULAR_NODE_CREATOR_VIEW : TRIGGER_NODE_CREATOR_VIEW;
1149
- }
1150
- setSelectedView(nodeCreatorView);
1151
- isCreateNodeActive.value = createNodeActive;
1152
- if (createNodeActive && source) {
1153
- setOpenSource(source);
1154
- }
1155
- void externalHooks.run("nodeView.createNodeActiveChanged", {
1156
- source,
1157
- mode: getMode(nodeCreatorView),
1158
- createNodeActive
1159
- });
1160
- if (createNodeActive) {
1161
- onCreatorOpened({
1162
- source,
1163
- mode: getMode(nodeCreatorView),
1164
- workflow_id: workflowsStore.workflowId
1165
- });
1166
- }
1167
- }
1168
- function openNodeCreatorForConnectingNode({
1169
- connection,
1170
- eventSource,
1171
- nodeCreatorView
1172
- }) {
1173
- const sourceNode = workflowsStore.getNodeById(connection.source);
1174
- if (!sourceNode) {
1175
- return;
1176
- }
1177
- const { type, index, mode } = parseCanvasConnectionHandleString(connection.sourceHandle);
1178
- uiStore.lastSelectedNode = sourceNode.name;
1179
- uiStore.lastSelectedNodeEndpointUuid = connection.sourceHandle ?? null;
1180
- uiStore.lastSelectedNodeOutputIndex = index;
1181
- if (isVueFlowConnection(connection)) {
1182
- uiStore.lastInteractedWithNodeConnection = connection;
1183
- }
1184
- uiStore.lastInteractedWithNodeHandle = connection.sourceHandle ?? null;
1185
- uiStore.lastInteractedWithNodeId = sourceNode.id;
1186
- const isOutput = mode === CanvasConnectionMode.Output;
1187
- const isScopedConnection = type !== NodeConnectionTypes.Main;
1188
- setNodeCreatorState({
1189
- source: eventSource,
1190
- createNodeActive: true,
1191
- nodeCreatorView: isScopedConnection ? AI_UNCATEGORIZED_CATEGORY : nodeCreatorView
1192
- });
1193
- if (isScopedConnection) {
1194
- useViewStacks().gotoCompatibleConnectionView(type, isOutput, getNodeCreatorFilter(sourceNode.name, type)).catch(() => {
1195
- });
1196
- }
1197
- }
1198
- function openNodeCreatorForTriggerNodes(source) {
1199
- ndvStore.activeNodeName = null;
1200
- setSelectedView(TRIGGER_NODE_CREATOR_VIEW);
1201
- setShowScrim(true);
1202
- setNodeCreatorState({
1203
- source,
1204
- createNodeActive: true,
1205
- nodeCreatorView: TRIGGER_NODE_CREATOR_VIEW
1206
- });
1207
- }
1208
- function getNodeCreatorFilter(nodeName, outputType) {
1209
- let filter;
1210
- const workflow = workflowsStore.getCurrentWorkflow();
1211
- const workflowNode = workflow.getNode(nodeName);
1212
- if (!workflowNode) return { nodes: [] };
1213
- const nodeType = nodeTypesStore.getNodeType(workflowNode?.type, workflowNode.typeVersion);
1214
- if (nodeType) {
1215
- const inputs = getNodeInputs(workflow, workflowNode, nodeType);
1216
- const filterFound = inputs.filter((input) => {
1217
- if (typeof input === "string" || input.type !== outputType || !input.filter) {
1218
- return false;
1219
- }
1220
- return true;
1221
- });
1222
- if (filterFound.length) {
1223
- filter = filterFound[0].filter;
1224
- }
1225
- }
1226
- return filter;
1227
- }
1228
- function resetNodesPanelSession() {
1229
- nodePanelSessionId.value = `nodes_panel_session_${(/* @__PURE__ */ new Date()).valueOf()}`;
1230
- }
1231
- function trackNodeCreatorEvent(event, properties = {}, withPostHog = false) {
1232
- telemetry.track(
1233
- event,
1234
- {
1235
- ...properties,
1236
- nodes_panel_session_id: nodePanelSessionId.value
1237
- },
1238
- {
1239
- withPostHog
1240
- }
1241
- );
1242
- }
1243
- function onCreatorOpened({
1244
- source,
1245
- mode,
1246
- workflow_id
1247
- }) {
1248
- resetNodesPanelSession();
1249
- trackNodeCreatorEvent("User opened nodes panel", {
1250
- source,
1251
- mode,
1252
- workflow_id
1253
- });
1254
- }
1255
- function onNodeFilterChanged({
1256
- newValue,
1257
- filteredNodes,
1258
- filterMode,
1259
- subcategory,
1260
- title
1261
- }) {
1262
- if (!newValue.length) {
1263
- return;
1264
- }
1265
- const { results_count, trigger_count, regular_count } = filteredNodes.reduce(
1266
- (accu, node) => {
1267
- if (!("properties" in node)) {
1268
- return accu;
1269
- }
1270
- const isCustomAction = "actionKey" in node.properties && node.properties.actionKey === CUSTOM_API_CALL_KEY;
1271
- if (isCustomAction) {
1272
- return accu;
1273
- }
1274
- const isTrigger = node.key.includes("Trigger");
1275
- return {
1276
- results_count: accu.results_count + 1,
1277
- trigger_count: accu.trigger_count + (isTrigger ? 1 : 0),
1278
- regular_count: accu.regular_count + (isTrigger ? 0 : 1)
1279
- };
1280
- },
1281
- {
1282
- results_count: 0,
1283
- trigger_count: 0,
1284
- regular_count: 0
1285
- }
1286
- );
1287
- trackNodeCreatorEvent("User entered nodes panel search term", {
1288
- search_string: newValue,
1289
- filter_mode: getMode(filterMode),
1290
- category_name: subcategory,
1291
- results_count,
1292
- trigger_count,
1293
- regular_count,
1294
- title
1295
- });
1296
- }
1297
- function onCategoryExpanded(properties) {
1298
- trackNodeCreatorEvent("User viewed node category", { ...properties, is_subcategory: false });
1299
- }
1300
- function onViewActions(properties) {
1301
- trackNodeCreatorEvent("User viewed node actions", properties);
1302
- }
1303
- function onActionsCustomAPIClicked(properties) {
1304
- trackNodeCreatorEvent("User clicked custom API from node actions", properties);
1305
- }
1306
- function onAddActions(properties) {
1307
- trackNodeCreatorEvent("User added action", properties);
1308
- }
1309
- function onSubcategorySelected(properties) {
1310
- trackNodeCreatorEvent("User viewed node category", {
1311
- category_name: properties.subcategory,
1312
- is_subcategory: true
1313
- });
1314
- }
1315
- function onNodeAddedToCanvas(properties) {
1316
- trackNodeCreatorEvent("User added node to workflow canvas", properties, true);
1317
- }
1318
- function getMode(mode) {
1319
- if (mode === AI_NODE_CREATOR_VIEW || mode === AI_OTHERS_NODE_CREATOR_VIEW) {
1320
- return "ai";
1321
- }
1322
- if (mode === TRIGGER_NODE_CREATOR_VIEW) {
1323
- return "trigger";
1324
- }
1325
- return "regular";
1326
- }
1327
- return {
1328
- isCreateNodeActive,
1329
- openSource,
1330
- selectedView,
1331
- showScrim,
1332
- mergedNodes,
1333
- actions,
1334
- allNodeCreatorNodes,
1335
- setShowScrim,
1336
- setSelectedView,
1337
- setOpenSource,
1338
- setActions,
1339
- setMergeNodes,
1340
- removeNodeFromMergedNodes,
1341
- setNodeCreatorState,
1342
- openSelectiveNodeCreator,
1343
- openNodeCreatorForConnectingNode,
1344
- openNodeCreatorForTriggerNodes,
1345
- onCreatorOpened,
1346
- onNodeFilterChanged,
1347
- onCategoryExpanded,
1348
- onActionsCustomAPIClicked,
1349
- onViewActions,
1350
- onAddActions,
1351
- onSubcategorySelected,
1352
- onNodeAddedToCanvas
1353
- };
1354
- });
1355
- function useUniqueNodeName() {
1356
- function numberSuffixedNames() {
1357
- return useNodeTypesStore().allNodeTypes.reduce((acc, nodeType) => {
1358
- if (typeof nodeType.defaults.name !== "string") {
1359
- throw new Error("Expected node name default to be a string");
1360
- }
1361
- if (/\d$/.test(nodeType.defaults.name)) acc.push(nodeType.defaults.name);
1362
- return acc;
1363
- }, []);
1364
- }
1365
- function uniqueNodeName(originalName, extraNames = []) {
1366
- const { canvasNames } = useWorkflowsStore();
1367
- const isUnique = !canvasNames.has(originalName) && !extraNames.includes(originalName);
1368
- if (isUnique) return originalName;
1369
- const nsn = numberSuffixedNames().find((nsn2) => originalName.startsWith(nsn2));
1370
- if (nsn) {
1371
- let unique2 = "";
1372
- let index2 = 1;
1373
- const remainder = originalName.split(nsn).pop();
1374
- const lastChar = remainder?.[remainder.length - 1];
1375
- if (lastChar && Number.isInteger(Number(lastChar))) {
1376
- index2 = parseInt(lastChar, 10);
1377
- originalName = originalName.slice(0, -1);
1378
- }
1379
- unique2 = originalName;
1380
- while (canvasNames.has(unique2) || extraNames.includes(unique2)) {
1381
- unique2 = originalName + index2++;
1382
- }
1383
- return unique2;
1384
- }
1385
- if (/^\d+-?\d*$/.test(originalName)) {
1386
- let unique2 = "";
1387
- let index2 = 1;
1388
- const match2 = originalName.match(/(?<base>\d+)-?(?<suffix>\d*)/);
1389
- if (!match2?.groups) {
1390
- throw new Error("Failed to find match for unique name");
1391
- }
1392
- if (match2?.groups?.suffix !== "") {
1393
- index2 = parseInt(match2.groups.suffix, 10);
1394
- }
1395
- unique2 = match2.groups.base;
1396
- while (canvasNames.has(unique2) || extraNames.includes(unique2)) {
1397
- unique2 = match2.groups.base + "-" + index2++;
1398
- }
1399
- return unique2;
1400
- }
1401
- let unique = "";
1402
- let index = 1;
1403
- const match = originalName.match(/(?<base>.*\D+)(?<suffix>\d*)/);
1404
- if (!match?.groups) {
1405
- throw new Error("Failed to find match for unique name");
1406
- }
1407
- if (match?.groups?.suffix !== "") {
1408
- index = parseInt(match.groups.suffix, 10);
1409
- }
1410
- unique = match.groups.base;
1411
- while (canvasNames.has(unique) || extraNames.includes(unique)) {
1412
- unique = match.groups.base + index++;
1413
- }
1414
- return unique;
1415
- }
1416
- return { uniqueNodeName };
1417
- }
1418
- function useCanvasOperations({ router }) {
1419
- const rootStore = useRootStore();
1420
- const workflowsStore = useWorkflowsStore();
1421
- const credentialsStore = useCredentialsStore();
1422
- const historyStore = useHistoryStore();
1423
- const uiStore = useUIStore();
1424
- const ndvStore = useNDVStore();
1425
- const nodeTypesStore = useNodeTypesStore();
1426
- const canvasStore = useCanvasStore();
1427
- const settingsStore = useSettingsStore();
1428
- const tagsStore = useTagsStore();
1429
- const nodeCreatorStore = useNodeCreatorStore();
1430
- const executionsStore = useExecutionsStore();
1431
- const projectsStore = useProjectsStore();
1432
- const i18n = useI18n();
1433
- const toast = useToast();
1434
- const workflowHelpers = useWorkflowHelpers({ router });
1435
- const nodeHelpers = useNodeHelpers();
1436
- const telemetry = useTelemetry();
1437
- const externalHooks = useExternalHooks();
1438
- const clipboard = useClipboard();
1439
- const { uniqueNodeName } = useUniqueNodeName();
1440
- const lastClickPosition = ref([0, 0]);
1441
- const preventOpeningNDV = !!localStorage.getItem("NodeView.preventOpeningNDV");
1442
- const editableWorkflow = computed(() => workflowsStore.workflow);
1443
- const editableWorkflowObject = computed(() => workflowsStore.getCurrentWorkflow());
1444
- const triggerNodes = computed(() => {
1445
- return workflowsStore.workflowTriggerNodes;
1446
- });
1447
- function tidyUp({ result, source, target }) {
1448
- updateNodesPosition(
1449
- result.nodes.map(({ id, x, y }) => ({ id, position: { x, y } })),
1450
- { trackBulk: true, trackHistory: true }
1451
- );
1452
- trackTidyUp({ result, source, target });
1453
- }
1454
- function trackTidyUp({ result, source, target }) {
1455
- telemetry.track(
1456
- "User tidied up canvas",
1457
- {
1458
- source,
1459
- target,
1460
- nodes_count: result.nodes.length
1461
- },
1462
- { withPostHog: true }
1463
- );
1464
- }
1465
- function updateNodesPosition(events, { trackHistory = false, trackBulk = true } = {}) {
1466
- if (trackHistory && trackBulk) {
1467
- historyStore.startRecordingUndo();
1468
- }
1469
- events.forEach(({ id, position }) => {
1470
- updateNodePosition(id, position, { trackHistory });
1471
- });
1472
- if (trackHistory && trackBulk) {
1473
- historyStore.stopRecordingUndo();
1474
- }
1475
- }
1476
- function updateNodePosition(id, position, { trackHistory = false } = {}) {
1477
- const node = workflowsStore.getNodeById(id);
1478
- if (!node) {
1479
- return;
1480
- }
1481
- const oldPosition = [...node.position];
1482
- const newPosition = [position.x, position.y];
1483
- workflowsStore.setNodePositionById(id, newPosition);
1484
- if (trackHistory) {
1485
- historyStore.pushCommandToUndo(
1486
- new MoveNodeCommand(node.name, oldPosition, newPosition, Date.now())
1487
- );
1488
- }
1489
- }
1490
- function revertUpdateNodePosition(nodeName, position) {
1491
- const node = workflowsStore.getNodeByName(nodeName);
1492
- if (!node) {
1493
- return;
1494
- }
1495
- updateNodePosition(node.id, position);
1496
- }
1497
- async function renameNode(currentName, newName, { trackHistory = false, trackBulk = true } = {}) {
1498
- if (currentName === newName) {
1499
- return;
1500
- }
1501
- if (trackHistory && trackBulk) {
1502
- historyStore.startRecordingUndo();
1503
- }
1504
- newName = uniqueNodeName(newName);
1505
- const workflow = workflowsStore.getCurrentWorkflow(true);
1506
- workflow.renameNode(currentName, newName);
1507
- if (trackHistory) {
1508
- historyStore.pushCommandToUndo(new RenameNodeCommand(currentName, newName, Date.now()));
1509
- }
1510
- workflowsStore.renameNodeSelectedAndExecution({ old: currentName, new: newName });
1511
- workflowsStore.setNodes(Object.values(workflow.nodes));
1512
- workflowsStore.setConnections(workflow.connectionsBySourceNode);
1513
- const isRenamingActiveNode = ndvStore.activeNodeName === currentName;
1514
- if (isRenamingActiveNode) {
1515
- ndvStore.activeNodeName = newName;
1516
- }
1517
- if (trackHistory && trackBulk) {
1518
- historyStore.stopRecordingUndo();
1519
- }
1520
- }
1521
- async function revertRenameNode(currentName, previousName) {
1522
- await renameNode(currentName, previousName);
1523
- }
1524
- function connectAdjacentNodes(id, { trackHistory = false } = {}) {
1525
- const node = workflowsStore.getNodeById(id);
1526
- if (!node) {
1527
- return;
1528
- }
1529
- const outputConnectionsByType = workflowsStore.outgoingConnectionsByNodeName(node.name);
1530
- const incomingConnectionsByType = workflowsStore.incomingConnectionsByNodeName(node.name);
1531
- for (const [type, incomingConnectionsByInputIndex] of Object.entries(
1532
- incomingConnectionsByType
1533
- )) {
1534
- for (const incomingConnection of incomingConnectionsByInputIndex.at(0) ?? []) {
1535
- const incomingNodeId = workflowsStore.getNodeByName(incomingConnection.node)?.id;
1536
- if (!incomingNodeId) continue;
1537
- for (const outgoingConnection of outputConnectionsByType[type]?.at(0) ?? []) {
1538
- const outgoingNodeId = workflowsStore.getNodeByName(outgoingConnection.node)?.id;
1539
- if (!outgoingNodeId) continue;
1540
- if (trackHistory) {
1541
- historyStore.pushCommandToUndo(
1542
- new AddConnectionCommand(
1543
- [
1544
- {
1545
- node: incomingConnection.node,
1546
- type,
1547
- index: incomingConnection.index
1548
- },
1549
- {
1550
- node: outgoingConnection.node,
1551
- type,
1552
- index: outgoingConnection.index
1553
- }
1554
- ],
1555
- Date.now()
1556
- )
1557
- );
1558
- }
1559
- createConnection({
1560
- source: incomingNodeId,
1561
- sourceHandle: createCanvasConnectionHandleString({
1562
- mode: CanvasConnectionMode.Output,
1563
- type,
1564
- index: incomingConnection.index
1565
- }),
1566
- target: outgoingNodeId,
1567
- targetHandle: createCanvasConnectionHandleString({
1568
- mode: CanvasConnectionMode.Input,
1569
- type,
1570
- index: outgoingConnection.index
1571
- })
1572
- });
1573
- }
1574
- }
1575
- }
1576
- }
1577
- function deleteNode(id, { trackHistory = false, trackBulk = true } = {}) {
1578
- const node = workflowsStore.getNodeById(id);
1579
- if (!node) {
1580
- return;
1581
- }
1582
- if (trackHistory && trackBulk) {
1583
- historyStore.startRecordingUndo();
1584
- }
1585
- if (uiStore.lastInteractedWithNodeId === id) {
1586
- uiStore.lastInteractedWithNodeId = void 0;
1587
- }
1588
- connectAdjacentNodes(id, { trackHistory });
1589
- deleteConnectionsByNodeId(id, { trackHistory, trackBulk: false });
1590
- workflowsStore.removeNodeExecutionDataById(id);
1591
- workflowsStore.removeNodeById(id);
1592
- if (trackHistory) {
1593
- historyStore.pushCommandToUndo(new RemoveNodeCommand(node, Date.now()));
1594
- if (trackBulk) {
1595
- historyStore.stopRecordingUndo();
1596
- }
1597
- }
1598
- trackDeleteNode(id);
1599
- }
1600
- function deleteNodes(ids, { trackHistory = true, trackBulk = true } = {}) {
1601
- if (trackHistory && trackBulk) {
1602
- historyStore.startRecordingUndo();
1603
- }
1604
- ids.forEach((id) => deleteNode(id, { trackHistory, trackBulk: false }));
1605
- if (trackHistory && trackBulk) {
1606
- historyStore.stopRecordingUndo();
1607
- }
1608
- }
1609
- function revertDeleteNode(node) {
1610
- workflowsStore.addNode(node);
1611
- }
1612
- function trackDeleteNode(id) {
1613
- const node = workflowsStore.getNodeById(id);
1614
- if (!node) {
1615
- return;
1616
- }
1617
- if (node.type === STICKY_NODE_TYPE) {
1618
- telemetry.track("User deleted workflow note", {
1619
- workflow_id: workflowsStore.workflowId
1620
- });
1621
- } else {
1622
- void externalHooks.run("node.deleteNode", { node });
1623
- telemetry.track("User deleted node", {
1624
- node_type: node.type,
1625
- workflow_id: workflowsStore.workflowId
1626
- });
1627
- }
1628
- }
1629
- function setNodeActive(id) {
1630
- const node = workflowsStore.getNodeById(id);
1631
- if (!node) {
1632
- return;
1633
- }
1634
- workflowsStore.setNodePristine(node.name, false);
1635
- setNodeActiveByName(node.name);
1636
- }
1637
- function setNodeActiveByName(name) {
1638
- ndvStore.activeNodeName = name;
1639
- }
1640
- function clearNodeActive() {
1641
- ndvStore.activeNodeName = null;
1642
- }
1643
- function setNodeParameters(id, parameters) {
1644
- const node = workflowsStore.getNodeById(id);
1645
- if (!node) {
1646
- return;
1647
- }
1648
- workflowsStore.setNodeParameters(
1649
- {
1650
- name: node.name,
1651
- value: parameters
1652
- },
1653
- true
1654
- );
1655
- }
1656
- function setNodeSelected(id) {
1657
- if (!id) {
1658
- uiStore.lastInteractedWithNodeId = void 0;
1659
- uiStore.lastSelectedNode = "";
1660
- return;
1661
- }
1662
- const node = workflowsStore.getNodeById(id);
1663
- if (!node) {
1664
- return;
1665
- }
1666
- uiStore.lastInteractedWithNodeId = id;
1667
- uiStore.lastSelectedNode = node.name;
1668
- }
1669
- function toggleNodesDisabled(ids, { trackHistory = true, trackBulk = true } = {}) {
1670
- if (trackHistory && trackBulk) {
1671
- historyStore.startRecordingUndo();
1672
- }
1673
- const nodes = workflowsStore.getNodesByIds(ids);
1674
- nodeHelpers.disableNodes(nodes, { trackHistory, trackBulk: false });
1675
- if (trackHistory && trackBulk) {
1676
- historyStore.stopRecordingUndo();
1677
- }
1678
- }
1679
- function revertToggleNodeDisabled(nodeName) {
1680
- const node = workflowsStore.getNodeByName(nodeName);
1681
- if (node) {
1682
- nodeHelpers.disableNodes([node]);
1683
- }
1684
- }
1685
- function toggleNodesPinned(ids, source, { trackHistory = true, trackBulk = true } = {}) {
1686
- if (trackHistory && trackBulk) {
1687
- historyStore.startRecordingUndo();
1688
- }
1689
- const nodes = workflowsStore.getNodesByIds(ids);
1690
- const nextStatePinned = nodes.some((node) => !workflowsStore.pinDataByNodeName(node.name));
1691
- for (const node of nodes) {
1692
- const pinnedDataForNode = usePinnedData(node);
1693
- if (nextStatePinned) {
1694
- const dataToPin = useDataSchema().getInputDataWithPinned(node);
1695
- if (dataToPin.length !== 0) {
1696
- pinnedDataForNode.setData(dataToPin, source);
1697
- }
1698
- } else {
1699
- pinnedDataForNode.unsetData(source);
1700
- }
1701
- }
1702
- if (trackHistory && trackBulk) {
1703
- historyStore.stopRecordingUndo();
1704
- }
1705
- }
1706
- function requireNodeTypeDescription(type, version) {
1707
- return nodeTypesStore.getNodeType(type, version) ?? {
1708
- properties: [],
1709
- displayName: type,
1710
- name: type,
1711
- group: [],
1712
- description: "",
1713
- version: version ?? 1,
1714
- defaults: {},
1715
- inputs: [],
1716
- outputs: []
1717
- };
1718
- }
1719
- async function addNodes(nodes, options = {}) {
1720
- let insertPosition = options.position;
1721
- let lastAddedNode;
1722
- const addedNodes = [];
1723
- const nodesWithTypeVersion = nodes.map((node) => {
1724
- const typeVersion = node.typeVersion ?? resolveNodeVersion(requireNodeTypeDescription(node.type));
1725
- return {
1726
- ...node,
1727
- typeVersion
1728
- };
1729
- });
1730
- await loadNodeTypesProperties(nodesWithTypeVersion);
1731
- if (options.trackHistory && options.trackBulk) {
1732
- historyStore.startRecordingUndo();
1733
- }
1734
- for (const nodeAddData of nodesWithTypeVersion) {
1735
- const { isAutoAdd, openDetail: openNDV, ...node } = nodeAddData;
1736
- const position = node.position ?? insertPosition;
1737
- const nodeTypeDescription = requireNodeTypeDescription(node.type, node.typeVersion);
1738
- try {
1739
- const newNode = addNode(
1740
- {
1741
- ...node,
1742
- position
1743
- },
1744
- nodeTypeDescription,
1745
- {
1746
- ...options,
1747
- openNDV,
1748
- isAutoAdd
1749
- }
1750
- );
1751
- lastAddedNode = newNode;
1752
- addedNodes.push(newNode);
1753
- } catch (error) {
1754
- toast.showError(error, i18n.baseText("error"));
1755
- console.error(error);
1756
- continue;
1757
- }
1758
- insertPosition = [
1759
- lastAddedNode.position[0] + NODE_SIZE * 2 + GRID_SIZE,
1760
- lastAddedNode.position[1]
1761
- ];
1762
- }
1763
- if (lastAddedNode) {
1764
- updatePositionForNodeWithMultipleInputs(lastAddedNode);
1765
- }
1766
- if (options.trackHistory && options.trackBulk) {
1767
- historyStore.stopRecordingUndo();
1768
- }
1769
- if (!options.keepPristine) {
1770
- uiStore.stateIsDirty = true;
1771
- }
1772
- return addedNodes;
1773
- }
1774
- function updatePositionForNodeWithMultipleInputs(node) {
1775
- const inputNodes = editableWorkflowObject.value.getParentNodesByDepth(node.name, 1);
1776
- if (inputNodes.length > 1) {
1777
- inputNodes.slice(1).forEach((inputNode, index) => {
1778
- const nodeUi = workflowsStore.getNodeByName(inputNode.name);
1779
- if (!nodeUi) return;
1780
- updateNodePosition(nodeUi.id, {
1781
- x: nodeUi.position[0],
1782
- y: nodeUi.position[1] + 100 * (index + 1)
1783
- });
1784
- });
1785
- }
1786
- }
1787
- function checkMaxNodesOfTypeReached(nodeTypeDescription) {
1788
- if (nodeTypeDescription.maxNodes !== void 0 && workflowHelpers.getNodeTypeCount(nodeTypeDescription.name) >= nodeTypeDescription.maxNodes) {
1789
- throw new Error(
1790
- i18n.baseText("nodeView.showMessage.showMaxNodeTypeError.message", {
1791
- adjustToNumber: nodeTypeDescription.maxNodes,
1792
- interpolate: { nodeTypeDataDisplayName: nodeTypeDescription.displayName }
1793
- })
1794
- );
1795
- }
1796
- }
1797
- function addNode(node, nodeTypeDescription, options = {}) {
1798
- checkMaxNodesOfTypeReached(nodeTypeDescription);
1799
- const nodeData = resolveNodeData(node, nodeTypeDescription);
1800
- if (!nodeData) {
1801
- throw new Error(i18n.baseText("nodeViewV2.showError.failedToCreateNode"));
1802
- }
1803
- workflowsStore.addNode(nodeData);
1804
- if (options.trackHistory) {
1805
- historyStore.pushCommandToUndo(new AddNodeCommand(nodeData, Date.now()));
1806
- }
1807
- if (!options.isAutoAdd) {
1808
- createConnectionToLastInteractedWithNode(nodeData, options);
1809
- }
1810
- void nextTick(() => {
1811
- if (!options.keepPristine) {
1812
- uiStore.stateIsDirty = true;
1813
- }
1814
- workflowsStore.setNodePristine(nodeData.name, true);
1815
- nodeHelpers.matchCredentials(nodeData);
1816
- nodeHelpers.updateNodeParameterIssues(nodeData);
1817
- nodeHelpers.updateNodeCredentialIssues(nodeData);
1818
- nodeHelpers.updateNodeInputIssues(nodeData);
1819
- if (options.telemetry) {
1820
- trackAddNode(nodeData, options);
1821
- }
1822
- if (nodeData.type !== STICKY_NODE_TYPE) {
1823
- void externalHooks.run("nodeView.addNodeButton", { nodeTypeName: nodeData.type });
1824
- if (options.openNDV && !preventOpeningNDV) {
1825
- ndvStore.setActiveNodeName(nodeData.name);
1826
- }
1827
- }
1828
- });
1829
- return nodeData;
1830
- }
1831
- async function revertAddNode(nodeName) {
1832
- const node = workflowsStore.getNodeByName(nodeName);
1833
- if (!node) {
1834
- return;
1835
- }
1836
- deleteNode(node.id);
1837
- }
1838
- function createConnectionToLastInteractedWithNode(node, options = {}) {
1839
- const lastInteractedWithNode = uiStore.lastInteractedWithNode;
1840
- if (!lastInteractedWithNode) {
1841
- return;
1842
- }
1843
- const lastInteractedWithNodeId = lastInteractedWithNode.id;
1844
- const lastInteractedWithNodeConnection = uiStore.lastInteractedWithNodeConnection;
1845
- const lastInteractedWithNodeHandle = uiStore.lastInteractedWithNodeHandle;
1846
- if (lastInteractedWithNodeHandle) {
1847
- const { type: connectionType, mode } = parseCanvasConnectionHandleString(
1848
- lastInteractedWithNodeHandle
1849
- );
1850
- const nodeId = node.id;
1851
- const nodeHandle = createCanvasConnectionHandleString({
1852
- mode: CanvasConnectionMode.Input,
1853
- type: connectionType,
1854
- index: 0
1855
- });
1856
- if (mode === CanvasConnectionMode.Input) {
1857
- createConnection({
1858
- source: nodeId,
1859
- sourceHandle: nodeHandle,
1860
- target: lastInteractedWithNodeId,
1861
- targetHandle: lastInteractedWithNodeHandle
1862
- });
1863
- } else {
1864
- createConnection({
1865
- source: lastInteractedWithNodeId,
1866
- sourceHandle: lastInteractedWithNodeHandle,
1867
- target: nodeId,
1868
- targetHandle: nodeHandle
1869
- });
1870
- }
1871
- } else {
1872
- createConnection({
1873
- source: lastInteractedWithNodeId,
1874
- sourceHandle: createCanvasConnectionHandleString({
1875
- mode: CanvasConnectionMode.Output,
1876
- type: NodeConnectionTypes.Main,
1877
- index: 0
1878
- }),
1879
- target: node.id,
1880
- targetHandle: createCanvasConnectionHandleString({
1881
- mode: CanvasConnectionMode.Input,
1882
- type: NodeConnectionTypes.Main,
1883
- index: 0
1884
- })
1885
- });
1886
- }
1887
- if (lastInteractedWithNodeConnection) {
1888
- deleteConnection(lastInteractedWithNodeConnection, { trackHistory: options.trackHistory });
1889
- const targetNode = workflowsStore.getNodeById(lastInteractedWithNodeConnection.target);
1890
- if (targetNode) {
1891
- createConnection({
1892
- source: node.id,
1893
- sourceHandle: createCanvasConnectionHandleString({
1894
- mode: CanvasConnectionMode.Input,
1895
- type: NodeConnectionTypes.Main,
1896
- index: 0
1897
- }),
1898
- target: lastInteractedWithNodeConnection.target,
1899
- targetHandle: lastInteractedWithNodeConnection.targetHandle
1900
- });
1901
- }
1902
- }
1903
- }
1904
- function trackAddNode(nodeData, options) {
1905
- switch (nodeData.type) {
1906
- case STICKY_NODE_TYPE:
1907
- trackAddStickyNoteNode();
1908
- break;
1909
- default:
1910
- trackAddDefaultNode(nodeData, options);
1911
- }
1912
- }
1913
- function trackAddStickyNoteNode() {
1914
- telemetry.track("User inserted workflow note", {
1915
- workflow_id: workflowsStore.workflowId
1916
- });
1917
- }
1918
- function trackAddDefaultNode(nodeData, options) {
1919
- nodeCreatorStore.onNodeAddedToCanvas({
1920
- node_id: nodeData.id,
1921
- node_type: nodeData.type,
1922
- node_version: nodeData.typeVersion,
1923
- is_auto_add: options.isAutoAdd,
1924
- workflow_id: workflowsStore.workflowId,
1925
- drag_and_drop: options.dragAndDrop,
1926
- input_node_type: uiStore.lastInteractedWithNode ? uiStore.lastInteractedWithNode.type : void 0
1927
- });
1928
- }
1929
- function resolveNodeData(node, nodeTypeDescription) {
1930
- const id = node.id ?? nodeHelpers.assignNodeId(node);
1931
- const name = node.name ?? nodeTypeDescription.defaults.name;
1932
- const type = nodeTypeDescription.name;
1933
- const typeVersion = node.typeVersion;
1934
- const position = resolveNodePosition(node, nodeTypeDescription);
1935
- const disabled = node.disabled ?? false;
1936
- const parameters = node.parameters ?? {};
1937
- const nodeData = {
1938
- ...node,
1939
- id,
1940
- name,
1941
- type,
1942
- typeVersion,
1943
- position,
1944
- disabled,
1945
- parameters
1946
- };
1947
- resolveNodeName(nodeData);
1948
- resolveNodeParameters(nodeData, nodeTypeDescription);
1949
- resolveNodeWebhook(nodeData, nodeTypeDescription);
1950
- return nodeData;
1951
- }
1952
- async function loadNodeTypesProperties(nodes) {
1953
- const allNodeTypeDescriptions = nodeTypesStore.allNodeTypes;
1954
- const nodesToBeFetched = [];
1955
- allNodeTypeDescriptions.forEach((nodeTypeDescription) => {
1956
- const nodeVersions = Array.isArray(nodeTypeDescription.version) ? nodeTypeDescription.version : [nodeTypeDescription.version];
1957
- if (!!nodes.find(
1958
- (n) => n.type === nodeTypeDescription.name && nodeVersions.includes(n.typeVersion)
1959
- ) && !nodeTypeDescription.hasOwnProperty("properties")) {
1960
- nodesToBeFetched.push({
1961
- name: nodeTypeDescription.name,
1962
- version: Array.isArray(nodeTypeDescription.version) ? nodeTypeDescription.version.slice(-1)[0] : nodeTypeDescription.version
1963
- });
1964
- }
1965
- });
1966
- if (nodesToBeFetched.length > 0) {
1967
- await nodeTypesStore.getNodesInformation(nodesToBeFetched);
1968
- }
1969
- }
1970
- function resolveNodeVersion(nodeTypeDescription) {
1971
- let nodeVersion = nodeTypeDescription.defaultVersion;
1972
- if (typeof nodeVersion === "undefined") {
1973
- nodeVersion = Array.isArray(nodeTypeDescription.version) ? nodeTypeDescription.version.slice(-1)[0] : nodeTypeDescription.version;
1974
- }
1975
- return nodeVersion;
1976
- }
1977
- function resolveNodeParameters(node, nodeTypeDescription) {
1978
- const nodeParameters = getNodeParameters(
1979
- nodeTypeDescription?.properties ?? [],
1980
- node.parameters,
1981
- true,
1982
- false,
1983
- node,
1984
- nodeTypeDescription
1985
- );
1986
- node.parameters = nodeParameters ?? {};
1987
- }
1988
- function resolveNodePosition(node, nodeTypeDescription) {
1989
- let position = node.position;
1990
- let pushOffsets = [40, 40];
1991
- if (position) {
1992
- return getNewNodePosition(workflowsStore.allNodes, position, pushOffsets);
1993
- }
1994
- const lastInteractedWithNode = uiStore.lastInteractedWithNode;
1995
- const lastInteractedWithNodeConnection = uiStore.lastInteractedWithNodeConnection;
1996
- const lastInteractedWithNodeHandle = uiStore.lastInteractedWithNodeHandle;
1997
- const { type: connectionType, index: connectionIndex } = parseCanvasConnectionHandleString(
1998
- lastInteractedWithNodeHandle ?? lastInteractedWithNodeConnection?.sourceHandle ?? ""
1999
- );
2000
- const nodeSize = connectionType === NodeConnectionTypes.Main ? DEFAULT_NODE_SIZE : CONFIGURATION_NODE_SIZE;
2001
- if (lastInteractedWithNode) {
2002
- const lastInteractedWithNodeTypeDescription = nodeTypesStore.getNodeType(
2003
- lastInteractedWithNode.type,
2004
- lastInteractedWithNode.typeVersion
2005
- );
2006
- const lastInteractedWithNodeObject = editableWorkflowObject.value.getNode(
2007
- lastInteractedWithNode.name
2008
- );
2009
- const newNodeInsertPosition = uiStore.lastCancelledConnectionPosition;
2010
- if (newNodeInsertPosition) {
2011
- const xOffset = connectionType === NodeConnectionTypes.Main ? 0 : -nodeSize[0] / 2;
2012
- const yOffset = connectionType === NodeConnectionTypes.Main ? -nodeSize[1] / 2 : 0;
2013
- position = [newNodeInsertPosition[0] + xOffset, newNodeInsertPosition[1] + yOffset];
2014
- uiStore.lastCancelledConnectionPosition = void 0;
2015
- } else if (lastInteractedWithNodeTypeDescription && lastInteractedWithNodeObject) {
2016
- const lastInteractedWithNodeInputs = getNodeInputs(
2017
- editableWorkflowObject.value,
2018
- lastInteractedWithNodeObject,
2019
- lastInteractedWithNodeTypeDescription
2020
- );
2021
- const lastInteractedWithNodeInputTypes = getConnectionTypes(
2022
- lastInteractedWithNodeInputs
2023
- );
2024
- const lastInteractedWithNodeScopedInputTypes = (lastInteractedWithNodeInputTypes || []).filter((input) => input !== NodeConnectionTypes.Main);
2025
- const lastInteractedWithNodeOutputs = getNodeOutputs(
2026
- editableWorkflowObject.value,
2027
- lastInteractedWithNodeObject,
2028
- lastInteractedWithNodeTypeDescription
2029
- );
2030
- const lastInteractedWithNodeOutputTypes = getConnectionTypes(
2031
- lastInteractedWithNodeOutputs
2032
- );
2033
- const lastInteractedWithNodeMainOutputs = lastInteractedWithNodeOutputTypes.filter(
2034
- (output) => output === NodeConnectionTypes.Main
2035
- );
2036
- let yOffset = 0;
2037
- if (lastInteractedWithNodeConnection) {
2038
- shiftDownstreamNodesPosition(lastInteractedWithNode.name, PUSH_NODES_OFFSET, {
2039
- trackHistory: true
2040
- });
2041
- }
2042
- if (lastInteractedWithNodeMainOutputs.length > 1) {
2043
- const yOffsetValues = generateOffsets(
2044
- lastInteractedWithNodeMainOutputs.length,
2045
- NODE_SIZE,
2046
- GRID_SIZE
2047
- );
2048
- yOffset = yOffsetValues[connectionIndex];
2049
- }
2050
- let outputs = [];
2051
- try {
2052
- outputs = getNodeOutputs(
2053
- editableWorkflowObject.value,
2054
- node,
2055
- nodeTypeDescription
2056
- );
2057
- } catch (e) {
2058
- }
2059
- const outputTypes = getConnectionTypes(outputs);
2060
- pushOffsets = [100, 0];
2061
- if (outputTypes.length > 0 && outputTypes.every((outputName) => outputName !== NodeConnectionTypes.Main)) {
2062
- const scopedConnectionIndex = lastInteractedWithNodeScopedInputTypes.findIndex(
2063
- (inputType) => outputs[0] === inputType
2064
- );
2065
- const lastInteractedWithNodeWidthDivisions = Math.max(
2066
- lastInteractedWithNodeScopedInputTypes.length + 1,
2067
- 1
2068
- );
2069
- position = [
2070
- lastInteractedWithNode.position[0] + CONFIGURABLE_NODE_SIZE[0] / lastInteractedWithNodeWidthDivisions * (scopedConnectionIndex + 1) - nodeSize[0] / 2,
2071
- lastInteractedWithNode.position[1] + PUSH_NODES_OFFSET
2072
- ];
2073
- } else {
2074
- let pushOffset = PUSH_NODES_OFFSET;
2075
- if (!!lastInteractedWithNodeInputTypes.find((input) => input !== NodeConnectionTypes.Main)) {
2076
- pushOffset += 140;
2077
- }
2078
- position = [
2079
- lastInteractedWithNode.position[0] + pushOffset,
2080
- lastInteractedWithNode.position[1] + yOffset
2081
- ];
2082
- }
2083
- }
2084
- }
2085
- if (!position) {
2086
- if (nodeTypesStore.isTriggerNode(node.type) && triggerNodes.value.length === 0) {
2087
- position = [0, 0];
2088
- } else {
2089
- position = lastClickPosition.value;
2090
- }
2091
- }
2092
- return getNewNodePosition(workflowsStore.allNodes, position, pushOffsets);
2093
- }
2094
- function resolveNodeName(node) {
2095
- const localizedName = i18n.localizeNodeName(node.name, node.type);
2096
- node.name = uniqueNodeName(localizedName);
2097
- }
2098
- function resolveNodeWebhook(node, nodeTypeDescription) {
2099
- if (nodeTypeDescription.webhooks?.length && !node.webhookId) {
2100
- nodeHelpers.assignWebhookId(node);
2101
- }
2102
- if ([WEBHOOK_NODE_TYPE, FORM_TRIGGER_NODE_TYPE, MCP_TRIGGER_NODE_TYPE].includes(node.type) && node.parameters.path === "") {
2103
- node.parameters.path = node.webhookId;
2104
- }
2105
- }
2106
- function shiftDownstreamNodesPosition(sourceNodeName, margin, { trackHistory = false }) {
2107
- const sourceNode = workflowsStore.nodesByName[sourceNodeName];
2108
- const checkNodes = workflowHelpers.getConnectedNodes(
2109
- "downstream",
2110
- editableWorkflowObject.value,
2111
- sourceNodeName
2112
- );
2113
- for (const nodeName of checkNodes) {
2114
- const node = workflowsStore.nodesByName[nodeName];
2115
- if (node.position[0] < sourceNode.position[0]) {
2116
- continue;
2117
- }
2118
- updateNodePosition(
2119
- node.id,
2120
- {
2121
- x: node.position[0] + margin,
2122
- y: node.position[1]
2123
- },
2124
- { trackHistory }
2125
- );
2126
- }
2127
- }
2128
- function createConnection(connection, { trackHistory = false, keepPristine = false } = {}) {
2129
- const sourceNode = workflowsStore.getNodeById(connection.source);
2130
- const targetNode = workflowsStore.getNodeById(connection.target);
2131
- if (!sourceNode || !targetNode) {
2132
- return;
2133
- }
2134
- if (trackHistory) {
2135
- historyStore.pushCommandToUndo(
2136
- new AddConnectionCommand(
2137
- mapCanvasConnectionToLegacyConnection(sourceNode, targetNode, connection),
2138
- Date.now()
2139
- )
2140
- );
2141
- }
2142
- const mappedConnection = mapCanvasConnectionToLegacyConnection(
2143
- sourceNode,
2144
- targetNode,
2145
- connection
2146
- );
2147
- if (!isConnectionAllowed(sourceNode, targetNode, mappedConnection[0], mappedConnection[1])) {
2148
- return;
2149
- }
2150
- workflowsStore.addConnection({
2151
- connection: mappedConnection
2152
- });
2153
- void nextTick(() => {
2154
- nodeHelpers.updateNodeInputIssues(sourceNode);
2155
- nodeHelpers.updateNodeInputIssues(targetNode);
2156
- });
2157
- if (!keepPristine) {
2158
- uiStore.stateIsDirty = true;
2159
- }
2160
- }
2161
- function revertCreateConnection(connection) {
2162
- const sourceNodeName = connection[0].node;
2163
- const sourceNode = workflowsStore.getNodeByName(sourceNodeName);
2164
- const targetNodeName = connection[1].node;
2165
- const targetNode = workflowsStore.getNodeByName(targetNodeName);
2166
- if (!sourceNode || !targetNode) {
2167
- return;
2168
- }
2169
- deleteConnection(mapLegacyConnectionToCanvasConnection(sourceNode, targetNode, connection));
2170
- }
2171
- function deleteConnectionsByNodeId(targetNodeId, { trackHistory = false, trackBulk = true } = {}) {
2172
- const targetNode = workflowsStore.getNodeById(targetNodeId);
2173
- if (!targetNode) {
2174
- return;
2175
- }
2176
- if (trackHistory && trackBulk) {
2177
- historyStore.startRecordingUndo();
2178
- }
2179
- const connections = workflowsStore.workflow.connections;
2180
- for (const nodeName of Object.keys(connections)) {
2181
- const node = workflowsStore.getNodeByName(nodeName);
2182
- if (!node) {
2183
- continue;
2184
- }
2185
- for (const type of Object.keys(connections[nodeName])) {
2186
- for (const index of Object.keys(connections[nodeName][type])) {
2187
- const connectionsToDelete = connections[nodeName][type][parseInt(index, 10)] ?? [];
2188
- for (const connectionIndex of Object.keys(connectionsToDelete)) {
2189
- const connectionData = connectionsToDelete[parseInt(connectionIndex, 10)];
2190
- if (!connectionData) {
2191
- continue;
2192
- }
2193
- const connectionDataNode = workflowsStore.getNodeByName(connectionData.node);
2194
- if (connectionDataNode && (connectionDataNode.id === targetNode.id || node.name === targetNode.name)) {
2195
- deleteConnection(
2196
- {
2197
- source: node.id,
2198
- sourceHandle: createCanvasConnectionHandleString({
2199
- mode: CanvasConnectionMode.Output,
2200
- type,
2201
- index: parseInt(index, 10)
2202
- }),
2203
- target: connectionDataNode.id,
2204
- targetHandle: createCanvasConnectionHandleString({
2205
- mode: CanvasConnectionMode.Input,
2206
- type: connectionData.type,
2207
- index: connectionData.index
2208
- })
2209
- },
2210
- { trackHistory, trackBulk: false }
2211
- );
2212
- }
2213
- }
2214
- }
2215
- }
2216
- }
2217
- delete workflowsStore.workflow.connections[targetNode.name];
2218
- if (trackHistory && trackBulk) {
2219
- historyStore.stopRecordingUndo();
2220
- }
2221
- }
2222
- function deleteConnection(connection, { trackHistory = false, trackBulk = true } = {}) {
2223
- const sourceNode = workflowsStore.getNodeById(connection.source);
2224
- const targetNode = workflowsStore.getNodeById(connection.target);
2225
- if (!sourceNode || !targetNode) {
2226
- return;
2227
- }
2228
- const mappedConnection = mapCanvasConnectionToLegacyConnection(
2229
- sourceNode,
2230
- targetNode,
2231
- connection
2232
- );
2233
- if (trackHistory && trackBulk) {
2234
- historyStore.startRecordingUndo();
2235
- }
2236
- workflowsStore.removeConnection({
2237
- connection: mappedConnection
2238
- });
2239
- if (trackHistory) {
2240
- historyStore.pushCommandToUndo(new RemoveConnectionCommand(mappedConnection, Date.now()));
2241
- if (trackBulk) {
2242
- historyStore.stopRecordingUndo();
2243
- }
2244
- }
2245
- }
2246
- function revertDeleteConnection(connection) {
2247
- workflowsStore.addConnection({
2248
- connection
2249
- });
2250
- }
2251
- function revalidateNodeConnections(id, connectionMode) {
2252
- const node = workflowsStore.getNodeById(id);
2253
- const isInput = connectionMode === CanvasConnectionMode.Input;
2254
- if (!node) {
2255
- return;
2256
- }
2257
- const nodeType = nodeTypesStore.getNodeType(node.type, node.typeVersion);
2258
- if (!nodeType) {
2259
- return;
2260
- }
2261
- const connections = mapLegacyConnectionsToCanvasConnections(
2262
- workflowsStore.workflow.connections,
2263
- workflowsStore.workflow.nodes
2264
- );
2265
- connections.forEach((connection) => {
2266
- const isRelevantConnection = isInput ? connection.target === id : connection.source === id;
2267
- if (isRelevantConnection) {
2268
- const otherNodeId = isInput ? connection.source : connection.target;
2269
- const otherNode = workflowsStore.getNodeById(otherNodeId);
2270
- if (!otherNode || !connection.data) {
2271
- return;
2272
- }
2273
- const [firstNode, secondNode] = isInput ? [otherNode, node] : [node, otherNode];
2274
- if (!isConnectionAllowed(
2275
- firstNode,
2276
- secondNode,
2277
- connection.data.source,
2278
- connection.data.target
2279
- )) {
2280
- void nextTick(() => deleteConnection(connection));
2281
- }
2282
- }
2283
- });
2284
- }
2285
- function revalidateNodeInputConnections(id) {
2286
- return revalidateNodeConnections(id, CanvasConnectionMode.Input);
2287
- }
2288
- function revalidateNodeOutputConnections(id) {
2289
- return revalidateNodeConnections(id, CanvasConnectionMode.Output);
2290
- }
2291
- function isConnectionAllowed(sourceNode, targetNode, sourceConnection, targetConnection) {
2292
- const blocklist = [STICKY_NODE_TYPE];
2293
- if (sourceConnection.type !== targetConnection.type) {
2294
- return false;
2295
- }
2296
- if (blocklist.includes(sourceNode.type) || blocklist.includes(targetNode.type)) {
2297
- return false;
2298
- }
2299
- const sourceNodeType = nodeTypesStore.getNodeType(sourceNode.type, sourceNode.typeVersion);
2300
- const sourceWorkflowNode = editableWorkflowObject.value.getNode(sourceNode.name);
2301
- if (!sourceWorkflowNode) {
2302
- return false;
2303
- }
2304
- let sourceNodeOutputs = [];
2305
- if (sourceNodeType) {
2306
- sourceNodeOutputs = getNodeOutputs(
2307
- editableWorkflowObject.value,
2308
- sourceWorkflowNode,
2309
- sourceNodeType
2310
- ) || [];
2311
- }
2312
- const sourceNodeHasOutputConnectionOfType = !!sourceNodeOutputs.find((output) => {
2313
- const outputType = typeof output === "string" ? output : output.type;
2314
- return outputType === sourceConnection.type;
2315
- });
2316
- const sourceNodeHasOutputConnectionPortOfType = sourceConnection.index < sourceNodeOutputs.length;
2317
- if (!sourceNodeHasOutputConnectionOfType || !sourceNodeHasOutputConnectionPortOfType) {
2318
- return false;
2319
- }
2320
- const targetNodeType = nodeTypesStore.getNodeType(targetNode.type, targetNode.typeVersion);
2321
- const targetWorkflowNode = editableWorkflowObject.value.getNode(targetNode.name);
2322
- if (!targetWorkflowNode) {
2323
- return false;
2324
- }
2325
- let targetNodeInputs = [];
2326
- if (targetNodeType) {
2327
- targetNodeInputs = getNodeInputs(
2328
- editableWorkflowObject.value,
2329
- targetWorkflowNode,
2330
- targetNodeType
2331
- ) || [];
2332
- }
2333
- const targetNodeHasInputConnectionOfType = !!targetNodeInputs.find((input) => {
2334
- const inputType = typeof input === "string" ? input : input.type;
2335
- if (inputType !== targetConnection.type) return false;
2336
- const filter = typeof input === "object" && "filter" in input ? input.filter : void 0;
2337
- if (filter?.nodes.length && !filter.nodes.includes(sourceNode.type)) {
2338
- toast.showToast({
2339
- title: i18n.baseText("nodeView.showError.nodeNodeCompatible.title"),
2340
- message: i18n.baseText("nodeView.showError.nodeNodeCompatible.message", {
2341
- interpolate: { sourceNodeName: sourceNode.name, targetNodeName: targetNode.name }
2342
- }),
2343
- type: "error",
2344
- duration: 5e3
2345
- });
2346
- return false;
2347
- }
2348
- return true;
2349
- });
2350
- const targetNodeHasInputConnectionPortOfType = targetConnection.index < targetNodeInputs.length;
2351
- return targetNodeHasInputConnectionOfType && targetNodeHasInputConnectionPortOfType;
2352
- }
2353
- async function addConnections(connections, { trackBulk = true, trackHistory = false, keepPristine = false } = {}) {
2354
- await nextTick();
2355
- if (trackBulk && trackHistory) {
2356
- historyStore.startRecordingUndo();
2357
- }
2358
- for (const connection of connections) {
2359
- createConnection(connection, { trackHistory, keepPristine });
2360
- }
2361
- if (trackBulk && trackHistory) {
2362
- historyStore.stopRecordingUndo();
2363
- }
2364
- if (!keepPristine) {
2365
- uiStore.stateIsDirty = true;
2366
- }
2367
- }
2368
- function resetWorkspace() {
2369
- nodeCreatorStore.setNodeCreatorState({ createNodeActive: false });
2370
- nodeCreatorStore.setShowScrim(false);
2371
- if (workflowsStore.executionWaitingForWebhook) {
2372
- try {
2373
- void workflowsStore.removeTestWebhook(workflowsStore.workflowId);
2374
- } catch (error) {
2375
- }
2376
- }
2377
- workflowsStore.resetWorkflow();
2378
- workflowsStore.resetState();
2379
- workflowsStore.currentWorkflowExecutions = [];
2380
- workflowsStore.setActiveExecutionId(void 0);
2381
- uiStore.resetLastInteractedWith();
2382
- uiStore.stateIsDirty = false;
2383
- executionsStore.activeExecution = null;
2384
- nodeHelpers.credentialsUpdated.value = false;
2385
- }
2386
- function initializeWorkspace(data) {
2387
- workflowHelpers.initState(data);
2388
- data.nodes.forEach((node) => {
2389
- const nodeTypeDescription = requireNodeTypeDescription(node.type, node.typeVersion);
2390
- nodeHelpers.matchCredentials(node);
2391
- resolveNodeParameters(node, nodeTypeDescription);
2392
- resolveNodeWebhook(node, nodeTypeDescription);
2393
- });
2394
- workflowsStore.setNodes(data.nodes);
2395
- workflowsStore.setConnections(data.connections);
2396
- }
2397
- function removeUnknownCredentials(workflow) {
2398
- if (!workflow?.nodes) return;
2399
- for (const node of workflow.nodes) {
2400
- if (!node.credentials) continue;
2401
- for (const [name, credential] of Object.entries(node.credentials)) {
2402
- if (typeof credential === "string" || credential.id === null) continue;
2403
- if (!credentialsStore.getCredentialById(credential.id)) {
2404
- delete node.credentials[name];
2405
- }
2406
- }
2407
- }
2408
- }
2409
- async function addImportedNodesToWorkflow(data, { trackBulk = true, trackHistory = false } = {}) {
2410
- const nodeNameTable = {};
2411
- const newNodeNames = new Set((data.nodes ?? []).map((node) => node.name));
2412
- if (!data.nodes) {
2413
- throw new Error(i18n.baseText("nodeView.noNodesGivenToAdd"));
2414
- }
2415
- const nodeTypesCount = workflowHelpers.getNodeTypesMaxCount();
2416
- let oldName;
2417
- let newName;
2418
- const createNodes = [];
2419
- await nodeHelpers.loadNodesProperties(
2420
- data.nodes.map((node) => ({ name: node.type, version: node.typeVersion }))
2421
- );
2422
- data.nodes.forEach((node) => {
2423
- if (nodeTypesCount[node.type] !== void 0) {
2424
- if (nodeTypesCount[node.type].exist >= nodeTypesCount[node.type].max) {
2425
- nodeNameTable[node.name] = nodeTypesCount[node.type].nodeNames[0];
2426
- return;
2427
- } else {
2428
- nodeTypesCount[node.type].exist += 1;
2429
- }
2430
- }
2431
- oldName = node.name;
2432
- const localized = i18n.localizeNodeName(node.name, node.type);
2433
- newNodeNames.delete(oldName);
2434
- newName = uniqueNodeName(localized, Array.from(newNodeNames));
2435
- newNodeNames.add(newName);
2436
- nodeNameTable[oldName] = newName;
2437
- createNodes.push(node);
2438
- });
2439
- const newConnections = {};
2440
- const currentConnections = data.connections ?? {};
2441
- const createNodeNames = createNodes.map((node) => node.name);
2442
- let sourceNode, type, sourceIndex, connectionIndex, connectionData;
2443
- for (sourceNode of Object.keys(currentConnections)) {
2444
- if (!createNodeNames.includes(sourceNode)) {
2445
- continue;
2446
- }
2447
- const connection = {};
2448
- for (type of Object.keys(currentConnections[sourceNode])) {
2449
- connection[type] = [];
2450
- for (sourceIndex = 0; sourceIndex < currentConnections[sourceNode][type].length; sourceIndex++) {
2451
- const nodeSourceConnections = [];
2452
- const connectionsToCheck = currentConnections[sourceNode][type][sourceIndex];
2453
- if (connectionsToCheck) {
2454
- for (connectionIndex = 0; connectionIndex < connectionsToCheck.length; connectionIndex++) {
2455
- connectionData = connectionsToCheck[connectionIndex];
2456
- if (!createNodeNames.includes(connectionData.node)) {
2457
- continue;
2458
- }
2459
- nodeSourceConnections.push(connectionData);
2460
- }
2461
- }
2462
- connection[type].push(nodeSourceConnections);
2463
- }
2464
- }
2465
- newConnections[sourceNode] = connection;
2466
- }
2467
- const tempWorkflow = workflowsStore.getWorkflow(createNodes, newConnections);
2468
- for (oldName in nodeNameTable) {
2469
- if (oldName === nodeNameTable[oldName]) {
2470
- continue;
2471
- }
2472
- tempWorkflow.renameNode(oldName, nodeNameTable[oldName]);
2473
- }
2474
- if (data.pinData) {
2475
- let pinDataSuccess = true;
2476
- for (const nodeName of Object.keys(data.pinData)) {
2477
- if (!pinDataSuccess) {
2478
- toast.showError(
2479
- new Error(i18n.baseText("ndv.pinData.error.tooLarge.description")),
2480
- i18n.baseText("ndv.pinData.error.tooLarge.title")
2481
- );
2482
- continue;
2483
- }
2484
- const node = tempWorkflow.nodes[nodeNameTable[nodeName]];
2485
- try {
2486
- const pinnedDataForNode = usePinnedData(node);
2487
- pinnedDataForNode.setData(data.pinData[nodeName], "add-nodes");
2488
- pinDataSuccess = true;
2489
- } catch (error) {
2490
- pinDataSuccess = false;
2491
- console.error(error);
2492
- }
2493
- }
2494
- }
2495
- if (trackBulk && trackHistory) {
2496
- historyStore.startRecordingUndo();
2497
- }
2498
- await addNodes(Object.values(tempWorkflow.nodes), { trackBulk: false, trackHistory });
2499
- await addConnections(
2500
- mapLegacyConnectionsToCanvasConnections(
2501
- tempWorkflow.connectionsBySourceNode,
2502
- Object.values(tempWorkflow.nodes)
2503
- ),
2504
- { trackBulk: false, trackHistory }
2505
- );
2506
- if (trackBulk && trackHistory) {
2507
- historyStore.stopRecordingUndo();
2508
- }
2509
- uiStore.stateIsDirty = true;
2510
- return {
2511
- nodes: Object.values(tempWorkflow.nodes),
2512
- connections: tempWorkflow.connectionsBySourceNode
2513
- };
2514
- }
2515
- async function importWorkflowData(workflowData, source, importTags = true, { trackBulk = true, trackHistory = true } = {}) {
2516
- uiStore.resetLastInteractedWith();
2517
- if (!workflowData.hasOwnProperty("nodes") || !workflowData.hasOwnProperty("connections")) {
2518
- return {};
2519
- }
2520
- try {
2521
- const nodeIdMap = {};
2522
- if (workflowData.nodes) {
2523
- const nodeNames = new Set(workflowData.nodes.map((node) => node.name));
2524
- workflowData.nodes.forEach((node) => {
2525
- if (!node.name) {
2526
- const nodeType = nodeTypesStore.getNodeType(node.type);
2527
- const newName = uniqueNodeName(
2528
- nodeType?.displayName ?? node.type,
2529
- Array.from(nodeNames)
2530
- );
2531
- node.name = newName;
2532
- nodeNames.add(newName);
2533
- }
2534
- if (node.webhookId && UPDATE_WEBHOOK_ID_NODE_TYPES.includes(node.type)) {
2535
- const isDuplicate = Object.values(workflowHelpers.getCurrentWorkflow().nodes).some(
2536
- (n) => n.webhookId === node.webhookId
2537
- );
2538
- if (isDuplicate) {
2539
- nodeHelpers.assignWebhookId(node);
2540
- if (node.parameters.path) {
2541
- node.parameters.path = node.webhookId;
2542
- } else if (node.parameters.options.path) {
2543
- node.parameters.options.path = node.webhookId;
2544
- }
2545
- }
2546
- }
2547
- if (node.id) {
2548
- const previousId = node.id;
2549
- const newId = nodeHelpers.assignNodeId(node);
2550
- nodeIdMap[newId] = previousId;
2551
- } else {
2552
- nodeHelpers.assignNodeId(node);
2553
- }
2554
- });
2555
- }
2556
- removeUnknownCredentials(workflowData);
2557
- const nodeGraph = JSON.stringify(
2558
- generateNodesGraph(
2559
- workflowData,
2560
- workflowHelpers.getNodeTypes(),
2561
- {
2562
- nodeIdMap,
2563
- sourceInstanceId: workflowData.meta && workflowData.meta.instanceId !== rootStore.instanceId ? workflowData.meta.instanceId : "",
2564
- isCloudDeployment: settingsStore.isCloudDeployment
2565
- }
2566
- ).nodeGraph
2567
- );
2568
- if (source === "paste") {
2569
- telemetry.track("User pasted nodes", {
2570
- workflow_id: workflowsStore.workflowId,
2571
- node_graph_string: nodeGraph
2572
- });
2573
- } else if (source === "duplicate") {
2574
- telemetry.track("User duplicated nodes", {
2575
- workflow_id: workflowsStore.workflowId,
2576
- node_graph_string: nodeGraph
2577
- });
2578
- } else {
2579
- telemetry.track("User imported workflow", {
2580
- source,
2581
- workflow_id: workflowsStore.workflowId,
2582
- node_graph_string: nodeGraph
2583
- });
2584
- }
2585
- workflowHelpers.updateNodePositions(
2586
- workflowData,
2587
- getNewNodePosition(editableWorkflow.value.nodes, lastClickPosition.value)
2588
- );
2589
- await addImportedNodesToWorkflow(workflowData, { trackBulk, trackHistory });
2590
- if (importTags && settingsStore.areTagsEnabled && Array.isArray(workflowData.tags)) {
2591
- await importWorkflowTags(workflowData);
2592
- }
2593
- return workflowData;
2594
- } catch (error) {
2595
- toast.showError(error, i18n.baseText("nodeView.showError.importWorkflowData.title"));
2596
- return {};
2597
- }
2598
- }
2599
- async function importWorkflowTags(workflowData) {
2600
- const allTags = await tagsStore.fetchAll();
2601
- const tagNames = new Set(allTags.map((tag) => tag.name));
2602
- const workflowTags = workflowData.tags;
2603
- const notFound = workflowTags.filter((tag) => !tagNames.has(tag.name));
2604
- const creatingTagPromises = [];
2605
- for (const tag of notFound) {
2606
- const creationPromise = tagsStore.create(tag.name).then((newTag) => {
2607
- allTags.push(newTag);
2608
- return newTag;
2609
- });
2610
- creatingTagPromises.push(creationPromise);
2611
- }
2612
- await Promise.all(creatingTagPromises);
2613
- const tagIds = workflowTags.reduce((accu, imported) => {
2614
- const tag = allTags.find((t) => t.name === imported.name);
2615
- if (tag) {
2616
- accu.push(tag.id);
2617
- }
2618
- return accu;
2619
- }, []);
2620
- workflowsStore.addWorkflowTagIds(tagIds);
2621
- }
2622
- async function fetchWorkflowDataFromUrl(url) {
2623
- let workflowData;
2624
- canvasStore.startLoading();
2625
- try {
2626
- workflowData = await workflowsStore.getWorkflowFromUrl(url);
2627
- } catch (error) {
2628
- toast.showError(error, i18n.baseText("nodeView.showError.getWorkflowDataFromUrl.title"));
2629
- return;
2630
- } finally {
2631
- canvasStore.stopLoading();
2632
- }
2633
- return workflowData;
2634
- }
2635
- function getNodesToSave(nodes) {
2636
- const data = {
2637
- nodes: [],
2638
- connections: {},
2639
- pinData: {}
2640
- };
2641
- const exportedNodeNames = /* @__PURE__ */ new Set();
2642
- for (const node of nodes) {
2643
- const nodeSaveData = workflowHelpers.getNodeDataToSave(node);
2644
- const pinDataForNode = workflowsStore.pinDataByNodeName(node.name);
2645
- if (pinDataForNode) {
2646
- data.pinData[node.name] = pinDataForNode;
2647
- }
2648
- if (nodeSaveData.credentials && settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]) {
2649
- nodeSaveData.credentials = filterAllowedCredentials(
2650
- nodeSaveData.credentials,
2651
- workflowsStore.usedCredentials
2652
- );
2653
- }
2654
- data.nodes.push(nodeSaveData);
2655
- exportedNodeNames.add(node.name);
2656
- }
2657
- data.connections = getConnectionsForNodes(data.nodes, exportedNodeNames);
2658
- workflowHelpers.removeForeignCredentialsFromWorkflow(data, credentialsStore.allCredentials);
2659
- return data;
2660
- }
2661
- function filterAllowedCredentials(credentials, usedCredentials) {
2662
- return Object.fromEntries(
2663
- Object.entries(credentials).filter(([, credential]) => {
2664
- return credential.id && (!usedCredentials[credential.id] || usedCredentials[credential.id]?.currentUserHasAccess);
2665
- })
2666
- );
2667
- }
2668
- function getConnectionsForNodes(nodes, includeNodeNames) {
2669
- const connections = {};
2670
- for (const node of nodes) {
2671
- const outgoingConnections = workflowsStore.outgoingConnectionsByNodeName(node.name);
2672
- if (!Object.keys(outgoingConnections).length) continue;
2673
- const filteredConnections = filterConnectionsByNodes(outgoingConnections, includeNodeNames);
2674
- if (Object.keys(filteredConnections).length) {
2675
- connections[node.name] = filteredConnections;
2676
- }
2677
- }
2678
- return connections;
2679
- }
2680
- function filterConnectionsByNodes(connections, includeNodeNames) {
2681
- const filteredConnections = {};
2682
- for (const [type, typeConnections] of Object.entries(connections)) {
2683
- const validConnections = typeConnections.map(
2684
- (sourceConnections) => (sourceConnections ?? []).filter((connection) => includeNodeNames.has(connection.node))
2685
- );
2686
- if (validConnections.length) {
2687
- filteredConnections[type] = validConnections;
2688
- }
2689
- }
2690
- return filteredConnections;
2691
- }
2692
- async function duplicateNodes(ids) {
2693
- const workflowData = deepCopy(getNodesToSave(workflowsStore.getNodesByIds(ids)));
2694
- const result = await importWorkflowData(workflowData, "duplicate", false);
2695
- return result.nodes?.map((node) => node.id).filter(isPresent) ?? [];
2696
- }
2697
- async function copyNodes(ids) {
2698
- const workflowData = deepCopy(getNodesToSave(workflowsStore.getNodesByIds(ids)));
2699
- workflowData.meta = {
2700
- ...workflowData.meta,
2701
- ...workflowsStore.workflow.meta,
2702
- instanceId: rootStore.instanceId
2703
- };
2704
- await clipboard.copy(JSON.stringify(workflowData, null, 2));
2705
- telemetry.track("User copied nodes", {
2706
- node_types: workflowData.nodes.map((node) => node.type),
2707
- workflow_id: workflowsStore.workflowId
2708
- });
2709
- }
2710
- async function cutNodes(ids) {
2711
- await copyNodes(ids);
2712
- deleteNodes(ids);
2713
- }
2714
- async function openExecution(executionId) {
2715
- let data;
2716
- try {
2717
- data = await workflowsStore.getExecution(executionId);
2718
- } catch (error) {
2719
- toast.showError(error, i18n.baseText("nodeView.showError.openExecution.title"));
2720
- return;
2721
- }
2722
- if (data === void 0) {
2723
- throw new Error(`Execution with id "${executionId}" could not be found!`);
2724
- }
2725
- initializeWorkspace(data.workflowData);
2726
- workflowsStore.setWorkflowExecutionData(data);
2727
- if (!["manual", "evaluation"].includes(data.mode)) {
2728
- workflowsStore.setWorkflowPinData({});
2729
- }
2730
- uiStore.stateIsDirty = false;
2731
- return data;
2732
- }
2733
- async function toggleChatOpen(source, isOpen) {
2734
- const workflow = workflowsStore.getCurrentWorkflow();
2735
- workflowsStore.toggleLogsPanelOpen(isOpen);
2736
- const payload = {
2737
- workflow_id: workflow.id,
2738
- button_type: source
2739
- };
2740
- void externalHooks.run("nodeView.onOpenChat", payload);
2741
- telemetry.track("User clicked chat open button", payload);
2742
- }
2743
- async function importTemplate({
2744
- id,
2745
- name,
2746
- workflow
2747
- }) {
2748
- const convertedNodes = workflow.nodes?.map(workflowsStore.convertTemplateNodeToNodeUi);
2749
- if (workflow.connections) {
2750
- workflowsStore.setConnections(workflow.connections);
2751
- }
2752
- await addNodes(convertedNodes ?? []);
2753
- await workflowsStore.getNewWorkflowDataAndMakeShareable(name, projectsStore.currentProjectId);
2754
- workflowsStore.addToWorkflowMetadata({ templateId: `${id}` });
2755
- }
2756
- function tryToOpenSubworkflowInNewTab(nodeId) {
2757
- const node = workflowsStore.getNodeById(nodeId);
2758
- if (!node) return false;
2759
- const subWorkflowId = getSubworkflowId(node);
2760
- if (!subWorkflowId) return false;
2761
- window.open(`${rootStore.baseUrl}workflow/${subWorkflowId}`, "_blank");
2762
- return true;
2763
- }
2764
- return {
2765
- lastClickPosition,
2766
- editableWorkflow,
2767
- editableWorkflowObject,
2768
- triggerNodes,
2769
- requireNodeTypeDescription,
2770
- addNodes,
2771
- addNode,
2772
- resolveNodePosition,
2773
- revertAddNode,
2774
- updateNodesPosition,
2775
- updateNodePosition,
2776
- tidyUp,
2777
- revertUpdateNodePosition,
2778
- setNodeActive,
2779
- setNodeActiveByName,
2780
- clearNodeActive,
2781
- setNodeSelected,
2782
- toggleNodesDisabled,
2783
- revertToggleNodeDisabled,
2784
- toggleNodesPinned,
2785
- setNodeParameters,
2786
- renameNode,
2787
- revertRenameNode,
2788
- deleteNode,
2789
- deleteNodes,
2790
- copyNodes,
2791
- cutNodes,
2792
- duplicateNodes,
2793
- getNodesToSave,
2794
- revertDeleteNode,
2795
- addConnections,
2796
- createConnection,
2797
- revertCreateConnection,
2798
- deleteConnection,
2799
- revertDeleteConnection,
2800
- deleteConnectionsByNodeId,
2801
- revalidateNodeInputConnections,
2802
- revalidateNodeOutputConnections,
2803
- isConnectionAllowed,
2804
- filterConnectionsByNodes,
2805
- connectAdjacentNodes,
2806
- importWorkflowData,
2807
- fetchWorkflowDataFromUrl,
2808
- resetWorkspace,
2809
- initializeWorkspace,
2810
- resolveNodeWebhook,
2811
- openExecution,
2812
- toggleChatOpen,
2813
- importTemplate,
2814
- tryToOpenSubworkflowInNewTab
2815
- };
2816
- }
2817
- export {
2818
- AINodesView as A,
2819
- RegularView as R,
2820
- TriggerView as T,
2821
- useCanvasOperations as a,
2822
- capitalize as b,
2823
- createCanvasConnectionHandleString as c,
2824
- checkOverlap as d,
2825
- mapLegacyConnectionsToCanvasConnections as e,
2826
- useViewStacks as f,
2827
- camelCase as g,
2828
- useKeyboardNavigation as h,
2829
- insertSpacersBetweenEndpoints as i,
2830
- AIView as j,
2831
- mapLegacyEndpointsToCanvasConnectionPort as m,
2832
- parseCanvasConnectionHandleString as p,
2833
- useNodeCreatorStore as u
2834
- };