@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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { FileTextIcon } from "../icons.js";
|
|
3
|
+
import { useRunFile, useStrings, useWorkflowEngine } from "../components/Provider.js";
|
|
4
|
+
import Markdown from "../components/Markdown.js";
|
|
5
|
+
import { RunStatusIcon } from "../components/RunStatusIcon.js";
|
|
6
|
+
import { jobLabel } from "./util.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
9
|
+
//#region src/graph/StepSummaries.tsx
|
|
10
|
+
var SEPARATOR = " › ";
|
|
11
|
+
function completion(job) {
|
|
12
|
+
const millis = job.completedAt ? Date.parse(job.completedAt) : NaN;
|
|
13
|
+
return Number.isNaN(millis) ? Number.POSITIVE_INFINITY : millis;
|
|
14
|
+
}
|
|
15
|
+
/** The steps, subworkflows' included, that wrote a summary, in the order their jobs completed. */
|
|
16
|
+
function stepSummarySources(jobs) {
|
|
17
|
+
const found = [];
|
|
18
|
+
const collect = (level, prefix, parents) => {
|
|
19
|
+
for (const [job, value] of Object.entries(level)) {
|
|
20
|
+
const jobNames = [...parents, jobLabel(job, value)];
|
|
21
|
+
value.steps?.forEach((step, index) => {
|
|
22
|
+
if (step.summary) found.push({
|
|
23
|
+
prefix,
|
|
24
|
+
job,
|
|
25
|
+
jobNames,
|
|
26
|
+
index,
|
|
27
|
+
step,
|
|
28
|
+
completedAt: completion(value)
|
|
29
|
+
});
|
|
30
|
+
if (step.subworkflow?.jobs) collect(step.subworkflow.jobs, `${prefix}subworkflows/${job}/step_${index}/`, jobNames);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
collect(jobs, "", []);
|
|
35
|
+
return found.sort((a, b) => a.completedAt - b.completedAt || 0).map(({ completedAt: _, ...source }) => source);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A run's step summaries, each on its own card headed by the job and step that wrote it, so a run
|
|
39
|
+
* reads like a report under its graph. The job list beside the graph already shows the run's tree,
|
|
40
|
+
* so the cards are flat.
|
|
41
|
+
*/
|
|
42
|
+
function StepSummaries({ runSlug, jobs, onOpenLog }) {
|
|
43
|
+
const { dag } = useStrings();
|
|
44
|
+
const sources = stepSummarySources(jobs);
|
|
45
|
+
if (sources.length === 0) return null;
|
|
46
|
+
return /* @__PURE__ */ jsx("section", {
|
|
47
|
+
"aria-label": dag.stepSummaries,
|
|
48
|
+
className: "flex flex-col gap-3",
|
|
49
|
+
children: sources.map((source) => /* @__PURE__ */ jsx(SummaryCard, {
|
|
50
|
+
runSlug,
|
|
51
|
+
source,
|
|
52
|
+
onOpenLog: () => onOpenLog(source)
|
|
53
|
+
}, `${source.prefix}${source.job}:${source.index}`))
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function SummaryCard({ runSlug, source, onOpenLog }) {
|
|
57
|
+
const { dag } = useStrings();
|
|
58
|
+
const engine = useWorkflowEngine();
|
|
59
|
+
const headingId = useId();
|
|
60
|
+
const ref = useRef(null);
|
|
61
|
+
const near = useNearViewport(ref);
|
|
62
|
+
const path = engine.stepLogPath(source.prefix, source.job, source.index).replace(/logs\.out$/, "summary.md");
|
|
63
|
+
const failed = source.step.status === "failed";
|
|
64
|
+
const job = source.jobNames.join(SEPARATOR);
|
|
65
|
+
const step = engine.stepLabel(source.step, source.index);
|
|
66
|
+
return /* @__PURE__ */ jsxs("article", {
|
|
67
|
+
ref,
|
|
68
|
+
"aria-labelledby": headingId,
|
|
69
|
+
className: cx("panel min-w-0 rounded-lg border", failed && "border-(--theme-error)"),
|
|
70
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
71
|
+
className: "flex items-center gap-2 border-b px-4 py-2.5",
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx(RunStatusIcon, { status: source.step.status }),
|
|
74
|
+
/* @__PURE__ */ jsxs("h3", {
|
|
75
|
+
id: headingId,
|
|
76
|
+
"aria-label": `${job}${SEPARATOR}${step}`,
|
|
77
|
+
className: "flex min-w-0 flex-1 items-center gap-1.5 text-sm",
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsx("span", {
|
|
80
|
+
className: "min-w-0 shrink-[2] truncate theme-muted-text",
|
|
81
|
+
title: job,
|
|
82
|
+
children: job
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ jsx("span", {
|
|
85
|
+
className: "shrink-0 theme-muted-text",
|
|
86
|
+
children: SEPARATOR
|
|
87
|
+
}),
|
|
88
|
+
/* @__PURE__ */ jsx("span", {
|
|
89
|
+
className: "min-w-0 truncate font-medium",
|
|
90
|
+
title: step,
|
|
91
|
+
children: step
|
|
92
|
+
})
|
|
93
|
+
]
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ jsxs("button", {
|
|
96
|
+
type: "button",
|
|
97
|
+
onClick: onOpenLog,
|
|
98
|
+
"aria-describedby": headingId,
|
|
99
|
+
className: "inline-flex shrink-0 items-center gap-1.5 rounded px-1.5 py-0.5 text-sm theme-muted-text transition-colors hover:bg-(--theme-hover) hover:text-(--theme-link)",
|
|
100
|
+
children: [/* @__PURE__ */ jsx(FileTextIcon, {
|
|
101
|
+
"aria-hidden": true,
|
|
102
|
+
className: "h-3.5 w-3.5"
|
|
103
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
104
|
+
className: "max-sm:sr-only",
|
|
105
|
+
children: dag.logsTab
|
|
106
|
+
})]
|
|
107
|
+
})
|
|
108
|
+
]
|
|
109
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
110
|
+
className: "px-4 py-3.5 sm:px-5",
|
|
111
|
+
children: /* @__PURE__ */ jsx(SummaryBody, {
|
|
112
|
+
runSlug,
|
|
113
|
+
path: near ? path : null
|
|
114
|
+
})
|
|
115
|
+
})]
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function SummaryBody({ runSlug, path }) {
|
|
119
|
+
const { dag } = useStrings();
|
|
120
|
+
const { data, isLoading, error } = useRunFile(runSlug, path);
|
|
121
|
+
if (path === null || isLoading && data === void 0) return /* @__PURE__ */ jsx("div", {
|
|
122
|
+
role: "status",
|
|
123
|
+
"aria-label": dag.loadingSummary,
|
|
124
|
+
className: "flex flex-col gap-2 py-1",
|
|
125
|
+
children: [
|
|
126
|
+
"w-2/3",
|
|
127
|
+
"w-1/2",
|
|
128
|
+
"w-5/6"
|
|
129
|
+
].map((width) => /* @__PURE__ */ jsx("div", { className: cx("h-3 rounded bg-(--theme-border) motion-safe:animate-pulse", width) }, width))
|
|
130
|
+
});
|
|
131
|
+
if (error || data === void 0) return /* @__PURE__ */ jsx("p", {
|
|
132
|
+
className: "text-sm theme-muted-text",
|
|
133
|
+
children: dag.summaryLoadFailed
|
|
134
|
+
});
|
|
135
|
+
return /* @__PURE__ */ jsx(Clamped, { children: /* @__PURE__ */ jsx(Markdown, {
|
|
136
|
+
httpsImagesOnly: true,
|
|
137
|
+
compact: true,
|
|
138
|
+
children: data
|
|
139
|
+
}) });
|
|
140
|
+
}
|
|
141
|
+
function useNearViewport(ref) {
|
|
142
|
+
const [near, setNear] = useState(typeof IntersectionObserver === "undefined");
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
const el = ref.current;
|
|
145
|
+
if (near || !el) return;
|
|
146
|
+
const observer = new IntersectionObserver((entries) => {
|
|
147
|
+
if (entries.some((entry) => entry.isIntersecting)) setNear(true);
|
|
148
|
+
}, { rootMargin: "200% 0px" });
|
|
149
|
+
observer.observe(el);
|
|
150
|
+
return () => observer.disconnect();
|
|
151
|
+
}, [ref, near]);
|
|
152
|
+
return near;
|
|
153
|
+
}
|
|
154
|
+
function Clamped({ children }) {
|
|
155
|
+
const { common } = useStrings();
|
|
156
|
+
const ref = useRef(null);
|
|
157
|
+
const [expanded, setExpanded] = useState(false);
|
|
158
|
+
const [clipped, setClipped] = useState(false);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
const el = ref.current;
|
|
161
|
+
if (!el || expanded) return;
|
|
162
|
+
const measure = () => setClipped(el.scrollHeight > el.clientHeight + 1);
|
|
163
|
+
const observer = new ResizeObserver(measure);
|
|
164
|
+
observer.observe(el);
|
|
165
|
+
measure();
|
|
166
|
+
return () => observer.disconnect();
|
|
167
|
+
}, [expanded]);
|
|
168
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
169
|
+
className: "flex flex-col gap-2",
|
|
170
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
171
|
+
ref,
|
|
172
|
+
className: cx("min-w-0 [overflow-wrap:anywhere] [&_table]:[overflow-wrap:normal] [&_[data-streamdown=table-wrapper]>div]:max-h-none!", !expanded && "max-h-[32rem] overflow-hidden", !expanded && clipped && "mask-[linear-gradient(to_bottom,black_75%,transparent)]"),
|
|
173
|
+
children
|
|
174
|
+
}), (clipped || expanded) && /* @__PURE__ */ jsx("button", {
|
|
175
|
+
type: "button",
|
|
176
|
+
"aria-expanded": expanded,
|
|
177
|
+
onClick: () => setExpanded(!expanded),
|
|
178
|
+
className: "link w-fit text-sm font-medium",
|
|
179
|
+
children: expanded ? common.showLess : common.showMore
|
|
180
|
+
})]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
export { StepSummaries, stepSummarySources };
|
package/dist/list/listSearch.js
CHANGED
|
@@ -134,7 +134,7 @@ function ListSearchControl({ search, placeholder, label: labelProp }) {
|
|
|
134
134
|
function ListCount({ total, matches, filterActive, noun, nounPlural }) {
|
|
135
135
|
const { list: t } = useStrings();
|
|
136
136
|
return /* @__PURE__ */ jsx("div", {
|
|
137
|
-
className: "flex items-center h-
|
|
137
|
+
className: "flex items-center h-8",
|
|
138
138
|
children: /* @__PURE__ */ jsx("span", {
|
|
139
139
|
role: "status",
|
|
140
140
|
className: "text-[13px] text-(--theme-muted-text-color)",
|
package/dist/styles/theme.css
CHANGED
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
|
|
138
138
|
/* The bordered panel graphs and settings cards sit in; graph circles hide connectors with its color. */
|
|
139
139
|
@utility panel {
|
|
140
|
-
@apply border-solid rounded-
|
|
140
|
+
@apply border-solid rounded-xl border border-(--theme-border) theme-panel;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
@utility theme-muted-panel {
|