@burdenoff/fluidgrids-fe-sdk 2026.1111.16 → 2026.1111.18

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 (119) hide show
  1. package/README.md +41 -0
  2. package/dist/AiStudioPage-BHVEU4Wp.js +774 -0
  3. package/dist/ApprovalInboxPage-dbBDSJ-f.js +558 -0
  4. package/dist/DataSinkDashboardPage-1h2QsMzH.js +270 -0
  5. package/dist/DataTablesPage-BZy2z0LB.js +1690 -0
  6. package/dist/EntityTagPicker-BqRNsLCQ.js +135 -0
  7. package/dist/{ExecutionDetailPage-D-0_POAf.js → ExecutionDetailPage-BdcZmLT4.js} +799 -4420
  8. package/dist/ExecutionDetailPage-DvQ667OE.d.ts +10 -0
  9. package/dist/ExecutionsListPage-BCUJoAIE.js +2742 -0
  10. package/dist/{FailureTriagePanel-BHiduL7A.js → FailureTriagePanel-B9hDQymi.js} +4 -97
  11. package/dist/{FluidGridsProvider-DmvFADFa.js → FluidGridsProvider-dvZSNtSW.js} +10 -350
  12. package/dist/HistoryPage-BLoRpJ1R.d.ts +6 -0
  13. package/dist/{HistoryPage-BbUgxx1I.js → HistoryPage-U0tqupBN.js} +6 -4
  14. package/dist/HumanRequestCard-D-ooVPDn.js +439 -0
  15. package/dist/{InsightsPage-s6f5bU-8.js → InsightsPage-CALo16eB.js} +17 -328
  16. package/dist/ManagedAiPolicyAuthority-BxwJ3ptd.js +40 -0
  17. package/dist/{ManagedAiPolicyAuthority-CGux_DaV.d.ts → ManagedAiPolicyAuthority-DM3t3wNr.d.ts} +1 -5
  18. package/dist/ManagedAiPolicyAuthorityContext-CNkxIOZ1.js +10 -0
  19. package/dist/{MissingNodesInstallModal-B-9gHy2K.js → MissingNodesInstallModal-CMybsI8h.js} +3 -2
  20. package/dist/{NodesPage-ClvhUfbh.js → NodesPage-Bf5PhfBK.js} +7 -3
  21. package/dist/NodesPage-DEbnz9iU.d.ts +6 -0
  22. package/dist/{PublishCustomNodeAction-D2F7oN0S.js → PublishCustomNodeAction-5XXnSA3H.js} +3 -45
  23. package/dist/QuotaExhaustedDialog-7IFSaLyi.js +54 -0
  24. package/dist/RunnerStatusPill-Ctg4TJcP.js +187 -0
  25. package/dist/RunnersPage-CLCOCclc.js +467 -0
  26. package/dist/{ManagedAiPolicyAuthority-DsSaz-vg.js → SettingsPage-CJLZvv4J.js} +743 -773
  27. package/dist/SettingsPage-DMHQFj5-.d.ts +9 -0
  28. package/dist/TagFilterSelect-DCBOH6Ou.js +41 -0
  29. package/dist/TaskQueuesPage-9VgSnLdL.js +951 -0
  30. package/dist/TemplateCard-DsC0KNH1.js +1416 -0
  31. package/dist/{TemplateConfigurationModal-D_Mvgxqa.js → TemplateConfigurationModal-BhGWIzpm.js} +3 -2
  32. package/dist/{TemplateDetailPanel-DfFfUcOe.js → TemplateDetailPanel-D4cUVr-m.js} +3 -3
  33. package/dist/TemplatePreview-FayF6jxh.js +231 -0
  34. package/dist/TemplatesPage-BG3H-6v6.d.ts +10 -0
  35. package/dist/{TemplatesPage-Cku13bav.js → TemplatesPage-CsDNT54N.js} +11 -228
  36. package/dist/VariablesPage-67WR_lVE.js +949 -0
  37. package/dist/{VersionDiffDialog-Dq2xlPFI.js → VersionDiffDialog-DSN0mU0f.js} +2 -1
  38. package/dist/WorkflowBuilder-CPnXEL5J.js +555 -0
  39. package/dist/{WorkflowSearchRedirect-CaoOOpEl.js → WorkflowBuilder-YXRysvZc.js} +19 -585
  40. package/dist/{WorkflowProposalCard-8Vr56kQa.js → WorkflowProposalCard-qrEeNyYG.js} +4 -405
  41. package/dist/WorkflowSearchRedirect-DwDNZ_q5.js +36 -0
  42. package/dist/WorkflowShareDialog-mbIwRQUY.js +168 -0
  43. package/dist/WorkflowsList-CcNDQge5.d.ts +6 -0
  44. package/dist/{WorkflowsList-B2j1Pehb.js → WorkflowsList-DiiGyZkT.js} +12 -6
  45. package/dist/agent-form-Bfvm32j1.js +83 -0
  46. package/dist/{agentTools-DJ5o2ekg.js → agentTools-8s_25Q_F.js} +3 -2
  47. package/dist/{ai-usage-D5p7ZeRR.js → ai-usage-glCwHyQz.js} +1 -1
  48. package/dist/api-BrCHB5oA.js +224 -0
  49. package/dist/api-C8e0iV-Q.js +55 -0
  50. package/dist/button-DG7y_FVJ.js +48 -0
  51. package/dist/{canvasNoteTools-D3zUdEeg.js → canvasNoteTools-B6pYARgU.js} +2 -2
  52. package/dist/client-C9XSzSXr.js +1147 -0
  53. package/dist/code-editor-field-9-GdVE_8.js +111 -0
  54. package/dist/{codec-client-DstqyzTN.js → codec-client-CJ95Rmqo.js} +1 -1
  55. package/dist/constants-B2lhWNoN.js +202 -0
  56. package/dist/constants-XdvUxeWK.d.ts +162 -0
  57. package/dist/dialog-Cjb4lB4D.js +105 -0
  58. package/dist/executions.d.ts +1 -1
  59. package/dist/executions.js +2 -1
  60. package/dist/feature-flags-DM5myWaD.js +296 -0
  61. package/dist/flags.d.ts +3 -0
  62. package/dist/flags.js +4 -0
  63. package/dist/{flow-builder-DEzT8TQu.js → flow-builder-CZDKRc6f.js} +662 -10716
  64. package/dist/{node-endpoint-configs-DHFGA5MQ.js → graphql-operation-types-kX-MMjgW.js} +1 -1194
  65. package/dist/{graphql-types-XcDLtFwU.js → graphql-types-CDKVWH2R.js} +2 -202
  66. package/dist/history.d.ts +1 -1
  67. package/dist/history.js +1 -1
  68. package/dist/{index-DRf25-D3.d.ts → index-6JR2vD9J.d.ts} +33 -215
  69. package/dist/index-72XFgvbn.d.ts +132 -0
  70. package/dist/index-BcdtKBM-.d.ts +56 -0
  71. package/dist/{index-B3BWqafN.d.ts → index-DjiFgEQl.d.ts} +5 -131
  72. package/dist/index.d.ts +13 -9
  73. package/dist/index.js +52 -5300
  74. package/dist/{node-detail-view-LNqeIqN-.js → node-detail-view-CV4ZRwqh.js} +13 -8
  75. package/dist/node-editor-tab-body-DU-dh35X.js +174 -0
  76. package/dist/node-endpoint-configs-B5bjNMDW.js +37 -0
  77. package/dist/node-registry-refresh-Dy0uRg9f.js +84 -0
  78. package/dist/nodes.d.ts +1 -1
  79. package/dist/nodes.js +1 -1
  80. package/dist/observability.d.ts +1 -1
  81. package/dist/observability.js +2 -1
  82. package/dist/popover-BJHvrFGR.js +472 -0
  83. package/dist/{quick-config-panel-D3ogsaFL.js → quick-config-panel-ws3pLvbt.js} +3 -2
  84. package/dist/rolldown-runtime-hDbaFkMy.js +18 -0
  85. package/dist/run-display-BycKYSU0.js +46 -0
  86. package/dist/run-list-links-ByYC0OlV.js +98 -0
  87. package/dist/schedule-panel-C0mfGQSD.js +7542 -0
  88. package/dist/settings.d.ts +2 -1
  89. package/dist/settings.js +2 -1
  90. package/dist/shared-CMfn30xT.js +196 -0
  91. package/dist/sidebar-node-editor-CR1PiZO-.js +177 -0
  92. package/dist/templates.d.ts +1 -1
  93. package/dist/templates.js +2 -1
  94. package/dist/theme-provider-B3mIuz2d.js +11 -0
  95. package/dist/{useAgentDefinitions-NFtLytDR.js → useAgentDefinitions-B0dam3_o.js} +3 -397
  96. package/dist/useConnections-Cs7LCWEM.js +401 -0
  97. package/dist/useDurableParity-CzUQMFJ3.js +415 -0
  98. package/dist/useEntityTags-DhnsZcTl.js +236 -0
  99. package/dist/{useExecutions-DAzeWHS6.js → useExecutions-9aLuOt1c.js} +4 -3
  100. package/dist/{useObservability-COCZ0hUS.js → useObservability-CfEw3ZFD.js} +2 -2
  101. package/dist/{useRunHistory-CsYUbouO.js → useRunHistory-B1xJDwl1.js} +4 -3
  102. package/dist/{WorkflowShareDialog-6RRDe-_v.js → useWorkflowCodeExport-Bu2QYJzA.js} +7 -210
  103. package/dist/{useWorkflows-w4Dx2fF2.js → useWorkflows-BlVVu8NM.js} +3 -2
  104. package/dist/utils-uaL5UVxb.js +65 -0
  105. package/dist/workflow-builder.d.ts +1 -1
  106. package/dist/workflow-builder.js +4 -2
  107. package/dist/workflow-host.d.ts +6 -0
  108. package/dist/workflow-host.js +9 -0
  109. package/dist/workflow-pages.d.ts +55 -0
  110. package/dist/workflow-pages.js +113 -0
  111. package/dist/workflows-list.d.ts +1 -1
  112. package/dist/workflows-list.js +1 -1
  113. package/package.json +13 -1
  114. package/dist/ExecutionDetailPage-MvsnOnE1.d.ts +0 -4
  115. package/dist/HistoryPage-BqUizaFv.d.ts +0 -3
  116. package/dist/NodesPage-C97-9K2Y.d.ts +0 -3
  117. package/dist/TemplatesPage-D0qnXzHh.d.ts +0 -4
  118. package/dist/WorkflowsList-0d5GSKdh.d.ts +0 -3
  119. package/dist/agent-form-BvMWhQ42.js +0 -496
@@ -0,0 +1,558 @@
1
+ "use client";
2
+ import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
3
+ import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
4
+ import { r as usePendingHumanRequests, t as HumanRequestCard } from "./HumanRequestCard-D-ooVPDn.js";
5
+ import { t as FluidGridsDocsLink } from "./FluidGridsDocsLink-JxkBpOeb.js";
6
+ import { _ as throwIfResultError, h as isForbiddenError, n as getFluidGridsClient } from "./client-C9XSzSXr.js";
7
+ import { i as SdkPermissionButton, s as useFluidGridsPermission, t as FLUIDGRIDS_PERMISSIONS } from "./constants-B2lhWNoN.js";
8
+ import { useCallback, useEffect, useState } from "react";
9
+ import { useNavigate } from "react-router";
10
+ import { Icon } from "@iconify/react";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
+ import { toast } from "sonner";
13
+ import { gql } from "@apollo/client";
14
+ import { Badge, Card, CardContent, CardHeader, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Label, Textarea } from "@burdenoff/fe-libs/ui";
15
+ import { Button as Button$1 } from "@burdenoff/fe-libs/button";
16
+
17
+ // src/modules/tool-approval/hooks/useToolApprovals.ts
18
+ /**
19
+ * Custom hooks for the AI Agent tool-approval inbox (BOFF-7521).
20
+ * Queries/mutates wspace-workflow-svc via the federated GraphQL gateway —
21
+ * mirrors the variables module's hook pattern
22
+ * (`modules/variables/hooks/useVariables.ts`).
23
+ */
24
+ const TOOL_APPROVAL_FIELDS = gql`
25
+ fragment ToolApprovalRequestFields on ToolApprovalRequest {
26
+ id
27
+ runId
28
+ nodeId
29
+ workflowId
30
+ workflowKey
31
+ status
32
+ toolCalls {
33
+ callId
34
+ name
35
+ argsJson
36
+ }
37
+ decisions {
38
+ callId
39
+ decision
40
+ reason
41
+ }
42
+ timeoutAt
43
+ timeoutAction
44
+ requestedAt
45
+ decidedAt
46
+ decidedBy
47
+ }
48
+ `;
49
+ const GET_PENDING_TOOL_APPROVALS = gql`
50
+ ${TOOL_APPROVAL_FIELDS}
51
+ query GetPendingToolApprovals($limit: Int, $offset: Int) {
52
+ pendingToolApprovals(limit: $limit, offset: $offset) {
53
+ totalCount
54
+ items {
55
+ ...ToolApprovalRequestFields
56
+ }
57
+ }
58
+ }
59
+ `;
60
+ const DECIDE_TOOL_APPROVAL = gql`
61
+ ${TOOL_APPROVAL_FIELDS}
62
+ mutation DecideToolApproval(
63
+ $id: ID!
64
+ $decisions: [ToolApprovalDecisionInput!]!
65
+ ) {
66
+ decideToolApproval(id: $id, decisions: $decisions) {
67
+ success
68
+ error
69
+ resumedFromNodeId
70
+ request {
71
+ ...ToolApprovalRequestFields
72
+ }
73
+ }
74
+ }
75
+ `;
76
+ /**
77
+ * Polls the pending tool-approval inbox. Short polling interval (not a
78
+ * subscription) — approvals are rare/low-volume and the caller wants a
79
+ * near-real-time inbox without standing up a dedicated subscription channel
80
+ * for a v1 feature.
81
+ *
82
+ * Pass `enabled: false` when the caller lacks `tool-approval-request:read`:
83
+ * the query is then never sent, so the gateway's FORBIDDEN never reaches the
84
+ * shell's global error toast (BOFF-10104). If the gateway still denies the
85
+ * query, `forbidden` turns true and polling stops.
86
+ */
87
+ function usePendingToolApprovals(options) {
88
+ const limit = options?.limit ?? 50;
89
+ const offset = options?.offset ?? 0;
90
+ const pollIntervalMs = options?.pollIntervalMs ?? 15e3;
91
+ const enabled = options?.enabled ?? true;
92
+ const [items, setItems] = useState([]);
93
+ const [totalCount, setTotalCount] = useState(0);
94
+ const [loading, setLoading] = useState(enabled);
95
+ const [error, setError] = useState(null);
96
+ const [forbidden, setForbidden] = useState(false);
97
+ const fetchData = useCallback(async () => {
98
+ if (!enabled) return;
99
+ setError(null);
100
+ try {
101
+ const client = getFluidGridsClient();
102
+ const result = throwIfResultError(await client.query({
103
+ query: GET_PENDING_TOOL_APPROVALS,
104
+ variables: {
105
+ limit,
106
+ offset
107
+ },
108
+ fetchPolicy: "network-only"
109
+ }));
110
+ setItems(result.data?.pendingToolApprovals?.items ?? []);
111
+ setTotalCount(result.data?.pendingToolApprovals?.totalCount ?? 0);
112
+ } catch (err) {
113
+ if (isForbiddenError(err)) {
114
+ setForbidden(true);
115
+ setItems([]);
116
+ setTotalCount(0);
117
+ } else setError(err);
118
+ } finally {
119
+ setLoading(false);
120
+ }
121
+ }, [
122
+ enabled,
123
+ limit,
124
+ offset
125
+ ]);
126
+ useEffect(() => {
127
+ setForbidden(false);
128
+ if (!enabled) {
129
+ setItems([]);
130
+ setTotalCount(0);
131
+ setError(null);
132
+ }
133
+ }, [enabled]);
134
+ useEffect(() => {
135
+ if (!enabled || forbidden) {
136
+ setLoading(false);
137
+ return;
138
+ }
139
+ setLoading(true);
140
+ fetchData();
141
+ if (pollIntervalMs <= 0) return;
142
+ const interval = setInterval(fetchData, pollIntervalMs);
143
+ return () => clearInterval(interval);
144
+ }, [
145
+ enabled,
146
+ fetchData,
147
+ forbidden,
148
+ pollIntervalMs
149
+ ]);
150
+ return {
151
+ items,
152
+ totalCount,
153
+ loading,
154
+ error,
155
+ forbidden: forbidden || !enabled,
156
+ refetch: fetchData
157
+ };
158
+ }
159
+ function useDecideToolApproval() {
160
+ const [loading, setLoading] = useState(false);
161
+ const [error, setError] = useState(null);
162
+ const decide = useCallback(async (id, decisions) => {
163
+ setLoading(true);
164
+ setError(null);
165
+ try {
166
+ const client = getFluidGridsClient();
167
+ const response = throwIfResultError(await client.mutate({
168
+ mutation: DECIDE_TOOL_APPROVAL,
169
+ variables: {
170
+ id,
171
+ decisions
172
+ }
173
+ })).data?.decideToolApproval;
174
+ if (!response?.success) throw new Error(response?.error ?? "Failed to record the decision");
175
+ return response;
176
+ } catch (err) {
177
+ setError(err);
178
+ throw err;
179
+ } finally {
180
+ setLoading(false);
181
+ }
182
+ }, []);
183
+ return {
184
+ decide,
185
+ decideAll: useCallback(async (request, decision, reason) => {
186
+ return decide(request.id, request.toolCalls.map((call) => ({
187
+ callId: call.callId,
188
+ decision,
189
+ reason
190
+ })));
191
+ }, [decide]),
192
+ loading,
193
+ error
194
+ };
195
+ }
196
+
197
+ // src/modules/tool-approval/utils/timeout.ts
198
+ /**
199
+ * Classifies timeout metadata without changing server-owned request status.
200
+ * The timeout sweep remains authoritative for auto-resolving WAITING runs.
201
+ */
202
+ function getToolApprovalTimeoutState(timeoutAt, nowMs = Date.now()) {
203
+ if (!timeoutAt) return "NONE";
204
+ const timeoutMs = Date.parse(timeoutAt);
205
+ if (!Number.isFinite(timeoutMs)) return "NONE";
206
+ return timeoutMs <= nowMs ? "DUE" : "ACTIVE";
207
+ }
208
+
209
+ // src/modules/tool-approval/pages/ApprovalInboxPage.tsx
210
+ /**
211
+ * Tool Approval Inbox (BOFF-7521)
212
+ *
213
+ * Human-in-the-loop gate for AI Agent tool calls: lists every run currently
214
+ * paused waiting for a decision, shows the proposed tool call(s) and their
215
+ * arguments, and lets the reviewer approve or reject the whole batch (or, in
216
+ * a future iteration, individual calls). Approving/rejecting resumes the
217
+ * underlying run via `decideToolApproval`, which reuses the exact same
218
+ * WAITING/`resumeWorkflowRun` mechanism the Wait node uses.
219
+ */
220
+ var ApprovalInboxPage_exports = /* @__PURE__ */ __exportAll({ ApprovalInboxPage: () => ApprovalInboxPage });
221
+ function formatArgs(argsJson) {
222
+ try {
223
+ return JSON.stringify(JSON.parse(argsJson), null, 2);
224
+ } catch {
225
+ return argsJson;
226
+ }
227
+ }
228
+ function timeAgo(iso, tr) {
229
+ const then = new Date(iso).getTime();
230
+ const diffMs = Date.now() - then;
231
+ const minutes = Math.floor(diffMs / 6e4);
232
+ if (minutes < 1) return tr("fluidgrids.toolApproval.justNow", "just now");
233
+ if (minutes < 60) return tr("fluidgrids.toolApproval.minutesAgo", "{{minutes}}m ago", { minutes });
234
+ const hours = Math.floor(minutes / 60);
235
+ if (hours < 24) return tr("fluidgrids.toolApproval.hoursAgo", "{{hours}}h ago", { hours });
236
+ return tr("fluidgrids.toolApproval.daysAgo", "{{days}}d ago", { days: Math.floor(hours / 24) });
237
+ }
238
+ function RejectDialog({ open, onOpenChange, onConfirm, submitting }) {
239
+ const tr = useTr();
240
+ const [reason, setReason] = useState("");
241
+ return /* @__PURE__ */ jsx(Dialog, {
242
+ open,
243
+ onOpenChange,
244
+ children: /* @__PURE__ */ jsxs(DialogContent, { children: [
245
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: tr("fluidgrids.toolApproval.rejectDialogTitle", "Reject tool call") }) }),
246
+ /* @__PURE__ */ jsxs("div", {
247
+ className: "space-y-1.5",
248
+ children: [/* @__PURE__ */ jsx(Label, {
249
+ htmlFor: "reject-reason",
250
+ children: tr("fluidgrids.toolApproval.rejectReasonLabel", "Reason (optional)")
251
+ }), /* @__PURE__ */ jsx(Textarea, {
252
+ id: "reject-reason",
253
+ value: reason,
254
+ onChange: (e) => setReason(e.target.value),
255
+ placeholder: tr("fluidgrids.toolApproval.rejectReasonPlaceholder", "Why is this call being rejected? The agent sees this.")
256
+ })]
257
+ }),
258
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button$1, {
259
+ variant: "outline",
260
+ onClick: () => onOpenChange(false),
261
+ disabled: submitting,
262
+ children: tr("fluidgrids.toolApproval.cancel", "Cancel")
263
+ }), /* @__PURE__ */ jsx(Button$1, {
264
+ variant: "destructive",
265
+ onClick: () => onConfirm(reason),
266
+ disabled: submitting,
267
+ children: submitting ? tr("fluidgrids.toolApproval.rejecting", "Rejecting…") : tr("fluidgrids.toolApproval.rejectConfirm", "Reject")
268
+ })] })
269
+ ] })
270
+ });
271
+ }
272
+ function RequestCard({ request, onDecided }) {
273
+ const tr = useTr();
274
+ const { decideAll, loading } = useDecideToolApproval();
275
+ const [showReject, setShowReject] = useState(false);
276
+ const [nowMs, setNowMs] = useState(() => Date.now());
277
+ const timeoutState = getToolApprovalTimeoutState(request.timeoutAt, nowMs);
278
+ const timeoutDue = timeoutState === "DUE";
279
+ useEffect(() => {
280
+ if (timeoutState !== "ACTIVE") return;
281
+ const interval = setInterval(() => setNowMs(Date.now()), 1e3);
282
+ return () => clearInterval(interval);
283
+ }, [timeoutState]);
284
+ const handleDecide = async (decision, reason) => {
285
+ try {
286
+ await decideAll(request, decision, reason);
287
+ toast.success(decision === "APPROVED" ? tr("fluidgrids.toolApproval.approvedToast", "Tool call approved — run resumed") : tr("fluidgrids.toolApproval.rejectedToast", "Tool call rejected — run resumed"));
288
+ setShowReject(false);
289
+ onDecided();
290
+ } catch (err) {
291
+ toast.error(err instanceof Error ? err.message : tr("fluidgrids.toolApproval.decisionFailed", "Failed to record the decision"));
292
+ }
293
+ };
294
+ return /* @__PURE__ */ jsxs(Card, {
295
+ className: "border border-border-secondary bg-background-secondary",
296
+ "data-testid": "tool-approval-card",
297
+ "data-request-id": request.id,
298
+ children: [
299
+ /* @__PURE__ */ jsxs(CardHeader, {
300
+ className: "pb-3",
301
+ children: [/* @__PURE__ */ jsxs("div", {
302
+ className: "flex flex-wrap items-center justify-between gap-2",
303
+ children: [/* @__PURE__ */ jsxs("div", {
304
+ className: "flex items-center gap-2",
305
+ children: [/* @__PURE__ */ jsx(Icon, {
306
+ icon: "mdi:robot-outline",
307
+ width: 18,
308
+ className: "text-text-secondary"
309
+ }), /* @__PURE__ */ jsxs("span", {
310
+ className: "text-sm font-semibold text-text-primary",
311
+ children: [
312
+ tr("fluidgrids.toolApproval.nodeLabel", "Node"),
313
+ ":",
314
+ " ",
315
+ request.nodeId
316
+ ]
317
+ })]
318
+ }), /* @__PURE__ */ jsx(Badge, {
319
+ variant: "outline",
320
+ className: "font-mono text-[10px]",
321
+ children: request.workflowKey
322
+ })]
323
+ }), /* @__PURE__ */ jsxs("p", {
324
+ className: "text-xs text-text-secondary",
325
+ children: [tr("fluidgrids.toolApproval.requestedAt", "Requested {{when}}", { when: timeAgo(request.requestedAt, tr) }), request.timeoutAt && timeoutDue ? ` · ${tr("fluidgrids.toolApproval.timeoutDue", "timeout reached; automatic decision pending")}` : request.timeoutAt && ` · ${tr("fluidgrids.toolApproval.autoResolvesAt", "auto-resolves at {{time}}", { time: new Date(request.timeoutAt).toLocaleString() })}`]
326
+ })]
327
+ }),
328
+ /* @__PURE__ */ jsxs(CardContent, {
329
+ className: "space-y-3",
330
+ children: [request.toolCalls.map((call) => /* @__PURE__ */ jsxs("div", {
331
+ className: "rounded-md border border-border-secondary bg-background-primary p-3",
332
+ children: [/* @__PURE__ */ jsxs("div", {
333
+ className: "mb-1 flex items-center gap-2",
334
+ children: [/* @__PURE__ */ jsx(Icon, {
335
+ icon: "mdi:function-variant",
336
+ width: 14,
337
+ className: "text-text-secondary"
338
+ }), /* @__PURE__ */ jsx("span", {
339
+ className: "text-sm font-medium text-text-primary",
340
+ children: call.name
341
+ })]
342
+ }), /* @__PURE__ */ jsx("pre", {
343
+ className: "overflow-x-auto whitespace-pre-wrap break-all text-xs text-text-secondary",
344
+ children: formatArgs(call.argsJson)
345
+ })]
346
+ }, call.callId)), /* @__PURE__ */ jsxs("div", {
347
+ className: "flex items-center gap-2 pt-1",
348
+ children: [/* @__PURE__ */ jsx(SdkPermissionButton, {
349
+ permission: FLUIDGRIDS_PERMISSIONS.TOOL_APPROVAL_REQUEST_EXECUTE,
350
+ deniedTooltip: tr("fluidgrids.toolApproval.decideDeniedTooltip", "You don't have permission to decide tool approvals"),
351
+ children: /* @__PURE__ */ jsxs(Button$1, {
352
+ "data-agent": "confirm",
353
+ size: "sm",
354
+ disabled: loading || timeoutDue,
355
+ onClick: () => handleDecide("APPROVED"),
356
+ "data-testid": "tool-approval-approve",
357
+ children: [/* @__PURE__ */ jsx(Icon, {
358
+ icon: "mdi:check",
359
+ className: "mr-1.5",
360
+ width: 16
361
+ }), tr("fluidgrids.toolApproval.approve", "Approve")]
362
+ })
363
+ }), /* @__PURE__ */ jsx(SdkPermissionButton, {
364
+ permission: FLUIDGRIDS_PERMISSIONS.TOOL_APPROVAL_REQUEST_EXECUTE,
365
+ deniedTooltip: tr("fluidgrids.toolApproval.decideDeniedTooltip", "You don't have permission to decide tool approvals"),
366
+ children: /* @__PURE__ */ jsxs(Button$1, {
367
+ size: "sm",
368
+ variant: "destructive",
369
+ disabled: loading || timeoutDue,
370
+ onClick: () => setShowReject(true),
371
+ "data-testid": "tool-approval-reject",
372
+ children: [/* @__PURE__ */ jsx(Icon, {
373
+ icon: "mdi:close",
374
+ className: "mr-1.5",
375
+ width: 16
376
+ }), tr("fluidgrids.toolApproval.reject", "Reject")]
377
+ })
378
+ })]
379
+ })]
380
+ }),
381
+ /* @__PURE__ */ jsx(RejectDialog, {
382
+ open: showReject,
383
+ onOpenChange: setShowReject,
384
+ submitting: loading,
385
+ onConfirm: (reason) => handleDecide("REJECTED", reason || void 0)
386
+ })
387
+ ]
388
+ });
389
+ }
390
+ const HUMAN_PAGE_SIZE = 50;
391
+ function ApprovalInboxPage() {
392
+ const tr = useTr();
393
+ const navigate = useNavigate();
394
+ const { allowed: canReadToolApprovals, isLoading: permissionsLoading } = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.TOOL_APPROVAL_REQUEST_READ);
395
+ const { items, totalCount, loading, error, forbidden, refetch } = usePendingToolApprovals({ enabled: canReadToolApprovals });
396
+ const toolsForbidden = forbidden && !permissionsLoading;
397
+ const [humanOffset, setHumanOffset] = useState(0);
398
+ const human = usePendingHumanRequests({
399
+ limit: HUMAN_PAGE_SIZE,
400
+ offset: humanOffset
401
+ });
402
+ const humanTotal = human.totalCount;
403
+ useEffect(() => {
404
+ if (humanOffset > 0 && humanOffset >= humanTotal) setHumanOffset(Math.max(0, Math.ceil(humanTotal / HUMAN_PAGE_SIZE) - 1) * HUMAN_PAGE_SIZE);
405
+ }, [humanOffset, humanTotal]);
406
+ return /* @__PURE__ */ jsxs("div", {
407
+ className: "p-4 sm:p-6 bg-background-primary min-h-screen",
408
+ children: [
409
+ /* @__PURE__ */ jsxs("div", {
410
+ className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6",
411
+ "data-tour": "fluidgrids-approvals-header",
412
+ children: [/* @__PURE__ */ jsxs("div", { children: [
413
+ /* @__PURE__ */ jsx("h1", {
414
+ className: "text-2xl sm:text-3xl font-bold text-text-primary",
415
+ children: tr("fluidgrids.approvals.pageTitle", "Approvals")
416
+ }),
417
+ /* @__PURE__ */ jsx("p", {
418
+ className: "text-text-secondary mt-1",
419
+ children: tr("fluidgrids.approvals.pageSubtitle", "Requests from your workflows waiting for a person, and AI Agent tool calls waiting for a decision")
420
+ }),
421
+ /* @__PURE__ */ jsx(FluidGridsDocsLink, {
422
+ topic: "approvals",
423
+ className: "mt-1"
424
+ })
425
+ ] }), /* @__PURE__ */ jsxs(Button$1, {
426
+ variant: "outline",
427
+ onClick: () => navigate("../runs"),
428
+ children: [/* @__PURE__ */ jsx(Icon, {
429
+ icon: "mdi:arrow-left",
430
+ className: "mr-2",
431
+ width: 16
432
+ }), tr("fluidgrids.toolApproval.backToRuns", "Back to Runs")]
433
+ })]
434
+ }),
435
+ (loading || permissionsLoading) && items.length === 0 && /* @__PURE__ */ jsx("p", {
436
+ className: "text-text-secondary text-sm",
437
+ children: tr("fluidgrids.toolApproval.loading", "Loading…")
438
+ }),
439
+ error && /* @__PURE__ */ jsx("p", {
440
+ className: "text-sm text-destructive",
441
+ role: "alert",
442
+ children: tr("fluidgrids.toolApproval.loadFailed", "Failed to load pending approvals: {{message}}", { message: error.message })
443
+ }),
444
+ human.items.length > 0 && /* @__PURE__ */ jsxs("section", {
445
+ className: "mb-8",
446
+ "data-testid": "human-requests-section",
447
+ "data-tour": "fluidgrids-approvals-human",
448
+ children: [
449
+ /* @__PURE__ */ jsx("h2", {
450
+ className: "mb-1 text-lg font-semibold text-text-primary",
451
+ children: tr("fluidgrids.humanResponse.inboxHeading", "Waiting for a response")
452
+ }),
453
+ /* @__PURE__ */ jsx("p", {
454
+ className: "mb-3 text-xs text-text-secondary",
455
+ children: tr("fluidgrids.humanResponse.inboxSubtitle", "Workflows paused on a person — approve, decline or answer to let them continue.")
456
+ }),
457
+ /* @__PURE__ */ jsx("div", {
458
+ className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
459
+ children: human.items.map((request) => /* @__PURE__ */ jsx(HumanRequestCard, {
460
+ request,
461
+ onAnswered: human.refetch
462
+ }, request.id))
463
+ }),
464
+ human.totalCount > HUMAN_PAGE_SIZE && /* @__PURE__ */ jsxs("div", {
465
+ className: "mt-4 flex items-center gap-3",
466
+ children: [
467
+ /* @__PURE__ */ jsx("span", {
468
+ className: "text-xs text-text-secondary",
469
+ children: tr("fluidgrids.humanResponse.pageRange", "{{from}}–{{to}} of {{total}}", {
470
+ from: humanOffset + 1,
471
+ to: humanOffset + human.items.length,
472
+ total: human.totalCount
473
+ })
474
+ }),
475
+ /* @__PURE__ */ jsx(Button$1, {
476
+ variant: "outline",
477
+ size: "sm",
478
+ disabled: humanOffset === 0,
479
+ onClick: () => setHumanOffset((current) => Math.max(0, current - HUMAN_PAGE_SIZE)),
480
+ children: tr("fluidgrids.humanResponse.previousPage", "Previous")
481
+ }),
482
+ /* @__PURE__ */ jsx(Button$1, {
483
+ variant: "outline",
484
+ size: "sm",
485
+ disabled: humanOffset + HUMAN_PAGE_SIZE >= human.totalCount,
486
+ onClick: () => setHumanOffset((current) => current + HUMAN_PAGE_SIZE),
487
+ children: tr("fluidgrids.humanResponse.nextPage", "Next")
488
+ })
489
+ ]
490
+ })
491
+ ]
492
+ }),
493
+ human.error && /* @__PURE__ */ jsx("p", {
494
+ className: "mb-4 text-sm text-destructive",
495
+ role: "alert",
496
+ children: tr("fluidgrids.humanResponse.loadFailed", "Failed to load requests waiting for a response: {{message}}", { message: human.error.message })
497
+ }),
498
+ toolsForbidden && /* @__PURE__ */ jsx(Card, {
499
+ className: "mb-6 border border-border-secondary bg-background-secondary",
500
+ "data-testid": "tool-approval-no-access",
501
+ children: /* @__PURE__ */ jsxs(CardContent, {
502
+ className: "flex items-start gap-3 py-4",
503
+ children: [/* @__PURE__ */ jsx(Icon, {
504
+ icon: "mdi:lock-outline",
505
+ width: 20,
506
+ className: "mt-0.5 shrink-0 text-text-secondary"
507
+ }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
508
+ className: "text-sm font-medium text-text-primary",
509
+ children: tr("fluidgrids.toolApproval.noAccessTitle", "You can't review AI Agent tool calls")
510
+ }), /* @__PURE__ */ jsx("p", {
511
+ className: "mt-1 text-xs text-text-secondary",
512
+ children: tr("fluidgrids.toolApproval.noAccessSubtitle", "Your role doesn't include permission to read tool approval requests. Ask a workspace admin if you need access.")
513
+ })] })]
514
+ })
515
+ }),
516
+ !loading && !permissionsLoading && !toolsForbidden && !error && !human.loading && !human.error && items.length === 0 && human.items.length === 0 && /* @__PURE__ */ jsx(Card, {
517
+ className: "border border-border-secondary bg-background-secondary",
518
+ "data-tour": "fluidgrids-approvals-empty",
519
+ children: /* @__PURE__ */ jsxs(CardContent, {
520
+ className: "flex flex-col items-center gap-2 py-10 text-center",
521
+ children: [
522
+ /* @__PURE__ */ jsx(Icon, {
523
+ icon: "mdi:shield-check-outline",
524
+ width: 32,
525
+ className: "text-text-secondary"
526
+ }),
527
+ /* @__PURE__ */ jsx("p", {
528
+ className: "text-sm font-medium text-text-primary",
529
+ children: tr("fluidgrids.toolApproval.emptyTitle", "Nothing waiting for approval")
530
+ }),
531
+ /* @__PURE__ */ jsx("p", {
532
+ className: "text-xs text-text-secondary",
533
+ children: tr("fluidgrids.toolApproval.emptySubtitle", "Runs will appear here when an AI Agent with tool approval enabled proposes a tool call.")
534
+ })
535
+ ]
536
+ })
537
+ }),
538
+ !toolsForbidden && items.length > 0 && /* @__PURE__ */ jsx("div", {
539
+ className: "mb-3 text-xs text-text-secondary",
540
+ "data-testid": "tool-approval-count",
541
+ children: tr("fluidgrids.toolApproval.count", "{{count}} pending ({{total}} total)", {
542
+ count: items.length,
543
+ total: totalCount
544
+ })
545
+ }),
546
+ /* @__PURE__ */ jsx("div", {
547
+ className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
548
+ "data-tour": "fluidgrids-approvals-tools",
549
+ children: !toolsForbidden && items.map((request) => /* @__PURE__ */ jsx(RequestCard, {
550
+ request,
551
+ onDecided: refetch
552
+ }, request.id))
553
+ })
554
+ ]
555
+ });
556
+ }
557
+
558
+ export { usePendingToolApprovals as i, ApprovalInboxPage_exports as n, useDecideToolApproval as r, ApprovalInboxPage as t };