@burdenoff/fluidgrids-fe-sdk 2026.1115.2 → 2026.1115.3

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 (62) hide show
  1. package/dist/{AiStudioPage-CtHmZ3Lw.js → AiStudioPage-CRgw_P7Y.js} +4 -4
  2. package/dist/{DataSinkDashboardPage-DFtWv2nD.js → DataSinkDashboardPage-C2Lb5c7p.js} +2 -2
  3. package/dist/{ExecutionDetailPage-C-aY7qWI.js → ExecutionDetailPage-72GPEmJf.js} +9 -9
  4. package/dist/{ExecutionsListPage-BYW5WiX7.js → ExecutionsListPage-sdpULJ-y.js} +6 -6
  5. package/dist/{FailureTriagePanel-Ddua9uxn.js → FailureTriagePanel-Chvh8S_q.js} +1 -1
  6. package/dist/{FluidGridsProvider-CDjkq3Zj.js → FluidGridsProvider-64qAUX4Y.js} +1 -1
  7. package/dist/{HistoryPage-fMZlXsIY.js → HistoryPage-DDIwBAsG.js} +1 -1
  8. package/dist/{InsightsPage-DozSYGVD.js → InsightsPage-Dw2ElMGW.js} +1005 -14
  9. package/dist/{OpenTemplateAsCodeButton-Cjnagq9H.js → OpenTemplateAsCodeButton-DCEbeUb5.js} +2 -2
  10. package/dist/{PaidTemplateConfirm-Crs0CXXl.js → PaidTemplateConfirm-B3R-JvoA.js} +1 -1
  11. package/dist/{SettingsPage-qSvV7r0y.js → SettingsPage-Drgu5p5s.js} +5 -5
  12. package/dist/{TaskQueuesPage-BuWQwT5I.js → TaskQueuesPage-9MpmiHvJ.js} +1 -1
  13. package/dist/{TemplateCard-BsrXJ1Su.js → TemplateCard-CA4tMUzN.js} +4 -4
  14. package/dist/{TemplateConfigurationModal-B_ME8M-1.js → TemplateConfigurationModal-CObP8Po7.js} +1 -1
  15. package/dist/{TemplatePreview-BOIhJSBD.js → TemplatePreview-CXvkYDem.js} +5 -5
  16. package/dist/{TemplatesPage-dj7NseMt.js → TemplatesPage-xwQk9WrO.js} +9 -9
  17. package/dist/{WorkflowBuilder-ByG9twmu.js → WorkflowBuilder-BFJq_45O.js} +5 -5
  18. package/dist/{WorkflowBuilder-DjpAoBVO.js → WorkflowBuilder-uhe3YUI5.js} +3 -3
  19. package/dist/{WorkflowSearchRedirect-DRidTx1L.js → WorkflowSearchRedirect-DgSyY4Uj.js} +1 -1
  20. package/dist/{WorkflowShareDialog-B9yZMhEi.js → WorkflowShareDialog-DherIHZo.js} +1 -1
  21. package/dist/{WorkflowsList-BQ_5hkWi.js → WorkflowsList-Cjjti0SI.js} +9 -9
  22. package/dist/{agentTools-Cx5yPBe7.js → agentTools-pSaWntVD.js} +1 -1
  23. package/dist/{ai-usage-Dit3U_aG.js → ai-usage-BovljL6l.js} +1 -1
  24. package/dist/{assert-rules-DtQmtG1p.js → assert-rules-BA2caUAZ.js} +1 -1
  25. package/dist/{canvasNoteTools-BxknF5rX.js → canvasNoteTools-Hr1m_3mF.js} +1 -1
  26. package/dist/executions.js +2 -2
  27. package/dist/{flow-builder-D8f31DFR.js → flow-builder-D6iWW6tJ.js} +16 -16
  28. package/dist/{graphql-types-dS3Fk9Z5.js → graphql-types-BjCOnRUQ.js} +58 -1
  29. package/dist/history.js +1 -1
  30. package/dist/{index-BprVea6e.d.ts → index-D_U-nNAe.d.ts} +291 -1
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +34 -34
  33. package/dist/{node-detail-view-C__INEVF.js → node-detail-view-cr0pbiSX.js} +5 -5
  34. package/dist/{node-editor-tab-body-BintGoSp.js → node-editor-tab-body-_09aIAMK.js} +2 -2
  35. package/dist/observability.d.ts +1 -1
  36. package/dist/observability.js +2 -2
  37. package/dist/{popover-2-6xmS1q.js → popover-BdjGE-KB.js} +2 -2
  38. package/dist/{quick-config-panel-Bxi9TwCG.js → quick-config-panel-BQpUJ1Ed.js} +3 -3
  39. package/dist/{run-list-links-CH-V4Li5.js → run-list-links-DPWTtVr5.js} +1 -1
  40. package/dist/{run-mode-Bu_pgjeM.js → run-mode-DMlMGEdu.js} +1 -1
  41. package/dist/{schedule-panel-BbRtGDEt.js → schedule-panel-Dwq6JXhH.js} +6 -6
  42. package/dist/settings.js +1 -1
  43. package/dist/{sidebar-node-editor-DG-34YEW.js → sidebar-node-editor-Cx9-gwpu.js} +3 -3
  44. package/dist/{template-code-B7x-XMAm.js → template-code-xlEMDtL8.js} +1 -1
  45. package/dist/templates.js +2 -2
  46. package/dist/{use-workflow-tests-Dkij09vJ.js → use-workflow-tests-C0KaRy7p.js} +2 -2
  47. package/dist/{useAgentDefinitions-YUDx_OW2.js → useAgentDefinitions-dpKr9Mee.js} +1 -1
  48. package/dist/{useDurableParity-X_zfFzQv.js → useDurableParity-ClG3HMH8.js} +1 -1
  49. package/dist/{useExecutions-BWbMt16D.js → useExecutions-D9Sc9QbB.js} +2 -2
  50. package/dist/{useGlobalStoreClient-CwBAeiXV.js → useGlobalStoreClient-iCPQeryK.js} +1 -1
  51. package/dist/{useObservability-mXM7lCop.js → useObservability-CkNAUULL.js} +1 -1
  52. package/dist/{useRunHistory-DYDriBz1.js → useRunHistory-Dv1V1EO0.js} +2 -2
  53. package/dist/{useWorkflowCodeExport-uKBDVvnA.js → useWorkflowCodeExport-C1UH65gc.js} +2 -2
  54. package/dist/{useWorkflows-Dg7q_Tzf.js → useWorkflows-CEOWXYpV.js} +1 -1
  55. package/dist/{utils-C0dtnN4R.js → utils-CXEodE1a.js} +6 -1
  56. package/dist/workflow-builder.js +4 -4
  57. package/dist/{workflow-description-CeXdyWX8.js → workflow-description-QYwLwwFT.js} +1 -1
  58. package/dist/workflow-pages.d.ts +1 -1
  59. package/dist/workflow-pages.js +14 -14
  60. package/dist/{workflow-transfer-CktP7o1c.js → workflow-transfer-390a-CK8.js} +1 -1
  61. package/dist/workflows-list.js +1 -1
  62. package/package.json +1 -1
@@ -3,17 +3,17 @@ import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
3
3
  import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
4
4
  import { n as useNavigationV2 } from "./useNavigationV2-C2WeqN7d.js";
5
5
  import { t as TechnicalDetails } from "./TechnicalDetails-r5JXr1jZ.js";
6
- import { o as useRunReplayActions, r as useInsightsData } from "./useObservability-mXM7lCop.js";
7
- import { a as getTopFailingNodes, i as getFailureBreakdown, l as rankedFailingWorkflows, n as formatDuration, o as getTopFailingWorkflows, s as percentage, u as summarySuccessRate } from "./utils-C0dtnN4R.js";
8
- import { n as FailureTriagePanel } from "./FailureTriagePanel-Ddua9uxn.js";
9
- import { c as useContinuousOptimisationEnabled } from "./feature-flags-B_b8PJ6Z.js";
6
+ import { o as useRunReplayActions, r as useInsightsData } from "./useObservability-CkNAUULL.js";
7
+ import { a as getFailureBreakdown, c as percentage, d as summarySuccessRate, n as formatDuration, o as getTopFailingNodes, r as formatMs, s as getTopFailingWorkflows, u as rankedFailingWorkflows } from "./utils-CXEodE1a.js";
8
+ import { n as FailureTriagePanel } from "./FailureTriagePanel-Chvh8S_q.js";
9
+ import { c as useContinuousOptimisationEnabled, l as useDurableFunctionNodesEnabled } from "./feature-flags-B_b8PJ6Z.js";
10
10
  import { i as SdkPermissionButton, s as useFluidGridsPermission, t as FLUIDGRIDS_PERMISSIONS } from "./constants-65QV61nQ.js";
11
- import { Hw as OptimisationKind, Uw as OptimisationSuggestionStatus, Vw as OptimisationDismissReason } from "./graphql-types-dS3Fk9Z5.js";
11
+ import { Fj as TaskQueueAvailability, Hw as OptimisationDismissReason, Rv as InsightsRunKind, Uw as OptimisationKind, Ww as OptimisationSuggestionStatus } from "./graphql-types-BjCOnRUQ.js";
12
12
  import { n as getFluidGridsClient } from "./client-Ctl4jmY3.js";
13
13
  import { o as throwIfResultError } from "./errors-xPZ-IbQd.js";
14
14
  import { t as WorkflowProposalDocument } from "./WorkflowProposalDocument-BdUbsrd0.js";
15
- import { a as formatTokens, c as DISMISS_REASONS, f as monthlySavingLabel, i as aiSpendPeriod, l as evidenceFacts, p as shortRunId, r as aiCost, s as runsOfWorkflowPath, t as AI_SPEND_RANGE_DAYS, u as evidenceWindowDays } from "./ai-usage-Dit3U_aG.js";
16
- import { i as utcDay, r as runListPath } from "./run-list-links-CH-V4Li5.js";
15
+ import { a as formatTokens, c as DISMISS_REASONS, f as monthlySavingLabel, i as aiSpendPeriod, l as evidenceFacts, p as shortRunId, r as aiCost, s as runsOfWorkflowPath, t as AI_SPEND_RANGE_DAYS, u as evidenceWindowDays } from "./ai-usage-BovljL6l.js";
16
+ import { i as utcDay, r as runListPath } from "./run-list-links-DPWTtVr5.js";
17
17
  import { t as proposalCanvasPath } from "./useRequestedProposal-B7uPXfZB.js";
18
18
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
19
19
  import { Link, useNavigate } from "react-router";
@@ -24,6 +24,494 @@ import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogH
24
24
  import { Button as Button$1 } from "@burdenoff/fe-libs/button";
25
25
  import { BadgeDollarSign, DatabaseZap, Lightbulb, RotateCcw, Scissors, ShieldCheck, Timer } from "lucide-react";
26
26
 
27
+ // src/generated/documents/wspace/CodeWorkflowInsightsDocument.ts
28
+ const CodeWorkflowInsightsDocument = {
29
+ "kind": "Document",
30
+ "definitions": [{
31
+ "kind": "OperationDefinition",
32
+ "operation": "query",
33
+ "name": {
34
+ "kind": "Name",
35
+ "value": "CodeWorkflowInsights"
36
+ },
37
+ "variableDefinitions": [{
38
+ "kind": "VariableDefinition",
39
+ "variable": {
40
+ "kind": "Variable",
41
+ "name": {
42
+ "kind": "Name",
43
+ "value": "input"
44
+ }
45
+ },
46
+ "type": {
47
+ "kind": "NamedType",
48
+ "name": {
49
+ "kind": "Name",
50
+ "value": "CodeWorkflowInsightsInput"
51
+ }
52
+ },
53
+ "directives": []
54
+ }],
55
+ "directives": [],
56
+ "selectionSet": {
57
+ "kind": "SelectionSet",
58
+ "selections": [{
59
+ "kind": "Field",
60
+ "name": {
61
+ "kind": "Name",
62
+ "value": "codeWorkflowInsights"
63
+ },
64
+ "arguments": [{
65
+ "kind": "Argument",
66
+ "name": {
67
+ "kind": "Name",
68
+ "value": "input"
69
+ },
70
+ "value": {
71
+ "kind": "Variable",
72
+ "name": {
73
+ "kind": "Name",
74
+ "value": "input"
75
+ }
76
+ }
77
+ }],
78
+ "directives": [],
79
+ "selectionSet": {
80
+ "kind": "SelectionSet",
81
+ "selections": [
82
+ {
83
+ "kind": "Field",
84
+ "name": {
85
+ "kind": "Name",
86
+ "value": "startDate"
87
+ },
88
+ "arguments": [],
89
+ "directives": []
90
+ },
91
+ {
92
+ "kind": "Field",
93
+ "name": {
94
+ "kind": "Name",
95
+ "value": "endDate"
96
+ },
97
+ "arguments": [],
98
+ "directives": []
99
+ },
100
+ {
101
+ "kind": "Field",
102
+ "name": {
103
+ "kind": "Name",
104
+ "value": "runsByKind"
105
+ },
106
+ "arguments": [],
107
+ "directives": [],
108
+ "selectionSet": {
109
+ "kind": "SelectionSet",
110
+ "selections": [
111
+ {
112
+ "kind": "Field",
113
+ "name": {
114
+ "kind": "Name",
115
+ "value": "kind"
116
+ },
117
+ "arguments": [],
118
+ "directives": []
119
+ },
120
+ {
121
+ "kind": "Field",
122
+ "name": {
123
+ "kind": "Name",
124
+ "value": "total"
125
+ },
126
+ "arguments": [],
127
+ "directives": []
128
+ },
129
+ {
130
+ "kind": "Field",
131
+ "name": {
132
+ "kind": "Name",
133
+ "value": "completed"
134
+ },
135
+ "arguments": [],
136
+ "directives": []
137
+ },
138
+ {
139
+ "kind": "Field",
140
+ "name": {
141
+ "kind": "Name",
142
+ "value": "failed"
143
+ },
144
+ "arguments": [],
145
+ "directives": []
146
+ },
147
+ {
148
+ "kind": "Field",
149
+ "name": {
150
+ "kind": "Name",
151
+ "value": "open"
152
+ },
153
+ "arguments": [],
154
+ "directives": []
155
+ },
156
+ {
157
+ "kind": "Field",
158
+ "name": {
159
+ "kind": "Name",
160
+ "value": "cancelled"
161
+ },
162
+ "arguments": [],
163
+ "directives": []
164
+ }
165
+ ]
166
+ }
167
+ },
168
+ {
169
+ "kind": "Field",
170
+ "name": {
171
+ "kind": "Name",
172
+ "value": "replay"
173
+ },
174
+ "arguments": [],
175
+ "directives": [],
176
+ "selectionSet": {
177
+ "kind": "SelectionSet",
178
+ "selections": [
179
+ {
180
+ "kind": "Field",
181
+ "name": {
182
+ "kind": "Name",
183
+ "value": "workflowTasks"
184
+ },
185
+ "arguments": [],
186
+ "directives": []
187
+ },
188
+ {
189
+ "kind": "Field",
190
+ "name": {
191
+ "kind": "Name",
192
+ "value": "failedWorkflowTasks"
193
+ },
194
+ "arguments": [],
195
+ "directives": []
196
+ },
197
+ {
198
+ "kind": "Field",
199
+ "name": {
200
+ "kind": "Name",
201
+ "value": "timedOutWorkflowTasks"
202
+ },
203
+ "arguments": [],
204
+ "directives": []
205
+ },
206
+ {
207
+ "kind": "Field",
208
+ "name": {
209
+ "kind": "Name",
210
+ "value": "eventsReplayed"
211
+ },
212
+ "arguments": [],
213
+ "directives": []
214
+ },
215
+ {
216
+ "kind": "Field",
217
+ "name": {
218
+ "kind": "Name",
219
+ "value": "avgEventsPerTask"
220
+ },
221
+ "arguments": [],
222
+ "directives": []
223
+ },
224
+ {
225
+ "kind": "Field",
226
+ "name": {
227
+ "kind": "Name",
228
+ "value": "avgTaskDurationMs"
229
+ },
230
+ "arguments": [],
231
+ "directives": []
232
+ },
233
+ {
234
+ "kind": "Field",
235
+ "name": {
236
+ "kind": "Name",
237
+ "value": "p95TaskDurationMs"
238
+ },
239
+ "arguments": [],
240
+ "directives": []
241
+ },
242
+ {
243
+ "kind": "Field",
244
+ "name": {
245
+ "kind": "Name",
246
+ "value": "maxHistoryLength"
247
+ },
248
+ "arguments": [],
249
+ "directives": []
250
+ },
251
+ {
252
+ "kind": "Field",
253
+ "name": {
254
+ "kind": "Name",
255
+ "value": "topWorkflows"
256
+ },
257
+ "arguments": [],
258
+ "directives": [],
259
+ "selectionSet": {
260
+ "kind": "SelectionSet",
261
+ "selections": [
262
+ {
263
+ "kind": "Field",
264
+ "name": {
265
+ "kind": "Name",
266
+ "value": "workflowKey"
267
+ },
268
+ "arguments": [],
269
+ "directives": []
270
+ },
271
+ {
272
+ "kind": "Field",
273
+ "name": {
274
+ "kind": "Name",
275
+ "value": "name"
276
+ },
277
+ "arguments": [],
278
+ "directives": []
279
+ },
280
+ {
281
+ "kind": "Field",
282
+ "name": {
283
+ "kind": "Name",
284
+ "value": "workflowTasks"
285
+ },
286
+ "arguments": [],
287
+ "directives": []
288
+ },
289
+ {
290
+ "kind": "Field",
291
+ "name": {
292
+ "kind": "Name",
293
+ "value": "eventsReplayed"
294
+ },
295
+ "arguments": [],
296
+ "directives": []
297
+ },
298
+ {
299
+ "kind": "Field",
300
+ "name": {
301
+ "kind": "Name",
302
+ "value": "avgTaskDurationMs"
303
+ },
304
+ "arguments": [],
305
+ "directives": []
306
+ }
307
+ ]
308
+ }
309
+ }
310
+ ]
311
+ }
312
+ },
313
+ {
314
+ "kind": "Field",
315
+ "name": {
316
+ "kind": "Name",
317
+ "value": "determinism"
318
+ },
319
+ "arguments": [],
320
+ "directives": [],
321
+ "selectionSet": {
322
+ "kind": "SelectionSet",
323
+ "selections": [
324
+ {
325
+ "kind": "Field",
326
+ "name": {
327
+ "kind": "Name",
328
+ "value": "violatingRuns"
329
+ },
330
+ "arguments": [],
331
+ "directives": []
332
+ },
333
+ {
334
+ "kind": "Field",
335
+ "name": {
336
+ "kind": "Name",
337
+ "value": "openViolatingRuns"
338
+ },
339
+ "arguments": [],
340
+ "directives": []
341
+ },
342
+ {
343
+ "kind": "Field",
344
+ "name": {
345
+ "kind": "Name",
346
+ "value": "topWorkflows"
347
+ },
348
+ "arguments": [],
349
+ "directives": [],
350
+ "selectionSet": {
351
+ "kind": "SelectionSet",
352
+ "selections": [
353
+ {
354
+ "kind": "Field",
355
+ "name": {
356
+ "kind": "Name",
357
+ "value": "workflowKey"
358
+ },
359
+ "arguments": [],
360
+ "directives": []
361
+ },
362
+ {
363
+ "kind": "Field",
364
+ "name": {
365
+ "kind": "Name",
366
+ "value": "name"
367
+ },
368
+ "arguments": [],
369
+ "directives": []
370
+ },
371
+ {
372
+ "kind": "Field",
373
+ "name": {
374
+ "kind": "Name",
375
+ "value": "runs"
376
+ },
377
+ "arguments": [],
378
+ "directives": []
379
+ },
380
+ {
381
+ "kind": "Field",
382
+ "name": {
383
+ "kind": "Name",
384
+ "value": "openRuns"
385
+ },
386
+ "arguments": [],
387
+ "directives": []
388
+ },
389
+ {
390
+ "kind": "Field",
391
+ "name": {
392
+ "kind": "Name",
393
+ "value": "lastViolationAt"
394
+ },
395
+ "arguments": [],
396
+ "directives": []
397
+ }
398
+ ]
399
+ }
400
+ }
401
+ ]
402
+ }
403
+ }
404
+ ]
405
+ }
406
+ }]
407
+ }
408
+ }]
409
+ };
410
+
411
+ // src/generated/documents/wspace/TaskQueueAvailabilityDocument.ts
412
+ const TaskQueueAvailabilityDocument = {
413
+ "kind": "Document",
414
+ "definitions": [{
415
+ "kind": "OperationDefinition",
416
+ "operation": "query",
417
+ "name": {
418
+ "kind": "Name",
419
+ "value": "TaskQueueAvailability"
420
+ },
421
+ "variableDefinitions": [],
422
+ "directives": [],
423
+ "selectionSet": {
424
+ "kind": "SelectionSet",
425
+ "selections": [{
426
+ "kind": "Field",
427
+ "name": {
428
+ "kind": "Name",
429
+ "value": "taskQueueAvailability"
430
+ },
431
+ "arguments": [],
432
+ "directives": [],
433
+ "selectionSet": {
434
+ "kind": "SelectionSet",
435
+ "selections": [
436
+ {
437
+ "kind": "Field",
438
+ "name": {
439
+ "kind": "Name",
440
+ "value": "name"
441
+ },
442
+ "arguments": [],
443
+ "directives": []
444
+ },
445
+ {
446
+ "kind": "Field",
447
+ "name": {
448
+ "kind": "Name",
449
+ "value": "kind"
450
+ },
451
+ "arguments": [],
452
+ "directives": []
453
+ },
454
+ {
455
+ "kind": "Field",
456
+ "name": {
457
+ "kind": "Name",
458
+ "value": "environments"
459
+ },
460
+ "arguments": [],
461
+ "directives": []
462
+ },
463
+ {
464
+ "kind": "Field",
465
+ "name": {
466
+ "kind": "Name",
467
+ "value": "availability"
468
+ },
469
+ "arguments": [],
470
+ "directives": []
471
+ },
472
+ {
473
+ "kind": "Field",
474
+ "name": {
475
+ "kind": "Name",
476
+ "value": "pollers"
477
+ },
478
+ "arguments": [],
479
+ "directives": []
480
+ },
481
+ {
482
+ "kind": "Field",
483
+ "name": {
484
+ "kind": "Name",
485
+ "value": "workflowBacklog"
486
+ },
487
+ "arguments": [],
488
+ "directives": []
489
+ },
490
+ {
491
+ "kind": "Field",
492
+ "name": {
493
+ "kind": "Name",
494
+ "value": "activityBacklog"
495
+ },
496
+ "arguments": [],
497
+ "directives": []
498
+ },
499
+ {
500
+ "kind": "Field",
501
+ "name": {
502
+ "kind": "Name",
503
+ "value": "oldestBacklogAgeSeconds"
504
+ },
505
+ "arguments": [],
506
+ "directives": []
507
+ }
508
+ ]
509
+ }
510
+ }]
511
+ }
512
+ }]
513
+ };
514
+
27
515
  // src/generated/documents/wspace/ErrorAnalyticsDocument.ts
28
516
  const ErrorAnalyticsDocument = {
29
517
  "kind": "Document",
@@ -2954,7 +3442,7 @@ function useContinuousOptimisation(active) {
2954
3442
 
2955
3443
  // src/modules/observability/optimisation-labels.ts
2956
3444
  /** The kind's short label, e.g. "Raise the node timeout". */
2957
- function kindLabel(tr, kind) {
3445
+ function kindLabel$1(tr, kind) {
2958
3446
  switch (kind) {
2959
3447
  case "ADD_RETRY": return tr("fluidgrids.optimisation.kind.ADD_RETRY", "Retry transient failures");
2960
3448
  case "CHEAPER_MODEL": return tr("fluidgrids.optimisation.kind.CHEAPER_MODEL", "Use a cheaper model");
@@ -3216,7 +3704,7 @@ function OptimisationSuggestionRow({ suggestion, pending, onOpenRun, onApply, on
3216
3704
  children: [
3217
3705
  /* @__PURE__ */ jsxs("span", {
3218
3706
  className: "inline-flex items-center gap-1 rounded-full bg-surface px-2 py-0.5 text-xs text-text-secondary",
3219
- children: [/* @__PURE__ */ jsx(KindIcon, { className: "size-3.5" }), kindLabel(tr, kind)]
3707
+ children: [/* @__PURE__ */ jsx(KindIcon, { className: "size-3.5" }), kindLabel$1(tr, kind)]
3220
3708
  }),
3221
3709
  /* @__PURE__ */ jsx("span", {
3222
3710
  className: "font-medium text-text-primary",
@@ -3444,7 +3932,7 @@ function useWorkspaceAiUsage(days) {
3444
3932
  * reads "Not priced yet", never "$0.00". Each row opens the Runs list
3445
3933
  * filtered to that workflow.
3446
3934
  */
3447
- function rangeLabel(days, tr) {
3935
+ function rangeLabel$1(days, tr) {
3448
3936
  switch (days) {
3449
3937
  case 7: return tr("fluidgrids.insights.aiSpend.range7", "7 days");
3450
3938
  case 30: return tr("fluidgrids.insights.aiSpend.range30", "30 days");
@@ -3476,7 +3964,7 @@ function AiSpendPanel() {
3476
3964
  }), /* @__PURE__ */ jsx("p", {
3477
3965
  className: "mt-1 text-sm text-text-secondary",
3478
3966
  children: tr("fluidgrids.insights.aiSpend.subtitle", "Model calls made by your workflow runs, most expensive workflow first.")
3479
- })] }), /* @__PURE__ */ jsx(RangeSelector, {
3967
+ })] }), /* @__PURE__ */ jsx(RangeSelector$1, {
3480
3968
  days,
3481
3969
  onChange: setDays,
3482
3970
  tr
@@ -3490,7 +3978,7 @@ function AiSpendPanel() {
3490
3978
  })]
3491
3979
  });
3492
3980
  }
3493
- function RangeSelector({ days, onChange, tr }) {
3981
+ function RangeSelector$1({ days, onChange, tr }) {
3494
3982
  return /* @__PURE__ */ jsx("div", {
3495
3983
  className: "flex shrink-0 gap-1 rounded-lg border border-border-default p-1",
3496
3984
  role: "group",
@@ -3500,7 +3988,7 @@ function RangeSelector({ days, onChange, tr }) {
3500
3988
  "aria-pressed": days === option,
3501
3989
  onClick: () => onChange(option),
3502
3990
  className: `rounded px-3 py-1 text-sm ${days === option ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:text-text-primary"}`,
3503
- children: rangeLabel(option, tr)
3991
+ children: rangeLabel$1(option, tr)
3504
3992
  }, option))
3505
3993
  });
3506
3994
  }
@@ -3910,6 +4398,503 @@ function ErrorAnalyticsPanel({ analytics, period, loading, error, onRetry }) {
3910
4398
  });
3911
4399
  }
3912
4400
 
4401
+ // src/modules/observability/hooks/useCodeWorkflowInsights.ts
4402
+ /**
4403
+ * useCodeWorkflowInsights / useTaskQueueAvailability — the reads behind the
4404
+ * Insights "Code workflows" panel (gap G21, spec code-first 09 §5).
4405
+ *
4406
+ * - `codeWorkflowInsights(input)` (dashboard:read): runs by kind, replay cost
4407
+ * and determinism violations over the last 7, 30 or 90 days.
4408
+ * - `taskQueueAvailability` (task-queue:read): whether each task queue has
4409
+ * workers right now.
4410
+ *
4411
+ * Each is a plain network read per period and refresh; they load and fail
4412
+ * independently, so a member without task-queue:read still sees the run
4413
+ * figures. Nothing is read while `enabled` is false.
4414
+ */
4415
+ /** The periods the panel offers, in days; the service allows up to 90. */
4416
+ const CODE_INSIGHTS_RANGE_DAYS = [
4417
+ 7,
4418
+ 30,
4419
+ 90
4420
+ ];
4421
+ /** Rows per ranking (replay cost and determinism). */
4422
+ const CODE_INSIGHTS_LIMIT = 5;
4423
+ const DAY_MS = 864e5;
4424
+ /** The window ending `now`, `days` long, as the query input wants it. */
4425
+ function codeInsightsWindow(days, now) {
4426
+ return {
4427
+ startDate: (/* @__PURE__ */ new Date(now.getTime() - days * DAY_MS)).toISOString(),
4428
+ endDate: now.toISOString()
4429
+ };
4430
+ }
4431
+ async function fetchCodeWorkflowInsights(days, now = /* @__PURE__ */ new Date()) {
4432
+ const result = await getFluidGridsClient().query({
4433
+ query: CodeWorkflowInsightsDocument,
4434
+ variables: { input: {
4435
+ ...codeInsightsWindow(days, now),
4436
+ limit: 5
4437
+ } },
4438
+ fetchPolicy: "network-only"
4439
+ });
4440
+ throwIfResultError(result);
4441
+ return result.data?.codeWorkflowInsights ?? null;
4442
+ }
4443
+ async function fetchTaskQueueAvailability() {
4444
+ const result = await getFluidGridsClient().query({
4445
+ query: TaskQueueAvailabilityDocument,
4446
+ fetchPolicy: "network-only"
4447
+ });
4448
+ throwIfResultError(result);
4449
+ return result.data?.taskQueueAvailability ?? [];
4450
+ }
4451
+ /**
4452
+ * The latest answer of `load`, re-read whenever `load` changes and on
4453
+ * `refetch`. An older read that settles after a newer one was sent is
4454
+ * dropped; a failed refresh keeps the last good data on screen.
4455
+ */
4456
+ function useLatestRead(load, enabled) {
4457
+ const [sent, setSent] = useState(0);
4458
+ const [settled, setSettled] = useState(null);
4459
+ const request = useRef(0);
4460
+ const read = useCallback(async () => {
4461
+ if (!enabled) return;
4462
+ const id = ++request.current;
4463
+ setSent(id);
4464
+ let data = null;
4465
+ let error = null;
4466
+ try {
4467
+ data = await load();
4468
+ } catch (err) {
4469
+ error = err instanceof Error ? err.message : String(err);
4470
+ }
4471
+ if (id !== request.current) return;
4472
+ setSettled((previous) => ({
4473
+ request: id,
4474
+ data: error ? previous?.data ?? null : data,
4475
+ error
4476
+ }));
4477
+ }, [enabled, load]);
4478
+ useEffect(() => {
4479
+ read();
4480
+ }, [read]);
4481
+ return {
4482
+ data: settled?.data ?? null,
4483
+ loading: enabled && (settled?.request ?? -1) !== sent,
4484
+ error: settled?.error ?? null,
4485
+ refetch: read
4486
+ };
4487
+ }
4488
+ function useCodeWorkflowInsights(days, enabled) {
4489
+ return useLatestRead(useCallback(() => fetchCodeWorkflowInsights(days), [days]), enabled);
4490
+ }
4491
+ function useTaskQueueAvailability(enabled) {
4492
+ return useLatestRead(fetchTaskQueueAvailability, enabled);
4493
+ }
4494
+
4495
+ // src/modules/observability/components/CodeWorkflowsPanel.tsx
4496
+ /**
4497
+ * Insights: Code workflows (gap G21, spec code-first 09 §5). How the
4498
+ * workspace's runs split between canvas runs, code workflows and standalone
4499
+ * activities; what replaying code workflows costs (the history each workflow
4500
+ * task replays and how long tasks take); determinism violations, with the
4501
+ * runs still stuck on one; and whether each task queue has workers now.
4502
+ *
4503
+ * Rendered by Insights only while fluidgrids.code-first and
4504
+ * fluidgrids.durable-functions are on. Worker availability needs
4505
+ * task-queue:read and loads on its own, so a member without it still sees
4506
+ * the run figures.
4507
+ */
4508
+ /** A count that may be fractional (events replayed) as a whole number. */
4509
+ function formatCount(value) {
4510
+ return Math.round(value).toLocaleString();
4511
+ }
4512
+ function rangeLabel(days, tr) {
4513
+ switch (days) {
4514
+ case 7: return tr("fluidgrids.insights.codeWorkflows.range7", "7 days");
4515
+ case 30: return tr("fluidgrids.insights.codeWorkflows.range30", "30 days");
4516
+ case 90: return tr("fluidgrids.insights.codeWorkflows.range90", "90 days");
4517
+ }
4518
+ }
4519
+ function kindLabel(kind, tr) {
4520
+ switch (kind) {
4521
+ case "GRAPH": return tr("fluidgrids.insights.codeWorkflows.kindGraph", "Canvas runs");
4522
+ case "CODE_WORKFLOW": return tr("fluidgrids.insights.codeWorkflows.kindCode", "Code workflows");
4523
+ case "STANDALONE_ACTIVITY": return tr("fluidgrids.insights.codeWorkflows.kindActivity", "Standalone activities");
4524
+ }
4525
+ }
4526
+ function kindIcon(kind) {
4527
+ switch (kind) {
4528
+ case "GRAPH": return "mdi:graph-outline";
4529
+ case "CODE_WORKFLOW": return "mdi:code-braces";
4530
+ case "STANDALONE_ACTIVITY": return "mdi:lightning-bolt-outline";
4531
+ }
4532
+ }
4533
+ function CodeWorkflowsPanel({ canReadQueues }) {
4534
+ const tr = useTr();
4535
+ const [days, setDays] = useState(30);
4536
+ const insights = useCodeWorkflowInsights(days, true);
4537
+ const queues = useTaskQueueAvailability(canReadQueues);
4538
+ return /* @__PURE__ */ jsxs("section", {
4539
+ className: "rounded-xl border border-border-default bg-surface p-4 sm:p-5",
4540
+ "aria-label": tr("fluidgrids.insights.codeWorkflows.title", "Code workflows"),
4541
+ "data-testid": "insights-code-workflows",
4542
+ children: [
4543
+ /* @__PURE__ */ jsxs("div", {
4544
+ className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
4545
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
4546
+ className: "text-base font-semibold text-text-primary",
4547
+ children: tr("fluidgrids.insights.codeWorkflows.title", "Code workflows")
4548
+ }), /* @__PURE__ */ jsx("p", {
4549
+ className: "mt-1 text-sm text-text-secondary",
4550
+ children: tr("fluidgrids.insights.codeWorkflows.subtitle", "Runs by kind, what replaying code workflows costs, determinism violations and worker availability.")
4551
+ })] }), /* @__PURE__ */ jsxs("div", {
4552
+ className: "flex shrink-0 items-center gap-2",
4553
+ children: [/* @__PURE__ */ jsx(RangeSelector, {
4554
+ days,
4555
+ onChange: setDays,
4556
+ tr
4557
+ }), /* @__PURE__ */ jsx(Button$1, {
4558
+ variant: "outline",
4559
+ size: "sm",
4560
+ onClick: () => {
4561
+ insights.refetch();
4562
+ if (canReadQueues) queues.refetch();
4563
+ },
4564
+ disabled: insights.loading,
4565
+ "aria-label": tr("fluidgrids.insights.codeWorkflows.refresh", "Refresh code workflow insights"),
4566
+ children: /* @__PURE__ */ jsx(Icon, {
4567
+ icon: "mdi:refresh",
4568
+ width: 16
4569
+ })
4570
+ })]
4571
+ })]
4572
+ }),
4573
+ /* @__PURE__ */ jsx(InsightsBody, {
4574
+ data: insights.data,
4575
+ loading: insights.loading,
4576
+ error: insights.error,
4577
+ onRetry: () => void insights.refetch(),
4578
+ tr
4579
+ }),
4580
+ canReadQueues && /* @__PURE__ */ jsx(WorkerAvailability, {
4581
+ queues: queues.data,
4582
+ loading: queues.loading,
4583
+ error: queues.error,
4584
+ onRetry: () => void queues.refetch(),
4585
+ tr
4586
+ })
4587
+ ]
4588
+ });
4589
+ }
4590
+ function RangeSelector({ days, onChange, tr }) {
4591
+ return /* @__PURE__ */ jsx("div", {
4592
+ className: "flex gap-1 rounded-lg border border-border-default p-1",
4593
+ role: "group",
4594
+ "aria-label": tr("fluidgrids.insights.codeWorkflows.rangeLabel", "Period"),
4595
+ children: CODE_INSIGHTS_RANGE_DAYS.map((option) => /* @__PURE__ */ jsx("button", {
4596
+ type: "button",
4597
+ "aria-pressed": days === option,
4598
+ onClick: () => onChange(option),
4599
+ className: `rounded px-3 py-1 text-sm ${days === option ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:text-text-primary"}`,
4600
+ children: rangeLabel(option, tr)
4601
+ }, option))
4602
+ });
4603
+ }
4604
+ function ErrorNotice({ message, label, onRetry, tr }) {
4605
+ return /* @__PURE__ */ jsxs("div", {
4606
+ className: "mt-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle p-4 text-sm text-status-error-text",
4607
+ role: "alert",
4608
+ children: [
4609
+ /* @__PURE__ */ jsx("p", {
4610
+ className: "font-medium",
4611
+ children: label
4612
+ }),
4613
+ /* @__PURE__ */ jsx("p", {
4614
+ className: "mt-1",
4615
+ children: message
4616
+ }),
4617
+ /* @__PURE__ */ jsx(Button$1, {
4618
+ variant: "outline",
4619
+ size: "sm",
4620
+ className: "mt-3",
4621
+ onClick: onRetry,
4622
+ children: tr("fluidgrids.insights.codeWorkflows.retry", "Try again")
4623
+ })
4624
+ ]
4625
+ });
4626
+ }
4627
+ function InsightsBody({ data, loading, error, onRetry, tr }) {
4628
+ if (error && !data) return /* @__PURE__ */ jsx(ErrorNotice, {
4629
+ message: error,
4630
+ label: tr("fluidgrids.insights.codeWorkflows.loadError", "Could not load code workflow insights"),
4631
+ onRetry,
4632
+ tr
4633
+ });
4634
+ if (!data) return /* @__PURE__ */ jsx("div", {
4635
+ className: "mt-4 grid gap-3 sm:grid-cols-3",
4636
+ "aria-busy": loading,
4637
+ "data-testid": "insights-code-workflows-loading",
4638
+ children: [
4639
+ 1,
4640
+ 2,
4641
+ 3
4642
+ ].map((item) => /* @__PURE__ */ jsx("div", { className: "h-20 animate-pulse rounded-lg border border-border-default bg-surface-sunken" }, item))
4643
+ });
4644
+ return /* @__PURE__ */ jsxs("div", {
4645
+ className: "mt-4 space-y-5",
4646
+ children: [
4647
+ /* @__PURE__ */ jsx(RunsByKind, {
4648
+ kinds: data.runsByKind,
4649
+ tr
4650
+ }),
4651
+ /* @__PURE__ */ jsx(ReplayCost, {
4652
+ replay: data.replay,
4653
+ tr
4654
+ }),
4655
+ /* @__PURE__ */ jsx(Determinism, {
4656
+ determinism: data.determinism,
4657
+ tr
4658
+ })
4659
+ ]
4660
+ });
4661
+ }
4662
+ function RunsByKind({ kinds, tr }) {
4663
+ return /* @__PURE__ */ jsx("ul", {
4664
+ className: "m-0 grid list-none gap-3 p-0 sm:grid-cols-3",
4665
+ "aria-label": tr("fluidgrids.insights.codeWorkflows.byKind", "Runs by kind"),
4666
+ "data-testid": "insights-code-runs-by-kind",
4667
+ children: kinds.map((kind) => /* @__PURE__ */ jsxs("li", {
4668
+ className: "rounded-lg border border-border-default p-3",
4669
+ "data-testid": `insights-code-kind-${kind.kind}`,
4670
+ children: [
4671
+ /* @__PURE__ */ jsxs("div", {
4672
+ className: "flex items-center gap-2 text-sm text-text-secondary",
4673
+ children: [/* @__PURE__ */ jsx(Icon, {
4674
+ icon: kindIcon(kind.kind),
4675
+ width: 16
4676
+ }), /* @__PURE__ */ jsx("span", { children: kindLabel(kind.kind, tr) })]
4677
+ }),
4678
+ /* @__PURE__ */ jsx("p", {
4679
+ className: "mt-2 text-xl font-semibold text-text-primary",
4680
+ children: kind.total.toLocaleString()
4681
+ }),
4682
+ /* @__PURE__ */ jsx("p", {
4683
+ className: "mt-1 text-xs text-text-secondary",
4684
+ children: tr("fluidgrids.insights.codeWorkflows.kindBreakdown", "{{completed}} completed · {{failed}} failed · {{open}} open · {{cancelled}} cancelled", {
4685
+ completed: kind.completed.toLocaleString(),
4686
+ failed: kind.failed.toLocaleString(),
4687
+ open: kind.open.toLocaleString(),
4688
+ cancelled: kind.cancelled.toLocaleString()
4689
+ })
4690
+ })
4691
+ ]
4692
+ }, kind.kind))
4693
+ });
4694
+ }
4695
+ function Stat({ label, value, detail, testId }) {
4696
+ return /* @__PURE__ */ jsxs("div", {
4697
+ "data-testid": testId,
4698
+ children: [
4699
+ /* @__PURE__ */ jsx("p", {
4700
+ className: "text-xs text-text-secondary",
4701
+ children: label
4702
+ }),
4703
+ /* @__PURE__ */ jsx("p", {
4704
+ className: "mt-1 text-lg font-semibold text-text-primary",
4705
+ children: value
4706
+ }),
4707
+ detail && /* @__PURE__ */ jsx("p", {
4708
+ className: "text-xs text-text-secondary",
4709
+ children: detail
4710
+ })
4711
+ ]
4712
+ });
4713
+ }
4714
+ function ReplayCost({ replay, tr }) {
4715
+ const failures = replay.failedWorkflowTasks + replay.timedOutWorkflowTasks;
4716
+ return /* @__PURE__ */ jsxs("div", {
4717
+ "data-testid": "insights-code-replay",
4718
+ children: [
4719
+ /* @__PURE__ */ jsx("h3", {
4720
+ className: "text-sm font-semibold text-text-primary",
4721
+ children: tr("fluidgrids.insights.codeWorkflows.replayTitle", "Replay cost")
4722
+ }),
4723
+ /* @__PURE__ */ jsx("p", {
4724
+ className: "mt-0.5 text-xs text-text-secondary",
4725
+ children: tr("fluidgrids.insights.codeWorkflows.replayHelp", "Each workflow task replays the run's history from the start. Long histories make every task slower; continue-as-new keeps them short.")
4726
+ }),
4727
+ /* @__PURE__ */ jsxs("div", {
4728
+ className: "mt-3 grid grid-cols-2 gap-4 lg:grid-cols-4",
4729
+ children: [
4730
+ /* @__PURE__ */ jsx(Stat, {
4731
+ label: tr("fluidgrids.insights.codeWorkflows.workflowTasks", "Workflow tasks"),
4732
+ value: replay.workflowTasks.toLocaleString(),
4733
+ detail: failures > 0 ? tr("fluidgrids.insights.codeWorkflows.taskFailures", "{{failed}} failed · {{timedOut}} timed out", {
4734
+ failed: replay.failedWorkflowTasks.toLocaleString(),
4735
+ timedOut: replay.timedOutWorkflowTasks.toLocaleString()
4736
+ }) : void 0,
4737
+ testId: "insights-code-workflow-tasks"
4738
+ }),
4739
+ /* @__PURE__ */ jsx(Stat, {
4740
+ label: tr("fluidgrids.insights.codeWorkflows.eventsReplayed", "Events replayed"),
4741
+ value: formatCount(replay.eventsReplayed),
4742
+ detail: replay.avgEventsPerTask != null ? tr("fluidgrids.insights.codeWorkflows.eventsPerTask", "{{count}} per task on average", { count: replay.avgEventsPerTask.toFixed(1) }) : void 0,
4743
+ testId: "insights-code-events-replayed"
4744
+ }),
4745
+ /* @__PURE__ */ jsx(Stat, {
4746
+ label: tr("fluidgrids.insights.codeWorkflows.taskTime", "Task time (avg / p95)"),
4747
+ value: `${formatMs(replay.avgTaskDurationMs)} / ${formatMs(replay.p95TaskDurationMs)}`,
4748
+ testId: "insights-code-task-time"
4749
+ }),
4750
+ /* @__PURE__ */ jsx(Stat, {
4751
+ label: tr("fluidgrids.insights.codeWorkflows.longestHistory", "Longest history"),
4752
+ value: tr("fluidgrids.insights.codeWorkflows.events", "{{count}} events", { count: replay.maxHistoryLength.toLocaleString() }),
4753
+ testId: "insights-code-longest-history"
4754
+ })
4755
+ ]
4756
+ }),
4757
+ replay.topWorkflows.length > 0 ? /* @__PURE__ */ jsx("ul", {
4758
+ className: "mt-3 divide-y divide-border-default rounded-lg border border-border-default",
4759
+ "aria-label": tr("fluidgrids.insights.codeWorkflows.replayRanking", "Workflows that replayed the most"),
4760
+ children: replay.topWorkflows.map((row) => /* @__PURE__ */ jsxs("li", {
4761
+ className: "flex flex-col gap-1 px-3 py-2 text-sm sm:flex-row sm:items-center sm:gap-4",
4762
+ children: [/* @__PURE__ */ jsx(Link, {
4763
+ to: runsOfWorkflowPath(row.workflowKey),
4764
+ className: "min-w-0 flex-1 truncate font-medium text-text-link hover:underline",
4765
+ children: row.name || row.workflowKey
4766
+ }), /* @__PURE__ */ jsx("span", {
4767
+ className: "text-xs text-text-secondary",
4768
+ children: tr("fluidgrids.insights.codeWorkflows.replayRow", "{{tasks}} tasks · {{events}} events · {{time}} avg", {
4769
+ tasks: row.workflowTasks.toLocaleString(),
4770
+ events: formatCount(row.eventsReplayed),
4771
+ time: formatMs(row.avgTaskDurationMs)
4772
+ })
4773
+ })]
4774
+ }, row.workflowKey))
4775
+ }) : /* @__PURE__ */ jsx("p", {
4776
+ className: "mt-3 text-sm text-text-secondary",
4777
+ children: tr("fluidgrids.insights.codeWorkflows.noTasks", "No code workflow ran a task in this period.")
4778
+ })
4779
+ ]
4780
+ });
4781
+ }
4782
+ function Determinism({ determinism, tr }) {
4783
+ const clean = determinism.violatingRuns === 0;
4784
+ return /* @__PURE__ */ jsxs("div", {
4785
+ "data-testid": "insights-code-determinism",
4786
+ children: [
4787
+ /* @__PURE__ */ jsxs("div", {
4788
+ className: "flex items-center gap-2",
4789
+ children: [/* @__PURE__ */ jsx(Icon, {
4790
+ icon: clean ? "mdi:check-circle-outline" : "mdi:alert-outline",
4791
+ width: 18,
4792
+ className: clean ? "text-status-success-text" : "text-status-warning-text"
4793
+ }), /* @__PURE__ */ jsx("h3", {
4794
+ className: "text-sm font-semibold text-text-primary",
4795
+ children: tr("fluidgrids.insights.codeWorkflows.determinismTitle", "Determinism violations")
4796
+ })]
4797
+ }),
4798
+ /* @__PURE__ */ jsx("p", {
4799
+ className: "mt-1 text-sm text-text-secondary",
4800
+ "data-testid": "insights-code-determinism-summary",
4801
+ children: clean ? tr("fluidgrids.insights.codeWorkflows.noViolations", "No run hit a determinism violation in this period.") : tr("fluidgrids.insights.codeWorkflows.violations", "{{runs}} runs hit a determinism violation; {{open}} are still retrying until a fixed version is deployed.", {
4802
+ runs: determinism.violatingRuns.toLocaleString(),
4803
+ open: determinism.openViolatingRuns.toLocaleString()
4804
+ })
4805
+ }),
4806
+ determinism.topWorkflows.length > 0 && /* @__PURE__ */ jsx("ul", {
4807
+ className: "mt-2 divide-y divide-border-default rounded-lg border border-border-default",
4808
+ children: determinism.topWorkflows.map((row) => /* @__PURE__ */ jsxs("li", {
4809
+ className: "flex flex-col gap-1 px-3 py-2 text-sm sm:flex-row sm:items-center sm:gap-4",
4810
+ children: [/* @__PURE__ */ jsx(Link, {
4811
+ to: runsOfWorkflowPath(row.workflowKey),
4812
+ className: "min-w-0 flex-1 truncate font-medium text-text-link hover:underline",
4813
+ children: row.name || row.workflowKey
4814
+ }), /* @__PURE__ */ jsx("span", {
4815
+ className: "text-xs text-text-secondary",
4816
+ children: tr("fluidgrids.insights.codeWorkflows.violationRow", "{{runs}} runs · {{open}} open · last {{when}}", {
4817
+ runs: row.runs.toLocaleString(),
4818
+ open: row.openRuns.toLocaleString(),
4819
+ when: new Date(row.lastViolationAt).toLocaleString()
4820
+ })
4821
+ })]
4822
+ }, row.workflowKey))
4823
+ })
4824
+ ]
4825
+ });
4826
+ }
4827
+ function availabilityLabel(availability, tr) {
4828
+ switch (availability) {
4829
+ case "MANAGED": return tr("fluidgrids.insights.codeWorkflows.queueManaged", "Managed");
4830
+ case "AVAILABLE": return tr("fluidgrids.insights.codeWorkflows.queueAvailable", "Workers online");
4831
+ case "UNAVAILABLE": return tr("fluidgrids.insights.codeWorkflows.queueUnavailable", "No workers, tasks waiting");
4832
+ case "IDLE": return tr("fluidgrids.insights.codeWorkflows.queueIdle", "No workers");
4833
+ case "UNKNOWN": return tr("fluidgrids.insights.codeWorkflows.queueUnknown", "Unknown");
4834
+ }
4835
+ }
4836
+ function availabilityClass(availability) {
4837
+ switch (availability) {
4838
+ case "MANAGED":
4839
+ case "AVAILABLE": return "bg-status-success-bg-subtle text-status-success-text";
4840
+ case "UNAVAILABLE": return "bg-status-error-bg-subtle text-status-error-text";
4841
+ case "IDLE": return "bg-status-warning-bg-subtle text-status-warning-text";
4842
+ case "UNKNOWN": return "bg-surface-sunken text-text-secondary";
4843
+ }
4844
+ }
4845
+ function WorkerAvailability({ queues, loading, error, onRetry, tr }) {
4846
+ return /* @__PURE__ */ jsxs("div", {
4847
+ className: "mt-5",
4848
+ "data-testid": "insights-code-workers",
4849
+ children: [
4850
+ /* @__PURE__ */ jsx("h3", {
4851
+ className: "text-sm font-semibold text-text-primary",
4852
+ children: tr("fluidgrids.insights.codeWorkflows.workersTitle", "Worker availability")
4853
+ }),
4854
+ /* @__PURE__ */ jsx("p", {
4855
+ className: "mt-0.5 text-xs text-text-secondary",
4856
+ children: tr("fluidgrids.insights.codeWorkflows.workersHelp", "Right now, per task queue. A self-hosted queue has workers when one polled it in the last two minutes.")
4857
+ }),
4858
+ error && !queues ? /* @__PURE__ */ jsx(ErrorNotice, {
4859
+ message: error,
4860
+ label: tr("fluidgrids.insights.codeWorkflows.workersError", "Could not load worker availability"),
4861
+ onRetry,
4862
+ tr
4863
+ }) : !queues ? /* @__PURE__ */ jsx("div", {
4864
+ className: "mt-3 h-12 animate-pulse rounded-lg border border-border-default bg-surface-sunken",
4865
+ "aria-busy": loading
4866
+ }) : /* @__PURE__ */ jsx("ul", {
4867
+ className: "mt-3 divide-y divide-border-default rounded-lg border border-border-default",
4868
+ children: queues.map((queue) => /* @__PURE__ */ jsxs("li", {
4869
+ className: "flex flex-col gap-1 px-3 py-2 text-sm sm:flex-row sm:items-center sm:gap-4",
4870
+ "data-testid": "insights-code-queue",
4871
+ children: [
4872
+ /* @__PURE__ */ jsxs("span", {
4873
+ className: "min-w-0 flex-1 truncate font-medium text-text-primary",
4874
+ children: [queue.name, queue.environments.length > 0 && /* @__PURE__ */ jsx("span", {
4875
+ className: "ml-2 text-xs font-normal text-text-secondary",
4876
+ children: queue.environments.join(", ")
4877
+ })]
4878
+ }),
4879
+ /* @__PURE__ */ jsx("span", {
4880
+ className: "text-xs text-text-secondary",
4881
+ children: tr("fluidgrids.insights.codeWorkflows.queueRow", "{{pollers}} workers · {{waiting}} waiting · oldest {{age}}", {
4882
+ pollers: queue.pollers.toLocaleString(),
4883
+ waiting: (queue.workflowBacklog + queue.activityBacklog).toLocaleString(),
4884
+ age: formatDuration(queue.oldestBacklogAgeSeconds)
4885
+ })
4886
+ }),
4887
+ /* @__PURE__ */ jsx("span", {
4888
+ className: `w-fit rounded-full px-2 py-0.5 text-xs ${availabilityClass(queue.availability)}`,
4889
+ children: availabilityLabel(queue.availability, tr)
4890
+ })
4891
+ ]
4892
+ }, queue.name))
4893
+ })
4894
+ ]
4895
+ });
4896
+ }
4897
+
3913
4898
  // src/modules/observability/hooks/useErrorAnalytics.ts
3914
4899
  /**
3915
4900
  * useErrorAnalytics — the workspace's failed runs over the last
@@ -4024,6 +5009,8 @@ function InsightsPage({ showErrors = false }) {
4024
5009
  const { retryRun, retryFromTriage, retryLoading } = useInsightsRetry();
4025
5010
  const { allowed: canManageTriage } = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.WORKFLOW_PUBLISH);
4026
5011
  const { allowed: canRetryRuns } = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.WORKFLOW_RUN_EXECUTE);
5012
+ const codeWorkflowsEnabled = useDurableFunctionNodesEnabled();
5013
+ const { allowed: canReadQueues } = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.TASK_QUEUE_READ);
4027
5014
  const [activeTab, setActiveTab] = useState(showErrors ? "errors" : "overview");
4028
5015
  const errorAnalytics = useErrorAnalytics(activeTab === "errors");
4029
5016
  const failureBreakdown = useMemo(() => getFailureBreakdown(failedRuns), [failedRuns]);
@@ -4081,6 +5068,10 @@ function InsightsPage({ showErrors = false }) {
4081
5068
  onOpenRun: (runId) => navigate(`../runs/${runId}`),
4082
5069
  onOpenProposal: (target) => navigate(`../${proposalCanvasPath(target.workflowKey, target.version, target.proposalId)}`)
4083
5070
  }),
5071
+ activeTab === "overview" && codeWorkflowsEnabled && /* @__PURE__ */ jsx("div", {
5072
+ className: "mb-6",
5073
+ children: /* @__PURE__ */ jsx(CodeWorkflowsPanel, { canReadQueues })
5074
+ }),
4084
5075
  activeTab === "overview" && /* @__PURE__ */ jsx("div", {
4085
5076
  className: "mb-6",
4086
5077
  children: /* @__PURE__ */ jsx(AiSpendPanel, {})
@@ -4440,4 +5431,4 @@ function ErrorAnalyticsPage() {
4440
5431
  return /* @__PURE__ */ jsx(InsightsPage, { showErrors: true });
4441
5432
  }
4442
5433
 
4443
- export { ContinuousOptimisationSettingsDocument as a, ProposeOptimisationDocument as c, WorkspaceAiUsageDocument as d, ErrorAnalyticsDocument as f, OptimisationSuggestionsDocument as i, FgRunOptimisationScanDocument as l, InsightsPage as n, SnoozeOptimisationSuggestionDocument as o, InsightsPage_exports as r, SetContinuousOptimisationEnabledDocument as s, ErrorAnalyticsPage as t, DismissOptimisationSuggestionDocument as u };
5434
+ export { ContinuousOptimisationSettingsDocument as a, ProposeOptimisationDocument as c, WorkspaceAiUsageDocument as d, ErrorAnalyticsDocument as f, OptimisationSuggestionsDocument as i, FgRunOptimisationScanDocument as l, CodeWorkflowInsightsDocument as m, InsightsPage as n, SnoozeOptimisationSuggestionDocument as o, TaskQueueAvailabilityDocument as p, InsightsPage_exports as r, SetContinuousOptimisationEnabledDocument as s, ErrorAnalyticsPage as t, DismissOptimisationSuggestionDocument as u };