@parallelworks/ui 0.20.0 → 0.21.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 (154) hide show
  1. package/dist/ai/adapter/openai/createOpenAIStream.js +3 -2
  2. package/dist/ai/agent/diff.d.ts +0 -1
  3. package/dist/ai/agent/diff.js +3 -2
  4. package/dist/ai/agent/toolfmt.js +2 -3
  5. package/dist/ai/ai.css +5 -0
  6. package/dist/ai/components/AllocationSelector.js +3 -2
  7. package/dist/ai/components/AttachmentManager.js +1 -1
  8. package/dist/ai/components/BranchNavigator.js +4 -2
  9. package/dist/ai/components/ChatInput.d.ts +2 -5
  10. package/dist/ai/components/ChatInput.js +10 -7
  11. package/dist/ai/components/ChatMessage.js +7 -7
  12. package/dist/ai/components/ChatSidebar.d.ts +0 -1
  13. package/dist/ai/components/ChatSidebar.js +4 -6
  14. package/dist/ai/components/ChatThread.js +5 -8
  15. package/dist/ai/components/ModelSelector.js +3 -2
  16. package/dist/ai/components/ShareDialog.js +6 -3
  17. package/dist/ai/components/SlashMenu.d.ts +0 -1
  18. package/dist/ai/components/agent/ActivityLine.d.ts +0 -1
  19. package/dist/ai/components/agent/ActivityLine.js +2 -2
  20. package/dist/ai/components/agent/AgentMessageParts.d.ts +1 -26
  21. package/dist/ai/components/agent/AgentMessageParts.js +4 -5
  22. package/dist/ai/core/ChatProvider.d.ts +2 -6
  23. package/dist/ai/core/ChatProvider.js +42 -67
  24. package/dist/ai/core/KeyboardShortcutsProvider.js +1 -1
  25. package/dist/ai/core/chatReducer.d.ts +0 -6
  26. package/dist/ai/core/chatReducer.js +1 -15
  27. package/dist/ai/core/useKeyboardShortcuts.d.ts +3 -1
  28. package/dist/ai/core/useKeyboardShortcuts.js +9 -11
  29. package/dist/ai/core/useSSEStream.d.ts +0 -1
  30. package/dist/ai/core/useSSEStream.js +5 -17
  31. package/dist/ai/strings.d.ts +0 -1
  32. package/dist/ai/strings.js +0 -1
  33. package/dist/ai/types.d.ts +1 -1
  34. package/dist/ai/ui/Avatar.d.ts +1 -2
  35. package/dist/ai/ui/Avatar.js +7 -18
  36. package/dist/ai/ui/Markdown.d.ts +1 -3
  37. package/dist/ai/ui/Markdown.js +1 -2
  38. package/dist/ai/ui/sidebar.d.ts +0 -1
  39. package/dist/ai/ui/sidebar.js +3 -1
  40. package/dist/ai/utils.js +1 -1
  41. package/dist/components/Avatar.js +4 -2
  42. package/dist/components/BareModal.js +1 -5
  43. package/dist/components/Breadcrumbs.js +21 -14
  44. package/dist/components/CollapsiblePanel.d.ts +1 -3
  45. package/dist/components/CollapsiblePanel.js +5 -5
  46. package/dist/components/Dropdown.d.ts +0 -4
  47. package/dist/components/Dropdown.js +5 -6
  48. package/dist/components/Listbox.js +14 -18
  49. package/dist/components/MultiSelect.js +5 -8
  50. package/dist/components/Pagination.js +1 -1
  51. package/dist/components/Provider.d.ts +0 -8
  52. package/dist/components/SwitchToggle.js +3 -5
  53. package/dist/components/Table.d.ts +1 -3
  54. package/dist/components/dropdownUtils.js +5 -6
  55. package/dist/components/relativeTime.d.ts +0 -7
  56. package/dist/components/relativeTime.js +1 -1
  57. package/dist/duration.js +1 -1
  58. package/dist/editor/Editor.d.ts +1 -1
  59. package/dist/editor/Editor.js +1 -1
  60. package/dist/editor/EditorField.d.ts +0 -1
  61. package/dist/editor/EditorField.js +8 -8
  62. package/dist/editor/FormCodePanel.js +14 -20
  63. package/dist/editor/yamlLanguage.js +2 -2
  64. package/dist/file-explorer/FileExplorer.js +56 -59
  65. package/dist/file-explorer/FileExplorerContext.d.ts +1 -2
  66. package/dist/file-explorer/FileExplorerContext.js +92 -125
  67. package/dist/file-explorer/FilePreview/Inline.d.ts +1 -2
  68. package/dist/file-explorer/FilePreview/Inline.js +2 -2
  69. package/dist/file-explorer/FilePreview/Viewer.js +0 -4
  70. package/dist/file-explorer/FilePreview/index.d.ts +1 -2
  71. package/dist/file-explorer/FilePreview/index.js +3 -3
  72. package/dist/file-explorer/FilePreview/parse.d.ts +2 -1
  73. package/dist/file-explorer/FilePreview/useObjectBlobUrl.d.ts +5 -4
  74. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +23 -36
  75. package/dist/file-explorer/FilePreview/useObjectText.d.ts +1 -2
  76. package/dist/file-explorer/FilePreview/useObjectText.js +5 -7
  77. package/dist/file-explorer/FileRow.js +1 -1
  78. package/dist/file-explorer/FileRowsWindow.d.ts +5 -12
  79. package/dist/file-explorer/FileTable.d.ts +2 -6
  80. package/dist/file-explorer/LoadMoreRow.d.ts +8 -0
  81. package/dist/file-explorer/TreeView.d.ts +0 -1
  82. package/dist/file-explorer/TreeView.js +6 -6
  83. package/dist/file-explorer/helpers.js +2 -4
  84. package/dist/file-explorer/lib/fileExplorer.d.ts +0 -2
  85. package/dist/file-explorer/lib/types.d.ts +0 -1
  86. package/dist/file-explorer/lib/utils.js +15 -20
  87. package/dist/file-explorer/toasts.js +36 -34
  88. package/dist/form/Fields/BooleanField.js +5 -4
  89. package/dist/form/Fields/CheckboxGroupField.js +5 -4
  90. package/dist/form/Fields/ColorField.js +5 -4
  91. package/dist/form/Fields/DropdownField.d.ts +0 -1
  92. package/dist/form/Fields/DropdownField.js +10 -13
  93. package/dist/form/Fields/DurationField.js +2 -2
  94. package/dist/form/Fields/LabelField.js +5 -5
  95. package/dist/form/Fields/MultiDropdownField.d.ts +1 -1
  96. package/dist/form/Fields/MultiDropdownField.js +8 -11
  97. package/dist/form/Fields/NumberField.js +6 -5
  98. package/dist/form/Fields/ObjectField.d.ts +1 -2
  99. package/dist/form/Fields/ObjectField.js +22 -21
  100. package/dist/form/Fields/RadioField.js +4 -3
  101. package/dist/form/Fields/RangeField.js +7 -6
  102. package/dist/form/Fields/StringField.js +2 -1
  103. package/dist/form/Fields/TextAreaField.js +2 -1
  104. package/dist/form/Form.d.ts +7 -8
  105. package/dist/form/Form.js +52 -78
  106. package/dist/form/SpecialTypes/DropdownWrapper.d.ts +0 -2
  107. package/dist/form/SpecialTypes/DropdownWrapper.js +1 -3
  108. package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +1 -3
  109. package/dist/form/SpecialTypes/FormikCustomDropdown.js +4 -7
  110. package/dist/form/SpecialTypes/FormikCustomInput.js +13 -11
  111. package/dist/form/Wizard/WizardContainer.js +8 -25
  112. package/dist/form/Wizard/WizardNavigation.d.ts +1 -1
  113. package/dist/form/Wizard/WizardNavigation.js +5 -6
  114. package/dist/form/Wizard/WizardStepContent.d.ts +1 -1
  115. package/dist/form/Wizard/WizardStepContent.js +2 -2
  116. package/dist/form/Wizard/WizardStepIndicator.js +7 -17
  117. package/dist/form/Wizard/types.d.ts +4 -46
  118. package/dist/form/Wizard/useWizardState.d.ts +2 -10
  119. package/dist/form/Wizard/useWizardState.js +42 -92
  120. package/dist/form/Wizard/utils.js +6 -11
  121. package/dist/form/lib.js +28 -54
  122. package/dist/form/types/fieldTypes.d.ts +4 -5
  123. package/dist/form/utils/dependentOptions.d.ts +6 -0
  124. package/dist/form/utils/dependentOptions.js +21 -0
  125. package/dist/form/utils/getParentValue.d.ts +2 -1
  126. package/dist/form/utils/getParentValue.js +10 -15
  127. package/dist/form/utils/getValueUsingPath.js +1 -1
  128. package/dist/graph/AnnotationBanner.d.ts +1 -1
  129. package/dist/graph/AnnotationBanner.js +1 -1
  130. package/dist/graph/Collapse.d.ts +3 -3
  131. package/dist/graph/Collapse.js +3 -8
  132. package/dist/graph/DependencyGraph.d.ts +5 -4
  133. package/dist/graph/DependencyGraph.js +172 -222
  134. package/dist/graph/JobSummary.d.ts +10 -8
  135. package/dist/graph/JobSummary.js +13 -13
  136. package/dist/graph/MatrixGroup.d.ts +5 -17
  137. package/dist/graph/MatrixGroup.js +11 -22
  138. package/dist/graph/TreeView.d.ts +1 -3
  139. package/dist/graph/TreeView.js +104 -491
  140. package/dist/graph/types.d.ts +3 -2
  141. package/dist/graph/util.d.ts +5 -0
  142. package/dist/graph/util.js +18 -0
  143. package/dist/icons.d.ts +2 -2
  144. package/dist/icons.js +2 -2
  145. package/dist/index.d.ts +1 -1
  146. package/dist/list/ListViewControls.js +17 -35
  147. package/dist/list/RowContextMenu.js +7 -7
  148. package/dist/logviewer/LogViewer.js +7 -9
  149. package/dist/logviewer/segments.js +2 -2
  150. package/dist/styles/theme.css +1 -0
  151. package/dist/styles.css +1 -1
  152. package/dist/theme/index.js +5 -5
  153. package/package.json +28 -30
  154. package/dist/ai/ui/buttons.d.ts +0 -1
@@ -9,6 +9,7 @@ import { toAbsHumanDuration } from "../duration.js";
9
9
  import { AnnotationBanner } from "./AnnotationBanner.js";
10
10
  import { Collapse } from "./Collapse.js";
11
11
  import { Reveal } from "./Reveal.js";
12
+ import { jobLabel, toggled } from "./util.js";
12
13
  import { Joblist } from "./JobSummary.js";
13
14
  import { MatrixGroupNode, MatrixGroupSummaryItem } from "./MatrixGroup.js";
14
15
  import TreeView from "./TreeView.js";
@@ -54,7 +55,7 @@ var addCleanupSteps = ({ jobs }) => {
54
55
  linkedStep: `${sourceSteps.length - index - 1}`
55
56
  };
56
57
  delete newStep.cleanup;
57
- const clonedStep = cloned.steps[index];
58
+ const clonedStep = cloned.steps[sourceSteps.length - index - 1];
58
59
  if (clonedStep) delete clonedStep.cleanup;
59
60
  cloned.steps.push(newStep);
60
61
  });
@@ -72,7 +73,7 @@ var addCleanupSteps = ({ jobs }) => {
72
73
  linkedStep: `${sourceCleanup.length - index - 1 + cloned.steps.length}`
73
74
  };
74
75
  delete newStep.cleanup;
75
- const clonedStep = clonedCleanup[index];
76
+ const clonedStep = clonedCleanup[sourceCleanup.length - index - 1];
76
77
  if (clonedStep) delete clonedStep.cleanup;
77
78
  clonedCleanup.push(newStep);
78
79
  });
@@ -124,10 +125,14 @@ function parsePrefixToPath(prefix) {
124
125
  }
125
126
  return path;
126
127
  }
127
- function computeGraphLayout(engine, jobs, matrixGroups) {
128
+ function displayJobsOf(engine, jobs, matrixGroups) {
128
129
  const visibleJobs = structuredClone(jobs);
129
- for (const jobName of Object.keys(jobs ?? {})) if (jobs[jobName]?.if === false) delete visibleJobs[jobName];
130
+ for (const jobName of Object.keys(jobs)) if (jobs[jobName]?.if === false) delete visibleJobs[jobName];
130
131
  engine.collapseMatrixGroups(matrixGroups, visibleJobs);
132
+ return visibleJobs;
133
+ }
134
+ function computeGraphLayout(engine, jobs, matrixGroups) {
135
+ const visibleJobs = displayJobsOf(engine, jobs, matrixGroups);
131
136
  const allDeps = {};
132
137
  for (const jobName of Object.keys(visibleJobs)) allDeps[jobName] = engine.jobDependencies(jobName, visibleJobs, allDeps);
133
138
  const filteredDeps = {};
@@ -142,37 +147,29 @@ function computeGraphLayout(engine, jobs, matrixGroups) {
142
147
  }).sort();
143
148
  }
144
149
  const depended_on = {};
145
- Object.keys(visibleJobs).forEach((jobName) => {
146
- if (filteredDeps[jobName] && Array.isArray(filteredDeps[jobName])) filteredDeps[jobName].forEach((dep) => {
147
- if (depended_on[dep]) depended_on[dep].push(jobName);
148
- else depended_on[dep] = [jobName];
149
- });
150
- });
151
- Object.keys(visibleJobs).forEach((jobName) => {
152
- if (depended_on[jobName]) depended_on[jobName].sort();
153
- });
154
- const unfinished = structuredClone(visibleJobs);
150
+ for (const jobName of Object.keys(visibleJobs)) for (const dep of filteredDeps[jobName] ?? []) {
151
+ depended_on[dep] ??= [];
152
+ depended_on[dep].push(jobName);
153
+ }
154
+ for (const dependents of Object.values(depended_on)) dependents.sort();
155
+ const unfinished = new Set(Object.keys(visibleJobs));
155
156
  const rootLevel = [];
156
157
  const deps = [rootLevel];
157
- Object.keys(visibleJobs).forEach((jobName) => {
158
- if (filteredDeps[jobName]?.length === 0) {
159
- rootLevel.push(jobName);
160
- delete unfinished[jobName];
161
- }
162
- });
158
+ for (const jobName of unfinished) if (filteredDeps[jobName]?.length === 0) {
159
+ rootLevel.push(jobName);
160
+ unfinished.delete(jobName);
161
+ }
163
162
  let prevLen;
164
163
  do {
165
164
  const toAppend = [];
166
- const unfinishedArr = Object.keys(unfinished);
167
- prevLen = unfinishedArr.length;
168
- unfinishedArr.forEach((jobName) => {
169
- if ((filteredDeps[jobName] ?? []).every((dep) => !unfinishedArr.includes(dep))) {
170
- toAppend.push(jobName);
171
- delete unfinished[jobName];
172
- }
173
- });
165
+ const pending = new Set(unfinished);
166
+ prevLen = pending.size;
167
+ for (const jobName of pending) if ((filteredDeps[jobName] ?? []).every((dep) => !pending.has(dep))) {
168
+ toAppend.push(jobName);
169
+ unfinished.delete(jobName);
170
+ }
174
171
  if (toAppend.length > 0) deps.push(toAppend);
175
- } while (prevLen !== Object.keys(unfinished).length);
172
+ } while (prevLen !== unfinished.size);
176
173
  const finalDeps = [];
177
174
  deps.forEach((col) => {
178
175
  const toAppend = [];
@@ -201,16 +198,7 @@ function computeGraphLayout(engine, jobs, matrixGroups) {
201
198
  }
202
199
  finalDeps.push(toAppend);
203
200
  });
204
- while (finalDeps.length > 0) {
205
- const first = finalDeps[0];
206
- if (!first) break;
207
- if (first.length === 0) {
208
- finalDeps.splice(0, 1);
209
- continue;
210
- }
211
- if (first[0]?.length !== 0) break;
212
- while (first.length > 0 && first[0]?.length === 0) first.splice(0, 1);
213
- }
201
+ if (finalDeps[0]?.length === 0) finalDeps.shift();
214
202
  const ancestorDists = {};
215
203
  const descendantDists = {};
216
204
  const jobNames = Object.keys(visibleJobs);
@@ -222,8 +210,8 @@ function computeGraphLayout(engine, jobs, matrixGroups) {
222
210
  for (const start of jobNames) {
223
211
  const aDist = /* @__PURE__ */ new Map();
224
212
  const q1 = [[start, 0]];
225
- while (q1.length > 0) {
226
- const [job, d] = q1.shift();
213
+ for (let next = q1.shift(); next; next = q1.shift()) {
214
+ const [job, d] = next;
227
215
  for (const dep of filteredDeps[job] ?? []) if (!aDist.has(dep)) {
228
216
  aDist.set(dep, d + 1);
229
217
  q1.push([dep, d + 1]);
@@ -232,8 +220,8 @@ function computeGraphLayout(engine, jobs, matrixGroups) {
232
220
  ancestorDists[start] = aDist;
233
221
  const dDist = /* @__PURE__ */ new Map();
234
222
  const q2 = [[start, 0]];
235
- while (q2.length > 0) {
236
- const [job, d] = q2.shift();
223
+ for (let next = q2.shift(); next; next = q2.shift()) {
224
+ const [job, d] = next;
237
225
  for (const child of reverseDeps[job] ?? []) if (!dDist.has(child)) {
238
226
  dDist.set(child, d + 1);
239
227
  q2.push([child, d + 1]);
@@ -249,6 +237,32 @@ function computeGraphLayout(engine, jobs, matrixGroups) {
249
237
  descendantDists
250
238
  };
251
239
  }
240
+ function jobHandlers({ engine, jobs, displayJobs, pathPrefix, stepsOpen, toggleSteps, expandedSubworkflows, toggleSubworkflow, openInNewGraph, setSublogOpen, renderWell }) {
241
+ const isStepsOpen = (j) => stepsOpen.has(pathPrefix + j);
242
+ const subworkflowKey = (j, s) => `${pathPrefix}${j}:${s}`;
243
+ const openLog = (j, s) => setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
244
+ return {
245
+ isStepsOpen,
246
+ onJobClick: (j) => {
247
+ const status = jobs[j]?.status ?? displayJobs[j]?.status;
248
+ if (!isStepsOpen(j) && (status === "skipped" || status === "skipped-failed")) return;
249
+ toggleSteps(pathPrefix + j);
250
+ },
251
+ onStepClick: (j, s) => {
252
+ const step = jobs[j]?.steps?.[s];
253
+ if (step?.status === "skipped" || step?.status === "skipped-failed") return;
254
+ if (step?.subworkflow) toggleSubworkflow(subworkflowKey(j, s));
255
+ else openLog(j, s);
256
+ },
257
+ onStepLogClick: openLog,
258
+ onSubworkflowIcon: (j, s) => openInNewGraph(pathPrefix, j, s),
259
+ renderSubworkflow: (j, s) => {
260
+ const subJobs = jobs[j]?.steps?.[s]?.subworkflow?.jobs;
261
+ if (!subJobs) return null;
262
+ return renderWell(subJobs, `${pathPrefix}subworkflows/${j}/step_${s}/`, expandedSubworkflows.has(subworkflowKey(j, s)));
263
+ }
264
+ };
265
+ }
252
266
  function SubworkflowWell({ expanded, onSettled, className, children }) {
253
267
  return /* @__PURE__ */ jsx(Reveal, {
254
268
  open: expanded,
@@ -262,6 +276,8 @@ function SubworkflowWell({ expanded, onSettled, className, children }) {
262
276
  });
263
277
  }
264
278
  var SUBGRAPH_Z_STEP = 100;
279
+ var CONNECTOR_COLOR = "var(--theme-border)";
280
+ var HIGHLIGHT_COLOR = "#3B82F6";
265
281
  var FIT_ANIMATION_MS = 300;
266
282
  function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflows, toggleSubworkflow, openInNewGraph, setSublogOpen, invalidateConnectors, requestFit, stepsOpen, toggleSteps, matrixOpen, toggleMatrix, onReady }) {
267
283
  const engine = useWorkflowEngine();
@@ -353,36 +369,27 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
353
369
  invalidateConnectors
354
370
  ]);
355
371
  const buildBoxLayer = useCallback(() => {
356
- const isStepsOpen = (j) => stepsOpen.has(pathPrefix + j);
357
- const onJobClick = (j) => {
358
- const status = jobs[j]?.status ?? displayJobs[j]?.status;
359
- if (!isStepsOpen(j) && (status === "skipped" || status === "skipped-failed")) return;
360
- toggleSteps(pathPrefix + j);
361
- };
362
- const expandInline = (j, s) => {
363
- toggleSubworkflow(`${pathPrefix}${j}:${s}`);
364
- requestAnimationFrame(invalidateConnectors);
365
- };
366
- const openNew = (j, s) => openInNewGraph(pathPrefix, j, s);
367
- const onStepClick = (j, s) => {
368
- const stepStatus = jobs[j]?.steps?.[+s]?.status;
369
- if (stepStatus === "skipped" || stepStatus === "skipped-failed") return;
370
- if (jobs[j]?.steps[+s]?.subworkflow) expandInline(j, +s);
371
- else setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
372
- };
373
- const onStepLogClick = (j, s) => setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
374
- const onSubworkflowIcon = (j, s) => openNew(j, s);
375
- const isSubworkflowExpanded = (j, s) => expandedSubworkflows.has(`${pathPrefix}${j}:${s}`);
376
- const renderSubworkflow = (j, s) => {
377
- const subJobs = jobs[j]?.steps?.[s]?.subworkflow?.jobs;
378
- if (!subJobs) return null;
379
- return /* @__PURE__ */ jsx(SubworkflowWell, {
380
- expanded: isSubworkflowExpanded(j, s),
372
+ const handlers = jobHandlers({
373
+ engine,
374
+ jobs,
375
+ displayJobs,
376
+ pathPrefix,
377
+ stepsOpen,
378
+ toggleSteps,
379
+ expandedSubworkflows,
380
+ toggleSubworkflow: (key) => {
381
+ toggleSubworkflow(key);
382
+ requestAnimationFrame(invalidateConnectors);
383
+ },
384
+ openInNewGraph,
385
+ setSublogOpen,
386
+ renderWell: (subJobs, subPrefix, expanded) => /* @__PURE__ */ jsx(SubworkflowWell, {
387
+ expanded,
381
388
  onSettled: requestFit,
382
389
  className: "my-2 rounded-lg border-4 border-(--theme-border)",
383
390
  children: /* @__PURE__ */ jsx(NestedSubgraph, {
384
391
  jobs: subJobs,
385
- pathPrefix: `${pathPrefix}subworkflows/${j}/step_${s}/`,
392
+ pathPrefix: subPrefix,
386
393
  depth: depth + 1,
387
394
  preview,
388
395
  animT,
@@ -397,13 +404,15 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
397
404
  matrixOpen,
398
405
  toggleMatrix
399
406
  })
400
- });
401
- };
407
+ })
408
+ });
402
409
  return /* @__PURE__ */ jsx("div", {
403
410
  className: "flex relative",
404
411
  children: dependencyCols.map((col) => {
405
412
  return /* @__PURE__ */ jsx("div", { children: col.map((jobNames) => {
406
- const matrixGroup = displayJobs[jobNames[0]]?._matrixGroup;
413
+ const first = jobNames[0];
414
+ if (first === void 0) return null;
415
+ const matrixGroup = displayJobs[first]?._matrixGroup;
407
416
  if (matrixGroup) return /* @__PURE__ */ jsx(MatrixGroupNode, {
408
417
  matrixGroup,
409
418
  jobNames,
@@ -412,50 +421,38 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
412
421
  onToggle: () => toggleMatrix(pathPrefix + matrixGroup.originaljob),
413
422
  jobs,
414
423
  activeDists,
415
- onMouseEnter: () => setHoveredJob(jobNames[0]),
424
+ onMouseEnter: () => setHoveredJob(first),
416
425
  onMouseLeave: () => setHoveredJob(null),
417
426
  hoveredRelated,
418
427
  animT,
419
428
  zBase,
420
- isStepsOpen,
421
- onJobClick,
422
- onStepClick,
423
- onStepLogClick,
424
- onSubworkflowIcon,
425
- isSubworkflowExpanded,
426
- renderSubworkflow,
429
+ handlers,
427
430
  preview
428
- }, "node_" + jobNames[0]);
431
+ }, `node_${first}`);
429
432
  return /* @__PURE__ */ jsxs("div", {
430
- id: "node_" + pathPrefix + jobNames[0],
433
+ id: `node_${pathPrefix}${first}`,
431
434
  role: "none",
432
435
  className: "relative m-24",
433
- style: { zIndex: (activeDists?.has(jobNames[0]) ? 25 : 1) + zBase },
434
- onMouseEnter: () => setHoveredJob(jobNames[0]),
436
+ style: { zIndex: (activeDists?.has(first) ? 25 : 1) + zBase },
437
+ onMouseEnter: () => setHoveredJob(first),
435
438
  onMouseLeave: () => setHoveredJob(null),
436
- onFocus: () => setHoveredJob(jobNames[0]),
439
+ onFocus: () => setHoveredJob(first),
437
440
  onBlur: () => setHoveredJob(null),
438
441
  children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-2xl bg-(--theme-panel-bg)" }), /* @__PURE__ */ jsx("div", {
439
442
  className: "relative border-solid shadow py-4 px-8 rounded-xl border-4 whitespace-nowrap bg-(--theme-panel-bg) text-2xl",
440
443
  style: {
441
- opacity: hoveredRelated && !hoveredRelated.has(jobNames[0]) ? .5 : 1,
444
+ opacity: hoveredRelated && !hoveredRelated.has(first) ? .5 : 1,
442
445
  transition: `opacity ${animT}s`
443
446
  },
444
447
  children: /* @__PURE__ */ jsx(Joblist, {
445
448
  jobs: displayJobs,
446
449
  jobNames,
447
- onJobClick,
448
- isStepsOpen,
449
- onStepClick,
450
- onStepLogClick,
451
- onSubworkflowIcon,
452
- isSubworkflowExpanded,
453
- renderSubworkflow,
450
+ ...handlers,
454
451
  growWidth: true,
455
452
  preview
456
453
  })
457
454
  })]
458
- }, "node_" + jobNames[0]);
455
+ }, `node_${first}`);
459
456
  }) }, col[0]?.[0]);
460
457
  })
461
458
  });
@@ -484,13 +481,13 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
484
481
  ]);
485
482
  const memoizedBoxLayer = useMemo(() => buildBoxLayer(), [buildBoxLayer]);
486
483
  const hasLiveNestedGraph = Array.from(expandedSubworkflows).some((k) => k.startsWith(pathPrefix));
487
- if (!Array.isArray(dependencyCols) || dependencyCols.length === 0 || !Array.isArray(dependencyCols[0]) || dependencyCols[0].length === 0 || !Array.isArray(dependencyCols[0][0]) || dependencyCols[0][0].length === 0) return null;
484
+ if (!dependencyCols[0]?.length) return null;
488
485
  return /* @__PURE__ */ jsxs("div", {
489
486
  ref: wrapperRef,
490
487
  className: "relative",
491
488
  children: [(() => {
492
489
  const wrapper = wrapperRef.current;
493
- const gid = (name) => document.getElementById("node_" + pathPrefix + name);
490
+ const gid = (name) => document.getElementById(`node_${pathPrefix}${name}`);
494
491
  const ox = (el) => offsetWithin(el, wrapper).x;
495
492
  const nodeConnectorY = (el) => offsetWithin(el, wrapper).y + 37;
496
493
  let colGap = 32;
@@ -500,27 +497,29 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
500
497
  if (col0 && col1) colGap = ox(col1) - (ox(col0) + col0.offsetWidth);
501
498
  }
502
499
  let minAdy = Number.POSITIVE_INFINITY;
503
- for (const col of dependencyCols) for (const jobNames of col) for (const dep of directDeps[jobNames[0]] ?? []) {
504
- const s = gid(dep);
505
- const e = gid(jobNames[0]);
506
- if (!s || !e) continue;
507
- const dy = Math.abs(nodeConnectorY(e) - nodeConnectorY(s));
508
- if (dy > 0 && dy < minAdy) minAdy = dy;
500
+ for (const col of dependencyCols) for (const jobNames of col) {
501
+ const first = jobNames[0];
502
+ if (first === void 0) continue;
503
+ for (const dep of directDeps[first] ?? []) {
504
+ const s = gid(dep);
505
+ const e = gid(first);
506
+ if (!s || !e) continue;
507
+ const dy = Math.abs(nodeConnectorY(e) - nodeConnectorY(s));
508
+ if (dy > 0 && dy < minAdy) minAdy = dy;
509
+ }
509
510
  }
510
511
  const MAX_ARC_R = 16;
511
512
  const arcR = Math.min(minAdy === Number.POSITIVE_INFINITY ? MAX_ARC_R : minAdy / 4, colGap / 2, MAX_ARC_R);
512
- return dependencyCols.map((col) => /* @__PURE__ */ jsx(React.Fragment, { children: col.map((jobNames) => /* @__PURE__ */ jsx(React.Fragment, { children: (directDeps[jobNames[0]] ?? []).map((dep) => {
513
- const isHighlighted = hoveredRelated?.has(jobNames[0]) && hoveredRelated?.has(dep);
514
- const baseColor = "var(--theme-border)";
513
+ return dependencyCols.map((col) => /* @__PURE__ */ jsx(React.Fragment, { children: col.map(([first]) => first === void 0 ? null : /* @__PURE__ */ jsx(React.Fragment, { children: (directDeps[first] ?? []).map((dep) => {
514
+ const isHighlighted = hoveredRelated?.has(first) && hoveredRelated?.has(dep);
515
515
  const depDist = activeDists?.get(dep) ?? 0;
516
- const targetDist = activeDists?.get(jobNames[0]) ?? 0;
517
- const hopDelay = animT;
516
+ const targetDist = activeDists?.get(first) ?? 0;
518
517
  const closerDist = Math.min(depDist, targetDist);
519
- const connectorDelay = closerDist * hopDelay;
520
- const retractDelay = (maxHoveredDistRef.current - closerDist) * hopDelay;
518
+ const connectorDelay = closerDist * animT;
519
+ const retractDelay = (maxHoveredDistRef.current - closerDist) * animT;
521
520
  const drawRightToLeft = targetDist < depDist;
522
521
  const start = gid(dep);
523
- const end = gid(jobNames[0]);
522
+ const end = gid(first);
524
523
  if (!start || !end) return null;
525
524
  const x1 = ox(start) + start.offsetWidth - 2;
526
525
  const y1 = nodeConnectorY(start);
@@ -567,7 +566,7 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
567
566
  "aria-hidden": "true",
568
567
  overflow: "visible",
569
568
  className: "absolute pointer-events-none",
570
- style: { zIndex: (isHighlighted || activeDists?.has(dep) && activeDists?.has(jobNames[0]) ? 30 : 10) + zBase },
569
+ style: { zIndex: (isHighlighted || activeDists?.has(dep) && activeDists?.has(first) ? 30 : 10) + zBase },
571
570
  children: [
572
571
  /* @__PURE__ */ jsx("rect", {
573
572
  x: x1 - 16,
@@ -587,20 +586,20 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
587
586
  cx: x1,
588
587
  cy: y1,
589
588
  r: "8",
590
- fill: isHighlighted ? "#3B82F6" : baseColor,
589
+ fill: isHighlighted ? HIGHLIGHT_COLOR : CONNECTOR_COLOR,
591
590
  style: {
592
591
  opacity: hoveredRelated && !isHighlighted ? .3 : 1,
593
- transition: isHighlighted ? `fill ${animT}s ${depDist * hopDelay}s, opacity 0s` : `fill ${animT}s ${(maxHoveredDistRef.current - depDist) * hopDelay}s, opacity 0s`
592
+ transition: isHighlighted ? `fill ${animT}s ${depDist * animT}s, opacity 0s` : `fill ${animT}s ${(maxHoveredDistRef.current - depDist) * animT}s, opacity 0s`
594
593
  }
595
594
  }),
596
595
  /* @__PURE__ */ jsx("circle", {
597
596
  cx: x2,
598
597
  cy: y2,
599
598
  r: "8",
600
- fill: isHighlighted ? "#3B82F6" : baseColor,
599
+ fill: isHighlighted ? HIGHLIGHT_COLOR : CONNECTOR_COLOR,
601
600
  style: {
602
601
  opacity: hoveredRelated && !isHighlighted ? .3 : 1,
603
- transition: isHighlighted ? `fill ${animT}s ${targetDist * hopDelay}s, opacity 0s` : `fill ${animT}s ${(maxHoveredDistRef.current - targetDist) * hopDelay}s, opacity 0s`
602
+ transition: isHighlighted ? `fill ${animT}s ${targetDist * animT}s, opacity 0s` : `fill ${animT}s ${(maxHoveredDistRef.current - targetDist) * animT}s, opacity 0s`
604
603
  }
605
604
  })
606
605
  ]
@@ -617,7 +616,7 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
617
616
  fill: "transparent"
618
617
  }), /* @__PURE__ */ jsx("path", {
619
618
  d: pathD,
620
- stroke: baseColor,
619
+ stroke: CONNECTOR_COLOR,
621
620
  strokeWidth: "6",
622
621
  fill: "transparent",
623
622
  style: {
@@ -635,7 +634,7 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
635
634
  d: drawRightToLeft ? pathDReversed : pathD,
636
635
  fill: "transparent",
637
636
  style: {
638
- stroke: "#3B82F6",
637
+ stroke: HIGHLIGHT_COLOR,
639
638
  strokeWidth: 6,
640
639
  strokeDasharray: `${pathLen} ${pathLen}`,
641
640
  strokeDashoffset: isHighlighted ? 0 : pathLen,
@@ -643,16 +642,16 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
643
642
  transition: isHighlighted ? `stroke-dashoffset ${animT}s ease ${connectorDelay}s, opacity 0s ease ${connectorDelay}s` : "stroke-dashoffset 0s, opacity 0s"
644
643
  }
645
644
  }), (() => {
646
- const connKey = `${dep}→${jobNames[0]}`;
645
+ const connKey = `${dep}→${first}`;
647
646
  if (isHighlighted) retractPathLensRef.current.set(connKey, pathLen);
648
- const isRetracting = !isHighlighted && !!activeDists?.has(dep) && !!activeDists?.has(jobNames[0]);
647
+ const isRetracting = !isHighlighted && !!activeDists?.has(dep) && !!activeDists?.has(first);
649
648
  if (!isHighlighted && !isRetracting) return null;
650
649
  const frozenLen = retractPathLensRef.current.get(connKey) ?? pathLen;
651
650
  return /* @__PURE__ */ jsx("path", {
652
651
  d: drawRightToLeft ? pathDReversed : pathD,
653
652
  fill: "transparent",
654
653
  style: {
655
- stroke: "#3B82F6",
654
+ stroke: HIGHLIGHT_COLOR,
656
655
  strokeWidth: 6,
657
656
  strokeDasharray: `${frozenLen} ${frozenLen}`,
658
657
  strokeDashoffset: isHighlighted ? 0 : frozenLen,
@@ -663,53 +662,32 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
663
662
  })()]
664
663
  })
665
664
  ] }, dep);
666
- }) }, jobNames[0])) }, col[0]?.[0]));
665
+ }) }, first)) }, col[0]?.[0]));
667
666
  })(), hasLiveNestedGraph ? buildBoxLayer() : memoizedBoxLayer]
668
667
  });
669
668
  }
670
669
  var NestedSubgraph = Subgraph;
671
- function SidebarWell({ expanded, children }) {
672
- return /* @__PURE__ */ jsx(Collapse, {
673
- expanded,
674
- releaseOverflow: false,
675
- children
676
- });
677
- }
678
670
  function SidebarJobs({ jobs, pathPrefix, preview, stepsOpen, toggleSteps, expandedSubworkflows, toggleSubworkflow, matrixOpen, toggleMatrix, openInNewGraph, setSublogOpen }) {
679
671
  const engine = useWorkflowEngine();
680
- const matrixGroups = useMemo(() => engine.matrixGroups(jobs), [engine, jobs]);
681
- const { displayJobs } = useMemo(() => computeGraphLayout(engine, jobs, matrixGroups), [
672
+ const displayJobs = useMemo(() => displayJobsOf(engine, jobs, engine.matrixGroups(jobs)), [engine, jobs]);
673
+ const handlers = jobHandlers({
682
674
  engine,
683
675
  jobs,
684
- matrixGroups
685
- ]);
686
- const isStepsOpen = (j) => stepsOpen.has(pathPrefix + j);
687
- const onJobClick = (j) => {
688
- const status = jobs[j]?.status ?? displayJobs[j]?.status;
689
- if (!isStepsOpen(j) && (status === "skipped" || status === "skipped-failed")) return;
690
- toggleSteps(pathPrefix + j);
691
- };
692
- const expandInline = (j, s) => toggleSubworkflow(`${pathPrefix}${j}:${s}`);
693
- const openNew = (j, s) => openInNewGraph(pathPrefix, j, s);
694
- const onStepClick = (j, s) => {
695
- const stepStatus = jobs[j]?.steps?.[+s]?.status;
696
- if (stepStatus === "skipped" || stepStatus === "skipped-failed") return;
697
- if (jobs[j]?.steps[+s]?.subworkflow) expandInline(j, +s);
698
- else setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
699
- };
700
- const onStepLogClick = (j, s) => setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
701
- const onSubworkflowIcon = (j, s) => openNew(j, s);
702
- const isSubworkflowExpanded = (j, s) => expandedSubworkflows.has(`${pathPrefix}${j}:${s}`);
703
- const renderSubworkflow = (j, s) => {
704
- const subJobs = jobs[j]?.steps?.[s]?.subworkflow?.jobs;
705
- if (!subJobs) return null;
706
- return /* @__PURE__ */ jsx(SidebarWell, {
707
- expanded: isSubworkflowExpanded(j, s),
676
+ displayJobs,
677
+ pathPrefix,
678
+ stepsOpen,
679
+ toggleSteps,
680
+ expandedSubworkflows,
681
+ toggleSubworkflow,
682
+ openInNewGraph,
683
+ setSublogOpen,
684
+ renderWell: (subJobs, subPrefix, expanded) => /* @__PURE__ */ jsx(Collapse, {
685
+ expanded,
708
686
  children: /* @__PURE__ */ jsx("div", {
709
687
  className: "ml-6 mt-0.5 border-l border-(--theme-border) pl-4",
710
688
  children: /* @__PURE__ */ jsx(SidebarJobs, {
711
689
  jobs: subJobs,
712
- pathPrefix: `${pathPrefix}subworkflows/${j}/step_${s}/`,
690
+ pathPrefix: subPrefix,
713
691
  preview,
714
692
  stepsOpen,
715
693
  toggleSteps,
@@ -721,8 +699,8 @@ function SidebarJobs({ jobs, pathPrefix, preview, stepsOpen, toggleSteps, expand
721
699
  setSublogOpen
722
700
  })
723
701
  })
724
- });
725
- };
702
+ })
703
+ });
726
704
  const seenMatrixGroups = /* @__PURE__ */ new Set();
727
705
  const orderedKeys = Object.keys(jobs).flatMap((jobName) => {
728
706
  const originaljob = jobs[jobName]?._matrix?.originaljob;
@@ -739,27 +717,15 @@ function SidebarJobs({ jobs, pathPrefix, preview, stepsOpen, toggleSteps, expand
739
717
  isExpanded: matrixOpen.has(pathPrefix + mg.originaljob),
740
718
  onToggle: () => toggleMatrix(pathPrefix + mg.originaljob),
741
719
  jobs,
742
- isStepsOpen,
743
- onJobClick,
744
- onStepClick,
745
- onStepLogClick,
746
- onSubworkflowIcon,
747
- isSubworkflowExpanded,
748
- renderSubworkflow,
720
+ handlers,
749
721
  preview
750
- }, "matrix-" + pathPrefix + mg.originaljob);
722
+ }, `matrix-${pathPrefix}${mg.originaljob}`);
751
723
  return /* @__PURE__ */ jsx(Joblist, {
752
724
  jobs,
753
725
  jobNames: [jobName],
754
- onJobClick,
755
- isStepsOpen,
756
- onStepClick,
757
- onStepLogClick,
758
- onSubworkflowIcon,
759
- isSubworkflowExpanded,
760
- renderSubworkflow,
726
+ ...handlers,
761
727
  preview
762
- }, "job-" + pathPrefix + jobName);
728
+ }, `job-${pathPrefix}${jobName}`);
763
729
  }) });
764
730
  }
765
731
  var RUN_STATUSES = [
@@ -786,7 +752,7 @@ function walkJobPath(root, path) {
786
752
  }
787
753
  return isJobRecord(cursor) ? cursor : {};
788
754
  }
789
- function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder, viewMode = "dag", setViewMode }) {
755
+ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag", setViewMode }) {
790
756
  const engine = useWorkflowEngine();
791
757
  const animT = .125;
792
758
  const minScale = .2;
@@ -883,7 +849,8 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
883
849
  const timer = setInterval(() => setNow(DateTime.now()), 1e3);
884
850
  return () => clearInterval(timer);
885
851
  }, [isRunFinished]);
886
- const jobs = walkJobPath(rootJobs, executedJobsPath[executedJobsPathIdx] ?? []);
852
+ const currentPath = executedJobsPath[executedJobsPathIdx] ?? [];
853
+ const jobs = walkJobPath(rootJobs, currentPath);
887
854
  const resetGraph = useCallback(() => {
888
855
  setSublogOpen("");
889
856
  setStepsOpen(/* @__PURE__ */ new Set());
@@ -903,29 +870,14 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
903
870
  setExecutedJobsPathIdx(0);
904
871
  }, [executedJobsPathIdx, resetGraph]);
905
872
  const toggleSubworkflow = useCallback((key) => {
906
- setExpandedSubworkflows((prev) => {
907
- const next = new Set(prev);
908
- if (next.has(key)) next.delete(key);
909
- else next.add(key);
910
- return next;
911
- });
873
+ setExpandedSubworkflows((prev) => toggled(prev, key));
912
874
  }, []);
913
875
  const toggleSteps = useCallback((key) => {
914
- setStepsOpen((prev) => {
915
- const next = new Set(prev);
916
- if (next.has(key)) next.delete(key);
917
- else next.add(key);
918
- return next;
919
- });
876
+ setStepsOpen((prev) => toggled(prev, key));
920
877
  requestAnimationFrame(invalidateConnectors);
921
878
  }, [invalidateConnectors]);
922
879
  const toggleMatrix = useCallback((key) => {
923
- setMatrixOpen((prev) => {
924
- const next = new Set(prev);
925
- if (next.has(key)) next.delete(key);
926
- else next.add(key);
927
- return next;
928
- });
880
+ setMatrixOpen((prev) => toggled(prev, key));
929
881
  requestAnimationFrame(invalidateConnectors);
930
882
  }, [invalidateConnectors]);
931
883
  const { data: sublogs, isLoading: sublogsLoading, error: sublogsError } = useRunFile(runSlug, sublogOpen || null, preview ? void 0 : { refreshInterval: 2e3 });
@@ -937,11 +889,14 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
937
889
  sublogsError,
938
890
  sublogsLoading
939
891
  ]);
940
- const jobAndStep = sublogOpen.split("/").slice(-3, -1);
941
- if (jobAndStep.length > 1) jobAndStep[1] = jobAndStep[1].split("_")[1] ?? "";
942
- const sublogIsStep = jobAndStep.length > 1;
943
- const logName = jobAndStep.length > 1 ? "Job: " + (jobAndStep[0][0].toUpperCase() + jobAndStep[0].slice(1)).replace(/_/g, " ") + " \nStep: " + (jobs[jobAndStep[0]]?.steps[Number(jobAndStep[1])]?.name || "Step " + jobAndStep[1]) : "";
944
- const sublogIsSubworkflow = jobAndStep.length > 1 && jobs[jobAndStep[0]]?.steps[Number(jobAndStep[1])]?.subworkflow;
892
+ const [sublogJob = "", sublogStepDir] = sublogOpen.split("/").slice(-3, -1);
893
+ const sublogStep = sublogStepDir === void 0 ? void 0 : sublogStepDir.split("_")[1] ?? "";
894
+ const sublogIsStep = sublogStep !== void 0;
895
+ const sublogStepData = sublogIsStep ? jobs[sublogJob]?.steps[Number(sublogStep)] : void 0;
896
+ const logName = sublogIsStep ? `Job: ${jobLabel(sublogJob)} \nStep: ${sublogStepData?.name || `Step ${sublogStep}`}` : "";
897
+ const sublogIsSubworkflow = !!sublogStepData?.subworkflow;
898
+ const sublogFileStart = sublogOpen.lastIndexOf("/") + 1;
899
+ const sublogShowsLog = sublogOpen.slice(sublogFileStart) === "logs.out";
945
900
  const matrixGroups = useMemo(() => engine.matrixGroups(jobs), [engine, jobs]);
946
901
  const { dependencyCols } = useMemo(() => computeGraphLayout(engine, jobs, matrixGroups), [
947
902
  engine,
@@ -1001,20 +956,18 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1001
956
  windowSize,
1002
957
  executedJobsPathIdx
1003
958
  ]);
1004
- const currentPath = executedJobsPath[executedJobsPathIdx] ?? [];
1005
959
  const nestingDepth = currentPath.length / 5;
1006
- let pathAppend = "";
1007
- for (let i = 0; i < nestingDepth; i++) pathAppend += `subworkflows/${currentPath[5 * i]}/step_${currentPath[5 * i + 2]?.toString()}/`;
960
+ const levelPrefixes = [];
961
+ for (let i = 0; i < nestingDepth; i++) levelPrefixes.push(`subworkflows/${currentPath[5 * i]}/step_${currentPath[5 * i + 2]}/`);
962
+ const pathAppend = levelPrefixes.join("");
1008
963
  let generalLogPath = "logs.out";
1009
964
  if (nestingDepth > 0) {
1010
- let parentPrefix = "";
1011
- for (let i = 0; i < nestingDepth - 1; i++) parentPrefix += `subworkflows/${currentPath[5 * i]}/step_${currentPath[5 * i + 2]?.toString()}/`;
1012
965
  const lastJob = String(currentPath[5 * (nestingDepth - 1)] ?? "");
1013
966
  const lastStep = currentPath[5 * (nestingDepth - 1) + 2] ?? "";
1014
- generalLogPath = engine.stepLogPath(parentPrefix, lastJob, lastStep);
967
+ generalLogPath = engine.stepLogPath(levelPrefixes.slice(0, -1).join(""), lastJob, lastStep);
1015
968
  }
1016
969
  const missingLogText = sublogIsSubworkflow ? "Subworkflows generally have no logs/scripts at this level.\nClick on the \"Open in new graph\" icon on the subworkflow step to open the subworkflow graph." : sublogsError ? dagStrings.logLoadFailed : (sublogOpen === generalLogPath ? dagStrings.statusReason(run.statusReason) : void 0) ?? dagStrings.noLogFound;
1017
- const currentSublog = sublogOpen === "" ? "" : preview ? engine.toYaml(jobs[jobAndStep[0]]?.steps[Number(jobAndStep[1])]) : sublogsError || !sublogs ? missingLogText : sublogs;
970
+ const currentSublog = sublogOpen === "" ? "" : preview ? engine.toYaml(sublogStepData) : sublogsError || !sublogs ? missingLogText : sublogs;
1018
971
  const expansionKeys = useMemo(() => engine.expansionKeys(jobs, pathAppend), [
1019
972
  engine,
1020
973
  jobs,
@@ -1040,7 +993,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1040
993
  const nextStep = useCallback((backward) => {
1041
994
  const sublogSplit = sublogOpen.split("/");
1042
995
  let job = sublogSplit[sublogSplit.length - 3] ?? "";
1043
- let step = parseInt(sublogSplit[sublogSplit.length - 2].slice(5), 10);
996
+ let step = parseInt((sublogSplit[sublogSplit.length - 2] ?? "").slice(5), 10);
1044
997
  const jobArr = Object.keys(jobs);
1045
998
  let idx = jobArr.indexOf(job);
1046
999
  if (backward) {
@@ -1056,7 +1009,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1056
1009
  job = jobArr[idx + 1] ?? "";
1057
1010
  step = 0;
1058
1011
  }
1059
- setSublogOpen(sublogSplit.slice(0, -3).join("/") + `/${job}/step_${step}/` + sublogSplit.slice(-1)[0]);
1012
+ setSublogOpen(`${sublogSplit.slice(0, -3).join("/")}/${job}/step_${step}/${sublogSplit.slice(-1)[0]}`);
1060
1013
  }, [jobs, sublogOpen]);
1061
1014
  const handleKeyDown = useCallback((e) => {
1062
1015
  if (e.key === "ArrowRight") nextStep(false);
@@ -1091,7 +1044,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1091
1044
  toggleMatrix,
1092
1045
  openInNewGraph
1093
1046
  ]);
1094
- if (!Array.isArray(dependencyCols) || dependencyCols.length === 0 || !Array.isArray(dependencyCols[0]) || dependencyCols[0].length === 0 || !Array.isArray(dependencyCols[0][0]) || dependencyCols[0][0].length === 0) return;
1047
+ if (!dependencyCols[0]?.length) return;
1095
1048
  const startDt = run.createdAt ? DateTime.fromISO(run.createdAt) : now;
1096
1049
  const endDt = run.completedAt ? DateTime.fromISO(run.completedAt) : now;
1097
1050
  const runtime = toAbsHumanDuration(startDt, endDt);
@@ -1113,16 +1066,16 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1113
1066
  children: logName
1114
1067
  })
1115
1068
  ] }) : void 0;
1116
- const additionalBottomRightBarComponents = (!preview || sublogIsSubworkflow) && sublogOpen && sublogIsStep ? /* @__PURE__ */ jsx("button", {
1069
+ const additionalBottomRightBarComponents = (!preview || sublogIsSubworkflow) && sublogIsStep ? /* @__PURE__ */ jsx("button", {
1117
1070
  type: "button",
1118
1071
  className: "btn btn-neutral",
1119
1072
  onClick: () => {
1120
1073
  if (sublogIsSubworkflow) {
1121
- openInNewGraph(pathAppend, jobAndStep[0], parseInt(jobAndStep[1], 10));
1074
+ openInNewGraph(pathAppend, sublogJob, parseInt(sublogStep ?? "", 10));
1122
1075
  setSublogOpen("");
1123
- } else setSublogOpen(sublogOpen.split("/").slice(-1)[0] === "logs.out" ? [...sublogOpen.split("/").slice(0, -1), "script-unstable-redacted.sh"].join("/") : [...sublogOpen.split("/").slice(0, -1), "logs.out"].join("/"));
1076
+ } else setSublogOpen(sublogOpen.slice(0, sublogFileStart) + (sublogShowsLog ? "script-unstable-redacted.sh" : "logs.out"));
1124
1077
  },
1125
- children: /* @__PURE__ */ jsx("span", { children: sublogIsSubworkflow ? "Open Subworkflow" : sublogOpen.split("/").slice(-1)[0] === "logs.out" ? "Show Script" : "Show Logs" })
1078
+ children: /* @__PURE__ */ jsx("span", { children: sublogIsSubworkflow ? "Open Subworkflow" : sublogShowsLog ? "Show Script" : "Show Logs" })
1126
1079
  }) : void 0;
1127
1080
  return /* @__PURE__ */ jsxs("div", {
1128
1081
  className: "flex flex-col lg:flex-row w-full",
@@ -1212,7 +1165,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1212
1165
  children: dagStrings.submitted
1213
1166
  }), /* @__PURE__ */ jsx("div", {
1214
1167
  className: "text-sm font-semibold flex items-center gap-x-1",
1215
- children: startDt ? startDt.toLocaleString(DateTime.DATETIME_SHORT) : ""
1168
+ children: startDt.toLocaleString(DateTime.DATETIME_SHORT)
1216
1169
  })]
1217
1170
  }),
1218
1171
  /* @__PURE__ */ jsx("div", { className: "flex-1" }),
@@ -1223,7 +1176,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1223
1176
  setStepsOpen(/* @__PURE__ */ new Set());
1224
1177
  requestAnimationFrame(fitGraph);
1225
1178
  }
1226
- setViewMode?.(mode);
1179
+ setViewMode(mode);
1227
1180
  }
1228
1181
  })
1229
1182
  ]
@@ -1233,15 +1186,13 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1233
1186
  className: "panel w-full border",
1234
1187
  children: /* @__PURE__ */ jsx(TreeView, {
1235
1188
  jobs,
1236
- workflowName,
1237
- runNumber,
1238
1189
  slug: runSlug,
1239
1190
  expandedJobs,
1240
1191
  setExpandedJobs
1241
1192
  })
1242
1193
  }) : /* @__PURE__ */ jsx("div", {
1243
1194
  ref: setContainerElement,
1244
- className: "panel w-full " + (removeBorder ? "border-none" : "border") + " overflow-hidden relative",
1195
+ className: cx("panel w-full overflow-hidden relative", removeBorder ? "border-none" : "border"),
1245
1196
  style: {
1246
1197
  height: containerHeight !== null ? `${containerHeight}px` : previewHeight !== null ? `${Math.min(previewHeight, windowSize.h * .62)}px` : "62vh",
1247
1198
  minHeight: previewHeight !== null ? 0 : 160
@@ -1275,7 +1226,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1275
1226
  className: "btn btn-info w-21 cursor-pointer h-6",
1276
1227
  "aria-label": "Reset view",
1277
1228
  onClick: () => {
1278
- if ((executedJobsPath[executedJobsPathIdx]?.length ?? 0) > 0) {
1229
+ if (currentPath.length > 0) {
1279
1230
  resetGraph();
1280
1231
  setExecutedJobsPath([[], ...executedJobsPath.slice(executedJobsPathIdx, 10)]);
1281
1232
  setExecutedJobsPathIdx(0);
@@ -1350,7 +1301,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1350
1301
  value: currentSublog,
1351
1302
  height: window.innerHeight / 1.4,
1352
1303
  width: window.innerWidth / 1.4,
1353
- contentKey: "editor_" + sublogOpen
1304
+ contentKey: `editor_${sublogOpen}`
1354
1305
  }) ?? /* @__PURE__ */ jsx("pre", {
1355
1306
  className: "h-full overflow-auto text-xs p-4",
1356
1307
  style: {
@@ -1368,7 +1319,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
1368
1319
  })
1369
1320
  }), additionalBottomRightBarComponents]
1370
1321
  })] }) : /* @__PURE__ */ jsx(LogViewer, {
1371
- log: currentSublog?.length > 1e3 ? currentSublog.slice(-1e5) : currentSublog,
1322
+ log: currentSublog.slice(-1e5),
1372
1323
  height: windowSize.h / 1.2,
1373
1324
  width: windowSize.w / 1.2,
1374
1325
  hideExpand: true,
@@ -1390,9 +1341,8 @@ function DependencyGraphPreview(inputs) {
1390
1341
  workflowName: ""
1391
1342
  },
1392
1343
  preview: true,
1393
- initialScale: inputs.initialScale || 1,
1394
1344
  removeBorder: inputs.removeBorder
1395
1345
  });
1396
1346
  }
1397
1347
  //#endregion
1398
- export { DependencyGraphPreview, DependencyGraph as default };
1348
+ export { DependencyGraphPreview, addCleanupSteps, DependencyGraph as default };