windmill-components 1.537.1 → 1.542.5

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 (275) hide show
  1. package/package/components/AIProviderPicker.svelte +181 -0
  2. package/package/components/AIProviderPicker.svelte.d.ts +15 -0
  3. package/package/components/ArgInfo.svelte +2 -2
  4. package/package/components/ArgInput.svelte +35 -9
  5. package/package/components/ArgInput.svelte.d.ts +3 -3
  6. package/package/components/AssignableTagsInner.svelte +89 -3
  7. package/package/components/ConcurrentJobsChart.svelte +36 -48
  8. package/package/components/ConcurrentJobsChart.svelte.d.ts +8 -20
  9. package/package/components/CustomPopover.svelte.d.ts +1 -1
  10. package/package/components/DropdownSelect.svelte +26 -0
  11. package/package/components/DropdownSelect.svelte.d.ts +11 -0
  12. package/package/components/DropdownV2Inner.svelte +1 -1
  13. package/package/components/{DynSelect.svelte → DynamicInput.svelte} +47 -15
  14. package/package/components/DynamicInput.svelte.d.ts +11 -0
  15. package/package/components/EditableSchemaForm.svelte +119 -95
  16. package/package/components/EditableSchemaForm.svelte.d.ts +4 -4
  17. package/package/components/Editor.svelte +86 -93
  18. package/package/components/Editor.svelte.d.ts +4 -3
  19. package/package/components/EditorBar.svelte +2 -5
  20. package/package/components/EditorSettings.svelte +11 -9
  21. package/package/components/FlowBuilder.svelte +3 -3
  22. package/package/components/FlowLogRow.svelte +64 -0
  23. package/package/components/FlowLogRow.svelte.d.ts +15 -0
  24. package/package/components/FlowLogViewer.svelte +406 -373
  25. package/package/components/FlowLogViewer.svelte.d.ts +5 -1
  26. package/package/components/FlowLogViewerWrapper.svelte +44 -1
  27. package/package/components/FlowLoopIterationPreview.svelte.d.ts +1 -1
  28. package/package/components/FlowPreviewContent.svelte.d.ts +1 -1
  29. package/package/components/FlowStatusViewerInner.svelte +34 -3
  30. package/package/components/FolderPicker.svelte +1 -1
  31. package/package/components/InputTransformForm.svelte +20 -10
  32. package/package/components/JobArgs.svelte +1 -1
  33. package/package/components/JobLoader.svelte.d.ts +1 -1
  34. package/package/components/JobStatus.svelte +2 -0
  35. package/package/components/LogSnippetViewer.svelte +3 -3
  36. package/package/components/LogSnippetViewer.svelte.d.ts +1 -1
  37. package/package/components/LogViewer.svelte +87 -71
  38. package/package/components/LogViewer.svelte.d.ts +1 -0
  39. package/package/components/Path.svelte +7 -1
  40. package/package/components/Path.svelte.d.ts +1 -1
  41. package/package/components/PrefixedInput.svelte +120 -0
  42. package/package/components/PrefixedInput.svelte.d.ts +8 -0
  43. package/package/components/QueuePosition.svelte +81 -0
  44. package/package/components/QueuePosition.svelte.d.ts +8 -0
  45. package/package/components/ResourceNarrowing.svelte +13 -0
  46. package/package/components/ResourceNarrowing.svelte.d.ts +6 -0
  47. package/package/components/ResourceTypePicker.svelte +49 -74
  48. package/package/components/RunChart.svelte +74 -89
  49. package/package/components/RunChart.svelte.d.ts +10 -22
  50. package/package/components/S3FilePicker.svelte +1 -1
  51. package/package/components/SchemaForm.svelte.d.ts +2 -2
  52. package/package/components/ScriptBuilder.svelte +2 -1
  53. package/package/components/ScriptEditor.svelte +4 -3
  54. package/package/components/ScriptEditor.svelte.d.ts +2 -1
  55. package/package/components/ServiceLogsInner.svelte +1 -1
  56. package/package/components/ShareModal.svelte.d.ts +1 -1
  57. package/package/components/SimpleEditor.svelte +4 -67
  58. package/package/components/StringTypeNarrowing.svelte +5 -10
  59. package/package/components/TemplateEditor.svelte +2 -16
  60. package/package/components/TimeAgo.svelte +1 -1
  61. package/package/components/TimeAgo.svelte.d.ts +1 -0
  62. package/package/components/Toggle.svelte +2 -1
  63. package/package/components/Toggle.svelte.d.ts +2 -1
  64. package/package/components/WorkerRepl.svelte +1 -1
  65. package/package/components/apps/components/display/AppNavbarItem.svelte +2 -1
  66. package/package/components/apps/components/display/table/AppAggridTable.svelte +44 -48
  67. package/package/components/apps/components/display/table/SyncColumnDefs.svelte +101 -19
  68. package/package/components/apps/components/display/table/SyncColumnDefs.svelte.d.ts +5 -2
  69. package/package/components/apps/components/display/table/utils.js +36 -5
  70. package/package/components/apps/components/inputs/currency/CurrencyInput.svelte +10 -5
  71. package/package/components/apps/editor/AppEditor.svelte +4 -3
  72. package/package/components/apps/editor/AppEditorHeader.svelte +0 -1
  73. package/package/components/apps/editor/GridViewer.svelte.d.ts +11 -4
  74. package/package/components/apps/editor/SettingsPanel.svelte +2 -2
  75. package/package/components/apps/editor/componentsPanel/ListItem.svelte +2 -2
  76. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte.d.ts +1 -1
  77. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte.d.ts +1 -1
  78. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte.d.ts +1 -1
  79. package/package/components/apps/editor/settingsPanel/ArrayStaticInputEditor.svelte +26 -3
  80. package/package/components/apps/editor/settingsPanel/InputsSpecEditor.svelte +1 -1
  81. package/package/components/apps/editor/settingsPanel/inputEditor/StaticInputEditor.svelte +13 -5
  82. package/package/components/apps/svelte-grid/Grid.svelte.d.ts +30 -11
  83. package/package/components/assets/JobAssetsViewer.svelte +28 -24
  84. package/package/components/auditLogs/AuditLogsTable.svelte +2 -6
  85. package/package/components/chartjs-wrappers/Chart.svelte.d.ts +14 -7
  86. package/package/components/common/OnChange.svelte.d.ts +11 -4
  87. package/package/components/common/badge/Badge.svelte +9 -2
  88. package/package/components/common/badge/Badge.svelte.d.ts +2 -1
  89. package/package/components/common/calendarPicker/CalendarPicker.svelte +5 -1
  90. package/package/components/common/calendarPicker/CalendarPicker.svelte.d.ts +5 -4
  91. package/package/components/common/drawer/Disposable.svelte +9 -11
  92. package/package/components/common/drawer/Drawer.svelte +3 -4
  93. package/package/components/common/drawer/Drawer.svelte.d.ts +1 -0
  94. package/package/components/common/menu/MenuItem.svelte.d.ts +2 -2
  95. package/package/components/common/modal/Modal.svelte.d.ts +1 -1
  96. package/package/components/common/tabs/TabContent.svelte +2 -7
  97. package/package/components/common/tabs/TabContent.svelte.d.ts +5 -27
  98. package/package/components/common/toggleButton-v2/ToggleButtonGroup.svelte +9 -3
  99. package/package/components/common/toggleButton-v2/ToggleButtonGroup.svelte.d.ts +1 -0
  100. package/package/components/common/toggleButton-v2/ToggleButtonMore.svelte +8 -4
  101. package/package/components/common/toggleButton-v2/ToggleButtonMore.svelte.d.ts +1 -0
  102. package/package/components/copilot/MetadataGen.svelte +1 -1
  103. package/package/components/copilot/chat/AIChatManager.svelte.js +24 -102
  104. package/package/components/copilot/chat/AssistantMessage.svelte +0 -4
  105. package/package/components/copilot/chat/anthropic.d.ts +15 -0
  106. package/package/components/copilot/chat/anthropic.js +208 -0
  107. package/package/components/copilot/chat/api/apiTools.d.ts +2 -2
  108. package/package/components/copilot/chat/api/apiTools.js +10 -7
  109. package/package/components/copilot/chat/api/core.d.ts +1 -1
  110. package/package/components/copilot/chat/api/core.js +7 -2
  111. package/package/components/copilot/chat/ask/core.d.ts +1 -1
  112. package/package/components/copilot/chat/ask/core.js +7 -2
  113. package/package/components/copilot/chat/flow/core.d.ts +1 -1
  114. package/package/components/copilot/chat/flow/core.js +14 -4
  115. package/package/components/copilot/chat/monaco-adapter.d.ts +6 -5
  116. package/package/components/copilot/chat/navigator/core.d.ts +1 -1
  117. package/package/components/copilot/chat/navigator/core.js +7 -2
  118. package/package/components/copilot/chat/script/CodeDisplay.svelte +10 -111
  119. package/package/components/copilot/chat/script/core.d.ts +5 -4
  120. package/package/components/copilot/chat/script/core.js +131 -19
  121. package/package/components/copilot/chat/shared.d.ts +7 -7
  122. package/package/components/copilot/lib.d.ts +29 -8
  123. package/package/components/copilot/lib.js +199 -24
  124. package/package/components/custom_ui.d.ts +1 -0
  125. package/package/components/flows/content/FlowInput.svelte +5 -5
  126. package/package/components/flows/content/FlowModuleComponent.svelte +5 -2
  127. package/package/components/flows/content/FlowModuleEarlyStop.svelte +47 -17
  128. package/package/components/flows/content/FlowModuleSleep.svelte +4 -1
  129. package/package/components/flows/content/FlowModuleSuspend.svelte +0 -1
  130. package/package/components/flows/content/FlowModuleTimeout.svelte +50 -10
  131. package/package/components/flows/content/FlowModuleTimeout.svelte.d.ts +1 -0
  132. package/package/components/flows/content/FlowRetries.svelte +108 -3
  133. package/package/components/flows/content/FlowRetries.svelte.d.ts +3 -2
  134. package/package/components/flows/flowInfers.js +8 -35
  135. package/package/components/flows/flowStore.d.ts +45 -1
  136. package/package/components/flows/flowStore.js +1 -1
  137. package/package/components/flows/map/FlowJobsMenu.svelte +3 -3
  138. package/package/components/flows/map/FlowModuleSchemaItem.svelte +61 -54
  139. package/package/components/flows/map/FlowModuleSchemaItem.svelte.d.ts +1 -1
  140. package/package/components/flows/map/FlowModuleSchemaItemViewer.svelte +1 -1
  141. package/package/components/flows/map/InsertModuleButton.svelte +1 -0
  142. package/package/components/flows/map/InsertModuleInner.svelte +12 -15
  143. package/package/components/flows/map/InsertModuleInner.svelte.d.ts +10 -9
  144. package/package/components/flows/propPicker/OutputPickerInner.svelte.d.ts +1 -1
  145. package/package/components/git_sync/DetectionFlow.svelte +15 -17
  146. package/package/components/git_sync/GitSyncContext.svelte.js +1 -1
  147. package/package/components/git_sync/GitSyncRepositoryCard.svelte +0 -1
  148. package/package/components/graph/graphBuilder.svelte.d.ts +5 -1
  149. package/package/components/graph/renderers/edges/BaseEdge.svelte +9 -1
  150. package/package/components/graph/renderers/edges/BaseEdge.svelte.d.ts +4 -1
  151. package/package/components/graph/renderers/nodes/BranchAllStart.svelte +2 -3
  152. package/package/components/graph/renderers/nodes/BranchOneStart.svelte +2 -3
  153. package/package/components/graph/renderers/triggers/TriggerButton.svelte.d.ts +1 -1
  154. package/package/components/graph/renderers/triggers/TriggersBadge.svelte +3 -1
  155. package/package/components/graph/renderers/triggers/TriggersWrapper.svelte +34 -24
  156. package/package/components/graph/renderers/triggers/TriggersWrapper.svelte.d.ts +1 -2
  157. package/package/components/home/ItemsList.svelte +17 -13
  158. package/package/components/home/TreeView.svelte +21 -27
  159. package/package/components/home/TreeView.svelte.d.ts +2 -29
  160. package/package/components/home/TreeViewRoot.svelte +11 -23
  161. package/package/components/home/TreeViewRoot.svelte.d.ts +15 -13
  162. package/package/components/icons/GitIcon.svelte +10 -2
  163. package/package/components/icons/GitIcon.svelte.d.ts +1 -0
  164. package/package/components/meltComponents/MeltButton.svelte.d.ts +1 -1
  165. package/package/components/meltComponents/Popover.svelte +23 -3
  166. package/package/components/meltComponents/Popover.svelte.d.ts +2 -1
  167. package/package/components/monacoLanguagesOptions.d.ts +3 -0
  168. package/package/components/monacoLanguagesOptions.js +109 -0
  169. package/package/components/propertyPicker/ObjectViewer.svelte +7 -2
  170. package/package/components/propertyPicker/PropPicker.svelte +1 -1
  171. package/package/components/propertyPicker/utils.js +14 -7
  172. package/package/components/runs/JobRunsPreview.svelte +212 -177
  173. package/package/components/runs/JobsLoader.svelte +2 -2
  174. package/package/components/runs/JobsLoader.svelte.d.ts +1 -1
  175. package/package/components/runs/NoWorkerWithTagWarning.svelte +18 -5
  176. package/package/components/runs/RunBadges.svelte +100 -0
  177. package/package/components/runs/RunBadges.svelte.d.ts +12 -0
  178. package/package/components/runs/RunLabels.svelte +86 -0
  179. package/package/components/runs/RunLabels.svelte.d.ts +10 -0
  180. package/package/components/runs/RunOption.svelte +20 -0
  181. package/package/components/runs/RunOption.svelte.d.ts +10 -0
  182. package/package/components/runs/RunRow.svelte +239 -151
  183. package/package/components/runs/RunRow.svelte.d.ts +12 -9
  184. package/package/components/runs/RunsBatchActionsDropdown.svelte +13 -17
  185. package/package/components/runs/RunsBatchActionsDropdown.svelte.d.ts +5 -18
  186. package/package/components/runs/RunsFilter.svelte +369 -243
  187. package/package/components/runs/RunsFilter.svelte.d.ts +2 -0
  188. package/package/components/runs/RunsQueue.svelte +96 -25
  189. package/package/components/runs/RunsQueue.svelte.d.ts +7 -21
  190. package/package/components/runs/RunsTable.svelte +62 -71
  191. package/package/components/runs/RunsTable.svelte.d.ts +2 -1
  192. package/package/components/runs/runs-grid.css +95 -0
  193. package/package/components/schema/EditableSchemaDrawer.svelte +12 -12
  194. package/package/components/schema/FlowPropertyEditor.svelte +197 -206
  195. package/package/components/schema/PropertyEditor.svelte +33 -35
  196. package/package/components/schema/SchemaFormDND.svelte.d.ts +2 -2
  197. package/package/components/search/GlobalSearchModal.svelte +8 -1
  198. package/package/components/select/DraggableTags.svelte.d.ts +17 -7
  199. package/package/components/select/MultiSelect.svelte.d.ts +21 -11
  200. package/package/components/select/Select.svelte +2 -1
  201. package/package/components/select/Select.svelte.d.ts +25 -13
  202. package/package/components/select/SelectDropdown.svelte.d.ts +14 -7
  203. package/package/components/settings/TokenDisplay.svelte +1 -1
  204. package/package/components/sidebar/OperatorMenu.svelte +5 -0
  205. package/package/components/sidebar/SidebarContent.svelte +48 -2
  206. package/package/components/sidebar/WorkspaceMenu.svelte +116 -17
  207. package/package/components/toast.js +6 -3
  208. package/package/components/triggers/AddTriggersButton.svelte +7 -6
  209. package/package/components/triggers/CaptureWrapper.svelte +19 -3
  210. package/package/components/triggers/TriggerLabel.svelte +8 -0
  211. package/package/components/triggers/TriggerTokens.svelte +1 -1
  212. package/package/components/triggers/TriggersEditor.svelte +9 -5
  213. package/package/components/triggers/TriggersTable.svelte +2 -2
  214. package/package/components/triggers/TriggersWrapper.svelte +16 -5
  215. package/package/components/triggers/TriggersWrapper.svelte.d.ts +3 -19
  216. package/package/components/{details/EmailTriggerCaptures.svelte → triggers/email/DefaultEmailCapture.svelte} +5 -5
  217. package/package/components/{details/EmailTriggerCaptures.svelte.d.ts → triggers/email/DefaultEmailCapture.svelte.d.ts} +4 -4
  218. package/package/components/{details/EmailTriggerConfigSection.svelte → triggers/email/DefaultEmailConfigSection.svelte} +24 -14
  219. package/package/components/triggers/email/DefaultEmailConfigSection.svelte.d.ts +13 -0
  220. package/package/components/triggers/email/DefaultEmailPanel.svelte +71 -0
  221. package/package/components/triggers/email/DefaultEmailPanel.svelte.d.ts +11 -0
  222. package/package/components/triggers/email/EmailCapture.svelte +39 -0
  223. package/package/components/triggers/email/EmailCapture.svelte.d.ts +43 -0
  224. package/package/components/triggers/email/EmailTriggerEditor.svelte +20 -0
  225. package/package/components/triggers/email/EmailTriggerEditor.svelte.d.ts +11 -0
  226. package/package/components/triggers/email/EmailTriggerEditorConfigSection.svelte +133 -0
  227. package/package/components/triggers/email/EmailTriggerEditorConfigSection.svelte.d.ts +14 -0
  228. package/package/components/triggers/email/EmailTriggerEditorInner.svelte +335 -0
  229. package/package/components/triggers/email/EmailTriggerEditorInner.svelte.d.ts +22 -0
  230. package/package/components/triggers/email/EmailTriggerPanel.svelte +61 -0
  231. package/package/components/triggers/email/EmailTriggerPanel.svelte.d.ts +14 -0
  232. package/package/components/triggers/email/utils.d.ts +4 -0
  233. package/package/components/triggers/email/utils.js +52 -0
  234. package/package/components/triggers/http/RouteEditorConfigSection.svelte +1 -1
  235. package/package/components/triggers/http/utils.js +1 -1
  236. package/package/components/triggers/triggers.svelte.d.ts +1 -0
  237. package/package/components/triggers/triggers.svelte.js +24 -2
  238. package/package/components/triggers/utils.js +19 -5
  239. package/package/components/triggers.d.ts +1 -1
  240. package/package/components/triggers.js +2 -0
  241. package/package/components/wizards/AgGridWizard.svelte +85 -80
  242. package/package/components/workspaceSettings/AISettings.svelte +74 -22
  243. package/package/components/workspaceSettings/AISettings.svelte.d.ts +2 -1
  244. package/package/components/workspaceSettings/CreateWorkspace.svelte +395 -0
  245. package/package/components/workspaceSettings/CreateWorkspace.svelte.d.ts +6 -0
  246. package/package/components/workspaceSettings/DucklakeSettings.svelte +3 -1
  247. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte +1 -1
  248. package/package/components/workspaceSettings/StorageSettings.svelte +69 -48
  249. package/package/gen/core/OpenAPI.js +1 -1
  250. package/package/gen/schemas.gen.d.ts +142 -3
  251. package/package/gen/schemas.gen.js +144 -3
  252. package/package/gen/services.gen.d.ts +129 -1
  253. package/package/gen/services.gen.js +267 -1
  254. package/package/gen/types.gen.d.ts +434 -8
  255. package/package/hubPaths.json +4 -2
  256. package/package/infer.js +1 -1
  257. package/package/keyboardChain.d.ts +5 -0
  258. package/package/keyboardChain.js +40 -0
  259. package/package/services/JobManager.js +2 -2
  260. package/package/stores.d.ts +3 -1
  261. package/package/stores.js +8 -5
  262. package/package/utils/workspaceHierarchy.d.ts +27 -0
  263. package/package/utils/workspaceHierarchy.js +101 -0
  264. package/package/utils.d.ts +6 -3
  265. package/package/utils.js +30 -15
  266. package/package/workspace_settings.js +2 -3
  267. package/package.json +9 -11
  268. package/package/components/DynSelect.svelte.d.ts +0 -11
  269. package/package/components/ObjectTypeNarrowing.svelte +0 -18
  270. package/package/components/ObjectTypeNarrowing.svelte.d.ts +0 -22
  271. package/package/components/details/DetailPageTriggerPanel.svelte +0 -121
  272. package/package/components/details/DetailPageTriggerPanel.svelte.d.ts +0 -20
  273. package/package/components/details/EmailTriggerConfigSection.svelte.d.ts +0 -12
  274. package/package/components/details/EmailTriggerPanel.svelte +0 -76
  275. package/package/components/details/EmailTriggerPanel.svelte.d.ts +0 -26
@@ -1,14 +1,16 @@
1
- <script lang="ts">import { ChevronDown, ChevronRight, GitBranch, Repeat, Code, ArrowDownToLine, ArrowDownFromLine, FoldVertical, UnfoldVertical } from 'lucide-svelte';
1
+ <script lang="ts">import { GitBranch, Repeat, Code, ArrowDownToLine, ArrowDownFromLine, FoldVertical, UnfoldVertical, ExternalLink, Keyboard } from 'lucide-svelte';
2
2
  import { base } from '../base';
3
3
  import { workspaceStore } from '../stores';
4
- import { truncateRev } from '../utils';
5
4
  import ObjectViewer from './propertyPicker/ObjectViewer.svelte';
6
5
  import LogViewer from './LogViewer.svelte';
7
6
  import FlowLogViewer from './FlowLogViewer.svelte';
8
7
  import { twMerge } from 'tailwind-merge';
9
8
  import FlowJobsMenu from './flows/map/FlowJobsMenu.svelte';
10
9
  import BarsStaggered from './icons/BarsStaggered.svelte';
11
- let { modules, localModuleStates, rootJob, flowStatus, expandedRows, allExpanded, showResultsInputs, toggleExpanded, toggleExpandAll, workspaceId, render, level = 0, flowId = 'root', onSelectedIteration, getSelectedIteration, flowSummary, mode = 'flow' } = $props();
10
+ import { updateLinks } from '../keyboardChain';
11
+ import FlowLogRow from './FlowLogRow.svelte';
12
+ import { Tooltip } from './meltComponents';
13
+ let { modules, localModuleStates, rootJob, flowStatus, expandedRows, allExpanded, showResultsInputs, toggleExpanded, toggleExpandAll, workspaceId, render, level = 0, flowId = 'root', onSelectedIteration, getSelectedIteration, flowSummary, mode = 'flow', currentId, navigationChain = $bindable(), select } = $props();
12
14
  function getJobLink(jobId) {
13
15
  if (!jobId)
14
16
  return '';
@@ -132,6 +134,83 @@ const flowInfo = $derived.by(() => {
132
134
  parentsWithErrors
133
135
  };
134
136
  });
137
+ let subloopNavigationChains = $state({});
138
+ function buildNavigationLinks() {
139
+ const items = [];
140
+ // Flow header (always first)
141
+ items.push(`flow-${flowId}`);
142
+ if (level > 0 && !isExpanded(`flow-${flowId}`)) {
143
+ return { [`flow-${flowId}`]: { upId: null, downId: null } };
144
+ }
145
+ // Flow input (if exists and shown)
146
+ if (showResultsInputs && flowInfo.inputs && Object.keys(flowInfo.inputs).length > 0) {
147
+ items.push(`flow-${flowId}-input`);
148
+ }
149
+ // Add modules in order
150
+ modules.forEach((module) => {
151
+ items.push(module.id);
152
+ // If module is expanded, add its children
153
+ if (isExpanded(module.id, localModuleStates[module.id]?.type === 'InProgress' ||
154
+ localModuleStates[module.id]?.type === 'WaitingForExecutor')) {
155
+ // Check if it has subflows
156
+ const subflows = getSubflows(module);
157
+ if (subflows.length > 0) {
158
+ // Add subflow IDs
159
+ subflows.forEach((subflow) => {
160
+ items.push(`flow-${subflow.flowId}`);
161
+ });
162
+ }
163
+ else {
164
+ // Add input if exists and shown (leaf nodes only)
165
+ if (showResultsInputs &&
166
+ localModuleStates[module.id]?.args &&
167
+ Object.keys(localModuleStates[module.id].args).length > 0) {
168
+ items.push(`${module.id}-input`);
169
+ }
170
+ items.push(`${module.id}-logs`);
171
+ // Add result if exists and shown (leaf nodes only)
172
+ if (showResultsInputs && localModuleStates[module.id]?.result !== undefined) {
173
+ items.push(`${module.id}-result`);
174
+ }
175
+ }
176
+ }
177
+ });
178
+ // Flow result (if exists and shown)
179
+ if (showResultsInputs && flowInfo.result !== undefined && rootJob.type === 'CompletedJob') {
180
+ items.push(`flow-${flowId}-result`);
181
+ }
182
+ // Convert items to navigation links
183
+ let links = items.reduce((acc, itemId, index) => {
184
+ let upId = index > 0 ? items[index - 1] : null;
185
+ let downId = index < items.length - 1 ? items[index + 1] : null;
186
+ acc[itemId] = { upId, downId };
187
+ return acc;
188
+ }, {});
189
+ // Add subflow chains
190
+ Object.entries(subloopNavigationChains).forEach(([_, chain]) => {
191
+ links = updateLinks($state.snapshot(links), $state.snapshot(chain));
192
+ });
193
+ return links;
194
+ }
195
+ const links = $derived.by(buildNavigationLinks);
196
+ $effect(() => {
197
+ navigationChain = links;
198
+ });
199
+ // Helper to check if an item is currently focused
200
+ function isCurrent(itemId) {
201
+ return currentId === itemId;
202
+ }
203
+ // Scroll current item into view
204
+ $effect(() => {
205
+ if (currentId) {
206
+ const element = document.querySelector(`[data-nav-id="${currentId}"]`);
207
+ if (element) {
208
+ ;
209
+ element.focus?.({ preventScroll: true });
210
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
211
+ }
212
+ }
213
+ });
135
214
  function hasSubflows(module) {
136
215
  return (module.value.type === 'forloopflow' ||
137
216
  module.value.type === 'whileloopflow' ||
@@ -173,6 +252,12 @@ function getSubflows(module) {
173
252
  {#if render}
174
253
  {#if level === 0 && toggleExpandAll}
175
254
  <div class="flex justify-end gap-4 items-center p-2 bg-surface-secondary border-b">
255
+ <Tooltip>
256
+ {#snippet text()}
257
+ Keyboard navigation available - ↑/↓/Enter
258
+ {/snippet}
259
+ <Keyboard size={16} class="text-tertiary" />
260
+ </Tooltip>
176
261
  <div class="flex items-center gap-2 whitespace-nowrap">
177
262
  <label
178
263
  for="showResultsInputs"
@@ -204,413 +289,366 @@ function getSubflows(module) {
204
289
  {/if}
205
290
  <ul class="w-full font-mono text-xs bg-surface-secondary list-none">
206
291
  <!-- Flow entry -->
207
- <li class="border-b flex flex-row">
208
- <div class="py-2 leading-tight align-top">
209
- {#if level > 0}
210
- <button
211
- class="w-4 flex items-center justify-center text-xs text-tertiary hover:text-primary transition-colors"
212
- onclick={() => toggleExpanded(`flow-${flowId}`)}
213
- >
214
- {#if isExpanded(`flow-${flowId}`, rootJob.type === 'QueuedJob')}
215
- <ChevronDown size={8} />
216
- {:else}
217
- <ChevronRight size={8} />
218
- {/if}
219
- </button>
220
- {:else}
221
- <!-- Root flow - no collapse button, just spacing -->
222
- <div class="w-4"></div>
223
- {/if}
224
- </div>
225
- <div class="grow min-w-0 leading-tight">
226
- <!-- svelte-ignore a11y_click_events_have_key_events -->
227
- <!-- svelte-ignore a11y_no_static_element_interactions -->
228
- <div
229
- class={twMerge(
230
- 'py-1 flex items-center justify-between pr-2',
231
- level > 0 ? 'cursor-pointer' : '',
232
- rootJob.type === undefined ? 'opacity-50' : ''
233
- )}
234
- onclick={level > 0 ? () => toggleExpanded(`flow-${flowId}`) : undefined}
235
- >
236
- <div class="flex items-center gap-2 grow min-w-0">
237
- <!-- Flow icon -->
238
- {@render flowIcon(level == 0 ? getFlowStatus(rootJob) : flowStatus, flowInfo.hasErrors)}
292
+ <FlowLogRow
293
+ id={`flow-${flowId}`}
294
+ isCollapsible={level > 0}
295
+ isRunning={rootJob.type === 'QueuedJob'}
296
+ {isCurrent}
297
+ {isExpanded}
298
+ {toggleExpanded}
299
+ class={rootJob.type === undefined ? 'opacity-50' : ''}
300
+ {select}
301
+ >
302
+ {#snippet label()}
303
+ <div class="flex items-center gap-2">
304
+ <!-- Flow icon -->
305
+ {@render flowIcon(level == 0 ? getFlowStatus(rootJob) : flowStatus, flowInfo.hasErrors)}
239
306
 
240
- <div class="flex items-center gap-2">
241
- <span class="text-xs font-mono">
242
- {mode === 'aiagent' ? 'AI Agent' : level == 0 ? 'Flow' : 'Subflow'}
243
- {#if flowInfo.label}
244
- : {flowInfo.label}
245
- {/if}
246
- <span class="text-tertiary">{getStepProgress(rootJob, modules.length)}</span>
247
- </span>
248
- </div>
307
+ <div class="text-xs text-left font-mono grow min-w-0">
308
+ {mode === 'aiagent' ? 'AI Agent' : level == 0 ? 'Flow' : 'Subflow'}
309
+ {#if flowInfo.label}
310
+ : {flowInfo.label}
311
+ {/if}
312
+ <span class="text-tertiary">{getStepProgress(rootJob, modules.length)}</span>
249
313
  </div>
250
314
 
251
315
  {#if flowInfo.jobId}
252
316
  <a
253
317
  href={getJobLink(flowInfo.jobId)}
254
- class="text-xs text-primary hover:underline font-mono"
318
+ class="text-xs text-gray-400 hover:text-primary pl-1"
255
319
  target="_blank"
256
320
  rel="noopener noreferrer"
257
321
  onclick={(e) => e.stopPropagation()}
258
322
  >
259
- {truncateRev(flowInfo.jobId, 6)}
323
+ <ExternalLink size={12} />
260
324
  </a>
261
325
  {/if}
262
326
  </div>
327
+ {/snippet}
263
328
 
264
- {#if level === 0 || isExpanded(`flow-${flowId}`, rootJob.type === 'QueuedJob')}
265
- <div class="mb-2 transition-all duration-200 ease-in-out w-full">
266
- <!-- Flow logs -->
267
- {#if flowInfo.logs}
268
- <LogViewer
269
- content={flowInfo.logs}
270
- jobId={flowInfo.jobId}
271
- isLoading={false}
272
- small={true}
273
- download={false}
274
- noAutoScroll={true}
275
- tag={undefined}
276
- noPadding
277
- wrapperClass="w-full mb-2 pr-2"
278
- />
279
- {/if}
329
+ {#if level === 0 || isExpanded(`flow-${flowId}`, rootJob.type === 'QueuedJob')}
330
+ <div class="mb-2 transition-all duration-200 ease-in-out w-full">
331
+ <!-- Flow logs -->
332
+ {#if flowInfo.logs}
333
+ <LogViewer
334
+ content={flowInfo.logs}
335
+ jobId={flowInfo.jobId}
336
+ isLoading={false}
337
+ small={true}
338
+ download={false}
339
+ noAutoScroll={true}
340
+ tag={undefined}
341
+ noPadding
342
+ wrapperClass="w-full mb-2 pr-2"
343
+ />
344
+ {/if}
280
345
 
281
- <!-- Flow steps - nested as children -->
282
- <ul class="w-full font-mono text-xs bg-surface-secondary list-none border-l">
283
- <!-- Flow inputs as first row entry -->
284
- {#if showResultsInputs && flowInfo.inputs && Object.keys(flowInfo.inputs).length > 0}
285
- <li class="border-b flex flex-row w-full">
286
- <div class="py-2 leading-tight align-top">
287
- <button
288
- class="w-4 flex items-center justify-center text-xs text-tertiary hover:text-primary transition-colors"
289
- onclick={() => toggleExpanded(`flow-${flowId}-input`)}
290
- >
291
- {#if isExpanded(`flow-${flowId}-input`)}
292
- <ChevronDown size={8} />
293
- {:else}
294
- <ChevronRight size={8} />
295
- {/if}
296
- </button>
346
+ <!-- Flow steps - nested as children -->
347
+ <ul class="w-full font-mono text-xs bg-surface-secondary list-none border-l">
348
+ <!-- Flow inputs as first row entry -->
349
+ {#if showResultsInputs && flowInfo.inputs && Object.keys(flowInfo.inputs).length > 0}
350
+ <FlowLogRow
351
+ id={`flow-${flowId}-input`}
352
+ isCollapsible={true}
353
+ isRunning={false}
354
+ {isCurrent}
355
+ {isExpanded}
356
+ {toggleExpanded}
357
+ {select}
358
+ >
359
+ {#snippet label()}
360
+ <div class="flex items-center gap-2 grow min-w-0">
361
+ <ArrowDownToLine size={10} />
362
+ <span class="text-xs font-mono">Inputs</span>
297
363
  </div>
364
+ {/snippet}
365
+ {#if isExpanded(`flow-${flowId}-input`)}
366
+ <div class="my-1 transition-all duration-200 ease-in-out">
367
+ <div class="pl-4">
368
+ <ObjectViewer json={flowInfo.inputs} pureViewer={true} />
369
+ </div>
370
+ </div>
371
+ {/if}
372
+ </FlowLogRow>
373
+ {/if}
298
374
 
299
- <div class="grow min-w-0 leading-tight">
300
- <!-- svelte-ignore a11y_no_static_element_interactions -->
301
- <!-- svelte-ignore a11y_click_events_have_key_events -->
375
+ {#if modules.length > 0}
376
+ {#each modules as module (module.id)}
377
+ {@const isLeafStep = !hasSubflows(module)}
378
+ {@const status = localModuleStates[module.id]?.type}
379
+ {@const isRunning = status === 'InProgress' || status === 'WaitingForExecutor'}
380
+ {@const hasEmptySubflowValue = hasEmptySubflow(module.id, module.value.type)}
381
+ {@const isCollapsible = !hasEmptySubflowValue}
382
+ <FlowLogRow
383
+ id={module.id}
384
+ {isCollapsible}
385
+ {isRunning}
386
+ {isCurrent}
387
+ {isExpanded}
388
+ {toggleExpanded}
389
+ {select}
390
+ >
391
+ {#snippet label()}
302
392
  <div
303
- class="py-1 flex items-center justify-between pr-2 cursor-pointer"
304
- onclick={() => toggleExpanded(`flow-${flowId}-input`)}
393
+ class={twMerge(
394
+ 'flex items-center justify-between',
395
+ status === 'WaitingForPriorSteps' ||
396
+ status === 'WaitingForEvents' ||
397
+ status === 'WaitingForExecutor' ||
398
+ status === undefined
399
+ ? 'opacity-50'
400
+ : ''
401
+ )}
305
402
  >
306
403
  <div class="flex items-center gap-2 grow min-w-0">
307
- <ArrowDownToLine size={10} />
308
- <span class="text-xs font-mono">Inputs</span>
309
- </div>
310
- </div>
311
-
312
- {#if isExpanded(`flow-${flowId}-input`)}
313
- <div class="my-1 transition-all duration-200 ease-in-out">
314
- <div class="pl-4">
315
- <ObjectViewer json={flowInfo.inputs} pureViewer={true} />
316
- </div>
317
- </div>
318
- {/if}
319
- </div>
320
- </li>
321
- {/if}
322
-
323
- {#if modules.length > 0}
324
- {#each modules as module (module.id)}
325
- {@const isLeafStep = !hasSubflows(module)}
326
- {@const status = localModuleStates[module.id]?.type}
327
- {@const isRunning = status === 'InProgress' || status === 'WaitingForExecutor'}
328
- {@const hasEmptySubflowValue = hasEmptySubflow(module.id, module.value.type)}
329
- {@const isCollapsible = !hasEmptySubflowValue}
330
- <li class="border-b flex flex-row">
331
- <div class="py-2 leading-tight align-top">
332
- {#if isCollapsible}
333
- <button
334
- class="w-4 flex items-center justify-center text-xs text-tertiary hover:text-primary transition-colors"
335
- onclick={() => toggleExpanded(module.id)}
336
- >
337
- {#if isExpanded(module.id, isRunning)}
338
- <ChevronDown size={8} />
339
- {:else}
340
- <ChevronRight size={8} />
341
- {/if}
342
- </button>
343
- {:else}
344
- <!-- Empty subflow - no collapse button, just spacing -->
345
- <div class="w-4"></div>
346
- {/if}
347
- </div>
348
- <div class="w-full leading-tight grow min-w-0">
349
- <!-- svelte-ignore a11y_click_events_have_key_events -->
350
- <!-- svelte-ignore a11y_no_static_element_interactions -->
351
- <div
352
- class={twMerge(
353
- 'py-1 flex items-center justify-between pr-2',
354
- isCollapsible ? 'cursor-pointer' : '',
355
- status === 'WaitingForPriorSteps' ||
356
- status === 'WaitingForEvents' ||
357
- status === 'WaitingForExecutor' ||
358
- status === undefined
359
- ? 'opacity-50'
360
- : ''
404
+ <!-- Step icon -->
405
+ {@render stepIcon(
406
+ module.value.type,
407
+ status as FlowStatusModule['type'],
408
+ flowInfo.parentsWithErrors.has(module.id)
361
409
  )}
362
- onclick={isCollapsible ? () => toggleExpanded(module.id) : undefined}
363
- >
364
- <div class="flex items-center gap-2 grow min-w-0">
365
- <!-- Step icon -->
366
- {@render stepIcon(
367
- module.value.type,
368
- status as FlowStatusModule['type'],
369
- flowInfo.parentsWithErrors.has(module.id)
370
- )}
371
410
 
372
- <div class="flex items-center gap-2">
373
- <span class="text-xs font-mono">
374
- <b>
375
- {mode === 'aiagent'
376
- ? module.summary
377
- ? 'Tool call'
378
- : 'Message'
379
- : module.id}
380
- </b>
381
- {#if mode === 'flow'}
382
- {#if module.value.type === 'forloopflow'}
383
- For loop
384
- {:else if module.value.type === 'whileloopflow'}
385
- While loop
386
- {:else if module.value.type === 'branchall'}
387
- Branch to all
388
- {:else if module.value.type === 'branchone'}
389
- Branch to one
390
- {:else if module.value.type === 'flow'}
391
- Subflow
392
- {:else}
393
- Step
394
- {/if}
395
- {/if}
396
- {#if module.summary}
397
- : {module.summary}
398
- {/if}
399
- {#if hasEmptySubflowValue}
400
- <span class="text-tertiary">
401
- {#if module.value.type === 'forloopflow' || module.value.type === 'whileloopflow'}
402
- (empty loop)
403
- {:else if module.value.type === 'branchall' || module.value.type === 'branchone'}
404
- (no branch)
405
- {/if}
406
- </span>
411
+ <div class="flex items-center gap-2">
412
+ <span class="text-xs font-mono text-left">
413
+ <b>
414
+ {mode === 'aiagent'
415
+ ? module.summary
416
+ ? 'Tool call'
417
+ : 'Message'
418
+ : module.id}
419
+ </b>
420
+ {#if mode === 'flow'}
421
+ {#if module.value.type === 'forloopflow'}
422
+ For loop
423
+ {:else if module.value.type === 'whileloopflow'}
424
+ While loop
425
+ {:else if module.value.type === 'branchall'}
426
+ Branch to all
427
+ {:else if module.value.type === 'branchone'}
428
+ Branch to one
429
+ {:else if module.value.type === 'flow'}
430
+ Subflow
431
+ {:else}
432
+ Step
407
433
  {/if}
408
- </span>
409
- {#if !hasEmptySubflowValue && localModuleStates[module.id]?.flow_jobs && (module.value.type === 'forloopflow' || module.value.type === 'whileloopflow')}
410
- <span
411
- class="text-xs font-mono font-medium inline-flex items-center grow min-w-0 -my-2"
412
- >
413
- <span onclick={(e) => e.stopPropagation()}>
414
- <FlowJobsMenu
415
- moduleId={module.id}
416
- id={module.id}
417
- {onSelectedIteration}
418
- flowJobsSuccess={localModuleStates[module.id]
419
- ?.flow_jobs_success}
420
- flowJobs={localModuleStates[module.id]?.flow_jobs}
421
- selected={localModuleStates[module.id]?.selectedForloopIndex ??
422
- 0}
423
- selectedManually={localModuleStates[module.id]
424
- ?.selectedForLoopSetManually ?? false}
425
- showIcon={false}
426
- />
427
- </span>
428
- {#if module.value.type === 'forloopflow'}
429
- {`/${localModuleStates[module.id]?.iteration_total ?? 0}`}
434
+ {/if}
435
+ {#if module.summary}
436
+ : {module.summary}
437
+ {/if}
438
+ {#if hasEmptySubflowValue}
439
+ <span class="text-tertiary">
440
+ {#if module.value.type === 'forloopflow' || module.value.type === 'whileloopflow'}
441
+ (empty loop)
442
+ {:else if module.value.type === 'branchall' || module.value.type === 'branchone'}
443
+ (no branch)
430
444
  {/if}
431
445
  </span>
432
446
  {/if}
433
- </div>
434
- </div>
435
-
436
- {#if isLeafStep}
437
- {@const jobId = localModuleStates[module.id]?.job_id}
438
- {#if jobId}
439
- <a
440
- href={getJobLink(jobId ?? '')}
441
- class="text-xs text-primary hover:underline font-mono"
442
- target="_blank"
443
- rel="noopener noreferrer"
447
+ </span>
448
+ {#if !hasEmptySubflowValue && localModuleStates[module.id]?.flow_jobs && (module.value.type === 'forloopflow' || module.value.type === 'whileloopflow')}
449
+ <span
450
+ class="text-xs font-mono font-medium inline-flex items-center grow min-w-0 -my-2"
444
451
  >
445
- {truncateRev(jobId ?? '', 6)}
446
- </a>
452
+ <button onclick={(e) => e.stopPropagation()}>
453
+ <FlowJobsMenu
454
+ moduleId={module.id}
455
+ id={module.id}
456
+ {onSelectedIteration}
457
+ flowJobsSuccess={localModuleStates[module.id]?.flow_jobs_success}
458
+ flowJobs={localModuleStates[module.id]?.flow_jobs}
459
+ selected={localModuleStates[module.id]?.selectedForloopIndex ?? 0}
460
+ selectedManually={localModuleStates[module.id]
461
+ ?.selectedForLoopSetManually ?? false}
462
+ showIcon={false}
463
+ />
464
+ </button>
465
+ {#if module.value.type === 'forloopflow'}
466
+ {`/${localModuleStates[module.id]?.iteration_total ?? 0}`}
467
+ {/if}
468
+ </span>
447
469
  {/if}
448
- {/if}
470
+ </div>
449
471
  </div>
450
472
 
451
- {#if isCollapsible && isExpanded(module.id, isRunning)}
452
- {@const args = localModuleStates[module.id]?.args}
453
- {@const logs = localModuleStates[module.id]?.logs}
454
- {@const result = localModuleStates[module.id]?.result}
473
+ {#if isLeafStep}
455
474
  {@const jobId = localModuleStates[module.id]?.job_id}
456
- <div class="my-1 transition-all duration-200 ease-in-out">
457
- <!-- Show child steps if they exist -->
458
- {#each getSubflows(module) as subflow}
459
- {@const subflowJob = {
460
- id: jobId,
461
- type:
462
- localModuleStates[module.id]?.type === 'Failure' ||
463
- localModuleStates[module.id]?.type === 'Success'
464
- ? 'CompletedJob'
465
- : ('QueuedJob' as Job['type']),
466
- logs,
467
- result,
468
- args,
469
- success: localModuleStates[module.id]?.type === 'Success'
470
- }}
471
- <div class="border-l mb-2">
472
- <!-- Recursively render child steps using FlowLogViewer -->
473
- <FlowLogViewer
474
- modules={subflow.modules}
475
- {localModuleStates}
476
- rootJob={subflowJob}
477
- flowStatus={localModuleStates[module.id]?.type}
478
- {expandedRows}
479
- {allExpanded}
480
- {showResultsInputs}
481
- {toggleExpanded}
482
- toggleExpandAll={undefined}
483
- {workspaceId}
484
- {render}
485
- level={level + 1}
486
- flowId={subflow.flowId}
487
- flowSummary={subflow.label}
488
- {onSelectedIteration}
489
- {getSelectedIteration}
490
- />
491
- </div>
492
- {/each}
493
- <!-- Show input arguments -->
494
- {#if getSubflows(module).length === 0}
495
- {#if showResultsInputs && isLeafStep && args && Object.keys(args).length > 0}
496
- <div class="mb-2">
497
- <!-- svelte-ignore a11y_click_events_have_key_events -->
498
- <!-- svelte-ignore a11y_no_static_element_interactions -->
499
- <div
500
- class="flex items-center gap-1 cursor-pointer hover:text-primary text-xs font-mono font-medium mb-1"
501
- onclick={() => toggleExpanded(`${module.id}-input`)}
502
- >
503
- {#if isExpanded(`${module.id}-input`)}
504
- <ChevronDown size={8} />
505
- {:else}
506
- <ChevronRight size={8} />
507
- {/if}
508
- Input
509
- </div>
510
- {#if isExpanded(`${module.id}-input`)}
511
- <div class="pl-4">
512
- <ObjectViewer json={args} pureViewer={true} />
513
- </div>
514
- {/if}
515
- </div>
516
- {/if}
475
+ {#if jobId}
476
+ <a
477
+ href={getJobLink(jobId ?? '')}
478
+ class="text-xs text-gray-400 hover:text-primary pl-1"
479
+ target="_blank"
480
+ rel="noopener noreferrer"
481
+ >
482
+ <ExternalLink size={12} />
483
+ </a>
484
+ {/if}
485
+ {/if}
486
+ </div>
487
+ {/snippet}
517
488
 
518
- <!-- Show logs if they exist -->
519
- {#if logs}
520
- <LogViewer
521
- content={logs}
522
- jobId={jobId ?? ''}
523
- isLoading={false}
524
- small={true}
525
- download={false}
526
- noAutoScroll={true}
527
- tag={undefined}
528
- noPadding
529
- wrapperClass="w-full mb-2 pr-2"
530
- />
531
- {:else if jobId && !hasSubflows(module)}
532
- <div class="mb-2">
533
- <div class="text-xs text-tertiary font-mono">
534
- No logs available
535
- </div>
489
+ {#if isCollapsible && isExpanded(module.id, isRunning)}
490
+ {@const args = localModuleStates[module.id]?.args}
491
+ {@const logs = localModuleStates[module.id]?.logs}
492
+ {@const result = localModuleStates[module.id]?.result}
493
+ {@const jobId = localModuleStates[module.id]?.job_id}
494
+ <div class="my-1 transition-all duration-200 ease-in-out border-l">
495
+ <!-- Show child steps if they exist -->
496
+ {#each getSubflows(module) as subflow}
497
+ {@const subflowJob = {
498
+ id: jobId,
499
+ type:
500
+ localModuleStates[module.id]?.type === 'Failure' ||
501
+ localModuleStates[module.id]?.type === 'Success'
502
+ ? 'CompletedJob'
503
+ : ('QueuedJob' as Job['type']),
504
+ logs,
505
+ result,
506
+ args,
507
+ success: localModuleStates[module.id]?.type === 'Success'
508
+ }}
509
+ <div class="border-l mb-2">
510
+ <!-- Recursively render child steps using FlowLogViewer -->
511
+ <FlowLogViewer
512
+ modules={subflow.modules}
513
+ {localModuleStates}
514
+ rootJob={subflowJob}
515
+ flowStatus={localModuleStates[module.id]?.type}
516
+ {expandedRows}
517
+ {allExpanded}
518
+ {showResultsInputs}
519
+ {toggleExpanded}
520
+ toggleExpandAll={undefined}
521
+ {workspaceId}
522
+ {render}
523
+ level={level + 1}
524
+ flowId={subflow.flowId}
525
+ flowSummary={subflow.label}
526
+ {onSelectedIteration}
527
+ {getSelectedIteration}
528
+ {currentId}
529
+ bind:navigationChain={subloopNavigationChains[subflow.flowId]}
530
+ {select}
531
+ />
532
+ </div>
533
+ {/each}
534
+
535
+ {#if getSubflows(module).length === 0}
536
+ <!-- Show input arguments -->
537
+ {#if showResultsInputs && isLeafStep && args && Object.keys(args).length > 0}
538
+ <FlowLogRow
539
+ id={`${module.id}-input`}
540
+ isCollapsible={true}
541
+ isRunning={false}
542
+ {isCurrent}
543
+ {isExpanded}
544
+ {toggleExpanded}
545
+ {select}
546
+ >
547
+ {#snippet label()}
548
+ <div class="flex items-center gap-2 grow min-w-0">
549
+ <ArrowDownFromLine size={10} />
550
+ <span class="text-xs font-mono">Input</span>
551
+ </div>
552
+ {/snippet}
553
+ {#if isExpanded(`${module.id}-input`)}
554
+ <div class="pl-4">
555
+ <ObjectViewer json={args} pureViewer={true} />
536
556
  </div>
537
557
  {/if}
558
+ </FlowLogRow>
559
+ {/if}
538
560
 
539
- <!-- Show result if completed -->
561
+ <!-- Show logs if they exist -->
562
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
563
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
564
+ {#if logs}
565
+ <div onclick={() => select(`${module.id}-logs`)}>
566
+ <LogViewer
567
+ content={logs}
568
+ jobId={jobId ?? ''}
569
+ isLoading={false}
570
+ small={true}
571
+ download={false}
572
+ noAutoScroll={true}
573
+ tag={undefined}
574
+ noPadding
575
+ wrapperClass={twMerge(
576
+ 'w-full mb-2 px-2',
577
+ isCurrent(`${module.id}-logs`)
578
+ ? 'border-l-2 border-l-gray-400 -ml-[2px]'
579
+ : ''
580
+ )}
581
+ navigationId={`${module.id}-logs`}
582
+ />
583
+ </div>
584
+ {:else if jobId && !hasSubflows(module)}
585
+ <div
586
+ class={twMerge(
587
+ 'w-full mb-2 px-2',
588
+ isCurrent(`${module.id}-logs`)
589
+ ? 'border-l-2 border-l-gray-400 -ml-[2px]'
590
+ : ''
591
+ )}
592
+ >
593
+ <div class="text-xs text-tertiary font-mono"> No logs available </div>
594
+ </div>
595
+ {/if}
540
596
 
541
- {#if showResultsInputs && isLeafStep && result !== undefined && (status === 'Success' || status === 'Failure')}
542
- <div class="mb-2 mt-2">
543
- <!-- svelte-ignore a11y_click_events_have_key_events -->
544
- <!-- svelte-ignore a11y_no_static_element_interactions -->
545
- <div
546
- class="flex items-center gap-1 cursor-pointer hover:text-primary text-xs font-mono font-medium mb-1"
547
- onclick={() => toggleExpanded(`${module.id}-result`)}
548
- >
549
- {#if isExpanded(`${module.id}-result`)}
550
- <ChevronDown size={8} />
551
- {:else}
552
- <ChevronRight size={8} />
553
- {/if}
554
- Result
555
- </div>
556
- {#if isExpanded(`${module.id}-result`)}
557
- <div class="pl-4">
558
- <ObjectViewer json={result} pureViewer={true} />
559
- </div>
560
- {/if}
597
+ <!-- Show result if completed -->
598
+ {#if showResultsInputs && isLeafStep && result !== undefined && (status === 'Success' || status === 'Failure')}
599
+ <FlowLogRow
600
+ id={`${module.id}-result`}
601
+ isCollapsible={true}
602
+ isRunning={false}
603
+ {isCurrent}
604
+ {isExpanded}
605
+ {toggleExpanded}
606
+ {select}
607
+ >
608
+ {#snippet label()}
609
+ <div class="flex items-center gap-2 grow min-w-0">
610
+ <ArrowDownFromLine size={10} />
611
+ <span class="text-xs font-mono">Result</span>
612
+ </div>
613
+ {/snippet}
614
+ {#if isExpanded(`${module.id}-result`)}
615
+ <div class="pl-4">
616
+ <ObjectViewer json={result} pureViewer={true} />
561
617
  </div>
562
618
  {/if}
563
- {/if}
564
- </div>
565
- {/if}
566
- </div>
567
- </li>
568
- {/each}
569
- {/if}
570
-
571
- <!-- Flow result as last row entry -->
572
- {#if showResultsInputs && flowInfo.result !== undefined && rootJob.type === 'CompletedJob'}
573
- <li class="border-b flex">
574
- <div class="py-2 leading-tight align-top">
575
- <button
576
- class="w-4 flex items-center justify-center text-xs text-tertiary hover:text-primary transition-colors"
577
- onclick={() => toggleExpanded(`flow-${flowId}-result`)}
578
- >
579
- {#if isExpanded(`flow-${flowId}-result`)}
580
- <ChevronDown size={8} />
581
- {:else}
582
- <ChevronRight size={8} />
619
+ </FlowLogRow>
620
+ {/if}
583
621
  {/if}
584
- </button>
585
- </div>
586
- <div class="w-full leading-tight">
587
- <!-- svelte-ignore a11y_no_static_element_interactions -->
588
- <!-- svelte-ignore a11y_click_events_have_key_events -->
589
- <div
590
- class="py-1 flex items-center justify-between pr-2 cursor-pointer"
591
- onclick={() => toggleExpanded(`flow-${flowId}-result`)}
592
- >
593
- <div class="flex items-center gap-2 grow min-w-0">
594
- <ArrowDownFromLine size={10} />
595
- <span class="text-xs font-mono">Results</span>
596
- </div>
597
622
  </div>
623
+ {/if}
624
+ </FlowLogRow>
625
+ {/each}
626
+ {/if}
598
627
 
599
- {#if isExpanded(`flow-${flowId}-result`)}
600
- <div class="my-1 transition-all duration-200 ease-in-out">
601
- <div class="pl-4">
602
- <ObjectViewer json={flowInfo.result} pureViewer={true} />
603
- </div>
604
- </div>
605
- {/if}
628
+ <!-- Flow result as last row entry -->
629
+ {#if showResultsInputs && flowInfo.result !== undefined && rootJob.type === 'CompletedJob'}
630
+ <FlowLogRow
631
+ id={`flow-${flowId}-result`}
632
+ isCollapsible={true}
633
+ isRunning={false}
634
+ {isCurrent}
635
+ {isExpanded}
636
+ {toggleExpanded}
637
+ {select}
638
+ >
639
+ {#snippet label()}
640
+ <div class="flex items-center gap-2 grow min-w-0">
641
+ <ArrowDownFromLine size={10} />
642
+ <span class="text-xs font-mono">Results</span>
606
643
  </div>
607
- </li>
608
- {/if}
609
- </ul>
610
- </div>
611
- {/if}
612
- </div>
613
- </li>
644
+ {/snippet}
645
+ <ObjectViewer json={flowInfo.result} pureViewer={true} />
646
+ </FlowLogRow>
647
+ {/if}
648
+ </ul>
649
+ </div>
650
+ {/if}
651
+ </FlowLogRow>
614
652
  </ul>
615
653
  {/if}
616
654
 
@@ -653,8 +691,3 @@ function getSubflows(module) {
653
691
  {/if}
654
692
  </div>
655
693
  {/snippet}
656
-
657
- <style>
658
- .transition-all {
659
- transition: all 0.2s ease-in-out;
660
- }</style>