@burdenoff/fluidgrids-fe-sdk 2026.1028.6 → 2026.1028.8
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/ExecutionDetailPage-ACTSQG5E.js +20 -0
- package/dist/{ExecutionsListPage-IMN7OTNZ.js → ExecutionsListPage-FABXLXWT.js} +8 -8
- package/dist/WorkflowBuilder-OECFTQDQ.js +24 -0
- package/dist/WorkflowsList-4HG3KBMR.js +20 -0
- package/dist/{chunk-IQE7ZY6Q.js → chunk-2ZV6UJD6.js} +2 -2
- package/dist/{chunk-F6NH55LU.js → chunk-3GOZYLTM.js} +3 -3
- package/dist/{chunk-ACUNTZTQ.js → chunk-3LYRZ4KN.js} +3 -3
- package/dist/{chunk-MKKBEVXO.js → chunk-6T5EBO7G.js} +1 -1
- package/dist/chunk-77NA7TPJ.js +38 -0
- package/dist/{chunk-QW24ZBSR.js → chunk-7OJDILWM.js} +1 -1
- package/dist/{chunk-6J4RR46J.js → chunk-7PBOU7JC.js} +2 -1
- package/dist/{chunk-NAFJQGLV.js → chunk-DL2OCKHC.js} +5 -5
- package/dist/{chunk-LOZ6XNOX.js → chunk-DOPSPCO3.js} +26 -1
- package/dist/{chunk-FO22JCOW.js → chunk-EAF47LYM.js} +368 -103
- package/dist/{chunk-XZPXIOGE.js → chunk-GGINSR75.js} +1402 -7
- package/dist/{chunk-FDEZGRRL.js → chunk-GQQV2L74.js} +1 -1
- package/dist/{chunk-UWNYWWWG.js → chunk-ILTWXDRG.js} +4 -4
- package/dist/{chunk-VP2RXXRF.js → chunk-J3PETXDA.js} +7 -7
- package/dist/{chunk-WBH2XEWO.js → chunk-JUUYPCFY.js} +4 -1
- package/dist/chunk-M62CJVTR.js +458 -0
- package/dist/{chunk-C4AY6JI2.js → chunk-NVUJFHTQ.js} +2 -2
- package/dist/{chunk-A2JSAGNQ.js → chunk-OAFNNQN7.js} +1 -1
- package/dist/{chunk-RLA4YUDY.js → chunk-OYFBLD5F.js} +3 -3
- package/dist/{chunk-STPQQDIJ.js → chunk-QBEQOQF7.js} +867 -127
- package/dist/{chunk-3KNW5QLR.js → chunk-SQ6VSXFI.js} +2 -2
- package/dist/chunk-TX6WIT3N.js +749 -0
- package/dist/{chunk-I2ZNBBRK.js → chunk-VFPIMW52.js} +3 -14
- package/dist/{chunk-VQHBQAJY.js → chunk-VZHR7FCD.js} +3 -3
- package/dist/{chunk-3VJ3AIFS.js → chunk-YNOR2AGJ.js} +2 -2
- package/dist/{chunk-RZQPHWFV.js → chunk-YQZ7HBOJ.js} +5 -3
- package/dist/{chunk-Q22GC7RJ.js → chunk-ZFCXCSY4.js} +1 -1
- package/dist/executions.js +13 -13
- package/dist/global-operations-D2USVOPM.js +2 -0
- package/dist/history.js +5 -5
- package/dist/index.d.ts +1294 -57
- package/dist/index.js +37 -35
- package/dist/nodes.js +2 -2
- package/dist/observability.js +8 -7
- package/dist/settings.js +8 -6
- package/dist/templates.js +12 -10
- package/dist/{workflow-builder-C7qKY7LD.d.ts → workflow-builder-BxyapBo5.d.ts} +18 -0
- package/dist/workflow-builder.d.ts +1 -1
- package/dist/workflow-builder.js +14 -12
- package/dist/workflows-list.js +10 -8
- package/package.json +1 -1
- package/dist/ExecutionDetailPage-DHIQNBAZ.js +0 -20
- package/dist/WorkflowBuilder-VJAAKETX.js +0 -22
- package/dist/WorkflowsList-3EWDWWIH.js +0 -18
- package/dist/chunk-HHN2TIK2.js +0 -59
- package/dist/global-operations-ZWQZ7DNT.js +0 -2
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { CreateWorkflowRefusalDialog, firstWorkflowProgress, GUIDED_TOUR_STATE, builderPathFor } from './chunk-
|
|
2
|
-
import { useExecutions } from './chunk-
|
|
3
|
-
import { QuotaExhaustedDialog } from './chunk-
|
|
4
|
-
import { useCreateWorkflow, useWorkflowDefinitions, useLazyWorkflowDefinition, useImportWorkflow, useDuplicateWorkflow, useDeleteWorkflow } from './chunk-
|
|
1
|
+
import { CreateWorkflowRefusalDialog, firstWorkflowProgress, GUIDED_TOUR_STATE, builderPathFor } from './chunk-OAFNNQN7.js';
|
|
2
|
+
import { useExecutions } from './chunk-YNOR2AGJ.js';
|
|
3
|
+
import { useExportWorkflowAs, downloadWorkflowExport, importAcceptAttribute, QuotaExhaustedDialog, importFileKind, parseWorkflowImport, CODE_EXPORT_FORMATS, ImportSourceError, assertImportByteSize, MAX_IMPORT_ARCHIVE_BYTES, readProjectArchive, checkTypeScriptImport, MAX_IMPORT_SOURCE_BYTES, typeScriptModuleFile, typeScriptImportSource, workflowNameFromFile, primaryImportModule } from './chunk-M62CJVTR.js';
|
|
4
|
+
import { useCreateWorkflow, useWorkflowDefinitions, useLazyWorkflowDefinition, useImportWorkflow, useDuplicateWorkflow, useDeleteWorkflow } from './chunk-YQZ7HBOJ.js';
|
|
5
5
|
import { workflowsListControls } from './chunk-D3UWK7GY.js';
|
|
6
6
|
import { useFluidGridsPageControls } from './chunk-PJAWNFJV.js';
|
|
7
7
|
import { FluidGridsDocsLink } from './chunk-4VJ3MDOV.js';
|
|
8
|
-
import {
|
|
8
|
+
import { useFluidGridsFlag, FLUIDGRIDS_FLAGS } from './chunk-77NA7TPJ.js';
|
|
9
|
+
import { createThenOpen, useFluidGridsPermission, FLUIDGRIDS_PERMISSIONS, SdkPermissionButton, BILLING_PLANS_PATH, describeOperationError, useFlowStore, SdkPermissionGate, isQuotaExhaustedFailure } from './chunk-NVUJFHTQ.js';
|
|
9
10
|
import { useTr } from './chunk-UULVIT25.js';
|
|
10
11
|
import { useState, useRef, useCallback, useMemo } from 'react';
|
|
11
12
|
import { useNavigate } from 'react-router';
|
|
12
13
|
import { v4 } from 'uuid';
|
|
13
14
|
import { Icon } from '@iconify/react';
|
|
14
|
-
import { NextSteps, Button, Badge, Input, IllustratedEmptyState, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Label, Textarea, DialogFooter, Skeleton, TooltipProvider, Card, Tooltip, TooltipTrigger, TooltipContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from '@burdenoff/fe-libs/ui';
|
|
15
|
+
import { NextSteps, Button, Badge, Input, IllustratedEmptyState, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Label, Textarea, DialogFooter, Skeleton, TooltipProvider, Card, Tooltip, TooltipTrigger, TooltipContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@burdenoff/fe-libs/ui';
|
|
15
16
|
import { cn } from '@burdenoff/fe-libs/utils';
|
|
16
17
|
import { TagBadge } from '@burdenoff/fe-libs/tag';
|
|
17
18
|
import { toast } from 'sonner';
|
|
@@ -269,6 +270,72 @@ function WorkflowStatusPill({ status }) {
|
|
|
269
270
|
info.label
|
|
270
271
|
] });
|
|
271
272
|
}
|
|
273
|
+
function exportFormatLabel(tr, format) {
|
|
274
|
+
switch (format) {
|
|
275
|
+
case "TYPESCRIPT" /* Typescript */:
|
|
276
|
+
return tr(
|
|
277
|
+
"fluidgrids.builder.cardWorkflow.exportAsTypeScript",
|
|
278
|
+
"Export as TypeScript"
|
|
279
|
+
);
|
|
280
|
+
case "PYTHON" /* Python */:
|
|
281
|
+
return tr(
|
|
282
|
+
"fluidgrids.builder.cardWorkflow.exportAsPython",
|
|
283
|
+
"Export as Python"
|
|
284
|
+
);
|
|
285
|
+
default:
|
|
286
|
+
return tr(
|
|
287
|
+
"fluidgrids.builder.cardWorkflow.exportAsJson",
|
|
288
|
+
"Export as JSON"
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
var FORMAT_ICON = {
|
|
293
|
+
["TYPESCRIPT" /* Typescript */]: "mynaui:code",
|
|
294
|
+
["PYTHON" /* Python */]: "mynaui:code-square",
|
|
295
|
+
["JSON" /* Json */]: "mynaui:file-text"
|
|
296
|
+
};
|
|
297
|
+
function WorkflowExportMenu({
|
|
298
|
+
onExportAs,
|
|
299
|
+
exporting
|
|
300
|
+
}) {
|
|
301
|
+
const tr = useTr();
|
|
302
|
+
const label = tr("fluidgrids.builder.cardWorkflow.exportMenu", "Export");
|
|
303
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
304
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
305
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
306
|
+
Button,
|
|
307
|
+
{
|
|
308
|
+
variant: "ghost",
|
|
309
|
+
size: "icon",
|
|
310
|
+
className: "size-8",
|
|
311
|
+
"aria-label": label,
|
|
312
|
+
"data-testid": "fluidgrids-card-export-menu",
|
|
313
|
+
disabled: exporting !== null,
|
|
314
|
+
children: /* @__PURE__ */ jsx(
|
|
315
|
+
Icon,
|
|
316
|
+
{
|
|
317
|
+
icon: exporting ? "mynaui:spinner" : "mynaui:download",
|
|
318
|
+
className: exporting ? "size-4 animate-spin" : "size-4"
|
|
319
|
+
}
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
) }) }),
|
|
323
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "top", children: /* @__PURE__ */ jsx("p", { children: label }) })
|
|
324
|
+
] }),
|
|
325
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", "data-card-action": "", children: CODE_EXPORT_FORMATS.map((format) => /* @__PURE__ */ jsxs(
|
|
326
|
+
DropdownMenuItem,
|
|
327
|
+
{
|
|
328
|
+
onClick: () => onExportAs(format),
|
|
329
|
+
"data-testid": `fluidgrids-card-export-${format.toLowerCase()}`,
|
|
330
|
+
children: [
|
|
331
|
+
/* @__PURE__ */ jsx(Icon, { icon: FORMAT_ICON[format], className: "mr-2 size-4" }),
|
|
332
|
+
exportFormatLabel(tr, format)
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
format
|
|
336
|
+
)) })
|
|
337
|
+
] });
|
|
338
|
+
}
|
|
272
339
|
function relativeTime(iso) {
|
|
273
340
|
if (!iso) return "\u2014";
|
|
274
341
|
const then = new Date(iso).getTime();
|
|
@@ -289,7 +356,9 @@ function relativeTime(iso) {
|
|
|
289
356
|
var CardWorkflow = ({
|
|
290
357
|
workflow,
|
|
291
358
|
onUpdateSuccess,
|
|
292
|
-
onExport
|
|
359
|
+
onExport,
|
|
360
|
+
onExportAs,
|
|
361
|
+
exportingFormat = null
|
|
293
362
|
}) => {
|
|
294
363
|
const tr = useTr();
|
|
295
364
|
const navigate = useNavigate();
|
|
@@ -492,7 +561,13 @@ var CardWorkflow = ({
|
|
|
492
561
|
"Sharing is not available for workflows yet"
|
|
493
562
|
) }) })
|
|
494
563
|
] }),
|
|
495
|
-
|
|
564
|
+
onExportAs ? /* @__PURE__ */ jsx("span", { "data-card-action": "", children: /* @__PURE__ */ jsx(
|
|
565
|
+
WorkflowExportMenu,
|
|
566
|
+
{
|
|
567
|
+
onExportAs,
|
|
568
|
+
exporting: exportingFormat
|
|
569
|
+
}
|
|
570
|
+
) }) : onExport ? /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
496
571
|
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
497
572
|
Button,
|
|
498
573
|
{
|
|
@@ -511,7 +586,7 @@ var CardWorkflow = ({
|
|
|
511
586
|
"fluidgrids.builder.cardWorkflow.exportWorkflow",
|
|
512
587
|
"Export workflow JSON"
|
|
513
588
|
) }) })
|
|
514
|
-
] }),
|
|
589
|
+
] }) : null,
|
|
515
590
|
/* @__PURE__ */ jsx(
|
|
516
591
|
SdkPermissionGate,
|
|
517
592
|
{
|
|
@@ -621,91 +696,89 @@ var CardWorkflow = ({
|
|
|
621
696
|
)
|
|
622
697
|
] });
|
|
623
698
|
};
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
699
|
+
function formatMiB(bytes) {
|
|
700
|
+
const mib = bytes / (1024 * 1024);
|
|
701
|
+
return Number.isInteger(mib) ? String(mib) : mib.toFixed(1);
|
|
628
702
|
}
|
|
629
|
-
function
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
703
|
+
function describeImportSourceProblem(tr, problem) {
|
|
704
|
+
switch (problem.code) {
|
|
705
|
+
case "too-large":
|
|
706
|
+
return tr(
|
|
707
|
+
"fluidgrids.workflowsList.importSourceTooLarge",
|
|
708
|
+
"The workflow sources are larger than {{size}} MiB, the import limit.",
|
|
709
|
+
{ size: formatMiB(problem.limitBytes) }
|
|
710
|
+
);
|
|
711
|
+
case "too-many-files":
|
|
712
|
+
return tr(
|
|
713
|
+
"fluidgrids.workflowsList.importSourceTooManyFiles",
|
|
714
|
+
"An import holds at most {{limit}} files.",
|
|
715
|
+
{ limit: String(problem.limit) }
|
|
716
|
+
);
|
|
717
|
+
case "invalid-archive":
|
|
718
|
+
return tr(
|
|
719
|
+
"fluidgrids.workflowsList.importSourceInvalidArchive",
|
|
720
|
+
"The file is not a readable .zip archive."
|
|
721
|
+
);
|
|
722
|
+
case "no-module":
|
|
723
|
+
return tr(
|
|
724
|
+
"fluidgrids.workflowsList.importSourceNoModule",
|
|
725
|
+
"No TypeScript workflow module (workflows/*.ts) was found."
|
|
726
|
+
);
|
|
727
|
+
case "python-needs-cli":
|
|
728
|
+
return tr(
|
|
729
|
+
"fluidgrids.workflowsList.importSourcePythonNeedsCli",
|
|
730
|
+
"Python workflows are imported with the FluidGrids CLI (fluidgrids push)."
|
|
731
|
+
);
|
|
732
|
+
case "needs-node-clients":
|
|
733
|
+
return tr(
|
|
734
|
+
"fluidgrids.workflowsList.importSourceNeedsNodeClients",
|
|
735
|
+
"{{path}} imports the generated node clients (.fluidgrids/nodes.ts). Import the .zip that Export as TypeScript downloads, which includes them.",
|
|
736
|
+
{ path: problem.path }
|
|
737
|
+
);
|
|
647
738
|
}
|
|
648
|
-
return references;
|
|
649
739
|
}
|
|
650
|
-
function
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
const anchor = document.createElement("a");
|
|
678
|
-
anchor.href = url;
|
|
679
|
-
anchor.download = `${workflow.workflowKey}-${workflow.version}.fluidgrids.json`;
|
|
680
|
-
anchor.click();
|
|
681
|
-
URL.revokeObjectURL(url);
|
|
740
|
+
function WorkflowImportIssues({
|
|
741
|
+
issues
|
|
742
|
+
}) {
|
|
743
|
+
const tr = useTr();
|
|
744
|
+
const errors = issues.errors.length > 0 ? issues.errors : issues.message ? [issues.message] : [];
|
|
745
|
+
if (errors.length === 0 && issues.warnings.length === 0) return null;
|
|
746
|
+
return /* @__PURE__ */ jsxs(
|
|
747
|
+
"div",
|
|
748
|
+
{
|
|
749
|
+
role: "alert",
|
|
750
|
+
"data-testid": "fluidgrids-import-issues",
|
|
751
|
+
className: "space-y-2 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bg)] p-3 text-xs",
|
|
752
|
+
children: [
|
|
753
|
+
errors.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
754
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-[var(--color-status-error-text)]", children: tr(
|
|
755
|
+
"fluidgrids.workflowsList.importErrorsTitle",
|
|
756
|
+
"The workflow could not be imported"
|
|
757
|
+
) }),
|
|
758
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1 list-disc space-y-0.5 pl-4 text-[var(--color-status-error-text)]", children: errors.map((error, index) => /* @__PURE__ */ jsx("li", { className: "break-words", children: error }, `e-${index}`)) })
|
|
759
|
+
] }),
|
|
760
|
+
issues.warnings.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
761
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-[var(--color-status-warning-text)]", children: tr("fluidgrids.workflowsList.importWarningsTitle", "Warnings") }),
|
|
762
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1 list-disc space-y-0.5 pl-4 text-[var(--color-status-warning-text)]", children: issues.warnings.map((warning, index) => /* @__PURE__ */ jsx("li", { className: "break-words", children: warning }, `w-${index}`)) })
|
|
763
|
+
] })
|
|
764
|
+
]
|
|
765
|
+
}
|
|
766
|
+
);
|
|
682
767
|
}
|
|
683
|
-
function
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
if (!root) throw new Error("Import must contain a JSON object");
|
|
687
|
-
const definitionJson = asRecord(root.definitionJson) ?? root;
|
|
688
|
-
const name = typeof root.name === "string" && root.name.trim() ? root.name : "Imported workflow";
|
|
689
|
-
return {
|
|
690
|
-
definitionJson,
|
|
691
|
-
name,
|
|
692
|
-
workflowKey: typeof root.workflowKey === "string" ? root.workflowKey : void 0,
|
|
693
|
-
version: typeof root.version === "string" ? root.version : void 0,
|
|
694
|
-
description: typeof root.description === "string" ? root.description : void 0,
|
|
695
|
-
context: asRecord(root.context) ?? void 0,
|
|
696
|
-
tags: Array.isArray(root.tags) && root.tags.every((tag) => typeof tag === "string") ? root.tags : void 0,
|
|
697
|
-
tagsV2: root.tagsV2,
|
|
698
|
-
icon: typeof root.icon === "string" ? root.icon : void 0,
|
|
699
|
-
category: typeof root.category === "string" ? root.category : void 0,
|
|
700
|
-
nodeReferences: Array.isArray(root.nodeReferences) ? root.nodeReferences : collectWorkflowNodeReferences(definitionJson)
|
|
701
|
-
};
|
|
768
|
+
function declaredLength(response) {
|
|
769
|
+
const value = Number(response.headers.get("content-length"));
|
|
770
|
+
return Number.isFinite(value) && value > 0 ? value : null;
|
|
702
771
|
}
|
|
703
772
|
function WorkflowImportDialog({
|
|
704
773
|
onImported
|
|
705
774
|
}) {
|
|
706
775
|
const tr = useTr();
|
|
707
|
-
const
|
|
776
|
+
const codeFirst = useFluidGridsFlag(FLUIDGRIDS_FLAGS.codeFirst);
|
|
777
|
+
const { importWorkflow, loading, error: importError } = useImportWorkflow();
|
|
708
778
|
const [open, setOpen] = useState(false);
|
|
779
|
+
const [typeScript, setTypeScript] = useState(null);
|
|
780
|
+
const [issues, setIssues] = useState(null);
|
|
781
|
+
const [submitted, setSubmitted] = useState(false);
|
|
709
782
|
const [rawJson, setRawJson] = useState("");
|
|
710
783
|
const [url, setUrl] = useState("");
|
|
711
784
|
const [parsed, setParsed] = useState(null);
|
|
@@ -720,8 +793,53 @@ function WorkflowImportDialog({
|
|
|
720
793
|
setName("");
|
|
721
794
|
setWorkflowKey("");
|
|
722
795
|
setVersion("");
|
|
796
|
+
setTypeScript(null);
|
|
797
|
+
setIssues(null);
|
|
798
|
+
setSubmitted(false);
|
|
799
|
+
};
|
|
800
|
+
const selectTypeScript = (label, files) => {
|
|
801
|
+
setParsed(null);
|
|
802
|
+
setIssues(null);
|
|
803
|
+
setSubmitted(false);
|
|
804
|
+
setTypeScript({ label, files });
|
|
805
|
+
setName(workflowNameFromFile(primaryImportModule(files)?.path ?? label));
|
|
806
|
+
setWorkflowKey("");
|
|
807
|
+
setVersion("");
|
|
808
|
+
};
|
|
809
|
+
const refuseSource = (error) => {
|
|
810
|
+
setTypeScript(null);
|
|
811
|
+
setParsed(null);
|
|
812
|
+
setSubmitted(false);
|
|
813
|
+
setIssues({
|
|
814
|
+
errors: [describeImportSourceProblem(tr, error.problem)],
|
|
815
|
+
warnings: []
|
|
816
|
+
});
|
|
817
|
+
};
|
|
818
|
+
const readCodeSource = async (kind, label, size, read) => {
|
|
819
|
+
if (!codeFirst || kind === null || kind === "json") return false;
|
|
820
|
+
try {
|
|
821
|
+
if (kind === "python") {
|
|
822
|
+
throw new ImportSourceError({ code: "python-needs-cli" });
|
|
823
|
+
}
|
|
824
|
+
if (kind === "archive") {
|
|
825
|
+
if (size !== null) assertImportByteSize(size, MAX_IMPORT_ARCHIVE_BYTES);
|
|
826
|
+
const files2 = await readProjectArchive(await read.bytes());
|
|
827
|
+
selectTypeScript(label, checkTypeScriptImport(files2));
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
if (size !== null) assertImportByteSize(size, MAX_IMPORT_SOURCE_BYTES);
|
|
831
|
+
const files = [typeScriptModuleFile(label, await read.text())];
|
|
832
|
+
selectTypeScript(label, checkTypeScriptImport(files));
|
|
833
|
+
} catch (error) {
|
|
834
|
+
if (!(error instanceof ImportSourceError)) throw error;
|
|
835
|
+
refuseSource(error);
|
|
836
|
+
}
|
|
837
|
+
return true;
|
|
723
838
|
};
|
|
724
839
|
const parse = (value) => {
|
|
840
|
+
setTypeScript(null);
|
|
841
|
+
setIssues(null);
|
|
842
|
+
setSubmitted(false);
|
|
725
843
|
try {
|
|
726
844
|
const next = parseWorkflowImport(value);
|
|
727
845
|
setParsed(next);
|
|
@@ -741,10 +859,19 @@ function WorkflowImportDialog({
|
|
|
741
859
|
const handleFile = async (file) => {
|
|
742
860
|
if (!file) return;
|
|
743
861
|
try {
|
|
744
|
-
|
|
862
|
+
const handled = await readCodeSource(
|
|
863
|
+
importFileKind(file.name),
|
|
864
|
+
file.name,
|
|
865
|
+
file.size,
|
|
866
|
+
{ text: () => file.text(), bytes: () => file.arrayBuffer() }
|
|
867
|
+
);
|
|
868
|
+
if (!handled) parse(await file.text());
|
|
745
869
|
} catch (error) {
|
|
746
870
|
toast.error(
|
|
747
|
-
error instanceof Error ? error.message :
|
|
871
|
+
error instanceof Error ? error.message : tr(
|
|
872
|
+
"fluidgrids.workflowsList.importReadFileFailed",
|
|
873
|
+
"Unable to read import file"
|
|
874
|
+
)
|
|
748
875
|
);
|
|
749
876
|
}
|
|
750
877
|
};
|
|
@@ -754,10 +881,18 @@ function WorkflowImportDialog({
|
|
|
754
881
|
try {
|
|
755
882
|
parsedUrl = new URL(url.trim());
|
|
756
883
|
if (parsedUrl.protocol !== "https:")
|
|
757
|
-
throw new Error(
|
|
884
|
+
throw new Error(
|
|
885
|
+
tr(
|
|
886
|
+
"fluidgrids.workflowsList.importUrlNotHttps",
|
|
887
|
+
"Import URLs must use HTTPS"
|
|
888
|
+
)
|
|
889
|
+
);
|
|
758
890
|
} catch (error) {
|
|
759
891
|
toast.error(
|
|
760
|
-
error instanceof Error ? error.message :
|
|
892
|
+
error instanceof Error ? error.message : tr(
|
|
893
|
+
"fluidgrids.workflowsList.importUrlInvalid",
|
|
894
|
+
"Invalid import URL"
|
|
895
|
+
)
|
|
761
896
|
);
|
|
762
897
|
return;
|
|
763
898
|
}
|
|
@@ -765,18 +900,72 @@ function WorkflowImportDialog({
|
|
|
765
900
|
try {
|
|
766
901
|
const response = await fetch(parsedUrl, { credentials: "omit" });
|
|
767
902
|
if (!response.ok)
|
|
768
|
-
throw new Error(
|
|
769
|
-
|
|
903
|
+
throw new Error(
|
|
904
|
+
tr(
|
|
905
|
+
"fluidgrids.workflowsList.importUrlHttpError",
|
|
906
|
+
"Import URL returned HTTP {{status}}",
|
|
907
|
+
{ status: String(response.status) }
|
|
908
|
+
)
|
|
909
|
+
);
|
|
910
|
+
const segments = parsedUrl.pathname.split("/").filter(Boolean);
|
|
911
|
+
const handled = await readCodeSource(
|
|
912
|
+
importFileKind(parsedUrl.pathname),
|
|
913
|
+
decodeURIComponent(segments[segments.length - 1] ?? "workflow.ts"),
|
|
914
|
+
declaredLength(response),
|
|
915
|
+
{ text: () => response.text(), bytes: () => response.arrayBuffer() }
|
|
916
|
+
);
|
|
917
|
+
if (!handled) parse(await response.text());
|
|
770
918
|
} catch (error) {
|
|
771
919
|
toast.error(
|
|
772
|
-
error instanceof Error ? error.message :
|
|
920
|
+
error instanceof Error ? error.message : tr(
|
|
921
|
+
"fluidgrids.workflowsList.importUrlFetchFailed",
|
|
922
|
+
"Unable to fetch import URL"
|
|
923
|
+
)
|
|
773
924
|
);
|
|
774
925
|
} finally {
|
|
775
926
|
setLoadingUrl(false);
|
|
776
927
|
}
|
|
777
928
|
};
|
|
929
|
+
const handleTypeScriptImport = async (source) => {
|
|
930
|
+
setIssues(null);
|
|
931
|
+
setSubmitted(true);
|
|
932
|
+
const input = {
|
|
933
|
+
workflowKey: workflowKey.trim() || void 0,
|
|
934
|
+
version: version.trim() || void 0,
|
|
935
|
+
name: name.trim(),
|
|
936
|
+
source: typeScriptImportSource(source.files),
|
|
937
|
+
allowMissingNodes: false
|
|
938
|
+
};
|
|
939
|
+
const imported = await importWorkflow(input);
|
|
940
|
+
if (!imported) return;
|
|
941
|
+
if (!imported.success || !imported.workflow) {
|
|
942
|
+
setIssues({
|
|
943
|
+
errors: imported.validation.errors,
|
|
944
|
+
warnings: imported.validation.warnings,
|
|
945
|
+
message: imported.message || tr(
|
|
946
|
+
"fluidgrids.workflowsList.importValidationFailed",
|
|
947
|
+
"Workflow import validation failed"
|
|
948
|
+
)
|
|
949
|
+
});
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
toast.success(
|
|
953
|
+
tr("fluidgrids.workflowsList.importSuccess", "Workflow imported")
|
|
954
|
+
);
|
|
955
|
+
setOpen(false);
|
|
956
|
+
reset();
|
|
957
|
+
onImported();
|
|
958
|
+
};
|
|
778
959
|
const handleImport = async () => {
|
|
960
|
+
if (typeScript && name.trim()) {
|
|
961
|
+
await handleTypeScriptImport(typeScript);
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
779
964
|
if (!parsed || !name.trim()) return;
|
|
965
|
+
if (codeFirst) {
|
|
966
|
+
setIssues(null);
|
|
967
|
+
setSubmitted(true);
|
|
968
|
+
}
|
|
780
969
|
const input = {
|
|
781
970
|
workflowKey: workflowKey.trim() || `${name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${Date.now()}`,
|
|
782
971
|
version: version.trim() || "v1",
|
|
@@ -793,6 +982,17 @@ function WorkflowImportDialog({
|
|
|
793
982
|
const imported = await importWorkflow(input);
|
|
794
983
|
if (!imported) return;
|
|
795
984
|
if (!imported.success || !imported.workflow) {
|
|
985
|
+
if (codeFirst) {
|
|
986
|
+
setIssues({
|
|
987
|
+
errors: imported.validation.errors,
|
|
988
|
+
warnings: imported.validation.warnings,
|
|
989
|
+
message: imported.message || tr(
|
|
990
|
+
"fluidgrids.workflowsList.importValidationFailed",
|
|
991
|
+
"Workflow import validation failed"
|
|
992
|
+
)
|
|
993
|
+
});
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
796
996
|
const validationMessage = [
|
|
797
997
|
...imported.validation.errors,
|
|
798
998
|
...imported.validation.warnings
|
|
@@ -836,8 +1036,17 @@ function WorkflowImportDialog({
|
|
|
836
1036
|
),
|
|
837
1037
|
/* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[90vh] overflow-y-auto sm:max-w-2xl", children: [
|
|
838
1038
|
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
839
|
-
/* @__PURE__ */ jsx(DialogTitle, { children: tr(
|
|
840
|
-
|
|
1039
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: codeFirst ? tr(
|
|
1040
|
+
"fluidgrids.workflowsList.importTitleCode",
|
|
1041
|
+
"Import workflow"
|
|
1042
|
+
) : tr(
|
|
1043
|
+
"fluidgrids.workflowsList.importTitle",
|
|
1044
|
+
"Import workflow JSON"
|
|
1045
|
+
) }),
|
|
1046
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: codeFirst ? tr(
|
|
1047
|
+
"fluidgrids.workflowsList.importDescriptionCode",
|
|
1048
|
+
"Import a workflow JSON file, a TypeScript workflow module, or the .zip that Export as TypeScript downloads, from a file, an HTTPS URL, or pasted JSON. Credentials remain references and must be configured in this workspace."
|
|
1049
|
+
) : tr(
|
|
841
1050
|
"fluidgrids.workflowsList.importDescription",
|
|
842
1051
|
"Import from a file, an HTTPS URL, or pasted JSON. Credentials remain references and must be configured in this workspace."
|
|
843
1052
|
) })
|
|
@@ -851,7 +1060,10 @@ function WorkflowImportDialog({
|
|
|
851
1060
|
className: "inline-flex cursor-pointer items-center gap-2 rounded-md border border-border px-3 py-2 text-sm hover:bg-accent",
|
|
852
1061
|
children: [
|
|
853
1062
|
/* @__PURE__ */ jsx(Icon, { icon: "mynaui:upload", className: "size-4" }),
|
|
854
|
-
tr(
|
|
1063
|
+
codeFirst ? tr(
|
|
1064
|
+
"fluidgrids.workflowsList.importChooseFileCode",
|
|
1065
|
+
"Choose JSON, TypeScript or .zip file"
|
|
1066
|
+
) : tr(
|
|
855
1067
|
"fluidgrids.workflowsList.importChooseFile",
|
|
856
1068
|
"Choose JSON file"
|
|
857
1069
|
)
|
|
@@ -863,7 +1075,7 @@ function WorkflowImportDialog({
|
|
|
863
1075
|
{
|
|
864
1076
|
id: "fluidgrids-workflow-import-file",
|
|
865
1077
|
type: "file",
|
|
866
|
-
accept:
|
|
1078
|
+
accept: importAcceptAttribute(codeFirst),
|
|
867
1079
|
className: "sr-only",
|
|
868
1080
|
onChange: (event) => void handleFile(event.currentTarget.files?.[0])
|
|
869
1081
|
}
|
|
@@ -876,7 +1088,10 @@ function WorkflowImportDialog({
|
|
|
876
1088
|
value: url,
|
|
877
1089
|
onChange: (event) => setUrl(event.target.value),
|
|
878
1090
|
placeholder: "https://example.com/workflow.json",
|
|
879
|
-
"aria-label": tr(
|
|
1091
|
+
"aria-label": codeFirst ? tr(
|
|
1092
|
+
"fluidgrids.workflowsList.importUrlLabelCode",
|
|
1093
|
+
"Workflow JSON, TypeScript or .zip URL"
|
|
1094
|
+
) : tr(
|
|
880
1095
|
"fluidgrids.workflowsList.importUrlLabel",
|
|
881
1096
|
"Workflow JSON URL"
|
|
882
1097
|
)
|
|
@@ -888,7 +1103,7 @@ function WorkflowImportDialog({
|
|
|
888
1103
|
variant: "outline",
|
|
889
1104
|
onClick: () => void handleUrl(),
|
|
890
1105
|
disabled: loadingUrl || !url.trim(),
|
|
891
|
-
children: loadingUrl ? "Loading\u2026" : tr("fluidgrids.workflowsList.importFetchUrl", "Fetch")
|
|
1106
|
+
children: loadingUrl ? tr("fluidgrids.workflowsList.importFetchingUrl", "Loading\u2026") : tr("fluidgrids.workflowsList.importFetchUrl", "Fetch")
|
|
892
1107
|
}
|
|
893
1108
|
)
|
|
894
1109
|
] }),
|
|
@@ -912,15 +1127,33 @@ function WorkflowImportDialog({
|
|
|
912
1127
|
)
|
|
913
1128
|
}
|
|
914
1129
|
),
|
|
915
|
-
parsed && /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-lg border border-border bg-muted/30 p-3", children: [
|
|
916
|
-
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
1130
|
+
(parsed || typeScript) && /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-lg border border-border bg-muted/30 p-3", children: [
|
|
1131
|
+
parsed ? /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
917
1132
|
parsed.nodeReferences.length,
|
|
918
1133
|
" ",
|
|
919
1134
|
tr(
|
|
920
1135
|
"fluidgrids.workflowsList.importNodeReferences",
|
|
921
1136
|
"node references found"
|
|
922
1137
|
)
|
|
923
|
-
] })
|
|
1138
|
+
] }) : typeScript ? /* @__PURE__ */ jsx(
|
|
1139
|
+
"p",
|
|
1140
|
+
{
|
|
1141
|
+
className: "text-xs text-muted-foreground",
|
|
1142
|
+
"data-testid": "fluidgrids-import-typescript",
|
|
1143
|
+
children: typeScript.files.length > 1 ? tr(
|
|
1144
|
+
"fluidgrids.workflowsList.importTypeScriptProject",
|
|
1145
|
+
"{{file}}: {{count}} project files. The service builds the TypeScript and checks the workflow it defines before creating a draft.",
|
|
1146
|
+
{
|
|
1147
|
+
file: typeScript.label,
|
|
1148
|
+
count: String(typeScript.files.length)
|
|
1149
|
+
}
|
|
1150
|
+
) : tr(
|
|
1151
|
+
"fluidgrids.workflowsList.importTypeScriptFile",
|
|
1152
|
+
"TypeScript module {{file}}: the service builds it and checks the workflow it defines before creating a draft.",
|
|
1153
|
+
{ file: typeScript.label }
|
|
1154
|
+
)
|
|
1155
|
+
}
|
|
1156
|
+
) : null,
|
|
924
1157
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [
|
|
925
1158
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1 sm:col-span-3", children: [
|
|
926
1159
|
/* @__PURE__ */ jsx(Label, { htmlFor: "fluidgrids-import-name", children: tr("fluidgrids.workflowsList.importName", "Name") }),
|
|
@@ -960,7 +1193,17 @@ function WorkflowImportDialog({
|
|
|
960
1193
|
)
|
|
961
1194
|
] })
|
|
962
1195
|
] })
|
|
963
|
-
] })
|
|
1196
|
+
] }),
|
|
1197
|
+
codeFirst && !loading && (issues || submitted && importError) && /* @__PURE__ */ jsx(
|
|
1198
|
+
WorkflowImportIssues,
|
|
1199
|
+
{
|
|
1200
|
+
issues: issues ?? {
|
|
1201
|
+
errors: [],
|
|
1202
|
+
warnings: [],
|
|
1203
|
+
message: importError?.message ?? null
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
)
|
|
964
1207
|
] }),
|
|
965
1208
|
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
966
1209
|
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setOpen(false), children: tr("fluidgrids.workflowsList.importCancel", "Cancel") }),
|
|
@@ -968,7 +1211,7 @@ function WorkflowImportDialog({
|
|
|
968
1211
|
Button,
|
|
969
1212
|
{
|
|
970
1213
|
onClick: () => void handleImport(),
|
|
971
|
-
disabled: loading || !parsed || !name.trim(),
|
|
1214
|
+
disabled: loading || !parsed && !typeScript || !name.trim(),
|
|
972
1215
|
children: loading ? tr("fluidgrids.workflowsList.importing", "Importing\u2026") : tr("fluidgrids.workflowsList.importConfirm", "Import workflow")
|
|
973
1216
|
}
|
|
974
1217
|
)
|
|
@@ -1267,6 +1510,22 @@ function WorkflowsList() {
|
|
|
1267
1510
|
]
|
|
1268
1511
|
);
|
|
1269
1512
|
useFluidGridsPageControls(assistantControls);
|
|
1513
|
+
const codeFirst = useFluidGridsFlag(FLUIDGRIDS_FLAGS.codeFirst);
|
|
1514
|
+
const { exportAs, exporting } = useExportWorkflowAs();
|
|
1515
|
+
const [exportingKey, setExportingKey] = useState(null);
|
|
1516
|
+
const handleExportAs = async (workflowKey, version, format) => {
|
|
1517
|
+
setExportingKey(workflowKey);
|
|
1518
|
+
try {
|
|
1519
|
+
await exportAs({ workflowKey, version, format });
|
|
1520
|
+
} catch (error2) {
|
|
1521
|
+
toast.error(
|
|
1522
|
+
tr("fluidgrids.workflowsList.exportFailed", "Export failed"),
|
|
1523
|
+
{ description: describeOperationError(error2) }
|
|
1524
|
+
);
|
|
1525
|
+
} finally {
|
|
1526
|
+
setExportingKey(null);
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1270
1529
|
const handleExport = async (id) => {
|
|
1271
1530
|
const workflow = await getWorkflow(void 0, id);
|
|
1272
1531
|
if (!workflow) return;
|
|
@@ -1507,7 +1766,13 @@ function WorkflowsList() {
|
|
|
1507
1766
|
}))
|
|
1508
1767
|
},
|
|
1509
1768
|
onUpdateSuccess: () => refetch(),
|
|
1510
|
-
onExport: () => void handleExport(workflow.id)
|
|
1769
|
+
onExport: () => void handleExport(workflow.id),
|
|
1770
|
+
onExportAs: codeFirst ? (format) => void handleExportAs(
|
|
1771
|
+
workflow.workflowKey,
|
|
1772
|
+
workflow.version,
|
|
1773
|
+
format
|
|
1774
|
+
) : void 0,
|
|
1775
|
+
exportingFormat: exportingKey === workflow.workflowKey ? exporting : null
|
|
1511
1776
|
},
|
|
1512
1777
|
workflow.id
|
|
1513
1778
|
)) })
|