@burdenoff/fluidgrids-fe-sdk 2026.1114.5 → 2026.1114.6

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.
@@ -19,6 +19,7 @@ import { t as EntityTagPicker } from "./EntityTagPicker-BppBSEJk.js";
19
19
  import { a as useRecipientLabel, n as ApprovalApprovers, t as channelLabel } from "./channel-DtF1n_ab.js";
20
20
  import { r as useRunHumanRequests } from "./useHumanRequests-DwG2tQ3f.js";
21
21
  import { a as encodedPayloadBytes, f as EffectBadge, h as useRunPolicyDecisions, i as decodePayloads, l as formatBudgetUsd, n as checkCodecServerUrl, o as isEncodedPayload, r as containsEncodedPayload, t as CodecServerError } from "./codec-client-CAYl6j46.js";
22
+ import { a as RUN_CONTROL_DIALOG_STYLE, c as parseJsonInput, i as NativeSelect, l as parseJsonObjectInput, n as JsonBlock, o as StatusPill, r as JsonField, s as newRunControlId, t as FieldError, u as useResource } from "./shared-C0LCTtyh.js";
22
23
  import { t as useWorkflowProposal } from "./useWorkflowProposal-B9vXLKef.js";
23
24
  import { t as WorkflowProposalCard } from "./WorkflowProposalCard-SmRv_Egf.js";
24
25
  import { t as AiCreditBalanceSlot } from "./aiCreditsBridge-BuE92tKo.js";
@@ -30,7 +31,6 @@ import { a as formatTokens, d as formatMicroUsd, o as modelLabel, r as aiCost }
30
31
  import { _ as useWorkflowTestsEnabled, l as useDurableFunctionNodesEnabled, m as usePhaseCFlags, u as useDurableParityEnabled } from "./feature-flags-B_b8PJ6Z.js";
31
32
  import { A as revokeSignalToken, B as updateActivityOptions, D as resetActivities, E as queryRun, N as sendRunUpdate, O as resetRun, R as unpauseActivities, S as fetchSignalTokens, V as upsertRunSearchAttributes, _ as fetchPauseRules, b as fetchRunUpdate, d as failActivityById, g as fetchCodecServerSettings, i as completeActivityById, k as resetRunToLastCleanTask, s as createSignalToken, v as fetchRunControlFields, w as pauseActivities, y as fetchRunHistoryArchive } from "./api-CEnNq15C.js";
32
33
  import { a as fetchTaskQueueStats } from "./api-DKfMt0IX.js";
33
- import { a as RUN_CONTROL_DIALOG_STYLE, c as parseJsonInput, i as NativeSelect, l as parseJsonObjectInput, n as JsonBlock, o as StatusPill, r as JsonField, s as newRunControlId, t as FieldError, u as useResource } from "./shared-C0LCTtyh.js";
34
34
  import { v as useWorkflowVersions } from "./useWorkflows-BrqrVT8h.js";
35
35
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
36
36
  import { Link, useNavigate, useParams, useSearchParams } from "react-router";
@@ -1611,14 +1611,14 @@ function RunHumanRequestRow({ request, plain }) {
1611
1611
  * instead of `steps`. Output is free-form JSON, so every read is defensive:
1612
1612
  * a field of an unexpected shape is skipped, never thrown on.
1613
1613
  */
1614
- function isRecord$3(value) {
1614
+ function isRecord$4(value) {
1615
1615
  return typeof value === "object" && value !== null && !Array.isArray(value);
1616
1616
  }
1617
1617
  function asRecord(value) {
1618
- if (isRecord$3(value)) return value;
1618
+ if (isRecord$4(value)) return value;
1619
1619
  if (typeof value === "string") {
1620
1620
  const parsed = tryParseJson(value);
1621
- return isRecord$3(parsed) ? parsed : null;
1621
+ return isRecord$4(parsed) ? parsed : null;
1622
1622
  }
1623
1623
  return null;
1624
1624
  }
@@ -1680,7 +1680,7 @@ function classifyObservation(observation) {
1680
1680
  };
1681
1681
  }
1682
1682
  function toStep(raw, index) {
1683
- if (!isRecord$3(raw)) return null;
1683
+ if (!isRecord$4(raw)) return null;
1684
1684
  const tool = stringOrNull(raw.tool) ?? stringOrNull(raw.toolName) ?? stringOrNull(raw.action) ?? stringOrNull(raw.name);
1685
1685
  if (!tool) return null;
1686
1686
  const observationRaw = raw.observation ?? raw.output ?? raw.result;
@@ -1709,7 +1709,7 @@ function toPendingApprovals(raw) {
1709
1709
  if (!Array.isArray(raw)) return [];
1710
1710
  const pending = [];
1711
1711
  for (const item of raw) {
1712
- if (!isRecord$3(item)) continue;
1712
+ if (!isRecord$4(item)) continue;
1713
1713
  const tool = stringOrNull(item.name) ?? stringOrNull(item.tool);
1714
1714
  if (!tool) continue;
1715
1715
  const callId = stringOrNull(item.id) ?? stringOrNull(item.callId);
@@ -1731,7 +1731,7 @@ const PAYLOAD_KEYS = [
1731
1731
  "intermediateSteps"
1732
1732
  ];
1733
1733
  function looksLikeAgentPayload(value) {
1734
- return isRecord$3(value) && PAYLOAD_KEYS.some((key) => key in value);
1734
+ return isRecord$4(value) && PAYLOAD_KEYS.some((key) => key in value);
1735
1735
  }
1736
1736
  /**
1737
1737
  * The agent payload inside a node output: the output itself when it carries
@@ -3181,7 +3181,7 @@ function RunDataPrunedNotice({ dataPrunedAt }) {
3181
3181
  }
3182
3182
 
3183
3183
  // src/modules/executions/utils/run-queue-marker.ts
3184
- function isRecord$2(value) {
3184
+ function isRecord$3(value) {
3185
3185
  return typeof value === "object" && value !== null && !Array.isArray(value);
3186
3186
  }
3187
3187
  function isRunQueueScope(value) {
@@ -3189,9 +3189,9 @@ function isRunQueueScope(value) {
3189
3189
  }
3190
3190
  /** The queue marker on a run's context, or null when there is none or it is malformed. */
3191
3191
  function readRunQueueMarker(context) {
3192
- if (!isRecord$2(context)) return null;
3192
+ if (!isRecord$3(context)) return null;
3193
3193
  const marker = context.concurrency;
3194
- if (!isRecord$2(marker)) return null;
3194
+ if (!isRecord$3(marker)) return null;
3195
3195
  const { queuedAt, checkedAt, limit, active, position, scope } = marker;
3196
3196
  if (typeof queuedAt !== "string" || typeof checkedAt !== "string" || typeof limit !== "number" || typeof active !== "number" || typeof position !== "number" || scope !== void 0 && !isRunQueueScope(scope)) return null;
3197
3197
  return {
@@ -3250,6 +3250,65 @@ function RunQueuedBanner({ status, context }) {
3250
3250
  });
3251
3251
  }
3252
3252
 
3253
+ // src/modules/executions/components/RulePausedBanner.tsx
3254
+ /**
3255
+ * *Paused by rule* on a graph run (BOFF-13553, spec code-first 11 §2.28,
3256
+ * HC5): the nodes an activity pause rule holds, each with the rule's reason.
3257
+ * The run continues by itself once the rule is deleted or expires, so the
3258
+ * banner says so instead of offering Resume (the service refuses a generic
3259
+ * resume for a held node).
3260
+ */
3261
+ function RulePausedBanner({ nodes }) {
3262
+ const tr = useTr();
3263
+ if (nodes.length === 0) return null;
3264
+ return /* @__PURE__ */ jsxs("section", {
3265
+ "data-testid": "rule-paused-banner",
3266
+ className: "mb-6 rounded-md border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bg-subtle)] p-3",
3267
+ children: [
3268
+ /* @__PURE__ */ jsxs("div", {
3269
+ className: "mb-2 flex items-center gap-2",
3270
+ children: [/* @__PURE__ */ jsx(Icon, {
3271
+ icon: "mdi:pause-octagon-outline",
3272
+ width: 16,
3273
+ className: "text-[var(--color-status-warning-text)]"
3274
+ }), /* @__PURE__ */ jsx("h4", {
3275
+ className: "text-sm font-medium text-text-primary",
3276
+ children: tr("fluidgrids.executions.rulePaused.title", "Held by a pause rule")
3277
+ })]
3278
+ }),
3279
+ /* @__PURE__ */ jsx("p", {
3280
+ className: "mb-2 text-sm text-text-secondary",
3281
+ children: tr("fluidgrids.executions.rulePaused.body", "A workspace pause rule holds these steps. The run continues by itself when the rule is deleted or expires (Settings → Execution → Pause rules).")
3282
+ }),
3283
+ /* @__PURE__ */ jsx("ul", {
3284
+ className: "space-y-1",
3285
+ children: nodes.map((node) => /* @__PURE__ */ jsxs("li", {
3286
+ className: "flex flex-wrap items-center gap-2 text-sm",
3287
+ "data-testid": "rule-paused-node",
3288
+ children: [
3289
+ /* @__PURE__ */ jsx("code", {
3290
+ className: "font-mono text-xs text-text-primary",
3291
+ children: node.nodeId
3292
+ }),
3293
+ /* @__PURE__ */ jsx("span", {
3294
+ title: node.reason ?? void 0,
3295
+ children: /* @__PURE__ */ jsx(StatusPill, {
3296
+ tone: "warning",
3297
+ testId: "node-paused-by-rule",
3298
+ children: tr("fluidgrids.runControl.activities.pausedByRule", "Paused by rule")
3299
+ })
3300
+ }),
3301
+ node.reason && /* @__PURE__ */ jsx("span", {
3302
+ className: "text-xs text-text-secondary",
3303
+ children: node.reason
3304
+ })
3305
+ ]
3306
+ }, node.nodeId))
3307
+ })
3308
+ ]
3309
+ });
3310
+ }
3311
+
3253
3312
  // src/modules/executions/components/RunBudgetPanel.tsx
3254
3313
  /**
3255
3314
  * Run detail: the run's AI budget (BOFF-9943).
@@ -4028,6 +4087,37 @@ function WaitingAtPanel({ trace, loading, error, onRefresh, metadata }) {
4028
4087
  });
4029
4088
  }
4030
4089
 
4090
+ // src/modules/executions/utils/rule-paused-nodes.ts
4091
+ /** The waiting marker of a graph node a pause rule holds. */
4092
+ const RULE_PAUSED_WAIT = "activity_paused";
4093
+ function isRecord$2(value) {
4094
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4095
+ }
4096
+ function str(value) {
4097
+ return typeof value === "string" && value.trim() ? value : null;
4098
+ }
4099
+ /** Whether a node state is a graph node held by a pause rule. */
4100
+ function isRulePausedNode(state) {
4101
+ return state.status === "WAITING" && isRecord$2(state.output) && state.output._waiting === "activity_paused";
4102
+ }
4103
+ /** The held nodes of a run, one entry per node id, in node-state order. */
4104
+ function rulePausedNodes(nodeStates) {
4105
+ const result = [];
4106
+ const seen = /* @__PURE__ */ new Set();
4107
+ for (const state of nodeStates ?? []) {
4108
+ if (!isRulePausedNode(state) || seen.has(state.nodeId)) continue;
4109
+ seen.add(state.nodeId);
4110
+ const output = state.output;
4111
+ result.push({
4112
+ nodeId: state.nodeId,
4113
+ ruleId: str(output._pauseRuleId),
4114
+ reason: str(output._pauseReason),
4115
+ pausedAt: str(output._pausedAt)
4116
+ });
4117
+ }
4118
+ return result;
4119
+ }
4120
+
4031
4121
  // src/modules/executions/utils/detail-tab.ts
4032
4122
  function resolveDetailTab(selection, runId, available, fallback) {
4033
4123
  if (selection.runId !== runId) return fallback;
@@ -7971,6 +8061,12 @@ function ExecutionDetailPage() {
7971
8061
  }, [durableEnabled, execution]);
7972
8062
  const canSendSignal = canControlRuns && canSignalRun(signalTargets);
7973
8063
  const waitingOnSignal = !isDurableRun && signalTargets.targets.some((target) => !!target.nodeId);
8064
+ const heldByRule = useMemo(() => !isDurableRun && execution?.status === "WAITING" ? rulePausedNodes(execution.nodeStates) : [], [
8065
+ isDurableRun,
8066
+ execution?.status,
8067
+ execution?.nodeStates
8068
+ ]);
8069
+ const offerGenericResume = humanRequestsCurrent && !awaitingPerson && !isDurableRun && !waitingOnSignal && heldByRule.length === 0;
7974
8070
  const handleControl = async (action) => {
7975
8071
  if (!runId) return;
7976
8072
  const result = await controlExecution(action, runId);
@@ -8677,7 +8773,7 @@ function ExecutionDetailPage() {
8677
8773
  }), tr("fluidgrids.executions.executionDetail.cancelButton", "Cancel")]
8678
8774
  })] }),
8679
8775
  canControlRuns && execution.status === "WAITING" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
8680
- humanRequestsCurrent && !awaitingPerson && !isDurableRun && !waitingOnSignal && /* @__PURE__ */ jsxs(Button$1, {
8776
+ offerGenericResume && /* @__PURE__ */ jsxs(Button$1, {
8681
8777
  "data-agent": "confirm",
8682
8778
  variant: "outline",
8683
8779
  size: "sm",
@@ -8951,6 +9047,7 @@ function ExecutionDetailPage() {
8951
9047
  status: execution.status,
8952
9048
  context: execution.context
8953
9049
  }),
9050
+ /* @__PURE__ */ jsx(RulePausedBanner, { nodes: heldByRule }),
8954
9051
  /* @__PURE__ */ jsx(RunDataPrunedNotice, { dataPrunedAt: execution.dataPrunedAt }),
8955
9052
  /* @__PURE__ */ jsx(RunBudgetPanel, { budget: execution.budget }),
8956
9053
  /* @__PURE__ */ jsx(ChildRunsPanel, {
@@ -1,5 +1,5 @@
1
1
  "use client";
2
2
  import { t as ExecutionsListPage } from "./ExecutionsListPage-Ky3TAL9U.js";
3
- import { t as ExecutionDetailPage } from "./ExecutionDetailPage-heD4wBjg.js";
3
+ import { t as ExecutionDetailPage } from "./ExecutionDetailPage-B-8s_Sqw.js";
4
4
 
5
5
  export { ExecutionDetailPage, ExecutionsListPage };
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { _ as WorkflowRunsCountDocument, b as DurableParityRunFieldsDocument, v
15
15
  import { c as RunEventAppendedDocument, d as WorkflowRunDeterminismStatusDocument, f as DurableRunFieldsDocument, l as WorkflowRunStackTraceDocument, m as SignalWorkflowRunDocument, p as TerminateWorkflowRunDocument, u as WorkflowRunHistoryDocument } from "./useRunHistory-Be-GggNA.js";
16
16
  import { a as getGraphQLEndpoint, c as setFluidGridsConfig, d as applyFluidGridsTheme, f as sanitizeThemeValue, m as themeToCssVariables, o as resetFluidGridsConfig, p as themeKey, r as getFluidGridsConfig, s as resetFluidGridsExecutionState, t as config, u as FLUIDGRIDS_THEME_TOKEN_MAP } from "./config-X97zrIvn.js";
17
17
  import { r as WorkflowBatchOperationUpdatedDocument, t as ExecutionsListPage } from "./ExecutionsListPage-Ky3TAL9U.js";
18
- import { a as AgentStepUpdatedDocument, c as AgentTraceDocument, i as ExplainRunDocument, o as WorkflowRunHierarchyDocument, r as RunHumanRequests, s as RunAiUsageDocument, t as ExecutionDetailPage } from "./ExecutionDetailPage-heD4wBjg.js";
18
+ import { a as AgentStepUpdatedDocument, c as AgentTraceDocument, i as ExplainRunDocument, o as WorkflowRunHierarchyDocument, r as RunHumanRequests, s as RunAiUsageDocument, t as ExecutionDetailPage } from "./ExecutionDetailPage-B-8s_Sqw.js";
19
19
  import { i as FileDownloadUrlDocument, n as WorkflowCodeSourceDocument, r as BuildWorkflowCodeDocument, t as WorkflowEditLeaseStatusDocument } from "./WorkflowEditLeaseStatusDocument-Dp62med3.js";
20
20
  import { c as RunLogAppendedDocument, l as RunLogsDocument } from "./agent-form-D0uLvzx4.js";
21
21
  import { C as CreateWorkflowTestCaseFromRunDocument, D as AgentTokenDeltaDocument, E as CreateWorkflowTestCaseDocument, S as RunWorkflowTestsDocument, T as UpdateWorkflowTestCaseDocument, b as WorkflowTestRunDocument, w as DeleteWorkflowTestCaseDocument, x as WorkflowTestCasesDocument, y as WorkflowTestRunsDocument } from "./use-workflow-tests-Dkij09vJ.js";
@@ -5254,7 +5254,7 @@ const FluidgridsAvailableTagFieldsFragmentDoc = {
5254
5254
  const WorkflowsList$1 = lazy(() => import("./WorkflowsList-4VADoiz_.js").then((n) => n.n).then((m) => ({ default: m.WorkflowsList })));
5255
5255
  const WorkflowBuilder$2 = lazy(() => import("./WorkflowBuilder-DkzzbrNn.js").then((n) => n.n).then((m) => ({ default: m.WorkflowBuilder })));
5256
5256
  const ExecutionsListPage$1 = lazy(() => import("./ExecutionsListPage-Ky3TAL9U.js").then((n) => n.n).then((m) => ({ default: m.ExecutionsListPage })));
5257
- const ExecutionDetailPage$1 = lazy(() => import("./ExecutionDetailPage-heD4wBjg.js").then((n) => n.n).then((m) => ({ default: m.ExecutionDetailPage })));
5257
+ const ExecutionDetailPage$1 = lazy(() => import("./ExecutionDetailPage-B-8s_Sqw.js").then((n) => n.n).then((m) => ({ default: m.ExecutionDetailPage })));
5258
5258
  const PageLoader = () => /* @__PURE__ */ jsx("div", {
5259
5259
  className: "flex items-center justify-center h-64",
5260
5260
  children: /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" })
@@ -60,7 +60,7 @@ const pages = createWorkflowPages({
60
60
  TemplatePreview: () => import("./TemplatePreview-DwdGa8bH.js").then((n) => n.n),
61
61
  AiStudioPage: () => import("./AiStudioPage-C2SBRqab.js").then((n) => n.n),
62
62
  ExecutionsListPage: () => import("./ExecutionsListPage-Ky3TAL9U.js").then((n) => n.n),
63
- ExecutionDetailPage: () => import("./ExecutionDetailPage-heD4wBjg.js").then((n) => n.n),
63
+ ExecutionDetailPage: () => import("./ExecutionDetailPage-B-8s_Sqw.js").then((n) => n.n),
64
64
  HistoryPage: () => import("./HistoryPage-D4rkw4zu.js").then((n) => n.n),
65
65
  TemplatesPage: () => import("./TemplatesPage-DF5PK7CB.js").then((n) => n.n),
66
66
  NodesPage: () => import("./NodesPage-C3sh0aL9.js").then((n) => n.n),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/fluidgrids-fe-sdk",
3
- "version": "2026.1114.5",
3
+ "version": "2026.1114.6",
4
4
  "description": "FluidGrids Workflow Builder SDK - Embeddable visual workflow automation",
5
5
  "type": "module",
6
6
  "imports": {