@parallelworks/ui 0.62.0 → 0.64.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/dist/components/Avatar.js +3 -3
- package/dist/components/Card.d.ts +2 -0
- package/dist/components/Card.js +2 -2
- package/dist/components/Drawer.js +1 -1
- package/dist/components/Field.js +3 -3
- package/dist/components/Modal.js +3 -3
- package/dist/components/OneTimeCodeInput.js +1 -1
- package/dist/components/PageHeader.js +1 -1
- package/dist/components/Provider.d.ts +2 -0
- package/dist/components/Provider.js +2 -1
- package/dist/components/Section.js +5 -5
- package/dist/components/SettingModeOption.js +1 -1
- package/dist/components/SettingsCard.js +4 -4
- package/dist/components/Table.js +1 -1
- package/dist/components/dismiss.d.ts +1 -1
- package/dist/components/dismiss.js +1 -1
- package/dist/components/fieldBox.js +3 -3
- package/dist/graph/DependencyGraph.d.ts +1 -4
- package/dist/graph/DependencyGraph.js +24 -17
- package/dist/graph/JobSummary.d.ts +1 -0
- package/dist/graph/JobSummary.js +46 -40
- package/dist/graph/StepSummaries.d.ts +22 -0
- package/dist/graph/StepSummaries.js +184 -0
- package/dist/list/listSearch.js +1 -1
- package/dist/styles/theme.css +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -6,8 +6,8 @@ import { Avatar } from "@base-ui/react/avatar";
|
|
|
6
6
|
//#region src/components/Avatar.tsx
|
|
7
7
|
var SIZE_CLASSES = {
|
|
8
8
|
xs: "size-4 text-[9px]",
|
|
9
|
-
sm: "size-
|
|
10
|
-
md: "size-
|
|
9
|
+
sm: "size-5 text-[9px]",
|
|
10
|
+
md: "size-7 text-xs",
|
|
11
11
|
lg: "size-10 text-base",
|
|
12
12
|
xl: "size-12 text-lg",
|
|
13
13
|
"2xl": "size-16 text-xl"
|
|
@@ -58,7 +58,7 @@ function Avatar$1({ src, name, colorKey, size = "md", status, className }) {
|
|
|
58
58
|
})]
|
|
59
59
|
}), status && /* @__PURE__ */ jsx("span", {
|
|
60
60
|
"data-testid": "online-indicator",
|
|
61
|
-
className: cx("absolute right-0 bottom-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "xs" || size === "sm" ? "size-1.5" : "size-2.5")
|
|
61
|
+
className: cx("absolute right-0 bottom-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "xs" || size === "sm" ? "size-1.5" : size === "md" ? "size-2" : "size-2.5")
|
|
62
62
|
})]
|
|
63
63
|
});
|
|
64
64
|
}
|
|
@@ -25,6 +25,8 @@ export interface CardHeaderProps {
|
|
|
25
25
|
title: string;
|
|
26
26
|
description?: ReactNode;
|
|
27
27
|
className?: string;
|
|
28
|
+
/** `left` starts the title on the same edge as the labels and fields under it; `center`
|
|
29
|
+
* suits a card whose content is centred too. */
|
|
28
30
|
align?: 'center' | 'left';
|
|
29
31
|
/** The title's level in the page's outline: 1 for a card that is the page, such
|
|
30
32
|
* as sign-in; 2 or 3 for a card among others under the page's own title. */
|
package/dist/components/Card.js
CHANGED
|
@@ -19,12 +19,12 @@ function Card({ children, size = "md", elevated = false, render: renderProp, hre
|
|
|
19
19
|
return useRender({
|
|
20
20
|
render: render ?? /* @__PURE__ */ jsx("div", {}),
|
|
21
21
|
props: {
|
|
22
|
-
className: cx("block w-full rounded-
|
|
22
|
+
className: cx("block w-full rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) backdrop-blur-xl", elevated ? "shadow-(--theme-shadow-xl)" : "shadow-(--theme-shadow)", sizeClasses[size], render && "cursor-pointer text-left text-inherit no-underline transition-[background-color,box-shadow] duration-150 hover:bg-(--theme-panel-hover) hover:shadow-(--theme-shadow-lg) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-link) motion-reduce:transition-none", className),
|
|
23
23
|
children
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
function CardHeader({ badge, title, description, className = "", align = "
|
|
27
|
+
function CardHeader({ badge, title, description, className = "", align = "left", headingLevel = 1 }) {
|
|
28
28
|
const Heading = `h${headingLevel}`;
|
|
29
29
|
return /* @__PURE__ */ jsxs("div", {
|
|
30
30
|
className: cx(align === "center" ? "text-center" : "text-left", "mb-6", className),
|
|
@@ -92,7 +92,7 @@ function Drawer$1({ open, onClose, title, description, onBack, backLabel, footer
|
|
|
92
92
|
children
|
|
93
93
|
}),
|
|
94
94
|
footer && /* @__PURE__ */ jsx("div", {
|
|
95
|
-
className: cx("flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-
|
|
95
|
+
className: cx("flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3", "px-4"),
|
|
96
96
|
children: footer
|
|
97
97
|
})
|
|
98
98
|
]
|
package/dist/components/Field.js
CHANGED
|
@@ -42,9 +42,9 @@ var labelSizes = {
|
|
|
42
42
|
},
|
|
43
43
|
md: {
|
|
44
44
|
text: "text-sm text-(--theme-app)",
|
|
45
|
-
inlineHeight: "min-h-
|
|
45
|
+
inlineHeight: "min-h-8",
|
|
46
46
|
stackGap: "gap-1.5",
|
|
47
|
-
inlineLine: "py-
|
|
47
|
+
inlineLine: "py-1.5"
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
var labelClassName = "flex items-center gap-1 font-medium";
|
|
@@ -295,7 +295,7 @@ function FieldValue({ size = "md", className, children, ...props }) {
|
|
|
295
295
|
"aria-labelledby": control?.["aria-labelledby"],
|
|
296
296
|
"aria-describedby": control?.["aria-describedby"],
|
|
297
297
|
...props,
|
|
298
|
-
className: cx("flex min-w-0 items-center break-words text-(--theme-app)", size === "sm" ? "min-h-7 text-xs" : "min-h-
|
|
298
|
+
className: cx("flex min-w-0 items-center break-words text-(--theme-app)", size === "sm" ? "min-h-7 text-xs" : "min-h-8 text-sm", className),
|
|
299
299
|
children
|
|
300
300
|
});
|
|
301
301
|
}
|
package/dist/components/Modal.js
CHANGED
|
@@ -36,7 +36,7 @@ function Modal({ open, onClose, title, description, footer, size, alert = false,
|
|
|
36
36
|
className: cx(panel && "rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-2xl", size && [sizeClasses[size], "max-w-full"], laidOut && "flex max-h-full flex-col", "outline-none", className),
|
|
37
37
|
children: laidOut ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38
38
|
header && /* @__PURE__ */ jsxs("div", {
|
|
39
|
-
className: cx("shrink-0 px-
|
|
39
|
+
className: cx("shrink-0 px-4 pt-4", !body && "pb-4"),
|
|
40
40
|
children: [title !== void 0 && /* @__PURE__ */ jsx(ModalTitle, {
|
|
41
41
|
className: "m-0 text-lg font-semibold",
|
|
42
42
|
children: title
|
|
@@ -46,11 +46,11 @@ function Modal({ open, onClose, title, description, footer, size, alert = false,
|
|
|
46
46
|
})]
|
|
47
47
|
}),
|
|
48
48
|
body && /* @__PURE__ */ jsx("div", {
|
|
49
|
-
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-
|
|
49
|
+
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-4",
|
|
50
50
|
children
|
|
51
51
|
}),
|
|
52
52
|
footer !== void 0 && /* @__PURE__ */ jsx("div", {
|
|
53
|
-
className: "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-
|
|
53
|
+
className: "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3",
|
|
54
54
|
children: footer
|
|
55
55
|
})
|
|
56
56
|
] }) : children
|
|
@@ -32,7 +32,7 @@ function OneTimeCodeInput({ length = 6, size = "md", className, "aria-label": ar
|
|
|
32
32
|
...ariaInvalid && { "aria-invalid": true },
|
|
33
33
|
...ariaRequired && { "aria-required": true },
|
|
34
34
|
autoFocus: autoFocus && index === 0,
|
|
35
|
-
className: cx(fieldBox({ size }), "px-0 text-center font-mono tabular-nums", size === "sm" ? "w-7" : "w-
|
|
35
|
+
className: cx(fieldBox({ size }), "px-0 text-center font-mono tabular-nums", size === "sm" ? "w-7" : "w-8 text-base")
|
|
36
36
|
}, index))]
|
|
37
37
|
});
|
|
38
38
|
}
|
|
@@ -135,7 +135,7 @@ function HeaderLayout({ breadcrumbs, titleActions, actions, toolbar, compact = f
|
|
|
135
135
|
return /* @__PURE__ */ jsxs("div", {
|
|
136
136
|
className: cx("@container w-full shrink-0 bg-(--theme-app-bg)", className),
|
|
137
137
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
138
|
-
className: cx("flex items-center justify-between gap-4 border-b border-(--theme-border) px-4", compact ? "h-8" : "h-
|
|
138
|
+
className: cx("flex items-center justify-between gap-4 border-b border-(--theme-border) px-4", compact ? "h-8" : "h-12"),
|
|
139
139
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
140
140
|
className: "flex min-w-0 flex-1 items-center gap-2",
|
|
141
141
|
children: [
|
|
@@ -234,6 +234,8 @@ export interface UIStrings {
|
|
|
234
234
|
stepOf: (position: number, count: number) => string;
|
|
235
235
|
summaryLoadFailed: string;
|
|
236
236
|
summaryTab: string;
|
|
237
|
+
/** Names the cards under the graph, one for each step that wrote a summary. */
|
|
238
|
+
stepSummaries: string;
|
|
237
239
|
logsTab: string;
|
|
238
240
|
scriptTab: string;
|
|
239
241
|
openSubworkflow: string;
|
|
@@ -239,10 +239,11 @@ var DEFAULTS = {
|
|
|
239
239
|
noLogFound: "No log found",
|
|
240
240
|
logLoadFailed: "Log could not be loaded",
|
|
241
241
|
loadingSummary: "Loading summary",
|
|
242
|
-
hasSummary: "
|
|
242
|
+
hasSummary: "Step summary",
|
|
243
243
|
stepOf: (position, count) => `Step ${position} of ${count}`,
|
|
244
244
|
summaryLoadFailed: "Summary could not be loaded",
|
|
245
245
|
summaryTab: "Summary",
|
|
246
|
+
stepSummaries: "Step summaries",
|
|
246
247
|
logsTab: "Logs",
|
|
247
248
|
scriptTab: "Script",
|
|
248
249
|
openSubworkflow: "Open Subworkflow",
|
|
@@ -10,13 +10,13 @@ var rootClasses = {
|
|
|
10
10
|
card: "panel mb-1 flex w-full flex-col"
|
|
11
11
|
};
|
|
12
12
|
var headerClasses = {
|
|
13
|
-
plain: "mb-
|
|
14
|
-
card: "flex w-full items-center gap-2
|
|
13
|
+
plain: "mb-4 flex w-full items-center gap-2 border-b border-(--theme-border) pb-1",
|
|
14
|
+
card: "flex w-full items-center gap-2 p-4"
|
|
15
15
|
};
|
|
16
|
-
var cardBodyClassName = "px-
|
|
16
|
+
var cardBodyClassName = "px-4 pb-4";
|
|
17
17
|
var titleClasses = {
|
|
18
|
-
plain: "text-
|
|
19
|
-
card: "text-
|
|
18
|
+
plain: "text-base font-semibold",
|
|
19
|
+
card: "text-base font-semibold"
|
|
20
20
|
};
|
|
21
21
|
var foldedTitleClasses = {
|
|
22
22
|
plain: "",
|
|
@@ -8,7 +8,7 @@ import { useId } from "react";
|
|
|
8
8
|
function SettingModeOption({ value, label, description, disabled }) {
|
|
9
9
|
const id = useId();
|
|
10
10
|
return /* @__PURE__ */ jsxs("label", {
|
|
11
|
-
className: cx("flex items-start gap-3
|
|
11
|
+
className: cx("flex items-start gap-3 p-4", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", "border-t border-(--theme-border) first:border-t-0"),
|
|
12
12
|
children: [/* @__PURE__ */ jsx(Radio, {
|
|
13
13
|
value,
|
|
14
14
|
disabled,
|
|
@@ -12,11 +12,11 @@ function SettingsCard({ title, description, action, actionAlign = "beside", head
|
|
|
12
12
|
children: /* @__PURE__ */ jsxs("section", {
|
|
13
13
|
className: cx("mt-10 first:mt-0", className),
|
|
14
14
|
children: [(title || action) && /* @__PURE__ */ jsxs("div", {
|
|
15
|
-
className: "mb-
|
|
15
|
+
className: "mb-4 px-0.5",
|
|
16
16
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
17
17
|
className: cx("flex items-center gap-1.5", actionAlign === "end" && "justify-between"),
|
|
18
18
|
children: [title && /* @__PURE__ */ jsx(Heading, {
|
|
19
|
-
className: "text-
|
|
19
|
+
className: "text-base leading-none font-semibold theme-text",
|
|
20
20
|
children: title
|
|
21
21
|
}), action]
|
|
22
22
|
}), description && /* @__PURE__ */ jsx("p", {
|
|
@@ -34,7 +34,7 @@ function SettingsCard({ title, description, action, actionAlign = "beside", head
|
|
|
34
34
|
function SettingsHeading({ children }) {
|
|
35
35
|
const Heading = `h${useContext(HeadingLevel)}`;
|
|
36
36
|
return /* @__PURE__ */ jsx(Heading, {
|
|
37
|
-
className: "px-
|
|
37
|
+
className: "px-4 py-3 text-sm font-semibold tracking-wider uppercase theme-muted-panel theme-muted-text",
|
|
38
38
|
children
|
|
39
39
|
});
|
|
40
40
|
}
|
|
@@ -44,7 +44,7 @@ function SettingRow({ label, htmlFor, helpText, fill = false, onClick, children
|
|
|
44
44
|
return /* @__PURE__ */ jsxs("div", {
|
|
45
45
|
role: "none",
|
|
46
46
|
onClick,
|
|
47
|
-
className: cx("grid grid-cols-1 gap-x-8 gap-y-2
|
|
47
|
+
className: cx("grid grid-cols-1 gap-x-8 gap-y-2 p-4", fill ? "md:grid-cols-[200px_1fr]" : "md:grid-cols-[1fr_auto]", onClick && "cursor-pointer transition-colors select-none hover:theme-hover"),
|
|
48
48
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
49
49
|
className: "flex flex-col gap-y-1",
|
|
50
50
|
children: [/* @__PURE__ */ jsx("label", {
|
package/dist/components/Table.js
CHANGED
|
@@ -60,7 +60,7 @@ function Table({ density = "comfortable", borderless = false, panel = true, clas
|
|
|
60
60
|
className: "flex h-32 items-center justify-center",
|
|
61
61
|
children: /* @__PURE__ */ jsx(Loader, {})
|
|
62
62
|
}) : /* @__PURE__ */ jsx("div", {
|
|
63
|
-
className: cx("inline-block min-w-full align-middle", !stickyHeader && "overflow-x-auto", panel && "theme-panel", !borderless && "border theme-border", rounded && "rounded-
|
|
63
|
+
className: cx("inline-block min-w-full align-middle", !stickyHeader && "overflow-x-auto", panel && "theme-panel", !borderless && "border theme-border", rounded && "rounded-xl", roundedBottom && "rounded-b-xl", roundedTop && "rounded-t-xl"),
|
|
64
64
|
children: /* @__PURE__ */ jsxs("table", {
|
|
65
65
|
className: cx("min-w-full divide-y theme-border", className),
|
|
66
66
|
...tableProps,
|
|
@@ -8,5 +8,5 @@ interface CloseDetails {
|
|
|
8
8
|
* press on a toast never does, since the toast sits above the backdrop. */
|
|
9
9
|
export declare function closeHandler(dismissible: boolean, onClose: () => void): (next: boolean, details: CloseDetails) => void;
|
|
10
10
|
/** The row of a dialog's actions along its bottom edge, ruled off from its body. */
|
|
11
|
-
export declare const dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-
|
|
11
|
+
export declare const dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3";
|
|
12
12
|
export {};
|
|
@@ -14,6 +14,6 @@ function closeHandler(dismissible, onClose) {
|
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
/** The row of a dialog's actions along its bottom edge, ruled off from its body. */
|
|
17
|
-
var dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-
|
|
17
|
+
var dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3";
|
|
18
18
|
//#endregion
|
|
19
19
|
export { closeHandler, dialogFooterClassName };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
1
|
import type { GraphLayout } from '../editing.js';
|
|
3
2
|
import type { DependencyGraphEditor } from './editorApi.js';
|
|
4
3
|
import { type RunLink, type WorkflowJob } from './types.js';
|
|
@@ -18,7 +17,7 @@ interface GraphRun {
|
|
|
18
17
|
executedJobs?: Record<string, unknown> | undefined;
|
|
19
18
|
links?: Record<string, RunLink> | undefined;
|
|
20
19
|
}
|
|
21
|
-
export default function DependencyGraph({ run, preview, removeBorder, viewMode, setViewMode, layout, editor, yamlJobs, inputs, workflow, fixedHeight, openStep, onCloseLog, sidebarStickyTop,
|
|
20
|
+
export default function DependencyGraph({ run, preview, removeBorder, viewMode, setViewMode, layout, editor, yamlJobs, inputs, workflow, fixedHeight, openStep, onCloseLog, sidebarStickyTop, }: {
|
|
22
21
|
run: GraphRun;
|
|
23
22
|
preview?: boolean;
|
|
24
23
|
removeBorder?: boolean | undefined;
|
|
@@ -41,8 +40,6 @@ export default function DependencyGraph({ run, preview, removeBorder, viewMode,
|
|
|
41
40
|
onCloseLog?: (() => void) | undefined;
|
|
42
41
|
/** Pins the job list this many pixels below the top of the page's scroll area, under the host's own pinned bars. */
|
|
43
42
|
sidebarStickyTop?: number | undefined;
|
|
44
|
-
/** Shown under the annotations, above the graph. */
|
|
45
|
-
children?: ReactNode;
|
|
46
43
|
}): import("react").JSX.Element | undefined;
|
|
47
44
|
export declare function DependencyGraphPreview(inputs: {
|
|
48
45
|
yml?: Record<string, unknown>;
|
|
@@ -28,6 +28,7 @@ import { routeConnectors, sameBoxes } from "./connectorGeometry.js";
|
|
|
28
28
|
import { isJobRecord } from "./types.js";
|
|
29
29
|
import { computeGraphLayout, displayJobsOf, hopDistances, positionsOf } from "./graphLayout.js";
|
|
30
30
|
import { MatrixGroupNode, MatrixGroupSummaryItem } from "./MatrixGroup.js";
|
|
31
|
+
import { StepSummaries } from "./StepSummaries.js";
|
|
31
32
|
import { StepSummary } from "./StepSummary.js";
|
|
32
33
|
import TreeView from "./TreeView.js";
|
|
33
34
|
import { FIT_MAX_SCALE, MIN_SCALE, ZOOM_STEP, fitMargin, fitView, intoView, wheelFactor, zoomAround, zoomLimit } from "./viewport.js";
|
|
@@ -166,12 +167,12 @@ var addCleanupSteps = ({ jobs }) => {
|
|
|
166
167
|
}
|
|
167
168
|
return clonedJobs;
|
|
168
169
|
};
|
|
169
|
-
var
|
|
170
|
+
var FIT_PADDING = 24;
|
|
170
171
|
function outerNodes(content) {
|
|
171
172
|
const top = content.querySelectorAll(":scope > div > div > div > div[id^=\"node_\"]");
|
|
172
173
|
return top.length > 0 ? top : content.querySelectorAll("[id^=\"node_\"]");
|
|
173
174
|
}
|
|
174
|
-
function
|
|
175
|
+
function measureFitHeight(content, viewRef) {
|
|
175
176
|
const nodes = content ? outerNodes(content) : void 0;
|
|
176
177
|
const transform = content?.parentElement ? getComputedStyle(content.parentElement).transform : "none";
|
|
177
178
|
if (!content || !nodes?.length || transform === "none") return null;
|
|
@@ -185,7 +186,7 @@ function measurePreviewHeight(content, viewRef) {
|
|
|
185
186
|
const { scale, offsetY } = viewRef.current;
|
|
186
187
|
let bottom = 0;
|
|
187
188
|
for (const node of nodes) bottom = Math.max(bottom, offsetWithin(node, content).y + node.offsetHeight);
|
|
188
|
-
return Math.ceil(bottom * scale + offsetY +
|
|
189
|
+
return Math.ceil(bottom * scale + offsetY + FIT_PADDING);
|
|
189
190
|
}
|
|
190
191
|
function offsetWithin(el, ancestor) {
|
|
191
192
|
let x = 0;
|
|
@@ -220,6 +221,7 @@ function jobHandlers({ engine, jobs, displayJobs, pathPrefix, stepsOpen, toggleS
|
|
|
220
221
|
const isStepsOpen = (j) => stepsOpen.has(pathPrefix + j);
|
|
221
222
|
const subworkflowKey = (j, s) => `${pathPrefix}${j}:${s}`;
|
|
222
223
|
const openLog = (j, s) => setSublogOpen(engine.stepLogPath(pathPrefix, j, s));
|
|
224
|
+
const openSummary = (j, s) => setSublogOpen(fileBeside(engine.stepLogPath(pathPrefix, j, s), "summary.md"));
|
|
223
225
|
return {
|
|
224
226
|
isStepsOpen,
|
|
225
227
|
onJobClick: (j) => {
|
|
@@ -238,6 +240,7 @@ function jobHandlers({ engine, jobs, displayJobs, pathPrefix, stepsOpen, toggleS
|
|
|
238
240
|
else openLog(j, s);
|
|
239
241
|
},
|
|
240
242
|
onStepLogClick: openLog,
|
|
243
|
+
onStepSummaryClick: openSummary,
|
|
241
244
|
onSubworkflowIcon: (j, s) => openInNewGraph(pathPrefix, j, s),
|
|
242
245
|
renderSubworkflow: (j, s) => {
|
|
243
246
|
const subJobs = jobs[j]?.steps?.[s]?.subworkflow?.jobs;
|
|
@@ -696,7 +699,7 @@ function graphBounds(content) {
|
|
|
696
699
|
}
|
|
697
700
|
return bounds;
|
|
698
701
|
}
|
|
699
|
-
function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag", setViewMode, layout, editor, yamlJobs, inputs, workflow, fixedHeight, openStep, onCloseLog, sidebarStickyTop
|
|
702
|
+
function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag", setViewMode, layout, editor, yamlJobs, inputs, workflow, fixedHeight, openStep, onCloseLog, sidebarStickyTop }) {
|
|
700
703
|
const engine = useWorkflowEngine();
|
|
701
704
|
const animT = .125;
|
|
702
705
|
const rootJobs = isJobRecord(run.executedJobs) ? run.executedJobs : {};
|
|
@@ -750,23 +753,24 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
750
753
|
}
|
|
751
754
|
}, [preview]);
|
|
752
755
|
const containerHeight = topOffset !== null ? Math.max(windowSize.h - topOffset - 16, 160) : null;
|
|
753
|
-
const [
|
|
754
|
-
const
|
|
756
|
+
const [fitHeight, setFitHeight] = useState(null);
|
|
757
|
+
const fitViewRef = useRef(null);
|
|
755
758
|
useEffect(() => {
|
|
756
|
-
const container =
|
|
757
|
-
|
|
759
|
+
const container = containerEl;
|
|
760
|
+
fitViewRef.current = null;
|
|
761
|
+
if (!container || fixedHeight) return;
|
|
758
762
|
let raf = 0;
|
|
759
763
|
let attempts = 0;
|
|
760
764
|
const measure = () => {
|
|
761
765
|
cancelAnimationFrame(raf);
|
|
762
766
|
raf = requestAnimationFrame(() => {
|
|
763
|
-
const next =
|
|
767
|
+
const next = measureFitHeight(graphContentRef.current, fitViewRef);
|
|
764
768
|
if (next === null) {
|
|
765
769
|
if (attempts++ < 120) measure();
|
|
766
770
|
return;
|
|
767
771
|
}
|
|
768
772
|
attempts = 0;
|
|
769
|
-
|
|
773
|
+
setFitHeight((prev) => prev === next ? prev : next);
|
|
770
774
|
});
|
|
771
775
|
};
|
|
772
776
|
measure();
|
|
@@ -779,7 +783,7 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
779
783
|
observer.disconnect();
|
|
780
784
|
cancelAnimationFrame(raf);
|
|
781
785
|
};
|
|
782
|
-
}, [
|
|
786
|
+
}, [containerEl, fixedHeight]);
|
|
783
787
|
const { common, dag: dagStrings } = useStrings();
|
|
784
788
|
const stepHeaderRef = useRef(null);
|
|
785
789
|
const slots = useSlots();
|
|
@@ -959,8 +963,8 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
959
963
|
await Promise.allSettled(running.map((transition) => transition.finished));
|
|
960
964
|
running = sizingTransitions(content);
|
|
961
965
|
}
|
|
962
|
-
const panelHeight =
|
|
963
|
-
if (panelHeight !== null) flushSync(() =>
|
|
966
|
+
const panelHeight = fixedHeight ? null : measureFitHeight(content, fitViewRef);
|
|
967
|
+
if (panelHeight !== null) flushSync(() => setFitHeight(panelHeight));
|
|
964
968
|
await sizesSettled([
|
|
965
969
|
container,
|
|
966
970
|
content,
|
|
@@ -971,7 +975,6 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
971
975
|
}, [
|
|
972
976
|
fitGraph,
|
|
973
977
|
invalidateConnectors,
|
|
974
|
-
preview,
|
|
975
978
|
fixedHeight
|
|
976
979
|
]);
|
|
977
980
|
const centerOn = useCallback((el) => {
|
|
@@ -1361,7 +1364,6 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
1361
1364
|
]
|
|
1362
1365
|
}),
|
|
1363
1366
|
!preview && /* @__PURE__ */ jsx(AnnotationBanner, { executedJobs: jobs }),
|
|
1364
|
-
children,
|
|
1365
1367
|
viewMode === "tree" && !preview ? /* @__PURE__ */ jsx("div", {
|
|
1366
1368
|
className: "panel w-full border",
|
|
1367
1369
|
children: /* @__PURE__ */ jsx(TreeView, {
|
|
@@ -1375,8 +1377,8 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
1375
1377
|
tabIndex: editor ? -1 : void 0,
|
|
1376
1378
|
className: cx("panel w-full overflow-hidden relative", removeBorder ? "border-none" : "border", editor && "outline-none"),
|
|
1377
1379
|
style: {
|
|
1378
|
-
height: fixedHeight ?? (
|
|
1379
|
-
minHeight:
|
|
1380
|
+
height: fixedHeight ?? (fitHeight !== null ? `${Math.min(fitHeight, containerHeight ?? windowSize.h * .62)}px` : containerHeight !== null ? `${containerHeight}px` : "62vh"),
|
|
1381
|
+
minHeight: preview && fitHeight !== null && !fixedHeight ? 0 : 160
|
|
1380
1382
|
},
|
|
1381
1383
|
children: [/* @__PURE__ */ jsx(TransformWrapper, {
|
|
1382
1384
|
ref: transformRef,
|
|
@@ -1444,6 +1446,11 @@ function DependencyGraph({ run, preview = false, removeBorder, viewMode = "dag",
|
|
|
1444
1446
|
})
|
|
1445
1447
|
}) })] })
|
|
1446
1448
|
}), editorOverlays]
|
|
1449
|
+
}),
|
|
1450
|
+
!preview && /* @__PURE__ */ jsx(StepSummaries, {
|
|
1451
|
+
runSlug,
|
|
1452
|
+
jobs: rootJobs,
|
|
1453
|
+
onOpenLog: ({ prefix, job, index }) => setSublogOpen(engine.stepLogPath(prefix, job, index))
|
|
1447
1454
|
})
|
|
1448
1455
|
]
|
|
1449
1456
|
}),
|
|
@@ -6,6 +6,7 @@ export interface JobHandlers {
|
|
|
6
6
|
onJobClick: (jobName: string) => void;
|
|
7
7
|
onStepClick: (jobName: string, stepIndex: number) => void;
|
|
8
8
|
onStepLogClick: (jobName: string, stepIndex: number) => void;
|
|
9
|
+
onStepSummaryClick: (jobName: string, stepIndex: number) => void;
|
|
9
10
|
onSubworkflowIcon: (jobName: string, stepIndex: number) => void;
|
|
10
11
|
renderSubworkflow: (jobName: string, stepIndex: number) => ReactNode;
|
|
11
12
|
}
|
package/dist/graph/JobSummary.js
CHANGED
|
@@ -68,57 +68,63 @@ function Joblist(inputs) {
|
|
|
68
68
|
onClick: () => inputs.onStepClick(jobName, i),
|
|
69
69
|
className: cx(inputs.preview ? "ml-1.5" : "ml-4", "gap-x-1.5 flex items-center text-left"),
|
|
70
70
|
"data-testid": stepLabel,
|
|
71
|
-
children: [
|
|
72
|
-
inputs.preview ? "↳" : /* @__PURE__ */ jsx(RunStatusIcon, { status: step.status }),
|
|
73
|
-
/* @__PURE__ */ jsx("div", { children: stepLabel }),
|
|
74
|
-
step.summary && !inputs.preview && /* @__PURE__ */ jsx(Tooltip, {
|
|
75
|
-
content: dag.hasSummary,
|
|
76
|
-
children: /* @__PURE__ */ jsx(SummaryIcon, {
|
|
77
|
-
"aria-label": dag.hasSummary,
|
|
78
|
-
className: "w-[1.1em] h-[1.1em] shrink-0 text-(--theme-muted-text-color)"
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
]
|
|
71
|
+
children: [inputs.preview ? "↳" : /* @__PURE__ */ jsx(RunStatusIcon, { status: step.status }), /* @__PURE__ */ jsx("div", { children: stepLabel })]
|
|
82
72
|
});
|
|
83
73
|
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
84
74
|
className: cx("flex items-center", step.status === "skipped" || step.status === "skipped-failed" ? "cursor-default" : "cursor-pointer"),
|
|
85
|
-
children: [
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
75
|
+
children: [
|
|
76
|
+
(inputs.editable || inputs.editableSteps) && !step.linkedStep ? /* @__PURE__ */ jsx(EditableStepRow, {
|
|
77
|
+
job: job?._matrix?.originaljob ?? jobName,
|
|
78
|
+
index: i,
|
|
79
|
+
label: stepLabel,
|
|
80
|
+
children: stepButton
|
|
81
|
+
}) : stepButton,
|
|
82
|
+
step.summary && !inputs.preview && /* @__PURE__ */ jsx(Tooltip, {
|
|
83
|
+
content: dag.hasSummary,
|
|
93
84
|
children: /* @__PURE__ */ jsx("button", {
|
|
94
85
|
type: "button",
|
|
95
|
-
"aria-label":
|
|
86
|
+
"aria-label": dag.hasSummary,
|
|
96
87
|
onClick: (e) => {
|
|
97
88
|
e.stopPropagation();
|
|
98
|
-
inputs.
|
|
89
|
+
inputs.onStepSummaryClick(jobName, i);
|
|
99
90
|
},
|
|
100
|
-
className: "
|
|
101
|
-
children: /* @__PURE__ */ jsx(
|
|
91
|
+
className: "ml-1.5 shrink-0 text-(--theme-muted-text-color) hover:text-(--theme-link)",
|
|
92
|
+
children: /* @__PURE__ */ jsx(SummaryIcon, { className: "w-[1.1em] h-[1.1em]" })
|
|
102
93
|
})
|
|
103
94
|
}),
|
|
104
|
-
/* @__PURE__ */
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
95
|
+
step.subworkflow && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
96
|
+
/* @__PURE__ */ jsx(Tooltip, {
|
|
97
|
+
content: jobActions.openSubworkflowLogs,
|
|
98
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
99
|
+
type: "button",
|
|
100
|
+
"aria-label": jobActions.openSubworkflowLogs,
|
|
101
|
+
onClick: (e) => {
|
|
102
|
+
e.stopPropagation();
|
|
103
|
+
inputs.onStepLogClick(jobName, i);
|
|
104
|
+
},
|
|
105
|
+
className: "link ml-1",
|
|
106
|
+
children: /* @__PURE__ */ jsx(FileTextIcon, { className: "w-[1.2em] h-[1.2em]" })
|
|
107
|
+
})
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ jsx(UsesIcon, {
|
|
110
|
+
uses: step.uses,
|
|
111
|
+
subworkflow: step.subworkflow
|
|
112
|
+
}),
|
|
113
|
+
/* @__PURE__ */ jsx(Tooltip, {
|
|
114
|
+
content: jobActions.openInNewGraph,
|
|
115
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
116
|
+
type: "button",
|
|
117
|
+
"aria-label": jobActions.openInNewGraph,
|
|
118
|
+
onClick: (e) => {
|
|
119
|
+
e.stopPropagation();
|
|
120
|
+
inputs.onSubworkflowIcon(jobName, i);
|
|
121
|
+
},
|
|
122
|
+
className: "link ml-1",
|
|
123
|
+
children: /* @__PURE__ */ jsx(OpenInNewGraphIcon, { className: "w-[1.2em] h-[1.2em]" })
|
|
124
|
+
})
|
|
119
125
|
})
|
|
120
|
-
})
|
|
121
|
-
]
|
|
126
|
+
] })
|
|
127
|
+
]
|
|
122
128
|
}), canExpand && inputs.renderSubworkflow(jobName, i)] }, stepKey);
|
|
123
129
|
}), inputs.editable && /* @__PURE__ */ jsx(AddStepButton, { job: jobName })]
|
|
124
130
|
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WorkflowJob, WorkflowStep } from './types.js';
|
|
2
|
+
export interface StepSummarySource {
|
|
3
|
+
/** The `subworkflows/<job>/step_<n>/` chain of a step inside a subworkflow; empty at the top level. */
|
|
4
|
+
prefix: string;
|
|
5
|
+
job: string;
|
|
6
|
+
/** The job's name, after the names of the jobs whose subworkflows it runs in. */
|
|
7
|
+
jobNames: string[];
|
|
8
|
+
index: number;
|
|
9
|
+
step: WorkflowStep;
|
|
10
|
+
}
|
|
11
|
+
/** The steps, subworkflows' included, that wrote a summary, in the order their jobs completed. */
|
|
12
|
+
export declare function stepSummarySources(jobs: Record<string, WorkflowJob>): StepSummarySource[];
|
|
13
|
+
/**
|
|
14
|
+
* A run's step summaries, each on its own card headed by the job and step that wrote it, so a run
|
|
15
|
+
* reads like a report under its graph. The job list beside the graph already shows the run's tree,
|
|
16
|
+
* so the cards are flat.
|
|
17
|
+
*/
|
|
18
|
+
export declare function StepSummaries({ runSlug, jobs, onOpenLog, }: {
|
|
19
|
+
runSlug: string;
|
|
20
|
+
jobs: Record<string, WorkflowJob>;
|
|
21
|
+
onOpenLog: (source: StepSummarySource) => void;
|
|
22
|
+
}): import("react").JSX.Element | null;
|