@burdenoff/fluidgrids-fe-sdk 2026.929.1 → 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 (56) hide show
  1. package/dist/ExecutionDetailPage-RK3KJ46E.js +12 -0
  2. package/dist/{ExecutionDetailPage-F5XOP3JQ.js.map → ExecutionDetailPage-RK3KJ46E.js.map} +1 -1
  3. package/dist/ExecutionsListPage-NXINADRN.js +11 -0
  4. package/dist/{ExecutionsListPage-KQZK2T4O.js.map → ExecutionsListPage-NXINADRN.js.map} +1 -1
  5. package/dist/{WorkflowBuilder-TJFZ2TA3.js → WorkflowBuilder-MAFYHWGY.js} +7 -7
  6. package/dist/{WorkflowBuilder-TJFZ2TA3.js.map → WorkflowBuilder-MAFYHWGY.js.map} +1 -1
  7. package/dist/WorkflowsList-AFTTUUHX.js +13 -0
  8. package/dist/{WorkflowsList-72U6TS4Y.js.map → WorkflowsList-AFTTUUHX.js.map} +1 -1
  9. package/dist/{chunk-FJC2RJ4Y.js → chunk-3P4YQ7DO.js} +33 -3
  10. package/dist/chunk-3P4YQ7DO.js.map +1 -0
  11. package/dist/{chunk-EXJYUEXA.js → chunk-5OZB7AQ4.js} +49 -5
  12. package/dist/chunk-5OZB7AQ4.js.map +1 -0
  13. package/dist/{chunk-GZCHKR3C.js → chunk-7SX5OWZR.js} +4 -4
  14. package/dist/{chunk-GZCHKR3C.js.map → chunk-7SX5OWZR.js.map} +1 -1
  15. package/dist/{chunk-TPDO2EIC.js → chunk-G3RPRMP5.js} +3 -3
  16. package/dist/{chunk-TPDO2EIC.js.map → chunk-G3RPRMP5.js.map} +1 -1
  17. package/dist/{chunk-ZTLWHD2V.js → chunk-GKSXZFDY.js} +3 -3
  18. package/dist/{chunk-ZTLWHD2V.js.map → chunk-GKSXZFDY.js.map} +1 -1
  19. package/dist/{chunk-OCE32VUK.js → chunk-IJSJOTIZ.js} +4 -4
  20. package/dist/{chunk-OCE32VUK.js.map → chunk-IJSJOTIZ.js.map} +1 -1
  21. package/dist/{chunk-XBQBM3SE.js → chunk-NHZQE7ZB.js} +4 -4
  22. package/dist/{chunk-XBQBM3SE.js.map → chunk-NHZQE7ZB.js.map} +1 -1
  23. package/dist/{chunk-ULNNTBJO.js → chunk-NTJTPYCD.js} +27 -4
  24. package/dist/chunk-NTJTPYCD.js.map +1 -0
  25. package/dist/{chunk-5FFVT22V.js → chunk-ODOEVG2G.js} +5 -5
  26. package/dist/{chunk-5FFVT22V.js.map → chunk-ODOEVG2G.js.map} +1 -1
  27. package/dist/{chunk-PTHYN6HY.js → chunk-R5ZYOIZG.js} +4 -4
  28. package/dist/{chunk-PTHYN6HY.js.map → chunk-R5ZYOIZG.js.map} +1 -1
  29. package/dist/{chunk-IFQXZBKJ.js → chunk-T4BFEI3I.js} +5 -5
  30. package/dist/{chunk-IFQXZBKJ.js.map → chunk-T4BFEI3I.js.map} +1 -1
  31. package/dist/{chunk-EXNXJ7VL.js → chunk-USFSPC6S.js} +3 -3
  32. package/dist/{chunk-EXNXJ7VL.js.map → chunk-USFSPC6S.js.map} +1 -1
  33. package/dist/{chunk-C44DTSC6.js → chunk-VG2BTLUN.js} +411 -49
  34. package/dist/chunk-VG2BTLUN.js.map +1 -0
  35. package/dist/{chunk-YBX7EDDR.js → chunk-ZLYJKIKG.js} +3 -3
  36. package/dist/{chunk-YBX7EDDR.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 +677 -11
  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-DIjITfNE.d.ts → workflow-builder-DqInt43T.d.ts} +14 -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-F5XOP3JQ.js +0 -12
  51. package/dist/ExecutionsListPage-KQZK2T4O.js +0 -11
  52. package/dist/WorkflowsList-72U6TS4Y.js +0 -13
  53. package/dist/chunk-C44DTSC6.js.map +0 -1
  54. package/dist/chunk-EXJYUEXA.js.map +0 -1
  55. package/dist/chunk-FJC2RJ4Y.js.map +0 -1
  56. package/dist/chunk-ULNNTBJO.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-ZTLWHD2V.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-ULNNTBJO.js';
13
- import { NodeEndpointConfigsDocument, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowRunDocument, FluidgridsEntityTagsDocument, AvailableFluidgridsTagsDocument, SearchFluidgridsTagsDocument, TagFluidgridsEntityDocument, UntagFluidgridsEntityDocument, ReplaceFluidgridsEntityTagsDocument, CreateFluidgridsTagDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, EventRegistrationsDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-FJC2RJ4Y.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';
@@ -3641,6 +3641,9 @@ function useNodeExecution() {
3641
3641
  const startExecution = useFlowStore(
3642
3642
  (s) => s.actions.execution.startExecution
3643
3643
  );
3644
+ const setRunMetadata = useFlowStore(
3645
+ (s) => s.actions.execution.setRunMetadata
3646
+ );
3644
3647
  const setStepPlan = useFlowStore((s) => s.actions.execution.setStepPlan);
3645
3648
  const addLog = useFlowStore((s) => s.actions.execution.addLog);
3646
3649
  const updateLog = useFlowStore((s) => s.actions.execution.updateLog);
@@ -3805,6 +3808,11 @@ function useNodeExecution() {
3805
3808
  }
3806
3809
  return;
3807
3810
  }
3811
+ setRunMetadata({
3812
+ runId,
3813
+ workflowKey: run.workflowKey,
3814
+ version: run.version
3815
+ });
3808
3816
  if (run.nodeStates?.length) {
3809
3817
  processNodeStates(runId, run.nodeStates);
3810
3818
  }
@@ -3824,7 +3832,7 @@ function useNodeExecution() {
3824
3832
  };
3825
3833
  pollTimerRef.current = setTimeout(doPoll, 800);
3826
3834
  },
3827
- [processNodeStates, completeExecution, cleanup]
3835
+ [processNodeStates, completeExecution, cleanup, setRunMetadata]
3828
3836
  );
3829
3837
  const executeStep = useCallback(
3830
3838
  async (nodeId) => {
@@ -3859,7 +3867,10 @@ function useNodeExecution() {
3859
3867
  const stepResult = result.data?.executeStep;
3860
3868
  if (stepResult) {
3861
3869
  const backendRunId = stepResult.runId;
3862
- startExecution(nodeId, backendRunId);
3870
+ startExecution(nodeId, backendRunId, {
3871
+ workflowKey: stepResult.workflowKey,
3872
+ version: stepResult.version
3873
+ });
3863
3874
  setStepPlan({
3864
3875
  runId: backendRunId,
3865
3876
  ...stepResult.plan,
@@ -3967,7 +3978,10 @@ function useNodeExecution() {
3967
3978
  const triggerResult = result.data?.triggerWorkflow;
3968
3979
  if (triggerResult) {
3969
3980
  const backendRunId = triggerResult.runId;
3970
- startExecution(triggerNode.id, backendRunId);
3981
+ startExecution(triggerNode.id, backendRunId, {
3982
+ workflowKey: triggerResult.workflowKey,
3983
+ version: triggerResult.version
3984
+ });
3971
3985
  pollRunUpdates(backendRunId);
3972
3986
  return { success: true, runId: backendRunId };
3973
3987
  }
@@ -4035,7 +4049,10 @@ function useNodeExecution() {
4035
4049
  const runFromNodeResult = result.data?.runFromNode;
4036
4050
  if (runFromNodeResult) {
4037
4051
  const backendRunId = runFromNodeResult.runId;
4038
- startExecution(nodeId, backendRunId);
4052
+ startExecution(nodeId, backendRunId, {
4053
+ workflowKey: runFromNodeResult.workflowKey,
4054
+ version: runFromNodeResult.version
4055
+ });
4039
4056
  pollRunUpdates(backendRunId);
4040
4057
  return { success: true, runId: backendRunId };
4041
4058
  }
@@ -4095,7 +4112,10 @@ function useNodeExecution() {
4095
4112
  reusedFromRunId: nodeState.reusedFromRunId ?? null
4096
4113
  };
4097
4114
  });
4098
- loadDebugRun(runId, logs);
4115
+ loadDebugRun(runId, logs, {
4116
+ workflowKey: run.workflowKey,
4117
+ version: run.version
4118
+ });
4099
4119
  return { success: true, runId };
4100
4120
  } catch (error) {
4101
4121
  console.error("[useNodeExecution] Error loading execution:", error);
@@ -23827,6 +23847,335 @@ function useMediaQuery(query) {
23827
23847
  }, [query]);
23828
23848
  return matches;
23829
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
+ }
23830
24179
  var SECTION_LABEL5 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
23831
24180
  function NodeDetailView() {
23832
24181
  const tr = useTr();
@@ -23852,6 +24201,13 @@ function NodeDetailView() {
23852
24201
  const [inputView, setInputView] = useState("schema");
23853
24202
  const executionLogs = useFlowStore((s) => s.execution.logs);
23854
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);
23855
24211
  const stepPlan = useFlowStore((s) => s.execution.stepPlan);
23856
24212
  const nodeLog = useMemo(() => {
23857
24213
  if (!ndv?.nodeId) return null;
@@ -23897,18 +24253,7 @@ function NodeDetailView() {
23897
24253
  console.error("[NodeDetailView] Failed to toggle pinned data", err);
23898
24254
  }
23899
24255
  };
23900
- const { executeFromNode } = useNodeExecution();
23901
- const [runningFromHere, setRunningFromHere] = useState(false);
23902
- const canRunFromHere = !!currentRunId && nodeLog?.status === "completed";
23903
- const runFromHere = async () => {
23904
- if (!currentRunId || !ndv?.nodeId) return;
23905
- setRunningFromHere(true);
23906
- try {
23907
- await executeFromNode(currentRunId, ndv.nodeId);
23908
- } finally {
23909
- setRunningFromHere(false);
23910
- }
23911
- };
24256
+ const { executeStep, executeFromNode } = useNodeExecution();
23912
24257
  const threePaneLayout = useMediaQuery("(min-width: 1024px)");
23913
24258
  const [pane, setPane] = useState("parameters");
23914
24259
  const panesRef = useRef(null);
@@ -23970,33 +24315,6 @@ function NodeDetailView() {
23970
24315
  /* @__PURE__ */ jsx(DialogTitle, { className: "truncate text-sm font-semibold leading-tight", children: nodeTitle(node) }),
23971
24316
  nodeSubtitle(node) && /* @__PURE__ */ jsx(DialogDescription, { className: "truncate text-xs leading-tight", children: nodeSubtitle(node) })
23972
24317
  ] }),
23973
- canRunFromHere && /* @__PURE__ */ jsxs(
23974
- "button",
23975
- {
23976
- type: "button",
23977
- onClick: runFromHere,
23978
- disabled: runningFromHere,
23979
- "data-testid": "ndv-run-from-here",
23980
- 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",
23981
- title: tr(
23982
- "fluidgrids.builder.nodeDetailView.runFromHereHint",
23983
- "Re-run from this node, reusing upstream outputs instead of re-executing them."
23984
- ),
23985
- children: [
23986
- /* @__PURE__ */ jsx(
23987
- Icon,
23988
- {
23989
- icon: runningFromHere ? "svg-spinners:ring-resize" : "mdi:play",
23990
- className: "size-3.5"
23991
- }
23992
- ),
23993
- tr(
23994
- "fluidgrids.builder.nodeDetailView.runFromHereButton",
23995
- "Run from here"
23996
- )
23997
- ]
23998
- }
23999
- ),
24000
24318
  /* @__PURE__ */ jsx(
24001
24319
  "button",
24002
24320
  {
@@ -24023,6 +24341,27 @@ function NodeDetailView() {
24023
24341
  }
24024
24342
  )
24025
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
+ ),
24026
24365
  stepPlanForNode && /* @__PURE__ */ jsx(StepExecutionPlanSummary, { plan: stepPlanForNode }),
24027
24366
  !threePaneLayout && /* @__PURE__ */ jsxs(
24028
24367
  "div",
@@ -24610,6 +24949,9 @@ function QuickConfigPanelInner({
24610
24949
  const close = useFlowStore((s) => s.actions.quickConfig.close);
24611
24950
  const openNdv = useFlowStore((s) => s.actions.ndv.open);
24612
24951
  const tr = useTr();
24952
+ const { executeStep, executeFromNode } = useNodeExecution();
24953
+ const workflow = useFlowStore((s) => s.workflow);
24954
+ const execution = useFlowStore((s) => s.execution);
24613
24955
  const config2 = useNodeConfig({ nodeId});
24614
24956
  const {
24615
24957
  node,
@@ -24895,6 +25237,26 @@ function QuickConfigPanelInner({
24895
25237
  )
24896
25238
  }
24897
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
+ ),
24898
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(
24899
25261
  "fluidgrids.builder.quickConfigPanel.footerHint",
24900
25262
  "Changes apply instantly \xB7 double-click the node for the full editor"
@@ -26185,5 +26547,5 @@ var FlowBuilderPage = ({
26185
26547
  };
26186
26548
 
26187
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 };
26188
- //# sourceMappingURL=chunk-C44DTSC6.js.map
26189
- //# sourceMappingURL=chunk-C44DTSC6.js.map
26550
+ //# sourceMappingURL=chunk-VG2BTLUN.js.map
26551
+ //# sourceMappingURL=chunk-VG2BTLUN.js.map