@parallelworks/ui 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -6
- package/dist/ai/adapter/memoryStore.d.ts +8 -0
- package/dist/ai/adapter/mock/index.d.ts +2 -0
- package/dist/ai/adapter/mock/index.js +81 -0
- package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
- package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
- package/dist/ai/adapter/openai/errors.d.ts +3 -0
- package/dist/ai/adapter/openai/index.d.ts +6 -0
- package/dist/ai/adapter/openai/index.js +334 -0
- package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
- package/dist/ai/adapter/openai/responses.d.ts +4 -0
- package/dist/ai/adapter/openai/sse.d.ts +24 -0
- package/dist/ai/adapter/openai/wire.d.ts +40 -0
- package/dist/ai/adapter/types.d.ts +131 -0
- package/dist/ai/agent/classifier.d.ts +2 -0
- package/dist/ai/agent/diff.d.ts +35 -0
- package/dist/ai/agent/diffHighlight.d.ts +6 -0
- package/dist/ai/agent/index.d.ts +6 -0
- package/dist/ai/agent/permissions.d.ts +11 -0
- package/dist/ai/agent/toolfmt.d.ts +18 -0
- package/dist/ai/agent/transcript.d.ts +38 -0
- package/dist/ai/ai.css +325 -0
- package/dist/ai/components/AllocationSelector.d.ts +4 -0
- package/dist/ai/components/AttachmentManager.d.ts +1 -0
- package/dist/ai/components/AttachmentUpload.d.ts +24 -0
- package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
- package/dist/ai/components/BranchNavigator.d.ts +8 -0
- package/dist/ai/components/ChatEmptyState.d.ts +3 -0
- package/dist/ai/components/ChatInput.d.ts +45 -0
- package/dist/ai/components/ChatLayout.d.ts +5 -0
- package/dist/ai/components/ChatMessage.d.ts +24 -0
- package/dist/ai/components/ChatMessageList.d.ts +35 -0
- package/dist/ai/components/ChatSidebar.d.ts +5 -0
- package/dist/ai/components/ChatThread.d.ts +3 -0
- package/dist/ai/components/ComposerChrome.d.ts +18 -0
- package/dist/ai/components/ComposerFrame.d.ts +16 -0
- package/dist/ai/components/DragOverlay.d.ts +5 -0
- package/dist/ai/components/ModelSelector.d.ts +6 -0
- package/dist/ai/components/ShareDialog.d.ts +11 -0
- package/dist/ai/components/SlashMenu.d.ts +28 -0
- package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
- package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
- package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
- package/dist/ai/components/attachmentKeys.d.ts +4 -0
- package/dist/ai/core/ChatProvider.d.ts +66 -0
- package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
- package/dist/ai/core/chatReducer.d.ts +114 -0
- package/dist/ai/core/config.d.ts +47 -0
- package/dist/ai/core/events.d.ts +1 -0
- package/dist/ai/core/exportConversation.d.ts +4 -0
- package/dist/ai/core/greeting.d.ts +3 -0
- package/dist/ai/core/parts.d.ts +11 -0
- package/dist/ai/core/useDragDrop.d.ts +14 -0
- package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
- package/dist/ai/core/useSSEStream.d.ts +34 -0
- package/dist/ai/index.d.ts +40 -0
- package/dist/ai/index.js +6645 -0
- package/dist/ai/strings.d.ts +167 -0
- package/dist/ai/types.d.ts +236 -0
- package/dist/ai/ui/Avatar.d.ts +8 -0
- package/dist/ai/ui/Dropdown.d.ts +31 -0
- package/dist/ai/ui/Markdown.d.ts +8 -0
- package/dist/ai/ui/Notice.d.ts +21 -0
- package/dist/ai/ui/buttons.d.ts +1 -0
- package/dist/ai/ui/codeBreaks.d.ts +16 -0
- package/dist/ai/ui/prose.d.ts +1 -0
- package/dist/ai/ui/sidebar.d.ts +81 -0
- package/dist/ai/utils.d.ts +4 -0
- package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
- package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
- package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
- package/dist/chunks/{CodePreviewEditor-UAtnpmOV.js → CodePreviewEditor-YqQBz1YL.js} +2 -2
- package/dist/chunks/ConfirmModal-aOR4O1QE.js +79 -0
- package/dist/chunks/{lib-CUTRDpa6.js → FieldWrapper-Cszwg-4B.js} +52 -55
- package/dist/chunks/{CreateModal-BbV5cTj7.js → Markdown-CM-FenNE.js} +25 -97
- package/dist/chunks/Monaco-DJ8MW-Dq.js +110 -0
- package/dist/chunks/{PageHeader-MxuOs9cH.js → PageHeader-0kG_iypP.js} +170 -105
- package/dist/chunks/{Provider-DHmZ3v9i.js → Provider-CDYurraE.js} +60 -24
- package/dist/chunks/{SwitchToggle-BRQoEwLZ.js → SwitchToggle-DShNdcao.js} +143 -140
- package/dist/chunks/{Table-C6JdFFiJ.js → Table-DU2MW8xz.js} +6 -4
- package/dist/chunks/{Tooltip-n9w7Tkt1.js → Tooltip-K5HJr4_p.js} +32 -5
- package/dist/chunks/duration-BOv8Phl8.js +17 -0
- package/dist/chunks/{editor-mNznodJN.js → editor-Dk1rbV75.js} +33 -19
- package/dist/chunks/focus-D_iZJTW1.js +7 -0
- package/dist/chunks/{list-7k0eaI5N.js → list-CJm875m7.js} +497 -379
- package/dist/chunks/logviewer-BTKuQWzw.js +828 -0
- package/dist/chunks/memoryStore-CC91S5LP.js +152 -0
- package/dist/chunks/types-Yy0NrerF.js +11 -0
- package/dist/components/AddMenu.d.ts +1 -0
- package/dist/components/Avatar.d.ts +13 -0
- package/dist/components/Breadcrumbs.d.ts +1 -1
- package/dist/components/Dropdown.d.ts +3 -1
- package/dist/components/EmptyState.d.ts +1 -1
- package/dist/components/Indicator.d.ts +2 -2
- package/dist/components/Input.d.ts +1 -1
- package/dist/components/LetterBadge.d.ts +1 -1
- package/dist/components/MarkdownImpl.d.ts +1 -1
- package/dist/components/Provider.d.ts +18 -65
- package/dist/components/SettingRow.d.ts +1 -1
- package/dist/components/SettingsGroup.d.ts +1 -1
- package/dist/components/focus.d.ts +2 -0
- package/dist/components/keys.d.ts +12 -0
- package/dist/duration.d.ts +3 -0
- package/dist/editor/Monaco.d.ts +1 -20
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/index.js +2 -2
- package/dist/editor/yaml.d.ts +5 -0
- package/dist/engine.d.ts +98 -0
- package/dist/file-explorer/FileExplorer.d.ts +11 -2
- package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
- package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
- package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
- package/dist/file-explorer/FileRow.d.ts +1 -1
- package/dist/file-explorer/helpers.d.ts +4 -4
- package/dist/file-explorer/index.d.ts +3 -3
- package/dist/file-explorer/index.js +632 -665
- package/dist/file-explorer/lib/types.d.ts +6 -1
- package/dist/file-explorer/lib/utils.d.ts +1 -3
- package/dist/file-explorer/useNearEnd.d.ts +1 -1
- package/dist/form/FieldWrapper.d.ts +2 -1
- package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
- package/dist/form/Form.d.ts +7 -22
- package/dist/form/index.d.ts +11 -12
- package/dist/form/index.js +1333 -1454
- package/dist/form/lib.d.ts +6 -1
- package/dist/form/types/fieldComponentTypes.d.ts +4 -2
- package/dist/form/types/fieldTypes.d.ts +6 -20
- package/dist/form/useParsedOpts.d.ts +2 -2
- package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
- package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
- package/dist/{workflow → graph}/index.d.ts +1 -1
- package/dist/{workflow → graph}/index.js +220 -185
- package/dist/{workflow → graph}/types.d.ts +3 -3
- package/dist/icons.d.ts +20 -21
- package/dist/icons.js +3 -3
- package/dist/index.d.ts +38 -39
- package/dist/index.js +355 -354
- package/dist/list/ListTable.d.ts +1 -1
- package/dist/list/ListViewControls.d.ts +2 -2
- package/dist/list/RowContextMenu.d.ts +9 -9
- package/dist/list/UserHoverCard.d.ts +45 -0
- package/dist/list/index.d.ts +9 -8
- package/dist/list/index.js +3 -3
- package/dist/logviewer/LogViewer.d.ts +1 -1
- package/dist/logviewer/index.d.ts +1 -0
- package/dist/logviewer/index.js +2 -742
- package/dist/logviewer/segments.d.ts +9 -0
- package/dist/styles/Geist-Variable.woff2 +0 -0
- package/dist/styles/GeistMono-Variable.woff2 +0 -0
- package/dist/styles/base.css +57 -0
- package/dist/styles/fonts.css +15 -0
- package/dist/styles/theme.css +9 -41
- package/dist/styles.css +1 -1
- package/dist/theme/index.js +2 -2
- package/package.json +45 -20
- package/LICENSE +0 -21
- package/dist/chunks/Monaco-DVyIpyv4.js +0 -1046
- package/dist/editor/usesGitlab.d.ts +0 -97
- package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
- package/dist/form/types/workflow-schema.d.ts +0 -1145
- package/dist/form/utils/pwResolver.d.ts +0 -18
- package/dist/chunks/{BareModal-BqroLbZ5.js → BareModal-BtRiQezg.js} +1 -1
- package/dist/chunks/{MarkdownImpl-Bq4QhrtA.js → MarkdownImpl-CyeTVvSt.js} +1 -1
- /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
- /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
- /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
- /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
- /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
- /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
import { c as useRunFile, d as useWorkflowEngine, l as useSlots, r as useNavigation, u as useStrings } from "../chunks/Provider-CDYurraE.js";
|
|
1
2
|
import { ArrowLeftIcon, ArrowRightIcon, ChevronDownIcon, ChevronRightIcon, DocumentIcon, ErrorIcon, InfoIcon, LoaderIcon, OpenInNewGraphIcon, WarningIcon } from "../icons.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import { t as Loader } from "../chunks/Loader-BXoXTZGc.js";
|
|
5
|
-
import { n as modalPanelClasses, t as BareModal } from "../chunks/BareModal-BqroLbZ5.js";
|
|
3
|
+
import { n as TOOLTIP_ID, o as keyedByContent, r as TooltipInfo } from "../chunks/Tooltip-K5HJr4_p.js";
|
|
4
|
+
import { n as modalPanelClasses, t as BareModal } from "../chunks/BareModal-BtRiQezg.js";
|
|
6
5
|
import { t as Indicator } from "../chunks/Indicator-hBSIxOPK.js";
|
|
7
|
-
import {
|
|
6
|
+
import { t as Loader } from "../chunks/Loader-BXoXTZGc.js";
|
|
7
|
+
import { t as LogViewer } from "../chunks/logviewer-BTKuQWzw.js";
|
|
8
|
+
import { n as toAbsHumanDuration } from "../chunks/duration-BOv8Phl8.js";
|
|
8
9
|
import cx from "classnames";
|
|
9
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import React, { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
11
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
12
|
import { flushSync } from "react-dom";
|
|
12
13
|
import { DateTime } from "luxon";
|
|
13
|
-
import { buildSubworkflowLogPath, collapseMatrixGroupsInLayout, collectExpansionKeys, computeMatrixAggStatus, detectMatrixGroups, dumpYaml, getAllDeps, getStepLabel, isRunActive, toAbsHumanDuration } from "@parallelworks/workflow-parser";
|
|
14
14
|
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
|
|
15
15
|
import { AnimatePresence, motion } from "framer-motion";
|
|
16
|
-
//#region src/
|
|
16
|
+
//#region src/graph/AnnotationBanner.tsx
|
|
17
17
|
var typeOrder = {
|
|
18
18
|
error: 0,
|
|
19
19
|
warning: 1,
|
|
@@ -113,7 +113,7 @@ function AnnotationBanner({ executedJobs }) {
|
|
|
113
113
|
]
|
|
114
114
|
}), expanded && /* @__PURE__ */ jsx("div", {
|
|
115
115
|
className: "divide-y divide-[var(--theme-border)] max-h-[400px] overflow-y-auto",
|
|
116
|
-
children: annotations.map((
|
|
116
|
+
children: keyedByContent(annotations, (a) => a.id ?? `${a.type}:${a.title}:${a.message}`).map(({ key, item: annotation }) => {
|
|
117
117
|
const config = typeConfig[annotation.type] || typeConfig.notice;
|
|
118
118
|
const Icon = config.icon;
|
|
119
119
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -142,13 +142,13 @@ function AnnotationBanner({ executedJobs }) {
|
|
|
142
142
|
})
|
|
143
143
|
]
|
|
144
144
|
})]
|
|
145
|
-
},
|
|
145
|
+
}, key);
|
|
146
146
|
})
|
|
147
147
|
})]
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
150
|
//#endregion
|
|
151
|
-
//#region src/
|
|
151
|
+
//#region src/graph/Collapse.tsx
|
|
152
152
|
function Collapse({ expanded, children, releaseOverflow = true }) {
|
|
153
153
|
const [overflowVisible, setOverflowVisible] = useState(false);
|
|
154
154
|
return /* @__PURE__ */ jsx(AnimatePresence, {
|
|
@@ -185,7 +185,7 @@ function Collapse({ expanded, children, releaseOverflow = true }) {
|
|
|
185
185
|
});
|
|
186
186
|
}
|
|
187
187
|
//#endregion
|
|
188
|
-
//#region src/
|
|
188
|
+
//#region src/graph/Reveal.tsx
|
|
189
189
|
var EASE = "cubic-bezier(0.25, 0.1, 0.25, 1)";
|
|
190
190
|
var ROWS_TRANSITION = `grid-template-rows 200ms ${EASE}`;
|
|
191
191
|
var FULL_TRANSITION = `${ROWS_TRANSITION}, width 200ms ${EASE}`;
|
|
@@ -239,20 +239,13 @@ function Reveal({ open, children, growWidth = false, onSettled }) {
|
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
241
|
//#endregion
|
|
242
|
-
//#region src/
|
|
242
|
+
//#region src/graph/JobSummary.tsx
|
|
243
243
|
function UsesIcon({ uses, subworkflow }) {
|
|
244
244
|
const navigation = useNavigation();
|
|
245
245
|
const slots = useSlots();
|
|
246
246
|
const { jobActions } = useStrings();
|
|
247
247
|
if (!uses || !slots.workflowIcon) return null;
|
|
248
|
-
const open = () =>
|
|
249
|
-
if (uses.startsWith("workflow/")) navigation.toWorkflow(uses.split("/")[1] ?? "");
|
|
250
|
-
else if (subworkflow.sourceUrl) navigation.openExternal(subworkflow.sourceUrl);
|
|
251
|
-
else if (uses.startsWith("github/")) {
|
|
252
|
-
const [ownerRepo, ref] = uses.replace("github/", "").split("@");
|
|
253
|
-
navigation.openExternal("https://github.com/" + ownerRepo + "/tree/" + ref);
|
|
254
|
-
} else navigation.toMarketItem(uses.split("/")[1] ?? "");
|
|
255
|
-
};
|
|
248
|
+
const open = () => navigation.openStepSource(uses, subworkflow.sourceUrl);
|
|
256
249
|
return /* @__PURE__ */ jsx("button", {
|
|
257
250
|
type: "button",
|
|
258
251
|
"aria-label": jobActions.openOriginalWorkflow,
|
|
@@ -269,6 +262,7 @@ function UsesIcon({ uses, subworkflow }) {
|
|
|
269
262
|
}
|
|
270
263
|
function Joblist(inputs) {
|
|
271
264
|
const { jobActions } = useStrings();
|
|
265
|
+
const engine = useWorkflowEngine();
|
|
272
266
|
return inputs.jobNames.map((jobName) => {
|
|
273
267
|
if (inputs.jobs[jobName]?._matrixGroup) return null;
|
|
274
268
|
const jobStatus = inputs.jobs[jobName]?.status;
|
|
@@ -291,7 +285,8 @@ function Joblist(inputs) {
|
|
|
291
285
|
children: /* @__PURE__ */ jsx("div", {
|
|
292
286
|
className: "flex flex-col gap-y-0.5 mt-0.5",
|
|
293
287
|
children: (inputs.jobs[jobName]?.steps || []).map((step, i) => {
|
|
294
|
-
const stepLabel =
|
|
288
|
+
const stepLabel = engine.stepLabel(step, i);
|
|
289
|
+
const stepKey = `${jobName}:${i}`;
|
|
295
290
|
const subJobs = step.subworkflow?.jobs;
|
|
296
291
|
const canExpand = !!inputs.renderSubworkflow && !!subJobs && Object.keys(subJobs).length > 0;
|
|
297
292
|
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -302,7 +297,7 @@ function Joblist(inputs) {
|
|
|
302
297
|
className: cx(inputs.preview ? "ml-1.5" : "ml-4", "gap-x-1.5 flex items-center text-left"),
|
|
303
298
|
"data-testid": stepLabel,
|
|
304
299
|
children: [inputs.preview ? "↳" : /* @__PURE__ */ jsx(Indicator, { status: step.status }), /* @__PURE__ */ jsx("div", { children: stepLabel })]
|
|
305
|
-
}), step.subworkflow && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
300
|
+
}), step.subworkflow && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
306
301
|
inputs.onStepLogClick && /* @__PURE__ */ jsx("button", {
|
|
307
302
|
type: "button",
|
|
308
303
|
"aria-label": jobActions.openSubworkflowLogs,
|
|
@@ -332,7 +327,7 @@ function Joblist(inputs) {
|
|
|
332
327
|
children: /* @__PURE__ */ jsx(OpenInNewGraphIcon, { className: "w-[1.2em] h-[1.2em]" })
|
|
333
328
|
})
|
|
334
329
|
] })]
|
|
335
|
-
}), canExpand && inputs.renderSubworkflow?.(jobName, i)] },
|
|
330
|
+
}), canExpand && inputs.renderSubworkflow?.(jobName, i)] }, stepKey);
|
|
336
331
|
})
|
|
337
332
|
})
|
|
338
333
|
})]
|
|
@@ -340,14 +335,119 @@ function Joblist(inputs) {
|
|
|
340
335
|
});
|
|
341
336
|
}
|
|
342
337
|
//#endregion
|
|
343
|
-
//#region src/
|
|
338
|
+
//#region src/graph/MatrixGroup.tsx
|
|
339
|
+
/** Matrix group item in the summary sidebar. */
|
|
340
|
+
function MatrixGroupSummaryItem({ matrixGroup, status, isExpanded, onToggle, jobs, isStepsOpen, onJobClick, onStepClick, onStepLogClick, onSubworkflowIcon, isSubworkflowExpanded, renderSubworkflow, preview }) {
|
|
341
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
342
|
+
className: "py-1.5",
|
|
343
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
344
|
+
type: "button",
|
|
345
|
+
"aria-expanded": isExpanded,
|
|
346
|
+
onClick: onToggle,
|
|
347
|
+
className: "cursor-pointer flex items-center gap-x-1.5 w-full text-left",
|
|
348
|
+
children: [/* @__PURE__ */ jsx(Indicator, { status }), /* @__PURE__ */ jsxs("div", {
|
|
349
|
+
className: "font-semibold",
|
|
350
|
+
children: [
|
|
351
|
+
"Matrix: ",
|
|
352
|
+
matrixGroup.originaljob,
|
|
353
|
+
/* @__PURE__ */ jsxs("span", {
|
|
354
|
+
className: "font-normal text-sm ml-1",
|
|
355
|
+
children: [
|
|
356
|
+
"(",
|
|
357
|
+
matrixGroup.members.length,
|
|
358
|
+
" jobs)"
|
|
359
|
+
]
|
|
360
|
+
})
|
|
361
|
+
]
|
|
362
|
+
})]
|
|
363
|
+
}), /* @__PURE__ */ jsx(Reveal, {
|
|
364
|
+
open: isExpanded,
|
|
365
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
366
|
+
className: "ml-3 mt-0.5",
|
|
367
|
+
children: /* @__PURE__ */ jsx(Joblist, {
|
|
368
|
+
jobs,
|
|
369
|
+
jobNames: matrixGroup.members,
|
|
370
|
+
onJobClick,
|
|
371
|
+
isStepsOpen,
|
|
372
|
+
onStepClick,
|
|
373
|
+
onStepLogClick,
|
|
374
|
+
onSubworkflowIcon,
|
|
375
|
+
isSubworkflowExpanded,
|
|
376
|
+
renderSubworkflow,
|
|
377
|
+
preview
|
|
378
|
+
})
|
|
379
|
+
})
|
|
380
|
+
})]
|
|
381
|
+
}, "matrix-" + matrixGroup.originaljob);
|
|
382
|
+
}
|
|
383
|
+
/** Matrix group node in the DAG visualization. */
|
|
384
|
+
function MatrixGroupNode({ matrixGroup, jobNames, idPrefix, isExpanded, onToggle, jobs, activeDists, onMouseEnter, onMouseLeave, hoveredRelated, animT, zBase, isStepsOpen, onJobClick, onStepClick, onStepLogClick, onSubworkflowIcon, isSubworkflowExpanded, renderSubworkflow, preview }) {
|
|
385
|
+
const matrixName = matrixGroup.originaljob;
|
|
386
|
+
const matrixMembers = matrixGroup.members;
|
|
387
|
+
const { aggStatus, statusLabel } = useWorkflowEngine().matrixStatus(matrixMembers.map((m) => jobs[m]?.status));
|
|
388
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
389
|
+
id: "node_" + idPrefix + jobNames[0],
|
|
390
|
+
role: "none",
|
|
391
|
+
className: "relative m-24",
|
|
392
|
+
style: { zIndex: (activeDists?.has(jobNames[0]) ? 25 : 1) + zBase },
|
|
393
|
+
onMouseEnter,
|
|
394
|
+
onMouseLeave,
|
|
395
|
+
onFocus: onMouseEnter,
|
|
396
|
+
onBlur: onMouseLeave,
|
|
397
|
+
children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-2xl bg-(--theme-panel-bg)" }), /* @__PURE__ */ jsxs("div", {
|
|
398
|
+
className: "relative border-solid shadow py-4 px-8 rounded-xl border-4 whitespace-nowrap bg-(--theme-panel-bg) text-2xl",
|
|
399
|
+
style: {
|
|
400
|
+
opacity: hoveredRelated && !hoveredRelated.has(jobNames[0]) ? .5 : 1,
|
|
401
|
+
transition: `opacity ${animT}s`
|
|
402
|
+
},
|
|
403
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
404
|
+
type: "button",
|
|
405
|
+
"aria-expanded": isExpanded,
|
|
406
|
+
className: "cursor-pointer w-full text-left",
|
|
407
|
+
onClick: onToggle,
|
|
408
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
409
|
+
className: "font-semibold text-md p-0.5",
|
|
410
|
+
children: ["Matrix: ", matrixName.length > 20 ? matrixName.slice(0, 20) + "..." : matrixName]
|
|
411
|
+
}), !isExpanded && /* @__PURE__ */ jsxs("div", {
|
|
412
|
+
className: "mt-1 border-t border-(--theme-border) pt-1 flex items-center gap-x-1",
|
|
413
|
+
children: [/* @__PURE__ */ jsx(Indicator, { status: aggStatus }), /* @__PURE__ */ jsx("span", { children: statusLabel })]
|
|
414
|
+
})]
|
|
415
|
+
}), /* @__PURE__ */ jsx(Reveal, {
|
|
416
|
+
open: isExpanded,
|
|
417
|
+
growWidth: true,
|
|
418
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
419
|
+
className: "mt-1 border-t border-(--theme-border) pt-1",
|
|
420
|
+
children: /* @__PURE__ */ jsx(Joblist, {
|
|
421
|
+
jobs,
|
|
422
|
+
jobNames: matrixMembers,
|
|
423
|
+
onJobClick,
|
|
424
|
+
isStepsOpen,
|
|
425
|
+
onStepClick,
|
|
426
|
+
onStepLogClick,
|
|
427
|
+
onSubworkflowIcon,
|
|
428
|
+
isSubworkflowExpanded,
|
|
429
|
+
renderSubworkflow,
|
|
430
|
+
growWidth: true,
|
|
431
|
+
preview
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
})]
|
|
435
|
+
})]
|
|
436
|
+
}, "node_" + jobNames[0]);
|
|
437
|
+
}
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/graph/TreeView.tsx
|
|
344
440
|
function getStepDuration(step) {
|
|
345
441
|
if (!step.startedAt) return "";
|
|
346
|
-
|
|
442
|
+
const start = DateTime.fromISO(step.startedAt);
|
|
443
|
+
const end = step.completedAt ? DateTime.fromISO(step.completedAt) : DateTime.now();
|
|
444
|
+
return toAbsHumanDuration(start, end);
|
|
347
445
|
}
|
|
348
446
|
function getJobDuration(job) {
|
|
349
447
|
if (!job.startedAt) return "";
|
|
350
|
-
|
|
448
|
+
const start = DateTime.fromISO(job.startedAt);
|
|
449
|
+
const end = job.completedAt ? DateTime.fromISO(job.completedAt) : DateTime.now();
|
|
450
|
+
return toAbsHumanDuration(start, end);
|
|
351
451
|
}
|
|
352
452
|
function formatJobLabel(jobName, job) {
|
|
353
453
|
const matrix = job?._matrix;
|
|
@@ -355,7 +455,8 @@ function formatJobLabel(jobName, job) {
|
|
|
355
455
|
return (jobName[0].toUpperCase() + jobName.slice(1)).replace(/_/g, " ");
|
|
356
456
|
}
|
|
357
457
|
function InlineLogViewer({ slug, jobName, stepIndex }) {
|
|
358
|
-
const
|
|
458
|
+
const logPath = useWorkflowEngine().stepLogPath("", jobName, stepIndex);
|
|
459
|
+
const { data: logs, isLoading, error } = useRunFile(slug, logPath, { refreshInterval: 2e3 });
|
|
359
460
|
if (isLoading && !logs) return /* @__PURE__ */ jsxs("div", {
|
|
360
461
|
className: "flex items-center gap-2 px-5 py-4 text-sm text-[var(--theme-muted-text-color)]",
|
|
361
462
|
children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "w-4 h-4" }), /* @__PURE__ */ jsx("span", { children: "Loading logs..." })]
|
|
@@ -448,10 +549,11 @@ function JobRow({ jobName, job, isExpanded, onToggle, dependencies, workflowName
|
|
|
448
549
|
className: "ml-[38px] border-l-2 border-[var(--theme-border)]",
|
|
449
550
|
children: job.steps.map((step, index) => {
|
|
450
551
|
const stepKey = `${jobName}:${index}`;
|
|
552
|
+
const isStepExpanded = expandedSteps.has(stepKey);
|
|
451
553
|
return /* @__PURE__ */ jsx(StepRow, {
|
|
452
554
|
step,
|
|
453
555
|
index,
|
|
454
|
-
isExpanded:
|
|
556
|
+
isExpanded: isStepExpanded,
|
|
455
557
|
onToggle: () => onStepToggle(stepKey),
|
|
456
558
|
workflowName,
|
|
457
559
|
runNumber,
|
|
@@ -461,7 +563,7 @@ function JobRow({ jobName, job, isExpanded, onToggle, dependencies, workflowName
|
|
|
461
563
|
onJobToggle,
|
|
462
564
|
expandedSteps,
|
|
463
565
|
onStepToggle
|
|
464
|
-
},
|
|
566
|
+
}, stepKey);
|
|
465
567
|
})
|
|
466
568
|
})
|
|
467
569
|
})
|
|
@@ -469,9 +571,10 @@ function JobRow({ jobName, job, isExpanded, onToggle, dependencies, workflowName
|
|
|
469
571
|
});
|
|
470
572
|
}
|
|
471
573
|
function StepRow({ step, index, isExpanded, onToggle, workflowName, runNumber, slug, jobName, expandedJobs, onJobToggle, expandedSteps, onStepToggle, depth = 0 }) {
|
|
574
|
+
const engine = useWorkflowEngine();
|
|
472
575
|
const slots = useSlots();
|
|
473
576
|
const duration = getStepDuration(step);
|
|
474
|
-
const label =
|
|
577
|
+
const label = engine.stepLabel(step, index);
|
|
475
578
|
const isSubworkflow = !!step.subworkflow;
|
|
476
579
|
const panelId = useId();
|
|
477
580
|
const subworkflowJobs = step.subworkflow?.jobs ?? null;
|
|
@@ -583,10 +686,11 @@ function StepRow({ step, index, isExpanded, onToggle, workflowName, runNumber, s
|
|
|
583
686
|
const subJob = subworkflowJobs?.[subJobName];
|
|
584
687
|
if (!subJob) return null;
|
|
585
688
|
const subJobKey = `${jobName}:${index}:${subJobName}`;
|
|
689
|
+
const isSubJobExpanded = expandedJobs.has(subJobKey);
|
|
586
690
|
return /* @__PURE__ */ jsx(SubworkflowJobRow, {
|
|
587
691
|
jobName: subJobName,
|
|
588
692
|
job: subJob,
|
|
589
|
-
isExpanded:
|
|
693
|
+
isExpanded: isSubJobExpanded,
|
|
590
694
|
onToggle: () => onJobToggle(subJobKey),
|
|
591
695
|
dependencies: subworkflowDependenciesMap[subJobName],
|
|
592
696
|
slug,
|
|
@@ -677,10 +781,11 @@ function SubworkflowJobRow({ jobName, job, isExpanded, onToggle, dependencies, s
|
|
|
677
781
|
className: "ml-[38px] border-l-2 border-[var(--theme-border)]",
|
|
678
782
|
children: job.steps.map((step, index) => {
|
|
679
783
|
const stepKey = `${nestedSubworkflowPrefix}${jobName}:${index}`;
|
|
784
|
+
const isStepExpanded = expandedSteps.has(stepKey);
|
|
680
785
|
return /* @__PURE__ */ jsx(SubworkflowStepRow, {
|
|
681
786
|
step,
|
|
682
787
|
index,
|
|
683
|
-
isExpanded:
|
|
788
|
+
isExpanded: isStepExpanded,
|
|
684
789
|
onToggle: () => onStepToggle(stepKey),
|
|
685
790
|
slug,
|
|
686
791
|
subworkflowPrefix: nestedSubworkflowPrefix,
|
|
@@ -690,7 +795,7 @@ function SubworkflowJobRow({ jobName, job, isExpanded, onToggle, dependencies, s
|
|
|
690
795
|
expandedSteps,
|
|
691
796
|
onStepToggle,
|
|
692
797
|
depth
|
|
693
|
-
},
|
|
798
|
+
}, stepKey);
|
|
694
799
|
})
|
|
695
800
|
})
|
|
696
801
|
})
|
|
@@ -698,9 +803,10 @@ function SubworkflowJobRow({ jobName, job, isExpanded, onToggle, dependencies, s
|
|
|
698
803
|
});
|
|
699
804
|
}
|
|
700
805
|
function SubworkflowStepRow({ step, index, isExpanded, onToggle, slug, subworkflowPrefix, jobName, expandedJobs, onJobToggle, expandedSteps, onStepToggle, depth }) {
|
|
806
|
+
const engine = useWorkflowEngine();
|
|
701
807
|
const slots = useSlots();
|
|
702
808
|
const duration = getStepDuration(step);
|
|
703
|
-
const label =
|
|
809
|
+
const label = engine.stepLabel(step, index);
|
|
704
810
|
const isSubworkflow = !!step.subworkflow;
|
|
705
811
|
const panelId = useId();
|
|
706
812
|
const subworkflowJobs = step.subworkflow?.jobs ?? null;
|
|
@@ -813,10 +919,11 @@ function SubworkflowStepRow({ step, index, isExpanded, onToggle, slug, subworkfl
|
|
|
813
919
|
const subJob = subworkflowJobs?.[subJobName];
|
|
814
920
|
if (!subJob) return null;
|
|
815
921
|
const subJobKey = `${subworkflowPrefix}${jobName}:${index}:${subJobName}`;
|
|
922
|
+
const isSubJobExpanded = expandedJobs.has(subJobKey);
|
|
816
923
|
return /* @__PURE__ */ jsx(SubworkflowJobRow, {
|
|
817
924
|
jobName: subJobName,
|
|
818
925
|
job: subJob,
|
|
819
|
-
isExpanded:
|
|
926
|
+
isExpanded: isSubJobExpanded,
|
|
820
927
|
onToggle: () => onJobToggle(subJobKey),
|
|
821
928
|
dependencies: subworkflowDependenciesMap[subJobName],
|
|
822
929
|
slug,
|
|
@@ -836,7 +943,8 @@ function SubworkflowStepRow({ step, index, isExpanded, onToggle, slug, subworkfl
|
|
|
836
943
|
] });
|
|
837
944
|
}
|
|
838
945
|
function SubworkflowInlineLogViewer({ slug, subworkflowPrefix, jobName, stepIndex }) {
|
|
839
|
-
const
|
|
946
|
+
const logPath = useWorkflowEngine().stepLogPath(subworkflowPrefix, jobName, stepIndex);
|
|
947
|
+
const { data: logs, isLoading, error } = useRunFile(slug, logPath, { refreshInterval: 2e3 });
|
|
840
948
|
if (isLoading && !logs) return /* @__PURE__ */ jsxs("div", {
|
|
841
949
|
className: "flex items-center gap-2 px-5 py-4 text-sm text-[var(--theme-muted-text-color)]",
|
|
842
950
|
children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "w-4 h-4" }), /* @__PURE__ */ jsx("span", { children: "Loading logs..." })]
|
|
@@ -858,6 +966,7 @@ function SubworkflowInlineLogViewer({ slug, subworkflowPrefix, jobName, stepInde
|
|
|
858
966
|
});
|
|
859
967
|
}
|
|
860
968
|
function TreeView({ jobs, workflowName, runNumber, slug, expandedJobs, setExpandedJobs }) {
|
|
969
|
+
const engine = useWorkflowEngine();
|
|
861
970
|
const visibleJobNames = useMemo(() => {
|
|
862
971
|
return Object.keys(jobs).filter((jobName) => jobs[jobName]?.if !== false);
|
|
863
972
|
}, [jobs]);
|
|
@@ -924,10 +1033,17 @@ function TreeView({ jobs, workflowName, runNumber, slug, expandedJobs, setExpand
|
|
|
924
1033
|
const matrixGroups = {};
|
|
925
1034
|
for (const jobName of visibleJobNames) {
|
|
926
1035
|
const matrix = jobs[jobName]?._matrix;
|
|
927
|
-
if (matrix?.originaljob)
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1036
|
+
if (matrix?.originaljob) {
|
|
1037
|
+
let group = matrixGroups[matrix.originaljob];
|
|
1038
|
+
if (!group) {
|
|
1039
|
+
group = {
|
|
1040
|
+
originaljob: matrix.originaljob,
|
|
1041
|
+
members: []
|
|
1042
|
+
};
|
|
1043
|
+
matrixGroups[matrix.originaljob] = group;
|
|
1044
|
+
}
|
|
1045
|
+
group.members.push(jobName);
|
|
1046
|
+
}
|
|
931
1047
|
}
|
|
932
1048
|
for (const group of Object.values(matrixGroups)) group.members.sort((a, b) => (jobs[a]?._matrix?.index ?? 0) - (jobs[b]?._matrix?.index ?? 0));
|
|
933
1049
|
const rendered = [];
|
|
@@ -940,7 +1056,7 @@ function TreeView({ jobs, workflowName, runNumber, slug, expandedJobs, setExpand
|
|
|
940
1056
|
const group = matrixGroups[matrixOrigin];
|
|
941
1057
|
if (!group) continue;
|
|
942
1058
|
const isGroupExpanded = expandedJobs.has(`matrix:${matrixOrigin}`);
|
|
943
|
-
const { aggStatus } =
|
|
1059
|
+
const { aggStatus } = engine.matrixStatus(group.members.map((m) => jobs[m]?.status));
|
|
944
1060
|
rendered.push(/* @__PURE__ */ jsxs("div", {
|
|
945
1061
|
className: "border-b border-[var(--theme-border)]",
|
|
946
1062
|
children: [/* @__PURE__ */ jsxs("button", {
|
|
@@ -1020,117 +1136,12 @@ function TreeView({ jobs, workflowName, runNumber, slug, expandedJobs, setExpand
|
|
|
1020
1136
|
});
|
|
1021
1137
|
}
|
|
1022
1138
|
//#endregion
|
|
1023
|
-
//#region src/
|
|
1024
|
-
/** Matrix group item in the summary sidebar. */
|
|
1025
|
-
function MatrixGroupSummaryItem({ matrixGroup, status, isExpanded, onToggle, jobs, isStepsOpen, onJobClick, onStepClick, onStepLogClick, onSubworkflowIcon, isSubworkflowExpanded, renderSubworkflow, preview }) {
|
|
1026
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1027
|
-
className: "py-1.5",
|
|
1028
|
-
children: [/* @__PURE__ */ jsxs("button", {
|
|
1029
|
-
type: "button",
|
|
1030
|
-
"aria-expanded": isExpanded,
|
|
1031
|
-
onClick: onToggle,
|
|
1032
|
-
className: "cursor-pointer flex items-center gap-x-1.5 w-full text-left",
|
|
1033
|
-
children: [/* @__PURE__ */ jsx(Indicator, { status }), /* @__PURE__ */ jsxs("div", {
|
|
1034
|
-
className: "font-semibold",
|
|
1035
|
-
children: [
|
|
1036
|
-
"Matrix: ",
|
|
1037
|
-
matrixGroup.originaljob,
|
|
1038
|
-
/* @__PURE__ */ jsxs("span", {
|
|
1039
|
-
className: "font-normal text-sm ml-1",
|
|
1040
|
-
children: [
|
|
1041
|
-
"(",
|
|
1042
|
-
matrixGroup.members.length,
|
|
1043
|
-
" jobs)"
|
|
1044
|
-
]
|
|
1045
|
-
})
|
|
1046
|
-
]
|
|
1047
|
-
})]
|
|
1048
|
-
}), /* @__PURE__ */ jsx(Reveal, {
|
|
1049
|
-
open: isExpanded,
|
|
1050
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
1051
|
-
className: "ml-3 mt-0.5",
|
|
1052
|
-
children: /* @__PURE__ */ jsx(Joblist, {
|
|
1053
|
-
jobs,
|
|
1054
|
-
jobNames: matrixGroup.members,
|
|
1055
|
-
onJobClick,
|
|
1056
|
-
isStepsOpen,
|
|
1057
|
-
onStepClick,
|
|
1058
|
-
onStepLogClick,
|
|
1059
|
-
onSubworkflowIcon,
|
|
1060
|
-
isSubworkflowExpanded,
|
|
1061
|
-
renderSubworkflow,
|
|
1062
|
-
preview
|
|
1063
|
-
})
|
|
1064
|
-
})
|
|
1065
|
-
})]
|
|
1066
|
-
}, "matrix-" + matrixGroup.originaljob);
|
|
1067
|
-
}
|
|
1068
|
-
/** Matrix group node in the DAG visualization. */
|
|
1069
|
-
function MatrixGroupNode({ matrixGroup, jobNames, idPrefix, isExpanded, onToggle, jobs, activeDists, onMouseEnter, onMouseLeave, hoveredRelated, animT, zBase, isStepsOpen, onJobClick, onStepClick, onStepLogClick, onSubworkflowIcon, isSubworkflowExpanded, renderSubworkflow, preview }) {
|
|
1070
|
-
const matrixName = matrixGroup.originaljob;
|
|
1071
|
-
const matrixMembers = matrixGroup.members;
|
|
1072
|
-
const { aggStatus, statusLabel } = computeMatrixAggStatus(matrixMembers.map((m) => jobs[m]?.status));
|
|
1073
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1074
|
-
id: "node_" + idPrefix + jobNames[0],
|
|
1075
|
-
role: "none",
|
|
1076
|
-
className: "relative m-24",
|
|
1077
|
-
style: { zIndex: (activeDists?.has(jobNames[0]) ? 25 : 1) + zBase },
|
|
1078
|
-
onMouseEnter,
|
|
1079
|
-
onMouseLeave,
|
|
1080
|
-
onFocus: onMouseEnter,
|
|
1081
|
-
onBlur: onMouseLeave,
|
|
1082
|
-
children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-2xl bg-(--theme-panel-bg)" }), /* @__PURE__ */ jsxs("div", {
|
|
1083
|
-
className: "relative border-solid shadow py-4 px-8 rounded-xl border-4 whitespace-nowrap bg-(--theme-panel-bg) text-2xl",
|
|
1084
|
-
style: {
|
|
1085
|
-
opacity: hoveredRelated && !hoveredRelated.has(jobNames[0]) ? .5 : 1,
|
|
1086
|
-
transition: `opacity ${animT}s`
|
|
1087
|
-
},
|
|
1088
|
-
children: [/* @__PURE__ */ jsxs("button", {
|
|
1089
|
-
type: "button",
|
|
1090
|
-
"aria-expanded": isExpanded,
|
|
1091
|
-
className: "cursor-pointer w-full text-left",
|
|
1092
|
-
onClick: onToggle,
|
|
1093
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
1094
|
-
className: "font-semibold text-md p-0.5",
|
|
1095
|
-
children: [
|
|
1096
|
-
"Matrix:",
|
|
1097
|
-
" ",
|
|
1098
|
-
matrixName.length > 20 ? matrixName.slice(0, 20) + "..." : matrixName
|
|
1099
|
-
]
|
|
1100
|
-
}), !isExpanded && /* @__PURE__ */ jsxs("div", {
|
|
1101
|
-
className: "mt-1 border-t border-(--theme-border) pt-1 flex items-center gap-x-1",
|
|
1102
|
-
children: [/* @__PURE__ */ jsx(Indicator, { status: aggStatus }), /* @__PURE__ */ jsx("span", { children: statusLabel })]
|
|
1103
|
-
})]
|
|
1104
|
-
}), /* @__PURE__ */ jsx(Reveal, {
|
|
1105
|
-
open: isExpanded,
|
|
1106
|
-
growWidth: true,
|
|
1107
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
1108
|
-
className: "mt-1 border-t border-(--theme-border) pt-1",
|
|
1109
|
-
children: /* @__PURE__ */ jsx(Joblist, {
|
|
1110
|
-
jobs,
|
|
1111
|
-
jobNames: matrixMembers,
|
|
1112
|
-
onJobClick,
|
|
1113
|
-
isStepsOpen,
|
|
1114
|
-
onStepClick,
|
|
1115
|
-
onStepLogClick,
|
|
1116
|
-
onSubworkflowIcon,
|
|
1117
|
-
isSubworkflowExpanded,
|
|
1118
|
-
renderSubworkflow,
|
|
1119
|
-
growWidth: true,
|
|
1120
|
-
preview
|
|
1121
|
-
})
|
|
1122
|
-
})
|
|
1123
|
-
})]
|
|
1124
|
-
})]
|
|
1125
|
-
}, "node_" + jobNames[0]);
|
|
1126
|
-
}
|
|
1127
|
-
//#endregion
|
|
1128
|
-
//#region src/workflow/types.ts
|
|
1139
|
+
//#region src/graph/types.ts
|
|
1129
1140
|
function isJobRecord(value) {
|
|
1130
1141
|
return typeof value === "object" && value !== null;
|
|
1131
1142
|
}
|
|
1132
1143
|
//#endregion
|
|
1133
|
-
//#region src/
|
|
1144
|
+
//#region src/graph/DependencyGraph.tsx
|
|
1134
1145
|
function ViewToggle({ viewMode, setViewMode }) {
|
|
1135
1146
|
return /* @__PURE__ */ jsxs("div", {
|
|
1136
1147
|
className: "flex border border-[var(--theme-border)] rounded overflow-hidden",
|
|
@@ -1235,12 +1246,12 @@ function parsePrefixToPath(prefix) {
|
|
|
1235
1246
|
}
|
|
1236
1247
|
return path;
|
|
1237
1248
|
}
|
|
1238
|
-
function computeGraphLayout(jobs, matrixGroups) {
|
|
1249
|
+
function computeGraphLayout(engine, jobs, matrixGroups) {
|
|
1239
1250
|
const visibleJobs = structuredClone(jobs);
|
|
1240
1251
|
for (const jobName of Object.keys(jobs ?? {})) if (jobs[jobName]?.if === false) delete visibleJobs[jobName];
|
|
1241
|
-
|
|
1252
|
+
engine.collapseMatrixGroups(matrixGroups, visibleJobs);
|
|
1242
1253
|
const allDeps = {};
|
|
1243
|
-
for (const jobName of Object.keys(visibleJobs)) allDeps[jobName] =
|
|
1254
|
+
for (const jobName of Object.keys(visibleJobs)) allDeps[jobName] = engine.jobDependencies(jobName, visibleJobs, allDeps);
|
|
1244
1255
|
const filteredDeps = {};
|
|
1245
1256
|
for (const jobName of Object.keys(visibleJobs)) {
|
|
1246
1257
|
const needs = visibleJobs[jobName]?.needs;
|
|
@@ -1253,19 +1264,19 @@ function computeGraphLayout(jobs, matrixGroups) {
|
|
|
1253
1264
|
}).sort();
|
|
1254
1265
|
}
|
|
1255
1266
|
const depended_on = {};
|
|
1256
|
-
Object.keys(visibleJobs).
|
|
1267
|
+
Object.keys(visibleJobs).forEach((jobName) => {
|
|
1257
1268
|
if (filteredDeps[jobName] && Array.isArray(filteredDeps[jobName])) filteredDeps[jobName].forEach((dep) => {
|
|
1258
1269
|
if (depended_on[dep]) depended_on[dep].push(jobName);
|
|
1259
1270
|
else depended_on[dep] = [jobName];
|
|
1260
1271
|
});
|
|
1261
1272
|
});
|
|
1262
|
-
Object.keys(visibleJobs).
|
|
1273
|
+
Object.keys(visibleJobs).forEach((jobName) => {
|
|
1263
1274
|
if (depended_on[jobName]) depended_on[jobName].sort();
|
|
1264
1275
|
});
|
|
1265
1276
|
const unfinished = structuredClone(visibleJobs);
|
|
1266
1277
|
const rootLevel = [];
|
|
1267
1278
|
const deps = [rootLevel];
|
|
1268
|
-
Object.keys(visibleJobs).
|
|
1279
|
+
Object.keys(visibleJobs).forEach((jobName) => {
|
|
1269
1280
|
if (filteredDeps[jobName]?.length === 0) {
|
|
1270
1281
|
rootLevel.push(jobName);
|
|
1271
1282
|
delete unfinished[jobName];
|
|
@@ -1276,7 +1287,7 @@ function computeGraphLayout(jobs, matrixGroups) {
|
|
|
1276
1287
|
const toAppend = [];
|
|
1277
1288
|
const unfinishedArr = Object.keys(unfinished);
|
|
1278
1289
|
prevLen = unfinishedArr.length;
|
|
1279
|
-
unfinishedArr.
|
|
1290
|
+
unfinishedArr.forEach((jobName) => {
|
|
1280
1291
|
if ((filteredDeps[jobName] ?? []).every((dep) => !unfinishedArr.includes(dep))) {
|
|
1281
1292
|
toAppend.push(jobName);
|
|
1282
1293
|
delete unfinished[jobName];
|
|
@@ -1285,14 +1296,14 @@ function computeGraphLayout(jobs, matrixGroups) {
|
|
|
1285
1296
|
if (toAppend.length > 0) deps.push(toAppend);
|
|
1286
1297
|
} while (prevLen !== Object.keys(unfinished).length);
|
|
1287
1298
|
const finalDeps = [];
|
|
1288
|
-
deps.
|
|
1299
|
+
deps.forEach((col) => {
|
|
1289
1300
|
const toAppend = [];
|
|
1290
1301
|
while (col.length > 0) {
|
|
1291
1302
|
const head = col[0];
|
|
1292
1303
|
if (head === void 0) break;
|
|
1293
1304
|
const grouped = [head];
|
|
1294
1305
|
const toRm = [0];
|
|
1295
|
-
col.slice(1).
|
|
1306
|
+
col.slice(1).forEach((jobName, j) => {
|
|
1296
1307
|
if (visibleJobs[head]?._matrixGroup || visibleJobs[jobName]?._matrixGroup) return;
|
|
1297
1308
|
const depsA = depended_on[head];
|
|
1298
1309
|
const depsB = depended_on[jobName];
|
|
@@ -1375,14 +1386,19 @@ function SubworkflowWell({ expanded, onSettled, className, children }) {
|
|
|
1375
1386
|
var SUBGRAPH_Z_STEP = 100;
|
|
1376
1387
|
var FIT_ANIMATION_MS = 300;
|
|
1377
1388
|
function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflows, toggleSubworkflow, openInNewGraph, setSublogOpen, invalidateConnectors, requestFit, stepsOpen, toggleSteps, matrixOpen, toggleMatrix, onReady }) {
|
|
1389
|
+
const engine = useWorkflowEngine();
|
|
1378
1390
|
const wrapperRef = useRef(null);
|
|
1379
1391
|
const zBase = depth * SUBGRAPH_Z_STEP;
|
|
1380
1392
|
const [hoveredJob, setHoveredJob] = useState(null);
|
|
1381
1393
|
const lastHoveredDistancesRef = useRef(null);
|
|
1382
1394
|
const maxHoveredDistRef = useRef(0);
|
|
1383
1395
|
const retractPathLensRef = useRef(/* @__PURE__ */ new Map());
|
|
1384
|
-
const matrixGroups = useMemo(() =>
|
|
1385
|
-
const { dependencyCols, directDeps, displayJobs, ancestorDists, descendantDists } = useMemo(() => computeGraphLayout(jobs, matrixGroups), [
|
|
1396
|
+
const matrixGroups = useMemo(() => engine.matrixGroups(jobs), [engine, jobs]);
|
|
1397
|
+
const { dependencyCols, directDeps, displayJobs, ancestorDists, descendantDists } = useMemo(() => computeGraphLayout(engine, jobs, matrixGroups), [
|
|
1398
|
+
engine,
|
|
1399
|
+
jobs,
|
|
1400
|
+
matrixGroups
|
|
1401
|
+
]);
|
|
1386
1402
|
const hoveredDistances = useMemo(() => {
|
|
1387
1403
|
if (!hoveredJob) return null;
|
|
1388
1404
|
const dist = /* @__PURE__ */ new Map();
|
|
@@ -1474,9 +1490,9 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
|
|
|
1474
1490
|
const stepStatus = jobs[j]?.steps?.[+s]?.status;
|
|
1475
1491
|
if (stepStatus === "skipped" || stepStatus === "skipped-failed") return;
|
|
1476
1492
|
if (jobs[j]?.steps[+s]?.subworkflow) expandInline(j, +s);
|
|
1477
|
-
else setSublogOpen(
|
|
1493
|
+
else setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
|
|
1478
1494
|
};
|
|
1479
|
-
const onStepLogClick = (j, s) => setSublogOpen(
|
|
1495
|
+
const onStepLogClick = (j, s) => setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
|
|
1480
1496
|
const onSubworkflowIcon = (j, s) => openNew(j, s);
|
|
1481
1497
|
const isSubworkflowExpanded = (j, s) => expandedSubworkflows.has(`${pathPrefix}${j}:${s}`);
|
|
1482
1498
|
const renderSubworkflow = (j, s) => {
|
|
@@ -1486,7 +1502,7 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
|
|
|
1486
1502
|
expanded: isSubworkflowExpanded(j, s),
|
|
1487
1503
|
onSettled: requestFit,
|
|
1488
1504
|
className: "my-2 rounded-lg border-4 border-(--theme-border)",
|
|
1489
|
-
children: /* @__PURE__ */ jsx(
|
|
1505
|
+
children: /* @__PURE__ */ jsx(NestedSubgraph, {
|
|
1490
1506
|
jobs: subJobs,
|
|
1491
1507
|
pathPrefix: `${pathPrefix}subworkflows/${j}/step_${s}/`,
|
|
1492
1508
|
depth: depth + 1,
|
|
@@ -1584,6 +1600,7 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
|
|
|
1584
1600
|
toggleMatrix,
|
|
1585
1601
|
openInNewGraph,
|
|
1586
1602
|
setSublogOpen,
|
|
1603
|
+
engine,
|
|
1587
1604
|
invalidateConnectors,
|
|
1588
1605
|
requestFit
|
|
1589
1606
|
]);
|
|
@@ -1772,6 +1789,7 @@ function Subgraph({ jobs, pathPrefix, depth, preview, animT, expandedSubworkflow
|
|
|
1772
1789
|
})(), hasLiveNestedGraph ? buildBoxLayer() : memoizedBoxLayer]
|
|
1773
1790
|
});
|
|
1774
1791
|
}
|
|
1792
|
+
var NestedSubgraph = Subgraph;
|
|
1775
1793
|
function SidebarWell({ expanded, children }) {
|
|
1776
1794
|
return /* @__PURE__ */ jsx(Collapse, {
|
|
1777
1795
|
expanded,
|
|
@@ -1780,8 +1798,13 @@ function SidebarWell({ expanded, children }) {
|
|
|
1780
1798
|
});
|
|
1781
1799
|
}
|
|
1782
1800
|
function SidebarJobs({ jobs, pathPrefix, preview, stepsOpen, toggleSteps, expandedSubworkflows, toggleSubworkflow, matrixOpen, toggleMatrix, openInNewGraph, setSublogOpen }) {
|
|
1783
|
-
const
|
|
1784
|
-
const
|
|
1801
|
+
const engine = useWorkflowEngine();
|
|
1802
|
+
const matrixGroups = useMemo(() => engine.matrixGroups(jobs), [engine, jobs]);
|
|
1803
|
+
const { displayJobs } = useMemo(() => computeGraphLayout(engine, jobs, matrixGroups), [
|
|
1804
|
+
engine,
|
|
1805
|
+
jobs,
|
|
1806
|
+
matrixGroups
|
|
1807
|
+
]);
|
|
1785
1808
|
const isStepsOpen = (j) => stepsOpen.has(pathPrefix + j);
|
|
1786
1809
|
const onJobClick = (j) => {
|
|
1787
1810
|
const status = jobs[j]?.status ?? displayJobs[j]?.status;
|
|
@@ -1794,9 +1817,9 @@ function SidebarJobs({ jobs, pathPrefix, preview, stepsOpen, toggleSteps, expand
|
|
|
1794
1817
|
const stepStatus = jobs[j]?.steps?.[+s]?.status;
|
|
1795
1818
|
if (stepStatus === "skipped" || stepStatus === "skipped-failed") return;
|
|
1796
1819
|
if (jobs[j]?.steps[+s]?.subworkflow) expandInline(j, +s);
|
|
1797
|
-
else setSublogOpen(
|
|
1820
|
+
else setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
|
|
1798
1821
|
};
|
|
1799
|
-
const onStepLogClick = (j, s) => setSublogOpen(
|
|
1822
|
+
const onStepLogClick = (j, s) => setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
|
|
1800
1823
|
const onSubworkflowIcon = (j, s) => openNew(j, s);
|
|
1801
1824
|
const isSubworkflowExpanded = (j, s) => expandedSubworkflows.has(`${pathPrefix}${j}:${s}`);
|
|
1802
1825
|
const renderSubworkflow = (j, s) => {
|
|
@@ -1823,13 +1846,14 @@ function SidebarJobs({ jobs, pathPrefix, preview, stepsOpen, toggleSteps, expand
|
|
|
1823
1846
|
});
|
|
1824
1847
|
};
|
|
1825
1848
|
const seenMatrixGroups = /* @__PURE__ */ new Set();
|
|
1826
|
-
|
|
1849
|
+
const orderedKeys = Object.keys(jobs).flatMap((jobName) => {
|
|
1827
1850
|
const originaljob = jobs[jobName]?._matrix?.originaljob;
|
|
1828
1851
|
if (!originaljob) return [jobName];
|
|
1829
1852
|
if (seenMatrixGroups.has(originaljob)) return [];
|
|
1830
1853
|
seenMatrixGroups.add(originaljob);
|
|
1831
1854
|
return [originaljob];
|
|
1832
|
-
})
|
|
1855
|
+
});
|
|
1856
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: orderedKeys.map((jobName) => {
|
|
1833
1857
|
const mg = displayJobs[jobName]?._matrixGroup;
|
|
1834
1858
|
if (mg) return /* @__PURE__ */ jsx(MatrixGroupSummaryItem, {
|
|
1835
1859
|
matrixGroup: mg,
|
|
@@ -1885,6 +1909,7 @@ function walkJobPath(root, path) {
|
|
|
1885
1909
|
return isJobRecord(cursor) ? cursor : {};
|
|
1886
1910
|
}
|
|
1887
1911
|
function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder, viewMode = "dag", setViewMode }) {
|
|
1912
|
+
const engine = useWorkflowEngine();
|
|
1888
1913
|
const animT = .125;
|
|
1889
1914
|
const minScale = .2;
|
|
1890
1915
|
const maxScale = .6;
|
|
@@ -2039,8 +2064,12 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
|
|
|
2039
2064
|
const sublogIsStep = jobAndStep.length > 1;
|
|
2040
2065
|
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]) : "";
|
|
2041
2066
|
const sublogIsSubworkflow = jobAndStep.length > 1 && jobs[jobAndStep[0]]?.steps[Number(jobAndStep[1])]?.subworkflow;
|
|
2042
|
-
const matrixGroups = useMemo(() =>
|
|
2043
|
-
const { dependencyCols } = useMemo(() => computeGraphLayout(jobs, matrixGroups), [
|
|
2067
|
+
const matrixGroups = useMemo(() => engine.matrixGroups(jobs), [engine, jobs]);
|
|
2068
|
+
const { dependencyCols } = useMemo(() => computeGraphLayout(engine, jobs, matrixGroups), [
|
|
2069
|
+
engine,
|
|
2070
|
+
jobs,
|
|
2071
|
+
matrixGroups
|
|
2072
|
+
]);
|
|
2044
2073
|
const fitGraph = useCallback((animationMs = 0) => {
|
|
2045
2074
|
const container = containerRef.current;
|
|
2046
2075
|
const content = graphContentRef.current;
|
|
@@ -2104,11 +2133,15 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
|
|
|
2104
2133
|
for (let i = 0; i < nestingDepth - 1; i++) parentPrefix += `subworkflows/${currentPath[5 * i]}/step_${currentPath[5 * i + 2]?.toString()}/`;
|
|
2105
2134
|
const lastJob = String(currentPath[5 * (nestingDepth - 1)] ?? "");
|
|
2106
2135
|
const lastStep = currentPath[5 * (nestingDepth - 1) + 2] ?? "";
|
|
2107
|
-
generalLogPath =
|
|
2136
|
+
generalLogPath = engine.stepLogPath(parentPrefix, lastJob, lastStep);
|
|
2108
2137
|
}
|
|
2109
2138
|
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;
|
|
2110
|
-
const currentSublog = sublogOpen === "" ? "" : preview ?
|
|
2111
|
-
const expansionKeys = useMemo(() =>
|
|
2139
|
+
const currentSublog = sublogOpen === "" ? "" : preview ? engine.toYaml(jobs[jobAndStep[0]]?.steps[Number(jobAndStep[1])]) : sublogsError || !sublogs ? missingLogText : sublogs;
|
|
2140
|
+
const expansionKeys = useMemo(() => engine.expansionKeys(jobs, pathAppend), [
|
|
2141
|
+
engine,
|
|
2142
|
+
jobs,
|
|
2143
|
+
pathAppend
|
|
2144
|
+
]);
|
|
2112
2145
|
const hasExpandable = expansionKeys.subworkflowKeys.length > 0 || expansionKeys.matrixKeys.length > 0;
|
|
2113
2146
|
const allExpanded = hasExpandable && expansionKeys.subworkflowKeys.every((k) => expandedSubworkflows.has(k)) && expansionKeys.matrixKeys.every((k) => matrixOpen.has(k));
|
|
2114
2147
|
const toggleExpandAll = () => {
|
|
@@ -2132,13 +2165,14 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
|
|
|
2132
2165
|
let step = parseInt(sublogSplit[sublogSplit.length - 2].slice(5), 10);
|
|
2133
2166
|
const jobArr = Object.keys(jobs);
|
|
2134
2167
|
let idx = jobArr.indexOf(job);
|
|
2135
|
-
if (backward)
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2168
|
+
if (backward) {
|
|
2169
|
+
if (0 < step) step -= 1;
|
|
2170
|
+
else {
|
|
2171
|
+
if (idx === 0) idx = jobArr.length;
|
|
2172
|
+
job = jobArr[idx - 1] ?? "";
|
|
2173
|
+
step = (jobs[job]?.steps.length ?? 0) - 1;
|
|
2174
|
+
}
|
|
2175
|
+
} else if ((jobs[job]?.steps.length ?? 0) - 1 > step) step += 1;
|
|
2142
2176
|
else {
|
|
2143
2177
|
if (idx === jobArr.length - 1) idx = -1;
|
|
2144
2178
|
job = jobArr[idx + 1] ?? "";
|
|
@@ -2181,8 +2215,9 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
|
|
|
2181
2215
|
]);
|
|
2182
2216
|
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;
|
|
2183
2217
|
const startDt = run.createdAt ? DateTime.fromISO(run.createdAt) : now;
|
|
2184
|
-
const
|
|
2185
|
-
const
|
|
2218
|
+
const endDt = run.completedAt ? DateTime.fromISO(run.completedAt) : now;
|
|
2219
|
+
const runtime = toAbsHumanDuration(startDt, endDt);
|
|
2220
|
+
const additionalBottomLeftBarComponents = sublogIsStep ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2186
2221
|
/* @__PURE__ */ jsxs("button", {
|
|
2187
2222
|
type: "button",
|
|
2188
2223
|
className: "btn btn-neutral",
|
|
@@ -2222,7 +2257,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
|
|
|
2222
2257
|
children: slots.runSessions({
|
|
2223
2258
|
runId: run.id ?? "",
|
|
2224
2259
|
runNumber,
|
|
2225
|
-
runActive: isRunActive(run.status),
|
|
2260
|
+
runActive: engine.isRunActive(run.status),
|
|
2226
2261
|
links: run.links
|
|
2227
2262
|
})
|
|
2228
2263
|
}),
|
|
@@ -2348,7 +2383,7 @@ function DependencyGraph({ run, preview = false, initialScale = 1, removeBorder,
|
|
|
2348
2383
|
onTransform: invalidateConnectors,
|
|
2349
2384
|
onWheel: invalidateConnectors,
|
|
2350
2385
|
onZoom: invalidateConnectors,
|
|
2351
|
-
children: () => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
2386
|
+
children: () => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
2352
2387
|
className: "absolute z-10 top-2 right-2 flex flex-col items-end gap-y-1",
|
|
2353
2388
|
children: [
|
|
2354
2389
|
hasExpandable && /* @__PURE__ */ jsx("button", {
|