@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.
Files changed (50) hide show
  1. package/dist/ExecutionDetailPage-ACTSQG5E.js +20 -0
  2. package/dist/{ExecutionsListPage-IMN7OTNZ.js → ExecutionsListPage-FABXLXWT.js} +8 -8
  3. package/dist/WorkflowBuilder-OECFTQDQ.js +24 -0
  4. package/dist/WorkflowsList-4HG3KBMR.js +20 -0
  5. package/dist/{chunk-IQE7ZY6Q.js → chunk-2ZV6UJD6.js} +2 -2
  6. package/dist/{chunk-F6NH55LU.js → chunk-3GOZYLTM.js} +3 -3
  7. package/dist/{chunk-ACUNTZTQ.js → chunk-3LYRZ4KN.js} +3 -3
  8. package/dist/{chunk-MKKBEVXO.js → chunk-6T5EBO7G.js} +1 -1
  9. package/dist/chunk-77NA7TPJ.js +38 -0
  10. package/dist/{chunk-QW24ZBSR.js → chunk-7OJDILWM.js} +1 -1
  11. package/dist/{chunk-6J4RR46J.js → chunk-7PBOU7JC.js} +2 -1
  12. package/dist/{chunk-NAFJQGLV.js → chunk-DL2OCKHC.js} +5 -5
  13. package/dist/{chunk-LOZ6XNOX.js → chunk-DOPSPCO3.js} +26 -1
  14. package/dist/{chunk-FO22JCOW.js → chunk-EAF47LYM.js} +368 -103
  15. package/dist/{chunk-XZPXIOGE.js → chunk-GGINSR75.js} +1402 -7
  16. package/dist/{chunk-FDEZGRRL.js → chunk-GQQV2L74.js} +1 -1
  17. package/dist/{chunk-UWNYWWWG.js → chunk-ILTWXDRG.js} +4 -4
  18. package/dist/{chunk-VP2RXXRF.js → chunk-J3PETXDA.js} +7 -7
  19. package/dist/{chunk-WBH2XEWO.js → chunk-JUUYPCFY.js} +4 -1
  20. package/dist/chunk-M62CJVTR.js +458 -0
  21. package/dist/{chunk-C4AY6JI2.js → chunk-NVUJFHTQ.js} +2 -2
  22. package/dist/{chunk-A2JSAGNQ.js → chunk-OAFNNQN7.js} +1 -1
  23. package/dist/{chunk-RLA4YUDY.js → chunk-OYFBLD5F.js} +3 -3
  24. package/dist/{chunk-STPQQDIJ.js → chunk-QBEQOQF7.js} +867 -127
  25. package/dist/{chunk-3KNW5QLR.js → chunk-SQ6VSXFI.js} +2 -2
  26. package/dist/chunk-TX6WIT3N.js +749 -0
  27. package/dist/{chunk-I2ZNBBRK.js → chunk-VFPIMW52.js} +3 -14
  28. package/dist/{chunk-VQHBQAJY.js → chunk-VZHR7FCD.js} +3 -3
  29. package/dist/{chunk-3VJ3AIFS.js → chunk-YNOR2AGJ.js} +2 -2
  30. package/dist/{chunk-RZQPHWFV.js → chunk-YQZ7HBOJ.js} +5 -3
  31. package/dist/{chunk-Q22GC7RJ.js → chunk-ZFCXCSY4.js} +1 -1
  32. package/dist/executions.js +13 -13
  33. package/dist/global-operations-D2USVOPM.js +2 -0
  34. package/dist/history.js +5 -5
  35. package/dist/index.d.ts +1294 -57
  36. package/dist/index.js +37 -35
  37. package/dist/nodes.js +2 -2
  38. package/dist/observability.js +8 -7
  39. package/dist/settings.js +8 -6
  40. package/dist/templates.js +12 -10
  41. package/dist/{workflow-builder-C7qKY7LD.d.ts → workflow-builder-BxyapBo5.d.ts} +18 -0
  42. package/dist/workflow-builder.d.ts +1 -1
  43. package/dist/workflow-builder.js +14 -12
  44. package/dist/workflows-list.js +10 -8
  45. package/package.json +1 -1
  46. package/dist/ExecutionDetailPage-DHIQNBAZ.js +0 -20
  47. package/dist/WorkflowBuilder-VJAAKETX.js +0 -22
  48. package/dist/WorkflowsList-3EWDWWIH.js +0 -18
  49. package/dist/chunk-HHN2TIK2.js +0 -59
  50. package/dist/global-operations-ZWQZ7DNT.js +0 -2
@@ -2,16 +2,18 @@ import { deepClone, applyTemplateInputs } from './chunk-GEMNVFPK.js';
2
2
  import { Input } 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-HHN2TIK2.js';
6
- import { EntityTagPicker, useWorkflowProposal, WorkflowProposalCard } from './chunk-VQHBQAJY.js';
7
- import { useRestoreWorkflowVersion, useWorkflowVersions, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-RZQPHWFV.js';
5
+ import { QuotaExhaustedDialog, useWorkflowCodeExport, orderedExportFiles, fileBaseName, downloadWorkflowCodeExport, isLosslessReport, sortFidelityItems, isLossyFidelityItem, lineOfNode } from './chunk-M62CJVTR.js';
6
+ import { EntityTagPicker, useWorkflowProposal, WorkflowProposalCard } from './chunk-VZHR7FCD.js';
7
+ import { useRestoreWorkflowVersion, useWorkflowVersions, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-YQZ7HBOJ.js';
8
+ import { isAgentNodeType, AgentDefinitionSelectField } from './chunk-TX6WIT3N.js';
8
9
  import { FluidGridsDocsLink } from './chunk-4VJ3MDOV.js';
9
- import { NODE_CONFIGS, createConfiguredNode, resolveOutputHandles, resolveInputHandles, isNodeConfigsInitialized, useFlowStore, getNodeDetail, useSaveStatusStore, liveInternalOperations, resolveNodeOperation, readDisplayOptions, parseParameterValue, canAutosave, STICKY_NOTE_TYPE, isNodeTrigger, resolveUiSpec, RUNS_QUOTA_NAME, throwIfResultError, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useIsValidConnection, refetchStoreNodes, AVAILABLE_NODES, useInsertNode, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, fieldsFromValue, useFluidGridsAnalytics, useSaveWorkflow, workflowFingerprint, buildStickyNode, useNodeRegistryRevision, fieldsFromIO, isParamVisible, ConnectionSelector, structuredParameterType, nodeAccent, NodeTypeIcon, NODES_METADATA, useConnections, ConnectionFormDialog, SdkPermissionButton, FLUIDGRIDS_PERMISSIONS, saveIndicatorOf, inAppLeaveTarget, declaredOutputFields, subscribeWorkflowSaved, pathToExpression, ExpressionEditor, formatParameterValue, leaveNeedsConfirmation, buildOperationSeed, snapshotForSave, editStateOf, isImageIcon, NODES, synchronizeOperationUpdate, NodePropertyPanel, openRunQuotaUpgradePrompt, describeOperationError, isTriggerOperation, canRenderOperationPanel, resolveOperationName, AUTOSAVE_RETRY_DELAYS_MS, AUTOSAVE_DEBOUNCE_MS } from './chunk-C4AY6JI2.js';
10
+ import { useFluidGridsFlag, FLUIDGRIDS_FLAGS } from './chunk-77NA7TPJ.js';
11
+ import { NODE_CONFIGS, createConfiguredNode, resolveOutputHandles, resolveInputHandles, isNodeConfigsInitialized, useFlowStore, getNodeDetail, useSaveStatusStore, liveInternalOperations, resolveNodeOperation, readDisplayOptions, parseParameterValue, canAutosave, STICKY_NOTE_TYPE, isNodeTrigger, resolveUiSpec, RUNS_QUOTA_NAME, throwIfResultError, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useIsValidConnection, refetchStoreNodes, AVAILABLE_NODES, useInsertNode, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, fieldsFromValue, useFluidGridsAnalytics, useSaveWorkflow, workflowFingerprint, buildStickyNode, useNodeRegistryRevision, fieldsFromIO, isParamVisible, ConnectionSelector, structuredParameterType, nodeAccent, NodeTypeIcon, NODES_METADATA, useConnections, ConnectionFormDialog, SdkPermissionButton, FLUIDGRIDS_PERMISSIONS, saveIndicatorOf, inAppLeaveTarget, declaredOutputFields, subscribeWorkflowSaved, pathToExpression, ExpressionEditor, formatParameterValue, leaveNeedsConfirmation, buildOperationSeed, snapshotForSave, editStateOf, isImageIcon, NODES, synchronizeOperationUpdate, NodePropertyPanel, describeOperationError, openRunQuotaUpgradePrompt, isTriggerOperation, canRenderOperationPanel, resolveOperationName, AUTOSAVE_RETRY_DELAYS_MS, AUTOSAVE_DEBOUNCE_MS } from './chunk-NVUJFHTQ.js';
10
12
  import { cn } from './chunk-JL7CASN5.js';
11
13
  import { getGlobalStoreClient } from './chunk-PXIFUMLA.js';
12
14
  import { getFluidGridsConfig } from './chunk-CY6KX4RG.js';
13
- import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument } from './chunk-WBH2XEWO.js';
14
- import { WorkspaceRunsQuotaDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, WorkflowGenerationTemplatesDocument, WorkflowEnvironmentsDocument, WorkflowPromotionRequestsDocument, DeployWorkflowVersionToDevDocument, RequestWorkflowPromotionDocument, ApproveWorkflowPromotionDocument, RejectWorkflowPromotionDocument, CancelWorkflowPromotionDocument, UpdateWorkflowEnvironmentPolicyDocument, WorkflowGitRepositoryDocument, WorkflowGitPushesDocument, WorkflowGitCommitsDocument, LinkWorkflowGitRepositoryDocument, UnlinkWorkflowGitRepositoryDocument, PushWorkflowToGitDocument, WorkflowGitDiffDocument, RestoreWorkflowFromGitDocument, WorkflowAuthoringDocument, PreviewScheduleDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-6J4RR46J.js';
15
+ import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument, OrganizationPrivateNodesDocument, InstallOrganizationPrivateNodeDocument, UninstallOrganizationPrivateNodeDocument } from './chunk-JUUYPCFY.js';
16
+ import { WorkspaceRunsQuotaDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, WorkflowGenerationTemplatesDocument, WorkflowEnvironmentsDocument, WorkflowPromotionRequestsDocument, DeployWorkflowVersionToDevDocument, RequestWorkflowPromotionDocument, ApproveWorkflowPromotionDocument, RejectWorkflowPromotionDocument, CancelWorkflowPromotionDocument, UpdateWorkflowEnvironmentPolicyDocument, WorkflowGitRepositoryDocument, WorkflowGitPushesDocument, WorkflowGitCommitsDocument, LinkWorkflowGitRepositoryDocument, UnlinkWorkflowGitRepositoryDocument, PushWorkflowToGitDocument, WorkflowGitDiffDocument, RestoreWorkflowFromGitDocument, WorkflowAuthoringDocument, PreviewScheduleDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-7PBOU7JC.js';
15
17
  import { useTr } from './chunk-UULVIT25.js';
16
18
  import { getFluidGridsClient, waitForFluidGridsClient, getFluidGridsClientSafe } from './chunk-NTWG3CJX.js';
17
19
  import { __export } from './chunk-62GWEYJ5.js';
@@ -901,11 +903,11 @@ function useInstallNode() {
901
903
  installation: installationResult
902
904
  };
903
905
  } catch (error62) {
904
- const errorMessage = error62 instanceof Error ? error62.message : "Installation failed";
906
+ const errorMessage2 = error62 instanceof Error ? error62.message : "Installation failed";
905
907
  console.error("[useInstallNode] Installation failed:", error62);
906
908
  return {
907
909
  success: false,
908
- error: errorMessage
910
+ error: errorMessage2
909
911
  };
910
912
  } finally {
911
913
  setInstalling(null);
@@ -1557,11 +1559,11 @@ function useCreateOrder() {
1557
1559
  };
1558
1560
  } catch (error62) {
1559
1561
  console.error("[useCreateOrder] Failed to create order:", error62);
1560
- const errorMessage = error62 instanceof Error ? error62.message : "Failed to create order";
1562
+ const errorMessage2 = error62 instanceof Error ? error62.message : "Failed to create order";
1561
1563
  setCreating(false);
1562
1564
  return {
1563
1565
  success: false,
1564
- error: errorMessage
1566
+ error: errorMessage2
1565
1567
  };
1566
1568
  }
1567
1569
  },
@@ -1584,6 +1586,92 @@ gql$1`
1584
1586
  }
1585
1587
  }
1586
1588
  `;
1589
+ function errorMessage(error62, fallback) {
1590
+ return error62 instanceof Error && error62.message ? error62.message : fallback;
1591
+ }
1592
+ function useOrganizationPrivateNodes() {
1593
+ const client = useGlobalStoreClient();
1594
+ const context = useContext(FluidGridsContext);
1595
+ const workspaceId = context?.workspaceId ?? getFluidGridsConfig().workspaceId;
1596
+ const { refreshAvailableNodes } = useRefreshAvailableNodes();
1597
+ const [busyApplicationId, setBusyApplicationId] = useState(
1598
+ null
1599
+ );
1600
+ const { data, loading, error: error62, refetch } = useQuery(OrganizationPrivateNodesDocument, {
1601
+ client,
1602
+ variables: { workspaceId: workspaceId || "" },
1603
+ skip: !workspaceId,
1604
+ fetchPolicy: "cache-and-network"
1605
+ });
1606
+ const [installMutation] = useMutation(InstallOrganizationPrivateNodeDocument, { client });
1607
+ const [uninstallMutation] = useMutation(UninstallOrganizationPrivateNodeDocument, { client });
1608
+ const afterChange = useCallback(async () => {
1609
+ await refreshAvailableNodes();
1610
+ await refetch();
1611
+ }, [refreshAvailableNodes, refetch]);
1612
+ const install = useCallback(
1613
+ async (node2) => {
1614
+ if (!workspaceId) return { success: false, error: "No workspace" };
1615
+ setBusyApplicationId(node2.applicationId);
1616
+ try {
1617
+ const result = await installMutation({
1618
+ variables: {
1619
+ applicationId: node2.applicationId,
1620
+ workspaceId,
1621
+ version: node2.version
1622
+ }
1623
+ });
1624
+ if (result.error || !result.data?.installApp) {
1625
+ throw result.error ?? new Error("Installation failed");
1626
+ }
1627
+ await afterChange();
1628
+ return { success: true };
1629
+ } catch (err) {
1630
+ return {
1631
+ success: false,
1632
+ error: errorMessage(err, "Installation failed")
1633
+ };
1634
+ } finally {
1635
+ setBusyApplicationId(null);
1636
+ }
1637
+ },
1638
+ [afterChange, installMutation, workspaceId]
1639
+ );
1640
+ const uninstall = useCallback(
1641
+ async (node2) => {
1642
+ if (!node2.installationId) {
1643
+ return { success: false, error: "The node is not installed" };
1644
+ }
1645
+ setBusyApplicationId(node2.applicationId);
1646
+ try {
1647
+ const result = await uninstallMutation({
1648
+ variables: { installationId: node2.installationId }
1649
+ });
1650
+ if (result.error || result.data?.uninstallApp !== true) {
1651
+ throw result.error ?? new Error("Uninstall failed");
1652
+ }
1653
+ await afterChange();
1654
+ return { success: true };
1655
+ } catch (err) {
1656
+ return { success: false, error: errorMessage(err, "Uninstall failed") };
1657
+ } finally {
1658
+ setBusyApplicationId(null);
1659
+ }
1660
+ },
1661
+ [afterChange, uninstallMutation]
1662
+ );
1663
+ const listing = data?.organizationPrivateNodes;
1664
+ return {
1665
+ nodes: listing?.nodes ?? [],
1666
+ canManage: listing?.canManage ?? false,
1667
+ loading,
1668
+ error: error62,
1669
+ busyApplicationId,
1670
+ install,
1671
+ uninstall,
1672
+ refetch
1673
+ };
1674
+ }
1587
1675
  function formatNumber(count2) {
1588
1676
  if (count2 >= 1e6) {
1589
1677
  return `${(count2 / 1e6).toFixed(1)}M`;
@@ -23106,6 +23194,214 @@ function StoreNodeListItem({
23106
23194
  }
23107
23195
  );
23108
23196
  }
23197
+ var KEY = "fluidgrids.builder.organizationPrivateNodes";
23198
+ function NodeIcon({
23199
+ name,
23200
+ icon
23201
+ }) {
23202
+ return /* @__PURE__ */ jsx("div", { className: "size-9 shrink-0 rounded-lg bg-muted flex items-center justify-center overflow-hidden", children: icon ? isImageIcon(icon) ? /* @__PURE__ */ jsx("img", { src: icon, alt: name, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "size-5 text-muted-foreground" }) : /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-muted-foreground", children: name.charAt(0).toUpperCase() }) });
23203
+ }
23204
+ function OrganizationPrivateNodeRow({
23205
+ node: node2,
23206
+ canManage,
23207
+ busy,
23208
+ disabled,
23209
+ onInstall,
23210
+ onUninstall
23211
+ }) {
23212
+ const tr = useTr();
23213
+ const [confirmingUninstall, setConfirmingUninstall] = useState(false);
23214
+ return /* @__PURE__ */ jsxs(
23215
+ "div",
23216
+ {
23217
+ className: "flex items-center gap-3 px-2 py-2.5 rounded-md",
23218
+ "data-testid": "org-private-node",
23219
+ "data-application-id": node2.applicationId,
23220
+ children: [
23221
+ /* @__PURE__ */ jsx(NodeIcon, { name: node2.name, icon: node2.iconUrl }),
23222
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
23223
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
23224
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground truncate", children: node2.name }),
23225
+ node2.installed && /* @__PURE__ */ jsx(
23226
+ "span",
23227
+ {
23228
+ className: "shrink-0 inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold",
23229
+ style: node2.updateAvailable ? {
23230
+ background: "var(--color-status-warning-bgSubtle)",
23231
+ color: "var(--color-status-warning-text)"
23232
+ } : {
23233
+ background: "var(--color-status-success-bgSubtle)",
23234
+ color: "var(--color-status-success-text)"
23235
+ },
23236
+ "data-testid": "org-private-node-status",
23237
+ children: node2.updateAvailable ? tr(`${KEY}.updateBadge`, "Update") : tr(`${KEY}.installedBadge`, "Installed")
23238
+ }
23239
+ )
23240
+ ] }),
23241
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate mt-0.5 leading-snug", children: [
23242
+ "v",
23243
+ node2.installed && node2.installedVersion ? node2.installedVersion : node2.version,
23244
+ node2.updateAvailable ? ` \u2192 v${node2.version}` : "",
23245
+ node2.shortDescription ? ` \xB7 ${node2.shortDescription}` : ""
23246
+ ] })
23247
+ ] }),
23248
+ canManage && /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center gap-1", children: busy ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin text-muted-foreground" }) : !node2.installed ? /* @__PURE__ */ jsx(
23249
+ Button,
23250
+ {
23251
+ size: "xs",
23252
+ disabled,
23253
+ onClick: () => onInstall(node2),
23254
+ "data-testid": "org-private-node-install",
23255
+ children: tr(`${KEY}.installButton`, "Install")
23256
+ }
23257
+ ) : confirmingUninstall ? /* @__PURE__ */ jsxs(Fragment, { children: [
23258
+ /* @__PURE__ */ jsx(
23259
+ Button,
23260
+ {
23261
+ size: "xs",
23262
+ variant: "destructive",
23263
+ disabled,
23264
+ onClick: () => {
23265
+ setConfirmingUninstall(false);
23266
+ onUninstall(node2);
23267
+ },
23268
+ "data-testid": "org-private-node-uninstall-confirm",
23269
+ children: tr(`${KEY}.confirmUninstallButton`, "Remove")
23270
+ }
23271
+ ),
23272
+ /* @__PURE__ */ jsx(
23273
+ Button,
23274
+ {
23275
+ size: "xs",
23276
+ variant: "ghost",
23277
+ onClick: () => setConfirmingUninstall(false),
23278
+ children: tr(`${KEY}.cancelButton`, "Cancel")
23279
+ }
23280
+ )
23281
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
23282
+ node2.updateAvailable && /* @__PURE__ */ jsx(
23283
+ Button,
23284
+ {
23285
+ size: "xs",
23286
+ disabled,
23287
+ onClick: () => onInstall(node2),
23288
+ "data-testid": "org-private-node-update",
23289
+ children: tr(`${KEY}.updateButton`, "Update")
23290
+ }
23291
+ ),
23292
+ /* @__PURE__ */ jsx(
23293
+ Button,
23294
+ {
23295
+ size: "xs",
23296
+ variant: "outline",
23297
+ disabled,
23298
+ onClick: () => setConfirmingUninstall(true),
23299
+ "data-testid": "org-private-node-uninstall",
23300
+ children: tr(`${KEY}.uninstallButton`, "Uninstall")
23301
+ }
23302
+ )
23303
+ ] }) })
23304
+ ]
23305
+ }
23306
+ );
23307
+ }
23308
+ function OrganizationPrivateNodesSection() {
23309
+ const tr = useTr();
23310
+ const {
23311
+ nodes,
23312
+ canManage,
23313
+ loading,
23314
+ error: error62,
23315
+ busyApplicationId,
23316
+ install,
23317
+ uninstall
23318
+ } = useOrganizationPrivateNodes();
23319
+ if (nodes.length === 0) {
23320
+ if (error62 && !loading) {
23321
+ return /* @__PURE__ */ jsx(
23322
+ "p",
23323
+ {
23324
+ className: "px-2 py-2 text-xs text-muted-foreground",
23325
+ "data-testid": "org-private-nodes-error",
23326
+ children: tr(
23327
+ `${KEY}.loadError`,
23328
+ "Your organization's private nodes could not be loaded."
23329
+ )
23330
+ }
23331
+ );
23332
+ }
23333
+ return null;
23334
+ }
23335
+ const handleInstall = async (node2) => {
23336
+ const updating = node2.installed;
23337
+ const result = await install(node2);
23338
+ if (result.success) {
23339
+ toast.success(
23340
+ updating ? tr(`${KEY}.updateSuccessToast`, "Node updated") : tr(`${KEY}.installSuccessToast`, "Node installed"),
23341
+ {
23342
+ description: `${node2.name} v${node2.version} is in your workflow builder.`
23343
+ }
23344
+ );
23345
+ } else {
23346
+ toast.error(
23347
+ updating ? tr(`${KEY}.updateErrorToast`, "Update failed") : tr(`${KEY}.installErrorToast`, "Installation failed"),
23348
+ { description: result.error }
23349
+ );
23350
+ }
23351
+ };
23352
+ const handleUninstall = async (node2) => {
23353
+ const result = await uninstall(node2);
23354
+ if (result.success) {
23355
+ toast.success(tr(`${KEY}.uninstallSuccessToast`, "Node uninstalled"), {
23356
+ description: `${node2.name} was removed from this workspace.`
23357
+ });
23358
+ } else {
23359
+ toast.error(tr(`${KEY}.uninstallErrorToast`, "Uninstall failed"), {
23360
+ description: result.error
23361
+ });
23362
+ }
23363
+ };
23364
+ return /* @__PURE__ */ jsxs(
23365
+ "section",
23366
+ {
23367
+ className: "mb-2 rounded-lg border border-default px-1 py-1",
23368
+ "data-testid": "org-private-nodes",
23369
+ children: [
23370
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2 pt-2 pb-1", children: [
23371
+ /* @__PURE__ */ jsx(
23372
+ Icon,
23373
+ {
23374
+ icon: "mynaui:building",
23375
+ className: "size-4 shrink-0 text-muted-foreground"
23376
+ }
23377
+ ),
23378
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
23379
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-foreground leading-tight", children: tr(`${KEY}.title`, "Your organization") }),
23380
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground leading-snug", children: canManage ? tr(
23381
+ `${KEY}.subtitleAdmin`,
23382
+ "Private nodes your organization published for its workspaces."
23383
+ ) : tr(
23384
+ `${KEY}.subtitleMember`,
23385
+ "Private nodes your organization published. Ask a workspace admin to install one."
23386
+ ) })
23387
+ ] })
23388
+ ] }),
23389
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: nodes.map((node2) => /* @__PURE__ */ jsx(
23390
+ OrganizationPrivateNodeRow,
23391
+ {
23392
+ node: node2,
23393
+ canManage,
23394
+ busy: busyApplicationId === node2.applicationId,
23395
+ disabled: busyApplicationId !== null,
23396
+ onInstall: (n) => void handleInstall(n),
23397
+ onUninstall: (n) => void handleUninstall(n)
23398
+ },
23399
+ node2.applicationId
23400
+ )) })
23401
+ ]
23402
+ }
23403
+ );
23404
+ }
23109
23405
  function deprecatedItemToProduct(item) {
23110
23406
  return {
23111
23407
  id: item.productId,
@@ -23300,102 +23596,105 @@ function StoreCategoryList({
23300
23596
  ] })
23301
23597
  ) : (
23302
23598
  /* Main category list */
23303
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-2 pb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 pt-1", children: [
23304
- STORE_CATEGORIES.map((cat) => /* @__PURE__ */ jsxs(
23305
- "button",
23306
- {
23307
- onClick: () => onSelectCategory(cat),
23308
- className: "w-full flex items-center gap-3 px-2 py-3 rounded-lg border border-transparent hover:border-default hover:bg-muted/60 transition-colors text-left group",
23309
- children: [
23310
- /* @__PURE__ */ jsx(
23311
- "div",
23312
- {
23313
- className: "size-9 shrink-0 rounded-lg flex items-center justify-center",
23314
- style: {
23315
- backgroundColor: `color-mix(in oklab, var(${cat.color}) 16%, transparent)`
23316
- },
23317
- children: /* @__PURE__ */ jsx(
23318
- Icon,
23319
- {
23320
- icon: cat.icon,
23321
- className: "size-5",
23322
- style: { color: `var(${cat.color})` }
23323
- }
23324
- )
23325
- }
23326
- ),
23327
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
23328
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: cat.label }),
23329
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: cat.description })
23330
- ] }),
23331
- /* @__PURE__ */ jsx(
23332
- Icon,
23333
- {
23334
- icon: "mynaui:chevron-right",
23335
- className: "size-4 shrink-0 text-foreground/40 group-hover:translate-x-0.5 transition-transform"
23336
- }
23337
- )
23338
- ]
23339
- },
23340
- cat.key
23341
- )),
23342
- deprecatedInstallations.length > 0 && /* @__PURE__ */ jsxs(
23343
- "button",
23344
- {
23345
- onClick: () => setShowDeprecated(true),
23346
- className: "w-full flex items-center gap-3 px-2 py-3 rounded-lg border border-transparent hover:border-default hover:bg-muted/60 transition-colors text-left group",
23347
- children: [
23348
- /* @__PURE__ */ jsx(
23349
- "div",
23350
- {
23351
- className: "size-9 shrink-0 rounded-lg flex items-center justify-center",
23352
- style: {
23353
- backgroundColor: "var(--color-status-warning-bgSubtle)"
23354
- },
23355
- children: /* @__PURE__ */ jsx(
23356
- Icon,
23357
- {
23358
- icon: "mynaui:circle-warning",
23359
- className: "size-5",
23360
- style: {
23361
- color: "var(--color-status-warning-text)"
23599
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-2 pb-2", children: [
23600
+ /* @__PURE__ */ jsx(OrganizationPrivateNodesSection, {}),
23601
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 pt-1", children: [
23602
+ STORE_CATEGORIES.map((cat) => /* @__PURE__ */ jsxs(
23603
+ "button",
23604
+ {
23605
+ onClick: () => onSelectCategory(cat),
23606
+ className: "w-full flex items-center gap-3 px-2 py-3 rounded-lg border border-transparent hover:border-default hover:bg-muted/60 transition-colors text-left group",
23607
+ children: [
23608
+ /* @__PURE__ */ jsx(
23609
+ "div",
23610
+ {
23611
+ className: "size-9 shrink-0 rounded-lg flex items-center justify-center",
23612
+ style: {
23613
+ backgroundColor: `color-mix(in oklab, var(${cat.color}) 16%, transparent)`
23614
+ },
23615
+ children: /* @__PURE__ */ jsx(
23616
+ Icon,
23617
+ {
23618
+ icon: cat.icon,
23619
+ className: "size-5",
23620
+ style: { color: `var(${cat.color})` }
23362
23621
  }
23363
- }
23364
- )
23365
- }
23366
- ),
23367
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
23622
+ )
23623
+ }
23624
+ ),
23625
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
23626
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: cat.label }),
23627
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: cat.description })
23628
+ ] }),
23368
23629
  /* @__PURE__ */ jsx(
23369
- "p",
23630
+ Icon,
23370
23631
  {
23371
- className: "text-sm font-medium group-hover:text-primary transition-colors",
23632
+ icon: "mynaui:chevron-right",
23633
+ className: "size-4 shrink-0 text-foreground/40 group-hover:translate-x-0.5 transition-transform"
23634
+ }
23635
+ )
23636
+ ]
23637
+ },
23638
+ cat.key
23639
+ )),
23640
+ deprecatedInstallations.length > 0 && /* @__PURE__ */ jsxs(
23641
+ "button",
23642
+ {
23643
+ onClick: () => setShowDeprecated(true),
23644
+ className: "w-full flex items-center gap-3 px-2 py-3 rounded-lg border border-transparent hover:border-default hover:bg-muted/60 transition-colors text-left group",
23645
+ children: [
23646
+ /* @__PURE__ */ jsx(
23647
+ "div",
23648
+ {
23649
+ className: "size-9 shrink-0 rounded-lg flex items-center justify-center",
23372
23650
  style: {
23373
- color: "var(--color-status-warning-text)"
23651
+ backgroundColor: "var(--color-status-warning-bgSubtle)"
23374
23652
  },
23375
- children: tr(
23376
- "fluidgrids.builder.storeCategoryList.deprecatedCategoryLabel",
23377
- "Deprecated"
23653
+ children: /* @__PURE__ */ jsx(
23654
+ Icon,
23655
+ {
23656
+ icon: "mynaui:circle-warning",
23657
+ className: "size-5",
23658
+ style: {
23659
+ color: "var(--color-status-warning-text)"
23660
+ }
23661
+ }
23378
23662
  )
23379
23663
  }
23380
23664
  ),
23381
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: [
23382
- deprecatedInstallations.length,
23383
- " node",
23384
- deprecatedInstallations.length !== 1 ? "s" : "",
23385
- " no longer supported"
23386
- ] })
23387
- ] }),
23388
- /* @__PURE__ */ jsx(
23389
- Icon,
23390
- {
23391
- icon: "mynaui:chevron-right",
23392
- className: "size-4 shrink-0 text-foreground/40 group-hover:translate-x-0.5 transition-transform"
23393
- }
23394
- )
23395
- ]
23396
- }
23397
- )
23398
- ] }) })
23665
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
23666
+ /* @__PURE__ */ jsx(
23667
+ "p",
23668
+ {
23669
+ className: "text-sm font-medium group-hover:text-primary transition-colors",
23670
+ style: {
23671
+ color: "var(--color-status-warning-text)"
23672
+ },
23673
+ children: tr(
23674
+ "fluidgrids.builder.storeCategoryList.deprecatedCategoryLabel",
23675
+ "Deprecated"
23676
+ )
23677
+ }
23678
+ ),
23679
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: [
23680
+ deprecatedInstallations.length,
23681
+ " node",
23682
+ deprecatedInstallations.length !== 1 ? "s" : "",
23683
+ " no longer supported"
23684
+ ] })
23685
+ ] }),
23686
+ /* @__PURE__ */ jsx(
23687
+ Icon,
23688
+ {
23689
+ icon: "mynaui:chevron-right",
23690
+ className: "size-4 shrink-0 text-foreground/40 group-hover:translate-x-0.5 transition-transform"
23691
+ }
23692
+ )
23693
+ ]
23694
+ }
23695
+ )
23696
+ ] })
23697
+ ] })
23399
23698
  )
23400
23699
  ] });
23401
23700
  }
@@ -24843,7 +25142,7 @@ function DesktopSidebarFragment({
24843
25142
  );
24844
25143
  if (nodesToInstall.length > 0) {
24845
25144
  const { getGlobalStoreClient: getStore } = await import('./global-client-KLOVTVPP.js');
24846
- const { InstallWorkflowNodeDocument: InstallWorkflowNodeDocument2 } = await import('./global-operations-ZWQZ7DNT.js');
25145
+ const { InstallWorkflowNodeDocument: InstallWorkflowNodeDocument2 } = await import('./global-operations-D2USVOPM.js');
24847
25146
  const { getFluidGridsConfig: getFluidGridsConfig3 } = await import('./config-T7BQ7AO2.js');
24848
25147
  const storeClient = getStore();
24849
25148
  const cfg = getFluidGridsConfig3();
@@ -24963,7 +25262,7 @@ function DesktopSidebarFragment({
24963
25262
  });
24964
25263
  try {
24965
25264
  const { getGlobalStoreClient: getStoreClient } = await import('./global-client-KLOVTVPP.js');
24966
- const { InstallWorkflowNodeDocument: InstallWorkflowNodeDocument2 } = await import('./global-operations-ZWQZ7DNT.js');
25265
+ const { InstallWorkflowNodeDocument: InstallWorkflowNodeDocument2 } = await import('./global-operations-D2USVOPM.js');
24967
25266
  const storeClient = getStoreClient();
24968
25267
  if (storeClient) {
24969
25268
  throwIfResultError(
@@ -26387,8 +26686,8 @@ var reducer = (state, action) => {
26387
26686
  if (toastId) {
26388
26687
  addToRemoveQueue(toastId);
26389
26688
  } else {
26390
- state.toasts.forEach((toast15) => {
26391
- addToRemoveQueue(toast15.id);
26689
+ state.toasts.forEach((toast17) => {
26690
+ addToRemoveQueue(toast17.id);
26392
26691
  });
26393
26692
  }
26394
26693
  return {
@@ -26422,7 +26721,7 @@ function dispatch(action) {
26422
26721
  listener(memoryState);
26423
26722
  });
26424
26723
  }
26425
- function toast4({ ...props }) {
26724
+ function toast5({ ...props }) {
26426
26725
  const id = genId();
26427
26726
  const update = (props2) => dispatch({
26428
26727
  type: actionTypes.UPDATE_TOAST,
@@ -26459,7 +26758,7 @@ function useToast() {
26459
26758
  }, [state]);
26460
26759
  return {
26461
26760
  ...state,
26462
- toast: toast4,
26761
+ toast: toast5,
26463
26762
  dismiss: (toastId) => dispatch({ type: actionTypes.DISMISS_TOAST, toastId })
26464
26763
  };
26465
26764
  }
@@ -27764,7 +28063,7 @@ function VisualMapperContent({
27764
28063
  mapping,
27765
28064
  onMappingChange
27766
28065
  }) {
27767
- const { toast: toast15 } = useToast();
28066
+ const { toast: toast17 } = useToast();
27768
28067
  const tr = useTr();
27769
28068
  const reactFlowWrapper = useRef(null);
27770
28069
  const [selectedSourceNode, setSelectedSourceNode] = useState(null);
@@ -27784,7 +28083,7 @@ function VisualMapperContent({
27784
28083
  targetOperation
27785
28084
  );
27786
28085
  if (generatedNodes.length === 0) {
27787
- toast15({
28086
+ toast17({
27788
28087
  title: tr(
27789
28088
  "fluidgrids.builder.visualMapper.noFieldsFoundTitle",
27790
28089
  "No fields found"
@@ -27810,7 +28109,7 @@ function VisualMapperContent({
27810
28109
  targetNode,
27811
28110
  targetOperation,
27812
28111
  setNodes,
27813
- toast15,
28112
+ toast17,
27814
28113
  tr
27815
28114
  ]);
27816
28115
  useEffect(() => {
@@ -27917,7 +28216,7 @@ function VisualMapperContent({
27917
28216
  }
27918
28217
  onMappingChange(updatedMapping);
27919
28218
  if (isCompatible) {
27920
- toast15({
28219
+ toast17({
27921
28220
  title: tr(
27922
28221
  "fluidgrids.builder.visualMapper.mappingCreatedTitle",
27923
28222
  "Mapping created"
@@ -27925,7 +28224,7 @@ function VisualMapperContent({
27925
28224
  description: `Mapped ${sourcePath} (${sourceType}) to ${targetPath} (${targetType})`
27926
28225
  });
27927
28226
  } else {
27928
- toast15({
28227
+ toast17({
27929
28228
  title: tr(
27930
28229
  "fluidgrids.builder.visualMapper.typeMismatchTitle",
27931
28230
  "Type mismatch warning"
@@ -27935,7 +28234,7 @@ function VisualMapperContent({
27935
28234
  });
27936
28235
  }
27937
28236
  } else {
27938
- toast15({
28237
+ toast17({
27939
28238
  title: tr(
27940
28239
  "fluidgrids.builder.visualMapper.invalidMappingTitle",
27941
28240
  "Invalid mapping"
@@ -27948,7 +28247,7 @@ function VisualMapperContent({
27948
28247
  });
27949
28248
  }
27950
28249
  },
27951
- [nodes, mapping, onMappingChange, toast15, tr, setEdges]
28250
+ [nodes, mapping, onMappingChange, toast17, tr, setEdges]
27952
28251
  );
27953
28252
  const onEdgeDelete = useCallback(
27954
28253
  (edge) => {
@@ -28005,7 +28304,7 @@ function VisualMapperContent({
28005
28304
  const handleSaveMappingDialog = (expression, targetFieldName) => {
28006
28305
  const targetPath = targetFieldName || selectedTargetNode?.data?.path;
28007
28306
  if (!targetPath) {
28008
- toast15({
28307
+ toast17({
28009
28308
  title: tr(
28010
28309
  "fluidgrids.builder.visualMapper.noTargetFieldTitle",
28011
28310
  "No target field specified"
@@ -28037,7 +28336,7 @@ function VisualMapperContent({
28037
28336
  }
28038
28337
  onMappingChange(updatedMapping);
28039
28338
  const mappingType = detectMappingType(expression);
28040
- toast15({
28339
+ toast17({
28041
28340
  title: `${mappingType.charAt(0).toUpperCase() + mappingType.slice(1)} mapping created`,
28042
28341
  description: `${tr("fluidgrids.builder.visualMapper.appliedMappingTo", "Applied mapping to")} ${targetPath}`
28043
28342
  });
@@ -28336,7 +28635,7 @@ function MappingEditor({
28336
28635
  setEdges,
28337
28636
  edgeId
28338
28637
  }) {
28339
- const { toast: toast15 } = useToast();
28638
+ const { toast: toast17 } = useToast();
28340
28639
  const tr = useTr();
28341
28640
  const [mappingJson, setMappingJson] = useState({});
28342
28641
  const [jsonDataString, setJsonDataString] = useState(
@@ -28460,7 +28759,7 @@ function MappingEditor({
28460
28759
  const handleSaveMapping = () => {
28461
28760
  try {
28462
28761
  checkJsonValidity();
28463
- toast15({
28762
+ toast17({
28464
28763
  title: tr(
28465
28764
  "fluidgrids.builder.mappingEditor.mappingSavedTitle",
28466
28765
  "Mapping saved"
@@ -28471,7 +28770,7 @@ function MappingEditor({
28471
28770
  )
28472
28771
  });
28473
28772
  } catch (error62) {
28474
- toast15({
28773
+ toast17({
28475
28774
  title: tr(
28476
28775
  "fluidgrids.builder.mappingEditor.errorSavingTitle",
28477
28776
  "Error saving mapping"
@@ -28490,7 +28789,7 @@ function MappingEditor({
28490
28789
  const parsedData = checkJsonValidity();
28491
28790
  const result = await applyMapping(parsedData, sampleInput);
28492
28791
  setPreviewOutput(result);
28493
- toast15({
28792
+ toast17({
28494
28793
  title: tr(
28495
28794
  "fluidgrids.builder.mappingEditor.mappingTestedTitle",
28496
28795
  "Mapping tested"
@@ -28502,7 +28801,7 @@ function MappingEditor({
28502
28801
  });
28503
28802
  } catch (error62) {
28504
28803
  console.error("Test mapping error:", error62);
28505
- toast15({
28804
+ toast17({
28506
28805
  title: tr(
28507
28806
  "fluidgrids.builder.mappingEditor.mappingTestFailedTitle",
28508
28807
  "Mapping test failed"
@@ -35601,6 +35900,10 @@ function loopReturnStatus(nodeId2, edges, loopHandle = "loop") {
35601
35900
  if (!returns) return "missing-return";
35602
35901
  return exits ? "conditional-exit" : "connected";
35603
35902
  }
35903
+ function languageExtension(language) {
35904
+ if (language === "python") return python();
35905
+ return javascript({ typescript: language === "typescript" });
35906
+ }
35604
35907
  function normalizeCodeLanguage(value) {
35605
35908
  return typeof value === "string" && value.toLowerCase().startsWith("py") ? "python" : "javascript";
35606
35909
  }
@@ -35624,13 +35927,16 @@ function CodeEditorField({
35624
35927
  placeholder,
35625
35928
  label,
35626
35929
  onChange,
35930
+ readOnly = false,
35931
+ minHeight = "180px",
35932
+ maxHeight = "420px",
35627
35933
  className,
35628
35934
  "data-testid": testId
35629
35935
  }) {
35630
35936
  const dark = useIsDarkTheme();
35631
35937
  const extensions = useMemo(
35632
35938
  () => [
35633
- language === "python" ? python() : javascript(),
35939
+ languageExtension(language),
35634
35940
  // CodeMirror's contenteditable is the control assistive tech focuses; name it.
35635
35941
  ...label ? [EditorView.contentAttributes.of({ "aria-label": label })] : []
35636
35942
  ],
@@ -35650,20 +35956,22 @@ function CodeEditorField({
35650
35956
  CodeMirror,
35651
35957
  {
35652
35958
  value,
35653
- onChange,
35959
+ onChange: readOnly ? void 0 : onChange,
35654
35960
  extensions,
35655
35961
  theme: dark ? "dark" : "light",
35656
35962
  placeholder,
35657
- minHeight: "180px",
35658
- maxHeight: "420px",
35963
+ minHeight,
35964
+ maxHeight,
35965
+ editable: !readOnly,
35966
+ readOnly,
35659
35967
  basicSetup: {
35660
35968
  lineNumbers: true,
35661
35969
  foldGutter: true,
35662
- highlightActiveLine: true,
35663
- autocompletion: true,
35970
+ highlightActiveLine: !readOnly,
35971
+ autocompletion: !readOnly,
35664
35972
  bracketMatching: true,
35665
- closeBrackets: true,
35666
- indentOnInput: true
35973
+ closeBrackets: !readOnly,
35974
+ indentOnInput: !readOnly
35667
35975
  }
35668
35976
  }
35669
35977
  )
@@ -38409,6 +38717,15 @@ function NodeParamsForm({
38409
38717
  }
38410
38718
  ),
38411
38719
  isWebhookWait && /* @__PURE__ */ jsx(WaitResumeUrlField, {}),
38720
+ isAgentNodeType(nodeType) && /* @__PURE__ */ jsx(
38721
+ AgentDefinitionSelectField,
38722
+ {
38723
+ value: typeof argsState.agentDefinitionId === "string" ? argsState.agentDefinitionId : null,
38724
+ onChange: (next) => writeFixed("agentDefinitionId", next),
38725
+ sectionLabelClassName: SECTION_LABEL3,
38726
+ testIdPrefix
38727
+ }
38728
+ ),
38412
38729
  connectionAdapters.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": `${testIdPrefix}-connections`, children: [
38413
38730
  /* @__PURE__ */ jsx("div", { className: SECTION_LABEL3, children: tr(
38414
38731
  "fluidgrids.builder.nodeParamsForm.connectionsSection",
@@ -44797,6 +45114,427 @@ function AiDraftPanel({
44797
45114
  ] }) })
44798
45115
  ] });
44799
45116
  }
45117
+ function FidelityLevelBadge({
45118
+ fidelity
45119
+ }) {
45120
+ const tr = useTr();
45121
+ const lossless = isLosslessReport(fidelity);
45122
+ return /* @__PURE__ */ jsxs(
45123
+ Badge,
45124
+ {
45125
+ variant: lossless ? "secondary" : "destructive",
45126
+ "data-testid": "fluidgrids-code-fidelity-level",
45127
+ "data-level": lossless ? "lossless" : "lossy",
45128
+ className: "gap-1",
45129
+ children: [
45130
+ /* @__PURE__ */ jsx(
45131
+ Icon,
45132
+ {
45133
+ icon: lossless ? "mynaui:check-circle" : "mynaui:danger-triangle",
45134
+ className: "size-3.5"
45135
+ }
45136
+ ),
45137
+ lossless ? tr("fluidgrids.builder.codeView.lossless", "Lossless") : tr("fluidgrids.builder.codeView.lossy", "Lossy")
45138
+ ]
45139
+ }
45140
+ );
45141
+ }
45142
+ function FidelityReportList({
45143
+ fidelity,
45144
+ source,
45145
+ hasNode,
45146
+ onShowNode
45147
+ }) {
45148
+ const tr = useTr();
45149
+ const items = sortFidelityItems(fidelity.items);
45150
+ return /* @__PURE__ */ jsxs(
45151
+ "section",
45152
+ {
45153
+ "aria-labelledby": "fg-code-fidelity",
45154
+ "data-testid": "fluidgrids-code-fidelity",
45155
+ className: "space-y-2",
45156
+ children: [
45157
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
45158
+ /* @__PURE__ */ jsx(
45159
+ "h3",
45160
+ {
45161
+ id: "fg-code-fidelity",
45162
+ className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground",
45163
+ children: tr("fluidgrids.builder.codeView.fidelityTitle", "Fidelity")
45164
+ }
45165
+ ),
45166
+ /* @__PURE__ */ jsx(FidelityLevelBadge, { fidelity })
45167
+ ] }),
45168
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: isLosslessReport(fidelity) ? tr(
45169
+ "fluidgrids.builder.codeView.losslessHint",
45170
+ "Lowering this code gives back exactly this workflow."
45171
+ ) : tr(
45172
+ "fluidgrids.builder.codeView.lossyHint",
45173
+ "Lowering this code does not give back exactly this workflow. The items marked lossy say what differs."
45174
+ ) }),
45175
+ items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tr(
45176
+ "fluidgrids.builder.codeView.noFidelityItems",
45177
+ "Nothing to report."
45178
+ ) }) : /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: items.map((item, index) => {
45179
+ const lossy = isLossyFidelityItem(item);
45180
+ const nodeId2 = item.nodeId ?? null;
45181
+ const line = nodeId2 && source !== void 0 ? lineOfNode(source, nodeId2) : null;
45182
+ return /* @__PURE__ */ jsxs(
45183
+ "li",
45184
+ {
45185
+ "data-testid": "fluidgrids-code-fidelity-item",
45186
+ "data-kind": item.kind,
45187
+ "data-lossy": lossy ? "true" : "false",
45188
+ className: cn$1(
45189
+ "rounded-md border p-2 text-xs",
45190
+ lossy ? "border-[var(--color-status-error-border)] bg-[var(--color-status-error-bg)]" : "border-border bg-muted/30"
45191
+ ),
45192
+ children: [
45193
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
45194
+ /* @__PURE__ */ jsx(
45195
+ Badge,
45196
+ {
45197
+ variant: lossy ? "destructive" : "outline",
45198
+ className: "text-[10px]",
45199
+ children: lossy ? tr("fluidgrids.builder.codeView.itemLossy", "Lossy") : tr("fluidgrids.builder.codeView.itemLossless", "Kept")
45200
+ }
45201
+ ),
45202
+ /* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-card-foreground", children: item.kind }),
45203
+ line !== null && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: tr(
45204
+ "fluidgrids.builder.codeView.itemLine",
45205
+ "line {{line}}",
45206
+ {
45207
+ line: String(line)
45208
+ }
45209
+ ) })
45210
+ ] }),
45211
+ /* @__PURE__ */ jsx("p", { className: "mt-1 break-words text-card-foreground", children: item.detail }),
45212
+ item.path && /* @__PURE__ */ jsx("p", { className: "mt-0.5 break-all font-mono text-[11px] text-muted-foreground", children: item.path }),
45213
+ nodeId2 && /* @__PURE__ */ jsxs(
45214
+ Button$1,
45215
+ {
45216
+ variant: "link",
45217
+ size: "sm",
45218
+ className: "mt-1 h-auto gap-1 p-0 text-xs",
45219
+ disabled: !hasNode(nodeId2),
45220
+ onClick: () => onShowNode(nodeId2),
45221
+ "data-testid": "fluidgrids-code-fidelity-node",
45222
+ children: [
45223
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:location", className: "size-3.5" }),
45224
+ tr(
45225
+ "fluidgrids.builder.codeView.showNode",
45226
+ "Show node {{nodeId}}",
45227
+ { nodeId: nodeId2 }
45228
+ )
45229
+ ]
45230
+ }
45231
+ )
45232
+ ]
45233
+ },
45234
+ `${item.kind}-${nodeId2 ?? ""}-${item.path ?? ""}-${index}`
45235
+ );
45236
+ }) })
45237
+ ]
45238
+ }
45239
+ );
45240
+ }
45241
+ function editorLanguageOf(path) {
45242
+ if (path.endsWith(".py")) return "python";
45243
+ if (path.endsWith(".ts")) return "typescript";
45244
+ return "javascript";
45245
+ }
45246
+ function isCodeViewFormat(value) {
45247
+ return value === "TYPESCRIPT" /* Typescript */ || value === "PYTHON" /* Python */;
45248
+ }
45249
+ function CodeViewPanel({
45250
+ className,
45251
+ compact = false
45252
+ }) {
45253
+ const enabled = useFluidGridsFlag(FLUIDGRIDS_FLAGS.codeFirst);
45254
+ if (!enabled) return null;
45255
+ return /* @__PURE__ */ jsx(CodeViewSheet, { className, compact });
45256
+ }
45257
+ function CodeViewSheet({
45258
+ className,
45259
+ compact
45260
+ }) {
45261
+ const tr = useTr();
45262
+ const params = useParams();
45263
+ const workflowKey = params?.id ?? "";
45264
+ const version2 = params?.version ?? null;
45265
+ const [open2, setOpen] = useState(false);
45266
+ const [format, setFormat2] = useState(
45267
+ "TYPESCRIPT" /* Typescript */
45268
+ );
45269
+ const [selectedPath, setSelectedPath] = useState(null);
45270
+ const [downloading, setDownloading] = useState(false);
45271
+ const { data, loading, error: error62, refetch } = useWorkflowCodeExport(
45272
+ { workflowKey, version: version2, format },
45273
+ open2 && !!workflowKey
45274
+ );
45275
+ const dirty = useSaveStatusStore((s) => s.dirty);
45276
+ const lastSavedAt = useSaveStatusStore((s) => s.lastSavedAt);
45277
+ const seenSave = useRef(lastSavedAt);
45278
+ useEffect(() => {
45279
+ if (seenSave.current === lastSavedAt) return;
45280
+ seenSave.current = lastSavedAt;
45281
+ if (open2) void refetch();
45282
+ }, [lastSavedAt, open2, refetch]);
45283
+ const files = useMemo(
45284
+ () => data ? orderedExportFiles(data.files, format) : [],
45285
+ [data, format]
45286
+ );
45287
+ const shown = files.find((file2) => file2.path === selectedPath) ?? files[0] ?? null;
45288
+ const shownContent = shown?.content ?? "";
45289
+ useEffect(() => setSelectedPath(null), [format]);
45290
+ const { fitView } = useReactFlow();
45291
+ const nodes = useFlowStore((s) => s.workflow.nodes);
45292
+ const onNodesChange = useFlowStore((s) => s.actions.nodes.onNodesChange);
45293
+ const showNodePropertiesOf = useFlowStore(
45294
+ (s) => s.actions.sidebar.showNodePropertiesOf
45295
+ );
45296
+ const nodeIds = useMemo(() => new Set(nodes.map((n) => n.id)), [nodes]);
45297
+ const hasNode = useCallback((id) => nodeIds.has(id), [nodeIds]);
45298
+ const showNode = useCallback(
45299
+ (id) => {
45300
+ const node2 = nodes.find((n) => n.id === id);
45301
+ if (!node2) return;
45302
+ setOpen(false);
45303
+ onNodesChange(
45304
+ nodes.map((n) => ({ type: "select", id: n.id, selected: n.id === id }))
45305
+ );
45306
+ if (node2.type)
45307
+ showNodePropertiesOf({ id, type: node2.type });
45308
+ setTimeout(
45309
+ () => void fitView({
45310
+ nodes: [{ id }],
45311
+ duration: 300,
45312
+ padding: 0.4,
45313
+ maxZoom: 1.2
45314
+ }),
45315
+ 50
45316
+ );
45317
+ },
45318
+ [nodes, onNodesChange, showNodePropertiesOf, fitView]
45319
+ );
45320
+ const copy = async () => {
45321
+ if (!shown) return;
45322
+ try {
45323
+ await navigator.clipboard.writeText(shownContent);
45324
+ toast.success(tr("fluidgrids.builder.codeView.copied", "Code copied"));
45325
+ } catch (err) {
45326
+ toast.error(tr("fluidgrids.builder.codeView.copyError", "Copy failed"), {
45327
+ description: describeOperationError(err)
45328
+ });
45329
+ }
45330
+ };
45331
+ const download = async () => {
45332
+ if (!data) return;
45333
+ setDownloading(true);
45334
+ try {
45335
+ await downloadWorkflowCodeExport(data, format);
45336
+ } catch (err) {
45337
+ toast.error(
45338
+ tr("fluidgrids.builder.codeView.downloadError", "Download failed"),
45339
+ { description: describeOperationError(err) }
45340
+ );
45341
+ } finally {
45342
+ setDownloading(false);
45343
+ }
45344
+ };
45345
+ const label = tr("fluidgrids.builder.codeView.triggerButton", "Code");
45346
+ return /* @__PURE__ */ jsxs(Sheet, { open: open2, onOpenChange: setOpen, children: [
45347
+ /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
45348
+ Button$1,
45349
+ {
45350
+ "data-tour": "fluidgrids-builder-code",
45351
+ variant: "outline",
45352
+ size: compact ? "icon" : "sm",
45353
+ className: cn$1(!compact && "flex gap-1", className),
45354
+ "aria-label": label,
45355
+ title: compact ? label : void 0,
45356
+ disabled: !workflowKey,
45357
+ children: [
45358
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:code", className: "size-4" }),
45359
+ !compact && label
45360
+ ]
45361
+ }
45362
+ ) }),
45363
+ /* @__PURE__ */ jsxs(
45364
+ SheetContent,
45365
+ {
45366
+ side: "right",
45367
+ className: "flex w-[420px] flex-col overflow-y-auto sm:w-[640px] sm:max-w-[640px]",
45368
+ "data-testid": "fluidgrids-code-panel",
45369
+ children: [
45370
+ /* @__PURE__ */ jsxs(SheetHeader, { children: [
45371
+ /* @__PURE__ */ jsxs(SheetTitle, { className: "flex items-center gap-2", children: [
45372
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:code", className: "size-5" }),
45373
+ tr("fluidgrids.builder.codeView.title", "Code")
45374
+ ] }),
45375
+ /* @__PURE__ */ jsx(SheetDescription, { children: tr(
45376
+ "fluidgrids.builder.codeView.description",
45377
+ "This version as code, read-only. It is what the FluidGrids CLI pulls; edit the canvas or push code with the CLI to change it."
45378
+ ) })
45379
+ ] }),
45380
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-1 flex-col gap-4 pb-6", children: [
45381
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
45382
+ /* @__PURE__ */ jsx(
45383
+ Tabs,
45384
+ {
45385
+ value: format,
45386
+ onValueChange: (value) => {
45387
+ if (isCodeViewFormat(value)) setFormat2(value);
45388
+ },
45389
+ children: /* @__PURE__ */ jsxs(TabsList, { children: [
45390
+ /* @__PURE__ */ jsx(
45391
+ TabsTrigger,
45392
+ {
45393
+ value: "TYPESCRIPT" /* Typescript */,
45394
+ "data-testid": "fluidgrids-code-tab-typescript",
45395
+ children: tr("fluidgrids.builder.codeView.typescript", "TypeScript")
45396
+ }
45397
+ ),
45398
+ /* @__PURE__ */ jsx(
45399
+ TabsTrigger,
45400
+ {
45401
+ value: "PYTHON" /* Python */,
45402
+ "data-testid": "fluidgrids-code-tab-python",
45403
+ children: tr("fluidgrids.builder.codeView.python", "Python")
45404
+ }
45405
+ )
45406
+ ] })
45407
+ }
45408
+ ),
45409
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
45410
+ /* @__PURE__ */ jsxs(
45411
+ Button$1,
45412
+ {
45413
+ variant: "outline",
45414
+ size: "sm",
45415
+ className: "h-8 gap-1 text-xs",
45416
+ onClick: () => void copy(),
45417
+ disabled: !shown || loading,
45418
+ children: [
45419
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:copy", className: "size-3.5" }),
45420
+ tr("fluidgrids.builder.codeView.copy", "Copy")
45421
+ ]
45422
+ }
45423
+ ),
45424
+ /* @__PURE__ */ jsxs(
45425
+ Button$1,
45426
+ {
45427
+ variant: "outline",
45428
+ size: "sm",
45429
+ className: "h-8 gap-1 text-xs",
45430
+ onClick: () => void download(),
45431
+ disabled: !data || loading || downloading,
45432
+ children: [
45433
+ /* @__PURE__ */ jsx(Icon, { icon: "mynaui:download", className: "size-3.5" }),
45434
+ tr("fluidgrids.builder.codeView.download", "Download")
45435
+ ]
45436
+ }
45437
+ )
45438
+ ] })
45439
+ ] }),
45440
+ dirty && /* @__PURE__ */ jsx(
45441
+ "p",
45442
+ {
45443
+ role: "status",
45444
+ className: "rounded-md border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bg)] px-3 py-2 text-xs text-[var(--color-status-warning-text)]",
45445
+ children: tr(
45446
+ "fluidgrids.builder.codeView.unsavedNotice",
45447
+ "You have unsaved changes. The code shows the saved version and updates after the next save."
45448
+ )
45449
+ }
45450
+ ),
45451
+ loading && !data ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-8 text-sm text-muted-foreground", children: [
45452
+ /* @__PURE__ */ jsx(
45453
+ Icon,
45454
+ {
45455
+ icon: "mynaui:spinner",
45456
+ className: "mr-2 size-4 animate-spin"
45457
+ }
45458
+ ),
45459
+ tr(
45460
+ "fluidgrids.builder.codeView.loading",
45461
+ "Lifting the workflow\u2026"
45462
+ )
45463
+ ] }) : error62 ? /* @__PURE__ */ jsxs("div", { className: "py-6 text-sm", role: "alert", children: [
45464
+ /* @__PURE__ */ jsx("p", { className: "text-[var(--color-status-error-text)]", children: error62 }),
45465
+ /* @__PURE__ */ jsx(
45466
+ Button$1,
45467
+ {
45468
+ variant: "outline",
45469
+ size: "sm",
45470
+ className: "mt-3",
45471
+ onClick: () => void refetch(),
45472
+ children: tr("fluidgrids.builder.codeView.retry", "Retry")
45473
+ }
45474
+ )
45475
+ ] }) : data && shown ? /* @__PURE__ */ jsxs(Fragment, { children: [
45476
+ files.length > 1 && /* @__PURE__ */ jsx(
45477
+ "div",
45478
+ {
45479
+ className: "flex flex-wrap gap-1",
45480
+ role: "group",
45481
+ "aria-label": tr("fluidgrids.builder.codeView.files", "Files"),
45482
+ children: files.map((file2) => /* @__PURE__ */ jsx(
45483
+ Button$1,
45484
+ {
45485
+ variant: file2 === shown ? "secondary" : "ghost",
45486
+ size: "sm",
45487
+ className: "h-7 font-mono text-[11px]",
45488
+ title: file2.path,
45489
+ "aria-pressed": file2 === shown,
45490
+ onClick: () => setSelectedPath(file2.path),
45491
+ children: fileBaseName(file2.path)
45492
+ },
45493
+ file2.path
45494
+ ))
45495
+ }
45496
+ ),
45497
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: [
45498
+ /* @__PURE__ */ jsx("span", { className: "truncate font-mono", title: shown.path, children: shown.path }),
45499
+ /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
45500
+ /* @__PURE__ */ jsx("span", { className: "font-mono", title: data.irHash, children: data.irHash.slice(0, 19) }),
45501
+ /* @__PURE__ */ jsx(FidelityLevelBadge, { fidelity: data.fidelity })
45502
+ ] })
45503
+ ] }),
45504
+ /* @__PURE__ */ jsx(
45505
+ CodeEditorField,
45506
+ {
45507
+ value: shownContent,
45508
+ language: editorLanguageOf(shown.path),
45509
+ label: tr(
45510
+ "fluidgrids.builder.codeView.editorLabel",
45511
+ "Workflow code (read-only)"
45512
+ ),
45513
+ readOnly: true,
45514
+ minHeight: "260px",
45515
+ maxHeight: "55vh",
45516
+ "data-testid": "fluidgrids-code-editor"
45517
+ }
45518
+ ),
45519
+ /* @__PURE__ */ jsx(
45520
+ FidelityReportList,
45521
+ {
45522
+ fidelity: data.fidelity,
45523
+ source: shownContent,
45524
+ hasNode,
45525
+ onShowNode: showNode
45526
+ }
45527
+ )
45528
+ ] }) : /* @__PURE__ */ jsx("p", { className: "py-6 text-sm text-muted-foreground", children: tr(
45529
+ "fluidgrids.builder.codeView.empty",
45530
+ "The export returned no files."
45531
+ ) })
45532
+ ] })
45533
+ ]
45534
+ }
45535
+ )
45536
+ ] });
45537
+ }
44800
45538
  function RunWithViewRuns({
44801
45539
  onViewRuns,
44802
45540
  canViewRuns,
@@ -45068,7 +45806,8 @@ function PanelIcons() {
45068
45806
  return /* @__PURE__ */ jsxs(Fragment, { children: [
45069
45807
  /* @__PURE__ */ jsx(AiDraftPanel, { compact: true }),
45070
45808
  /* @__PURE__ */ jsx(EnvironmentsPanel, { compact: true }),
45071
- /* @__PURE__ */ jsx(GitSyncPanel, { compact: true })
45809
+ /* @__PURE__ */ jsx(GitSyncPanel, { compact: true }),
45810
+ /* @__PURE__ */ jsx(CodeViewPanel, { compact: true })
45072
45811
  ] });
45073
45812
  }
45074
45813
  function HeaderActions({ tier }) {
@@ -45086,6 +45825,7 @@ function HeaderActions({ tier }) {
45086
45825
  /* @__PURE__ */ jsx(VersionHistoryPanel, { compact: true }),
45087
45826
  /* @__PURE__ */ jsx(EnvironmentsPanel, { compact: true }),
45088
45827
  /* @__PURE__ */ jsx(GitSyncPanel, { compact: true }),
45828
+ /* @__PURE__ */ jsx(CodeViewPanel, { compact: true }),
45089
45829
  /* @__PURE__ */ jsx(GuideIcon, {}),
45090
45830
  /* @__PURE__ */ jsx(Divider, {}),
45091
45831
  /* @__PURE__ */ jsx(SaveFlowButton, {}),