@burdenoff/fluidgrids-fe-sdk 2026.1023.5 → 2026.1024.2
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-FDX242B5.js → ExecutionDetailPage-RF5NR2ND.js} +7 -7
- package/dist/{ExecutionsListPage-DYKEZ4KN.js → ExecutionsListPage-L447L5LX.js} +7 -7
- package/dist/{WorkflowBuilder-NITC5SKO.js → WorkflowBuilder-AWCE62C7.js} +9 -9
- package/dist/{WorkflowsList-7IHK3HTY.js → WorkflowsList-QFVCVGRY.js} +7 -7
- package/dist/{chunk-VMVY65DC.js → chunk-3GHYYFBA.js} +5 -5
- package/dist/{chunk-PZP5UYE7.js → chunk-4H7MRDNX.js} +77 -5
- package/dist/{chunk-XCQROWIZ.js → chunk-65DVJILQ.js} +2 -2
- package/dist/{chunk-EB344COE.js → chunk-7PC3ZBYU.js} +3 -3
- package/dist/{chunk-UKMXGBU3.js → chunk-7ST3XB36.js} +1 -1
- package/dist/{chunk-KAOLPDNX.js → chunk-DSBU5MH4.js} +1 -1
- package/dist/{chunk-3VF67N3X.js → chunk-GCOWR7J4.js} +1 -1
- package/dist/{chunk-CZURRUDX.js → chunk-GD7CSKFD.js} +4 -1
- package/dist/{chunk-TRYYDUCJ.js → chunk-GV76OCBP.js} +4 -4
- package/dist/{chunk-BT3ABHVR.js → chunk-I2DSSBIK.js} +5 -5
- package/dist/{chunk-2QTKDR23.js → chunk-INHBJPVE.js} +1 -1
- package/dist/{chunk-JG7UFL5M.js → chunk-IZMYI6QO.js} +621 -64
- package/dist/{chunk-7XBCGNUG.js → chunk-L37ZAZE4.js} +2 -2
- package/dist/{chunk-HAYSY6TZ.js → chunk-OQEQ3AIA.js} +1 -1
- package/dist/{chunk-OKWH2CHF.js → chunk-PMQECGSD.js} +3 -3
- package/dist/{chunk-LLPLOWMA.js → chunk-QIAXIFLW.js} +2 -2
- package/dist/{chunk-J3XDX5HG.js → chunk-S5ZKDRBV.js} +2 -2
- package/dist/{chunk-MR4OTF7D.js → chunk-T7X3HDNX.js} +2 -2
- package/dist/{chunk-HZC4TPPI.js → chunk-VZQSCUD4.js} +3 -3
- package/dist/{chunk-IULOX3NQ.js → chunk-XFVNTWM2.js} +1 -1
- package/dist/{chunk-NJZAWUGC.js → chunk-XXAVXVBW.js} +1 -1
- package/dist/executions.js +9 -9
- package/dist/history.js +4 -4
- package/dist/index.d.ts +800 -25
- package/dist/index.js +31 -31
- package/dist/nodes.js +2 -2
- package/dist/observability.js +4 -4
- package/dist/settings.js +4 -4
- package/dist/templates.js +8 -8
- package/dist/workflow-builder.js +10 -10
- package/dist/workflows-list.js +7 -7
- package/package.json +1 -1
|
@@ -2,16 +2,16 @@ import { deepClone, applyTemplateInputs } from './chunk-GEMNVFPK.js';
|
|
|
2
2
|
import { Input as Input$1 } from './chunk-IEVSFCFS.js';
|
|
3
3
|
import { Dialog as Dialog$1, DialogContent as DialogContent$1, DialogHeader as DialogHeader$1, DialogTitle as DialogTitle$1, DialogDescription as DialogDescription$1, DialogFooter } from './chunk-YXMFRQYV.js';
|
|
4
4
|
import { Badge as Badge$1, Button } from './chunk-BQXVT32O.js';
|
|
5
|
-
import { QuotaExhaustedDialog } from './chunk-
|
|
6
|
-
import { EntityTagPicker } from './chunk-
|
|
7
|
-
import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-
|
|
5
|
+
import { QuotaExhaustedDialog } from './chunk-GCOWR7J4.js';
|
|
6
|
+
import { EntityTagPicker } from './chunk-XFVNTWM2.js';
|
|
7
|
+
import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-S5ZKDRBV.js';
|
|
8
8
|
import { FluidGridsDocsLink } from './chunk-4VJ3MDOV.js';
|
|
9
|
-
import { RUNS_QUOTA_NAME, throwIfResultError, useFlowStore, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, NODE_CONFIGS, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useIsValidConnection, refetchStoreNodes, AVAILABLE_NODES, useInsertNode, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, useSaveWorkflow, SdkPermissionButton, FLUIDGRIDS_PERMISSIONS, STICKY_NOTE_TYPE, fieldsFromValue, getNodeDetail, useFluidGridsAnalytics, isNodeTrigger, buildStickyNode, fieldsFromIO, ConnectionSelector, structuredParameterType, nodeAccent, NodeTypeIcon, NODES_METADATA, resolveNodeOperation, declaredOutputFields, pathToExpression, ExpressionEditor, formatParameterValue, parseParameterValue, isNodeConfigsInitialized, resolveUiSpec, isImageIcon, NODES, synchronizeOperationUpdate, NodePropertyPanel, openRunQuotaUpgradePrompt, describeOperationError, isTriggerOperation, canRenderOperationPanel, resolveOperationName, resolveInputHandles } from './chunk-
|
|
9
|
+
import { RUNS_QUOTA_NAME, throwIfResultError, useFlowStore, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, NODE_CONFIGS, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useIsValidConnection, refetchStoreNodes, AVAILABLE_NODES, useInsertNode, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, useSaveWorkflow, SdkPermissionButton, FLUIDGRIDS_PERMISSIONS, STICKY_NOTE_TYPE, fieldsFromValue, getNodeDetail, useFluidGridsAnalytics, buildOperationSeed, isNodeTrigger, buildStickyNode, fieldsFromIO, ConnectionSelector, structuredParameterType, nodeAccent, NodeTypeIcon, NODES_METADATA, resolveNodeOperation, declaredOutputFields, pathToExpression, ExpressionEditor, formatParameterValue, parseParameterValue, isNodeConfigsInitialized, resolveUiSpec, isImageIcon, NODES, synchronizeOperationUpdate, NodePropertyPanel, openRunQuotaUpgradePrompt, describeOperationError, isTriggerOperation, canRenderOperationPanel, resolveOperationName, resolveInputHandles } from './chunk-T7X3HDNX.js';
|
|
10
10
|
import { cn } from './chunk-JL7CASN5.js';
|
|
11
11
|
import { getGlobalStoreClient } from './chunk-PXIFUMLA.js';
|
|
12
12
|
import { getFluidGridsConfig } from './chunk-CY6KX4RG.js';
|
|
13
13
|
import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument } from './chunk-WBH2XEWO.js';
|
|
14
|
-
import { WorkspaceRunsQuotaDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-
|
|
14
|
+
import { WorkspaceRunsQuotaDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, WorkflowGenerationTemplatesDocument, WorkflowGenerationDocument, GenerateWorkflowFromPromptDocument, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-GD7CSKFD.js';
|
|
15
15
|
import { useTr } from './chunk-UULVIT25.js';
|
|
16
16
|
import { getFluidGridsClient, waitForFluidGridsClient, getFluidGridsClientSafe } from './chunk-NTWG3CJX.js';
|
|
17
17
|
import * as React3 from 'react';
|
|
@@ -19,13 +19,13 @@ import React3__default, { forwardRef, lazy, memo, createContext, useState, useRe
|
|
|
19
19
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
20
20
|
import { gql } from '@apollo/client';
|
|
21
21
|
import { cn as cn$1 } from '@burdenoff/fe-libs/utils';
|
|
22
|
-
import { Card as Card$1, Badge, CardContent as CardContent$1, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Button as Button$1, Input, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle,
|
|
22
|
+
import { Card as Card$1, Badge, CardContent as CardContent$1, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Button as Button$1, Input, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, Label, Textarea, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, TooltipProvider, DropdownMenuItem, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Popover, PopoverTrigger, PopoverContent, Tooltip, TooltipTrigger, TooltipContent, Toaster, Tabs, TabsList, TabsTrigger, TabsContent, CardHeader as CardHeader$1, CardTitle as CardTitle$1, CardDescription as CardDescription$1, ScrollArea, DropdownMenuLabel, DropdownMenuSeparator } from '@burdenoff/fe-libs/ui';
|
|
23
23
|
import { Link, useNavigate, useParams } from 'react-router';
|
|
24
24
|
import { useEventBus } from '@burdenoff/fe-libs/shared/events';
|
|
25
25
|
import { useQuery, useMutation } from '@apollo/client/react';
|
|
26
26
|
import { gql as gql$1 } from '@apollo/client/core';
|
|
27
27
|
import 'jszip';
|
|
28
|
-
import { Sparkles, Star, Download, Eye, History, GitCompareArrows,
|
|
28
|
+
import { Sparkles, Star, Download, Eye, Loader2, History, GitCompareArrows, Play, RotateCcw, Trash2, Maximize2, Undo2, Redo2, LayoutGrid, Keyboard, Plus, GitBranch, AlertCircle, Search, RefreshCw, CheckCircle2, Package, Info, Copy, BadgeCheck, DollarSign, Type, Code, Hash, List, Braces, Workflow, PlusCircle, ChevronDown, ChevronRight, Layers, X, AlertTriangle } from 'lucide-react';
|
|
29
29
|
import { Icon } from '@iconify/react';
|
|
30
30
|
import { toast } from 'sonner';
|
|
31
31
|
import { useShallow, shallow } from 'zustand/shallow';
|
|
@@ -6456,8 +6456,8 @@ var reducer = (state, action) => {
|
|
|
6456
6456
|
if (toastId) {
|
|
6457
6457
|
addToRemoveQueue(toastId);
|
|
6458
6458
|
} else {
|
|
6459
|
-
state.toasts.forEach((
|
|
6460
|
-
addToRemoveQueue(
|
|
6459
|
+
state.toasts.forEach((toast11) => {
|
|
6460
|
+
addToRemoveQueue(toast11.id);
|
|
6461
6461
|
});
|
|
6462
6462
|
}
|
|
6463
6463
|
return {
|
|
@@ -7833,7 +7833,7 @@ function VisualMapperContent({
|
|
|
7833
7833
|
mapping,
|
|
7834
7834
|
onMappingChange
|
|
7835
7835
|
}) {
|
|
7836
|
-
const { toast:
|
|
7836
|
+
const { toast: toast11 } = useToast();
|
|
7837
7837
|
const tr = useTr();
|
|
7838
7838
|
const reactFlowWrapper = useRef(null);
|
|
7839
7839
|
const [selectedSourceNode, setSelectedSourceNode] = useState(null);
|
|
@@ -7853,7 +7853,7 @@ function VisualMapperContent({
|
|
|
7853
7853
|
targetOperation
|
|
7854
7854
|
);
|
|
7855
7855
|
if (generatedNodes.length === 0) {
|
|
7856
|
-
|
|
7856
|
+
toast11({
|
|
7857
7857
|
title: tr(
|
|
7858
7858
|
"fluidgrids.builder.visualMapper.noFieldsFoundTitle",
|
|
7859
7859
|
"No fields found"
|
|
@@ -7879,7 +7879,7 @@ function VisualMapperContent({
|
|
|
7879
7879
|
targetNode,
|
|
7880
7880
|
targetOperation,
|
|
7881
7881
|
setNodes,
|
|
7882
|
-
|
|
7882
|
+
toast11,
|
|
7883
7883
|
tr
|
|
7884
7884
|
]);
|
|
7885
7885
|
useEffect(() => {
|
|
@@ -7986,7 +7986,7 @@ function VisualMapperContent({
|
|
|
7986
7986
|
}
|
|
7987
7987
|
onMappingChange(updatedMapping);
|
|
7988
7988
|
if (isCompatible) {
|
|
7989
|
-
|
|
7989
|
+
toast11({
|
|
7990
7990
|
title: tr(
|
|
7991
7991
|
"fluidgrids.builder.visualMapper.mappingCreatedTitle",
|
|
7992
7992
|
"Mapping created"
|
|
@@ -7994,7 +7994,7 @@ function VisualMapperContent({
|
|
|
7994
7994
|
description: `Mapped ${sourcePath} (${sourceType}) to ${targetPath} (${targetType})`
|
|
7995
7995
|
});
|
|
7996
7996
|
} else {
|
|
7997
|
-
|
|
7997
|
+
toast11({
|
|
7998
7998
|
title: tr(
|
|
7999
7999
|
"fluidgrids.builder.visualMapper.typeMismatchTitle",
|
|
8000
8000
|
"Type mismatch warning"
|
|
@@ -8004,7 +8004,7 @@ function VisualMapperContent({
|
|
|
8004
8004
|
});
|
|
8005
8005
|
}
|
|
8006
8006
|
} else {
|
|
8007
|
-
|
|
8007
|
+
toast11({
|
|
8008
8008
|
title: tr(
|
|
8009
8009
|
"fluidgrids.builder.visualMapper.invalidMappingTitle",
|
|
8010
8010
|
"Invalid mapping"
|
|
@@ -8017,7 +8017,7 @@ function VisualMapperContent({
|
|
|
8017
8017
|
});
|
|
8018
8018
|
}
|
|
8019
8019
|
},
|
|
8020
|
-
[nodes, mapping, onMappingChange,
|
|
8020
|
+
[nodes, mapping, onMappingChange, toast11, tr, setEdges]
|
|
8021
8021
|
);
|
|
8022
8022
|
const onEdgeDelete = useCallback(
|
|
8023
8023
|
(edge) => {
|
|
@@ -8074,7 +8074,7 @@ function VisualMapperContent({
|
|
|
8074
8074
|
const handleSaveMappingDialog = (expression, targetFieldName) => {
|
|
8075
8075
|
const targetPath = targetFieldName || selectedTargetNode?.data?.path;
|
|
8076
8076
|
if (!targetPath) {
|
|
8077
|
-
|
|
8077
|
+
toast11({
|
|
8078
8078
|
title: tr(
|
|
8079
8079
|
"fluidgrids.builder.visualMapper.noTargetFieldTitle",
|
|
8080
8080
|
"No target field specified"
|
|
@@ -8106,7 +8106,7 @@ function VisualMapperContent({
|
|
|
8106
8106
|
}
|
|
8107
8107
|
onMappingChange(updatedMapping);
|
|
8108
8108
|
const mappingType = detectMappingType(expression);
|
|
8109
|
-
|
|
8109
|
+
toast11({
|
|
8110
8110
|
title: `${mappingType.charAt(0).toUpperCase() + mappingType.slice(1)} mapping created`,
|
|
8111
8111
|
description: `${tr("fluidgrids.builder.visualMapper.appliedMappingTo", "Applied mapping to")} ${targetPath}`
|
|
8112
8112
|
});
|
|
@@ -8405,7 +8405,7 @@ function MappingEditor({
|
|
|
8405
8405
|
setEdges,
|
|
8406
8406
|
edgeId
|
|
8407
8407
|
}) {
|
|
8408
|
-
const { toast:
|
|
8408
|
+
const { toast: toast11 } = useToast();
|
|
8409
8409
|
const tr = useTr();
|
|
8410
8410
|
const [mappingJson, setMappingJson] = useState({});
|
|
8411
8411
|
const [jsonDataString, setJsonDataString] = useState(
|
|
@@ -8529,7 +8529,7 @@ function MappingEditor({
|
|
|
8529
8529
|
const handleSaveMapping = () => {
|
|
8530
8530
|
try {
|
|
8531
8531
|
checkJsonValidity();
|
|
8532
|
-
|
|
8532
|
+
toast11({
|
|
8533
8533
|
title: tr(
|
|
8534
8534
|
"fluidgrids.builder.mappingEditor.mappingSavedTitle",
|
|
8535
8535
|
"Mapping saved"
|
|
@@ -8540,7 +8540,7 @@ function MappingEditor({
|
|
|
8540
8540
|
)
|
|
8541
8541
|
});
|
|
8542
8542
|
} catch (error) {
|
|
8543
|
-
|
|
8543
|
+
toast11({
|
|
8544
8544
|
title: tr(
|
|
8545
8545
|
"fluidgrids.builder.mappingEditor.errorSavingTitle",
|
|
8546
8546
|
"Error saving mapping"
|
|
@@ -8559,7 +8559,7 @@ function MappingEditor({
|
|
|
8559
8559
|
const parsedData = checkJsonValidity();
|
|
8560
8560
|
const result = await applyMapping(parsedData, sampleInput);
|
|
8561
8561
|
setPreviewOutput(result);
|
|
8562
|
-
|
|
8562
|
+
toast11({
|
|
8563
8563
|
title: tr(
|
|
8564
8564
|
"fluidgrids.builder.mappingEditor.mappingTestedTitle",
|
|
8565
8565
|
"Mapping tested"
|
|
@@ -8571,7 +8571,7 @@ function MappingEditor({
|
|
|
8571
8571
|
});
|
|
8572
8572
|
} catch (error) {
|
|
8573
8573
|
console.error("Test mapping error:", error);
|
|
8574
|
-
|
|
8574
|
+
toast11({
|
|
8575
8575
|
title: tr(
|
|
8576
8576
|
"fluidgrids.builder.mappingEditor.mappingTestFailedTitle",
|
|
8577
8577
|
"Mapping test failed"
|
|
@@ -19726,6 +19726,559 @@ function VersionHistoryPanel({ className }) {
|
|
|
19726
19726
|
)
|
|
19727
19727
|
] });
|
|
19728
19728
|
}
|
|
19729
|
+
|
|
19730
|
+
// src/builder/lib/ai-draft.ts
|
|
19731
|
+
var AI_DRAFT_POLL_INTERVAL_MS = 2500;
|
|
19732
|
+
var AI_DRAFT_MAX_WAIT_MS = 6 * 60 * 1e3;
|
|
19733
|
+
var AI_DRAFT_MAX_PROMPT_LENGTH = 4e3;
|
|
19734
|
+
function isRecord4(value) {
|
|
19735
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19736
|
+
}
|
|
19737
|
+
function stringOr(value, fallback) {
|
|
19738
|
+
return typeof value === "string" && value.trim() !== "" ? value : fallback;
|
|
19739
|
+
}
|
|
19740
|
+
function draftToCanvas(definitionJson) {
|
|
19741
|
+
const data = isRecord4(definitionJson) && isRecord4(definitionJson.data) ? definitionJson.data : {};
|
|
19742
|
+
const rawNodes = Array.isArray(data.nodes) ? data.nodes : [];
|
|
19743
|
+
const rawEdges = Array.isArray(data.edges) ? data.edges : [];
|
|
19744
|
+
const nodes = rawNodes.filter(isRecord4).flatMap((raw) => {
|
|
19745
|
+
if (typeof raw.id !== "string" || typeof raw.type !== "string") return [];
|
|
19746
|
+
const position = isRecord4(raw.position) ? {
|
|
19747
|
+
x: typeof raw.position.x === "number" ? raw.position.x : 0,
|
|
19748
|
+
y: typeof raw.position.y === "number" ? raw.position.y : 0
|
|
19749
|
+
} : { x: 0, y: 0 };
|
|
19750
|
+
const nodeData = isRecord4(raw.data) ? raw.data : {};
|
|
19751
|
+
const node = {
|
|
19752
|
+
...raw,
|
|
19753
|
+
id: raw.id,
|
|
19754
|
+
type: raw.type,
|
|
19755
|
+
position,
|
|
19756
|
+
data: nodeData,
|
|
19757
|
+
selected: false
|
|
19758
|
+
};
|
|
19759
|
+
return [node];
|
|
19760
|
+
});
|
|
19761
|
+
const ids = new Set(nodes.map((node) => node.id));
|
|
19762
|
+
const edges = rawEdges.filter(isRecord4).flatMap((raw) => {
|
|
19763
|
+
if (typeof raw.source !== "string" || typeof raw.target !== "string") {
|
|
19764
|
+
return [];
|
|
19765
|
+
}
|
|
19766
|
+
if (!ids.has(raw.source) || !ids.has(raw.target)) return [];
|
|
19767
|
+
const edge = {
|
|
19768
|
+
id: stringOr(raw.id, `e-${raw.source}-${raw.target}`),
|
|
19769
|
+
source: raw.source,
|
|
19770
|
+
target: raw.target,
|
|
19771
|
+
type: stringOr(raw.type, "deletable"),
|
|
19772
|
+
...typeof raw.sourceHandle === "string" ? { sourceHandle: raw.sourceHandle } : {},
|
|
19773
|
+
...typeof raw.targetHandle === "string" ? { targetHandle: raw.targetHandle } : {}
|
|
19774
|
+
};
|
|
19775
|
+
return [edge];
|
|
19776
|
+
});
|
|
19777
|
+
return { nodes, edges };
|
|
19778
|
+
}
|
|
19779
|
+
function enrichDraftNodes(nodes, seed) {
|
|
19780
|
+
return nodes.map((node) => {
|
|
19781
|
+
const data = isRecord4(node.data) ? node.data : {};
|
|
19782
|
+
const rootOperation = node.operation_name;
|
|
19783
|
+
let operationName;
|
|
19784
|
+
if (typeof data.operation_name === "string") {
|
|
19785
|
+
operationName = data.operation_name;
|
|
19786
|
+
} else if (typeof rootOperation === "string") {
|
|
19787
|
+
operationName = rootOperation;
|
|
19788
|
+
}
|
|
19789
|
+
if (!node.type || !operationName) return node;
|
|
19790
|
+
const seeded = seed(node.type, operationName, data);
|
|
19791
|
+
if (!seeded) return node;
|
|
19792
|
+
const seededArgs = isRecord4(seeded.args) ? seeded.args : {};
|
|
19793
|
+
const defaults = isRecord4(seededArgs.state) ? seededArgs.state : {};
|
|
19794
|
+
const draftArgs = isRecord4(data.args) ? data.args : {};
|
|
19795
|
+
const draftState = isRecord4(draftArgs.state) ? draftArgs.state : {};
|
|
19796
|
+
return {
|
|
19797
|
+
...node,
|
|
19798
|
+
data: {
|
|
19799
|
+
...seeded,
|
|
19800
|
+
args: { ...seededArgs, state: { ...defaults, ...draftState } }
|
|
19801
|
+
}
|
|
19802
|
+
};
|
|
19803
|
+
});
|
|
19804
|
+
}
|
|
19805
|
+
function summarizeDraftNodes(definitionJson) {
|
|
19806
|
+
return draftToCanvas(definitionJson).nodes.map((node) => {
|
|
19807
|
+
const data = isRecord4(node.data) ? node.data : {};
|
|
19808
|
+
const label = stringOr(
|
|
19809
|
+
node.label,
|
|
19810
|
+
stringOr(data.label, node.type ?? node.id)
|
|
19811
|
+
);
|
|
19812
|
+
return { id: node.id, type: node.type ?? "", label };
|
|
19813
|
+
});
|
|
19814
|
+
}
|
|
19815
|
+
function shortNodeType(type) {
|
|
19816
|
+
const afterColon = type.includes(":") ? type.split(":").pop() : type;
|
|
19817
|
+
const afterSlash = afterColon?.includes("/") ? afterColon.split("/").pop() : afterColon;
|
|
19818
|
+
return afterSlash ?? type;
|
|
19819
|
+
}
|
|
19820
|
+
function shouldKeepPolling(status, startedAt, now = Date.now()) {
|
|
19821
|
+
return status === "PROCESSING" && now - startedAt < AI_DRAFT_MAX_WAIT_MS;
|
|
19822
|
+
}
|
|
19823
|
+
function canvasHasWork(nodes) {
|
|
19824
|
+
return nodes.length > 1;
|
|
19825
|
+
}
|
|
19826
|
+
|
|
19827
|
+
// src/builder/hooks/use-ai-workflow-draft.ts
|
|
19828
|
+
function messageOf(error) {
|
|
19829
|
+
return error instanceof Error ? error.message : String(error);
|
|
19830
|
+
}
|
|
19831
|
+
function useAiWorkflowDraft() {
|
|
19832
|
+
const [generation, setGeneration] = useState(
|
|
19833
|
+
null
|
|
19834
|
+
);
|
|
19835
|
+
const [isGenerating, setIsGenerating] = useState(false);
|
|
19836
|
+
const [error, setError] = useState(null);
|
|
19837
|
+
const [timedOut, setTimedOut] = useState(false);
|
|
19838
|
+
const runRef = useRef(0);
|
|
19839
|
+
const timerRef = useRef(null);
|
|
19840
|
+
const clearTimer = useCallback(() => {
|
|
19841
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
19842
|
+
timerRef.current = null;
|
|
19843
|
+
}, []);
|
|
19844
|
+
const reset = useCallback(() => {
|
|
19845
|
+
runRef.current++;
|
|
19846
|
+
clearTimer();
|
|
19847
|
+
setGeneration(null);
|
|
19848
|
+
setIsGenerating(false);
|
|
19849
|
+
setError(null);
|
|
19850
|
+
setTimedOut(false);
|
|
19851
|
+
}, [clearTimer]);
|
|
19852
|
+
useEffect(
|
|
19853
|
+
() => () => {
|
|
19854
|
+
runRef.current++;
|
|
19855
|
+
clearTimer();
|
|
19856
|
+
},
|
|
19857
|
+
[clearTimer]
|
|
19858
|
+
);
|
|
19859
|
+
const poll = useCallback(
|
|
19860
|
+
async (run, id, startedAt) => {
|
|
19861
|
+
if (run !== runRef.current) return;
|
|
19862
|
+
try {
|
|
19863
|
+
const result = throwIfResultError(
|
|
19864
|
+
await getFluidGridsClient().query({
|
|
19865
|
+
query: WorkflowGenerationDocument,
|
|
19866
|
+
variables: { id },
|
|
19867
|
+
fetchPolicy: "network-only"
|
|
19868
|
+
})
|
|
19869
|
+
);
|
|
19870
|
+
if (run !== runRef.current) return;
|
|
19871
|
+
const next = result.data?.workflowGeneration ?? null;
|
|
19872
|
+
if (next) setGeneration(next);
|
|
19873
|
+
const status = next ? String(next.status) : void 0;
|
|
19874
|
+
if (shouldKeepPolling(status, startedAt)) {
|
|
19875
|
+
timerRef.current = setTimeout(
|
|
19876
|
+
() => void poll(run, id, startedAt),
|
|
19877
|
+
AI_DRAFT_POLL_INTERVAL_MS
|
|
19878
|
+
);
|
|
19879
|
+
return;
|
|
19880
|
+
}
|
|
19881
|
+
if (status === "PROCESSING") setTimedOut(true);
|
|
19882
|
+
setIsGenerating(false);
|
|
19883
|
+
} catch (pollError) {
|
|
19884
|
+
if (run !== runRef.current) return;
|
|
19885
|
+
setError(messageOf(pollError));
|
|
19886
|
+
setIsGenerating(false);
|
|
19887
|
+
}
|
|
19888
|
+
},
|
|
19889
|
+
[]
|
|
19890
|
+
);
|
|
19891
|
+
const start = useCallback(
|
|
19892
|
+
async (input) => {
|
|
19893
|
+
const run = ++runRef.current;
|
|
19894
|
+
clearTimer();
|
|
19895
|
+
setGeneration(null);
|
|
19896
|
+
setError(null);
|
|
19897
|
+
setTimedOut(false);
|
|
19898
|
+
setIsGenerating(true);
|
|
19899
|
+
try {
|
|
19900
|
+
const result = throwIfResultError(
|
|
19901
|
+
await getFluidGridsClient().mutate({
|
|
19902
|
+
mutation: GenerateWorkflowFromPromptDocument,
|
|
19903
|
+
variables: {
|
|
19904
|
+
input: {
|
|
19905
|
+
prompt: input.prompt,
|
|
19906
|
+
...input.template ? { template: input.template } : {},
|
|
19907
|
+
...input.baseDefinitionJson ? { baseDefinitionJson: input.baseDefinitionJson } : {},
|
|
19908
|
+
...input.workflowId ? { workflowId: input.workflowId } : {}
|
|
19909
|
+
}
|
|
19910
|
+
}
|
|
19911
|
+
})
|
|
19912
|
+
);
|
|
19913
|
+
const id = result.data?.generateWorkflowFromPrompt?.id;
|
|
19914
|
+
if (!id) throw new Error("The generation did not start");
|
|
19915
|
+
if (run !== runRef.current) return;
|
|
19916
|
+
timerRef.current = setTimeout(
|
|
19917
|
+
() => void poll(run, id, Date.now()),
|
|
19918
|
+
AI_DRAFT_POLL_INTERVAL_MS
|
|
19919
|
+
);
|
|
19920
|
+
} catch (startError) {
|
|
19921
|
+
if (run !== runRef.current) return;
|
|
19922
|
+
setError(messageOf(startError));
|
|
19923
|
+
setIsGenerating(false);
|
|
19924
|
+
}
|
|
19925
|
+
},
|
|
19926
|
+
[clearTimer, poll]
|
|
19927
|
+
);
|
|
19928
|
+
return { generation, isGenerating, error, timedOut, start, reset };
|
|
19929
|
+
}
|
|
19930
|
+
function useAiWorkflowTemplates(enabled) {
|
|
19931
|
+
const [templates, setTemplates] = useState(
|
|
19932
|
+
[]
|
|
19933
|
+
);
|
|
19934
|
+
useEffect(() => {
|
|
19935
|
+
if (!enabled) return;
|
|
19936
|
+
let active = true;
|
|
19937
|
+
getFluidGridsClient().query({
|
|
19938
|
+
query: WorkflowGenerationTemplatesDocument,
|
|
19939
|
+
fetchPolicy: "cache-first"
|
|
19940
|
+
}).then((result) => {
|
|
19941
|
+
if (active)
|
|
19942
|
+
setTemplates(result.data?.workflowGenerationTemplates ?? []);
|
|
19943
|
+
}).catch(() => {
|
|
19944
|
+
if (active) setTemplates([]);
|
|
19945
|
+
});
|
|
19946
|
+
return () => {
|
|
19947
|
+
active = false;
|
|
19948
|
+
};
|
|
19949
|
+
}, [enabled]);
|
|
19950
|
+
return templates;
|
|
19951
|
+
}
|
|
19952
|
+
var NO_TEMPLATE = "__none__";
|
|
19953
|
+
function AiDraftPanel({
|
|
19954
|
+
className,
|
|
19955
|
+
compact = false
|
|
19956
|
+
}) {
|
|
19957
|
+
const tr = useTr();
|
|
19958
|
+
const { id: workflowKey } = useParams();
|
|
19959
|
+
const { fitView } = useReactFlow();
|
|
19960
|
+
const [open, setOpen] = useState(false);
|
|
19961
|
+
const [prompt, setPrompt] = useState("");
|
|
19962
|
+
const [template, setTemplate] = useState(NO_TEMPLATE);
|
|
19963
|
+
const [refining, setRefining] = useState(false);
|
|
19964
|
+
const [confirmReplace, setConfirmReplace] = useState(false);
|
|
19965
|
+
const templates = useAiWorkflowTemplates(open);
|
|
19966
|
+
const { generation, isGenerating, error, timedOut, start, reset } = useAiWorkflowDraft();
|
|
19967
|
+
const [nodes, setNodes, setEdges] = useFlowStore(
|
|
19968
|
+
useShallow((s) => [
|
|
19969
|
+
s.workflow.nodes,
|
|
19970
|
+
s.actions.nodes.setNodes,
|
|
19971
|
+
s.actions.edges.setEdges
|
|
19972
|
+
])
|
|
19973
|
+
);
|
|
19974
|
+
const status = generation ? String(generation.status) : void 0;
|
|
19975
|
+
const draft = status === "COMPLETED" ? generation?.draft ?? null : null;
|
|
19976
|
+
const failed = status === "FAILED";
|
|
19977
|
+
const draftNodes = useMemo(
|
|
19978
|
+
() => draft ? summarizeDraftNodes(draft.definitionJson) : [],
|
|
19979
|
+
[draft]
|
|
19980
|
+
);
|
|
19981
|
+
const trimmed = prompt.trim();
|
|
19982
|
+
const handleGenerate = useCallback(() => {
|
|
19983
|
+
if (!trimmed) return;
|
|
19984
|
+
void start({
|
|
19985
|
+
prompt: trimmed,
|
|
19986
|
+
...template !== NO_TEMPLATE ? { template } : {},
|
|
19987
|
+
...refining && draft ? { baseDefinitionJson: draft.definitionJson } : {},
|
|
19988
|
+
...workflowKey ? { workflowId: workflowKey } : {}
|
|
19989
|
+
});
|
|
19990
|
+
}, [draft, refining, start, template, trimmed, workflowKey]);
|
|
19991
|
+
const applyDraft = useCallback(() => {
|
|
19992
|
+
if (!draft) return;
|
|
19993
|
+
const canvas = draftToCanvas(draft.definitionJson);
|
|
19994
|
+
const nodes2 = enrichDraftNodes(canvas.nodes, buildOperationSeed);
|
|
19995
|
+
registerWorkflowNodeTypes(nodes2);
|
|
19996
|
+
setNodes(nodes2, { historyKind: "ai-draft:apply" });
|
|
19997
|
+
setEdges(canvas.edges, { skipHistory: true });
|
|
19998
|
+
setConfirmReplace(false);
|
|
19999
|
+
setOpen(false);
|
|
20000
|
+
reset();
|
|
20001
|
+
setPrompt("");
|
|
20002
|
+
setRefining(false);
|
|
20003
|
+
setTimeout(() => void fitView({ padding: 0.2, duration: 300 }), 50);
|
|
20004
|
+
toast.success(
|
|
20005
|
+
tr(
|
|
20006
|
+
"fluidgrids.builder.aiDraft.appliedToast",
|
|
20007
|
+
"Draft added to the canvas"
|
|
20008
|
+
),
|
|
20009
|
+
{
|
|
20010
|
+
description: tr(
|
|
20011
|
+
"fluidgrids.builder.aiDraft.appliedToastDescription",
|
|
20012
|
+
"Review each node's settings, then save the workflow."
|
|
20013
|
+
)
|
|
20014
|
+
}
|
|
20015
|
+
);
|
|
20016
|
+
}, [draft, fitView, reset, setEdges, setNodes, tr]);
|
|
20017
|
+
const handleAccept = useCallback(() => {
|
|
20018
|
+
if (canvasHasWork(nodes)) setConfirmReplace(true);
|
|
20019
|
+
else applyDraft();
|
|
20020
|
+
}, [applyDraft, nodes]);
|
|
20021
|
+
const handleRefine = useCallback(() => {
|
|
20022
|
+
setRefining(true);
|
|
20023
|
+
setPrompt("");
|
|
20024
|
+
}, []);
|
|
20025
|
+
const handleReject = useCallback(() => {
|
|
20026
|
+
reset();
|
|
20027
|
+
setRefining(false);
|
|
20028
|
+
}, [reset]);
|
|
20029
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20030
|
+
/* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
|
|
20031
|
+
/* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
20032
|
+
Button$1,
|
|
20033
|
+
{
|
|
20034
|
+
variant: "outline",
|
|
20035
|
+
size: compact ? "icon" : "sm",
|
|
20036
|
+
"data-tour": "fluidgrids-builder-ai-draft",
|
|
20037
|
+
"data-testid": "ai-draft-open",
|
|
20038
|
+
"aria-label": tr(
|
|
20039
|
+
"fluidgrids.builder.aiDraft.openButton",
|
|
20040
|
+
"Generate with AI"
|
|
20041
|
+
),
|
|
20042
|
+
title: tr(
|
|
20043
|
+
"fluidgrids.builder.aiDraft.openButton",
|
|
20044
|
+
"Generate with AI"
|
|
20045
|
+
),
|
|
20046
|
+
className: cn$1("flex gap-2", className),
|
|
20047
|
+
children: [
|
|
20048
|
+
/* @__PURE__ */ jsx(Sparkles, { className: "size-4" }),
|
|
20049
|
+
!compact && tr("fluidgrids.builder.aiDraft.openButton", "Generate with AI")
|
|
20050
|
+
]
|
|
20051
|
+
}
|
|
20052
|
+
) }),
|
|
20053
|
+
/* @__PURE__ */ jsxs(
|
|
20054
|
+
SheetContent,
|
|
20055
|
+
{
|
|
20056
|
+
side: "right",
|
|
20057
|
+
className: "flex w-full flex-col gap-4 overflow-y-auto sm:max-w-lg",
|
|
20058
|
+
children: [
|
|
20059
|
+
/* @__PURE__ */ jsxs(SheetHeader, { children: [
|
|
20060
|
+
/* @__PURE__ */ jsx(SheetTitle, { children: tr("fluidgrids.builder.aiDraft.title", "Generate with AI") }),
|
|
20061
|
+
/* @__PURE__ */ jsx(SheetDescription, { children: tr(
|
|
20062
|
+
"fluidgrids.builder.aiDraft.description",
|
|
20063
|
+
"Describe what the workflow should do. You review the draft before anything changes on the canvas."
|
|
20064
|
+
) })
|
|
20065
|
+
] }),
|
|
20066
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 px-4", children: [
|
|
20067
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
20068
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "ai-draft-prompt", children: refining ? tr(
|
|
20069
|
+
"fluidgrids.builder.aiDraft.refineLabel",
|
|
20070
|
+
"What should change in this draft?"
|
|
20071
|
+
) : tr(
|
|
20072
|
+
"fluidgrids.builder.aiDraft.promptLabel",
|
|
20073
|
+
"Describe the workflow"
|
|
20074
|
+
) }),
|
|
20075
|
+
/* @__PURE__ */ jsx(
|
|
20076
|
+
Textarea,
|
|
20077
|
+
{
|
|
20078
|
+
id: "ai-draft-prompt",
|
|
20079
|
+
"data-testid": "ai-draft-prompt",
|
|
20080
|
+
rows: 5,
|
|
20081
|
+
maxLength: AI_DRAFT_MAX_PROMPT_LENGTH,
|
|
20082
|
+
value: prompt,
|
|
20083
|
+
disabled: isGenerating,
|
|
20084
|
+
placeholder: tr(
|
|
20085
|
+
"fluidgrids.builder.aiDraft.promptPlaceholder",
|
|
20086
|
+
"Every weekday at 9am, fetch new orders from our API, keep the ones over 500 and post a summary to a webhook. Log the rest."
|
|
20087
|
+
),
|
|
20088
|
+
onChange: (event) => setPrompt(event.target.value)
|
|
20089
|
+
}
|
|
20090
|
+
),
|
|
20091
|
+
/* @__PURE__ */ jsxs("span", { className: "self-end text-xs text-muted-foreground", children: [
|
|
20092
|
+
prompt.length,
|
|
20093
|
+
"/",
|
|
20094
|
+
AI_DRAFT_MAX_PROMPT_LENGTH
|
|
20095
|
+
] })
|
|
20096
|
+
] }),
|
|
20097
|
+
!refining && templates.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
20098
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "ai-draft-template", children: tr(
|
|
20099
|
+
"fluidgrids.builder.aiDraft.templateLabel",
|
|
20100
|
+
"Starting pattern (optional)"
|
|
20101
|
+
) }),
|
|
20102
|
+
/* @__PURE__ */ jsxs(
|
|
20103
|
+
Select,
|
|
20104
|
+
{
|
|
20105
|
+
value: template,
|
|
20106
|
+
onValueChange: setTemplate,
|
|
20107
|
+
disabled: isGenerating,
|
|
20108
|
+
children: [
|
|
20109
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id: "ai-draft-template", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
20110
|
+
/* @__PURE__ */ jsxs(SelectContent, { className: "z-[130]", children: [
|
|
20111
|
+
/* @__PURE__ */ jsx(SelectItem, { value: NO_TEMPLATE, children: tr(
|
|
20112
|
+
"fluidgrids.builder.aiDraft.noTemplate",
|
|
20113
|
+
"No pattern"
|
|
20114
|
+
) }),
|
|
20115
|
+
templates.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.id, children: option.name }, option.id))
|
|
20116
|
+
] })
|
|
20117
|
+
]
|
|
20118
|
+
}
|
|
20119
|
+
)
|
|
20120
|
+
] }),
|
|
20121
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
20122
|
+
/* @__PURE__ */ jsxs(
|
|
20123
|
+
Button$1,
|
|
20124
|
+
{
|
|
20125
|
+
"data-testid": "ai-draft-generate",
|
|
20126
|
+
onClick: handleGenerate,
|
|
20127
|
+
disabled: !trimmed || isGenerating,
|
|
20128
|
+
className: "flex gap-2",
|
|
20129
|
+
children: [
|
|
20130
|
+
isGenerating ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx(Sparkles, { className: "size-4" }),
|
|
20131
|
+
refining ? tr(
|
|
20132
|
+
"fluidgrids.builder.aiDraft.refineButton",
|
|
20133
|
+
"Refine draft"
|
|
20134
|
+
) : tr("fluidgrids.builder.aiDraft.generateButton", "Generate")
|
|
20135
|
+
]
|
|
20136
|
+
}
|
|
20137
|
+
),
|
|
20138
|
+
refining && !isGenerating && /* @__PURE__ */ jsx(Button$1, { variant: "ghost", onClick: () => setRefining(false), children: tr("fluidgrids.builder.aiDraft.cancelRefine", "Cancel") })
|
|
20139
|
+
] }),
|
|
20140
|
+
isGenerating && /* @__PURE__ */ jsx(
|
|
20141
|
+
"p",
|
|
20142
|
+
{
|
|
20143
|
+
className: "text-sm text-muted-foreground",
|
|
20144
|
+
"data-testid": "ai-draft-progress",
|
|
20145
|
+
children: tr(
|
|
20146
|
+
"fluidgrids.builder.aiDraft.generating",
|
|
20147
|
+
"Designing your workflow. This usually takes under a minute."
|
|
20148
|
+
)
|
|
20149
|
+
}
|
|
20150
|
+
),
|
|
20151
|
+
(error || timedOut) && /* @__PURE__ */ jsx(
|
|
20152
|
+
"div",
|
|
20153
|
+
{
|
|
20154
|
+
role: "alert",
|
|
20155
|
+
className: "rounded-md border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bg-subtle)] p-3 text-sm text-[var(--color-status-error-text)]",
|
|
20156
|
+
children: timedOut ? tr(
|
|
20157
|
+
"fluidgrids.builder.aiDraft.timedOut",
|
|
20158
|
+
"The draft is taking longer than expected. Try again in a moment."
|
|
20159
|
+
) : error
|
|
20160
|
+
}
|
|
20161
|
+
),
|
|
20162
|
+
failed && /* @__PURE__ */ jsxs(
|
|
20163
|
+
"div",
|
|
20164
|
+
{
|
|
20165
|
+
role: "alert",
|
|
20166
|
+
"data-testid": "ai-draft-failed",
|
|
20167
|
+
className: "flex flex-col gap-2 rounded-md border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bg-subtle)] p-3 text-sm text-[var(--color-status-error-text)]",
|
|
20168
|
+
children: [
|
|
20169
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: generation?.message ?? tr(
|
|
20170
|
+
"fluidgrids.builder.aiDraft.failed",
|
|
20171
|
+
"The workflow could not be generated."
|
|
20172
|
+
) }),
|
|
20173
|
+
(generation?.validation?.errors ?? []).length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-disc pl-4", children: generation?.validation?.errors.map((message) => /* @__PURE__ */ jsx("li", { children: message }, message)) }),
|
|
20174
|
+
/* @__PURE__ */ jsx("span", { children: tr(
|
|
20175
|
+
"fluidgrids.builder.aiDraft.failedHint",
|
|
20176
|
+
"Try describing the steps more concretely, then generate again."
|
|
20177
|
+
) })
|
|
20178
|
+
]
|
|
20179
|
+
}
|
|
20180
|
+
),
|
|
20181
|
+
draft && /* @__PURE__ */ jsxs(
|
|
20182
|
+
"div",
|
|
20183
|
+
{
|
|
20184
|
+
"data-testid": "ai-draft-result",
|
|
20185
|
+
className: "flex flex-col gap-3 rounded-lg border border-border bg-card p-3",
|
|
20186
|
+
children: [
|
|
20187
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
20188
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-card-foreground", children: draft.name }),
|
|
20189
|
+
draft.explanation && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: draft.explanation })
|
|
20190
|
+
] }),
|
|
20191
|
+
/* @__PURE__ */ jsx(
|
|
20192
|
+
"ol",
|
|
20193
|
+
{
|
|
20194
|
+
className: "flex flex-col gap-1.5",
|
|
20195
|
+
"data-testid": "ai-draft-nodes",
|
|
20196
|
+
children: draftNodes.map((node, index) => /* @__PURE__ */ jsxs(
|
|
20197
|
+
"li",
|
|
20198
|
+
{
|
|
20199
|
+
className: "flex items-center justify-between gap-2 text-sm",
|
|
20200
|
+
children: [
|
|
20201
|
+
/* @__PURE__ */ jsxs("span", { className: "truncate text-card-foreground", children: [
|
|
20202
|
+
index + 1,
|
|
20203
|
+
". ",
|
|
20204
|
+
node.label
|
|
20205
|
+
] }),
|
|
20206
|
+
/* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "shrink-0", children: shortNodeType(node.type) })
|
|
20207
|
+
]
|
|
20208
|
+
},
|
|
20209
|
+
node.id
|
|
20210
|
+
))
|
|
20211
|
+
}
|
|
20212
|
+
),
|
|
20213
|
+
(generation?.validation?.warnings ?? []).length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bg-subtle)] p-2 text-xs text-[var(--color-status-warning-text)]", children: [
|
|
20214
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: tr(
|
|
20215
|
+
"fluidgrids.builder.aiDraft.warningsTitle",
|
|
20216
|
+
"Still to configure:"
|
|
20217
|
+
) }),
|
|
20218
|
+
/* @__PURE__ */ jsx("ul", { className: "list-disc pl-4", children: generation?.validation?.warnings.map((message) => /* @__PURE__ */ jsx("li", { children: message }, message)) })
|
|
20219
|
+
] }),
|
|
20220
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
20221
|
+
/* @__PURE__ */ jsx(
|
|
20222
|
+
Button$1,
|
|
20223
|
+
{
|
|
20224
|
+
"data-testid": "ai-draft-accept",
|
|
20225
|
+
onClick: handleAccept,
|
|
20226
|
+
className: "flex gap-2",
|
|
20227
|
+
children: tr("fluidgrids.builder.aiDraft.accept", "Add to canvas")
|
|
20228
|
+
}
|
|
20229
|
+
),
|
|
20230
|
+
/* @__PURE__ */ jsx(
|
|
20231
|
+
Button$1,
|
|
20232
|
+
{
|
|
20233
|
+
variant: "outline",
|
|
20234
|
+
"data-testid": "ai-draft-refine",
|
|
20235
|
+
onClick: handleRefine,
|
|
20236
|
+
children: tr("fluidgrids.builder.aiDraft.refine", "Refine")
|
|
20237
|
+
}
|
|
20238
|
+
),
|
|
20239
|
+
/* @__PURE__ */ jsx(
|
|
20240
|
+
Button$1,
|
|
20241
|
+
{
|
|
20242
|
+
variant: "ghost",
|
|
20243
|
+
"data-testid": "ai-draft-reject",
|
|
20244
|
+
onClick: handleReject,
|
|
20245
|
+
children: tr("fluidgrids.builder.aiDraft.reject", "Discard")
|
|
20246
|
+
}
|
|
20247
|
+
)
|
|
20248
|
+
] })
|
|
20249
|
+
]
|
|
20250
|
+
}
|
|
20251
|
+
)
|
|
20252
|
+
] })
|
|
20253
|
+
]
|
|
20254
|
+
}
|
|
20255
|
+
)
|
|
20256
|
+
] }),
|
|
20257
|
+
/* @__PURE__ */ jsx(AlertDialog, { open: confirmReplace, onOpenChange: setConfirmReplace, children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
|
|
20258
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
20259
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: tr(
|
|
20260
|
+
"fluidgrids.builder.aiDraft.replaceTitle",
|
|
20261
|
+
"Replace the current canvas?"
|
|
20262
|
+
) }),
|
|
20263
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { children: tr(
|
|
20264
|
+
"fluidgrids.builder.aiDraft.replaceDescription",
|
|
20265
|
+
"The draft replaces the nodes on the canvas. You can undo this, and nothing is saved until you save the workflow."
|
|
20266
|
+
) })
|
|
20267
|
+
] }),
|
|
20268
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
|
|
20269
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { children: tr("fluidgrids.builder.aiDraft.replaceCancel", "Keep canvas") }),
|
|
20270
|
+
/* @__PURE__ */ jsx(
|
|
20271
|
+
AlertDialogAction,
|
|
20272
|
+
{
|
|
20273
|
+
"data-testid": "ai-draft-replace-confirm",
|
|
20274
|
+
onClick: applyDraft,
|
|
20275
|
+
children: tr("fluidgrids.builder.aiDraft.replaceConfirm", "Replace")
|
|
20276
|
+
}
|
|
20277
|
+
)
|
|
20278
|
+
] })
|
|
20279
|
+
] }) })
|
|
20280
|
+
] });
|
|
20281
|
+
}
|
|
19729
20282
|
var ActivateWorkflowButton = ({
|
|
19730
20283
|
className
|
|
19731
20284
|
}) => {
|
|
@@ -20071,6 +20624,7 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
20071
20624
|
] }),
|
|
20072
20625
|
name !== "" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20073
20626
|
/* @__PURE__ */ jsxs("div", { className: "hidden shrink-0 lg:inline-flex items-center gap-2", children: [
|
|
20627
|
+
!isReadOnly && /* @__PURE__ */ jsx(AiDraftPanel, {}),
|
|
20074
20628
|
/* @__PURE__ */ jsx(VersionHistoryPanel, {}),
|
|
20075
20629
|
/* @__PURE__ */ jsx(SaveFlowButton, {}),
|
|
20076
20630
|
/* @__PURE__ */ jsx(ActivateWorkflowButton, {}),
|
|
@@ -20091,47 +20645,50 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
20091
20645
|
}
|
|
20092
20646
|
)
|
|
20093
20647
|
] }),
|
|
20094
|
-
/* @__PURE__ */
|
|
20095
|
-
/* @__PURE__ */ jsx(
|
|
20096
|
-
|
|
20097
|
-
{
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20101
|
-
|
|
20102
|
-
|
|
20103
|
-
|
|
20104
|
-
|
|
20105
|
-
|
|
20106
|
-
|
|
20107
|
-
|
|
20108
|
-
|
|
20109
|
-
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
|
|
20113
|
-
|
|
20114
|
-
|
|
20115
|
-
|
|
20116
|
-
|
|
20117
|
-
|
|
20118
|
-
|
|
20119
|
-
|
|
20120
|
-
|
|
20121
|
-
|
|
20122
|
-
|
|
20123
|
-
|
|
20124
|
-
|
|
20125
|
-
|
|
20126
|
-
|
|
20127
|
-
|
|
20128
|
-
|
|
20129
|
-
|
|
20130
|
-
|
|
20131
|
-
|
|
20132
|
-
|
|
20133
|
-
|
|
20134
|
-
|
|
20648
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1 lg:hidden", children: [
|
|
20649
|
+
!isReadOnly && /* @__PURE__ */ jsx(AiDraftPanel, { compact: true }),
|
|
20650
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
20651
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
20652
|
+
Button$1,
|
|
20653
|
+
{
|
|
20654
|
+
variant: "ghost",
|
|
20655
|
+
size: "icon",
|
|
20656
|
+
className: "text-card-foreground",
|
|
20657
|
+
"data-tour": "fluidgrids-builder-actions-menu",
|
|
20658
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: "mynaui:dots-vertical", className: "size-5" })
|
|
20659
|
+
}
|
|
20660
|
+
) }),
|
|
20661
|
+
/* @__PURE__ */ jsxs(
|
|
20662
|
+
DropdownMenuContent,
|
|
20663
|
+
{
|
|
20664
|
+
align: "end",
|
|
20665
|
+
className: "flex flex-col gap-1.5 p-2 w-56",
|
|
20666
|
+
children: [
|
|
20667
|
+
/* @__PURE__ */ jsx(VersionHistoryPanel, { className: "w-full justify-start" }),
|
|
20668
|
+
/* @__PURE__ */ jsx(SaveFlowButton, { className: "w-full justify-start" }),
|
|
20669
|
+
/* @__PURE__ */ jsx(ActivateWorkflowButton, { className: "w-full justify-start" }),
|
|
20670
|
+
/* @__PURE__ */ jsx(
|
|
20671
|
+
RunWithViewRuns,
|
|
20672
|
+
{
|
|
20673
|
+
onViewRuns: handleViewRuns,
|
|
20674
|
+
canViewRuns: !!id,
|
|
20675
|
+
className: "w-full",
|
|
20676
|
+
runButtonClassName: "flex-1 justify-start rounded-l-lg"
|
|
20677
|
+
}
|
|
20678
|
+
),
|
|
20679
|
+
/* @__PURE__ */ jsx(
|
|
20680
|
+
FluidGridsDocsLink,
|
|
20681
|
+
{
|
|
20682
|
+
topic: "builder",
|
|
20683
|
+
className: "w-full rounded-md px-3 py-2",
|
|
20684
|
+
children: tr("fluidgrids.docs.builderGuide", "Builder guide")
|
|
20685
|
+
}
|
|
20686
|
+
)
|
|
20687
|
+
]
|
|
20688
|
+
}
|
|
20689
|
+
)
|
|
20690
|
+
] })
|
|
20691
|
+
] })
|
|
20135
20692
|
] })
|
|
20136
20693
|
] }),
|
|
20137
20694
|
/* @__PURE__ */ jsxs(
|