n8n-editor-ui 1.92.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 (124) hide show
  1. package/dist/assets/{AnimatedSpinner-CtKKeDrz.js → AnimatedSpinner-CY5xYI5m.js} +1 -1
  2. package/dist/assets/{AnnotationTagsDropdown.ee.vue_vue_type_script_setup_true_lang-DR6h_xsK.js → AnnotationTagsDropdown.ee.vue_vue_type_script_setup_true_lang-BOrzkwPH.js} +1 -1
  3. package/dist/assets/{AuthView-mKkzBRxh.js → AuthView-BTzGYAnY.js} +2 -2
  4. package/dist/assets/{CanvasChatSwitch-Bu2VD2kp.js → CanvasChatSwitch-CwpjFCL0.js} +17 -18
  5. package/dist/assets/{ChangePasswordView-D5UI1v-J.js → ChangePasswordView-BKR2UFVI.js} +3 -3
  6. package/dist/assets/CollectionParameter-BJtiV9En.js +4 -0
  7. package/dist/assets/{CredentialsView-B78eNJO5.js → CredentialsView-DVgxfnNi.js} +26 -11
  8. package/dist/assets/{DemoFooter-DP26HpCu.js → DemoFooter-C1T3Q0NX.js} +7 -8
  9. package/dist/assets/{ErrorView-C3fvEdCg.js → ErrorView-Cf2Yb8Ea.js} +1 -1
  10. package/dist/assets/{ExecutionsTime.vue_vue_type_script_setup_true_lang-BBpwYdHY.js → ExecutionsTime.vue_vue_type_script_setup_true_lang-DUu0UMcW.js} +2 -2
  11. package/dist/assets/{ExecutionsView-BvlDZwIs.js → ExecutionsView-DjNkfnDh.js} +20 -18
  12. package/dist/assets/{FileSaver.min-BzAtcQXX.js → FileSaver.min-C1p9Eies.js} +1 -1
  13. package/dist/assets/{FixedCollectionParameter-CS5zXMAh.js → FixedCollectionParameter-DN_uJhpe.js} +1 -1
  14. package/dist/assets/{ForgotMyPasswordView-CVQ7pcIG.js → ForgotMyPasswordView-BMQBDIrq.js} +3 -3
  15. package/dist/assets/{InsightsChartAverageRuntime-Boh0SMb3.js → InsightsChartAverageRuntime-JzBkV6Rc.js} +4 -4
  16. package/dist/assets/{InsightsChartFailed-IZ-KYOU9.js → InsightsChartFailed-DMD3c7zM.js} +4 -4
  17. package/dist/assets/{InsightsChartFailureRate-2fWw3p0L.js → InsightsChartFailureRate-D_qeZo4f.js} +4 -4
  18. package/dist/assets/{InsightsChartTimeSaved-B2pLVys1.js → InsightsChartTimeSaved-Cw2T-Wvp.js} +4 -4
  19. package/dist/assets/{InsightsChartTotal-2QD4wPLR.js → InsightsChartTotal-DlF47gob.js} +4 -4
  20. package/dist/assets/{InsightsDashboard-Bx4vx9gz.css → InsightsDashboard-BSrakbzr.css} +42 -8
  21. package/dist/assets/{InsightsDashboard-CbiFbJ8w.js → InsightsDashboard-CxQ9H296.js} +40 -41
  22. package/dist/assets/{InsightsPaywall-5d-cSdiS.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-_eTCUNCX.js → InsightsTableWorkflows-ybloXdDn.js} +5 -6
  27. package/dist/assets/{Logo-Dl2xVRIu.js → Logo-BGe7-2Vd.js} +1 -1
  28. package/dist/assets/{LogsPanel-JnYirDqa.js → LogsPanel-DtTp6kY0.js} +334 -338
  29. package/dist/assets/{MainHeader-CEPLiR-5.css → MainHeader-Y95RcfHb.css} +24 -17
  30. package/dist/assets/{MainHeader-Bk29pgmL.js → MainHeader-h2DV-VuD.js} +148 -82
  31. package/dist/assets/{MainSidebar-BM5ku_wM.js → MainSidebar-AAHHRXFA.js} +28 -11
  32. package/dist/assets/{MainSidebar-zZpP3qQ0.css → MainSidebar-D1_1YFQZ.css} +2 -2
  33. package/dist/assets/{NodeCreation-BEjdAYc_.js → NodeCreation-nHiG-Lhi.js} +9 -5
  34. package/dist/assets/{NodeCreator-D9fmPdS2.css → NodeCreator-D18StsVZ.css} +1021 -174
  35. package/dist/assets/{NodeCreator-cEUgbAI9.js → NodeCreator-weAzsmlU.js} +862 -418
  36. package/dist/assets/{NodeDetailsView-D4O9dKTA.js → NodeDetailsView-BsXbcyfb.js} +22 -15
  37. package/dist/assets/{NodeDetailsView-DsFLtbxi.css → NodeDetailsView-DpO8nTmN.css} +16 -16
  38. package/dist/assets/{NodeView-DDSOUm8E.js → NodeView-BY1O3wWl.js} +104 -50
  39. package/dist/assets/{ProjectCardBadge-BNn2hiMe.js → ProjectCardBadge-3xpk5Z4e.js} +38 -2
  40. package/dist/assets/{ProjectHeader-CaEZ2OPj.js → ProjectHeader-CpoOisjf.js} +106 -64
  41. package/dist/assets/{ProjectSettings-otA8E-yW.js → ProjectSettings-B__3XaPY.js} +14 -3
  42. package/dist/assets/{PushConnectionTracker.vue_vue_type_script_setup_true_lang-C3JbZMCk.js → PushConnectionTracker.vue_vue_type_script_setup_true_lang-DaoPdG_5.js} +1 -1
  43. package/dist/assets/{ResourcesListLayout-1d9Ic6VX.js → ResourcesListLayout-DAxou314.js} +156 -53
  44. package/dist/assets/{ResourcesListLayout-CtGME7aU.css → ResourcesListLayout-DuNjbsMn.css} +8 -8
  45. package/dist/assets/{RunData-BjlZgIyx.css → RunData-CE5FsU6k.css} +2 -2
  46. package/dist/assets/{RunData-Bx47sNQp.js → RunData-fnd-jejc.js} +257 -99
  47. package/dist/assets/{RunDataAi-DOac7nwD.js → RunDataAi-Ck3VGKP_.js} +3 -4
  48. package/dist/assets/{RunDataJson-Pev6yNEV.js → RunDataJson-B80Z4URL.js} +7 -7
  49. package/dist/assets/{RunDataJsonActions-Co4xgmVq.js → RunDataJsonActions-CdZi1Qul.js} +1 -1
  50. package/dist/assets/{RunDataParsedAiContent-D6MNLmT3.js → RunDataParsedAiContent-BczxQ63H.js} +5 -5
  51. package/dist/assets/{RunDataSearch-C8orcAlP.js → RunDataSearch-C4KmCz4c.js} +1 -1
  52. package/dist/assets/{RunDataTable-oi_l8dhA.js → RunDataTable-CsLCZIWp.js} +3 -3
  53. package/dist/assets/{SamlOnboarding-CT5J6dx0.js → SamlOnboarding-DkhjCrPa.js} +3 -3
  54. package/dist/assets/{SettingsApiView-CupjcI9v.js → SettingsApiView-Ci2-rEpm.js} +1 -1
  55. package/dist/assets/{SettingsCommunityNodesView-B5K2VLyJ.js → SettingsCommunityNodesView-_UOppuqS.js} +24 -11
  56. package/dist/assets/{SettingsExternalSecrets-BidJCf_t.js → SettingsExternalSecrets-DHIkKr53.js} +1 -1
  57. package/dist/assets/{SettingsLdapView-Cva6akhW.js → SettingsLdapView-B8ezgdqP.js} +1 -1
  58. package/dist/assets/{SettingsLogStreamingView-Cy-rAKUO.js → SettingsLogStreamingView-YP6Xy7Fe.js} +1 -1
  59. package/dist/assets/{SettingsPersonalView-ZJ1Syok2.js → SettingsPersonalView-BmbFyWPb.js} +1 -1
  60. package/dist/assets/{SettingsSourceControl-CMtqqlkO.js → SettingsSourceControl-DwaOdDke.js} +1 -1
  61. package/dist/assets/{SettingsSso-Bi3OpykL.js → SettingsSso-DOC-P2wt.js} +14 -1
  62. package/dist/assets/{SettingsUsageAndPlan-C5TbwZhP.js → SettingsUsageAndPlan-DVOLlEkG.js} +1 -1
  63. package/dist/assets/{SettingsUsersView-BHuP5k0A.js → SettingsUsersView-CN_KLeIm.js} +1 -1
  64. package/dist/assets/{SettingsView-DPIIqaKN.js → SettingsView-DiAhLyco.js} +1 -1
  65. package/dist/assets/{SetupView-C4V9j6sh.js → SetupView-OE_yCNOU.js} +3 -3
  66. package/dist/assets/{SetupWorkflowCredentialsButton-BZ9ILQUp.js → SetupWorkflowCredentialsButton-Dx1IkZgW.js} +1 -1
  67. package/dist/assets/{SetupWorkflowFromTemplateView-3uV3zSU2.js → SetupWorkflowFromTemplateView-lQXKgIuL.js} +3 -3
  68. package/dist/assets/{SigninView-DWZHdCjG.js → SigninView-BWSrzbF7.js} +3 -3
  69. package/dist/assets/{SignoutView-DbduXAir.js → SignoutView-DxGgFxt2.js} +1 -1
  70. package/dist/assets/{SignupView-DWq6VACk.js → SignupView-Dtu5bMqF.js} +3 -3
  71. package/dist/assets/{TemplateDetails-BckqE6GK.js → TemplateDetails-CQ7TYqsP.js} +1 -1
  72. package/dist/assets/{TemplateList-Bw0JeBMP.js → TemplateList-Cxmv-0p-.js} +1 -1
  73. package/dist/assets/{TemplatesCollectionView-CAKT-mpV.js → TemplatesCollectionView-xvV6FXib.js} +5 -5
  74. package/dist/assets/{TemplatesSearchView-I2a5us58.js → TemplatesSearchView-CsECyZ52.js} +3 -3
  75. package/dist/assets/{TemplatesView-6EwGFFJK.js → TemplatesView-DrEKpZTU.js} +1 -1
  76. package/dist/assets/{TemplatesWorkflowView-C8xYMhwu.js → TemplatesWorkflowView-iSAL_yol.js} +5 -5
  77. package/dist/assets/{TestDefinitionEditView-CNd3Cuzq.js → TestDefinitionEditView-C3ohfu_r.js} +6 -7
  78. package/dist/assets/{TestDefinitionListView-BwTWIaAM.js → TestDefinitionListView-Dwto0jxH.js} +1 -1
  79. package/dist/assets/{TestDefinitionNewView-BQas0_G1.js → TestDefinitionNewView-9xVUm2ZJ.js} +2 -2
  80. package/dist/assets/{TestDefinitionRootView-D971MFye.js → TestDefinitionRootView-DLurQ4xl.js} +1 -1
  81. package/dist/assets/{VariablesView-DcBBuFxh.js → VariablesView-Cg2WSt_e.js} +4 -3
  82. package/dist/assets/{WorkerView-DSgBNIeb.js → WorkerView-BG-Dl0Ej.js} +6 -6
  83. package/dist/assets/{WorkflowActivator-DAyH7N29.css → WorkflowActivator-DrMTmuTZ.css} +2 -2
  84. package/dist/assets/{WorkflowActivator-CPCbgb_n.js → WorkflowActivator-e7wvW1kJ.js} +17 -11
  85. package/dist/assets/{WorkflowExecutionsInfoAccordion-Bc6vzAZu.js → WorkflowExecutionsInfoAccordion-CijtfO0l.js} +1 -1
  86. package/dist/assets/{WorkflowExecutionsLandingPage-BPPS4V9i.js → WorkflowExecutionsLandingPage-Do4y1yOx.js} +2 -2
  87. package/dist/assets/{WorkflowExecutionsPreview-Bbb5MB8Z.js → WorkflowExecutionsPreview-Bqo_3PXl.js} +6 -6
  88. package/dist/assets/{WorkflowExecutionsView-Pz-7iHJY.js → WorkflowExecutionsView-C1gS45nc.js} +10 -10
  89. package/dist/assets/{WorkflowHistory-Czo9IuI6.js → WorkflowHistory-CypQw7rC.js} +37 -19
  90. package/dist/assets/{WorkflowOnboardingView-B8DdkfJ5.js → WorkflowOnboardingView-DoKXpaNj.js} +1 -1
  91. package/dist/assets/{WorkflowPreview-eVlO1itk.js → WorkflowPreview-Bxs5XzBX.js} +1 -1
  92. package/dist/assets/{WorkflowsView-Cr2D0vym.js → WorkflowsView-BlvgD3xI.js} +299 -157
  93. package/dist/assets/{WorkflowsView-B2_HJCJ5.css → WorkflowsView-CQvTAWQ0.css} +24 -13
  94. package/dist/assets/{chartjs.utils-Dk1WO3Mr.js → chartjs.utils-CuWcgqCr.js} +2 -2
  95. package/dist/assets/{dateFormatter-C8N5khiG.js → dateFormatter-LbucaaRt.js} +1 -1
  96. package/dist/assets/{easyAiWorkflowUtils-CLqHnasO.js → easyAiWorkflowUtils-_kvYb5hw.js} +1 -1
  97. package/dist/assets/{global-link-actions-BvoZh8u9.js → global-link-actions-DG0SjhQE.js} +1 -1
  98. package/dist/assets/{import-curl-BpxkGYMX.js → import-curl-DQ6uPzZ1.js} +1 -1
  99. package/dist/assets/{index-DCpy4nCU.css → index-BA8d2DN9.css} +311 -515
  100. package/dist/assets/{index-B6eunbxp.js → index-hdsPF3tl.js} +61611 -57550
  101. package/dist/assets/{index-Br8T1Gn6.js → index-vIybYvt3.js} +1 -1
  102. package/dist/assets/{pickBy-8Urz9lDY.js → pickBy-DmKUpB7M.js} +1 -1
  103. package/dist/assets/{polyfills-CLZ4X0Ad.js → polyfills-J2x06Gdp.js} +157 -224
  104. package/dist/assets/{templateActions-DzjysjbQ.js → templateActions-DxoxchKp.js} +1 -1
  105. package/dist/assets/{typescript.worker-BsxN2afA.js → typescript.worker-B1loTpxy.js} +1 -1
  106. package/dist/assets/{useBeforeUnload-DxrN8vOO.js → useBeforeUnload-B7JAQiE8.js} +1 -1
  107. package/dist/assets/{useCanvasMapping-cuXLM-h-.css → useCanvasMapping-CFf4cwnq.css} +6 -5
  108. package/dist/assets/{useCanvasMapping-C2BQB9QB.js → useCanvasMapping-CvcOHj5p.js} +94 -50
  109. package/dist/assets/{useClearExecutionButtonVisible-BV-jMf2m.js → useClearExecutionButtonVisible-DFNEJves.js} +1 -2
  110. package/dist/assets/{useExecutionDebugging-0pPCimcw.js → useExecutionDebugging-DsRIfE0y.js} +1 -1
  111. package/dist/assets/{useExecutionHelpers-DIvhViMz.js → useExecutionHelpers-CEOL8_vt.js} +3 -3
  112. package/dist/assets/{useImportCurlCommand-BWf4R83s.js → useImportCurlCommand-DdIN4YaF.js} +2 -2
  113. package/dist/assets/useProjectPages-OGc-GAxb.js +17 -0
  114. package/dist/assets/{usePushConnection-Pobjq0U9.js → usePushConnection-DNGIaS0A.js} +29 -127
  115. package/dist/assets/{useTestDefinitionForm-BA3IS_2B.js → useTestDefinitionForm-Bi6EgFVm.js} +1 -1
  116. package/dist/assets/{useWorkflowActivate-DFqvrpj6.js → useWorkflowActivate-CJ1hLmv2.js} +1 -1
  117. package/dist/assets/{useWorkflowSaving-BACesUoL.js → useWorkflowSaving-BuokdhTC.js} +2 -2
  118. package/dist/index.html +3 -3
  119. package/package.json +1 -1
  120. package/tsconfig.json +1 -0
  121. package/vite.config.mts +4 -0
  122. package/dist/assets/CollectionParameter-BeCTpZ-q.js +0 -4
  123. package/dist/assets/InsightsSummary-gldDQ9rg.js +0 -207
  124. package/dist/assets/useCanvasOperations-DaP5jKbH.js +0 -3183
@@ -1,8 +1,7 @@
1
- import { b0 as inject, b1 as isRef, i as createElementBlock, g as openBlock, k as createBaseVNode, d as defineComponent, q as computed, j as createVNode, e as createBlock, f as createCommentVNode, m as unref, t as toDisplayString, b2 as withModifiers, _ as _export_sfc, b3 as toRefs, r as ref, o as onMounted, n as normalizeClass, x as renderSlot, b4 as normalizeProps, b5 as guardReactiveProps, b6 as resolveDynamicComponent, b7 as mergeProps, b8 as VueMarkdown, F as Fragment, D as renderList, b9 as markdownLink, ba as useFileDialog, bb as onUnmounted, B as normalizeStyle, aA as withDirectives, bc as vModelText, bd as withKeys, w as withCtx, X as watch, h as resolveComponent, l as createTextVNode, be as N8nText, bf as useClipboard, a as useToast, c as useI18n$1, aR as N8nTooltip, bg as N8nButton, aT as _sfc_main$i, aV as createSlots, aJ as useStorage, a_ as watchEffect, y as onBeforeUnmount, G as useDebounce, bh as provide, bi as useProvideTooltipAppendTo, bj as IsInPiPWindowSymbol, bk as CHAT_TRIGGER_NODE_TYPE, bl as MANUAL_CHAT_TRIGGER_NODE_TYPE, bm as NodeConnectionTypes, bn as v4, bo as get, bp as isEmpty, bq as usePinnedData, ai as useMessage, aj as MODAL_CONFIRM, br as CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE, bs as AI_SUBCATEGORY, bt as AI_CATEGORY_AGENTS, bu as AI_CATEGORY_CHAINS, bv as AI_CODE_NODE_TYPE, bw as getNodeInputs, bx as getConnectionTypes, by as getNodeOutputs, Q as useWorkflowsStore, bz as useNodeTypesStore, b as useRouter, bA as useNodeHelpers, bB as useRunWorkflow, V as VIEWS, aZ as LOGS_PANEL_STATE, bC as _sfc_main$k, bD as I18nT, bE as N8nIcon, as as useNDVStore, bF as useVirtualList, bG as N8nRadioButtons, ag as useTelemetry, z as nextTick, bH as ndvEventBus, aS as N8nLink, av as useLocalStorage, bI as LOG_DETAILS_CONTENT, aY as useTemplateRef, a$ as N8nResizeWrapper, bJ as useStyles, $ as useCanvasStore, bK as Workflow, bL as IN_PROGRESS_EXECUTION_ID, bM as useThrottleFn } from "./index-B6eunbxp.js";
2
- import { u as useClearExecutionButtonVisible } from "./useClearExecutionButtonVisible-BV-jMf2m.js";
3
- import { H as HighlightJS, f as formatTokenUsageCount, _ as _sfc_main$j, g as getSubtreeTotalConsumedTokens, a as getTotalConsumedTokens, b as flattenLogEntries, R as RunData, c as createLogEntries, d as deepToRaw, e as findSelectedLogEntry } from "./RunData-Bx47sNQp.js";
4
- import { t as toTime, a as toDayMonth } from "./dateFormatter-C8N5khiG.js";
5
- import { u as upperFirst } from "./useCanvasOperations-DaP5jKbH.js";
1
+ import { b1 as inject, b2 as isRef, i as createElementBlock, g as openBlock, k as createBaseVNode, d as defineComponent, q as computed, j as createVNode, e as createBlock, f as createCommentVNode, m as unref, t as toDisplayString, b3 as withModifiers, _ as _export_sfc, b4 as toRefs, r as ref, o as onMounted, n as normalizeClass, x as renderSlot, b5 as normalizeProps, b6 as guardReactiveProps, b7 as resolveDynamicComponent, b8 as mergeProps, F as Fragment, D as renderList, b9 as markdownLink, ba as useFileDialog, bb as chatEventBus, bc as onUnmounted, B as normalizeStyle, aA as withDirectives, bd as vModelText, be as withKeys, w as withCtx, X as watch, h as resolveComponent, l as createTextVNode, bf as N8nText, bg as useClipboard, a as useToast, p as useSettingsStore, c as useI18n$1, aR as N8nTooltip, bh as N8nButton, aT as _sfc_main$i, aV as createSlots, aJ as useStorage, a$ as watchEffect, y as onBeforeUnmount, G as useDebounce, bi as provide, bj as useProvideTooltipAppendTo, bk as IsInPiPWindowSymbol, bl as usePinnedData, ai as useMessage, aj as MODAL_CONFIRM, bm as v4, bn as getInputKey, bo as extractBotResponse, bp as isChatNode, bq as CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE, br as AI_SUBCATEGORY, bs as AI_CATEGORY_AGENTS, bt as AI_CATEGORY_CHAINS, bu as AI_CODE_NODE_TYPE, bv as getNodeInputs, bw as getConnectionTypes, bx as getNodeOutputs, by as NodeConnectionTypes, Q as useWorkflowsStore, bz as useNodeTypesStore, aY as useLogsStore, b as useRouter, bA as useNodeHelpers, bB as useRunWorkflow, bC as restoreChatHistory, V as VIEWS, aZ as useTemplateRef, bD as _sfc_main$k, bE as I18nT, bF as N8nIcon, bG as upperFirst, z as nextTick, bH as useVirtualList, bI as toRef, bJ as N8nRadioButtons, as as useNDVStore, aS as N8nLink, av as useLocalStorage, bK as LOG_DETAILS_PANEL_STATE, bL as KeyboardShortcutTooltip, b0 as N8nResizeWrapper, bM as useStyles, a_ as LOGS_PANEL_STATE, ag as useTelemetry, bN as Workflow, bO as useThrottleFn, bP as parse, bQ as ndvEventBus } from "./index-hdsPF3tl.js";
2
+ import { u as useClearExecutionButtonVisible } from "./useClearExecutionButtonVisible-DFNEJves.js";
3
+ import { H as HighlightJS, V as VueMarkdown, f as formatTokenUsageCount, _ as _sfc_main$j, g as getSubtreeTotalConsumedTokens, a as getTotalConsumedTokens, h as hasSubExecution, R as RunData, c as createLogTree, d as deepToRaw, m as mergeStartData, b as findSelectedLogEntry, e as getEntryAtRelativeIndex, i as getDepth, j as flattenLogEntries } from "./RunData-fnd-jejc.js";
4
+ import { t as toTime, a as toDayMonth } from "./dateFormatter-LbucaaRt.js";
6
5
  function bash(hljs) {
7
6
  const regex = hljs.regex;
8
7
  const VAR = {};
@@ -2798,39 +2797,6 @@ function render(_ctx, _cache) {
2798
2797
  ]));
2799
2798
  }
2800
2799
  const IconSend = { name: "mdi-send", render };
2801
- function createEventBus() {
2802
- const handlers = /* @__PURE__ */ new Map();
2803
- function off(eventName, fn) {
2804
- const eventFns = handlers.get(eventName);
2805
- if (eventFns) {
2806
- eventFns.splice(eventFns.indexOf(fn) >>> 0, 1);
2807
- }
2808
- }
2809
- function on(eventName, fn) {
2810
- let eventFns = handlers.get(eventName);
2811
- if (!eventFns) {
2812
- eventFns = [fn];
2813
- } else {
2814
- eventFns.push(fn);
2815
- }
2816
- handlers.set(eventName, eventFns);
2817
- return () => off(eventName, fn);
2818
- }
2819
- function emit(eventName, event) {
2820
- const eventFns = handlers.get(eventName);
2821
- if (eventFns) {
2822
- eventFns.slice().forEach(async (handler) => {
2823
- await handler(event);
2824
- });
2825
- }
2826
- }
2827
- return {
2828
- on,
2829
- off,
2830
- emit
2831
- };
2832
- }
2833
- const chatEventBus = createEventBus();
2834
2800
  const _hoisted_1$4 = { class: "chat-inputs" };
2835
2801
  const _hoisted_2$2 = {
2836
2802
  key: 0,
@@ -3269,7 +3235,7 @@ const cssModules$a = {
3269
3235
  };
3270
3236
  const MessageOptionAction = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__cssModules", cssModules$a]]);
3271
3237
  const _sfc_main$a = /* @__PURE__ */ defineComponent({
3272
- __name: "PanelHeader",
3238
+ __name: "LogsPanelHeader",
3273
3239
  props: {
3274
3240
  title: {}
3275
3241
  },
@@ -3313,7 +3279,7 @@ const style0$9 = {
3313
3279
  const cssModules$9 = {
3314
3280
  "$style": style0$9
3315
3281
  };
3316
- const PanelHeader = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__cssModules", cssModules$9]]);
3282
+ const LogsPanelHeader = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__cssModules", cssModules$9]]);
3317
3283
  const _hoisted_1$2 = ["onClick"];
3318
3284
  const _sfc_main$9 = /* @__PURE__ */ defineComponent({
3319
3285
  __name: "ChatMessagesPanel",
@@ -3333,6 +3299,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
3333
3299
  const clipboard = useClipboard();
3334
3300
  const locale = useI18n$1();
3335
3301
  const toast = useToast();
3302
+ const settingsStore = useSettingsStore();
3336
3303
  const previousMessageIndex = ref(0);
3337
3304
  const sessionIdText = computed(
3338
3305
  () => locale.baseText("chat.window.session.id", {
@@ -3399,7 +3366,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
3399
3366
  watch(
3400
3367
  () => props.isOpen,
3401
3368
  (isOpen) => {
3402
- if (isOpen) {
3369
+ if (isOpen && !settingsStore.isNewLogsEnabled) {
3403
3370
  setTimeout(() => {
3404
3371
  chatEventBus.emit("focusInput");
3405
3372
  }, 0);
@@ -3409,10 +3376,11 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
3409
3376
  );
3410
3377
  return (_ctx, _cache) => {
3411
3378
  return openBlock(), createElementBlock("div", {
3412
- class: normalizeClass(_ctx.$style.chat),
3413
- "data-test-id": "workflow-lm-chat-dialog"
3379
+ class: normalizeClass([_ctx.$style.chat, "ignore-key-press-canvas"]),
3380
+ "data-test-id": "workflow-lm-chat-dialog",
3381
+ tabindex: "0"
3414
3382
  }, [
3415
- _ctx.isNewLogsEnabled ? (openBlock(), createBlock(PanelHeader, {
3383
+ _ctx.isNewLogsEnabled ? (openBlock(), createBlock(LogsPanelHeader, {
3416
3384
  key: 0,
3417
3385
  "data-test-id": "chat-header",
3418
3386
  title: unref(locale).baseText("chat.window.title"),
@@ -3776,85 +3744,6 @@ function usePiPWindow({
3776
3744
  });
3777
3745
  return { canPopOut, isPoppedOut, pipWindow };
3778
3746
  }
3779
- function isChatNode(node) {
3780
- return [CHAT_TRIGGER_NODE_TYPE, MANUAL_CHAT_TRIGGER_NODE_TYPE].includes(node.type);
3781
- }
3782
- function getInputKey(node) {
3783
- if (node.type === MANUAL_CHAT_TRIGGER_NODE_TYPE && node.typeVersion < 1.1) {
3784
- return "input";
3785
- }
3786
- if (node.type === CHAT_TRIGGER_NODE_TYPE) {
3787
- return "chatInput";
3788
- }
3789
- return "chatInput";
3790
- }
3791
- function extractChatInput(workflow, resultData) {
3792
- const chatTrigger = workflow.nodes.find(isChatNode);
3793
- if (chatTrigger === void 0) {
3794
- return void 0;
3795
- }
3796
- const inputKey = getInputKey(chatTrigger);
3797
- const runData = (resultData.runData[chatTrigger.name] ?? [])[0];
3798
- const message = runData?.data?.[NodeConnectionTypes.Main]?.[0]?.[0]?.json?.[inputKey];
3799
- if (runData === void 0 || typeof message !== "string") {
3800
- return void 0;
3801
- }
3802
- return {
3803
- text: message,
3804
- sender: "user",
3805
- id: v4()
3806
- };
3807
- }
3808
- function extractBotResponse(resultData, executionId, emptyText2) {
3809
- const lastNodeExecuted = resultData.lastNodeExecuted;
3810
- if (!lastNodeExecuted) return void 0;
3811
- const nodeResponseDataArray = get(resultData.runData, lastNodeExecuted) ?? [];
3812
- const nodeResponseData = nodeResponseDataArray[nodeResponseDataArray.length - 1];
3813
- let responseMessage;
3814
- if (get(nodeResponseData, "error")) {
3815
- responseMessage = "[ERROR: " + get(nodeResponseData, "error.message") + "]";
3816
- } else {
3817
- const responseData = get(nodeResponseData, "data.main[0][0].json");
3818
- const text = extractResponseText(responseData) ?? emptyText2;
3819
- if (!text) {
3820
- return void 0;
3821
- }
3822
- responseMessage = text;
3823
- }
3824
- return {
3825
- text: responseMessage,
3826
- sender: "bot",
3827
- id: executionId ?? v4()
3828
- };
3829
- }
3830
- function extractResponseText(responseData) {
3831
- if (!responseData || isEmpty(responseData)) {
3832
- return void 0;
3833
- }
3834
- const paths = ["output", "text", "response.text"];
3835
- const matchedPath = paths.find((path) => get(responseData, path));
3836
- if (!matchedPath) return JSON.stringify(responseData, null, 2);
3837
- const matchedOutput = get(responseData, matchedPath);
3838
- if (typeof matchedOutput === "object") {
3839
- return "```json\n" + JSON.stringify(matchedOutput, null, 2) + "\n```";
3840
- }
3841
- return matchedOutput?.toString() ?? "";
3842
- }
3843
- function restoreChatHistory(workflowExecutionData, emptyText2) {
3844
- if (!workflowExecutionData?.data) {
3845
- return [];
3846
- }
3847
- const userMessage = extractChatInput(
3848
- workflowExecutionData.workflowData,
3849
- workflowExecutionData.data.resultData
3850
- );
3851
- const botMessage = extractBotResponse(
3852
- workflowExecutionData.data.resultData,
3853
- workflowExecutionData.id,
3854
- emptyText2
3855
- );
3856
- return [...userMessage ? [userMessage] : [], ...botMessage ? [botMessage] : []];
3857
- }
3858
3747
  function useChatMessaging({
3859
3748
  chatTrigger,
3860
3749
  messages: messages2,
@@ -4047,13 +3936,13 @@ function useChatState(isReadOnly) {
4047
3936
  const locale = useI18n$1();
4048
3937
  const workflowsStore = useWorkflowsStore();
4049
3938
  const nodeTypesStore = useNodeTypesStore();
3939
+ const logsStore = useLogsStore();
4050
3940
  const router = useRouter();
4051
3941
  const nodeHelpers = useNodeHelpers();
4052
3942
  const { runWorkflow } = useRunWorkflow({ router });
4053
3943
  const messages2 = ref([]);
4054
3944
  const currentSessionId = ref(v4().replace(/-/g, ""));
4055
3945
  const previousChatMessages = computed(() => workflowsStore.getPastChatMessages);
4056
- const logsPanelState = computed(() => workflowsStore.logsPanelState);
4057
3946
  const workflow = computed(() => workflowsStore.getCurrentWorkflow());
4058
3947
  const { chatTriggerNode, connectedNode, allowFileUploads, allowedFilesMimeTypes } = useChatTrigger({
4059
3948
  workflow,
@@ -4147,7 +4036,7 @@ function useChatState(isReadOnly) {
4147
4036
  nodeHelpers.updateNodesExecutionIssues();
4148
4037
  messages2.value = [];
4149
4038
  currentSessionId.value = v4().replace(/-/g, "");
4150
- if (logsPanelState.value !== LOGS_PANEL_STATE.CLOSED) {
4039
+ if (logsStore.isOpen) {
4151
4040
  chatEventBus.emit("focusInput");
4152
4041
  }
4153
4042
  }
@@ -4170,7 +4059,7 @@ function useChatState(isReadOnly) {
4170
4059
  };
4171
4060
  }
4172
4061
  const _sfc_main$8 = /* @__PURE__ */ defineComponent({
4173
- __name: "ConsumedTokenCountText",
4062
+ __name: "LogsViewConsumedTokenCountText",
4174
4063
  props: {
4175
4064
  consumedTokens: {}
4176
4065
  },
@@ -4200,7 +4089,7 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
4200
4089
  const _hoisted_1$1 = { key: 0 };
4201
4090
  const _hoisted_2 = { key: 1 };
4202
4091
  const _sfc_main$7 = /* @__PURE__ */ defineComponent({
4203
- __name: "NodeName",
4092
+ __name: "LogsViewNodeName",
4204
4093
  props: {
4205
4094
  name: {},
4206
4095
  latestName: {},
@@ -4232,23 +4121,25 @@ const style0$7 = {
4232
4121
  const cssModules$7 = {
4233
4122
  "$style": style0$7
4234
4123
  };
4235
- const NodeName = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__cssModules", cssModules$7]]);
4236
- const _hoisted_1 = ["aria-expanded"];
4124
+ const LogsViewNodeName = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__cssModules", cssModules$7]]);
4125
+ const _hoisted_1 = ["aria-expanded", "aria-selected"];
4237
4126
  const _sfc_main$6 = /* @__PURE__ */ defineComponent({
4238
4127
  __name: "LogsOverviewRow",
4239
4128
  props: {
4240
4129
  data: {},
4241
4130
  isSelected: { type: Boolean },
4242
4131
  isReadOnly: { type: Boolean },
4243
- shouldShowConsumedTokens: { type: Boolean },
4132
+ shouldShowTokenCountColumn: { type: Boolean },
4244
4133
  isCompact: { type: Boolean },
4245
4134
  latestInfo: {},
4246
- expanded: { type: Boolean }
4135
+ expanded: { type: Boolean },
4136
+ canOpenNdv: { type: Boolean }
4247
4137
  },
4248
- emits: ["toggleExpanded", "triggerPartialExecution", "openNdv"],
4138
+ emits: ["toggleExpanded", "toggleSelected", "triggerPartialExecution", "openNdv"],
4249
4139
  setup(__props, { emit: __emit }) {
4250
4140
  const props = __props;
4251
4141
  const emit = __emit;
4142
+ const container2 = useTemplateRef("containerRef");
4252
4143
  const locale = useI18n$1();
4253
4144
  const nodeTypeStore = useNodeTypesStore();
4254
4145
  const type = computed(() => nodeTypeStore.getNodeType(props.data.node.type));
@@ -4265,7 +4156,10 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
4265
4156
  });
4266
4157
  });
4267
4158
  const subtreeConsumedTokens = computed(
4268
- () => props.shouldShowConsumedTokens ? getSubtreeTotalConsumedTokens(props.data) : void 0
4159
+ () => props.shouldShowTokenCountColumn ? getSubtreeTotalConsumedTokens(props.data, false) : void 0
4160
+ );
4161
+ const hasChildren = computed(
4162
+ () => props.data.children.length > 0 || !!props.data.runData.metadata?.subExecution
4269
4163
  );
4270
4164
  function isLastChild(level) {
4271
4165
  let parent = props.data.parent;
@@ -4278,18 +4172,32 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
4278
4172
  const lastSibling = siblings[siblings.length - 1];
4279
4173
  return data === void 0 && lastSibling === void 0 || data?.node === lastSibling?.node && data?.runIndex === lastSibling?.runIndex;
4280
4174
  }
4175
+ watch(
4176
+ () => props.isSelected,
4177
+ (isSelected) => {
4178
+ void nextTick(() => {
4179
+ if (isSelected) {
4180
+ container2.value?.focus();
4181
+ }
4182
+ });
4183
+ },
4184
+ { immediate: true }
4185
+ );
4281
4186
  return (_ctx, _cache) => {
4282
4187
  const _component_NodeIcon = _sfc_main$k;
4283
4188
  return openBlock(), createElementBlock("div", {
4189
+ ref: "containerRef",
4284
4190
  role: "treeitem",
4285
- tabindex: "0",
4191
+ tabindex: "-1",
4286
4192
  "aria-expanded": props.data.children.length > 0 && props.expanded,
4193
+ "aria-selected": props.isSelected,
4287
4194
  class: normalizeClass({
4288
4195
  [_ctx.$style.container]: true,
4289
4196
  [_ctx.$style.compact]: props.isCompact,
4290
4197
  [_ctx.$style.error]: isError.value,
4291
4198
  [_ctx.$style.selected]: props.isSelected
4292
- })
4199
+ }),
4200
+ onClick: _cache[3] || (_cache[3] = withModifiers(($event) => emit("toggleSelected"), ["stop"]))
4293
4201
  }, [
4294
4202
  (openBlock(true), createElementBlock(Fragment, null, renderList(props.data.depth, (level) => {
4295
4203
  return openBlock(), createElementBlock("div", {
@@ -4310,7 +4218,7 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
4310
4218
  size: 16,
4311
4219
  class: normalizeClass(_ctx.$style.icon)
4312
4220
  }, null, 8, ["node-type", "class"]),
4313
- createVNode(NodeName, {
4221
+ createVNode(LogsViewNodeName, {
4314
4222
  class: normalizeClass(_ctx.$style.name),
4315
4223
  "latest-name": _ctx.latestInfo?.name ?? props.data.node.name,
4316
4224
  name: props.data.node.name,
@@ -4397,12 +4305,15 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
4397
4305
  type: "secondary",
4398
4306
  size: "medium",
4399
4307
  icon: "edit",
4400
- style: { "color": "var(--color-text-base)" },
4308
+ style: normalizeStyle([{ "color": "var(--color-text-base)" }, {
4309
+ visibility: props.canOpenNdv ? "" : "hidden",
4310
+ color: "var(--color-text-base)"
4311
+ }]),
4401
4312
  disabled: props.latestInfo?.deleted,
4402
4313
  class: normalizeClass(_ctx.$style.openNdvButton),
4403
4314
  "aria-label": unref(locale).baseText("logs.overview.body.open"),
4404
- onClick: _cache[0] || (_cache[0] = withModifiers(($event) => emit("openNdv", props.data), ["stop"]))
4405
- }, null, 8, ["disabled", "class", "aria-label"])) : createCommentVNode("", true),
4315
+ onClick: _cache[0] || (_cache[0] = withModifiers(($event) => emit("openNdv"), ["stop"]))
4316
+ }, null, 8, ["style", "disabled", "class", "aria-label"])) : createCommentVNode("", true),
4406
4317
  !_ctx.isCompact || !props.isReadOnly && !props.latestInfo?.deleted && !props.latestInfo?.disabled ? (openBlock(), createBlock(unref(_sfc_main$i), {
4407
4318
  key: 5,
4408
4319
  type: "secondary",
@@ -4412,21 +4323,21 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
4412
4323
  "aria-label": unref(locale).baseText("logs.overview.body.run"),
4413
4324
  class: normalizeClass([_ctx.$style.partialExecutionButton, props.data.depth > 0 ? _ctx.$style.unavailable : ""]),
4414
4325
  disabled: props.latestInfo?.deleted || props.latestInfo?.disabled,
4415
- onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emit("triggerPartialExecution", props.data), ["stop"]))
4326
+ onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emit("triggerPartialExecution"), ["stop"]))
4416
4327
  }, null, 8, ["aria-label", "class", "disabled"])) : createCommentVNode("", true),
4417
- !_ctx.isCompact || props.data.children.length > 0 ? (openBlock(), createBlock(unref(N8nButton), {
4328
+ !_ctx.isCompact || hasChildren.value ? (openBlock(), createBlock(unref(N8nButton), {
4418
4329
  key: 6,
4419
4330
  type: "secondary",
4420
4331
  size: "small",
4421
4332
  square: true,
4422
4333
  style: normalizeStyle({
4423
- visibility: props.data.children.length === 0 ? "hidden" : "",
4334
+ visibility: hasChildren.value ? "" : "hidden",
4424
4335
  color: "var(--color-text-base)"
4425
4336
  // give higher specificity than the style from the component itself
4426
4337
  }),
4427
4338
  class: normalizeClass(_ctx.$style.toggleButton),
4428
4339
  "aria-label": unref(locale).baseText("logs.overview.body.toggleRow"),
4429
- onClick: _cache[2] || (_cache[2] = withModifiers(($event) => emit("toggleExpanded", props.data), ["stop"]))
4340
+ onClick: _cache[2] || (_cache[2] = withModifiers(($event) => emit("toggleExpanded"), ["stop"]))
4430
4341
  }, {
4431
4342
  default: withCtx(() => [
4432
4343
  createVNode(unref(N8nIcon), {
@@ -4485,7 +4396,7 @@ const cssModules$6 = {
4485
4396
  };
4486
4397
  const LogsOverviewRow = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__cssModules", cssModules$6]]);
4487
4398
  const _sfc_main$5 = /* @__PURE__ */ defineComponent({
4488
- __name: "ExecutionSummary",
4399
+ __name: "LogsViewExecutionSummary",
4489
4400
  props: {
4490
4401
  status: {},
4491
4402
  consumedTokens: {},
@@ -4527,7 +4438,7 @@ const style0$5 = {
4527
4438
  const cssModules$5 = {
4528
4439
  "$style": style0$5
4529
4440
  };
4530
- const ExecutionSummary = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__cssModules", cssModules$5]]);
4441
+ const LogsViewExecutionSummary = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__cssModules", cssModules$5]]);
4531
4442
  const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4532
4443
  __name: "LogsOverviewPanel",
4533
4444
  props: {
@@ -4536,62 +4447,49 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4536
4447
  isReadOnly: { type: Boolean },
4537
4448
  isCompact: { type: Boolean },
4538
4449
  execution: {},
4539
- latestNodeInfo: {},
4540
- scrollToSelection: { type: Boolean }
4450
+ entries: {},
4451
+ flatLogEntries: {},
4452
+ latestNodeInfo: {}
4541
4453
  },
4542
- emits: ["clickHeader", "select", "clearExecutionData"],
4454
+ emits: ["clickHeader", "select", "clearExecutionData", "openNdv", "toggleExpanded", "loadSubExecution"],
4543
4455
  setup(__props, { emit: __emit }) {
4544
4456
  const emit = __emit;
4545
4457
  const locale = useI18n$1();
4546
- const telemetry = useTelemetry();
4547
4458
  const router = useRouter();
4548
4459
  const runWorkflow = useRunWorkflow({ router });
4549
- const ndvStore = useNDVStore();
4550
4460
  const isClearExecutionButtonVisible = useClearExecutionButtonVisible();
4551
- const isEmpty2 = computed(() => __props.execution === void 0);
4461
+ const isEmpty = computed(() => __props.flatLogEntries.length === 0 || __props.execution === void 0);
4552
4462
  const switchViewOptions = computed(() => [
4553
4463
  { label: locale.baseText("logs.overview.header.switch.overview"), value: "overview" },
4554
4464
  { label: locale.baseText("logs.overview.header.switch.details"), value: "details" }
4555
4465
  ]);
4556
4466
  const consumedTokens2 = computed(
4557
- () => getTotalConsumedTokens(...(__props.execution?.tree ?? []).map(getSubtreeTotalConsumedTokens))
4467
+ () => getTotalConsumedTokens(
4468
+ ...__props.entries.map(
4469
+ (entry) => getSubtreeTotalConsumedTokens(
4470
+ entry,
4471
+ false
4472
+ // Exclude token usages from sub workflow which is loaded only after expanding the row
4473
+ )
4474
+ )
4475
+ )
4558
4476
  );
4559
- const collapsedEntries = ref({});
4560
- const flatLogEntries = computed(
4561
- () => flattenLogEntries(__props.execution?.tree ?? [], collapsedEntries.value)
4477
+ const shouldShowTokenCountColumn = computed(
4478
+ () => consumedTokens2.value.totalTokens > 0 || __props.entries.some((entry) => getSubtreeTotalConsumedTokens(entry, true).totalTokens > 0)
4479
+ );
4480
+ const virtualList = useVirtualList(
4481
+ toRef(() => __props.flatLogEntries),
4482
+ { itemHeight: 32 }
4562
4483
  );
4563
- const virtualList = useVirtualList(flatLogEntries, { itemHeight: 32 });
4564
- function handleClickNode(clicked) {
4565
- if (__props.selected?.node === clicked.node && __props.selected?.runIndex === clicked.runIndex) {
4566
- emit("select", void 0);
4567
- return;
4568
- }
4569
- emit("select", clicked);
4570
- telemetry.track("User selected node in log view", {
4571
- node_type: clicked.node.type,
4572
- node_id: clicked.node.id,
4573
- execution_id: __props.execution?.id,
4574
- workflow_id: __props.execution?.workflowData.id
4575
- });
4576
- }
4577
4484
  function handleSwitchView(value) {
4578
- emit(
4579
- "select",
4580
- value === "overview" || (__props.execution?.tree ?? []).length === 0 ? void 0 : __props.execution?.tree[0]
4581
- );
4485
+ emit("select", value === "overview" ? void 0 : __props.flatLogEntries[0]);
4582
4486
  }
4583
4487
  function handleToggleExpanded(treeNode) {
4584
- collapsedEntries.value[treeNode.id] = !collapsedEntries.value[treeNode.id];
4585
- }
4586
- async function handleOpenNdv(treeNode) {
4587
- ndvStore.setActiveNodeName(treeNode.node.name);
4588
- await nextTick(() => {
4589
- const source = treeNode.runData.source[0];
4590
- const inputBranch = source?.previousNodeOutput ?? 0;
4591
- ndvEventBus.emit("updateInputNodeName", source?.previousNode);
4592
- ndvEventBus.emit("setInputBranchIndex", inputBranch);
4593
- ndvStore.setOutputRunIndex(treeNode.runIndex);
4594
- });
4488
+ if (hasSubExecution(treeNode) && treeNode.children.length === 0) {
4489
+ emit("loadSubExecution", treeNode);
4490
+ return;
4491
+ }
4492
+ emit("toggleExpanded", treeNode);
4595
4493
  }
4596
4494
  async function handleTriggerPartialExecution(treeNode) {
4597
4495
  const latestName = __props.latestNodeInfo[treeNode.node.id]?.name ?? treeNode.node.name;
@@ -4600,10 +4498,10 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4600
4498
  }
4601
4499
  }
4602
4500
  watch(
4603
- () => __props.scrollToSelection ? __props.selected : void 0,
4604
- async (entry) => {
4605
- if (entry) {
4606
- const index = flatLogEntries.value.findIndex((e) => e.id === entry.id);
4501
+ () => __props.selected,
4502
+ async (selection) => {
4503
+ if (selection && virtualList.list.value.every((e) => e.data.id !== selection.id)) {
4504
+ const index = __props.flatLogEntries.findIndex((e) => e.id === selection?.id);
4607
4505
  if (index >= 0) {
4608
4506
  await nextTick(() => virtualList.scrollTo(index));
4609
4507
  }
@@ -4616,7 +4514,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4616
4514
  class: normalizeClass(_ctx.$style.container),
4617
4515
  "data-test-id": "logs-overview"
4618
4516
  }, [
4619
- createVNode(PanelHeader, {
4517
+ createVNode(LogsPanelHeader, {
4620
4518
  title: unref(locale).baseText("logs.overview.header.title"),
4621
4519
  "data-test-id": "logs-overview-header",
4622
4520
  onClick: _cache[1] || (_cache[1] = ($event) => emit("clickHeader"))
@@ -4632,6 +4530,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4632
4530
  type: "secondary",
4633
4531
  icon: "trash",
4634
4532
  "icon-size": "medium",
4533
+ "data-test-id": "clear-execution-data-button",
4635
4534
  class: normalizeClass(_ctx.$style.clearButton),
4636
4535
  onClick: _cache[0] || (_cache[0] = withModifiers(($event) => emit("clearExecutionData"), ["stop"]))
4637
4536
  }, {
@@ -4649,10 +4548,10 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4649
4548
  }, 8, ["title"]),
4650
4549
  _ctx.isOpen ? (openBlock(), createElementBlock("div", {
4651
4550
  key: 0,
4652
- class: normalizeClass([_ctx.$style.content, isEmpty2.value ? _ctx.$style.empty : ""]),
4551
+ class: normalizeClass([_ctx.$style.content, isEmpty.value ? _ctx.$style.empty : ""]),
4653
4552
  "data-test-id": "logs-overview-body"
4654
4553
  }, [
4655
- isEmpty2.value ? (openBlock(), createBlock(unref(N8nText), {
4554
+ isEmpty.value || _ctx.execution === void 0 ? (openBlock(), createBlock(unref(N8nText), {
4656
4555
  key: 0,
4657
4556
  tag: "p",
4658
4557
  size: "medium",
@@ -4665,13 +4564,13 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4665
4564
  ]),
4666
4565
  _: 1
4667
4566
  }, 8, ["class"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
4668
- _ctx.execution ? (openBlock(), createBlock(ExecutionSummary, {
4669
- key: 0,
4567
+ createVNode(LogsViewExecutionSummary, {
4568
+ "data-test-id": "logs-overview-status",
4670
4569
  class: normalizeClass(_ctx.$style.summary),
4671
4570
  status: _ctx.execution.status,
4672
4571
  "consumed-tokens": consumedTokens2.value,
4673
4572
  "time-took": _ctx.execution.startedAt && _ctx.execution.stoppedAt ? +new Date(_ctx.execution.stoppedAt) - +new Date(_ctx.execution.startedAt) : void 0
4674
- }, null, 8, ["class", "status", "consumed-tokens", "time-took"])) : createCommentVNode("", true),
4573
+ }, null, 8, ["class", "status", "consumed-tokens", "time-took"]),
4675
4574
  createBaseVNode("div", mergeProps({
4676
4575
  class: _ctx.$style.tree
4677
4576
  }, unref(virtualList).containerProps), [
@@ -4681,16 +4580,17 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
4681
4580
  key: index,
4682
4581
  data,
4683
4582
  "is-read-only": _ctx.isReadOnly,
4684
- "is-selected": data.node.name === _ctx.selected?.node.name && data.runIndex === _ctx.selected?.runIndex,
4583
+ "is-selected": data.id === _ctx.selected?.id,
4685
4584
  "is-compact": _ctx.isCompact,
4686
- "should-show-consumed-tokens": consumedTokens2.value.totalTokens > 0,
4585
+ "should-show-token-count-column": shouldShowTokenCountColumn.value,
4687
4586
  "latest-info": _ctx.latestNodeInfo[data.node.id],
4688
- expanded: !collapsedEntries.value[data.id],
4689
- onClick: withModifiers(($event) => handleClickNode(data), ["stop"]),
4690
- onToggleExpanded: handleToggleExpanded,
4691
- onOpenNdv: handleOpenNdv,
4692
- onTriggerPartialExecution: handleTriggerPartialExecution
4693
- }, null, 8, ["data", "is-read-only", "is-selected", "is-compact", "should-show-consumed-tokens", "latest-info", "expanded", "onClick"]);
4587
+ expanded: unref(virtualList).list.value[index + 1]?.data.parent?.id === data.id,
4588
+ "can-open-ndv": data.executionId === _ctx.execution?.id,
4589
+ onToggleExpanded: ($event) => handleToggleExpanded(data),
4590
+ onOpenNdv: ($event) => emit("openNdv", data),
4591
+ onTriggerPartialExecution: ($event) => handleTriggerPartialExecution(data),
4592
+ onToggleSelected: ($event) => emit("select", _ctx.selected?.id === data.id ? void 0 : data)
4593
+ }, null, 8, ["data", "is-read-only", "is-selected", "is-compact", "should-show-token-count-column", "latest-info", "expanded", "can-open-ndv", "onToggleExpanded", "onOpenNdv", "onTriggerPartialExecution", "onToggleSelected"]);
4694
4594
  }), 128))
4695
4595
  ], 16)
4696
4596
  ], 16),
@@ -4730,13 +4630,11 @@ const cssModules$4 = {
4730
4630
  };
4731
4631
  const LogsOverviewPanel = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__cssModules", cssModules$4]]);
4732
4632
  const _sfc_main$3 = /* @__PURE__ */ defineComponent({
4733
- __name: "RunDataView",
4633
+ __name: "LogsViewRunData",
4734
4634
  props: {
4735
4635
  title: {},
4736
4636
  paneType: {},
4737
- logEntry: {},
4738
- workflow: {},
4739
- execution: {}
4637
+ logEntry: {}
4740
4638
  },
4741
4639
  setup(__props) {
4742
4640
  const locale = useI18n$1();
@@ -4748,7 +4646,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
4748
4646
  return { node: __props.logEntry.node, runIndex: __props.logEntry.runIndex };
4749
4647
  }
4750
4648
  const source = __props.logEntry.runData.source[0];
4751
- const node = source && __props.workflow.getNode(source.previousNode);
4649
+ const node = source && __props.logEntry.workflow.getNode(source.previousNode);
4752
4650
  if (!source || !node) {
4753
4651
  return void 0;
4754
4652
  }
@@ -4770,8 +4668,8 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
4770
4668
  }
4771
4669
  return (_ctx, _cache) => {
4772
4670
  return runDataProps.value ? (openBlock(), createBlock(RunData, mergeProps({ key: 0 }, runDataProps.value, {
4773
- workflow: _ctx.workflow,
4774
- "workflow-execution": _ctx.execution,
4671
+ workflow: _ctx.logEntry.workflow,
4672
+ "workflow-execution": _ctx.logEntry.execution,
4775
4673
  "too-much-data-title": unref(locale).baseText("ndv.output.tooMuchData.title"),
4776
4674
  "no-data-in-branch-message": unref(locale).baseText("ndv.output.noOutputDataInBranch"),
4777
4675
  "executing-message": unref(locale).baseText("ndv.output.executing"),
@@ -4849,7 +4747,7 @@ const style0$3 = {
4849
4747
  const cssModules$3 = {
4850
4748
  "$style": style0$3
4851
4749
  };
4852
- const RunDataView = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__cssModules", cssModules$3]]);
4750
+ const LogsViewRunData = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__cssModules", cssModules$3]]);
4853
4751
  function useResizablePanel(localStorageKey, {
4854
4752
  container: container2,
4855
4753
  defaultSize,
@@ -4947,24 +4845,17 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
4947
4845
  props: {
4948
4846
  isOpen: { type: Boolean },
4949
4847
  logEntry: {},
4950
- workflow: {},
4951
- execution: {},
4952
4848
  window: {},
4953
- latestInfo: {}
4849
+ latestInfo: {},
4850
+ panels: {}
4954
4851
  },
4955
- emits: ["clickHeader"],
4852
+ emits: ["clickHeader", "toggleInputOpen", "toggleOutputOpen"],
4956
4853
  setup(__props, { emit: __emit }) {
4957
4854
  const emit = __emit;
4958
4855
  const locale = useI18n$1();
4959
- const telemetry = useTelemetry();
4960
4856
  const nodeTypeStore = useNodeTypesStore();
4961
- const content2 = useLocalStorage(
4962
- "N8N_LOGS_DETAIL_PANEL_CONTENT",
4963
- LOG_DETAILS_CONTENT.OUTPUT,
4964
- { writeDefaults: false }
4965
- );
4966
4857
  const type = computed(() => nodeTypeStore.getNodeType(__props.logEntry.node.type));
4967
- const consumedTokens2 = computed(() => getSubtreeTotalConsumedTokens(__props.logEntry));
4858
+ const consumedTokens2 = computed(() => getSubtreeTotalConsumedTokens(__props.logEntry, false));
4968
4859
  const isTriggerNode = computed(() => type.value?.group.includes("trigger"));
4969
4860
  const container2 = useTemplateRef("container");
4970
4861
  const resizer = useResizablePanel("N8N_LOGS_INPUT_PANEL_WIDTH", {
@@ -4975,35 +4866,13 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
4975
4866
  allowCollapse: true,
4976
4867
  allowFullSize: true
4977
4868
  });
4978
- const shouldResize = computed(() => content2.value === LOG_DETAILS_CONTENT.BOTH);
4979
- function handleToggleInput(open) {
4980
- const wasOpen = [LOG_DETAILS_CONTENT.INPUT, LOG_DETAILS_CONTENT.BOTH].includes(content2.value);
4981
- if (open === wasOpen) {
4982
- return;
4983
- }
4984
- content2.value = wasOpen ? LOG_DETAILS_CONTENT.OUTPUT : LOG_DETAILS_CONTENT.BOTH;
4985
- telemetry.track("User toggled log view sub pane", {
4986
- pane: "input",
4987
- newState: wasOpen ? "hidden" : "visible"
4988
- });
4989
- }
4990
- function handleToggleOutput(open) {
4991
- const wasOpen = [LOG_DETAILS_CONTENT.OUTPUT, LOG_DETAILS_CONTENT.BOTH].includes(content2.value);
4992
- if (open === wasOpen) {
4993
- return;
4994
- }
4995
- content2.value = wasOpen ? LOG_DETAILS_CONTENT.INPUT : LOG_DETAILS_CONTENT.BOTH;
4996
- telemetry.track("User toggled log view sub pane", {
4997
- pane: "output",
4998
- newState: wasOpen ? "hidden" : "visible"
4999
- });
5000
- }
4869
+ const shouldResize = computed(() => __props.panels === LOG_DETAILS_PANEL_STATE.BOTH);
5001
4870
  function handleResizeEnd() {
5002
4871
  if (resizer.isCollapsed.value) {
5003
- handleToggleInput(false);
4872
+ emit("toggleInputOpen", false);
5004
4873
  }
5005
4874
  if (resizer.isFullSize.value) {
5006
- handleToggleOutput(false);
4875
+ emit("toggleOutputOpen", false);
5007
4876
  }
5008
4877
  resizer.onResizeEnd();
5009
4878
  }
@@ -5014,10 +4883,10 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
5014
4883
  class: normalizeClass(_ctx.$style.container),
5015
4884
  "data-test-id": "log-details"
5016
4885
  }, [
5017
- createVNode(PanelHeader, {
4886
+ createVNode(LogsPanelHeader, {
5018
4887
  "data-test-id": "log-details-header",
5019
4888
  class: normalizeClass(_ctx.$style.header),
5020
- onClick: _cache[0] || (_cache[0] = ($event) => emit("clickHeader"))
4889
+ onClick: _cache[2] || (_cache[2] = ($event) => emit("clickHeader"))
5021
4890
  }, {
5022
4891
  title: withCtx(() => [
5023
4892
  createBaseVNode("div", {
@@ -5028,12 +4897,12 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
5028
4897
  size: 16,
5029
4898
  class: normalizeClass(_ctx.$style.icon)
5030
4899
  }, null, 8, ["node-type", "class"]),
5031
- createVNode(NodeName, {
4900
+ createVNode(LogsViewNodeName, {
5032
4901
  "latest-name": _ctx.latestInfo?.name ?? _ctx.logEntry.node.name,
5033
4902
  name: _ctx.logEntry.node.name,
5034
4903
  "is-deleted": _ctx.latestInfo?.deleted ?? false
5035
4904
  }, null, 8, ["latest-name", "name", "is-deleted"]),
5036
- _ctx.isOpen ? (openBlock(), createBlock(ExecutionSummary, {
4905
+ _ctx.isOpen ? (openBlock(), createBlock(LogsViewExecutionSummary, {
5037
4906
  key: 0,
5038
4907
  class: normalizeClass(_ctx.$style.executionSummary),
5039
4908
  status: _ctx.logEntry.runData.executionStatus ?? "unknown",
@@ -5047,28 +4916,44 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
5047
4916
  key: 0,
5048
4917
  class: normalizeClass(_ctx.$style.actions)
5049
4918
  }, [
5050
- createVNode(unref(N8nButton), {
5051
- size: "mini",
5052
- type: "secondary",
5053
- class: normalizeClass(unref(content2) === unref(LOG_DETAILS_CONTENT).OUTPUT ? "" : _ctx.$style.pressed),
5054
- onClick: withModifiers(handleToggleInput, ["stop"])
4919
+ createVNode(KeyboardShortcutTooltip, {
4920
+ label: unref(locale).baseText("generic.shortcutHint"),
4921
+ shortcut: { keys: ["i"] }
5055
4922
  }, {
5056
4923
  default: withCtx(() => [
5057
- createTextVNode(toDisplayString(unref(locale).baseText("logs.details.header.actions.input")), 1)
4924
+ createVNode(unref(N8nButton), {
4925
+ size: "mini",
4926
+ type: "secondary",
4927
+ class: normalizeClass(_ctx.panels === unref(LOG_DETAILS_PANEL_STATE).OUTPUT ? "" : _ctx.$style.pressed),
4928
+ onClick: _cache[0] || (_cache[0] = withModifiers(($event) => emit("toggleInputOpen"), ["stop"]))
4929
+ }, {
4930
+ default: withCtx(() => [
4931
+ createTextVNode(toDisplayString(unref(locale).baseText("logs.details.header.actions.input")), 1)
4932
+ ]),
4933
+ _: 1
4934
+ }, 8, ["class"])
5058
4935
  ]),
5059
4936
  _: 1
5060
- }, 8, ["class"]),
5061
- createVNode(unref(N8nButton), {
5062
- size: "mini",
5063
- type: "secondary",
5064
- class: normalizeClass(unref(content2) === unref(LOG_DETAILS_CONTENT).INPUT ? "" : _ctx.$style.pressed),
5065
- onClick: withModifiers(handleToggleOutput, ["stop"])
4937
+ }, 8, ["label"]),
4938
+ createVNode(KeyboardShortcutTooltip, {
4939
+ label: unref(locale).baseText("generic.shortcutHint"),
4940
+ shortcut: { keys: ["o"] }
5066
4941
  }, {
5067
4942
  default: withCtx(() => [
5068
- createTextVNode(toDisplayString(unref(locale).baseText("logs.details.header.actions.output")), 1)
4943
+ createVNode(unref(N8nButton), {
4944
+ size: "mini",
4945
+ type: "secondary",
4946
+ class: normalizeClass(_ctx.panels === unref(LOG_DETAILS_PANEL_STATE).INPUT ? "" : _ctx.$style.pressed),
4947
+ onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emit("toggleOutputOpen"), ["stop"]))
4948
+ }, {
4949
+ default: withCtx(() => [
4950
+ createTextVNode(toDisplayString(unref(locale).baseText("logs.details.header.actions.output")), 1)
4951
+ ]),
4952
+ _: 1
4953
+ }, 8, ["class"])
5069
4954
  ]),
5070
4955
  _: 1
5071
- }, 8, ["class"])
4956
+ }, 8, ["label"])
5072
4957
  ], 2)) : createCommentVNode("", true),
5073
4958
  renderSlot(_ctx.$slots, "actions")
5074
4959
  ]),
@@ -5079,7 +4964,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
5079
4964
  class: normalizeClass(_ctx.$style.content),
5080
4965
  "data-test-id": "logs-details-body"
5081
4966
  }, [
5082
- !isTriggerNode.value && unref(content2) !== unref(LOG_DETAILS_CONTENT).OUTPUT ? (openBlock(), createBlock(unref(N8nResizeWrapper), {
4967
+ !isTriggerNode.value && _ctx.panels !== unref(LOG_DETAILS_PANEL_STATE).OUTPUT ? (openBlock(), createBlock(unref(N8nResizeWrapper), {
5083
4968
  key: 0,
5084
4969
  class: normalizeClass({
5085
4970
  [_ctx.$style.inputResizer]: true,
@@ -5095,27 +4980,23 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
5095
4980
  onResizeend: handleResizeEnd
5096
4981
  }, {
5097
4982
  default: withCtx(() => [
5098
- createVNode(RunDataView, {
4983
+ createVNode(LogsViewRunData, {
5099
4984
  "data-test-id": "log-details-input",
5100
4985
  "pane-type": "input",
5101
4986
  title: unref(locale).baseText("logs.details.header.actions.input"),
5102
- "log-entry": _ctx.logEntry,
5103
- workflow: _ctx.workflow,
5104
- execution: _ctx.execution
5105
- }, null, 8, ["title", "log-entry", "workflow", "execution"])
4987
+ "log-entry": _ctx.logEntry
4988
+ }, null, 8, ["title", "log-entry"])
5106
4989
  ]),
5107
4990
  _: 1
5108
4991
  }, 8, ["class", "width", "style", "is-resizing-enabled", "window", "onResize"])) : createCommentVNode("", true),
5109
- isTriggerNode.value || unref(content2) !== unref(LOG_DETAILS_CONTENT).INPUT ? (openBlock(), createBlock(RunDataView, {
4992
+ isTriggerNode.value || _ctx.panels !== unref(LOG_DETAILS_PANEL_STATE).INPUT ? (openBlock(), createBlock(LogsViewRunData, {
5110
4993
  key: 1,
5111
4994
  "data-test-id": "log-details-output",
5112
4995
  "pane-type": "output",
5113
4996
  class: normalizeClass(_ctx.$style.outputPanel),
5114
4997
  title: unref(locale).baseText("logs.details.header.actions.output"),
5115
- "log-entry": _ctx.logEntry,
5116
- workflow: _ctx.workflow,
5117
- execution: _ctx.execution
5118
- }, null, 8, ["class", "title", "log-entry", "workflow", "execution"])) : createCommentVNode("", true)
4998
+ "log-entry": _ctx.logEntry
4999
+ }, null, 8, ["class", "title", "log-entry"])) : createCommentVNode("", true)
5119
5000
  ], 2)) : createCommentVNode("", true)
5120
5001
  ], 2);
5121
5002
  };
@@ -5189,10 +5070,11 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
5189
5070
  ]),
5190
5071
  _: 1
5191
5072
  }, 8, ["z-index", "content"])) : createCommentVNode("", true),
5192
- _ctx.showToggleButton ? (openBlock(), createBlock(unref(N8nTooltip), {
5073
+ _ctx.showToggleButton ? (openBlock(), createBlock(KeyboardShortcutTooltip, {
5193
5074
  key: 1,
5194
- "z-index": tooltipZIndex.value,
5195
- content: toggleButtonText.value
5075
+ label: unref(locales).baseText("generic.shortcutHint"),
5076
+ shortcut: { keys: ["l"] },
5077
+ "z-index": tooltipZIndex.value
5196
5078
  }, {
5197
5079
  default: withCtx(() => [
5198
5080
  createVNode(unref(_sfc_main$i), {
@@ -5206,7 +5088,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
5206
5088
  }, null, 8, ["icon", "aria-label"])
5207
5089
  ]),
5208
5090
  _: 1
5209
- }, 8, ["z-index", "content"])) : createCommentVNode("", true)
5091
+ }, 8, ["label", "z-index"])) : createCommentVNode("", true)
5210
5092
  ], 2);
5211
5093
  };
5212
5094
  }
@@ -5219,11 +5101,9 @@ const cssModules$1 = {
5219
5101
  "$style": style0$1
5220
5102
  };
5221
5103
  const LogsPanelActions = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__cssModules", cssModules$1]]);
5222
- function useLayout(pipContainer, pipContent2, container2, logsContainer2) {
5223
- const canvasStore = useCanvasStore();
5104
+ function useLogsPanelLayout(pipContainer, pipContent2, container2, logsContainer2) {
5105
+ const logsStore = useLogsStore();
5224
5106
  const telemetry = useTelemetry();
5225
- const workflowsStore = useWorkflowsStore();
5226
- const panelState = computed(() => workflowsStore.logsPanelState);
5227
5107
  const resizer = useResizablePanel(LOCAL_STORAGE_PANEL_HEIGHT, {
5228
5108
  container: document.body,
5229
5109
  position: "bottom",
@@ -5247,7 +5127,7 @@ function useLayout(pipContainer, pipContent2, container2, logsContainer2) {
5247
5127
  allowFullSize: true
5248
5128
  });
5249
5129
  const isOpen = computed(
5250
- () => panelState.value === LOGS_PANEL_STATE.CLOSED ? resizer.isResizing.value && resizer.size.value > 0 : !resizer.isCollapsed.value
5130
+ () => logsStore.isOpen ? !resizer.isCollapsed.value : resizer.isResizing.value && resizer.size.value > 0
5251
5131
  );
5252
5132
  const isCollapsingDetailsPanel = computed(() => overviewPanelResizer.isFullSize.value);
5253
5133
  const { canPopOut, isPoppedOut, pipWindow } = usePiPWindow({
@@ -5255,32 +5135,32 @@ function useLayout(pipContainer, pipContent2, container2, logsContainer2) {
5255
5135
  initialWidth: window.document.body.offsetWidth * 0.8,
5256
5136
  container: pipContainer,
5257
5137
  content: pipContent2,
5258
- shouldPopOut: computed(() => panelState.value === LOGS_PANEL_STATE.FLOATING),
5138
+ shouldPopOut: computed(() => logsStore.state === LOGS_PANEL_STATE.FLOATING),
5259
5139
  onRequestClose: () => {
5260
5140
  if (!isOpen.value) {
5261
5141
  return;
5262
5142
  }
5263
5143
  telemetry.track("User toggled log view", { new_state: "attached" });
5264
- workflowsStore.setPreferPoppedOutLogsView(false);
5144
+ logsStore.setPreferPoppedOut(false);
5265
5145
  }
5266
5146
  });
5267
5147
  function handleToggleOpen(open) {
5268
- const wasOpen = panelState.value !== LOGS_PANEL_STATE.CLOSED;
5148
+ const wasOpen = logsStore.isOpen;
5269
5149
  if (open === wasOpen) {
5270
5150
  return;
5271
5151
  }
5272
- workflowsStore.toggleLogsPanelOpen(open);
5152
+ logsStore.toggleOpen(open);
5273
5153
  telemetry.track("User toggled log view", {
5274
5154
  new_state: wasOpen ? "collapsed" : "attached"
5275
5155
  });
5276
5156
  }
5277
5157
  function handlePopOut() {
5278
5158
  telemetry.track("User toggled log view", { new_state: "floating" });
5279
- workflowsStore.toggleLogsPanelOpen(true);
5280
- workflowsStore.setPreferPoppedOutLogsView(true);
5159
+ logsStore.toggleOpen(true);
5160
+ logsStore.setPreferPoppedOut(true);
5281
5161
  }
5282
5162
  function handleResizeEnd() {
5283
- if (panelState.value === LOGS_PANEL_STATE.CLOSED && !resizer.isCollapsed.value) {
5163
+ if (!logsStore.isOpen && !resizer.isCollapsed.value) {
5284
5164
  handleToggleOpen(true);
5285
5165
  }
5286
5166
  if (resizer.isCollapsed.value) {
@@ -5289,9 +5169,9 @@ function useLayout(pipContainer, pipContent2, container2, logsContainer2) {
5289
5169
  resizer.onResizeEnd();
5290
5170
  }
5291
5171
  watch(
5292
- [panelState, resizer.size],
5172
+ [() => logsStore.state, resizer.size],
5293
5173
  ([state, height]) => {
5294
- canvasStore.setPanelHeight(
5174
+ logsStore.setHeight(
5295
5175
  state === LOGS_PANEL_STATE.FLOATING ? 0 : state === LOGS_PANEL_STATE.ATTACHED ? height : 32
5296
5176
  );
5297
5177
  },
@@ -5317,10 +5197,13 @@ function useLayout(pipContainer, pipContent2, container2, logsContainer2) {
5317
5197
  onOverviewPanelResizeEnd: overviewPanelResizer.onResizeEnd
5318
5198
  };
5319
5199
  }
5320
- function useExecutionData() {
5200
+ function useLogsExecutionData() {
5321
5201
  const nodeHelpers = useNodeHelpers();
5322
5202
  const workflowsStore = useWorkflowsStore();
5203
+ const toast = useToast();
5323
5204
  const execData = ref();
5205
+ const subWorkflowExecData = ref({});
5206
+ const subWorkflows = ref({});
5324
5207
  const workflow = computed(
5325
5208
  () => execData.value ? new Workflow({
5326
5209
  ...execData.value?.workflowData,
@@ -5346,35 +5229,65 @@ function useExecutionData() {
5346
5229
  (nodes) => nodes.some(isChatNode)
5347
5230
  )
5348
5231
  );
5349
- const execution = computed(() => {
5350
- if (!execData.value || !workflow.value) {
5351
- return void 0;
5232
+ const entries = computed(() => {
5233
+ if (!execData.value?.data || !workflow.value) {
5234
+ return [];
5352
5235
  }
5353
- return {
5354
- ...execData.value,
5355
- tree: createLogEntries(workflow.value, execData.value.data?.resultData.runData ?? {})
5356
- };
5236
+ return createLogTree(
5237
+ workflow.value,
5238
+ execData.value,
5239
+ subWorkflows.value,
5240
+ subWorkflowExecData.value
5241
+ );
5357
5242
  });
5358
- const updateInterval = computed(() => (execution.value?.tree.length ?? 0) > 10 ? 300 : 0);
5359
- const runStatusList = computed(
5360
- () => workflowsStore.workflowExecutionData?.id === IN_PROGRESS_EXECUTION_ID ? Object.values(workflowsStore.workflowExecutionData?.data?.resultData.runData ?? {}).flatMap((tasks) => tasks.map((task) => task.executionStatus ?? "")).join("|") : ""
5361
- );
5243
+ const updateInterval = computed(() => (entries.value?.length ?? 0) > 10 ? 300 : 0);
5362
5244
  function resetExecutionData() {
5363
5245
  execData.value = void 0;
5364
5246
  workflowsStore.setWorkflowExecutionData(null);
5365
5247
  nodeHelpers.updateNodesExecutionIssues();
5366
5248
  }
5249
+ async function loadSubExecution(logEntry) {
5250
+ const executionId = logEntry.runData.metadata?.subExecution?.executionId;
5251
+ const workflowId = logEntry.runData.metadata?.subExecution?.workflowId;
5252
+ if (!execData.value?.data || !executionId || !workflowId) {
5253
+ return;
5254
+ }
5255
+ try {
5256
+ const subExecution = await workflowsStore.fetchExecutionDataById(executionId);
5257
+ const data = subExecution?.data ? parse(subExecution.data) : void 0;
5258
+ if (!data || !subExecution) {
5259
+ throw Error("Data is missing");
5260
+ }
5261
+ subWorkflowExecData.value[executionId] = data;
5262
+ subWorkflows.value[workflowId] = new Workflow({
5263
+ ...subExecution.workflowData,
5264
+ nodeTypes: workflowsStore.getNodeTypes()
5265
+ });
5266
+ } catch (e) {
5267
+ toast.showError(e, "Unable to load sub execution");
5268
+ }
5269
+ }
5367
5270
  watch(
5368
5271
  // Fields that should trigger update
5369
5272
  [
5370
5273
  () => workflowsStore.workflowExecutionData?.id,
5371
5274
  () => workflowsStore.workflowExecutionData?.workflowData.id,
5372
5275
  () => workflowsStore.workflowExecutionData?.status,
5373
- runStatusList
5276
+ () => workflowsStore.workflowExecutionResultDataLastUpdate,
5277
+ () => workflowsStore.workflowExecutionStartedData
5374
5278
  ],
5375
5279
  useThrottleFn(
5376
- () => {
5377
- execData.value = deepToRaw(workflowsStore.workflowExecutionData ?? void 0);
5280
+ ([executionId], [previousExecutionId]) => {
5281
+ execData.value = workflowsStore.workflowExecutionData === null ? void 0 : deepToRaw(
5282
+ mergeStartData(
5283
+ workflowsStore.workflowExecutionStartedData?.[1] ?? {},
5284
+ workflowsStore.workflowExecutionData
5285
+ )
5286
+ );
5287
+ if (executionId !== previousExecutionId) {
5288
+ subWorkflowExecData.value = {};
5289
+ subWorkflows.value = {};
5290
+ }
5378
5291
  },
5379
5292
  updateInterval,
5380
5293
  true,
@@ -5382,7 +5295,53 @@ function useExecutionData() {
5382
5295
  ),
5383
5296
  { immediate: true }
5384
5297
  );
5385
- return { execution, workflow, hasChat, latestNodeNameById, resetExecutionData };
5298
+ return {
5299
+ execution: computed(() => execData.value),
5300
+ entries,
5301
+ hasChat,
5302
+ latestNodeNameById,
5303
+ resetExecutionData,
5304
+ loadSubExecution
5305
+ };
5306
+ }
5307
+ function useLogsSelection(execution, tree2, flatLogEntries) {
5308
+ const telemetry = useTelemetry();
5309
+ const manualLogEntrySelection = ref({ type: "initial" });
5310
+ const selected2 = computed(() => findSelectedLogEntry(manualLogEntrySelection.value, tree2.value));
5311
+ function select(value) {
5312
+ manualLogEntrySelection.value = value === void 0 ? { type: "none" } : { type: "selected", id: value.id };
5313
+ if (value) {
5314
+ telemetry.track("User selected node in log view", {
5315
+ node_type: value.node.type,
5316
+ node_id: value.node.id,
5317
+ execution_id: execution.value?.id,
5318
+ workflow_id: execution.value?.workflowData.id,
5319
+ subworkflow_depth: getDepth(value)
5320
+ });
5321
+ }
5322
+ }
5323
+ function selectPrev() {
5324
+ const entries = flatLogEntries.value;
5325
+ const prevEntry = selected2.value ? getEntryAtRelativeIndex(entries, selected2.value.id, -1) ?? entries[0] : entries[entries.length - 1];
5326
+ select(prevEntry);
5327
+ }
5328
+ function selectNext() {
5329
+ const entries = flatLogEntries.value;
5330
+ const nextEntry = selected2.value ? getEntryAtRelativeIndex(entries, selected2.value.id, 1) ?? entries[entries.length - 1] : entries[0];
5331
+ select(nextEntry);
5332
+ }
5333
+ return { selected: selected2, select, selectPrev, selectNext };
5334
+ }
5335
+ function useLogsTreeExpand(entries) {
5336
+ const collapsedEntries = ref({});
5337
+ const flatLogEntries = computed(() => flattenLogEntries(entries.value, collapsedEntries.value));
5338
+ function toggleExpanded(treeNode) {
5339
+ collapsedEntries.value[treeNode.id] = !collapsedEntries.value[treeNode.id];
5340
+ }
5341
+ return {
5342
+ flatLogEntries,
5343
+ toggleExpanded
5344
+ };
5386
5345
  }
5387
5346
  const _sfc_main = /* @__PURE__ */ defineComponent({
5388
5347
  __name: "LogsPanel",
@@ -5395,6 +5354,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5395
5354
  const logsContainer2 = useTemplateRef("logsContainer");
5396
5355
  const pipContainer = useTemplateRef("pipContainer");
5397
5356
  const pipContent2 = useTemplateRef("pipContent");
5357
+ const logsStore = useLogsStore();
5358
+ const ndvStore = useNDVStore();
5398
5359
  const {
5399
5360
  height,
5400
5361
  chatPanelWidth,
@@ -5413,7 +5374,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5413
5374
  onChatPanelResizeEnd,
5414
5375
  onOverviewPanelResize,
5415
5376
  onOverviewPanelResizeEnd
5416
- } = useLayout(pipContainer, pipContent2, container2, logsContainer2);
5377
+ } = useLogsPanelLayout(pipContainer, pipContent2, container2, logsContainer2);
5417
5378
  const {
5418
5379
  currentSessionId,
5419
5380
  messages: messages2,
@@ -5422,12 +5383,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5422
5383
  refreshSession,
5423
5384
  displayExecution
5424
5385
  } = useChatState(props.isReadOnly);
5425
- const { workflow, execution, hasChat, latestNodeNameById, resetExecutionData } = useExecutionData();
5426
- const manualLogEntrySelection = ref({ type: "initial" });
5427
- const selectedLogEntry = computed(
5428
- () => findSelectedLogEntry(manualLogEntrySelection.value, execution.value)
5386
+ const { entries, execution, hasChat, latestNodeNameById, resetExecutionData, loadSubExecution } = useLogsExecutionData();
5387
+ const { flatLogEntries, toggleExpanded } = useLogsTreeExpand(entries);
5388
+ const { selected: selected2, select, selectNext, selectPrev } = useLogsSelection(
5389
+ execution,
5390
+ entries,
5391
+ flatLogEntries
5429
5392
  );
5430
- const isLogDetailsOpen = computed(() => isOpen.value && selectedLogEntry.value !== void 0);
5393
+ const isLogDetailsOpen = computed(() => isOpen.value && selected2.value !== void 0);
5431
5394
  const isLogDetailsVisuallyOpen = computed(
5432
5395
  () => isLogDetailsOpen.value && !isCollapsingDetailsPanel.value
5433
5396
  );
@@ -5438,19 +5401,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5438
5401
  onPopOut,
5439
5402
  onToggleOpen
5440
5403
  }));
5441
- function handleSelectLogEntry(selected2) {
5442
- const workflowId = execution.value?.workflowData.id;
5443
- if (!workflowId) {
5444
- return;
5445
- }
5446
- manualLogEntrySelection.value = selected2 === void 0 ? { type: "none", workflowId } : { type: "selected", workflowId, data: selected2 };
5447
- }
5448
5404
  function handleResizeOverviewPanelEnd() {
5449
5405
  if (isOverviewPanelFullWidth.value) {
5450
- handleSelectLogEntry(void 0);
5406
+ select(void 0);
5451
5407
  }
5452
5408
  onOverviewPanelResizeEnd();
5453
5409
  }
5410
+ async function handleOpenNdv(treeNode) {
5411
+ ndvStore.setActiveNodeName(treeNode.node.name);
5412
+ await nextTick(() => {
5413
+ const source = treeNode.runData.source[0];
5414
+ const inputBranch = source?.previousNodeOutput ?? 0;
5415
+ ndvEventBus.emit("updateInputNodeName", source?.previousNode);
5416
+ ndvEventBus.emit("setInputBranchIndex", inputBranch);
5417
+ ndvStore.setOutputRunIndex(treeNode.runIndex);
5418
+ });
5419
+ }
5454
5420
  return (_ctx, _cache) => {
5455
5421
  return openBlock(), createElementBlock("div", {
5456
5422
  ref_key: "pipContainer",
@@ -5474,8 +5440,33 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5474
5440
  createBaseVNode("div", {
5475
5441
  ref_key: "container",
5476
5442
  ref: container2,
5477
- class: normalizeClass([_ctx.$style.container, "ignore-key-press-canvas"]),
5478
- tabindex: "0"
5443
+ class: normalizeClass(_ctx.$style.container),
5444
+ tabindex: "-1",
5445
+ onKeydown: [
5446
+ _cache[3] || (_cache[3] = withKeys(withModifiers(($event) => unref(select)(void 0), ["stop"]), ["esc"])),
5447
+ _cache[4] || (_cache[4] = withKeys(withModifiers(
5448
+ //@ts-ignore
5449
+ (...args) => unref(selectNext) && unref(selectNext)(...args),
5450
+ ["stop"]
5451
+ ), ["j"])),
5452
+ _cache[5] || (_cache[5] = withKeys(withModifiers(
5453
+ //@ts-ignore
5454
+ (...args) => unref(selectNext) && unref(selectNext)(...args),
5455
+ ["stop", "prevent"]
5456
+ ), ["down"])),
5457
+ _cache[6] || (_cache[6] = withKeys(withModifiers(
5458
+ //@ts-ignore
5459
+ (...args) => unref(selectPrev) && unref(selectPrev)(...args),
5460
+ ["stop"]
5461
+ ), ["k"])),
5462
+ _cache[7] || (_cache[7] = withKeys(withModifiers(
5463
+ //@ts-ignore
5464
+ (...args) => unref(selectPrev) && unref(selectPrev)(...args),
5465
+ ["stop", "prevent"]
5466
+ ), ["up"])),
5467
+ _cache[8] || (_cache[8] = withKeys(withModifiers(($event) => unref(selected2) && unref(toggleExpanded)(unref(selected2)), ["stop"]), ["space"])),
5468
+ _cache[9] || (_cache[9] = withKeys(withModifiers(($event) => unref(selected2) && handleOpenNdv(unref(selected2)), ["stop"]), ["enter"]))
5469
+ ]
5479
5470
  }, [
5480
5471
  unref(hasChat) && (!props.isReadOnly || unref(messages2).length > 0) ? (openBlock(), createBlock(unref(N8nResizeWrapper), {
5481
5472
  key: 0,
@@ -5529,40 +5520,45 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5529
5520
  "is-open": unref(isOpen),
5530
5521
  "is-read-only": _ctx.isReadOnly,
5531
5522
  "is-compact": isLogDetailsVisuallyOpen.value,
5532
- selected: selectedLogEntry.value,
5523
+ selected: unref(selected2),
5533
5524
  execution: unref(execution),
5534
- "scroll-to-selection": manualLogEntrySelection.value.type !== "selected" || manualLogEntrySelection.value.data.id !== selectedLogEntry.value?.id,
5525
+ entries: unref(entries),
5535
5526
  "latest-node-info": unref(latestNodeNameById),
5527
+ "flat-log-entries": unref(flatLogEntries),
5536
5528
  onClickHeader: _cache[1] || (_cache[1] = ($event) => unref(onToggleOpen)(true)),
5537
- onSelect: handleSelectLogEntry,
5538
- onClearExecutionData: unref(resetExecutionData)
5529
+ onSelect: unref(select),
5530
+ onClearExecutionData: unref(resetExecutionData),
5531
+ onToggleExpanded: unref(toggleExpanded),
5532
+ onOpenNdv: handleOpenNdv,
5533
+ onLoadSubExecution: unref(loadSubExecution)
5539
5534
  }, {
5540
5535
  actions: withCtx(() => [
5541
5536
  !isLogDetailsVisuallyOpen.value ? (openBlock(), createBlock(LogsPanelActions, normalizeProps(mergeProps({ key: 0 }, logsPanelActionsProps.value)), null, 16)) : createCommentVNode("", true)
5542
5537
  ]),
5543
5538
  _: 1
5544
- }, 8, ["class", "is-open", "is-read-only", "is-compact", "selected", "execution", "scroll-to-selection", "latest-node-info", "onClearExecutionData"]))
5539
+ }, 8, ["class", "is-open", "is-read-only", "is-compact", "selected", "execution", "entries", "latest-node-info", "flat-log-entries", "onSelect", "onClearExecutionData", "onToggleExpanded", "onLoadSubExecution"]))
5545
5540
  ]),
5546
5541
  _: 1
5547
5542
  }, 8, ["class", "width", "style", "is-resizing-enabled", "window", "onResize"]),
5548
- isLogDetailsVisuallyOpen.value && selectedLogEntry.value && unref(workflow) && unref(execution) ? (openBlock(), createBlock(LogsDetailsPanel, {
5543
+ isLogDetailsVisuallyOpen.value && unref(selected2) ? (openBlock(), createBlock(LogsDetailsPanel, {
5549
5544
  key: 0,
5550
5545
  class: normalizeClass(_ctx.$style.logDetails),
5551
5546
  "is-open": unref(isOpen),
5552
- "log-entry": selectedLogEntry.value,
5553
- workflow: unref(workflow),
5554
- execution: unref(execution),
5547
+ "log-entry": unref(selected2),
5555
5548
  window: unref(pipWindow),
5556
- "latest-info": unref(latestNodeNameById)[selectedLogEntry.value.node.id],
5557
- onClickHeader: _cache[2] || (_cache[2] = ($event) => unref(onToggleOpen)(true))
5549
+ "latest-info": unref(latestNodeNameById)[unref(selected2).id],
5550
+ panels: unref(logsStore).detailsState,
5551
+ onClickHeader: _cache[2] || (_cache[2] = ($event) => unref(onToggleOpen)(true)),
5552
+ onToggleInputOpen: unref(logsStore).toggleInputOpen,
5553
+ onToggleOutputOpen: unref(logsStore).toggleOutputOpen
5558
5554
  }, {
5559
5555
  actions: withCtx(() => [
5560
5556
  isLogDetailsVisuallyOpen.value ? (openBlock(), createBlock(LogsPanelActions, normalizeProps(mergeProps({ key: 0 }, logsPanelActionsProps.value)), null, 16)) : createCommentVNode("", true)
5561
5557
  ]),
5562
5558
  _: 1
5563
- }, 8, ["class", "is-open", "log-entry", "workflow", "execution", "window", "latest-info"])) : createCommentVNode("", true)
5559
+ }, 8, ["class", "is-open", "log-entry", "window", "latest-info", "panels", "onToggleInputOpen", "onToggleOutputOpen"])) : createCommentVNode("", true)
5564
5560
  ], 2)
5565
- ], 2)
5561
+ ], 34)
5566
5562
  ]),
5567
5563
  _: 1
5568
5564
  }, 8, ["height", "is-resizing-enabled", "class", "style", "onResize", "onResizeend"])