@burdenoff/fluidgrids-fe-sdk 2026.925.2 → 2026.930.1

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-RK3KJ46E.js +12 -0
  2. package/dist/{ExecutionDetailPage-3ZJMNWBY.js.map → ExecutionDetailPage-RK3KJ46E.js.map} +1 -1
  3. package/dist/ExecutionsListPage-NXINADRN.js +11 -0
  4. package/dist/{ExecutionsListPage-FPNETFQX.js.map → ExecutionsListPage-NXINADRN.js.map} +1 -1
  5. package/dist/{WorkflowBuilder-IS2ZZ6JY.js → WorkflowBuilder-MAFYHWGY.js} +7 -7
  6. package/dist/{WorkflowBuilder-IS2ZZ6JY.js.map → WorkflowBuilder-MAFYHWGY.js.map} +1 -1
  7. package/dist/WorkflowsList-AFTTUUHX.js +13 -0
  8. package/dist/{WorkflowsList-GEPG3OZ6.js.map → WorkflowsList-AFTTUUHX.js.map} +1 -1
  9. package/dist/{chunk-UBKJDGYS.js → chunk-3P4YQ7DO.js} +57 -3
  10. package/dist/chunk-3P4YQ7DO.js.map +1 -0
  11. package/dist/chunk-5OZB7AQ4.js +9878 -0
  12. package/dist/chunk-5OZB7AQ4.js.map +1 -0
  13. package/dist/{chunk-A6PDDUMN.js → chunk-7SX5OWZR.js} +4 -4
  14. package/dist/{chunk-A6PDDUMN.js.map → chunk-7SX5OWZR.js.map} +1 -1
  15. package/dist/{chunk-QV6T4R4T.js → chunk-G3RPRMP5.js} +3 -3
  16. package/dist/{chunk-QV6T4R4T.js.map → chunk-G3RPRMP5.js.map} +1 -1
  17. package/dist/{chunk-H5LGKSBM.js → chunk-GKSXZFDY.js} +3 -3
  18. package/dist/{chunk-H5LGKSBM.js.map → chunk-GKSXZFDY.js.map} +1 -1
  19. package/dist/{chunk-ZZ3SFJXV.js → chunk-IJSJOTIZ.js} +4 -4
  20. package/dist/{chunk-ZZ3SFJXV.js.map → chunk-IJSJOTIZ.js.map} +1 -1
  21. package/dist/{chunk-T7FJ2TBD.js → chunk-NHZQE7ZB.js} +4 -4
  22. package/dist/{chunk-T7FJ2TBD.js.map → chunk-NHZQE7ZB.js.map} +1 -1
  23. package/dist/{chunk-YMD3T6J2.js → chunk-NTJTPYCD.js} +37 -4
  24. package/dist/chunk-NTJTPYCD.js.map +1 -0
  25. package/dist/{chunk-6DQDX6LD.js → chunk-ODOEVG2G.js} +5 -5
  26. package/dist/{chunk-6DQDX6LD.js.map → chunk-ODOEVG2G.js.map} +1 -1
  27. package/dist/{chunk-IOP2IBDV.js → chunk-R5ZYOIZG.js} +4 -4
  28. package/dist/{chunk-IOP2IBDV.js.map → chunk-R5ZYOIZG.js.map} +1 -1
  29. package/dist/{chunk-CGQG3QUR.js → chunk-T4BFEI3I.js} +5 -5
  30. package/dist/{chunk-CGQG3QUR.js.map → chunk-T4BFEI3I.js.map} +1 -1
  31. package/dist/{chunk-O4UTOCZJ.js → chunk-USFSPC6S.js} +3 -3
  32. package/dist/{chunk-O4UTOCZJ.js.map → chunk-USFSPC6S.js.map} +1 -1
  33. package/dist/{chunk-6SXISR7B.js → chunk-VG2BTLUN.js} +600 -93
  34. package/dist/chunk-VG2BTLUN.js.map +1 -0
  35. package/dist/{chunk-YQ4GDK4I.js → chunk-ZLYJKIKG.js} +3 -3
  36. package/dist/{chunk-YQ4GDK4I.js.map → chunk-ZLYJKIKG.js.map} +1 -1
  37. package/dist/executions.js +5 -5
  38. package/dist/history.js +3 -3
  39. package/dist/index.d.ts +82113 -35336
  40. package/dist/index.js +20 -20
  41. package/dist/index.js.map +1 -1
  42. package/dist/nodes.js +2 -2
  43. package/dist/settings.js +3 -3
  44. package/dist/templates.js +5 -5
  45. package/dist/{workflow-builder-Y7PcoT2O.d.ts → workflow-builder-DqInt43T.d.ts} +31 -2
  46. package/dist/workflow-builder.d.ts +1 -1
  47. package/dist/workflow-builder.js +6 -6
  48. package/dist/workflows-list.js +4 -4
  49. package/package.json +1 -1
  50. package/dist/ExecutionDetailPage-3ZJMNWBY.js +0 -12
  51. package/dist/ExecutionsListPage-FPNETFQX.js +0 -11
  52. package/dist/WorkflowsList-GEPG3OZ6.js +0 -13
  53. package/dist/chunk-6SXISR7B.js.map +0 -1
  54. package/dist/chunk-HCL5CCLH.js +0 -4940
  55. package/dist/chunk-HCL5CCLH.js.map +0 -1
  56. package/dist/chunk-UBKJDGYS.js.map +0 -1
  57. package/dist/chunk-YMD3T6J2.js.map +0 -1
@@ -7,10 +7,10 @@ import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, Instal
7
7
  import { QuotaExhaustedDialog } from './chunk-AANIWER2.js';
8
8
  import { SdkPermissionGate, FLUIDGRIDS_PERMISSIONS, SdkPermissionButton } from './chunk-W23ZXNKU.js';
9
9
  import { cn as cn$1 } from './chunk-3ZYUGTIT.js';
10
- import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-H5LGKSBM.js';
10
+ import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-GKSXZFDY.js';
11
11
  import { config, getFluidGridsConfig, validateTrustedOrigin, setFluidGridsConfig, resetFluidGridsConfig } from './chunk-U4AJLVHA.js';
12
- import { useFlowStore } from './chunk-YMD3T6J2.js';
13
- import { NodeEndpointConfigsDocument, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowRunDocument, FluidgridsEntityTagsDocument, AvailableFluidgridsTagsDocument, SearchFluidgridsTagsDocument, TagFluidgridsEntityDocument, UntagFluidgridsEntityDocument, ReplaceFluidgridsEntityTagsDocument, CreateFluidgridsTagDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, EventRegistrationsDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-UBKJDGYS.js';
12
+ import { useFlowStore } from './chunk-NTJTPYCD.js';
13
+ import { NodeEndpointConfigsDocument, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowRunDocument, FluidgridsEntityTagsDocument, AvailableFluidgridsTagsDocument, SearchFluidgridsTagsDocument, TagFluidgridsEntityDocument, UntagFluidgridsEntityDocument, ReplaceFluidgridsEntityTagsDocument, CreateFluidgridsTagDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-3P4YQ7DO.js';
14
14
  import { throwIfResultError, describeOperationError } from './chunk-LMO5ASOE.js';
15
15
  import { useTr, FluidGridsTranslationProvider, ENGLISH_FALLBACK_TRANSLATOR } from './chunk-7YWBH2A5.js';
16
16
  import { waitForFluidGridsClient, getFluidGridsClient, getFluidGridsClientSafe, createFluidGridsClient, setFluidGridsClient, resetFluidGridsClient } from './chunk-5BDQNSP3.js';
@@ -3601,6 +3601,7 @@ function ConnectionSelector({
3601
3601
  ] });
3602
3602
  }
3603
3603
  var TRIGGER_WORKFLOW = TriggerWorkflowDocument;
3604
+ var EXECUTE_STEP = ExecuteStepDocument;
3604
3605
  var WORKFLOW_RUN = WorkflowRunDocument;
3605
3606
  var RUN_FROM_NODE = RunFromNodeDocument;
3606
3607
  var EXECUTION_DETAIL = ExecutionDetailDocument;
@@ -3640,6 +3641,10 @@ function useNodeExecution() {
3640
3641
  const startExecution = useFlowStore(
3641
3642
  (s) => s.actions.execution.startExecution
3642
3643
  );
3644
+ const setRunMetadata = useFlowStore(
3645
+ (s) => s.actions.execution.setRunMetadata
3646
+ );
3647
+ const setStepPlan = useFlowStore((s) => s.actions.execution.setStepPlan);
3643
3648
  const addLog = useFlowStore((s) => s.actions.execution.addLog);
3644
3649
  const updateLog = useFlowStore((s) => s.actions.execution.updateLog);
3645
3650
  const setNodeStatus = useFlowStore((s) => s.actions.execution.setNodeStatus);
@@ -3803,6 +3808,11 @@ function useNodeExecution() {
3803
3808
  }
3804
3809
  return;
3805
3810
  }
3811
+ setRunMetadata({
3812
+ runId,
3813
+ workflowKey: run.workflowKey,
3814
+ version: run.version
3815
+ });
3806
3816
  if (run.nodeStates?.length) {
3807
3817
  processNodeStates(runId, run.nodeStates);
3808
3818
  }
@@ -3822,60 +3832,56 @@ function useNodeExecution() {
3822
3832
  };
3823
3833
  pollTimerRef.current = setTimeout(doPoll, 800);
3824
3834
  },
3825
- [processNodeStates, completeExecution, cleanup]
3835
+ [processNodeStates, completeExecution, cleanup, setRunMetadata]
3826
3836
  );
3827
- const executeNode = useCallback(
3828
- async (stopAtNodeId) => {
3829
- const triggerNode = findTriggerNode();
3830
- if (!triggerNode) {
3831
- console.error("[useNodeExecution] No trigger node found in workflow");
3832
- return { success: false, error: "No trigger node found" };
3833
- }
3837
+ const executeStep = useCallback(
3838
+ async (nodeId) => {
3834
3839
  cleanup();
3835
3840
  clearLogs();
3836
3841
  const workflowKey = workflow.workflowKey || workflow.id;
3837
3842
  const version = workflow.version || "1.0.0";
3838
3843
  if (!workflowKey) {
3839
3844
  console.error(
3840
- "[useNodeExecution] Workflow must be saved before execution. No workflowKey found."
3845
+ "[useNodeExecution] Workflow must be saved before step execution. No workflowKey found."
3841
3846
  );
3842
3847
  return {
3843
3848
  success: false,
3844
3849
  error: "Workflow must be saved before execution"
3845
3850
  };
3846
3851
  }
3847
- setNodeStatus(stopAtNodeId, "running");
3852
+ setNodeStatus(nodeId, "running");
3848
3853
  try {
3849
3854
  const client = getFluidGridsClient();
3850
3855
  const result = throwIfResultError(
3851
3856
  await client.mutate({
3852
- mutation: TRIGGER_WORKFLOW,
3857
+ mutation: EXECUTE_STEP,
3853
3858
  variables: {
3854
3859
  input: {
3855
3860
  workflowKey,
3856
3861
  version,
3857
- triggerNodeId: triggerNode.id,
3858
- triggerData: {},
3859
- context: {},
3860
- stopAtNodeId,
3861
- // Step execution from the builder is always a manual/debug
3862
- // run (BOFF-7511) — pinned node data only ever applies here,
3863
- // never on a PRODUCTION trigger (webhook, schedule, API).
3864
- mode: "TEST"
3862
+ nodeId
3865
3863
  }
3866
3864
  }
3867
3865
  })
3868
3866
  );
3869
- const triggerResult = result.data?.triggerWorkflow;
3870
- if (triggerResult) {
3871
- const backendRunId = triggerResult.runId;
3872
- startExecution(stopAtNodeId, backendRunId);
3867
+ const stepResult = result.data?.executeStep;
3868
+ if (stepResult) {
3869
+ const backendRunId = stepResult.runId;
3870
+ startExecution(nodeId, backendRunId, {
3871
+ workflowKey: stepResult.workflowKey,
3872
+ version: stepResult.version
3873
+ });
3874
+ setStepPlan({
3875
+ runId: backendRunId,
3876
+ ...stepResult.plan,
3877
+ sourceRunId: stepResult.plan.sourceRunId ?? null
3878
+ });
3873
3879
  const initialLog = {
3874
- id: `${backendRunId}-${stopAtNodeId}`,
3880
+ id: `${backendRunId}-${nodeId}`,
3875
3881
  runId: backendRunId,
3876
- nodeId: stopAtNodeId,
3877
- nodeType: workflow.nodes.find((n) => n.id === stopAtNodeId)?.type || "unknown",
3878
- nodeName: getNodeName(stopAtNodeId),
3882
+ nodeId,
3883
+ nodeType: workflow.nodes.find((node) => node.id === nodeId)?.type || "unknown",
3884
+ nodeName: getNodeName(nodeId),
3879
3885
  status: "running",
3880
3886
  inputArgs: null,
3881
3887
  output: null,
@@ -3886,21 +3892,21 @@ function useNodeExecution() {
3886
3892
  };
3887
3893
  addLog(initialLog);
3888
3894
  pollRunUpdates(backendRunId);
3889
- return { success: true, runId: backendRunId };
3895
+ return { success: true, runId: backendRunId, plan: stepResult.plan };
3890
3896
  }
3891
- console.error("[useNodeExecution] No result from trigger");
3892
- setNodeStatus(stopAtNodeId, "error");
3893
- return { success: false, error: "No result from trigger" };
3897
+ console.error("[useNodeExecution] No result from executeStep");
3898
+ setNodeStatus(nodeId, "error");
3899
+ return { success: false, error: "No result from executeStep" };
3894
3900
  } catch (error) {
3895
- console.error("[useNodeExecution] Error triggering workflow:", error);
3901
+ console.error("[useNodeExecution] Error executing step:", error);
3896
3902
  const errorMessage = describeOperationError(error);
3897
3903
  const errorRunId = nanoid$1();
3898
3904
  const errorLog = {
3899
- id: `${errorRunId}-${stopAtNodeId}`,
3905
+ id: `${errorRunId}-${nodeId}`,
3900
3906
  runId: errorRunId,
3901
- nodeId: stopAtNodeId,
3902
- nodeType: workflow.nodes.find((n) => n.id === stopAtNodeId)?.type || "unknown",
3903
- nodeName: getNodeName(stopAtNodeId),
3907
+ nodeId,
3908
+ nodeType: workflow.nodes.find((node) => node.id === nodeId)?.type || "unknown",
3909
+ nodeName: getNodeName(nodeId),
3904
3910
  status: "failed",
3905
3911
  inputArgs: null,
3906
3912
  output: null,
@@ -3910,16 +3916,16 @@ function useNodeExecution() {
3910
3916
  endTime: (/* @__PURE__ */ new Date()).toISOString()
3911
3917
  };
3912
3918
  addLog(errorLog);
3913
- setNodeStatus(stopAtNodeId, "error");
3919
+ setNodeStatus(nodeId, "error");
3914
3920
  completeExecution();
3915
3921
  return { success: false, error: errorMessage };
3916
3922
  }
3917
3923
  },
3918
3924
  [
3919
- findTriggerNode,
3920
3925
  cleanup,
3921
3926
  clearLogs,
3922
3927
  startExecution,
3928
+ setStepPlan,
3923
3929
  workflow,
3924
3930
  getNodeName,
3925
3931
  addLog,
@@ -3961,8 +3967,9 @@ function useNodeExecution() {
3961
3967
  triggerNodeId: triggerNode.id,
3962
3968
  triggerData: customTriggerData || {},
3963
3969
  context: {},
3964
- // Builder "Test workflow" is always a manual/debug run
3965
- // (BOFF-7511) — see the note on executeNode above.
3970
+ // Builder "Test workflow" is always a manual/debug run.
3971
+ // Pinned node data only applies to TEST executions, never a
3972
+ // production trigger (webhook, schedule, API).
3966
3973
  mode: "TEST"
3967
3974
  }
3968
3975
  }
@@ -3971,7 +3978,10 @@ function useNodeExecution() {
3971
3978
  const triggerResult = result.data?.triggerWorkflow;
3972
3979
  if (triggerResult) {
3973
3980
  const backendRunId = triggerResult.runId;
3974
- startExecution(triggerNode.id, backendRunId);
3981
+ startExecution(triggerNode.id, backendRunId, {
3982
+ workflowKey: triggerResult.workflowKey,
3983
+ version: triggerResult.version
3984
+ });
3975
3985
  pollRunUpdates(backendRunId);
3976
3986
  return { success: true, runId: backendRunId };
3977
3987
  }
@@ -4030,7 +4040,7 @@ function useNodeExecution() {
4030
4040
  sourceRunId,
4031
4041
  nodeId,
4032
4042
  // Run-from-node is a debug affordance — always TEST, same
4033
- // rule as executeNode/executeFullWorkflow above.
4043
+ // rule as the other builder debug execution paths.
4034
4044
  mode: "TEST"
4035
4045
  }
4036
4046
  }
@@ -4039,7 +4049,10 @@ function useNodeExecution() {
4039
4049
  const runFromNodeResult = result.data?.runFromNode;
4040
4050
  if (runFromNodeResult) {
4041
4051
  const backendRunId = runFromNodeResult.runId;
4042
- startExecution(nodeId, backendRunId);
4052
+ startExecution(nodeId, backendRunId, {
4053
+ workflowKey: runFromNodeResult.workflowKey,
4054
+ version: runFromNodeResult.version
4055
+ });
4043
4056
  pollRunUpdates(backendRunId);
4044
4057
  return { success: true, runId: backendRunId };
4045
4058
  }
@@ -4099,7 +4112,10 @@ function useNodeExecution() {
4099
4112
  reusedFromRunId: nodeState.reusedFromRunId ?? null
4100
4113
  };
4101
4114
  });
4102
- loadDebugRun(runId, logs);
4115
+ loadDebugRun(runId, logs, {
4116
+ workflowKey: run.workflowKey,
4117
+ version: run.version
4118
+ });
4103
4119
  return { success: true, runId };
4104
4120
  } catch (error) {
4105
4121
  console.error("[useNodeExecution] Error loading execution:", error);
@@ -4117,7 +4133,7 @@ function useNodeExecution() {
4117
4133
  };
4118
4134
  }, [cleanup, completeExecution]);
4119
4135
  return {
4120
- executeNode,
4136
+ executeStep,
4121
4137
  executeFullWorkflow,
4122
4138
  executeFromNode,
4123
4139
  loadExecution,
@@ -6665,7 +6681,7 @@ var getNodeMetadata = (value) => {
6665
6681
  return updated;
6666
6682
  });
6667
6683
  }, [nodeType, id, edges, data, setNodes, zustandSetNodes]);
6668
- const { executeNode } = useNodeExecution();
6684
+ const { executeStep } = useNodeExecution();
6669
6685
  const deleteNode = useDeleteNode();
6670
6686
  const handleDeleteNode = () => {
6671
6687
  deleteNode(id);
@@ -6723,11 +6739,11 @@ var getNodeMetadata = (value) => {
6723
6739
  openNdv({ nodeId: id, type: value?.type });
6724
6740
  }, [id, openNdv]);
6725
6741
  const handleExecuteStep = useCallback(() => {
6726
- executeNode(id).then((_result) => {
6742
+ executeStep(id).then((_result) => {
6727
6743
  }).catch((error) => {
6728
- console.error("[NodeComponent] Execute error:", error);
6744
+ console.error("[NodeComponent] Execute step error:", error);
6729
6745
  });
6730
- }, [executeNode, id]);
6746
+ }, [executeStep, id]);
6731
6747
  const missingCredentials = useMemo(() => {
6732
6748
  const visibleAdapters = getVisibleConnectionAdapters(
6733
6749
  String(value?.type ?? ""),
@@ -23831,6 +23847,335 @@ function useMediaQuery(query) {
23831
23847
  }, [query]);
23832
23848
  return matches;
23833
23849
  }
23850
+
23851
+ // src/builder/lib/continuation.ts
23852
+ var BLOCKED = {
23853
+ eligible: false,
23854
+ action: null,
23855
+ blockers: [],
23856
+ blockerReason: null,
23857
+ reason: null
23858
+ };
23859
+ function blocked(blockerReason, reason, blockers = [], targetStatus = null) {
23860
+ return {
23861
+ ...BLOCKED,
23862
+ targetStatus,
23863
+ blockerReason,
23864
+ blockers,
23865
+ reason
23866
+ };
23867
+ }
23868
+ function sourceMetadata(input) {
23869
+ const source = input.sourceRun;
23870
+ return {
23871
+ runId: source?.runId ?? input.sourceRunId ?? null,
23872
+ workflowKey: source?.workflowKey ?? input.sourceRunWorkflowKey ?? null,
23873
+ version: source?.version ?? source?.workflowVersion ?? input.sourceRunVersion ?? null
23874
+ };
23875
+ }
23876
+ function getContinuationEligibility(input) {
23877
+ const source = sourceMetadata(input);
23878
+ if (!source.runId) {
23879
+ return blocked(
23880
+ "missing-source-run",
23881
+ "Load a completed or failed run before continuing from this node."
23882
+ );
23883
+ }
23884
+ if (!source.workflowKey || !source.version || source.workflowKey !== input.workflowKey || source.version !== input.workflowVersion) {
23885
+ return blocked(
23886
+ "incompatible-source-run",
23887
+ "The selected run belongs to a different workflow version."
23888
+ );
23889
+ }
23890
+ const nodeIds = new Set(input.nodes.map((node) => node.id));
23891
+ if (!nodeIds.has(input.targetNodeId)) {
23892
+ return blocked(
23893
+ "missing-target",
23894
+ "The selected node is not present in this workflow.",
23895
+ [input.targetNodeId]
23896
+ );
23897
+ }
23898
+ const logsByNode = /* @__PURE__ */ new Map();
23899
+ for (const log of input.logs) {
23900
+ if (log.runId === source.runId) logsByNode.set(log.nodeId, log);
23901
+ }
23902
+ const targetLog = logsByNode.get(input.targetNodeId);
23903
+ const targetStatus = targetLog?.status?.toLowerCase() ?? null;
23904
+ const action = targetStatus === "failed" ? "retry" : targetStatus === null || targetStatus === "completed" ? "continue" : null;
23905
+ if (!action) {
23906
+ return blocked(
23907
+ "target-not-terminal",
23908
+ "Continue is available only for completed or failed nodes.",
23909
+ [input.targetNodeId],
23910
+ targetStatus
23911
+ );
23912
+ }
23913
+ const predecessors = /* @__PURE__ */ new Map();
23914
+ for (const edge of input.edges) {
23915
+ const parents = predecessors.get(edge.target) ?? [];
23916
+ if (!parents.includes(edge.source)) parents.push(edge.source);
23917
+ predecessors.set(edge.target, parents);
23918
+ }
23919
+ const ancestors = /* @__PURE__ */ new Set();
23920
+ const cycleNodes = /* @__PURE__ */ new Set();
23921
+ const visiting = /* @__PURE__ */ new Set([input.targetNodeId]);
23922
+ const visited = /* @__PURE__ */ new Set();
23923
+ const visitAncestor = (nodeId) => {
23924
+ if (visiting.has(nodeId)) {
23925
+ cycleNodes.add(nodeId);
23926
+ return;
23927
+ }
23928
+ if (visited.has(nodeId)) return;
23929
+ ancestors.add(nodeId);
23930
+ visiting.add(nodeId);
23931
+ for (const parentId of predecessors.get(nodeId) ?? []) {
23932
+ visitAncestor(parentId);
23933
+ }
23934
+ visiting.delete(nodeId);
23935
+ visited.add(nodeId);
23936
+ };
23937
+ for (const parentId of predecessors.get(input.targetNodeId) ?? []) {
23938
+ visitAncestor(parentId);
23939
+ }
23940
+ if (cycleNodes.size > 0) {
23941
+ return blocked(
23942
+ "cycle",
23943
+ "This workflow has a cycle upstream of the selected node, so continuation is disabled.",
23944
+ [...cycleNodes].sort(),
23945
+ targetStatus
23946
+ );
23947
+ }
23948
+ for (const ancestorId of ancestors) {
23949
+ if (!nodeIds.has(ancestorId) || !logsByNode.has(ancestorId)) {
23950
+ return blocked(
23951
+ "missing-ancestor-log",
23952
+ "Every upstream node must have a result in the selected run.",
23953
+ [ancestorId],
23954
+ targetStatus
23955
+ );
23956
+ }
23957
+ const ancestor = logsByNode.get(ancestorId);
23958
+ if (ancestor?.status.toLowerCase() !== "completed") {
23959
+ return blocked(
23960
+ "ancestor-not-completed",
23961
+ "Every upstream node must be completed before continuing.",
23962
+ [ancestorId],
23963
+ targetStatus
23964
+ );
23965
+ }
23966
+ if (ancestor.output == null) {
23967
+ return blocked(
23968
+ "ancestor-missing-output",
23969
+ "Every completed upstream node must have output data before continuing.",
23970
+ [ancestorId],
23971
+ targetStatus
23972
+ );
23973
+ }
23974
+ }
23975
+ return {
23976
+ eligible: true,
23977
+ action,
23978
+ targetStatus,
23979
+ blockers: [],
23980
+ blockerReason: null,
23981
+ reason: null
23982
+ };
23983
+ }
23984
+ function NodeExecutionActions({
23985
+ targetNodeId,
23986
+ nodes,
23987
+ edges,
23988
+ logs,
23989
+ workflowKey,
23990
+ workflowVersion,
23991
+ sourceRun,
23992
+ onExecuteStep,
23993
+ onContinueFromNode,
23994
+ isExecuting = false,
23995
+ className,
23996
+ testIdPrefix = "node-execution"
23997
+ }) {
23998
+ const tr = useTr();
23999
+ const [pendingAction, setPendingAction] = useState(null);
24000
+ const localEligibility = useMemo(
24001
+ () => getContinuationEligibility({
24002
+ nodes,
24003
+ edges,
24004
+ logs,
24005
+ targetNodeId,
24006
+ workflowKey,
24007
+ workflowVersion,
24008
+ sourceRun
24009
+ }),
24010
+ [nodes, edges, logs, targetNodeId, workflowKey, workflowVersion, sourceRun]
24011
+ );
24012
+ const queryIdentity = `${sourceRun?.runId ?? ""}:${targetNodeId}`;
24013
+ const sourceStateVersion = useMemo(
24014
+ () => logs.filter((log) => !sourceRun || log.runId === sourceRun.runId).map(
24015
+ (log) => `${log.nodeId}:${log.status}:${log.output == null ? "empty" : "ready"}`
24016
+ ).sort().join("|"),
24017
+ [logs, sourceRun]
24018
+ );
24019
+ const queryIdentityRef = useRef(queryIdentity);
24020
+ const {
24021
+ data: eligibilityData,
24022
+ loading: eligibilityLoading,
24023
+ error: eligibilityError,
24024
+ refetch: refetchEligibility
24025
+ } = useRunFromNodeEligibilityQuery({
24026
+ variables: {
24027
+ input: {
24028
+ sourceRunId: sourceRun?.runId ?? "",
24029
+ nodeId: targetNodeId
24030
+ }
24031
+ },
24032
+ skip: !sourceRun,
24033
+ fetchPolicy: "network-only",
24034
+ nextFetchPolicy: "network-only"
24035
+ });
24036
+ useEffect(() => {
24037
+ if (!sourceRun) {
24038
+ queryIdentityRef.current = queryIdentity;
24039
+ return;
24040
+ }
24041
+ if (queryIdentityRef.current !== queryIdentity) {
24042
+ queryIdentityRef.current = queryIdentity;
24043
+ return;
24044
+ }
24045
+ void refetchEligibility();
24046
+ }, [queryIdentity, refetchEligibility, sourceRun?.runId, sourceStateVersion]);
24047
+ const serverEligibility = sourceRun && !eligibilityLoading && !eligibilityError && eligibilityData?.runFromNodeEligibility ? (() => {
24048
+ const result = eligibilityData.runFromNodeEligibility;
24049
+ const targetStatus = result.targetStatus?.toLowerCase() ?? null;
24050
+ return {
24051
+ eligible: result.eligible,
24052
+ action: targetStatus === "failed" ? "retry" : result.eligible ? "continue" : null,
24053
+ targetStatus,
24054
+ blockers: result.blockedNodeIds.length ? result.blockedNodeIds : result.blockers,
24055
+ blockerReason: null,
24056
+ reason: result.reason ?? null
24057
+ };
24058
+ })() : null;
24059
+ const eligibility = sourceRun ? serverEligibility ?? {
24060
+ eligible: false,
24061
+ action: null,
24062
+ reason: eligibilityError ? tr(
24063
+ "fluidgrids.builder.nodeExecutionActions.queryError",
24064
+ "Unable to verify continuation readiness. Try loading the run again."
24065
+ ) : tr(
24066
+ "fluidgrids.builder.nodeExecutionActions.checking",
24067
+ "Checking continuation readiness\u2026"
24068
+ )
24069
+ } : localEligibility;
24070
+ const runAction = async (action, callback) => {
24071
+ setPendingAction(action);
24072
+ try {
24073
+ await callback();
24074
+ } finally {
24075
+ setPendingAction(null);
24076
+ }
24077
+ };
24078
+ const executePending = pendingAction === "execute" || isExecuting;
24079
+ const continuePending = pendingAction === "continue";
24080
+ const continuationLabel = eligibility.action === "retry" ? tr(
24081
+ "fluidgrids.builder.nodeExecutionActions.retryFromHere",
24082
+ "Retry from here"
24083
+ ) : tr(
24084
+ "fluidgrids.builder.nodeExecutionActions.continueFromHere",
24085
+ "Continue from here"
24086
+ );
24087
+ const blockerLabel = eligibility.reason ? tr(
24088
+ "fluidgrids.builder.nodeExecutionActions.blocked",
24089
+ "Unavailable: {{reason}}",
24090
+ { reason: eligibility.reason }
24091
+ ) : tr(
24092
+ "fluidgrids.builder.nodeExecutionActions.noSourceRun",
24093
+ "Load a run to enable continuation."
24094
+ );
24095
+ return /* @__PURE__ */ jsxs(
24096
+ "section",
24097
+ {
24098
+ className: cn(
24099
+ "shrink-0 border-t border-border bg-muted/20 px-3 py-2",
24100
+ className
24101
+ ),
24102
+ "aria-label": tr(
24103
+ "fluidgrids.builder.nodeExecutionActions.ariaLabel",
24104
+ "Node execution actions"
24105
+ ),
24106
+ "data-testid": `${testIdPrefix}-execution-actions`,
24107
+ children: [
24108
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
24109
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: tr("fluidgrids.builder.nodeExecutionActions.heading", "Execution") }),
24110
+ /* @__PURE__ */ jsxs(
24111
+ "button",
24112
+ {
24113
+ type: "button",
24114
+ onClick: () => {
24115
+ void runAction("execute", () => onExecuteStep(targetNodeId));
24116
+ },
24117
+ disabled: executePending || continuePending,
24118
+ title: tr(
24119
+ "fluidgrids.builder.nodeExecutionActions.executeStepHint",
24120
+ "Run only this node as a fresh TEST execution."
24121
+ ),
24122
+ className: "inline-flex items-center gap-1 rounded-md border border-border bg-background px-2 py-1 text-xs font-medium text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
24123
+ "data-testid": `${testIdPrefix}-execute-step`,
24124
+ children: [
24125
+ /* @__PURE__ */ jsx(
24126
+ Icon,
24127
+ {
24128
+ icon: executePending ? "svg-spinners:ring-resize" : "mdi:play",
24129
+ className: "size-3.5"
24130
+ }
24131
+ ),
24132
+ tr(
24133
+ "fluidgrids.builder.nodeExecutionActions.executeStep",
24134
+ "Execute step"
24135
+ )
24136
+ ]
24137
+ }
24138
+ ),
24139
+ /* @__PURE__ */ jsxs(
24140
+ "button",
24141
+ {
24142
+ type: "button",
24143
+ onClick: () => {
24144
+ if (!eligibility.eligible || !sourceRun) return;
24145
+ void runAction(
24146
+ "continue",
24147
+ () => onContinueFromNode(sourceRun.runId, targetNodeId)
24148
+ );
24149
+ },
24150
+ disabled: !eligibility.eligible || !sourceRun || executePending || continuePending,
24151
+ title: eligibility.eligible ? continuationLabel : blockerLabel,
24152
+ className: "inline-flex items-center gap-1 rounded-md border border-primary/30 bg-primary/5 px-2 py-1 text-xs font-medium text-primary transition-colors hover:bg-primary/10 disabled:cursor-not-allowed disabled:opacity-50",
24153
+ "data-testid": `${testIdPrefix}-continue-from-here`,
24154
+ children: [
24155
+ /* @__PURE__ */ jsx(
24156
+ Icon,
24157
+ {
24158
+ icon: continuePending ? "svg-spinners:ring-resize" : "mdi:skip-forward",
24159
+ className: "size-3.5"
24160
+ }
24161
+ ),
24162
+ continuePending ? tr("fluidgrids.builder.nodeExecutionActions.running", "Running\u2026") : continuationLabel
24163
+ ]
24164
+ }
24165
+ )
24166
+ ] }),
24167
+ !eligibility.eligible && /* @__PURE__ */ jsx(
24168
+ "p",
24169
+ {
24170
+ className: "mt-1 text-[10px] leading-snug text-muted-foreground",
24171
+ "data-testid": `${testIdPrefix}-continuation-blocker`,
24172
+ children: blockerLabel
24173
+ }
24174
+ )
24175
+ ]
24176
+ }
24177
+ );
24178
+ }
23834
24179
  var SECTION_LABEL5 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
23835
24180
  function NodeDetailView() {
23836
24181
  const tr = useTr();
@@ -23856,11 +24201,20 @@ function NodeDetailView() {
23856
24201
  const [inputView, setInputView] = useState("schema");
23857
24202
  const executionLogs = useFlowStore((s) => s.execution.logs);
23858
24203
  const currentRunId = useFlowStore((s) => s.execution.currentRunId);
24204
+ const sourceRun = useFlowStore((s) => s.execution.sourceRun);
24205
+ const isExecuting = useFlowStore((s) => s.execution.isExecuting);
24206
+ const workflowNodes = useFlowStore((s) => s.workflow.nodes);
24207
+ const workflowEdges = useFlowStore((s) => s.workflow.edges);
24208
+ const workflowKey = useFlowStore((s) => s.workflow.workflowKey);
24209
+ const workflowId = useFlowStore((s) => s.workflow.id);
24210
+ const workflowVersion = useFlowStore((s) => s.workflow.version);
24211
+ const stepPlan = useFlowStore((s) => s.execution.stepPlan);
23859
24212
  const nodeLog = useMemo(() => {
23860
24213
  if (!ndv?.nodeId) return null;
23861
24214
  const matches = executionLogs.filter((l) => l.nodeId === ndv.nodeId);
23862
24215
  return matches.length > 0 ? matches[matches.length - 1] : null;
23863
24216
  }, [executionLogs, ndv?.nodeId]);
24217
+ const stepPlanForNode = stepPlan?.runId === currentRunId && stepPlan.targetNodeId === ndv?.nodeId ? stepPlan : null;
23864
24218
  const hasRealOutput = !!nodeLog?.output && Object.keys(nodeLog.output).length > 0;
23865
24219
  const hasRealInput = !!nodeLog?.inputArgs && Object.keys(nodeLog.inputArgs).length > 0;
23866
24220
  const realOutputFields = useMemo(
@@ -23899,18 +24253,7 @@ function NodeDetailView() {
23899
24253
  console.error("[NodeDetailView] Failed to toggle pinned data", err);
23900
24254
  }
23901
24255
  };
23902
- const { executeFromNode } = useNodeExecution();
23903
- const [runningFromHere, setRunningFromHere] = useState(false);
23904
- const canRunFromHere = !!currentRunId && nodeLog?.status === "completed";
23905
- const runFromHere = async () => {
23906
- if (!currentRunId || !ndv?.nodeId) return;
23907
- setRunningFromHere(true);
23908
- try {
23909
- await executeFromNode(currentRunId, ndv.nodeId);
23910
- } finally {
23911
- setRunningFromHere(false);
23912
- }
23913
- };
24256
+ const { executeStep, executeFromNode } = useNodeExecution();
23914
24257
  const threePaneLayout = useMediaQuery("(min-width: 1024px)");
23915
24258
  const [pane, setPane] = useState("parameters");
23916
24259
  const panesRef = useRef(null);
@@ -23972,33 +24315,6 @@ function NodeDetailView() {
23972
24315
  /* @__PURE__ */ jsx(DialogTitle, { className: "truncate text-sm font-semibold leading-tight", children: nodeTitle(node) }),
23973
24316
  nodeSubtitle(node) && /* @__PURE__ */ jsx(DialogDescription, { className: "truncate text-xs leading-tight", children: nodeSubtitle(node) })
23974
24317
  ] }),
23975
- canRunFromHere && /* @__PURE__ */ jsxs(
23976
- "button",
23977
- {
23978
- type: "button",
23979
- onClick: runFromHere,
23980
- disabled: runningFromHere,
23981
- "data-testid": "ndv-run-from-here",
23982
- className: "flex items-center gap-1 rounded-md border border-primary/30 px-2 py-1 text-xs text-primary hover:bg-primary/10 disabled:opacity-50",
23983
- title: tr(
23984
- "fluidgrids.builder.nodeDetailView.runFromHereHint",
23985
- "Re-run from this node, reusing upstream outputs instead of re-executing them."
23986
- ),
23987
- children: [
23988
- /* @__PURE__ */ jsx(
23989
- Icon,
23990
- {
23991
- icon: runningFromHere ? "svg-spinners:ring-resize" : "mdi:play",
23992
- className: "size-3.5"
23993
- }
23994
- ),
23995
- tr(
23996
- "fluidgrids.builder.nodeDetailView.runFromHereButton",
23997
- "Run from here"
23998
- )
23999
- ]
24000
- }
24001
- ),
24002
24318
  /* @__PURE__ */ jsx(
24003
24319
  "button",
24004
24320
  {
@@ -24025,6 +24341,28 @@ function NodeDetailView() {
24025
24341
  }
24026
24342
  )
24027
24343
  ] }),
24344
+ ndv && /* @__PURE__ */ jsx(
24345
+ NodeExecutionActions,
24346
+ {
24347
+ targetNodeId: ndv.nodeId,
24348
+ nodes: workflowNodes,
24349
+ edges: workflowEdges,
24350
+ logs: executionLogs,
24351
+ workflowKey: workflowKey || workflowId,
24352
+ workflowVersion: workflowVersion || "1.0.0",
24353
+ sourceRun,
24354
+ isExecuting,
24355
+ onExecuteStep: async (targetId) => {
24356
+ await executeStep(targetId);
24357
+ },
24358
+ onContinueFromNode: async (sourceRunId, targetId) => {
24359
+ await executeFromNode(sourceRunId, targetId);
24360
+ },
24361
+ testIdPrefix: "ndv",
24362
+ className: "border-t-0 border-b"
24363
+ }
24364
+ ),
24365
+ stepPlanForNode && /* @__PURE__ */ jsx(StepExecutionPlanSummary, { plan: stepPlanForNode }),
24028
24366
  !threePaneLayout && /* @__PURE__ */ jsxs(
24029
24367
  "div",
24030
24368
  {
@@ -24349,6 +24687,152 @@ function NodeDetailView() {
24349
24687
  }
24350
24688
  ) });
24351
24689
  }
24690
+ function StepExecutionPlanSummary({ plan }) {
24691
+ const tr = useTr();
24692
+ return /* @__PURE__ */ jsxs(
24693
+ "section",
24694
+ {
24695
+ className: "shrink-0 border-b border-border bg-muted/30 px-4 py-2.5",
24696
+ "data-testid": "ndv-step-execution-plan",
24697
+ "aria-live": "polite",
24698
+ children: [
24699
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
24700
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-foreground", children: tr(
24701
+ "fluidgrids.builder.nodeDetailView.stepPlanTitle",
24702
+ "TEST execution plan"
24703
+ ) }),
24704
+ /* @__PURE__ */ jsx(
24705
+ PlanMetric,
24706
+ {
24707
+ label: tr(
24708
+ "fluidgrids.builder.nodeDetailView.stepPlanExecute",
24709
+ "Execute"
24710
+ ),
24711
+ count: plan.executeNodeIds.length
24712
+ }
24713
+ ),
24714
+ /* @__PURE__ */ jsx(
24715
+ PlanMetric,
24716
+ {
24717
+ label: tr("fluidgrids.builder.nodeDetailView.stepPlanReuse", "Reuse"),
24718
+ count: plan.reusedNodeIds.length
24719
+ }
24720
+ ),
24721
+ /* @__PURE__ */ jsx(
24722
+ PlanMetric,
24723
+ {
24724
+ label: tr(
24725
+ "fluidgrids.builder.nodeDetailView.stepPlanPinned",
24726
+ "Pinned"
24727
+ ),
24728
+ count: plan.pinnedNodeIds.length
24729
+ }
24730
+ ),
24731
+ /* @__PURE__ */ jsx(
24732
+ PlanMetric,
24733
+ {
24734
+ label: tr(
24735
+ "fluidgrids.builder.nodeDetailView.stepPlanBlockers",
24736
+ "Blockers"
24737
+ ),
24738
+ count: plan.blockers.length
24739
+ }
24740
+ )
24741
+ ] }),
24742
+ plan.sourceRunId && /* @__PURE__ */ jsxs("p", { className: "mt-1 text-[11px] text-muted-foreground", children: [
24743
+ tr(
24744
+ "fluidgrids.builder.nodeDetailView.stepPlanSource",
24745
+ "Using compatible TEST data from run"
24746
+ ),
24747
+ " ",
24748
+ /* @__PURE__ */ jsx("code", { className: "font-mono text-foreground", children: plan.sourceRunId })
24749
+ ] }),
24750
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 grid gap-2 sm:grid-cols-2", children: [
24751
+ /* @__PURE__ */ jsx(
24752
+ PlanNodeList,
24753
+ {
24754
+ label: tr(
24755
+ "fluidgrids.builder.nodeDetailView.stepPlanExecuteNodes",
24756
+ "Nodes to execute"
24757
+ ),
24758
+ nodeIds: plan.executeNodeIds,
24759
+ emptyLabel: tr(
24760
+ "fluidgrids.builder.nodeDetailView.stepPlanExecuteNodesEmpty",
24761
+ "No nodes need execution."
24762
+ )
24763
+ }
24764
+ ),
24765
+ /* @__PURE__ */ jsx(
24766
+ PlanNodeList,
24767
+ {
24768
+ label: tr(
24769
+ "fluidgrids.builder.nodeDetailView.stepPlanReusedNodes",
24770
+ "Reused nodes"
24771
+ ),
24772
+ nodeIds: plan.reusedNodeIds,
24773
+ emptyLabel: tr(
24774
+ "fluidgrids.builder.nodeDetailView.stepPlanReusedNodesEmpty",
24775
+ "No prior node data reused."
24776
+ )
24777
+ }
24778
+ ),
24779
+ /* @__PURE__ */ jsx(
24780
+ PlanNodeList,
24781
+ {
24782
+ label: tr(
24783
+ "fluidgrids.builder.nodeDetailView.stepPlanPinnedNodes",
24784
+ "Pinned nodes"
24785
+ ),
24786
+ nodeIds: plan.pinnedNodeIds,
24787
+ emptyLabel: tr(
24788
+ "fluidgrids.builder.nodeDetailView.stepPlanPinnedNodesEmpty",
24789
+ "No pinned data used."
24790
+ )
24791
+ }
24792
+ ),
24793
+ /* @__PURE__ */ jsx(
24794
+ PlanNodeList,
24795
+ {
24796
+ label: tr(
24797
+ "fluidgrids.builder.nodeDetailView.stepPlanBlockerNodes",
24798
+ "Blockers"
24799
+ ),
24800
+ nodeIds: plan.blockers,
24801
+ emptyLabel: tr(
24802
+ "fluidgrids.builder.nodeDetailView.stepPlanBlockerNodesEmpty",
24803
+ "No blockers."
24804
+ )
24805
+ }
24806
+ )
24807
+ ] })
24808
+ ]
24809
+ }
24810
+ );
24811
+ }
24812
+ function PlanMetric({ label, count: count2 }) {
24813
+ return /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-muted-foreground", children: [
24814
+ label,
24815
+ ": ",
24816
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: count2 })
24817
+ ] });
24818
+ }
24819
+ function PlanNodeList({
24820
+ label,
24821
+ nodeIds,
24822
+ emptyLabel
24823
+ }) {
24824
+ return /* @__PURE__ */ jsxs("div", { className: "min-w-0 rounded-md border border-border bg-background/60 px-2 py-1.5", children: [
24825
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: label }),
24826
+ nodeIds.length > 0 ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-1", children: nodeIds.map((nodeId) => /* @__PURE__ */ jsx(
24827
+ "code",
24828
+ {
24829
+ className: "max-w-full truncate rounded bg-muted px-1 py-0.5 font-mono text-[10px] text-foreground",
24830
+ children: nodeId
24831
+ },
24832
+ `${label}-${nodeId}`
24833
+ )) }) : /* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: emptyLabel })
24834
+ ] });
24835
+ }
24352
24836
  function ResizeHandle({ onStart }) {
24353
24837
  return /* @__PURE__ */ jsx(
24354
24838
  "div",
@@ -24465,6 +24949,9 @@ function QuickConfigPanelInner({
24465
24949
  const close = useFlowStore((s) => s.actions.quickConfig.close);
24466
24950
  const openNdv = useFlowStore((s) => s.actions.ndv.open);
24467
24951
  const tr = useTr();
24952
+ const { executeStep, executeFromNode } = useNodeExecution();
24953
+ const workflow = useFlowStore((s) => s.workflow);
24954
+ const execution = useFlowStore((s) => s.execution);
24468
24955
  const config2 = useNodeConfig({ nodeId});
24469
24956
  const {
24470
24957
  node,
@@ -24750,6 +25237,26 @@ function QuickConfigPanelInner({
24750
25237
  )
24751
25238
  }
24752
25239
  ),
25240
+ /* @__PURE__ */ jsx(
25241
+ NodeExecutionActions,
25242
+ {
25243
+ targetNodeId: nodeId,
25244
+ nodes: workflow.nodes,
25245
+ edges: workflow.edges,
25246
+ logs: execution.logs,
25247
+ workflowKey: workflow.workflowKey || workflow.id,
25248
+ workflowVersion: workflow.version || "1.0.0",
25249
+ sourceRun: execution.sourceRun,
25250
+ isExecuting: execution.isExecuting,
25251
+ onExecuteStep: async (targetId) => {
25252
+ await executeStep(targetId);
25253
+ },
25254
+ onContinueFromNode: async (sourceRunId, targetId) => {
25255
+ await executeFromNode(sourceRunId, targetId);
25256
+ },
25257
+ testIdPrefix: "qc"
25258
+ }
25259
+ ),
24753
25260
  /* @__PURE__ */ jsx("p", { className: "shrink-0 border-t border-border px-3 py-1.5 text-[10px] leading-snug text-muted-foreground", children: tr(
24754
25261
  "fluidgrids.builder.quickConfigPanel.footerHint",
24755
25262
  "Changes apply instantly \xB7 double-click the node for the full editor"
@@ -26040,5 +26547,5 @@ var FlowBuilderPage = ({
26040
26547
  };
26041
26548
 
26042
26549
  export { Card2 as Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ConnectionFormDialog, ConnectionSelector, EntityTagPicker, FLUIDGRIDS_ENTITY_TYPES, FlowBuilderPage, FluidGridsMark, 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 };
26043
- //# sourceMappingURL=chunk-6SXISR7B.js.map
26044
- //# sourceMappingURL=chunk-6SXISR7B.js.map
26550
+ //# sourceMappingURL=chunk-VG2BTLUN.js.map
26551
+ //# sourceMappingURL=chunk-VG2BTLUN.js.map