@burdenoff/fluidgrids-fe-sdk 2026.922.5 → 2026.922.7

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 (57) hide show
  1. package/dist/{ExecutionDetailPage-W7OC3JAA.js → ExecutionDetailPage-WLC63RRK.js} +5 -5
  2. package/dist/{ExecutionDetailPage-W7OC3JAA.js.map → ExecutionDetailPage-WLC63RRK.js.map} +1 -1
  3. package/dist/ExecutionsListPage-P5DRISMN.js +10 -0
  4. package/dist/{ExecutionsListPage-OVBWXB2F.js.map → ExecutionsListPage-P5DRISMN.js.map} +1 -1
  5. package/dist/{WorkflowBuilder-JKILAD6H.js → WorkflowBuilder-LZ7X2M5Y.js} +8 -7
  6. package/dist/{WorkflowBuilder-JKILAD6H.js.map → WorkflowBuilder-LZ7X2M5Y.js.map} +1 -1
  7. package/dist/WorkflowsList-QDPC2HVV.js +13 -0
  8. package/dist/{WorkflowsList-ARAFHW6J.js.map → WorkflowsList-QDPC2HVV.js.map} +1 -1
  9. package/dist/{chunk-MGLTXIN5.js → chunk-275FCUOI.js} +3 -39
  10. package/dist/chunk-275FCUOI.js.map +1 -0
  11. package/dist/{chunk-5UNUNEGB.js → chunk-4KX6I7PA.js} +5 -5
  12. package/dist/{chunk-5UNUNEGB.js.map → chunk-4KX6I7PA.js.map} +1 -1
  13. package/dist/{chunk-CLESJQKA.js → chunk-4LJOUX2R.js} +5 -5
  14. package/dist/{chunk-CLESJQKA.js.map → chunk-4LJOUX2R.js.map} +1 -1
  15. package/dist/{chunk-2OJQPUBC.js → chunk-62OZJC2B.js} +4 -4
  16. package/dist/{chunk-2OJQPUBC.js.map → chunk-62OZJC2B.js.map} +1 -1
  17. package/dist/chunk-AANIWER2.js +41 -0
  18. package/dist/chunk-AANIWER2.js.map +1 -0
  19. package/dist/{chunk-VJDLWE5S.js → chunk-CQOQ6A73.js} +3 -3
  20. package/dist/{chunk-VJDLWE5S.js.map → chunk-CQOQ6A73.js.map} +1 -1
  21. package/dist/{chunk-N4URMBJP.js → chunk-CVNW2EUB.js} +3 -3
  22. package/dist/{chunk-N4URMBJP.js.map → chunk-CVNW2EUB.js.map} +1 -1
  23. package/dist/{chunk-FH5QBQXV.js → chunk-KAMWWBX5.js} +3 -3
  24. package/dist/{chunk-FH5QBQXV.js.map → chunk-KAMWWBX5.js.map} +1 -1
  25. package/dist/{chunk-ELB3LXRJ.js → chunk-OZBZS6DM.js} +3 -3
  26. package/dist/{chunk-ELB3LXRJ.js.map → chunk-OZBZS6DM.js.map} +1 -1
  27. package/dist/{chunk-77S64BTI.js → chunk-REM2BQK5.js} +5 -4
  28. package/dist/chunk-REM2BQK5.js.map +1 -0
  29. package/dist/{chunk-OGPTQCB6.js → chunk-VTKT6XDA.js} +891 -27
  30. package/dist/chunk-VTKT6XDA.js.map +1 -0
  31. package/dist/{chunk-6Y526LSH.js → chunk-WJQSPVU5.js} +11 -6
  32. package/dist/chunk-WJQSPVU5.js.map +1 -0
  33. package/dist/{chunk-ACRXNUU2.js → chunk-XA3IJE2D.js} +196 -49
  34. package/dist/chunk-XA3IJE2D.js.map +1 -0
  35. package/dist/{chunk-NOECWBYH.js → chunk-Z4XRVZZ2.js} +4 -4
  36. package/dist/{chunk-NOECWBYH.js.map → chunk-Z4XRVZZ2.js.map} +1 -1
  37. package/dist/executions.js +5 -5
  38. package/dist/history.js +3 -3
  39. package/dist/index.d.ts +51 -3
  40. package/dist/index.js +21 -20
  41. package/dist/index.js.map +1 -1
  42. package/dist/nodes.js +2 -2
  43. package/dist/settings.d.ts +12 -1
  44. package/dist/settings.js +3 -1
  45. package/dist/templates.js +6 -5
  46. package/dist/{workflow-builder-BNWKK8C7.d.ts → workflow-builder-lgLa__fU.d.ts} +102 -0
  47. package/dist/workflow-builder.d.ts +1 -1
  48. package/dist/workflow-builder.js +7 -6
  49. package/dist/workflows-list.js +5 -4
  50. package/package.json +1 -1
  51. package/dist/ExecutionsListPage-OVBWXB2F.js +0 -10
  52. package/dist/WorkflowsList-ARAFHW6J.js +0 -12
  53. package/dist/chunk-6Y526LSH.js.map +0 -1
  54. package/dist/chunk-77S64BTI.js.map +0 -1
  55. package/dist/chunk-ACRXNUU2.js.map +0 -1
  56. package/dist/chunk-MGLTXIN5.js.map +0 -1
  57. package/dist/chunk-OGPTQCB6.js.map +0 -1
@@ -4,14 +4,15 @@ import { Badge as Badge$1, Button as Button$1 } from './chunk-DBOMRIP5.js';
4
4
  import { getGlobalStoreClient, createGlobalStoreClient, setGlobalStoreClient, resetGlobalStoreClient } from './chunk-BQXHJIER.js';
5
5
  import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument } from './chunk-6LXMUIR3.js';
6
6
  import { deepClone, applyTemplateInputs } from './chunk-XQP33UJR.js';
7
- import { useFlowStore, QuotaExhaustedDialog } from './chunk-MGLTXIN5.js';
7
+ import { QuotaExhaustedDialog } from './chunk-AANIWER2.js';
8
8
  import { SdkPermissionGate, FLUIDGRIDS_PERMISSIONS, SdkPermissionButton } from './chunk-UIY2HBWA.js';
9
9
  import { cn as cn$1 } from './chunk-3ZYUGTIT.js';
10
- import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useDeactivateWorkflow } from './chunk-ELB3LXRJ.js';
10
+ import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useDeactivateWorkflow } from './chunk-OZBZS6DM.js';
11
11
  import { throwIfResultError, describeOperationError } from './chunk-LMO5ASOE.js';
12
12
  import { config, getFluidGridsConfig, validateTrustedOrigin, setFluidGridsConfig, resetFluidGridsConfig } from './chunk-WWU2O2SR.js';
13
- import { NodeEndpointConfigsDocument, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, TriggerWorkflowDocument, WorkflowRunDocument, FluidgridsEntityTagsDocument, AvailableFluidgridsTagsDocument, SearchFluidgridsTagsDocument, TagFluidgridsEntityDocument, UntagFluidgridsEntityDocument, ReplaceFluidgridsEntityTagsDocument, CreateFluidgridsTagDocument, NodeSchemaIntrospectionDocument, EventRegistrationsDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-WO3AHQVD.js';
14
13
  import { waitForFluidGridsClient, getFluidGridsClient, createFluidGridsClient, setFluidGridsClient, resetFluidGridsClient, getFluidGridsClientSafe } from './chunk-5BDQNSP3.js';
14
+ import { useFlowStore } from './chunk-275FCUOI.js';
15
+ import { NodeEndpointConfigsDocument, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, TriggerWorkflowDocument, WorkflowRunDocument, FluidgridsEntityTagsDocument, AvailableFluidgridsTagsDocument, SearchFluidgridsTagsDocument, TagFluidgridsEntityDocument, UntagFluidgridsEntityDocument, ReplaceFluidgridsEntityTagsDocument, CreateFluidgridsTagDocument, NodeSchemaIntrospectionDocument, EventRegistrationsDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-WO3AHQVD.js';
15
16
  import { useTr, FluidGridsTranslationProvider, ENGLISH_FALLBACK_TRANSLATOR } from './chunk-7YWBH2A5.js';
16
17
  import * as React2 from 'react';
17
18
  import React2__default, { forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, memo, createContext, lazy, useCallback, useContext, useLayoutEffect, Suspense, useDeferredValue } from 'react';
@@ -4349,6 +4350,50 @@ function createNodeWithDefaultData(type, data) {
4349
4350
  const defaultData = NODES.find((node) => node.type === type)?.defaultData ?? {};
4350
4351
  return Object.assign(createNodeData(type, defaultData), data);
4351
4352
  }
4353
+ var NODE_DOCS_URL = gql`
4354
+ query NodeDocsUrlLookup($nodeType: String!, $nodeVersion: String!) {
4355
+ nodeEndpointConfig(nodeType: $nodeType, nodeVersion: $nodeVersion) {
4356
+ docsUrl
4357
+ }
4358
+ }
4359
+ `;
4360
+ var cache = /* @__PURE__ */ new Map();
4361
+ var inFlight = /* @__PURE__ */ new Map();
4362
+ function fetchDocsUrl(nodeType, nodeVersion) {
4363
+ const key = `${nodeType}@${nodeVersion}`;
4364
+ if (cache.has(key)) return Promise.resolve(cache.get(key));
4365
+ const existing = inFlight.get(key);
4366
+ if (existing) return existing;
4367
+ const promise = getFluidGridsClient().query({
4368
+ query: NODE_DOCS_URL,
4369
+ variables: { nodeType, nodeVersion },
4370
+ fetchPolicy: "cache-first"
4371
+ }).then((result) => result.data?.nodeEndpointConfig?.docsUrl ?? void 0).catch(() => void 0).finally(() => inFlight.delete(key));
4372
+ inFlight.set(key, promise);
4373
+ return promise.then((url) => {
4374
+ cache.set(key, url);
4375
+ return url;
4376
+ });
4377
+ }
4378
+ function useNodeDocsUrl(nodeType, nodeVersion) {
4379
+ const [docsUrl, setDocsUrl] = useState(
4380
+ () => nodeType && nodeVersion ? cache.get(`${nodeType}@${nodeVersion}`) : void 0
4381
+ );
4382
+ useEffect(() => {
4383
+ if (!nodeType || !nodeVersion) {
4384
+ setDocsUrl(void 0);
4385
+ return;
4386
+ }
4387
+ let cancelled = false;
4388
+ fetchDocsUrl(nodeType, nodeVersion).then((url) => {
4389
+ if (!cancelled) setDocsUrl(url);
4390
+ });
4391
+ return () => {
4392
+ cancelled = true;
4393
+ };
4394
+ }, [nodeType, nodeVersion]);
4395
+ return docsUrl;
4396
+ }
4352
4397
  function isImageIcon(icon) {
4353
4398
  return !!icon && (/^https?:\/\//.test(icon) || icon.startsWith("data:"));
4354
4399
  }
@@ -6027,7 +6072,23 @@ function NodeInfoButtonWithModal({
6027
6072
  value: metadata.kind && metadata.kind.length > 0 ? metadata.kind.join(", ") : void 0
6028
6073
  }
6029
6074
  )
6030
- ] })
6075
+ ] }),
6076
+ metadata.docsUrl ? /* @__PURE__ */ jsxs(
6077
+ "a",
6078
+ {
6079
+ href: metadata.docsUrl,
6080
+ target: "_blank",
6081
+ rel: "noopener noreferrer",
6082
+ className: "inline-flex items-center gap-1 text-sm text-[var(--color-status-info-text)] hover:underline",
6083
+ children: [
6084
+ tr(
6085
+ "fluidgrids.builder.nodeInfoModal.docsLink",
6086
+ "View documentation"
6087
+ ),
6088
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2197" })
6089
+ ]
6090
+ }
6091
+ ) : null
6031
6092
  ] })
6032
6093
  ] });
6033
6094
  }
@@ -6423,6 +6484,10 @@ var getNodeMetadata = (value) => {
6423
6484
  function NodeComponent(props) {
6424
6485
  const { id, isConnectable, selected, data, dragging } = props;
6425
6486
  const tr = useTr();
6487
+ const docsUrl = useNodeDocsUrl(
6488
+ value?.type,
6489
+ data?.nodeData?.version || data?.version
6490
+ );
6426
6491
  const { edges, nodeLookup } = useStore(({ edges: edges2, nodeLookup: nodeLookup2 }) => ({
6427
6492
  edges: edges2,
6428
6493
  nodeLookup: nodeLookup2
@@ -6594,7 +6659,8 @@ var getNodeMetadata = (value) => {
6594
6659
  nodeType: value?.type,
6595
6660
  version: data?.nodeData?.version || data?.version,
6596
6661
  kind: nodeKinds,
6597
- operation: data?.operation_name
6662
+ operation: data?.operation_name,
6663
+ docsUrl
6598
6664
  };
6599
6665
  const isLogicNode = /(^|[:/])(if|switch|merge|loop|filter|branch|router|condition|aggregate)/.test(
6600
6666
  (value?.type || "").toLowerCase()
@@ -11835,8 +11901,8 @@ function DesktopSidebarFragment({
11835
11901
  }
11836
11902
  const { getFluidGridsClient: getFluidGridsClient2 } = await import('./client-AMUUS7VE.js');
11837
11903
  const { getFluidGridsConfig: getFluidGridsConfig2 } = await import('./config-E4E7M6IN.js');
11838
- const { gql: gql8 } = await import('@apollo/client/core');
11839
- const IMPORT_MUTATION = gql8`
11904
+ const { gql: gql10 } = await import('@apollo/client/core');
11905
+ const IMPORT_MUTATION = gql10`
11840
11906
  mutation ImportWorkflowTemplate(
11841
11907
  $input: ImportWorkflowTemplateInput!
11842
11908
  ) {
@@ -11982,8 +12048,8 @@ function DesktopSidebarFragment({
11982
12048
  { id: "template-load" }
11983
12049
  );
11984
12050
  const { getGlobalStoreClient: getGlobalStoreClient2 } = await import('./global-client-OW43ZRDR.js');
11985
- const { gql: gql8 } = await import('@apollo/client/core');
11986
- const GET_TEMPLATE_DETAIL = gql8`
12051
+ const { gql: gql10 } = await import('@apollo/client/core');
12052
+ const GET_TEMPLATE_DETAIL = gql10`
11987
12053
  query GetWorkflowTemplateDetail($id: ID!) {
11988
12054
  product(id: $id) {
11989
12055
  id
@@ -20669,6 +20735,7 @@ var LogDetailView = ({ log }) => {
20669
20735
  }[log.status];
20670
20736
  const data = activeTab === "input" ? log.inputArgs : log.output;
20671
20737
  const itemCount = data ? Object.keys(data).length : 0;
20738
+ const resumeUrl = typeof log.output?._resumeUrl === "string" ? log.output._resumeUrl : null;
20672
20739
  return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col", children: [
20673
20740
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-2 border-b border-card-foreground/10", children: [
20674
20741
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -20711,6 +20778,27 @@ var LogDetailView = ({ log }) => {
20711
20778
  )
20712
20779
  ] })
20713
20780
  ] }),
20781
+ resumeUrl && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-card-foreground/10 px-2 py-2", children: [
20782
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: tr("fluidgrids.builder.logsPanel.resumeUrl", "Resume URL") }),
20783
+ /* @__PURE__ */ jsx(
20784
+ "input",
20785
+ {
20786
+ readOnly: true,
20787
+ value: resumeUrl,
20788
+ onFocus: (e) => e.currentTarget.select(),
20789
+ className: "min-w-0 flex-1 rounded-md border border-border bg-muted/40 px-2 py-1 font-mono text-[11px] outline-none focus:border-primary"
20790
+ }
20791
+ ),
20792
+ /* @__PURE__ */ jsx(
20793
+ "button",
20794
+ {
20795
+ type: "button",
20796
+ onClick: () => void navigator.clipboard?.writeText(resumeUrl),
20797
+ className: "shrink-0 rounded-md border border-border px-2 py-1 text-[11px] font-medium hover:bg-muted",
20798
+ children: tr("fluidgrids.builder.logsPanel.copy", "Copy")
20799
+ }
20800
+ )
20801
+ ] }),
20714
20802
  /* @__PURE__ */ jsxs("div", { className: "flex border-b border-card-foreground/10", children: [
20715
20803
  /* @__PURE__ */ jsx(
20716
20804
  "button",
@@ -21984,6 +22072,63 @@ function CodeEditorField({
21984
22072
  );
21985
22073
  }
21986
22074
  var SECTION_LABEL = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
22075
+ var RESUME_URL_EXPRESSION = "${RunContext.resumeWebhookUrl}";
22076
+ function WaitResumeUrlField() {
22077
+ const tr = useTr();
22078
+ const [copied, setCopied] = useState(false);
22079
+ const handleCopy = async () => {
22080
+ try {
22081
+ await navigator.clipboard.writeText(RESUME_URL_EXPRESSION);
22082
+ setCopied(true);
22083
+ setTimeout(() => setCopied(false), 1500);
22084
+ } catch {
22085
+ }
22086
+ };
22087
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": "ndv-wait-resume-url", children: [
22088
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL, children: tr("fluidgrids.builder.waitResumeUrl.label", "Resume URL") }),
22089
+ /* @__PURE__ */ jsxs("div", { className: "flex items-stretch gap-2", children: [
22090
+ /* @__PURE__ */ jsx(
22091
+ "input",
22092
+ {
22093
+ readOnly: true,
22094
+ value: RESUME_URL_EXPRESSION,
22095
+ onFocus: (e) => e.currentTarget.select(),
22096
+ className: "min-w-0 flex-1 rounded-md border border-border bg-muted/40 px-3 py-2 font-mono text-xs text-foreground outline-none focus:border-primary"
22097
+ }
22098
+ ),
22099
+ /* @__PURE__ */ jsxs(
22100
+ "button",
22101
+ {
22102
+ type: "button",
22103
+ onClick: handleCopy,
22104
+ className: cn(
22105
+ "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border px-3 py-2 text-xs font-medium transition-colors",
22106
+ copied ? "border-primary bg-primary/10 text-primary" : "bg-background text-foreground hover:bg-muted"
22107
+ ),
22108
+ "aria-label": tr(
22109
+ "fluidgrids.builder.waitResumeUrl.copyAriaLabel",
22110
+ "Copy resume URL expression"
22111
+ ),
22112
+ children: [
22113
+ /* @__PURE__ */ jsx(
22114
+ Icon,
22115
+ {
22116
+ icon: copied ? "mdi:check" : "mdi:content-copy",
22117
+ className: "h-4 w-4"
22118
+ }
22119
+ ),
22120
+ copied ? tr("fluidgrids.builder.waitResumeUrl.copied", "Copied") : tr("fluidgrids.builder.waitResumeUrl.copy", "Copy")
22121
+ ]
22122
+ }
22123
+ )
22124
+ ] }),
22125
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tr(
22126
+ "fluidgrids.builder.waitResumeUrl.help",
22127
+ "Each run gets its own signed, single-use resume URL. Use this expression in an earlier node (an email or message) to send the link; the run continues when it is called. The URL for a finished or waiting run appears on this node's output as _resumeUrl."
22128
+ ) })
22129
+ ] });
22130
+ }
22131
+ var SECTION_LABEL2 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
21987
22132
  function WebhookUrlField({ webhookUrl, loading }) {
21988
22133
  const tr = useTr();
21989
22134
  const [copied, setCopied] = useState(false);
@@ -21997,7 +22142,7 @@ function WebhookUrlField({ webhookUrl, loading }) {
21997
22142
  }
21998
22143
  };
21999
22144
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": "ndv-webhook-url", children: [
22000
- /* @__PURE__ */ jsx("div", { className: SECTION_LABEL, children: tr("fluidgrids.builder.webhookUrlField.label", "Webhook URL") }),
22145
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL2, children: tr("fluidgrids.builder.webhookUrlField.label", "Webhook URL") }),
22001
22146
  webhookUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
22002
22147
  /* @__PURE__ */ jsxs("div", { className: "flex items-stretch gap-2", children: [
22003
22148
  /* @__PURE__ */ jsx(
@@ -22048,6 +22193,192 @@ function WebhookUrlField({ webhookUrl, loading }) {
22048
22193
  ) })
22049
22194
  ] });
22050
22195
  }
22196
+ var LOAD_NODE_OPTIONS = gql`
22197
+ query LoadNodeOptions(
22198
+ $nodeType: String!
22199
+ $nodeVersion: String!
22200
+ $operationName: String!
22201
+ $resultPath: String
22202
+ $labelField: String!
22203
+ $valueField: String!
22204
+ $connectionId: ID
22205
+ $args: JSON
22206
+ ) {
22207
+ loadNodeOptions(
22208
+ nodeType: $nodeType
22209
+ nodeVersion: $nodeVersion
22210
+ operationName: $operationName
22211
+ resultPath: $resultPath
22212
+ labelField: $labelField
22213
+ valueField: $valueField
22214
+ connectionId: $connectionId
22215
+ args: $args
22216
+ ) {
22217
+ label
22218
+ value
22219
+ }
22220
+ }
22221
+ `;
22222
+ var CLIENT_CACHE_TTL_MS = 3 * 60 * 1e3;
22223
+ var cache2 = /* @__PURE__ */ new Map();
22224
+ function cacheKey(nodeType, nodeVersion, spec, connectionId) {
22225
+ return [
22226
+ nodeType,
22227
+ nodeVersion,
22228
+ spec.operation,
22229
+ spec.resultPath ?? "",
22230
+ spec.labelField,
22231
+ spec.valueField,
22232
+ connectionId ?? ""
22233
+ ].join("::");
22234
+ }
22235
+ function useLoadNodeOptions(nodeType, nodeVersion, spec, connectionId) {
22236
+ const [options, setOptions] = useState([]);
22237
+ const [loading, setLoading] = useState(false);
22238
+ const [error, setError] = useState(null);
22239
+ const [nonce, setNonce] = useState(0);
22240
+ const mountedRef = useRef(true);
22241
+ useEffect(
22242
+ () => () => {
22243
+ mountedRef.current = false;
22244
+ },
22245
+ []
22246
+ );
22247
+ useEffect(() => {
22248
+ if (!nodeType || !nodeVersion || !spec || !connectionId) {
22249
+ setOptions([]);
22250
+ setError(null);
22251
+ return;
22252
+ }
22253
+ const key = cacheKey(nodeType, nodeVersion, spec, connectionId);
22254
+ const cached = cache2.get(key);
22255
+ if (cached && cached.expiresAt > Date.now()) {
22256
+ setOptions(cached.options);
22257
+ setError(null);
22258
+ return;
22259
+ }
22260
+ let cancelled = false;
22261
+ setLoading(true);
22262
+ setError(null);
22263
+ const client = getFluidGridsClient();
22264
+ client.query({
22265
+ query: LOAD_NODE_OPTIONS,
22266
+ variables: {
22267
+ nodeType,
22268
+ nodeVersion,
22269
+ operationName: spec.operation,
22270
+ resultPath: spec.resultPath ?? null,
22271
+ labelField: spec.labelField,
22272
+ valueField: spec.valueField,
22273
+ connectionId,
22274
+ args: {}
22275
+ },
22276
+ fetchPolicy: "network-only"
22277
+ }).then((result) => {
22278
+ if (cancelled || !mountedRef.current) return;
22279
+ const fetched = result.data?.loadNodeOptions ?? [];
22280
+ cache2.set(key, {
22281
+ options: fetched,
22282
+ expiresAt: Date.now() + CLIENT_CACHE_TTL_MS
22283
+ });
22284
+ setOptions(fetched);
22285
+ }).catch((err) => {
22286
+ if (cancelled || !mountedRef.current) return;
22287
+ setOptions([]);
22288
+ setError(err instanceof Error ? err : new Error(String(err)));
22289
+ }).finally(() => {
22290
+ if (cancelled || !mountedRef.current) return;
22291
+ setLoading(false);
22292
+ });
22293
+ return () => {
22294
+ cancelled = true;
22295
+ };
22296
+ }, [nodeType, nodeVersion, spec, connectionId, nonce]);
22297
+ return {
22298
+ options,
22299
+ loading,
22300
+ error,
22301
+ refetch: () => setNonce((n) => n + 1)
22302
+ };
22303
+ }
22304
+ function NodeLoadOptionsSelect({
22305
+ nodeType,
22306
+ nodeVersion,
22307
+ spec,
22308
+ connectionId,
22309
+ value,
22310
+ onChange,
22311
+ className,
22312
+ testId
22313
+ }) {
22314
+ const tr = useTr();
22315
+ const { options, loading, error } = useLoadNodeOptions(
22316
+ nodeType,
22317
+ nodeVersion,
22318
+ spec,
22319
+ connectionId
22320
+ );
22321
+ const stringValue = typeof value === "string" ? value : "";
22322
+ if (!connectionId) {
22323
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5", children: /* @__PURE__ */ jsx(
22324
+ "input",
22325
+ {
22326
+ type: "text",
22327
+ value: stringValue,
22328
+ onChange: (e) => onChange(e.target.value),
22329
+ placeholder: tr(
22330
+ "fluidgrids.builder.nodeParamsForm.loadOptionsNoConnection",
22331
+ "Connect an account above to load options, or type a value"
22332
+ ),
22333
+ "data-testid": testId,
22334
+ className
22335
+ }
22336
+ ) });
22337
+ }
22338
+ if (error) {
22339
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
22340
+ /* @__PURE__ */ jsx(
22341
+ "input",
22342
+ {
22343
+ type: "text",
22344
+ value: stringValue,
22345
+ onChange: (e) => onChange(e.target.value),
22346
+ placeholder: tr(
22347
+ "fluidgrids.builder.nodeParamsForm.loadOptionsErrorPlaceholder",
22348
+ "Enter a value"
22349
+ ),
22350
+ "data-testid": testId,
22351
+ className
22352
+ }
22353
+ ),
22354
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-destructive", children: tr(
22355
+ "fluidgrids.builder.nodeParamsForm.loadOptionsError",
22356
+ "Couldn't load options \u2014 enter a value manually."
22357
+ ) })
22358
+ ] });
22359
+ }
22360
+ return /* @__PURE__ */ jsxs(
22361
+ "select",
22362
+ {
22363
+ value: stringValue,
22364
+ onChange: (e) => onChange(e.target.value),
22365
+ disabled: loading,
22366
+ "data-testid": testId,
22367
+ className: cn(className, loading && "opacity-60"),
22368
+ children: [
22369
+ /* @__PURE__ */ jsx("option", { value: "", children: loading ? tr(
22370
+ "fluidgrids.builder.nodeParamsForm.loadOptionsLoading",
22371
+ "Loading\u2026"
22372
+ ) : tr(
22373
+ "fluidgrids.builder.nodeParamsForm.selectPlaceholder",
22374
+ "Select\u2026"
22375
+ ) }),
22376
+ stringValue && !options.some((o) => o.value === stringValue) && /* @__PURE__ */ jsx("option", { value: stringValue, children: stringValue }),
22377
+ options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
22378
+ ]
22379
+ }
22380
+ );
22381
+ }
22051
22382
  function useWebhookRegistration(workflowKey, triggerNodeId, enabled = true) {
22052
22383
  const [registration, setRegistration] = useState(
22053
22384
  null
@@ -22092,6 +22423,10 @@ function useWebhookRegistration(workflowKey, triggerNodeId, enabled = true) {
22092
22423
  }
22093
22424
 
22094
22425
  // src/builder/components/ndv/use-node-config.ts
22426
+ function errorConfigOf(node) {
22427
+ const config2 = asRecord(node?.data)?.errorConfig;
22428
+ return config2;
22429
+ }
22095
22430
  function coerceNumber(type, raw) {
22096
22431
  if (raw.trim() === "") return void 0;
22097
22432
  const n = type === "integer" ? parseInt(raw, 10) : parseFloat(raw);
@@ -22116,13 +22451,21 @@ function paramsFromOperation(op) {
22116
22451
  const options = Array.isArray(optsRaw) ? optsRaw.map(
22117
22452
  (o) => typeof o === "string" ? o : asRecord(o)?.value ?? asRecord(o)?.name
22118
22453
  ).filter((v) => typeof v === "string") : void 0;
22454
+ const loadOptionsRec = asRecord(rec?.loadOptions);
22455
+ const loadOptions = loadOptionsRec && typeof loadOptionsRec.operation === "string" && typeof loadOptionsRec.labelField === "string" && typeof loadOptionsRec.valueField === "string" ? {
22456
+ operation: loadOptionsRec.operation,
22457
+ labelField: loadOptionsRec.labelField,
22458
+ valueField: loadOptionsRec.valueField,
22459
+ resultPath: typeof loadOptionsRec.resultPath === "string" ? loadOptionsRec.resultPath : void 0
22460
+ } : void 0;
22119
22461
  return {
22120
22462
  name,
22121
22463
  type: typeof spec === "string" ? spec : typeof rec?.type === "string" ? rec.type : "any",
22122
22464
  required: rec?.required === true,
22123
22465
  description: typeof rec?.description === "string" ? rec.description : void 0,
22124
22466
  options,
22125
- defaultValue: rec?.default
22467
+ defaultValue: rec?.default,
22468
+ loadOptions
22126
22469
  };
22127
22470
  });
22128
22471
  }
@@ -22203,6 +22546,11 @@ function useNodeConfig(target, options) {
22203
22546
  const args = asRecord(data?.args);
22204
22547
  return asRecord(args?.state) ?? {};
22205
22548
  }, [node]);
22549
+ const isWebhookWait = useMemo(() => {
22550
+ const type = asRecord(asRecord(node?.data)?.args)?.context;
22551
+ const nodeType = asRecord(asRecord(type)?.node)?.type;
22552
+ return nodeType === "internal:wait" && argsState.mode === "webhook";
22553
+ }, [node, argsState]);
22206
22554
  const connectionAdapters = useMemo(() => {
22207
22555
  const op = asRecord(currentOp);
22208
22556
  const manifest = asRecord(asRecord(node?.data)?.nodeData);
@@ -22297,6 +22645,58 @@ function useNodeConfig(target, options) {
22297
22645
  store.actions.nodes.setNodes(next);
22298
22646
  clearMappingFromAllIncoming(field);
22299
22647
  };
22648
+ const writeErrorConfig = (patch) => {
22649
+ if (!nodeId) return;
22650
+ const store = useFlowStore.getState();
22651
+ const next = store.workflow.nodes.map((n) => {
22652
+ if (n.id !== nodeId) return n;
22653
+ const data = { ...asRecord(n.data) ?? {} };
22654
+ const prev = errorConfigOf(n) ?? {};
22655
+ const merged = { ...prev, ...patch };
22656
+ if (patch.retryConfig !== void 0) {
22657
+ merged.retryConfig = patch.retryConfig ? { ...prev.retryConfig, ...patch.retryConfig } : void 0;
22658
+ }
22659
+ if (patch.timeout !== void 0) {
22660
+ merged.timeout = patch.timeout ? { ...prev.timeout, ...patch.timeout } : void 0;
22661
+ }
22662
+ data.errorConfig = merged;
22663
+ return { ...n, data };
22664
+ });
22665
+ store.actions.nodes.setNodes(next);
22666
+ };
22667
+ const writeNodeDataField = (field, value) => {
22668
+ if (!nodeId) return;
22669
+ const store = useFlowStore.getState();
22670
+ const next = store.workflow.nodes.map((n) => {
22671
+ if (n.id !== nodeId) return n;
22672
+ const data = { ...asRecord(n.data) ?? {} };
22673
+ if (value === void 0 || value === "" || value === false) {
22674
+ delete data[field];
22675
+ } else {
22676
+ data[field] = value;
22677
+ }
22678
+ return { ...n, data };
22679
+ });
22680
+ store.actions.nodes.setNodes(next);
22681
+ };
22682
+ const writeNotes = (value) => writeNodeDataField("notes", value);
22683
+ const writeExecutionSettings = (patch) => {
22684
+ if (!nodeId) return;
22685
+ const store = useFlowStore.getState();
22686
+ const next = store.workflow.nodes.map((n) => {
22687
+ if (n.id !== nodeId) return n;
22688
+ const data = { ...asRecord(n.data) ?? {} };
22689
+ const prev = asRecord(data.executionSettings) ?? {};
22690
+ const merged = { ...prev, ...patch };
22691
+ if (!merged.alwaysOutputData && !merged.executeOnce) {
22692
+ delete data.executionSettings;
22693
+ } else {
22694
+ data.executionSettings = merged;
22695
+ }
22696
+ return { ...n, data };
22697
+ });
22698
+ store.actions.nodes.setNodes(next);
22699
+ };
22300
22700
  const toggleMode = (field, current) => {
22301
22701
  if (current === "expression") {
22302
22702
  clearMappingFromAllIncoming(field);
@@ -22306,6 +22706,17 @@ function useNodeConfig(target, options) {
22306
22706
  [field]: current === "expression" ? "fixed" : "expression"
22307
22707
  }));
22308
22708
  };
22709
+ const errorConfig = useMemo(() => errorConfigOf(node), [node]);
22710
+ const notes = useMemo(() => {
22711
+ const data = asRecord(node?.data);
22712
+ return typeof data?.notes === "string" ? data.notes : "";
22713
+ }, [node]);
22714
+ const executionSettings = useMemo(
22715
+ () => asRecord(asRecord(node?.data)?.executionSettings),
22716
+ [node]
22717
+ );
22718
+ const alwaysOutputData = executionSettings?.alwaysOutputData === true;
22719
+ const executeOnce = executionSettings?.executeOnce === true;
22309
22720
  const handleDropOnParam = (field) => (e) => {
22310
22721
  e.preventDefault();
22311
22722
  setDragField(null);
@@ -22333,6 +22744,7 @@ function useNodeConfig(target, options) {
22333
22744
  connectionAdapters,
22334
22745
  selectedConnections,
22335
22746
  isWebhookTrigger,
22747
+ isWebhookWait,
22336
22748
  webhookUrl,
22337
22749
  webhookUrlLoading,
22338
22750
  modeByField,
@@ -22342,10 +22754,18 @@ function useNodeConfig(target, options) {
22342
22754
  writeMapping,
22343
22755
  handleConnectionsChange,
22344
22756
  toggleMode,
22345
- handleDropOnParam
22757
+ handleDropOnParam,
22758
+ errorConfig,
22759
+ writeErrorConfig,
22760
+ notes,
22761
+ writeNotes,
22762
+ alwaysOutputData,
22763
+ executeOnce,
22764
+ writeExecutionSettings,
22765
+ writeNodeDataField
22346
22766
  };
22347
22767
  }
22348
- var SECTION_LABEL2 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
22768
+ var SECTION_LABEL3 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
22349
22769
  function NodeParamsForm({
22350
22770
  config: config2,
22351
22771
  nodeType,
@@ -22360,6 +22780,7 @@ function NodeParamsForm({
22360
22780
  connectionAdapters,
22361
22781
  selectedConnections,
22362
22782
  isWebhookTrigger,
22783
+ isWebhookWait,
22363
22784
  webhookUrl,
22364
22785
  webhookUrlLoading,
22365
22786
  currentEdge,
@@ -22372,10 +22793,24 @@ function NodeParamsForm({
22372
22793
  toggleMode,
22373
22794
  handleDropOnParam
22374
22795
  } = config2;
22796
+ const loadOptionsConnectionId = (() => {
22797
+ const adapterNames = new Set(connectionAdapters.map((a) => a.name));
22798
+ return selectedConnections.find((c) => adapterNames.has(c.adapter))?.connectionId ?? selectedConnections[0]?.connectionId;
22799
+ })();
22800
+ const nodeVersion = (() => {
22801
+ const data = asRecord(config2.node?.data);
22802
+ const nodeData = asRecord(data?.nodeData);
22803
+ const fromManifest = nodeData?.version;
22804
+ const fromData = data?.version;
22805
+ if (typeof fromManifest === "string") return fromManifest;
22806
+ if (typeof fromData === "string") return fromData;
22807
+ return "1.0.0";
22808
+ })();
22375
22809
  return /* @__PURE__ */ jsxs(Fragment, { children: [
22376
22810
  isWebhookTrigger && /* @__PURE__ */ jsx(WebhookUrlField, { webhookUrl, loading: webhookUrlLoading }),
22811
+ isWebhookWait && /* @__PURE__ */ jsx(WaitResumeUrlField, {}),
22377
22812
  connectionAdapters.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": `${testIdPrefix}-connections`, children: [
22378
- /* @__PURE__ */ jsx("div", { className: SECTION_LABEL2, children: tr(
22813
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL3, children: tr(
22379
22814
  "fluidgrids.builder.nodeParamsForm.connectionsSection",
22380
22815
  "Connections"
22381
22816
  ) }),
@@ -22442,7 +22877,7 @@ function NodeParamsForm({
22442
22877
  const fixedValue = argsState[p.name];
22443
22878
  const isCodeParam = p.type === "code" || nodeType === "internal:code" && p.name === "code";
22444
22879
  const highlight = dragField === p.name;
22445
- const inputCx = cn(
22880
+ const inputCx2 = cn(
22446
22881
  "w-full rounded-md border bg-background px-2.5 py-1.5 text-sm outline-none transition-colors disabled:opacity-50",
22447
22882
  highlight ? "border-primary ring-1 ring-primary" : "border-input focus:border-primary"
22448
22883
  );
@@ -22521,6 +22956,18 @@ function NodeParamsForm({
22521
22956
  onChange: (v) => writeFixed(p.name, v),
22522
22957
  "data-testid": `${testIdPrefix}-param-${p.name}`
22523
22958
  }
22959
+ ) : p.loadOptions ? /* @__PURE__ */ jsx(
22960
+ NodeLoadOptionsSelect,
22961
+ {
22962
+ nodeType,
22963
+ nodeVersion,
22964
+ spec: p.loadOptions,
22965
+ connectionId: loadOptionsConnectionId,
22966
+ value: fixedValue,
22967
+ onChange: (v) => writeFixed(p.name, v),
22968
+ className: inputCx2,
22969
+ testId: `${testIdPrefix}-param-${p.name}`
22970
+ }
22524
22971
  ) : p.type === "boolean" ? /* @__PURE__ */ jsxs("label", { className: "flex w-fit cursor-pointer items-center gap-2 text-sm", children: [
22525
22972
  /* @__PURE__ */ jsx(
22526
22973
  "input",
@@ -22542,7 +22989,7 @@ function NodeParamsForm({
22542
22989
  value: typeof fixedValue === "string" ? fixedValue : "",
22543
22990
  onChange: (e) => writeFixed(p.name, e.target.value),
22544
22991
  "data-testid": `${testIdPrefix}-param-${p.name}`,
22545
- className: inputCx,
22992
+ className: inputCx2,
22546
22993
  children: [
22547
22994
  /* @__PURE__ */ jsx("option", { value: "", children: p.defaultValue !== void 0 ? `Default (${String(p.defaultValue)})` : tr(
22548
22995
  "fluidgrids.builder.nodeParamsForm.selectPlaceholder",
@@ -22563,7 +23010,7 @@ function NodeParamsForm({
22563
23010
  ),
22564
23011
  onChange: (e) => writeFixed(p.name, coerceNumber(p.type, e.target.value)),
22565
23012
  "data-testid": `${testIdPrefix}-param-${p.name}`,
22566
- className: inputCx
23013
+ className: inputCx2
22567
23014
  }
22568
23015
  ) : /* @__PURE__ */ jsx(
22569
23016
  "input",
@@ -22576,7 +23023,7 @@ function NodeParamsForm({
22576
23023
  ),
22577
23024
  onChange: (e) => writeFixed(p.name, e.target.value),
22578
23025
  "data-testid": `${testIdPrefix}-param-${p.name}`,
22579
- className: inputCx
23026
+ className: inputCx2
22580
23027
  }
22581
23028
  ),
22582
23029
  p.description && /* @__PURE__ */ jsx("span", { className: "text-[11px] leading-snug text-muted-foreground", children: p.description })
@@ -22587,6 +23034,419 @@ function NodeParamsForm({
22587
23034
  })
22588
23035
  ] });
22589
23036
  }
23037
+ var SECTION_LABEL4 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
23038
+ var inputCx = "w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-sm outline-none transition-colors focus:border-primary disabled:opacity-50";
23039
+ function msToSeconds(ms, fallbackMs) {
23040
+ return Math.round((ms ?? fallbackMs) / 1e3 * 10) / 10;
23041
+ }
23042
+ function secondsInputToMs(raw, minMs) {
23043
+ const seconds = parseFloat(raw);
23044
+ if (Number.isNaN(seconds)) return minMs;
23045
+ return Math.max(minMs, Math.round(seconds * 1e3));
23046
+ }
23047
+ function NodeSettingsPanel({
23048
+ config: config2
23049
+ }) {
23050
+ const tr = useTr();
23051
+ const {
23052
+ nodes,
23053
+ node,
23054
+ errorConfig,
23055
+ writeErrorConfig,
23056
+ notes,
23057
+ writeNotes,
23058
+ alwaysOutputData,
23059
+ executeOnce,
23060
+ writeExecutionSettings
23061
+ } = config2;
23062
+ const onError = errorConfig?.onError ?? "stop";
23063
+ const retryEnabled = (errorConfig?.retryConfig?.maxRetries ?? 0) > 0;
23064
+ const timeoutEnabled = !!errorConfig?.timeout?.duration;
23065
+ const branchTargets = nodes.filter((n) => n.id !== node?.id);
23066
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", "data-testid": "ndv-settings-panel", children: [
23067
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
23068
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL4, children: tr("fluidgrids.builder.nodeSettings.retrySection", "Retry on Fail") }),
23069
+ /* @__PURE__ */ jsxs("label", { className: "flex w-fit cursor-pointer items-center gap-2 text-sm", children: [
23070
+ /* @__PURE__ */ jsx(
23071
+ "input",
23072
+ {
23073
+ type: "checkbox",
23074
+ checked: retryEnabled,
23075
+ onChange: (e) => writeErrorConfig({
23076
+ retryConfig: e.target.checked ? {
23077
+ maxRetries: errorConfig?.retryConfig?.maxRetries || 3,
23078
+ retryDelay: errorConfig?.retryConfig?.retryDelay || 1e3,
23079
+ backoffMultiplier: errorConfig?.retryConfig?.backoffMultiplier ?? 2,
23080
+ maxDelay: errorConfig?.retryConfig?.maxDelay ?? 3e4
23081
+ } : void 0
23082
+ }),
23083
+ "data-testid": "ndv-settings-retry-enabled",
23084
+ className: "size-4"
23085
+ }
23086
+ ),
23087
+ /* @__PURE__ */ jsx("span", { children: tr(
23088
+ "fluidgrids.builder.nodeSettings.retryEnabledLabel",
23089
+ "Retry this node on failure"
23090
+ ) })
23091
+ ] }),
23092
+ retryEnabled && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 pl-6", children: [
23093
+ /* @__PURE__ */ jsx(
23094
+ Field,
23095
+ {
23096
+ label: tr(
23097
+ "fluidgrids.builder.nodeSettings.maxRetries",
23098
+ "Max tries"
23099
+ ),
23100
+ children: /* @__PURE__ */ jsx(
23101
+ "input",
23102
+ {
23103
+ type: "number",
23104
+ min: 1,
23105
+ max: 20,
23106
+ value: errorConfig?.retryConfig?.maxRetries ?? 3,
23107
+ onChange: (e) => writeErrorConfig({
23108
+ retryConfig: {
23109
+ ...errorConfig?.retryConfig ?? {
23110
+ retryDelay: 1e3,
23111
+ maxRetries: 3
23112
+ },
23113
+ maxRetries: Math.max(
23114
+ 1,
23115
+ parseInt(e.target.value, 10) || 1
23116
+ )
23117
+ }
23118
+ }),
23119
+ "data-testid": "ndv-settings-max-retries",
23120
+ className: inputCx
23121
+ }
23122
+ )
23123
+ }
23124
+ ),
23125
+ /* @__PURE__ */ jsx(
23126
+ Field,
23127
+ {
23128
+ label: tr(
23129
+ "fluidgrids.builder.nodeSettings.retryDelay",
23130
+ "Wait (seconds)"
23131
+ ),
23132
+ children: /* @__PURE__ */ jsx(
23133
+ "input",
23134
+ {
23135
+ type: "number",
23136
+ min: 0,
23137
+ step: 0.1,
23138
+ value: msToSeconds(errorConfig?.retryConfig?.retryDelay, 1e3),
23139
+ onChange: (e) => writeErrorConfig({
23140
+ retryConfig: {
23141
+ ...errorConfig?.retryConfig ?? {
23142
+ maxRetries: 3,
23143
+ retryDelay: 1e3
23144
+ },
23145
+ retryDelay: secondsInputToMs(e.target.value, 0)
23146
+ }
23147
+ }),
23148
+ "data-testid": "ndv-settings-retry-delay",
23149
+ className: inputCx
23150
+ }
23151
+ )
23152
+ }
23153
+ ),
23154
+ /* @__PURE__ */ jsx(
23155
+ Field,
23156
+ {
23157
+ label: tr(
23158
+ "fluidgrids.builder.nodeSettings.backoffMultiplier",
23159
+ "Backoff \xD7"
23160
+ ),
23161
+ children: /* @__PURE__ */ jsx(
23162
+ "input",
23163
+ {
23164
+ type: "number",
23165
+ min: 1,
23166
+ step: 0.5,
23167
+ value: errorConfig?.retryConfig?.backoffMultiplier ?? 2,
23168
+ onChange: (e) => writeErrorConfig({
23169
+ retryConfig: {
23170
+ ...errorConfig?.retryConfig ?? {
23171
+ maxRetries: 3,
23172
+ retryDelay: 1e3
23173
+ },
23174
+ backoffMultiplier: parseFloat(e.target.value) || 1
23175
+ }
23176
+ }),
23177
+ "data-testid": "ndv-settings-backoff-multiplier",
23178
+ className: inputCx
23179
+ }
23180
+ )
23181
+ }
23182
+ ),
23183
+ /* @__PURE__ */ jsx(
23184
+ Field,
23185
+ {
23186
+ label: tr(
23187
+ "fluidgrids.builder.nodeSettings.maxDelay",
23188
+ "Max wait (seconds)"
23189
+ ),
23190
+ children: /* @__PURE__ */ jsx(
23191
+ "input",
23192
+ {
23193
+ type: "number",
23194
+ min: 0,
23195
+ step: 1,
23196
+ value: msToSeconds(errorConfig?.retryConfig?.maxDelay, 3e4),
23197
+ onChange: (e) => writeErrorConfig({
23198
+ retryConfig: {
23199
+ ...errorConfig?.retryConfig ?? {
23200
+ maxRetries: 3,
23201
+ retryDelay: 1e3
23202
+ },
23203
+ maxDelay: secondsInputToMs(e.target.value, 0)
23204
+ }
23205
+ }),
23206
+ "data-testid": "ndv-settings-max-delay",
23207
+ className: inputCx
23208
+ }
23209
+ )
23210
+ }
23211
+ )
23212
+ ] })
23213
+ ] }),
23214
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
23215
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL4, children: tr("fluidgrids.builder.nodeSettings.onErrorSection", "On Error") }),
23216
+ /* @__PURE__ */ jsxs(
23217
+ "select",
23218
+ {
23219
+ value: onError,
23220
+ onChange: (e) => writeErrorConfig({
23221
+ onError: e.target.value,
23222
+ errorBranchId: e.target.value === "branch" ? errorConfig?.errorBranchId : void 0
23223
+ }),
23224
+ "data-testid": "ndv-settings-on-error",
23225
+ className: cn(inputCx, "max-w-xs"),
23226
+ children: [
23227
+ /* @__PURE__ */ jsx("option", { value: "stop", children: tr(
23228
+ "fluidgrids.builder.nodeSettings.onErrorStop",
23229
+ "Stop workflow (default)"
23230
+ ) }),
23231
+ /* @__PURE__ */ jsx("option", { value: "continue", children: tr(
23232
+ "fluidgrids.builder.nodeSettings.onErrorContinue",
23233
+ "Continue on fail"
23234
+ ) }),
23235
+ /* @__PURE__ */ jsx("option", { value: "branch", children: tr(
23236
+ "fluidgrids.builder.nodeSettings.onErrorBranch",
23237
+ "Route to error branch"
23238
+ ) })
23239
+ ]
23240
+ }
23241
+ ),
23242
+ onError === "branch" && /* @__PURE__ */ jsx("div", { className: "pl-2", children: /* @__PURE__ */ jsx(
23243
+ Field,
23244
+ {
23245
+ label: tr(
23246
+ "fluidgrids.builder.nodeSettings.errorBranchTarget",
23247
+ "Error branch target"
23248
+ ),
23249
+ children: /* @__PURE__ */ jsxs(
23250
+ "select",
23251
+ {
23252
+ value: errorConfig?.errorBranchId ?? "",
23253
+ onChange: (e) => writeErrorConfig({
23254
+ errorBranchId: e.target.value || void 0
23255
+ }),
23256
+ "data-testid": "ndv-settings-error-branch-id",
23257
+ className: cn(inputCx, "max-w-xs"),
23258
+ children: [
23259
+ /* @__PURE__ */ jsx("option", { value: "", children: tr(
23260
+ "fluidgrids.builder.nodeSettings.selectNode",
23261
+ "Select a node\u2026"
23262
+ ) }),
23263
+ branchTargets.map((n) => /* @__PURE__ */ jsx("option", { value: n.id, children: nodeTitle(n) }, n.id))
23264
+ ]
23265
+ }
23266
+ )
23267
+ }
23268
+ ) })
23269
+ ] }),
23270
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
23271
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL4, children: tr("fluidgrids.builder.nodeSettings.timeoutSection", "Timeout") }),
23272
+ /* @__PURE__ */ jsxs("label", { className: "flex w-fit cursor-pointer items-center gap-2 text-sm", children: [
23273
+ /* @__PURE__ */ jsx(
23274
+ "input",
23275
+ {
23276
+ type: "checkbox",
23277
+ checked: timeoutEnabled,
23278
+ onChange: (e) => writeErrorConfig({
23279
+ timeout: e.target.checked ? { duration: errorConfig?.timeout?.duration || 3e4 } : void 0
23280
+ }),
23281
+ "data-testid": "ndv-settings-timeout-enabled",
23282
+ className: "size-4"
23283
+ }
23284
+ ),
23285
+ /* @__PURE__ */ jsx("span", { children: tr(
23286
+ "fluidgrids.builder.nodeSettings.timeoutEnabledLabel",
23287
+ "Abort this node if it runs too long"
23288
+ ) })
23289
+ ] }),
23290
+ timeoutEnabled && /* @__PURE__ */ jsxs("div", { className: "space-y-3 pl-6", children: [
23291
+ /* @__PURE__ */ jsx(
23292
+ Field,
23293
+ {
23294
+ label: tr(
23295
+ "fluidgrids.builder.nodeSettings.timeoutDuration",
23296
+ "Timeout (seconds)"
23297
+ ),
23298
+ children: /* @__PURE__ */ jsx(
23299
+ "input",
23300
+ {
23301
+ type: "number",
23302
+ min: 0.1,
23303
+ step: 0.5,
23304
+ value: msToSeconds(errorConfig?.timeout?.duration, 3e4),
23305
+ onChange: (e) => writeErrorConfig({
23306
+ timeout: {
23307
+ ...errorConfig?.timeout ?? { duration: 3e4 },
23308
+ duration: secondsInputToMs(e.target.value, 100)
23309
+ }
23310
+ }),
23311
+ "data-testid": "ndv-settings-timeout-duration",
23312
+ className: cn(inputCx, "max-w-[10rem]")
23313
+ }
23314
+ )
23315
+ }
23316
+ ),
23317
+ /* @__PURE__ */ jsx(
23318
+ Field,
23319
+ {
23320
+ label: tr(
23321
+ "fluidgrids.builder.nodeSettings.onTimeout",
23322
+ "On timeout"
23323
+ ),
23324
+ children: /* @__PURE__ */ jsxs(
23325
+ "select",
23326
+ {
23327
+ value: errorConfig?.timeout?.onTimeout ?? "stop",
23328
+ onChange: (e) => writeErrorConfig({
23329
+ timeout: {
23330
+ ...errorConfig?.timeout ?? { duration: 3e4 },
23331
+ onTimeout: e.target.value,
23332
+ timeoutBranchId: e.target.value === "branch" ? errorConfig?.timeout?.timeoutBranchId : void 0
23333
+ }
23334
+ }),
23335
+ "data-testid": "ndv-settings-on-timeout",
23336
+ className: cn(inputCx, "max-w-xs"),
23337
+ children: [
23338
+ /* @__PURE__ */ jsx("option", { value: "stop", children: tr(
23339
+ "fluidgrids.builder.nodeSettings.onTimeoutStop",
23340
+ "Use Retry/On Error settings above"
23341
+ ) }),
23342
+ /* @__PURE__ */ jsx("option", { value: "continue", children: tr(
23343
+ "fluidgrids.builder.nodeSettings.onTimeoutContinue",
23344
+ "Continue on timeout"
23345
+ ) }),
23346
+ /* @__PURE__ */ jsx("option", { value: "branch", children: tr(
23347
+ "fluidgrids.builder.nodeSettings.onTimeoutBranch",
23348
+ "Route to a specific branch"
23349
+ ) })
23350
+ ]
23351
+ }
23352
+ )
23353
+ }
23354
+ ),
23355
+ errorConfig?.timeout?.onTimeout === "branch" && /* @__PURE__ */ jsx(
23356
+ Field,
23357
+ {
23358
+ label: tr(
23359
+ "fluidgrids.builder.nodeSettings.timeoutBranchTarget",
23360
+ "Timeout branch target"
23361
+ ),
23362
+ children: /* @__PURE__ */ jsxs(
23363
+ "select",
23364
+ {
23365
+ value: errorConfig?.timeout?.timeoutBranchId ?? "",
23366
+ onChange: (e) => writeErrorConfig({
23367
+ timeout: {
23368
+ ...errorConfig?.timeout ?? { duration: 3e4 },
23369
+ timeoutBranchId: e.target.value || void 0
23370
+ }
23371
+ }),
23372
+ "data-testid": "ndv-settings-timeout-branch-id",
23373
+ className: cn(inputCx, "max-w-xs"),
23374
+ children: [
23375
+ /* @__PURE__ */ jsx("option", { value: "", children: tr(
23376
+ "fluidgrids.builder.nodeSettings.selectNode",
23377
+ "Select a node\u2026"
23378
+ ) }),
23379
+ branchTargets.map((n) => /* @__PURE__ */ jsx("option", { value: n.id, children: nodeTitle(n) }, n.id))
23380
+ ]
23381
+ }
23382
+ )
23383
+ }
23384
+ )
23385
+ ] })
23386
+ ] }),
23387
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
23388
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL4, children: tr("fluidgrids.builder.nodeSettings.otherSection", "Other") }),
23389
+ /* @__PURE__ */ jsxs("label", { className: "flex w-fit cursor-pointer items-center gap-2 text-sm", children: [
23390
+ /* @__PURE__ */ jsx(
23391
+ "input",
23392
+ {
23393
+ type: "checkbox",
23394
+ checked: alwaysOutputData,
23395
+ onChange: (e) => writeExecutionSettings({ alwaysOutputData: e.target.checked }),
23396
+ "data-testid": "ndv-settings-always-output-data",
23397
+ className: "size-4"
23398
+ }
23399
+ ),
23400
+ /* @__PURE__ */ jsx("span", { children: tr(
23401
+ "fluidgrids.builder.nodeSettings.alwaysOutputDataLabel",
23402
+ "Always output data"
23403
+ ) })
23404
+ ] }),
23405
+ /* @__PURE__ */ jsxs("label", { className: "flex w-fit cursor-pointer items-center gap-2 text-sm", children: [
23406
+ /* @__PURE__ */ jsx(
23407
+ "input",
23408
+ {
23409
+ type: "checkbox",
23410
+ checked: executeOnce,
23411
+ onChange: (e) => writeExecutionSettings({ executeOnce: e.target.checked }),
23412
+ "data-testid": "ndv-settings-execute-once",
23413
+ className: "size-4"
23414
+ }
23415
+ ),
23416
+ /* @__PURE__ */ jsx("span", { children: tr(
23417
+ "fluidgrids.builder.nodeSettings.executeOnceLabel",
23418
+ "Execute once"
23419
+ ) })
23420
+ ] })
23421
+ ] }),
23422
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
23423
+ /* @__PURE__ */ jsx("div", { className: SECTION_LABEL4, children: tr("fluidgrids.builder.nodeSettings.notesSection", "Notes") }),
23424
+ /* @__PURE__ */ jsx(
23425
+ "textarea",
23426
+ {
23427
+ value: notes,
23428
+ onChange: (e) => writeNotes(e.target.value),
23429
+ rows: 4,
23430
+ placeholder: tr(
23431
+ "fluidgrids.builder.nodeSettings.notesPlaceholder",
23432
+ "Leave a note for teammates about what this node does\u2026"
23433
+ ),
23434
+ "data-testid": "ndv-settings-notes",
23435
+ className: cn(inputCx, "resize-y")
23436
+ }
23437
+ )
23438
+ ] })
23439
+ ] });
23440
+ }
23441
+ function Field({
23442
+ label,
23443
+ children
23444
+ }) {
23445
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
23446
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: label }),
23447
+ children
23448
+ ] });
23449
+ }
22590
23450
  function useMediaQuery(query) {
22591
23451
  const [matches, setMatches] = React2.useState(false);
22592
23452
  React2.useEffect(() => {
@@ -22598,7 +23458,7 @@ function useMediaQuery(query) {
22598
23458
  }, [query]);
22599
23459
  return matches;
22600
23460
  }
22601
- var SECTION_LABEL3 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
23461
+ var SECTION_LABEL5 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
22602
23462
  function NodeDetailView() {
22603
23463
  const tr = useTr();
22604
23464
  const ndv = useFlowStore((s) => s.workflow.ndv);
@@ -22754,7 +23614,7 @@ function NodeDetailView() {
22754
23614
  ),
22755
23615
  children: [
22756
23616
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-2.5", children: [
22757
- /* @__PURE__ */ jsx("span", { className: SECTION_LABEL3, children: tr("fluidgrids.builder.nodeDetailView.inputSection", "Input") }),
23617
+ /* @__PURE__ */ jsx("span", { className: SECTION_LABEL5, children: tr("fluidgrids.builder.nodeDetailView.inputSection", "Input") }),
22758
23618
  sourceIds.length > 0 && /* @__PURE__ */ jsx(
22759
23619
  "select",
22760
23620
  {
@@ -22843,10 +23703,14 @@ function NodeDetailView() {
22843
23703
  }
22844
23704
  )
22845
23705
  }
22846
- ) : /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto p-4 text-xs text-muted-foreground", children: tr(
22847
- "fluidgrids.builder.nodeDetailView.noSettings",
22848
- "No additional settings for this node."
22849
- ) })
23706
+ ) : /* @__PURE__ */ jsx(
23707
+ "div",
23708
+ {
23709
+ className: "min-h-0 flex-1 overflow-auto p-4",
23710
+ "data-testid": "ndv-settings",
23711
+ children: /* @__PURE__ */ jsx(NodeSettingsPanel, { config: config2 })
23712
+ }
23713
+ )
22850
23714
  ]
22851
23715
  }
22852
23716
  ),
@@ -22861,7 +23725,7 @@ function NodeDetailView() {
22861
23725
  ),
22862
23726
  children: [
22863
23727
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-2.5", children: [
22864
- /* @__PURE__ */ jsx("span", { className: SECTION_LABEL3, children: tr(
23728
+ /* @__PURE__ */ jsx("span", { className: SECTION_LABEL5, children: tr(
22865
23729
  "fluidgrids.builder.nodeDetailView.outputSection",
22866
23730
  "Output"
22867
23731
  ) }),
@@ -24347,5 +25211,5 @@ var FlowBuilderPage = ({
24347
25211
  };
24348
25212
 
24349
25213
  export { Card2 as Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ConnectionFormDialog, ConnectionSelector, EntityTagPicker, FLUIDGRIDS_ENTITY_TYPES, FlowBuilderPage, FluidGridsProvider, ProviderPicker, SchemaConnectionForm, ScopePicker, TemplateCard, buildNodeCheck, buildRequiredNodeTypes, listCustomBlocks, mergeStickyNotes, refetchStoreNodes, registerCustomBlock, resolveUiSpec, stripSubmitActions, tagLabel, useAvailableTags, useConnection, useConnectionDialog, useConnections, useConnectionsByProvider, useCreateConnection, useCreateTag, useDraftEntityTags, useEntityTags, useFluidGridsContext, useImportWorkflowTemplate, useInitiateOAuth, useInstalledNodes, useNodeExecution, useProviderByKey, useProviderCatalog, useProviders, useReplaceEntityTags, useSearchTags, useTagEntity, useUntagEntity, useWorkflowTemplates };
24350
- //# sourceMappingURL=chunk-OGPTQCB6.js.map
24351
- //# sourceMappingURL=chunk-OGPTQCB6.js.map
25214
+ //# sourceMappingURL=chunk-VTKT6XDA.js.map
25215
+ //# sourceMappingURL=chunk-VTKT6XDA.js.map