@burdenoff/fluidgrids-fe-sdk 2026.922.7 → 2026.922.9

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-V3LXDOAT.js +11 -0
  2. package/dist/{ExecutionDetailPage-WLC63RRK.js.map → ExecutionDetailPage-V3LXDOAT.js.map} +1 -1
  3. package/dist/ExecutionsListPage-AATDFFIH.js +10 -0
  4. package/dist/{ExecutionsListPage-P5DRISMN.js.map → ExecutionsListPage-AATDFFIH.js.map} +1 -1
  5. package/dist/{WorkflowBuilder-LZ7X2M5Y.js → WorkflowBuilder-DS4EK7JE.js} +7 -7
  6. package/dist/{WorkflowBuilder-LZ7X2M5Y.js.map → WorkflowBuilder-DS4EK7JE.js.map} +1 -1
  7. package/dist/WorkflowsList-DUCKDRKC.js +13 -0
  8. package/dist/{WorkflowsList-QDPC2HVV.js.map → WorkflowsList-DUCKDRKC.js.map} +1 -1
  9. package/dist/{chunk-4KX6I7PA.js → chunk-5XUOENLH.js} +5 -5
  10. package/dist/{chunk-4KX6I7PA.js.map → chunk-5XUOENLH.js.map} +1 -1
  11. package/dist/{chunk-WO3AHQVD.js → chunk-BHITFSOK.js} +73 -3
  12. package/dist/chunk-BHITFSOK.js.map +1 -0
  13. package/dist/{chunk-Z4XRVZZ2.js → chunk-C4HOB3JQ.js} +4 -4
  14. package/dist/{chunk-Z4XRVZZ2.js.map → chunk-C4HOB3JQ.js.map} +1 -1
  15. package/dist/{chunk-OZBZS6DM.js → chunk-CVVNQCFM.js} +3 -3
  16. package/dist/{chunk-OZBZS6DM.js.map → chunk-CVVNQCFM.js.map} +1 -1
  17. package/dist/{chunk-CVNW2EUB.js → chunk-EUZZLC3N.js} +3 -3
  18. package/dist/{chunk-CVNW2EUB.js.map → chunk-EUZZLC3N.js.map} +1 -1
  19. package/dist/{chunk-CQOQ6A73.js → chunk-ISS73LG3.js} +3 -3
  20. package/dist/{chunk-CQOQ6A73.js.map → chunk-ISS73LG3.js.map} +1 -1
  21. package/dist/{chunk-4LJOUX2R.js → chunk-KLWMUV2N.js} +5 -5
  22. package/dist/{chunk-4LJOUX2R.js.map → chunk-KLWMUV2N.js.map} +1 -1
  23. package/dist/{chunk-VTKT6XDA.js → chunk-NOOLXG62.js} +352 -18
  24. package/dist/chunk-NOOLXG62.js.map +1 -0
  25. package/dist/{chunk-XA3IJE2D.js → chunk-PTGKDQ5K.js} +44 -17
  26. package/dist/chunk-PTGKDQ5K.js.map +1 -0
  27. package/dist/{chunk-62OZJC2B.js → chunk-R6JFXZXN.js} +4 -4
  28. package/dist/{chunk-62OZJC2B.js.map → chunk-R6JFXZXN.js.map} +1 -1
  29. package/dist/{chunk-KAMWWBX5.js → chunk-UNW4I442.js} +3 -3
  30. package/dist/{chunk-KAMWWBX5.js.map → chunk-UNW4I442.js.map} +1 -1
  31. package/dist/{chunk-REM2BQK5.js → chunk-XC7A7NLP.js} +4 -4
  32. package/dist/{chunk-REM2BQK5.js.map → chunk-XC7A7NLP.js.map} +1 -1
  33. package/dist/{chunk-275FCUOI.js → chunk-YMD3T6J2.js} +17 -2
  34. package/dist/chunk-YMD3T6J2.js.map +1 -0
  35. package/dist/{chunk-WJQSPVU5.js → chunk-YP6P5E6M.js} +4 -4
  36. package/dist/{chunk-WJQSPVU5.js.map → chunk-YP6P5E6M.js.map} +1 -1
  37. package/dist/executions.js +5 -5
  38. package/dist/history.js +3 -3
  39. package/dist/index.d.ts +228 -8
  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-lgLa__fU.d.ts → workflow-builder-Y7PcoT2O.d.ts} +45 -13
  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-WLC63RRK.js +0 -11
  51. package/dist/ExecutionsListPage-P5DRISMN.js +0 -10
  52. package/dist/WorkflowsList-QDPC2HVV.js +0 -13
  53. package/dist/chunk-275FCUOI.js.map +0 -1
  54. package/dist/chunk-VTKT6XDA.js.map +0 -1
  55. package/dist/chunk-WO3AHQVD.js.map +0 -1
  56. package/dist/chunk-XA3IJE2D.js.map +0 -1
@@ -7,12 +7,12 @@ import { deepClone, applyTemplateInputs } from './chunk-XQP33UJR.js';
7
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-OZBZS6DM.js';
10
+ import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useDeactivateWorkflow } from './chunk-CVVNQCFM.js';
11
11
  import { throwIfResultError, describeOperationError } from './chunk-LMO5ASOE.js';
12
12
  import { config, getFluidGridsConfig, validateTrustedOrigin, setFluidGridsConfig, resetFluidGridsConfig } from './chunk-WWU2O2SR.js';
13
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';
14
+ import { useFlowStore } from './chunk-YMD3T6J2.js';
15
+ 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-BHITFSOK.js';
16
16
  import { useTr, FluidGridsTranslationProvider, ENGLISH_FALLBACK_TRANSLATOR } from './chunk-7YWBH2A5.js';
17
17
  import * as React2 from 'react';
18
18
  import React2__default, { forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, memo, createContext, lazy, useCallback, useContext, useLayoutEffect, Suspense, useDeferredValue } from 'react';
@@ -3602,6 +3602,8 @@ function ConnectionSelector({
3602
3602
  }
3603
3603
  var TRIGGER_WORKFLOW = TriggerWorkflowDocument;
3604
3604
  var WORKFLOW_RUN = WorkflowRunDocument;
3605
+ var RUN_FROM_NODE = RunFromNodeDocument;
3606
+ var EXECUTION_DETAIL = ExecutionDetailDocument;
3605
3607
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
3606
3608
  "COMPLETED",
3607
3609
  "FAILED",
@@ -3648,6 +3650,7 @@ function useNodeExecution() {
3648
3650
  (s) => s.actions.execution.completeExecution
3649
3651
  );
3650
3652
  const clearLogs = useFlowStore((s) => s.actions.execution.clearLogs);
3653
+ const loadDebugRun = useFlowStore((s) => s.actions.execution.loadDebugRun);
3651
3654
  const cleanup = useCallback(() => {
3652
3655
  if (pollTimerRef.current) {
3653
3656
  clearTimeout(pollTimerRef.current);
@@ -3741,7 +3744,9 @@ function useNodeExecution() {
3741
3744
  error: nodeState.error ?? null,
3742
3745
  duration: nodeState.duration ?? null,
3743
3746
  startTime: nodeState.startTime ?? (/* @__PURE__ */ new Date()).toISOString(),
3744
- endTime: nodeState.endTime ?? null
3747
+ endTime: nodeState.endTime ?? null,
3748
+ usedPinnedData: nodeState.usedPinnedData ?? false,
3749
+ reusedFromRunId: nodeState.reusedFromRunId ?? null
3745
3750
  };
3746
3751
  addLog(newLog);
3747
3752
  } else {
@@ -3752,7 +3757,9 @@ function useNodeExecution() {
3752
3757
  output: nodeState.output ?? existingLog.output,
3753
3758
  error: nodeState.error ?? existingLog.error,
3754
3759
  duration: nodeState.duration ?? existingLog.duration,
3755
- endTime: nodeState.endTime ?? existingLog.endTime
3760
+ endTime: nodeState.endTime ?? existingLog.endTime,
3761
+ usedPinnedData: nodeState.usedPinnedData ?? existingLog.usedPinnedData,
3762
+ reusedFromRunId: nodeState.reusedFromRunId ?? existingLog.reusedFromRunId
3756
3763
  });
3757
3764
  }
3758
3765
  }
@@ -3850,7 +3857,11 @@ function useNodeExecution() {
3850
3857
  triggerNodeId: triggerNode.id,
3851
3858
  triggerData: {},
3852
3859
  context: {},
3853
- stopAtNodeId
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"
3854
3865
  }
3855
3866
  }
3856
3867
  })
@@ -3949,7 +3960,10 @@ function useNodeExecution() {
3949
3960
  version,
3950
3961
  triggerNodeId: triggerNode.id,
3951
3962
  triggerData: customTriggerData || {},
3952
- context: {}
3963
+ context: {},
3964
+ // Builder "Test workflow" is always a manual/debug run
3965
+ // (BOFF-7511) — see the note on executeNode above.
3966
+ mode: "TEST"
3953
3967
  }
3954
3968
  }
3955
3969
  })
@@ -4001,6 +4015,99 @@ function useNodeExecution() {
4001
4015
  completeExecution
4002
4016
  ]
4003
4017
  );
4018
+ const executeFromNode = useCallback(
4019
+ async (sourceRunId, nodeId) => {
4020
+ cleanup();
4021
+ clearLogs();
4022
+ setNodeStatus(nodeId, "running");
4023
+ try {
4024
+ const client = getFluidGridsClient();
4025
+ const result = throwIfResultError(
4026
+ await client.mutate({
4027
+ mutation: RUN_FROM_NODE,
4028
+ variables: {
4029
+ input: {
4030
+ sourceRunId,
4031
+ nodeId,
4032
+ // Run-from-node is a debug affordance — always TEST, same
4033
+ // rule as executeNode/executeFullWorkflow above.
4034
+ mode: "TEST"
4035
+ }
4036
+ }
4037
+ })
4038
+ );
4039
+ const runFromNodeResult = result.data?.runFromNode;
4040
+ if (runFromNodeResult) {
4041
+ const backendRunId = runFromNodeResult.runId;
4042
+ startExecution(nodeId, backendRunId);
4043
+ pollRunUpdates(backendRunId);
4044
+ return { success: true, runId: backendRunId };
4045
+ }
4046
+ console.error("[useNodeExecution] No result from runFromNode");
4047
+ setNodeStatus(nodeId, "error");
4048
+ return { success: false, error: "No result from runFromNode" };
4049
+ } catch (error) {
4050
+ console.error("[useNodeExecution] Error running from node:", error);
4051
+ const errorMessage = describeOperationError(error);
4052
+ setNodeStatus(nodeId, "error");
4053
+ completeExecution();
4054
+ return { success: false, error: errorMessage };
4055
+ }
4056
+ },
4057
+ [
4058
+ cleanup,
4059
+ clearLogs,
4060
+ setNodeStatus,
4061
+ startExecution,
4062
+ pollRunUpdates,
4063
+ completeExecution
4064
+ ]
4065
+ );
4066
+ const loadExecution = useCallback(
4067
+ async (runId) => {
4068
+ cleanup();
4069
+ try {
4070
+ const client = getFluidGridsClient();
4071
+ const result = throwIfResultError(
4072
+ await client.query({
4073
+ query: EXECUTION_DETAIL,
4074
+ variables: { id: runId },
4075
+ fetchPolicy: "network-only"
4076
+ })
4077
+ );
4078
+ const run = result.data?.workflowRun;
4079
+ if (!run) {
4080
+ return { success: false, error: "Execution not found" };
4081
+ }
4082
+ const logs = (run.nodeStates ?? []).map((nodeState) => {
4083
+ const rawStatus = nodeState.status.toLowerCase();
4084
+ const status = rawStatus === "completed" ? "completed" : rawStatus === "failed" || rawStatus === "timeout" ? "failed" : rawStatus === "running" || rawStatus === "waiting" || rawStatus === "delayed" || rawStatus === "waiting_subworkflow" ? "running" : "pending";
4085
+ return {
4086
+ id: `${runId}-${nodeState.nodeId}`,
4087
+ runId,
4088
+ nodeId: nodeState.nodeId,
4089
+ nodeType: nodeState.nodeType,
4090
+ nodeName: getNodeName(nodeState.nodeId),
4091
+ status,
4092
+ inputArgs: nodeState.inputArgs ?? null,
4093
+ output: nodeState.output ?? null,
4094
+ error: nodeState.error ?? null,
4095
+ duration: nodeState.duration ?? null,
4096
+ startTime: nodeState.startTime ?? run.startedAt ?? "",
4097
+ endTime: nodeState.endTime ?? null,
4098
+ usedPinnedData: nodeState.usedPinnedData ?? false,
4099
+ reusedFromRunId: nodeState.reusedFromRunId ?? null
4100
+ };
4101
+ });
4102
+ loadDebugRun(runId, logs);
4103
+ return { success: true, runId };
4104
+ } catch (error) {
4105
+ console.error("[useNodeExecution] Error loading execution:", error);
4106
+ return { success: false, error: describeOperationError(error) };
4107
+ }
4108
+ },
4109
+ [cleanup, getNodeName, loadDebugRun]
4110
+ );
4004
4111
  useEffect(() => {
4005
4112
  return () => {
4006
4113
  if (pollTimerRef.current) {
@@ -4012,6 +4119,8 @@ function useNodeExecution() {
4012
4119
  return {
4013
4120
  executeNode,
4014
4121
  executeFullWorkflow,
4122
+ executeFromNode,
4123
+ loadExecution,
4015
4124
  cleanup,
4016
4125
  findTriggerNode
4017
4126
  };
@@ -20652,13 +20761,17 @@ var ExecuteWorkflowButton = ({
20652
20761
  )
20653
20762
  ] });
20654
20763
  };
20655
- var JsonView = ({ data }) => {
20764
+ var JsonView = ({
20765
+ data
20766
+ }) => {
20656
20767
  const tr = useTr();
20657
20768
  if (!data)
20658
20769
  return /* @__PURE__ */ jsx("div", { className: "text-tertiary p-4", children: tr("fluidgrids.builder.logsPanel.jsonViewNoData", "No data") });
20659
20770
  return /* @__PURE__ */ jsx("pre", { className: "text-xs overflow-auto p-4 bg-card/50 rounded h-full", children: JSON.stringify(data, null, 2) });
20660
20771
  };
20661
- var TableView = ({ data }) => {
20772
+ var TableView = ({
20773
+ data
20774
+ }) => {
20662
20775
  const tr = useTr();
20663
20776
  if (!data)
20664
20777
  return /* @__PURE__ */ jsx("div", { className: "text-tertiary p-4", children: tr("fluidgrids.builder.logsPanel.tableViewNoData", "No data") });
@@ -21411,6 +21524,34 @@ function fieldsFromIO(io, root = "") {
21411
21524
  ([key, spec]) => fieldFromSpec(key, joinPath(root, key), spec)
21412
21525
  );
21413
21526
  }
21527
+ function typeOfValue(value) {
21528
+ if (value === null || value === void 0) return "any";
21529
+ if (Array.isArray(value)) return "array";
21530
+ if (typeof value === "object") return "object";
21531
+ if (typeof value === "number") return "number";
21532
+ if (typeof value === "boolean") return "boolean";
21533
+ if (typeof value === "string") return "string";
21534
+ return "any";
21535
+ }
21536
+ function fieldFromValue(key, path, value) {
21537
+ if (Array.isArray(value)) {
21538
+ const children = value.length > 0 ? [fieldFromValue("0", `${path}[0]`, value[0])] : void 0;
21539
+ return { key, path, type: "array", children };
21540
+ }
21541
+ if (isRecord2(value)) {
21542
+ const children = Object.entries(value).map(
21543
+ ([k, v]) => fieldFromValue(k, joinPath(path, k), v)
21544
+ );
21545
+ return { key, path, type: "object", children };
21546
+ }
21547
+ return { key, path, type: typeOfValue(value) };
21548
+ }
21549
+ function fieldsFromValue(value, root = "") {
21550
+ if (!isRecord2(value)) return [];
21551
+ return Object.entries(value).map(
21552
+ ([key, v]) => fieldFromValue(key, joinPath(root, key), v)
21553
+ );
21554
+ }
21414
21555
  function normalizeOperations(raw) {
21415
21556
  if (Array.isArray(raw)) return raw;
21416
21557
  if (isRecord2(raw) && Array.isArray(raw.operations)) {
@@ -23480,6 +23621,64 @@ function NodeDetailView() {
23480
23621
  } = config2;
23481
23622
  const [tab, setTab] = useState("parameters");
23482
23623
  const [outputView, setOutputView] = useState("schema");
23624
+ const [inputView, setInputView] = useState("schema");
23625
+ const executionLogs = useFlowStore((s) => s.execution.logs);
23626
+ const currentRunId = useFlowStore((s) => s.execution.currentRunId);
23627
+ const nodeLog = useMemo(() => {
23628
+ if (!ndv?.nodeId) return null;
23629
+ const matches = executionLogs.filter((l) => l.nodeId === ndv.nodeId);
23630
+ return matches.length > 0 ? matches[matches.length - 1] : null;
23631
+ }, [executionLogs, ndv?.nodeId]);
23632
+ const hasRealOutput = !!nodeLog?.output && Object.keys(nodeLog.output).length > 0;
23633
+ const hasRealInput = !!nodeLog?.inputArgs && Object.keys(nodeLog.inputArgs).length > 0;
23634
+ const realOutputFields = useMemo(
23635
+ () => hasRealOutput ? fieldsFromValue(nodeLog.output) : [],
23636
+ [hasRealOutput, nodeLog]
23637
+ );
23638
+ const realInputFields = useMemo(
23639
+ () => hasRealInput ? fieldsFromValue(nodeLog.inputArgs) : [],
23640
+ [hasRealInput, nodeLog]
23641
+ );
23642
+ const workflowDbId = useFlowStore((s) => s.workflow.dbId);
23643
+ const { data: pinnedDataResult, refetch: refetchPinnedData } = useWorkflowPinnedDataQuery({
23644
+ variables: { id: workflowDbId },
23645
+ skip: !workflowDbId || !open,
23646
+ fetchPolicy: "cache-and-network"
23647
+ });
23648
+ const pinnedNodeData = pinnedDataResult?.workflowDefinition?.pinnedNodeData ?? {};
23649
+ const isPinned = !!ndv?.nodeId && !!pinnedNodeData[ndv.nodeId];
23650
+ const [pinNodeData, { loading: pinning }] = usePinNodeDataMutation();
23651
+ const [unpinNodeData, { loading: unpinning }] = useUnpinNodeDataMutation();
23652
+ const togglePin = async () => {
23653
+ if (!workflowDbId || !ndv?.nodeId) return;
23654
+ try {
23655
+ if (isPinned) {
23656
+ await unpinNodeData({
23657
+ variables: { id: workflowDbId, nodeId: ndv.nodeId }
23658
+ });
23659
+ } else {
23660
+ const dataToPin = nodeLog?.output ?? currentOp?.output_fields ?? {};
23661
+ await pinNodeData({
23662
+ variables: { id: workflowDbId, nodeId: ndv.nodeId, data: dataToPin }
23663
+ });
23664
+ }
23665
+ await refetchPinnedData();
23666
+ } catch (err) {
23667
+ console.error("[NodeDetailView] Failed to toggle pinned data", err);
23668
+ }
23669
+ };
23670
+ const { executeFromNode } = useNodeExecution();
23671
+ const [runningFromHere, setRunningFromHere] = useState(false);
23672
+ const canRunFromHere = !!currentRunId && nodeLog?.status === "completed";
23673
+ const runFromHere = async () => {
23674
+ if (!currentRunId || !ndv?.nodeId) return;
23675
+ setRunningFromHere(true);
23676
+ try {
23677
+ await executeFromNode(currentRunId, ndv.nodeId);
23678
+ } finally {
23679
+ setRunningFromHere(false);
23680
+ }
23681
+ };
23483
23682
  const threePaneLayout = useMediaQuery("(min-width: 1024px)");
23484
23683
  const [pane, setPane] = useState("parameters");
23485
23684
  const panesRef = useRef(null);
@@ -23541,6 +23740,33 @@ function NodeDetailView() {
23541
23740
  /* @__PURE__ */ jsx(DialogTitle, { className: "truncate text-sm font-semibold leading-tight", children: nodeTitle(node) }),
23542
23741
  nodeSubtitle(node) && /* @__PURE__ */ jsx(DialogDescription, { className: "truncate text-xs leading-tight", children: nodeSubtitle(node) })
23543
23742
  ] }),
23743
+ canRunFromHere && /* @__PURE__ */ jsxs(
23744
+ "button",
23745
+ {
23746
+ type: "button",
23747
+ onClick: runFromHere,
23748
+ disabled: runningFromHere,
23749
+ "data-testid": "ndv-run-from-here",
23750
+ 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",
23751
+ title: tr(
23752
+ "fluidgrids.builder.nodeDetailView.runFromHereHint",
23753
+ "Re-run from this node, reusing upstream outputs instead of re-executing them."
23754
+ ),
23755
+ children: [
23756
+ /* @__PURE__ */ jsx(
23757
+ Icon,
23758
+ {
23759
+ icon: runningFromHere ? "svg-spinners:ring-resize" : "mdi:play",
23760
+ className: "size-3.5"
23761
+ }
23762
+ ),
23763
+ tr(
23764
+ "fluidgrids.builder.nodeDetailView.runFromHereButton",
23765
+ "Run from here"
23766
+ )
23767
+ ]
23768
+ }
23769
+ ),
23544
23770
  /* @__PURE__ */ jsx(
23545
23771
  "button",
23546
23772
  {
@@ -23615,7 +23841,21 @@ function NodeDetailView() {
23615
23841
  children: [
23616
23842
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-2.5", children: [
23617
23843
  /* @__PURE__ */ jsx("span", { className: SECTION_LABEL5, children: tr("fluidgrids.builder.nodeDetailView.inputSection", "Input") }),
23618
- sourceIds.length > 0 && /* @__PURE__ */ jsx(
23844
+ hasRealInput && /* @__PURE__ */ jsx(
23845
+ "span",
23846
+ {
23847
+ className: "rounded bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-primary",
23848
+ title: tr(
23849
+ "fluidgrids.builder.nodeDetailView.realDataBadgeHint",
23850
+ "Showing real data from the last execution."
23851
+ ),
23852
+ children: tr(
23853
+ "fluidgrids.builder.nodeDetailView.realDataBadge",
23854
+ "Live"
23855
+ )
23856
+ }
23857
+ ),
23858
+ sourceIds.length > 0 && !hasRealInput && /* @__PURE__ */ jsx(
23619
23859
  "select",
23620
23860
  {
23621
23861
  className: "ml-auto max-w-[60%] truncate rounded-md border border-input bg-background px-2 py-1 text-xs text-foreground outline-none focus:border-primary",
@@ -23627,14 +23867,49 @@ function NodeDetailView() {
23627
23867
  return /* @__PURE__ */ jsx("option", { value: sid, children: nodeTitle(sn) }, sid);
23628
23868
  })
23629
23869
  }
23630
- )
23870
+ ),
23871
+ (hasRealInput || inputFields.length > 0) && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
23872
+ /* @__PURE__ */ jsx(
23873
+ ToggleChip,
23874
+ {
23875
+ active: inputView === "schema",
23876
+ onClick: () => setInputView("schema"),
23877
+ children: tr(
23878
+ "fluidgrids.builder.nodeDetailView.outputViewSchema",
23879
+ "Schema"
23880
+ )
23881
+ }
23882
+ ),
23883
+ /* @__PURE__ */ jsx(
23884
+ ToggleChip,
23885
+ {
23886
+ active: inputView === "table",
23887
+ onClick: () => setInputView("table"),
23888
+ children: tr(
23889
+ "fluidgrids.builder.nodeDetailView.outputViewTable",
23890
+ "Table"
23891
+ )
23892
+ }
23893
+ ),
23894
+ /* @__PURE__ */ jsx(
23895
+ ToggleChip,
23896
+ {
23897
+ active: inputView === "json",
23898
+ onClick: () => setInputView("json"),
23899
+ children: tr(
23900
+ "fluidgrids.builder.nodeDetailView.outputViewJson",
23901
+ "JSON"
23902
+ )
23903
+ }
23904
+ )
23905
+ ] })
23631
23906
  ] }),
23632
23907
  /* @__PURE__ */ jsx(
23633
23908
  "div",
23634
23909
  {
23635
23910
  className: "min-h-0 flex-1 overflow-auto px-2 pb-3",
23636
23911
  "data-testid": "ndv-input-tree",
23637
- children: inputFields.length > 0 ? /* @__PURE__ */ jsx(FieldTree, { fields: inputFields, draggable: true }) : /* @__PURE__ */ jsx(
23912
+ children: hasRealInput ? inputView === "schema" ? /* @__PURE__ */ jsx(FieldTree, { fields: realInputFields, draggable: true }) : inputView === "table" ? /* @__PURE__ */ jsx(TableView, { data: nodeLog.inputArgs }) : /* @__PURE__ */ jsx(JsonView, { data: nodeLog.inputArgs }) : inputFields.length > 0 ? /* @__PURE__ */ jsx(FieldTree, { fields: inputFields, draggable: true }) : /* @__PURE__ */ jsx(
23638
23913
  EmptyState,
23639
23914
  {
23640
23915
  icon: "mdi:tray-arrow-down",
@@ -23729,7 +24004,55 @@ function NodeDetailView() {
23729
24004
  "fluidgrids.builder.nodeDetailView.outputSection",
23730
24005
  "Output"
23731
24006
  ) }),
23732
- outputFields.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
24007
+ hasRealOutput && /* @__PURE__ */ jsx(
24008
+ "span",
24009
+ {
24010
+ className: "rounded bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-primary",
24011
+ title: tr(
24012
+ "fluidgrids.builder.nodeDetailView.realDataBadgeHint",
24013
+ "Showing real data from the last execution."
24014
+ ),
24015
+ children: tr(
24016
+ "fluidgrids.builder.nodeDetailView.realDataBadge",
24017
+ "Live"
24018
+ )
24019
+ }
24020
+ ),
24021
+ nodeLog?.usedPinnedData && /* @__PURE__ */ jsx("span", { className: "rounded bg-amber-500/10 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-amber-600 dark:text-amber-400", children: tr(
24022
+ "fluidgrids.builder.nodeDetailView.pinnedDataUsedBadge",
24023
+ "Pinned"
24024
+ ) }),
24025
+ ndv?.nodeId && workflowDbId && /* @__PURE__ */ jsxs(
24026
+ "button",
24027
+ {
24028
+ type: "button",
24029
+ onClick: togglePin,
24030
+ disabled: pinning || unpinning,
24031
+ "data-testid": "ndv-pin-toggle",
24032
+ title: tr(
24033
+ isPinned ? "fluidgrids.builder.nodeDetailView.unpinHint" : "fluidgrids.builder.nodeDetailView.pinHint",
24034
+ isPinned ? "Unpin \u2014 TEST runs will call this node for real again." : "Pin this output \u2014 TEST runs will replay it instead of calling the node."
24035
+ ),
24036
+ className: cn(
24037
+ "flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide transition-colors disabled:opacity-50",
24038
+ isPinned ? "bg-amber-500/15 text-amber-600 dark:text-amber-400" : "text-muted-foreground hover:text-foreground"
24039
+ ),
24040
+ children: [
24041
+ /* @__PURE__ */ jsx(
24042
+ Icon,
24043
+ {
24044
+ icon: isPinned ? "mdi:pin" : "mdi:pin-outline",
24045
+ className: "size-3"
24046
+ }
24047
+ ),
24048
+ tr(
24049
+ isPinned ? "fluidgrids.builder.nodeDetailView.unpinButton" : "fluidgrids.builder.nodeDetailView.pinButton",
24050
+ isPinned ? "Pinned" : "Pin"
24051
+ )
24052
+ ]
24053
+ }
24054
+ ),
24055
+ (hasRealOutput || outputFields.length > 0) && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
23733
24056
  /* @__PURE__ */ jsx(
23734
24057
  ToggleChip,
23735
24058
  {
@@ -23741,6 +24064,17 @@ function NodeDetailView() {
23741
24064
  )
23742
24065
  }
23743
24066
  ),
24067
+ /* @__PURE__ */ jsx(
24068
+ ToggleChip,
24069
+ {
24070
+ active: outputView === "table",
24071
+ onClick: () => setOutputView("table"),
24072
+ children: tr(
24073
+ "fluidgrids.builder.nodeDetailView.outputViewTable",
24074
+ "Table"
24075
+ )
24076
+ }
24077
+ ),
23744
24078
  /* @__PURE__ */ jsx(
23745
24079
  ToggleChip,
23746
24080
  {
@@ -23759,7 +24093,7 @@ function NodeDetailView() {
23759
24093
  {
23760
24094
  className: "min-h-0 flex-1 overflow-auto px-2 pb-3",
23761
24095
  "data-testid": "ndv-output-tree",
23762
- children: outputFields.length === 0 ? /* @__PURE__ */ jsx(
24096
+ children: hasRealOutput ? outputView === "schema" ? /* @__PURE__ */ jsx(FieldTree, { fields: realOutputFields, draggable: true }) : outputView === "table" ? /* @__PURE__ */ jsx(TableView, { data: nodeLog.output }) : /* @__PURE__ */ jsx(JsonView, { data: nodeLog.output }) : outputFields.length === 0 ? /* @__PURE__ */ jsx(
23763
24097
  EmptyState,
23764
24098
  {
23765
24099
  icon: "mdi:tray-arrow-up",
@@ -23769,10 +24103,10 @@ function NodeDetailView() {
23769
24103
  ),
23770
24104
  hint: tr(
23771
24105
  "fluidgrids.builder.nodeDetailView.noOutputHint",
23772
- "This operation has no declared output fields."
24106
+ "This operation has no declared output fields. Run this node to see its real output here."
23773
24107
  )
23774
24108
  }
23775
- ) : outputView === "schema" ? /* @__PURE__ */ jsx(FieldTree, { fields: outputFields }) : /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap break-words px-2 text-[11px] leading-relaxed text-muted-foreground", children: JSON.stringify(currentOp?.output_fields ?? {}, null, 2) })
24109
+ ) : outputView === "schema" ? /* @__PURE__ */ jsx(FieldTree, { fields: outputFields, draggable: true }) : outputView === "table" ? /* @__PURE__ */ jsx(TableView, { data: null }) : /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap break-words px-2 text-[11px] leading-relaxed text-muted-foreground", children: JSON.stringify(currentOp?.output_fields ?? {}, null, 2) })
23776
24110
  }
23777
24111
  )
23778
24112
  ]
@@ -25211,5 +25545,5 @@ var FlowBuilderPage = ({
25211
25545
  };
25212
25546
 
25213
25547
  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 };
25214
- //# sourceMappingURL=chunk-VTKT6XDA.js.map
25215
- //# sourceMappingURL=chunk-VTKT6XDA.js.map
25548
+ //# sourceMappingURL=chunk-NOOLXG62.js.map
25549
+ //# sourceMappingURL=chunk-NOOLXG62.js.map