@parallelworks/ui 0.57.0 → 0.59.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 +60 -4
- package/dist/access/PrincipalPicker.js +2 -1
- package/dist/ai/agent/diff.d.ts +1 -0
- package/dist/ai/agent/diff.js +50 -3
- package/dist/ai/ai.css +38 -0
- package/dist/ai/components/AttachmentUpload.d.ts +3 -0
- package/dist/ai/components/AttachmentUpload.js +51 -43
- package/dist/ai/components/agent/AgentMessageParts.js +33 -6
- package/dist/ai/strings.d.ts +2 -0
- package/dist/ai/strings.js +2 -1
- package/dist/components/AppLink.js +8 -3
- package/dist/components/Avatar.d.ts +5 -1
- package/dist/components/Avatar.js +13 -5
- package/dist/components/ExternalLink.d.ts +3 -2
- package/dist/components/ExternalLink.js +5 -2
- package/dist/components/Field.d.ts +7 -1
- package/dist/components/Field.js +83 -56
- package/dist/components/HoverCard.js +12 -0
- package/dist/components/Markdown.d.ts +3 -0
- package/dist/components/Markdown.js +2 -1
- package/dist/components/MarkdownImpl.d.ts +1 -1
- package/dist/components/MarkdownImpl.js +5 -3
- package/dist/components/Provider.d.ts +16 -1
- package/dist/components/Provider.js +17 -3
- package/dist/components/StickyBar.d.ts +14 -0
- package/dist/components/StickyBar.js +22 -0
- package/dist/components/Table.d.ts +7 -5
- package/dist/components/Table.js +6 -2
- package/dist/components/Tabs.d.ts +2 -2
- package/dist/components/Tabs.js +5 -2
- package/dist/components/category.d.ts +9 -0
- package/dist/components/category.js +30 -0
- package/dist/components/httpsImages.d.ts +12 -0
- package/dist/components/httpsImages.js +27 -0
- package/dist/components/stickyTop.d.ts +14 -0
- package/dist/components/stickyTop.js +93 -0
- package/dist/file-explorer/FileExplorer.js +21 -15
- package/dist/graph/DependencyGraph.d.ts +14 -1
- package/dist/graph/DependencyGraph.js +169 -77
- package/dist/graph/JobSummary.js +13 -3
- package/dist/graph/StepSummary.d.ts +4 -0
- package/dist/graph/StepSummary.js +31 -0
- package/dist/graph/index.d.ts +1 -0
- package/dist/graph/index.js +2 -1
- package/dist/graph/types.d.ts +3 -0
- package/dist/graph/util.d.ts +1 -1
- package/dist/icons.d.ts +1 -0
- package/dist/icons.js +3 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/list/ActionToolbar.d.ts +2 -3
- package/dist/list/ActionToolbar.js +3 -3
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +2 -2
- package/dist/logviewer/LogViewer.js +3 -3
- package/dist/styles/theme.css +27 -0
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +2 -1
- package/dist/theme/derive.js +45 -1
- package/package.json +1 -1
package/dist/components/Field.js
CHANGED
|
@@ -37,12 +37,14 @@ var labelSizes = {
|
|
|
37
37
|
sm: {
|
|
38
38
|
text: "text-xs text-(--theme-muted-text-color)",
|
|
39
39
|
inlineHeight: "min-h-7",
|
|
40
|
-
stackGap: "gap-1"
|
|
40
|
+
stackGap: "gap-1",
|
|
41
|
+
inlineLine: "py-1.5"
|
|
41
42
|
},
|
|
42
43
|
md: {
|
|
43
44
|
text: "text-sm text-(--theme-app)",
|
|
44
45
|
inlineHeight: "min-h-9",
|
|
45
|
-
stackGap: "gap-1.5"
|
|
46
|
+
stackGap: "gap-1.5",
|
|
47
|
+
inlineLine: "py-2"
|
|
46
48
|
}
|
|
47
49
|
};
|
|
48
50
|
var labelClassName = "flex items-center gap-1 font-medium";
|
|
@@ -64,7 +66,7 @@ function ErrorText({ id, children }) {
|
|
|
64
66
|
}
|
|
65
67
|
/** A control with its label, help and error, tied to it for assistive technology. One frame
|
|
66
68
|
* for every field, in a form or standing alone. */
|
|
67
|
-
function Field$1({ label, hint, help, actions, description, error, invalid, required = false, disabled = false, layout = "stacked", compact = false, size = "md", group = false, id: ownId, className, children }) {
|
|
69
|
+
function Field$1({ label, hint, help, actions, description, error, invalid, required = false, disabled = false, layout = "stacked", compact = false, size = "md", group = false, controlFirst = false, id: ownId, className, children }) {
|
|
68
70
|
const uid = useId();
|
|
69
71
|
const id = ownId ?? `${uid}control`;
|
|
70
72
|
const labelId = `${uid}label`;
|
|
@@ -125,8 +127,8 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
|
|
|
125
127
|
}
|
|
126
128
|
} : {};
|
|
127
129
|
const labelBox = cx(labelClassName, labelSize.text, inline && cx(labelSize.inlineHeight, "shrink-0", compact ? "mr-2 w-fit" : "w-52 pr-3"), inRow && "row-start-1 self-end");
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
+
const nameContent = /* @__PURE__ */ jsxs(Fragment, { children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})] });
|
|
131
|
+
const labelExtras = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
130
132
|
helpTip,
|
|
131
133
|
hint,
|
|
132
134
|
actions && /* @__PURE__ */ jsx("span", {
|
|
@@ -135,42 +137,83 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
|
|
|
135
137
|
})
|
|
136
138
|
] });
|
|
137
139
|
const placed = typeof children === "function" ? children(control) : children;
|
|
140
|
+
const controlInContext = /* @__PURE__ */ jsx(FieldRowContext, {
|
|
141
|
+
value: false,
|
|
142
|
+
children: /* @__PURE__ */ jsx(ControlContext, {
|
|
143
|
+
value: controlContext,
|
|
144
|
+
children: placed
|
|
145
|
+
})
|
|
146
|
+
});
|
|
147
|
+
const messages = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
148
|
+
description && /* @__PURE__ */ jsx(Field.Description, {
|
|
149
|
+
id: descriptionId,
|
|
150
|
+
className: "text-xs leading-relaxed text-(--theme-muted-text-color)",
|
|
151
|
+
children: description
|
|
152
|
+
}),
|
|
153
|
+
help && /* @__PURE__ */ jsx(Field.Description, {
|
|
154
|
+
id: helpId,
|
|
155
|
+
hidden: true,
|
|
156
|
+
children: formatInfoTipContent(help)
|
|
157
|
+
}),
|
|
158
|
+
error && /* @__PURE__ */ jsxs(Field.Error, {
|
|
159
|
+
id: errorId,
|
|
160
|
+
match: true,
|
|
161
|
+
role: "alert",
|
|
162
|
+
className: errorTextClassName,
|
|
163
|
+
children: [/* @__PURE__ */ jsx(WarningIcon, {
|
|
164
|
+
"aria-hidden": "true",
|
|
165
|
+
className: "size-3.5 shrink-0"
|
|
166
|
+
}), error]
|
|
167
|
+
})
|
|
168
|
+
] });
|
|
169
|
+
const fieldLabel = (className) => /* @__PURE__ */ jsx(Field.Label, {
|
|
170
|
+
...labelledBy > 0 ? {
|
|
171
|
+
htmlFor: void 0,
|
|
172
|
+
onClick: () => document.getElementById(id)?.focus()
|
|
173
|
+
} : typeof children === "function" || ownId !== void 0 ? { htmlFor: id } : {},
|
|
174
|
+
id: labelId,
|
|
175
|
+
className,
|
|
176
|
+
"data-field-label": true,
|
|
177
|
+
children: nameContent
|
|
178
|
+
});
|
|
179
|
+
if (controlFirst && !group) {
|
|
180
|
+
const lined = inline || inRow;
|
|
181
|
+
return /* @__PURE__ */ jsxs(Field.Root, {
|
|
182
|
+
invalid: isInvalid,
|
|
183
|
+
disabled,
|
|
184
|
+
className: inRow ? cx("contents", className) : cx("flex w-full items-start", className),
|
|
185
|
+
"data-field-row": inRow || void 0,
|
|
186
|
+
children: [inline && !compact && /* @__PURE__ */ jsx("div", {
|
|
187
|
+
"aria-hidden": "true",
|
|
188
|
+
className: "w-52 shrink-0"
|
|
189
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
190
|
+
ref: help ? setControlBox : void 0,
|
|
191
|
+
className: cx("flex w-fit max-w-full min-w-0 items-start gap-2", lined && labelSize.inlineLine, inRow && "row-start-2"),
|
|
192
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
193
|
+
className: cx("flex h-lh shrink-0 items-center", labelSize.text),
|
|
194
|
+
...helpFocus,
|
|
195
|
+
children: controlInContext
|
|
196
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
197
|
+
className: "flex min-w-0 flex-col gap-1",
|
|
198
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
199
|
+
className: cx("font-medium", labelSize.text, disabled && "opacity-60"),
|
|
200
|
+
children: [fieldLabel(disabled ? "cursor-not-allowed" : "cursor-pointer"), (help || hint || actions) && /* @__PURE__ */ jsx("span", {
|
|
201
|
+
className: "ms-1 inline-flex items-center gap-1 align-[-0.125em]",
|
|
202
|
+
children: labelExtras
|
|
203
|
+
})]
|
|
204
|
+
}), messages]
|
|
205
|
+
})]
|
|
206
|
+
})]
|
|
207
|
+
});
|
|
208
|
+
}
|
|
138
209
|
const body = /* @__PURE__ */ jsxs("div", {
|
|
139
210
|
ref: help ? setControlBox : void 0,
|
|
140
211
|
className: cx("flex w-full min-w-0 flex-col gap-1", inRow && "row-start-2"),
|
|
141
212
|
...helpFocus,
|
|
142
|
-
children: [
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
value: controlContext,
|
|
147
|
-
children: inline ? /* @__PURE__ */ jsx("div", {
|
|
148
|
-
className: cx("grid items-center", labelSize.inlineHeight),
|
|
149
|
-
children: placed
|
|
150
|
-
}) : placed
|
|
151
|
-
})
|
|
152
|
-
}),
|
|
153
|
-
description && /* @__PURE__ */ jsx(Field.Description, {
|
|
154
|
-
id: descriptionId,
|
|
155
|
-
className: "text-xs leading-relaxed text-(--theme-muted-text-color)",
|
|
156
|
-
children: description
|
|
157
|
-
}),
|
|
158
|
-
help && /* @__PURE__ */ jsx(Field.Description, {
|
|
159
|
-
id: helpId,
|
|
160
|
-
hidden: true,
|
|
161
|
-
children: formatInfoTipContent(help)
|
|
162
|
-
}),
|
|
163
|
-
error && /* @__PURE__ */ jsxs(Field.Error, {
|
|
164
|
-
id: errorId,
|
|
165
|
-
match: true,
|
|
166
|
-
role: "alert",
|
|
167
|
-
className: errorTextClassName,
|
|
168
|
-
children: [/* @__PURE__ */ jsx(WarningIcon, {
|
|
169
|
-
"aria-hidden": "true",
|
|
170
|
-
className: "size-3.5 shrink-0"
|
|
171
|
-
}), error]
|
|
172
|
-
})
|
|
173
|
-
]
|
|
213
|
+
children: [inline ? /* @__PURE__ */ jsx("div", {
|
|
214
|
+
className: cx("grid items-center", labelSize.inlineHeight),
|
|
215
|
+
children: controlInContext
|
|
216
|
+
}) : controlInContext, messages]
|
|
174
217
|
});
|
|
175
218
|
const frame = inRow ? cx("contents", className) : cx("flex w-full", inline ? "items-start" : cx("flex-col", labelSize.stackGap), className);
|
|
176
219
|
if (group) return /* @__PURE__ */ jsx(Field.Root, {
|
|
@@ -182,10 +225,10 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
|
|
|
182
225
|
}),
|
|
183
226
|
children: /* @__PURE__ */ jsxs("div", {
|
|
184
227
|
className: frame,
|
|
185
|
-
children: [/* @__PURE__ */
|
|
228
|
+
children: [/* @__PURE__ */ jsxs(Fieldset.Legend, {
|
|
186
229
|
id: labelId,
|
|
187
230
|
className: labelBox,
|
|
188
|
-
children:
|
|
231
|
+
children: [/* @__PURE__ */ jsx("span", { children: nameContent }), labelExtras]
|
|
189
232
|
}), body]
|
|
190
233
|
})
|
|
191
234
|
});
|
|
@@ -196,23 +239,7 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
|
|
|
196
239
|
"data-field-row": inRow || void 0,
|
|
197
240
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
198
241
|
className: labelBox,
|
|
199
|
-
children: [
|
|
200
|
-
/* @__PURE__ */ jsxs(Field.Label, {
|
|
201
|
-
...labelledBy > 0 ? {
|
|
202
|
-
htmlFor: void 0,
|
|
203
|
-
onClick: () => document.getElementById(id)?.focus()
|
|
204
|
-
} : typeof children === "function" || ownId !== void 0 ? { htmlFor: id } : {},
|
|
205
|
-
id: labelId,
|
|
206
|
-
"data-field-label": true,
|
|
207
|
-
children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
|
|
208
|
-
}),
|
|
209
|
-
helpTip,
|
|
210
|
-
hint,
|
|
211
|
-
actions && /* @__PURE__ */ jsx("span", {
|
|
212
|
-
className: actionsClassName,
|
|
213
|
-
children: actions
|
|
214
|
-
})
|
|
215
|
-
]
|
|
242
|
+
children: [fieldLabel(), labelExtras]
|
|
216
243
|
}), body]
|
|
217
244
|
});
|
|
218
245
|
}
|
|
@@ -3,6 +3,17 @@ import { useFullscreenContainer } from "./fullscreen.js";
|
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { PreviewCard } from "@base-ui/react/preview-card";
|
|
5
5
|
//#region src/components/HoverCard.tsx
|
|
6
|
+
var stop = (event) => event.stopPropagation();
|
|
7
|
+
var pressHandlers = {
|
|
8
|
+
onClick: stop,
|
|
9
|
+
onAuxClick: stop,
|
|
10
|
+
onDoubleClick: stop,
|
|
11
|
+
onContextMenu: stop,
|
|
12
|
+
onPointerDown: stop,
|
|
13
|
+
onPointerUp: stop,
|
|
14
|
+
onMouseDown: stop,
|
|
15
|
+
onMouseUp: stop
|
|
16
|
+
};
|
|
6
17
|
/** Detail about its anchor, such as a person's profile, after a short hover or
|
|
7
18
|
* on focus. A visual enhancement: whatever the card shows must also be
|
|
8
19
|
* reachable another way, such as the page the anchor links to. The card
|
|
@@ -25,6 +36,7 @@ function HoverCard({ card, children, defaultOpen = false }) {
|
|
|
25
36
|
className: positionerClassName,
|
|
26
37
|
children: /* @__PURE__ */ jsx(PreviewCard.Popup, {
|
|
27
38
|
className: cardClassName,
|
|
39
|
+
...pressHandlers,
|
|
28
40
|
children: card
|
|
29
41
|
})
|
|
30
42
|
})
|
|
@@ -7,6 +7,9 @@ export interface MarkdownProps {
|
|
|
7
7
|
controls?: ControlsConfig;
|
|
8
8
|
/** Per-tag overrides of the rendered elements. */
|
|
9
9
|
components?: Components;
|
|
10
|
+
httpsImagesOnly?: boolean;
|
|
11
|
+
/** Sets it at the page's text size, for Markdown inside other UI rather than a document of its own. */
|
|
12
|
+
compact?: boolean;
|
|
10
13
|
}
|
|
11
14
|
/** Markdown, with highlighted code, math and mermaid diagrams. Links leave in a
|
|
12
15
|
* new tab, and inline code breaks after path separators. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
1
2
|
import { jsx } from "react/jsx-runtime";
|
|
2
3
|
import { Suspense, lazy } from "react";
|
|
3
4
|
//#region src/components/Markdown.tsx
|
|
@@ -7,7 +8,7 @@ var MarkdownImpl = lazy(() => import("./MarkdownImpl.js"));
|
|
|
7
8
|
function Markdown(props) {
|
|
8
9
|
return /* @__PURE__ */ jsx(Suspense, {
|
|
9
10
|
fallback: /* @__PURE__ */ jsx("div", {
|
|
10
|
-
className: "markdown whitespace-pre-wrap text-start w-full",
|
|
11
|
+
className: cx("markdown whitespace-pre-wrap text-start w-full", props.compact && "markdown-compact"),
|
|
11
12
|
children: props.children
|
|
12
13
|
}),
|
|
13
14
|
children: /* @__PURE__ */ jsx(MarkdownImpl, { ...props })
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'katex/dist/katex.min.css';
|
|
2
2
|
import type { MarkdownProps } from './Markdown.js';
|
|
3
|
-
export default function MarkdownImpl({ children, isStreaming, controls, components, }: MarkdownProps): import("react").JSX.Element;
|
|
3
|
+
export default function MarkdownImpl({ children, isStreaming, controls, components, httpsImagesOnly, compact, }: MarkdownProps): import("react").JSX.Element;
|
|
@@ -2,6 +2,7 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { ExternalLink } from "./ExternalLink.js";
|
|
3
3
|
import { readIsDark } from "./useCssIsDark.js";
|
|
4
4
|
import { CODE_THEMES } from "./codeTheme.js";
|
|
5
|
+
import { rehypeHttpsImagesOnly } from "./httpsImages.js";
|
|
5
6
|
import { rehypeCodeBreaks } from "./markdownCodeBreaks.js";
|
|
6
7
|
import { jsx } from "react/jsx-runtime";
|
|
7
8
|
import { useEffect, useState } from "react";
|
|
@@ -33,7 +34,8 @@ function loadMermaid() {
|
|
|
33
34
|
return mermaidLoad;
|
|
34
35
|
}
|
|
35
36
|
var rehypePlugins = [...Object.values(defaultRehypePlugins), rehypeCodeBreaks];
|
|
36
|
-
|
|
37
|
+
var httpsImagesRehypePlugins = [...Object.entries(defaultRehypePlugins).flatMap(([name, plugin]) => name === "harden" ? [rehypeHttpsImagesOnly, plugin] : [plugin]), rehypeCodeBreaks];
|
|
38
|
+
function MarkdownImpl({ children, isStreaming, controls, components, httpsImagesOnly, compact }) {
|
|
37
39
|
const needsMermaid = !!children && children.includes("```mermaid");
|
|
38
40
|
const [, setMermaidReady] = useState(() => !!pluginsWithMermaid);
|
|
39
41
|
useEffect(() => {
|
|
@@ -48,7 +50,7 @@ function MarkdownImpl({ children, isStreaming, controls, components }) {
|
|
|
48
50
|
}, [needsMermaid]);
|
|
49
51
|
const plugins = needsMermaid && pluginsWithMermaid ? pluginsWithMermaid : basePlugins;
|
|
50
52
|
return /* @__PURE__ */ jsx("div", {
|
|
51
|
-
className: "markdown whitespace-normal text-start w-full",
|
|
53
|
+
className: cx("markdown whitespace-normal text-start w-full", compact && "markdown-compact"),
|
|
52
54
|
children: /* @__PURE__ */ jsx(Streamdown, {
|
|
53
55
|
mode: isStreaming ? "streaming" : "static",
|
|
54
56
|
isAnimating: isStreaming ?? false,
|
|
@@ -58,7 +60,7 @@ function MarkdownImpl({ children, isStreaming, controls, components }) {
|
|
|
58
60
|
} : {},
|
|
59
61
|
...controls ? { controls } : {},
|
|
60
62
|
plugins,
|
|
61
|
-
rehypePlugins,
|
|
63
|
+
rehypePlugins: httpsImagesOnly ? httpsImagesRehypePlugins : rehypePlugins,
|
|
62
64
|
shikiTheme: CODE_THEMES,
|
|
63
65
|
components: {
|
|
64
66
|
a: ({ node, ...props }) => /* @__PURE__ */ jsx(ExternalLink, {
|
|
@@ -227,6 +227,14 @@ export interface UIStrings {
|
|
|
227
227
|
loadingLogs: string;
|
|
228
228
|
noLogFound: string;
|
|
229
229
|
logLoadFailed: string;
|
|
230
|
+
loadingSummary: string;
|
|
231
|
+
hasSummary: string;
|
|
232
|
+
stepOf: (position: number, count: number) => string;
|
|
233
|
+
summaryLoadFailed: string;
|
|
234
|
+
summaryTab: string;
|
|
235
|
+
logsTab: string;
|
|
236
|
+
scriptTab: string;
|
|
237
|
+
openSubworkflow: string;
|
|
230
238
|
statusLabel: (status: string) => string;
|
|
231
239
|
statusReason: (reason: string | undefined | null) => string | undefined;
|
|
232
240
|
/** A run's general log, beside its summary. */
|
|
@@ -277,6 +285,8 @@ export interface UIStrings {
|
|
|
277
285
|
openFolder: string;
|
|
278
286
|
/** A path's page in the app, as in "Copy link". */
|
|
279
287
|
link: string;
|
|
288
|
+
/** An object's key within its storage, as in "Copy path". */
|
|
289
|
+
path: string;
|
|
280
290
|
detailsTab: string;
|
|
281
291
|
previewTab: string;
|
|
282
292
|
preview: string;
|
|
@@ -734,7 +744,12 @@ export interface UIProviderProps {
|
|
|
734
744
|
/** The engine, or a loader that resolves to it. A loader is called once, the first one
|
|
735
745
|
* passed, so it may be written inline. */
|
|
736
746
|
engine?: WorkflowEngineSource | undefined;
|
|
747
|
+
/** The nonce the page's Content Security Policy allows inline scripts by,
|
|
748
|
+
* for a host that renders on the server: a few components emit a script
|
|
749
|
+
* that places them before hydration. The components render no inline
|
|
750
|
+
* `<style>`, so a policy without 'unsafe-inline' styles needs none. */
|
|
751
|
+
nonce?: string | undefined;
|
|
737
752
|
children: React.ReactNode;
|
|
738
753
|
}
|
|
739
|
-
export declare function UIProvider({ strings, navigation, data, slots, engine: engineProp, children, }: UIProviderProps): import("react").JSX.Element;
|
|
754
|
+
export declare function UIProvider({ strings, navigation, data, slots, engine: engineProp, nonce, children, }: UIProviderProps): import("react").JSX.Element;
|
|
740
755
|
export {};
|
|
@@ -4,6 +4,7 @@ import { Toaster } from "./Toast.js";
|
|
|
4
4
|
import { TooltipProvider } from "./Tooltip.js";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { createContext, use, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
7
|
+
import { CSPProvider } from "@base-ui/react/csp-provider";
|
|
7
8
|
import { dequal } from "dequal";
|
|
8
9
|
//#region src/components/Provider.tsx
|
|
9
10
|
var isGroup = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -236,6 +237,14 @@ var DEFAULTS = {
|
|
|
236
237
|
loadingLogs: "Loading logs",
|
|
237
238
|
noLogFound: "No log found",
|
|
238
239
|
logLoadFailed: "Log could not be loaded",
|
|
240
|
+
loadingSummary: "Loading summary",
|
|
241
|
+
hasSummary: "Has a summary",
|
|
242
|
+
stepOf: (position, count) => `Step ${position} of ${count}`,
|
|
243
|
+
summaryLoadFailed: "Summary could not be loaded",
|
|
244
|
+
summaryTab: "Summary",
|
|
245
|
+
logsTab: "Logs",
|
|
246
|
+
scriptTab: "Script",
|
|
247
|
+
openSubworkflow: "Open Subworkflow",
|
|
239
248
|
statusLabel: (status) => status,
|
|
240
249
|
statusReason: () => void 0,
|
|
241
250
|
generalLog: "General log",
|
|
@@ -289,6 +298,7 @@ var DEFAULTS = {
|
|
|
289
298
|
viewDetails: "View details",
|
|
290
299
|
openFolder: "Open folder",
|
|
291
300
|
link: "link",
|
|
301
|
+
path: "path",
|
|
292
302
|
detailsTab: "Details",
|
|
293
303
|
previewTab: "Preview",
|
|
294
304
|
preview: "Preview",
|
|
@@ -685,7 +695,7 @@ function useMerged(compute, input) {
|
|
|
685
695
|
};
|
|
686
696
|
return ref.current.value;
|
|
687
697
|
}
|
|
688
|
-
function UIProvider({ strings, navigation, data, slots, engine: engineProp, children }) {
|
|
698
|
+
function UIProvider({ strings, navigation, data, slots, engine: engineProp, nonce, children }) {
|
|
689
699
|
const [firstLoader] = useState(() => typeof engineProp === "function" ? engineProp : void 0);
|
|
690
700
|
const engine = typeof engineProp === "function" ? firstLoader ?? engineProp : engineProp;
|
|
691
701
|
useEffect(() => {
|
|
@@ -712,9 +722,13 @@ function UIProvider({ strings, navigation, data, slots, engine: engineProp, chil
|
|
|
712
722
|
value: mergedData,
|
|
713
723
|
children: /* @__PURE__ */ jsx(SlotsContext, {
|
|
714
724
|
value: stableSlots,
|
|
715
|
-
children: /* @__PURE__ */
|
|
725
|
+
children: /* @__PURE__ */ jsx(EngineContext, {
|
|
716
726
|
value: engine,
|
|
717
|
-
children:
|
|
727
|
+
children: /* @__PURE__ */ jsxs(CSPProvider, {
|
|
728
|
+
nonce,
|
|
729
|
+
disableStyleElements: true,
|
|
730
|
+
children: [/* @__PURE__ */ jsx(TooltipProvider, { children }), /* @__PURE__ */ jsx(Toaster, {})]
|
|
731
|
+
})
|
|
718
732
|
})
|
|
719
733
|
})
|
|
720
734
|
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface StickyBarProps {
|
|
3
|
+
/** Padding, borders and layout; the bar sets its own position, `top`,
|
|
4
|
+
* layer and background. */
|
|
5
|
+
className?: string | undefined;
|
|
6
|
+
testId?: string | undefined;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/** A strip of a page's own controls, such as a row of filters or a page's
|
|
10
|
+
* actions, pinned as the page scrolls. It stops just below whatever its
|
|
11
|
+
* scroller already pins at the top, such as the page header, and moves with
|
|
12
|
+
* it as that wraps or changes height. For an `ActionToolbar` or `Tabs` alone,
|
|
13
|
+
* give them `sticky` instead. */
|
|
14
|
+
export declare function StickyBar({ className, testId, children }: StickyBarProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { stickyClasses, useStickyTop } from "./stickyTop.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
//#region src/components/StickyBar.tsx
|
|
6
|
+
/** A strip of a page's own controls, such as a row of filters or a page's
|
|
7
|
+
* actions, pinned as the page scrolls. It stops just below whatever its
|
|
8
|
+
* scroller already pins at the top, such as the page header, and moves with
|
|
9
|
+
* it as that wraps or changes height. For an `ActionToolbar` or `Tabs` alone,
|
|
10
|
+
* give them `sticky` instead. */
|
|
11
|
+
function StickyBar({ className, testId, children }) {
|
|
12
|
+
const [el, setEl] = useState(null);
|
|
13
|
+
useStickyTop(el, true);
|
|
14
|
+
return /* @__PURE__ */ jsx("div", {
|
|
15
|
+
ref: setEl,
|
|
16
|
+
"data-testid": testId,
|
|
17
|
+
className: cx(stickyClasses, className),
|
|
18
|
+
children
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { StickyBar };
|
|
@@ -37,11 +37,13 @@ interface TableProps {
|
|
|
37
37
|
roundedBottom?: boolean;
|
|
38
38
|
isLoading?: boolean;
|
|
39
39
|
/** The header row stays in view while the rows scroll under it. It sticks
|
|
40
|
-
* to the nearest scrolling ancestor,
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
40
|
+
* to the nearest scrolling ancestor, just below whatever that ancestor
|
|
41
|
+
* already pins at its top, such as a page header, a toolbar or tabs, which
|
|
42
|
+
* it finds and follows by itself; in a box that scrolls on its own it pins
|
|
43
|
+
* at the box's top. So the table no longer scrolls or clips on its own: a
|
|
44
|
+
* box that scrolls itself is all a sticky header can stick to. Its ancestor
|
|
45
|
+
* scrolls it sideways as well as down. Rows pass under the header, so a
|
|
46
|
+
* `theadClassName` of your own needs a background. */
|
|
45
47
|
stickyHeader?: boolean | undefined;
|
|
46
48
|
/** Forwarded to the `<table>`, for attributes that must sit on the element owning
|
|
47
49
|
* the rows — `role='grid'`, aria-activedescendant, aria-rowcount. `className` is
|
package/dist/components/Table.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { SortDownIcon, SortUnsortedIcon, SortUpIcon } from "../icons.js";
|
|
3
3
|
import { Loader } from "./Loader.js";
|
|
4
|
+
import { useStickyTop } from "./stickyTop.js";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
import React, { createContext, useContext } from "react";
|
|
6
|
+
import React, { createContext, useContext, useState } from "react";
|
|
6
7
|
//#region src/components/Table.tsx
|
|
7
8
|
var DensityContext = createContext("comfortable");
|
|
8
9
|
var cellX = "px-3";
|
|
@@ -47,6 +48,8 @@ var isHeaderChild = (child) => {
|
|
|
47
48
|
* the children, then `<tr>`s of `Table.Item`s. */
|
|
48
49
|
function Table({ density = "comfortable", borderless = false, panel = true, className, wrapperClassName = "", tbodyClassName = "divide-y", theadClassName = "theme-muted-panel", children, roundedTop = false, rounded = false, roundedBottom = false, isLoading = false, stickyHeader = false, tableProps }) {
|
|
49
50
|
const childList = React.Children.toArray(children);
|
|
51
|
+
const [thead, setThead] = useState(null);
|
|
52
|
+
useStickyTop(thead, stickyHeader && !isLoading);
|
|
50
53
|
const hasOverflow = wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-"));
|
|
51
54
|
return /* @__PURE__ */ jsx(DensityContext, {
|
|
52
55
|
value: density,
|
|
@@ -62,7 +65,8 @@ function Table({ density = "comfortable", borderless = false, panel = true, clas
|
|
|
62
65
|
className: cx("min-w-full divide-y theme-border", className),
|
|
63
66
|
...tableProps,
|
|
64
67
|
children: [/* @__PURE__ */ jsx("thead", {
|
|
65
|
-
|
|
68
|
+
ref: setThead,
|
|
69
|
+
className: cx(stickyHeader && "sticky top-0 z-(--layer-sticky) border-b-0 shadow-[inset_0_-1px_0_var(--theme-border)]", theadClassName),
|
|
66
70
|
children: /* @__PURE__ */ jsx("tr", { children: childList.filter(isHeaderChild) })
|
|
67
71
|
}), /* @__PURE__ */ jsx("tbody", {
|
|
68
72
|
className: tbodyClassName,
|
|
@@ -25,8 +25,8 @@ export interface TabsProps<Value extends string> extends SegmentLayout {
|
|
|
25
25
|
variant?: 'line' | 'segmented' | undefined;
|
|
26
26
|
/** At the tab row's far end, such as a picker for what the tabs show. */
|
|
27
27
|
end?: ReactNode;
|
|
28
|
-
/** Pins the tab row
|
|
29
|
-
*
|
|
28
|
+
/** Pins the tab row as the page scrolls, just below whatever the page's
|
|
29
|
+
* scroller already pins at the top, such as the page header and a toolbar. */
|
|
30
30
|
sticky?: boolean | undefined;
|
|
31
31
|
/** On the tab row. */
|
|
32
32
|
className?: string | undefined;
|
package/dist/components/Tabs.js
CHANGED
|
@@ -2,11 +2,11 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { Tooltip } from "./Tooltip.js";
|
|
3
3
|
import { AppLink } from "./AppLink.js";
|
|
4
4
|
import { SegmentContent, segmentClassName, segmentGroupClassName } from "./segmented.js";
|
|
5
|
+
import { useStickyTop } from "./stickyTop.js";
|
|
5
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
7
|
import { useState } from "react";
|
|
7
8
|
import { Tabs } from "@base-ui/react/tabs";
|
|
8
9
|
//#region src/components/Tabs.tsx
|
|
9
|
-
var stickyClassName = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
|
|
10
10
|
/** Views of one thing, one shown at a time: panels below the tabs, or pages
|
|
11
11
|
* the tabs link to. A lone tab would only repeat the page's title, so the row
|
|
12
12
|
* hides unless there are two or more, or something at its end. */
|
|
@@ -19,6 +19,8 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
|
|
|
19
19
|
const [own, setOwn] = useState(defaultValue ?? items[0]?.value);
|
|
20
20
|
const current = value ?? own;
|
|
21
21
|
const showRow = items.length > 1 || !!end;
|
|
22
|
+
const [row, setRow] = useState(null);
|
|
23
|
+
useStickyTop(row, !!sticky);
|
|
22
24
|
const tabs = items.map((item) => {
|
|
23
25
|
const tab = /* @__PURE__ */ jsx(Tabs.Tab, {
|
|
24
26
|
value: item.value,
|
|
@@ -50,7 +52,8 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
|
|
|
50
52
|
"data-testid": testId,
|
|
51
53
|
className: children ? void 0 : "contents",
|
|
52
54
|
children: [showRow && /* @__PURE__ */ jsxs("div", {
|
|
53
|
-
|
|
55
|
+
ref: setRow,
|
|
56
|
+
className: cx("flex items-center justify-between gap-2", !segmented && "border-b border-(--theme-border)", sticky && "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)", className),
|
|
54
57
|
children: [/* @__PURE__ */ jsxs(Tabs.List, {
|
|
55
58
|
"aria-label": label,
|
|
56
59
|
className: cx(segmented ? segmentGroupClassName(layout) : "relative flex min-w-0 overflow-x-auto"),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** The fill and text of each palette entry, written out so the stylesheet build sees them. */
|
|
2
|
+
export declare const CATEGORY_CLASSES: readonly ['bg-(--theme-category-1) text-(--theme-category-1-text)', 'bg-(--theme-category-2) text-(--theme-category-2-text)', 'bg-(--theme-category-3) text-(--theme-category-3-text)', 'bg-(--theme-category-4) text-(--theme-category-4-text)', 'bg-(--theme-category-5) text-(--theme-category-5-text)', 'bg-(--theme-category-6) text-(--theme-category-6-text)', 'bg-(--theme-category-7) text-(--theme-category-7-text)', 'bg-(--theme-category-8) text-(--theme-category-8-text)'];
|
|
3
|
+
/** 32-bit FNV-1a over a string's UTF-8 bytes: cheap, well spread, and the same in any language. */
|
|
4
|
+
export declare function fnv1a(text: string): number;
|
|
5
|
+
/** The palette entry, 1–8, for a key. Case, surrounding space and Unicode composition don't
|
|
6
|
+
* change it, so "Ada Lovelace" and " ada lovelace" match. */
|
|
7
|
+
export declare function categoryOf(key: string): number;
|
|
8
|
+
/** The fill and text classes for a key. */
|
|
9
|
+
export declare function categoryClasses(key: string): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/components/category.ts
|
|
2
|
+
/** The fill and text of each palette entry, written out so the stylesheet build sees them. */
|
|
3
|
+
var CATEGORY_CLASSES = [
|
|
4
|
+
"bg-(--theme-category-1) text-(--theme-category-1-text)",
|
|
5
|
+
"bg-(--theme-category-2) text-(--theme-category-2-text)",
|
|
6
|
+
"bg-(--theme-category-3) text-(--theme-category-3-text)",
|
|
7
|
+
"bg-(--theme-category-4) text-(--theme-category-4-text)",
|
|
8
|
+
"bg-(--theme-category-5) text-(--theme-category-5-text)",
|
|
9
|
+
"bg-(--theme-category-6) text-(--theme-category-6-text)",
|
|
10
|
+
"bg-(--theme-category-7) text-(--theme-category-7-text)",
|
|
11
|
+
"bg-(--theme-category-8) text-(--theme-category-8-text)"
|
|
12
|
+
];
|
|
13
|
+
var encoder = new TextEncoder();
|
|
14
|
+
/** 32-bit FNV-1a over a string's UTF-8 bytes: cheap, well spread, and the same in any language. */
|
|
15
|
+
function fnv1a(text) {
|
|
16
|
+
let hash = 2166136261;
|
|
17
|
+
for (const byte of encoder.encode(text)) hash = Math.imul(hash ^ byte, 16777619);
|
|
18
|
+
return hash >>> 0;
|
|
19
|
+
}
|
|
20
|
+
/** The palette entry, 1–8, for a key. Case, surrounding space and Unicode composition don't
|
|
21
|
+
* change it, so "Ada Lovelace" and " ada lovelace" match. */
|
|
22
|
+
function categoryOf(key) {
|
|
23
|
+
return fnv1a(key.trim().normalize("NFC").toLowerCase()) % CATEGORY_CLASSES.length + 1;
|
|
24
|
+
}
|
|
25
|
+
/** The fill and text classes for a key. */
|
|
26
|
+
function categoryClasses(key) {
|
|
27
|
+
return CATEGORY_CLASSES[categoryOf(key) - 1];
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { CATEGORY_CLASSES, categoryClasses, categoryOf, fnv1a };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface HastElement {
|
|
2
|
+
type: 'element';
|
|
3
|
+
tagName: string;
|
|
4
|
+
properties?: Record<string, unknown>;
|
|
5
|
+
children: HastNode[];
|
|
6
|
+
}
|
|
7
|
+
type HastNode = HastElement | {
|
|
8
|
+
type: string;
|
|
9
|
+
children?: HastNode[];
|
|
10
|
+
};
|
|
11
|
+
export declare function rehypeHttpsImagesOnly(): (tree: HastNode) => void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/components/httpsImages.ts
|
|
2
|
+
function isHttpsUrl(url) {
|
|
3
|
+
if (typeof url !== "string") return false;
|
|
4
|
+
try {
|
|
5
|
+
return new URL(url).protocol === "https:";
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function isHttpsSrcSet(srcSet) {
|
|
11
|
+
return (Array.isArray(srcSet) ? srcSet : [srcSet]).every((entry) => typeof entry === "string" && entry.split(",").every((candidate) => isHttpsUrl(candidate.trim().split(/\s+/)[0])));
|
|
12
|
+
}
|
|
13
|
+
function walk(node) {
|
|
14
|
+
if (node.type === "element") {
|
|
15
|
+
const { tagName, properties } = node;
|
|
16
|
+
if (properties && tagName === "img" && !isHttpsUrl(properties["src"])) delete properties["src"];
|
|
17
|
+
if (properties && (tagName === "img" || tagName === "source") && !isHttpsSrcSet(properties["srcSet"])) delete properties["srcSet"];
|
|
18
|
+
}
|
|
19
|
+
for (const child of node.children ?? []) walk(child);
|
|
20
|
+
}
|
|
21
|
+
function rehypeHttpsImagesOnly() {
|
|
22
|
+
return (tree) => {
|
|
23
|
+
walk(tree);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { rehypeHttpsImagesOnly };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Pins a bar to the top of its scroller, over what scrolls under it.
|
|
2
|
+
* `useStickyTop` moves it below whatever else is pinned there. */
|
|
3
|
+
export declare const stickyClasses = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
|
|
4
|
+
/**
|
|
5
|
+
* Pins a `sticky` element just below whatever its scroller already pins at
|
|
6
|
+
* the top, such as a page header, a toolbar and a tab row, rather than at
|
|
7
|
+
* `top: 0` behind them. It finds them in the page, so neither they nor the
|
|
8
|
+
* host declare anything, and it follows them as they change height (a toolbar
|
|
9
|
+
* wrapping on a narrow screen), move, or come and go, before the browser
|
|
10
|
+
* paints. Chrome that uses it stacks: each piece pins under the ones before
|
|
11
|
+
* it, and its own `top` moving is a change the pieces after it follow.
|
|
12
|
+
* In a box that scrolls on its own, nothing sits above, so it pins at 0.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useStickyTop(el: HTMLElement | null, enabled: boolean): void;
|