@pipelex/mthds-ui 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-F6TZIJ7A.js +1 -0
- package/dist/{chunk-BFQHQQ3E.js → chunk-FD4PKRGZ.js} +40 -1
- package/dist/chunk-FD4PKRGZ.js.map +1 -0
- package/dist/form/index.d.ts +1 -0
- package/dist/form/index.js +3 -0
- package/dist/form/index.js.map +1 -0
- package/dist/form/react/index.d.ts +3 -2
- package/dist/form/react/index.js +4 -0
- package/dist/form/react/index.js.map +1 -1
- package/dist/graph/index.d.ts +68 -3
- package/dist/graph/index.js +6 -2
- package/dist/graph/react/index.css +0 -265
- package/dist/graph/react/index.css.map +1 -1
- package/dist/graph/react/index.d.ts +168 -122
- package/dist/graph/react/index.js +126 -533
- package/dist/graph/react/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -2
- package/dist/standalone/graph-standalone.html +185 -362
- package/dist/standalone/graph-viewer.css +2 -347
- package/dist/standalone/graph-viewer.js +183 -15
- package/dist/static-graph/index.d.ts +1 -1
- package/dist/styles/form-kernel.css +37 -0
- package/dist/{types-Cv5Elty8.d.ts → types-Cn2FttBC.d.ts} +1 -1
- package/package.json +6 -8
- package/dist/chunk-BFQHQQ3E.js.map +0 -1
- package/dist/chunk-QD5YDMWV.js +0 -1
- package/dist/graph/react/stuff/StuffViewer.css +0 -346
- /package/dist/{chunk-QD5YDMWV.js.map → chunk-F6TZIJ7A.js.map} +0 -0
|
@@ -8,13 +8,16 @@ import {
|
|
|
8
8
|
buildGraph,
|
|
9
9
|
buildValidationDecorations,
|
|
10
10
|
findCousinControllers,
|
|
11
|
+
findStuffByDigest,
|
|
11
12
|
getLayoutedElements,
|
|
12
13
|
getPipeBlueprint,
|
|
13
14
|
resolveConceptRef,
|
|
14
15
|
resolveIssueTargetNodeId,
|
|
15
16
|
validateGraphSpec
|
|
16
|
-
} from "../../chunk-
|
|
17
|
-
import
|
|
17
|
+
} from "../../chunk-FD4PKRGZ.js";
|
|
18
|
+
import {
|
|
19
|
+
parsePipeRef
|
|
20
|
+
} from "../../chunk-2N65P32H.js";
|
|
18
21
|
import {
|
|
19
22
|
DEFAULT_GRAPH_CONFIG,
|
|
20
23
|
getPaletteForTheme
|
|
@@ -43,8 +46,8 @@ import {
|
|
|
43
46
|
// src/graph/react/index.ts
|
|
44
47
|
import "./graph-core.css";
|
|
45
48
|
import "./detail/DetailPanel.css";
|
|
46
|
-
import "./stuff/StuffViewer.css";
|
|
47
49
|
import "./viewer/GraphToolbar.css";
|
|
50
|
+
import "../../styles/form-kernel.css";
|
|
48
51
|
|
|
49
52
|
// src/graph/react/viewer/GraphViewer.tsx
|
|
50
53
|
import React10 from "react";
|
|
@@ -101,457 +104,75 @@ function useSystemTheme(injected) {
|
|
|
101
104
|
return React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
// src/graph/react/
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (typeof data !== "object") return null;
|
|
119
|
-
const obj = data;
|
|
120
|
-
const candidates = [obj.public_url, obj.src, obj.href, obj.uri, obj.url];
|
|
121
|
-
for (const candidate of candidates) {
|
|
122
|
-
if (isSafeDisplayUrl(candidate)) return candidate;
|
|
123
|
-
}
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
function extractInlineUrl(data) {
|
|
127
|
-
if (!data) return null;
|
|
128
|
-
if (typeof data === "string") {
|
|
129
|
-
return isInlineRenderableUrl(data) ? data : null;
|
|
130
|
-
}
|
|
131
|
-
if (typeof data !== "object") return null;
|
|
132
|
-
const obj = data;
|
|
133
|
-
const candidates = [obj.public_url, obj.src, obj.href, obj.uri, obj.url];
|
|
134
|
-
for (const candidate of candidates) {
|
|
135
|
-
if (isInlineRenderableUrl(candidate)) return candidate;
|
|
136
|
-
}
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
function extractStorageUri(data) {
|
|
140
|
-
if (!data) return null;
|
|
141
|
-
if (typeof data === "string") {
|
|
142
|
-
return data.startsWith("pipelex-storage://") ? data : null;
|
|
143
|
-
}
|
|
144
|
-
if (typeof data !== "object") return null;
|
|
145
|
-
const obj = data;
|
|
146
|
-
const candidates = [obj.uri, obj.url, obj.src, obj.href];
|
|
147
|
-
for (const candidate of candidates) {
|
|
148
|
-
if (typeof candidate === "string" && candidate.startsWith("pipelex-storage://")) {
|
|
149
|
-
return candidate;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
function extractInnerHtml(data) {
|
|
155
|
-
const fromObject = (obj2) => {
|
|
156
|
-
const value = obj2.inner_html;
|
|
157
|
-
if (typeof value === "string" && value.trim() !== "") return value;
|
|
158
|
-
return null;
|
|
159
|
-
};
|
|
160
|
-
if (!data || typeof data !== "object" || Array.isArray(data)) return null;
|
|
161
|
-
const obj = data;
|
|
162
|
-
const direct = fromObject(obj);
|
|
163
|
-
if (direct != null) return direct;
|
|
164
|
-
for (const value of Object.values(obj)) {
|
|
165
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
166
|
-
const nested = fromObject(value);
|
|
167
|
-
if (nested != null) return nested;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
function extractFilename(data) {
|
|
173
|
-
if (!data || typeof data !== "object") return null;
|
|
174
|
-
const obj = data;
|
|
175
|
-
if (typeof obj.filename === "string" && obj.filename) return obj.filename;
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
function resolveMimeType(data, contentType, url) {
|
|
179
|
-
var _a;
|
|
180
|
-
if (contentType && contentType.includes("/")) return contentType;
|
|
181
|
-
if (data && typeof data === "object") {
|
|
182
|
-
const obj = data;
|
|
183
|
-
if (typeof obj.mime_type === "string" && obj.mime_type) return obj.mime_type;
|
|
184
|
-
}
|
|
185
|
-
const source = extractFilename(data) || url || (typeof data === "string" ? data : null);
|
|
186
|
-
if (source) {
|
|
187
|
-
const match = source.match(/\.([a-zA-Z0-9]+)(?:\?|#|$)/);
|
|
188
|
-
const ext = (_a = match == null ? void 0 : match[1]) == null ? void 0 : _a.toLowerCase();
|
|
189
|
-
if (ext) {
|
|
190
|
-
if (ext === "pdf") return "application/pdf";
|
|
191
|
-
if (["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp"].includes(ext)) {
|
|
192
|
-
return `image/${ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext}`;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
function getHtmlTabLabel(contentType) {
|
|
199
|
-
if (contentType === "application/pdf") return "PDF";
|
|
200
|
-
if (contentType == null ? void 0 : contentType.startsWith("image/")) return "Image";
|
|
201
|
-
return "HTML";
|
|
202
|
-
}
|
|
203
|
-
function findStuffDataByDigest(graphspec, digest) {
|
|
204
|
-
var _a, _b, _c, _d;
|
|
205
|
-
for (const node of graphspec.nodes) {
|
|
206
|
-
for (const output of (_b = (_a = node.io) == null ? void 0 : _a.outputs) != null ? _b : []) {
|
|
207
|
-
if (output.digest === digest) {
|
|
208
|
-
return {
|
|
209
|
-
digest,
|
|
210
|
-
name: output.name,
|
|
211
|
-
concept: output.concept,
|
|
212
|
-
contentType: output.content_type,
|
|
213
|
-
data: output.data,
|
|
214
|
-
dataText: output.data_text,
|
|
215
|
-
dataHtml: output.data_html
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
for (const node of graphspec.nodes) {
|
|
221
|
-
for (const input of (_d = (_c = node.io) == null ? void 0 : _c.inputs) != null ? _d : []) {
|
|
222
|
-
if (input.digest === digest) {
|
|
223
|
-
return {
|
|
224
|
-
digest,
|
|
225
|
-
name: input.name,
|
|
226
|
-
concept: input.concept,
|
|
227
|
-
contentType: input.content_type,
|
|
228
|
-
data: input.data,
|
|
229
|
-
dataText: input.data_text,
|
|
230
|
-
dataHtml: input.data_html
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// src/graph/react/stuff/StuffViewer.tsx
|
|
239
|
-
import React2 from "react";
|
|
240
|
-
import DOMPurify from "dompurify";
|
|
107
|
+
// src/graph/react/detail/StuffResultPanel.tsx
|
|
108
|
+
import * as React2 from "react";
|
|
109
|
+
import {
|
|
110
|
+
buildResultField,
|
|
111
|
+
getPipeInputForm,
|
|
112
|
+
getPipeIOContract,
|
|
113
|
+
getPipeOutputForm
|
|
114
|
+
} from "@pipelex/mthds-form";
|
|
115
|
+
import {
|
|
116
|
+
JsonView,
|
|
117
|
+
ResultEnvProvider,
|
|
118
|
+
StuffViewer,
|
|
119
|
+
useFieldStrings
|
|
120
|
+
} from "@pipelex/mthds-form/react";
|
|
241
121
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
var ICON_LOCAL_FILE = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z" }) });
|
|
247
|
-
function escapeHtml(text) {
|
|
248
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
249
|
-
}
|
|
250
|
-
function downloadBlob(content, filename, mimeType) {
|
|
251
|
-
const blob = new Blob([content], { type: mimeType });
|
|
252
|
-
const url = URL.createObjectURL(blob);
|
|
253
|
-
const link = document.createElement("a");
|
|
254
|
-
link.href = url;
|
|
255
|
-
link.download = filename;
|
|
256
|
-
link.click();
|
|
257
|
-
setTimeout(() => URL.revokeObjectURL(url), 1e4);
|
|
258
|
-
}
|
|
259
|
-
function downloadUrl(url, filename) {
|
|
260
|
-
const link = document.createElement("a");
|
|
261
|
-
link.href = url;
|
|
262
|
-
link.download = filename;
|
|
263
|
-
link.target = "_blank";
|
|
264
|
-
link.click();
|
|
265
|
-
}
|
|
266
|
-
function StuffViewer({
|
|
122
|
+
function StuffResultPanel({
|
|
123
|
+
contracts,
|
|
124
|
+
outputForm,
|
|
125
|
+
inputForm,
|
|
267
126
|
stuff,
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
127
|
+
producerPipeRef,
|
|
128
|
+
consumer,
|
|
129
|
+
resolveUrl,
|
|
130
|
+
resolveShareUrl
|
|
272
131
|
}) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const storageUri = React2.useMemo(() => extractStorageUri(stuff.data), [stuff.data]);
|
|
280
|
-
const filename = React2.useMemo(() => extractFilename(stuff.data), [stuff.data]);
|
|
281
|
-
const innerHtml = React2.useMemo(() => extractInnerHtml(stuff.data), [stuff.data]);
|
|
282
|
-
const [resolvedStorageUrl, setResolvedStorageUrl] = React2.useState(null);
|
|
283
|
-
React2.useEffect(() => {
|
|
284
|
-
setResolvedStorageUrl(null);
|
|
285
|
-
if (!storageUri || !resolveStorageUrl || httpInlineUrl) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
let cancelled = false;
|
|
289
|
-
resolveStorageUrl(storageUri).then((url) => {
|
|
290
|
-
if (cancelled) return;
|
|
291
|
-
setResolvedStorageUrl(isInlineRenderableUrl(url) ? url : null);
|
|
292
|
-
}).catch(() => {
|
|
293
|
-
if (!cancelled) setResolvedStorageUrl(null);
|
|
294
|
-
});
|
|
295
|
-
return () => {
|
|
296
|
-
cancelled = true;
|
|
297
|
-
};
|
|
298
|
-
}, [storageUri, resolveStorageUrl, httpInlineUrl]);
|
|
299
|
-
const inlineUrl = httpInlineUrl != null ? httpInlineUrl : resolvedStorageUrl;
|
|
300
|
-
const externalUrl = httpExternalUrl != null ? httpExternalUrl : resolvedStorageUrl;
|
|
301
|
-
const effectiveMime = React2.useMemo(
|
|
302
|
-
() => resolveMimeType(stuff.data, stuff.contentType, externalUrl != null ? externalUrl : storageUri),
|
|
303
|
-
[stuff.data, stuff.contentType, externalUrl, storageUri]
|
|
132
|
+
const field = React2.useMemo(
|
|
133
|
+
() => {
|
|
134
|
+
var _a;
|
|
135
|
+
return (_a = fromProducer(contracts, outputForm, producerPipeRef)) != null ? _a : fromConsumer(contracts, inputForm, consumer);
|
|
136
|
+
},
|
|
137
|
+
[contracts, outputForm, inputForm, producerPipeRef, consumer]
|
|
304
138
|
);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const { jsonString, jsonError } = React2.useMemo(() => {
|
|
309
|
-
if (stuff.data == null) return { jsonString: null, jsonError: null };
|
|
310
|
-
try {
|
|
311
|
-
return { jsonString: JSON.stringify(stuff.data, null, 2), jsonError: null };
|
|
312
|
-
} catch (err) {
|
|
313
|
-
return { jsonString: null, jsonError: err instanceof Error ? err.message : String(err) };
|
|
314
|
-
}
|
|
315
|
-
}, [stuff.data]);
|
|
316
|
-
React2.useEffect(() => {
|
|
317
|
-
if (activeTab !== "html" || !contentRef.current) return;
|
|
318
|
-
contentRef.current.querySelectorAll("a").forEach((link) => {
|
|
319
|
-
link.setAttribute("target", "_blank");
|
|
320
|
-
link.setAttribute("rel", "noopener noreferrer");
|
|
321
|
-
});
|
|
322
|
-
}, [activeTab, stuff.dataHtml]);
|
|
323
|
-
function renderMediaFallback(mediaLabel) {
|
|
324
|
-
const displayName = filename || stuff.name;
|
|
325
|
-
return /* @__PURE__ */ jsxs("div", { className: "stuff-viewer-local-file", children: [
|
|
326
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-local-file-icon", children: ICON_LOCAL_FILE }),
|
|
327
|
-
/* @__PURE__ */ jsxs("div", { className: "stuff-viewer-local-file-info", children: [
|
|
328
|
-
displayName && /* @__PURE__ */ jsx("div", { className: "stuff-viewer-local-file-name", children: displayName }),
|
|
329
|
-
/* @__PURE__ */ jsxs("div", { className: "stuff-viewer-local-file-hint", children: [
|
|
330
|
-
mediaLabel,
|
|
331
|
-
" \u2014 no preview available"
|
|
332
|
-
] })
|
|
333
|
-
] })
|
|
334
|
-
] });
|
|
335
|
-
}
|
|
336
|
-
function renderJsonError(detail) {
|
|
337
|
-
return /* @__PURE__ */ jsxs("div", { className: "stuff-viewer-error", role: "alert", children: [
|
|
338
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-error-title", children: "Unable to serialize data" }),
|
|
339
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-error-detail", children: detail })
|
|
340
|
-
] });
|
|
341
|
-
}
|
|
342
|
-
function renderContent() {
|
|
343
|
-
var _a2;
|
|
344
|
-
if (activeTab === "html") {
|
|
345
|
-
if (isPdf) {
|
|
346
|
-
const canEmbed = canEmbedPdf !== false;
|
|
347
|
-
if (canEmbed && inlineUrl) {
|
|
348
|
-
const pdfUrl = inlineUrl.includes("#") ? inlineUrl : `${inlineUrl}#pagemode=none`;
|
|
349
|
-
return /* @__PURE__ */ jsx("div", { className: "stuff-viewer-pdf", children: /* @__PURE__ */ jsx("embed", { src: pdfUrl, type: "application/pdf" }) });
|
|
350
|
-
}
|
|
351
|
-
if (externalUrl) {
|
|
352
|
-
const displayName = filename || stuff.name;
|
|
353
|
-
return /* @__PURE__ */ jsxs(
|
|
354
|
-
"button",
|
|
355
|
-
{
|
|
356
|
-
type: "button",
|
|
357
|
-
className: "stuff-viewer-local-file stuff-viewer-local-file--button",
|
|
358
|
-
onClick: handleOpenExternal,
|
|
359
|
-
children: [
|
|
360
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-local-file-icon", children: ICON_LOCAL_FILE }),
|
|
361
|
-
/* @__PURE__ */ jsxs("div", { className: "stuff-viewer-local-file-info", children: [
|
|
362
|
-
displayName && /* @__PURE__ */ jsx("div", { className: "stuff-viewer-local-file-name", children: displayName }),
|
|
363
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-local-file-hint", children: "Click to open PDF externally" })
|
|
364
|
-
] })
|
|
365
|
-
]
|
|
366
|
-
}
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
return renderMediaFallback("PDF");
|
|
370
|
-
}
|
|
371
|
-
if (isImage) {
|
|
372
|
-
if (inlineUrl) {
|
|
373
|
-
return /* @__PURE__ */ jsx("div", { className: "stuff-viewer-image", children: /* @__PURE__ */ jsx("img", { src: inlineUrl, alt: (_a2 = stuff.name) != null ? _a2 : "(unnamed stuff)" }) });
|
|
374
|
-
}
|
|
375
|
-
return renderMediaFallback("Image");
|
|
376
|
-
}
|
|
377
|
-
if (innerHtml != null) {
|
|
378
|
-
return /* @__PURE__ */ jsx(
|
|
379
|
-
"iframe",
|
|
380
|
-
{
|
|
381
|
-
className: "stuff-viewer-html-frame",
|
|
382
|
-
title: stuff.name ? `${stuff.name} preview` : "HTML preview",
|
|
383
|
-
sandbox: "",
|
|
384
|
-
srcDoc: DOMPurify.sanitize(innerHtml, { WHOLE_DOCUMENT: true })
|
|
385
|
-
}
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
if (stuff.dataHtml) {
|
|
389
|
-
return /* @__PURE__ */ jsx(
|
|
390
|
-
"div",
|
|
391
|
-
{
|
|
392
|
-
className: "stuff-viewer-html",
|
|
393
|
-
dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(stuff.dataHtml) }
|
|
394
|
-
}
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
if (jsonString) {
|
|
398
|
-
return /* @__PURE__ */ jsx(
|
|
399
|
-
"pre",
|
|
400
|
-
{
|
|
401
|
-
className: "stuff-viewer-pre",
|
|
402
|
-
dangerouslySetInnerHTML: { __html: escapeHtml(jsonString) }
|
|
403
|
-
}
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
if (jsonError) return renderJsonError(jsonError);
|
|
407
|
-
return /* @__PURE__ */ jsx("div", { className: "stuff-viewer-placeholder", children: "No content available" });
|
|
408
|
-
}
|
|
409
|
-
if (activeTab === "json") {
|
|
410
|
-
if (jsonString) {
|
|
411
|
-
return /* @__PURE__ */ jsx(
|
|
412
|
-
"pre",
|
|
413
|
-
{
|
|
414
|
-
className: "stuff-viewer-pre",
|
|
415
|
-
dangerouslySetInnerHTML: { __html: escapeHtml(jsonString) }
|
|
416
|
-
}
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
if (jsonError) return renderJsonError(jsonError);
|
|
420
|
-
return /* @__PURE__ */ jsx("div", { className: "stuff-viewer-placeholder", children: "No JSON data available" });
|
|
421
|
-
}
|
|
422
|
-
if (stuff.dataText) {
|
|
423
|
-
return /* @__PURE__ */ jsx(
|
|
424
|
-
"pre",
|
|
425
|
-
{
|
|
426
|
-
className: "stuff-viewer-pre stuff-viewer-pre--nowrap",
|
|
427
|
-
dangerouslySetInnerHTML: { __html: escapeHtml(stuff.dataText) }
|
|
428
|
-
}
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
if (jsonString) {
|
|
432
|
-
return /* @__PURE__ */ jsx(
|
|
433
|
-
"pre",
|
|
434
|
-
{
|
|
435
|
-
className: "stuff-viewer-pre",
|
|
436
|
-
dangerouslySetInnerHTML: { __html: escapeHtml(jsonString) }
|
|
437
|
-
}
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
if (jsonError) return renderJsonError(jsonError);
|
|
441
|
-
return /* @__PURE__ */ jsx("div", { className: "stuff-viewer-placeholder", children: "No text data available" });
|
|
442
|
-
}
|
|
443
|
-
function handleCopy() {
|
|
444
|
-
let textToCopy;
|
|
445
|
-
if (activeTab === "json") {
|
|
446
|
-
textToCopy = jsonString || "";
|
|
447
|
-
} else if (activeTab === "text") {
|
|
448
|
-
textToCopy = stuff.dataText || jsonString || "";
|
|
449
|
-
} else {
|
|
450
|
-
textToCopy = innerHtml || stuff.dataText || stuff.dataHtml || jsonString || "";
|
|
451
|
-
}
|
|
452
|
-
if (!textToCopy) return;
|
|
453
|
-
if (navigator.clipboard) {
|
|
454
|
-
navigator.clipboard.writeText(textToCopy).then(() => {
|
|
455
|
-
setCopied(true);
|
|
456
|
-
setTimeout(() => setCopied(false), 1500);
|
|
457
|
-
}).catch(() => {
|
|
458
|
-
});
|
|
459
|
-
}
|
|
139
|
+
if (field) {
|
|
140
|
+
const panel = /* @__PURE__ */ jsx(StuffViewer, { field, value: stuff.data });
|
|
141
|
+
return resolveUrl || resolveShareUrl ? /* @__PURE__ */ jsx(ResultEnvProvider, { resolveUrl, resolveShareUrl, children: panel }) : panel;
|
|
460
142
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
downloadUrl(externalUrl, `${stuff.name || "stuff"}.pdf`);
|
|
469
|
-
return;
|
|
470
|
-
}
|
|
471
|
-
if (activeTab === "json") {
|
|
472
|
-
downloadBlob(jsonString || "{}", `${stuff.name || "stuff"}.json`, "application/json");
|
|
473
|
-
} else if (activeTab === "text") {
|
|
474
|
-
downloadBlob(
|
|
475
|
-
stuff.dataText || jsonString || "",
|
|
476
|
-
`${stuff.name || "stuff"}.txt`,
|
|
477
|
-
"text/plain"
|
|
478
|
-
);
|
|
479
|
-
} else {
|
|
480
|
-
downloadBlob(
|
|
481
|
-
innerHtml || stuff.dataHtml || jsonString || "",
|
|
482
|
-
`${stuff.name || "stuff"}.html`,
|
|
483
|
-
"text/html"
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
function handleOpenExternal() {
|
|
488
|
-
if (!externalUrl) return;
|
|
489
|
-
if (onOpenExternally) {
|
|
490
|
-
onOpenExternally(externalUrl, filename != null ? filename : void 0);
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
window.open(externalUrl, "_blank", "noopener,noreferrer");
|
|
494
|
-
}
|
|
495
|
-
const rootClass = ["stuff-viewer", className].filter(Boolean).join(" ");
|
|
496
|
-
return /* @__PURE__ */ jsxs("div", { className: rootClass, children: [
|
|
497
|
-
/* @__PURE__ */ jsxs("div", { className: "stuff-viewer-header", children: [
|
|
498
|
-
/* @__PURE__ */ jsx("h3", { className: "stuff-viewer-title", children: (_b = stuff.name) != null ? _b : "(unnamed stuff)" }),
|
|
499
|
-
stuff.concept && /* @__PURE__ */ jsx("p", { className: "stuff-viewer-subtitle", children: stuff.concept })
|
|
500
|
-
] }),
|
|
501
|
-
/* @__PURE__ */ jsxs("div", { className: "stuff-viewer-toolbar", children: [
|
|
502
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-tabs", children: ["html", "json", "text"].map((tab) => {
|
|
503
|
-
const label = tab === "html" ? htmlTabLabel : tab === "json" ? "JSON" : "Pretty";
|
|
504
|
-
const isActive = activeTab === tab;
|
|
505
|
-
return /* @__PURE__ */ jsx(
|
|
506
|
-
"button",
|
|
507
|
-
{
|
|
508
|
-
type: "button",
|
|
509
|
-
className: `stuff-viewer-tab${isActive ? " stuff-viewer-tab--active" : ""}`,
|
|
510
|
-
onClick: () => setActiveTab(tab),
|
|
511
|
-
children: label
|
|
512
|
-
},
|
|
513
|
-
tab
|
|
514
|
-
);
|
|
515
|
-
}) }),
|
|
516
|
-
/* @__PURE__ */ jsxs("div", { className: "stuff-viewer-actions", children: [
|
|
517
|
-
externalUrl && /* @__PURE__ */ jsx(
|
|
518
|
-
"button",
|
|
519
|
-
{
|
|
520
|
-
type: "button",
|
|
521
|
-
className: "stuff-viewer-action-btn",
|
|
522
|
-
onClick: handleOpenExternal,
|
|
523
|
-
title: "Open in new window",
|
|
524
|
-
"aria-label": "Open in new window",
|
|
525
|
-
children: ICON_EXTERNAL
|
|
526
|
-
}
|
|
527
|
-
),
|
|
528
|
-
/* @__PURE__ */ jsx(
|
|
529
|
-
"button",
|
|
530
|
-
{
|
|
531
|
-
type: "button",
|
|
532
|
-
className: `stuff-viewer-action-btn${copied ? " stuff-viewer-action-btn--copied" : ""}`,
|
|
533
|
-
onClick: handleCopy,
|
|
534
|
-
title: "Copy",
|
|
535
|
-
"aria-label": "Copy",
|
|
536
|
-
children: copied ? ICON_CHECK : ICON_COPY
|
|
537
|
-
}
|
|
538
|
-
),
|
|
539
|
-
/* @__PURE__ */ jsx(
|
|
540
|
-
"button",
|
|
541
|
-
{
|
|
542
|
-
type: "button",
|
|
543
|
-
className: "stuff-viewer-action-btn",
|
|
544
|
-
onClick: handleDownload,
|
|
545
|
-
title: "Download",
|
|
546
|
-
"aria-label": "Download",
|
|
547
|
-
children: ICON_DOWNLOAD
|
|
548
|
-
}
|
|
549
|
-
)
|
|
550
|
-
] })
|
|
551
|
-
] }),
|
|
552
|
-
/* @__PURE__ */ jsx("div", { className: "stuff-viewer-content", ref: contentRef, children: renderContent() })
|
|
143
|
+
return stuff.data === void 0 || stuff.data === null ? null : /* @__PURE__ */ jsx(UndescribedValue, { value: stuff.data });
|
|
144
|
+
}
|
|
145
|
+
function UndescribedValue({ value }) {
|
|
146
|
+
const s = useFieldStrings();
|
|
147
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
148
|
+
/* @__PURE__ */ jsx("p", { className: "text-[12px] text-muted-foreground", children: s.resultUndescribed }),
|
|
149
|
+
/* @__PURE__ */ jsx(JsonView, { value })
|
|
553
150
|
] });
|
|
554
151
|
}
|
|
152
|
+
function fromProducer(contracts, outputForm, producerPipeRef) {
|
|
153
|
+
if (!producerPipeRef) return null;
|
|
154
|
+
const parsed = parsePipeRef(producerPipeRef);
|
|
155
|
+
if (!(parsed == null ? void 0 : parsed.domainPath)) return null;
|
|
156
|
+
const descriptor = getPipeOutputForm(outputForm, parsed.domainPath, parsed.pipeCode);
|
|
157
|
+
const contract = getPipeIOContract(contracts, parsed.domainPath, parsed.pipeCode);
|
|
158
|
+
if (!descriptor || !contract) return null;
|
|
159
|
+
return buildResultField(descriptor, contract.output.json_schema);
|
|
160
|
+
}
|
|
161
|
+
function fromConsumer(contracts, inputForm, consumer) {
|
|
162
|
+
if (!inputForm || !consumer) return null;
|
|
163
|
+
const parsed = parsePipeRef(consumer.pipeRef);
|
|
164
|
+
if (!(parsed == null ? void 0 : parsed.domainPath)) return null;
|
|
165
|
+
const descriptor = getPipeInputForm(inputForm, parsed.domainPath, parsed.pipeCode);
|
|
166
|
+
const contract = getPipeIOContract(contracts, parsed.domainPath, parsed.pipeCode);
|
|
167
|
+
if (!descriptor || !contract) return null;
|
|
168
|
+
const slot = contract.inputs[consumer.slotName];
|
|
169
|
+
if (!slot || slot.multiplicity !== "single") return null;
|
|
170
|
+
const node = descriptor.fields.find(
|
|
171
|
+
(candidate) => candidate.name === consumer.slotName
|
|
172
|
+
);
|
|
173
|
+
if (!node) return null;
|
|
174
|
+
return buildResultField({ field: node }, slot.json_schema);
|
|
175
|
+
}
|
|
555
176
|
|
|
556
177
|
// src/graph/react/detail/DetailPanel.tsx
|
|
557
178
|
import React3 from "react";
|
|
@@ -1689,9 +1310,7 @@ function ConceptDetailPanel({
|
|
|
1689
1310
|
concept,
|
|
1690
1311
|
ioData,
|
|
1691
1312
|
isDryRun,
|
|
1692
|
-
|
|
1693
|
-
canEmbedPdf,
|
|
1694
|
-
onOpenExternally,
|
|
1313
|
+
renderData,
|
|
1695
1314
|
instanceKey
|
|
1696
1315
|
}) {
|
|
1697
1316
|
var _a;
|
|
@@ -1711,23 +1330,15 @@ function ConceptDetailPanel({
|
|
|
1711
1330
|
concept,
|
|
1712
1331
|
ioData,
|
|
1713
1332
|
isDryRun,
|
|
1714
|
-
|
|
1715
|
-
canEmbedPdf,
|
|
1716
|
-
onOpenExternally
|
|
1333
|
+
renderData
|
|
1717
1334
|
},
|
|
1718
1335
|
instanceKey != null ? instanceKey : `${concept.code}:${ioData && "digest" in ioData ? ioData.digest : (_a = ioData == null ? void 0 : ioData.name) != null ? _a : ""}`
|
|
1719
1336
|
)
|
|
1720
1337
|
] });
|
|
1721
1338
|
}
|
|
1722
|
-
function ConceptBody({
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
isDryRun,
|
|
1726
|
-
resolveStorageUrl,
|
|
1727
|
-
canEmbedPdf,
|
|
1728
|
-
onOpenExternally
|
|
1729
|
-
}) {
|
|
1730
|
-
const hasData = Boolean(ioData) && !isDryRun;
|
|
1339
|
+
function ConceptBody({ concept, ioData, isDryRun, renderData }) {
|
|
1340
|
+
const dataView = ioData && !isDryRun ? renderData == null ? void 0 : renderData() : void 0;
|
|
1341
|
+
const hasData = Boolean(dataView);
|
|
1731
1342
|
const [activeTab, setActiveTab] = React7.useState(hasData ? "data" : "structure");
|
|
1732
1343
|
const baseId = React7.useId();
|
|
1733
1344
|
const tabId = (tab) => `${baseId}-tab-${tab}`;
|
|
@@ -1778,15 +1389,7 @@ function ConceptBody({
|
|
|
1778
1389
|
renderTab("data", "Data"),
|
|
1779
1390
|
renderTab("structure", "Structure")
|
|
1780
1391
|
] }),
|
|
1781
|
-
/* @__PURE__ */ jsx16("div", { role: "tabpanel", id: panelId(activeTab), "aria-labelledby": tabId(activeTab), children: activeTab === "data" ?
|
|
1782
|
-
StuffViewer,
|
|
1783
|
-
{
|
|
1784
|
-
stuff: toStuffViewerData(ioData),
|
|
1785
|
-
resolveStorageUrl,
|
|
1786
|
-
canEmbedPdf,
|
|
1787
|
-
onOpenExternally
|
|
1788
|
-
}
|
|
1789
|
-
) : structure })
|
|
1392
|
+
/* @__PURE__ */ jsx16("div", { role: "tabpanel", id: panelId(activeTab), "aria-labelledby": tabId(activeTab), children: activeTab === "data" ? dataView : structure })
|
|
1790
1393
|
] });
|
|
1791
1394
|
}
|
|
1792
1395
|
function SchemaTable({ schema }) {
|
|
@@ -1827,22 +1430,6 @@ function extractType(schema) {
|
|
|
1827
1430
|
}
|
|
1828
1431
|
return "(unresolved type)";
|
|
1829
1432
|
}
|
|
1830
|
-
function toStuffViewerData(ioData) {
|
|
1831
|
-
var _a;
|
|
1832
|
-
if (isStuffViewerData(ioData)) return ioData;
|
|
1833
|
-
return {
|
|
1834
|
-
digest: (_a = ioData.digest) != null ? _a : "",
|
|
1835
|
-
name: ioData.name,
|
|
1836
|
-
concept: ioData.concept,
|
|
1837
|
-
contentType: ioData.content_type,
|
|
1838
|
-
data: ioData.data,
|
|
1839
|
-
dataText: ioData.data_text,
|
|
1840
|
-
dataHtml: ioData.data_html
|
|
1841
|
-
};
|
|
1842
|
-
}
|
|
1843
|
-
function isStuffViewerData(ioData) {
|
|
1844
|
-
return "contentType" in ioData || "dataText" in ioData || "dataHtml" in ioData;
|
|
1845
|
-
}
|
|
1846
1433
|
|
|
1847
1434
|
// src/graph/react/rfTypes.ts
|
|
1848
1435
|
function toAppNodes(nodes) {
|
|
@@ -2893,36 +2480,44 @@ var nodeTypes = __spreadProps(__spreadValues({}, controllerNodeTypes), {
|
|
|
2893
2480
|
function StuffNodeDetail({
|
|
2894
2481
|
nodeId,
|
|
2895
2482
|
stuffData,
|
|
2483
|
+
producerPipeRef,
|
|
2484
|
+
consumer,
|
|
2896
2485
|
graphspec,
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2486
|
+
theme,
|
|
2487
|
+
contracts,
|
|
2488
|
+
outputForm,
|
|
2489
|
+
inputForm,
|
|
2490
|
+
resolveUrl,
|
|
2491
|
+
resolveShareUrl
|
|
2900
2492
|
}) {
|
|
2493
|
+
var _a;
|
|
2901
2494
|
const conceptInfo = stuffData.concept && graphspec ? resolveConceptRef(graphspec, stuffData.concept) : void 0;
|
|
2902
2495
|
const isDryRun = graphSpecMode(graphspec) === GRAPH_SPEC_MODE.DRY;
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
{
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
/*
|
|
2916
|
-
|
|
2917
|
-
StuffViewer,
|
|
2496
|
+
const renderData = contracts && outputForm ? () => /* @__PURE__ */ jsx24(
|
|
2497
|
+
StuffResultPanel,
|
|
2498
|
+
__spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadProps(__spreadValues({
|
|
2499
|
+
contracts,
|
|
2500
|
+
outputForm
|
|
2501
|
+
}, inputForm ? { inputForm } : {}), {
|
|
2502
|
+
stuff: stuffData
|
|
2503
|
+
}), conceptInfo ? { concept: conceptInfo } : {}), producerPipeRef ? { producerPipeRef } : {}), consumer ? { consumer } : {}), resolveUrl ? { resolveUrl } : {}), resolveShareUrl ? { resolveShareUrl } : {}), {
|
|
2504
|
+
theme
|
|
2505
|
+
})
|
|
2506
|
+
) : void 0;
|
|
2507
|
+
if (conceptInfo) {
|
|
2508
|
+
return /* @__PURE__ */ jsx24(
|
|
2509
|
+
ConceptDetailPanel,
|
|
2918
2510
|
{
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2511
|
+
concept: conceptInfo,
|
|
2512
|
+
ioData: stuffData,
|
|
2513
|
+
isDryRun,
|
|
2514
|
+
instanceKey: nodeId,
|
|
2515
|
+
renderData
|
|
2923
2516
|
}
|
|
2924
|
-
)
|
|
2925
|
-
|
|
2517
|
+
);
|
|
2518
|
+
}
|
|
2519
|
+
if (isDryRun) return /* @__PURE__ */ jsx24("div", { className: "detail-not-available", children: "Dry run data hidden" });
|
|
2520
|
+
return /* @__PURE__ */ jsx24(Fragment14, { children: (_a = renderData == null ? void 0 : renderData()) != null ? _a : /* @__PURE__ */ jsx24("div", { className: "detail-not-available", children: "No data" }) });
|
|
2926
2521
|
}
|
|
2927
2522
|
function seedFoldedControllers(mode, controllerIds) {
|
|
2928
2523
|
if (mode === FOLD_MODE.FOLDED) return new Set(controllerIds);
|
|
@@ -2989,9 +2584,11 @@ function GraphViewer(props) {
|
|
|
2989
2584
|
onNodeSelect,
|
|
2990
2585
|
onPaneClick,
|
|
2991
2586
|
renderDetailExtra,
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2587
|
+
contracts,
|
|
2588
|
+
outputForm,
|
|
2589
|
+
inputForm,
|
|
2590
|
+
resolveUrl,
|
|
2591
|
+
resolveShareUrl,
|
|
2995
2592
|
validationState,
|
|
2996
2593
|
validationIssues,
|
|
2997
2594
|
onValidationIssueClick
|
|
@@ -3492,9 +3089,8 @@ function GraphViewer(props) {
|
|
|
3492
3089
|
onNavigateToPipe(code, (_a2 = nodeData.pipeCardData) == null ? void 0 : _a2.status);
|
|
3493
3090
|
}
|
|
3494
3091
|
} else if (nodeData.isStuff && onStuffNodeClick && graphspec) {
|
|
3495
|
-
const
|
|
3496
|
-
|
|
3497
|
-
if (sd) onStuffNodeClick(sd);
|
|
3092
|
+
const found = findStuffByDigest(graphspec, stuffDigestFromId(node.id));
|
|
3093
|
+
if (found) onStuffNodeClick(found.item);
|
|
3498
3094
|
}
|
|
3499
3095
|
setConceptOverride(null);
|
|
3500
3096
|
if ((detailSelection == null ? void 0 : detailSelection.nodeId) === node.id && !conceptOverride) {
|
|
@@ -3502,13 +3098,14 @@ function GraphViewer(props) {
|
|
|
3502
3098
|
} else if (nodeData.isPipe || nodeData.isController) {
|
|
3503
3099
|
setDetailSelection({ kind: "pipe", nodeId: node.id, nodeData });
|
|
3504
3100
|
} else if (nodeData.isStuff && graphspec) {
|
|
3505
|
-
const
|
|
3506
|
-
const sd = findStuffDataByDigest(graphspec, digest);
|
|
3101
|
+
const found = findStuffByDigest(graphspec, stuffDigestFromId(node.id));
|
|
3507
3102
|
setDetailSelection({
|
|
3508
3103
|
kind: "stuff",
|
|
3509
3104
|
nodeId: node.id,
|
|
3510
3105
|
nodeData,
|
|
3511
|
-
stuffData:
|
|
3106
|
+
stuffData: found == null ? void 0 : found.item,
|
|
3107
|
+
producerPipeRef: found == null ? void 0 : found.producerPipeRef,
|
|
3108
|
+
consumer: found == null ? void 0 : found.consumer
|
|
3512
3109
|
});
|
|
3513
3110
|
}
|
|
3514
3111
|
setNodes((nds) => nds.map((n) => __spreadProps(__spreadValues({}, n), { selected: n.id === node.id })));
|
|
@@ -3661,10 +3258,15 @@ function GraphViewer(props) {
|
|
|
3661
3258
|
{
|
|
3662
3259
|
nodeId: detailSelection.nodeId,
|
|
3663
3260
|
stuffData: detailSelection.stuffData,
|
|
3261
|
+
producerPipeRef: detailSelection.producerPipeRef,
|
|
3262
|
+
consumer: detailSelection.consumer,
|
|
3664
3263
|
graphspec,
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3264
|
+
theme: resolvedTheme,
|
|
3265
|
+
contracts,
|
|
3266
|
+
outputForm,
|
|
3267
|
+
inputForm,
|
|
3268
|
+
resolveUrl,
|
|
3269
|
+
resolveShareUrl
|
|
3668
3270
|
}
|
|
3669
3271
|
) : null,
|
|
3670
3272
|
renderDetailExtra && detailSelection && !conceptOverride && renderDetailExtra(detailSelection.nodeId, detailSelection.nodeData)
|
|
@@ -3683,22 +3285,13 @@ export {
|
|
|
3683
3285
|
PipeCardBase,
|
|
3684
3286
|
PipeCardNode,
|
|
3685
3287
|
PipeDetailPanel,
|
|
3686
|
-
|
|
3288
|
+
StuffResultPanel,
|
|
3687
3289
|
ValidationPanel,
|
|
3688
3290
|
applyStatusOverrides,
|
|
3689
3291
|
controllerNodeTypes,
|
|
3690
3292
|
detectSystemTheme,
|
|
3691
|
-
extractFilename,
|
|
3692
|
-
extractInlineUrl,
|
|
3693
|
-
extractStorageUri,
|
|
3694
|
-
extractUrl,
|
|
3695
|
-
findStuffDataByDigest,
|
|
3696
|
-
getHtmlTabLabel,
|
|
3697
3293
|
hydrateLabels,
|
|
3698
|
-
isInlineRenderableUrl,
|
|
3699
|
-
isSafeDisplayUrl,
|
|
3700
3294
|
renderLabel,
|
|
3701
|
-
resolveMimeType,
|
|
3702
3295
|
toAppEdges,
|
|
3703
3296
|
toAppNodes,
|
|
3704
3297
|
useResizable,
|