@arbidocs/blocks 0.4.142 → 0.4.144

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 (125) hide show
  1. package/dist/agents/index.cjs +435 -432
  2. package/dist/agents/index.js +7 -4
  3. package/dist/chat/index.cjs +139 -138
  4. package/dist/chat/index.js +4 -3
  5. package/dist/{chunk-N5X37J3D.js → chunk-2FJMTZNJ.js} +8 -5
  6. package/dist/chunk-2FJMTZNJ.js.map +1 -0
  7. package/dist/chunk-33ZOUJXA.js +561 -0
  8. package/dist/chunk-33ZOUJXA.js.map +1 -0
  9. package/dist/{chunk-S24XEVPS.cjs → chunk-464YPRAE.cjs} +33 -2
  10. package/dist/chunk-464YPRAE.cjs.map +1 -0
  11. package/dist/{chunk-7YLJHTDC.cjs → chunk-5A2QQAF5.cjs} +11 -11
  12. package/dist/{chunk-7YLJHTDC.cjs.map → chunk-5A2QQAF5.cjs.map} +1 -1
  13. package/dist/chunk-76L6LOP3.cjs +308 -0
  14. package/dist/chunk-76L6LOP3.cjs.map +1 -0
  15. package/dist/{chunk-FXG7TFAG.js → chunk-7NGAWGA3.js} +3 -3
  16. package/dist/{chunk-FXG7TFAG.js.map → chunk-7NGAWGA3.js.map} +1 -1
  17. package/dist/chunk-A6J2IBUG.js +1602 -0
  18. package/dist/chunk-A6J2IBUG.js.map +1 -0
  19. package/dist/{chunk-DPGFEMVT.cjs → chunk-ABUO6PIQ.cjs} +51 -1659
  20. package/dist/chunk-ABUO6PIQ.cjs.map +1 -0
  21. package/dist/chunk-AOSUHWIL.js +98 -0
  22. package/dist/chunk-AOSUHWIL.js.map +1 -0
  23. package/dist/{chunk-GBS6QVGS.cjs → chunk-BUWBXJ2N.cjs} +5 -5
  24. package/dist/{chunk-GBS6QVGS.cjs.map → chunk-BUWBXJ2N.cjs.map} +1 -1
  25. package/dist/chunk-CQCC7LE7.js +210 -0
  26. package/dist/chunk-CQCC7LE7.js.map +1 -0
  27. package/dist/{chunk-UGCKUXRV.js → chunk-CSI2B2H5.js} +3 -3
  28. package/dist/{chunk-UGCKUXRV.js.map → chunk-CSI2B2H5.js.map} +1 -1
  29. package/dist/{chunk-JO3EMZ4X.js → chunk-GWSGIZQ5.js} +3 -3
  30. package/dist/{chunk-JO3EMZ4X.js.map → chunk-GWSGIZQ5.js.map} +1 -1
  31. package/dist/{chunk-OWCEQKAR.cjs → chunk-JSTKEZBS.cjs} +21 -318
  32. package/dist/chunk-JSTKEZBS.cjs.map +1 -0
  33. package/dist/{chunk-CKCBBYTA.js → chunk-KSHKTOY2.js} +5 -205
  34. package/dist/chunk-KSHKTOY2.js.map +1 -0
  35. package/dist/chunk-LJJJ6CYH.cjs +62 -0
  36. package/dist/chunk-LJJJ6CYH.cjs.map +1 -0
  37. package/dist/chunk-MHFF5N65.cjs +101 -0
  38. package/dist/chunk-MHFF5N65.cjs.map +1 -0
  39. package/dist/{chunk-GYAUJ4KT.js → chunk-MTSKK3BN.js} +32 -3
  40. package/dist/chunk-MTSKK3BN.js.map +1 -0
  41. package/dist/chunk-O2ODDTMA.cjs +1627 -0
  42. package/dist/chunk-O2ODDTMA.cjs.map +1 -0
  43. package/dist/{chunk-3BFGL2JL.cjs → chunk-ODRHHWHY.cjs} +4 -4
  44. package/dist/{chunk-3BFGL2JL.cjs.map → chunk-ODRHHWHY.cjs.map} +1 -1
  45. package/dist/{chunk-Y5KTM3V5.js → chunk-PDKM27DF.js} +17 -295
  46. package/dist/chunk-PDKM27DF.js.map +1 -0
  47. package/dist/{chunk-OAL3B2ZU.cjs → chunk-PLJ7PHWU.cjs} +5 -5
  48. package/dist/{chunk-OAL3B2ZU.cjs.map → chunk-PLJ7PHWU.cjs.map} +1 -1
  49. package/dist/chunk-RA3ZJ45L.cjs +574 -0
  50. package/dist/chunk-RA3ZJ45L.cjs.map +1 -0
  51. package/dist/chunk-RFIBUWLF.cjs +232 -0
  52. package/dist/chunk-RFIBUWLF.cjs.map +1 -0
  53. package/dist/{chunk-MIDXCYZB.cjs → chunk-RQ2Y7USX.cjs} +15 -235
  54. package/dist/chunk-RQ2Y7USX.cjs.map +1 -0
  55. package/dist/chunk-SV65E4QW.js +58 -0
  56. package/dist/chunk-SV65E4QW.js.map +1 -0
  57. package/dist/chunk-TZGBRLPK.js +288 -0
  58. package/dist/chunk-TZGBRLPK.js.map +1 -0
  59. package/dist/{chunk-PROK33G6.js → chunk-X3TGXEFS.js} +11 -1596
  60. package/dist/chunk-X3TGXEFS.js.map +1 -0
  61. package/dist/{chunk-HIJUXAWS.cjs → chunk-XGZX22ET.cjs} +77 -74
  62. package/dist/chunk-XGZX22ET.cjs.map +1 -0
  63. package/dist/{chunk-5BXEYYH6.js → chunk-ZM26YEOT.js} +3 -3
  64. package/dist/{chunk-5BXEYYH6.js.map → chunk-ZM26YEOT.js.map} +1 -1
  65. package/dist/connect/docx.cjs +35 -6
  66. package/dist/connect/docx.cjs.map +1 -1
  67. package/dist/connect/docx.d.ts +9 -2
  68. package/dist/connect/docx.js +29 -5
  69. package/dist/connect/docx.js.map +1 -1
  70. package/dist/connect/index.cjs +126 -339
  71. package/dist/connect/index.cjs.map +1 -1
  72. package/dist/connect/index.d.ts +1 -0
  73. package/dist/connect/index.js +15 -260
  74. package/dist/connect/index.js.map +1 -1
  75. package/dist/connection/docx/ConnectedNativeDocxComparison.d.ts +5 -0
  76. package/dist/connection/docx/ConnectedNativeDocxEditor.d.ts +16 -0
  77. package/dist/connection/{ConnectedStreamedWordArtifact.d.ts → docx/ConnectedStreamedWordArtifact.d.ts} +1 -1
  78. package/dist/connection/docx/support.d.ts +27 -0
  79. package/dist/connection/docx/useConnectedDocxReferences.d.ts +2 -0
  80. package/dist/connection/docx/useConnectedHouseTemplate.d.ts +2 -0
  81. package/dist/docx/index.cjs +17 -63
  82. package/dist/docx/index.cjs.map +1 -1
  83. package/dist/docx/index.d.ts +1 -0
  84. package/dist/docx/index.js +2 -64
  85. package/dist/docx/index.js.map +1 -1
  86. package/dist/docx/template/candidates.d.ts +16 -0
  87. package/dist/index.cjs +625 -609
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.d.ts +1 -0
  90. package/dist/index.js +13 -9
  91. package/dist/index.js.map +1 -1
  92. package/dist/lib/deep-link.d.ts +46 -0
  93. package/dist/settings/index.cjs +10 -9
  94. package/dist/settings/index.cjs.map +1 -1
  95. package/dist/settings/index.js +2 -1
  96. package/dist/settings/index.js.map +1 -1
  97. package/dist/studio/index.cjs +5 -4
  98. package/dist/studio/index.cjs.map +1 -1
  99. package/dist/studio/index.js +4 -3
  100. package/dist/studio/index.js.map +1 -1
  101. package/dist/workflow-canvas/index.cjs +58 -55
  102. package/dist/workflow-canvas/index.cjs.map +1 -1
  103. package/dist/workflow-canvas/index.js +7 -4
  104. package/dist/workflow-canvas/index.js.map +1 -1
  105. package/node_modules/@arbidocs/coedit/package.json +1 -1
  106. package/package.json +4 -4
  107. package/dist/chunk-4TR5QCCX.cjs +0 -43
  108. package/dist/chunk-4TR5QCCX.cjs.map +0 -1
  109. package/dist/chunk-7NDW4KF4.cjs +0 -112
  110. package/dist/chunk-7NDW4KF4.cjs.map +0 -1
  111. package/dist/chunk-CKCBBYTA.js.map +0 -1
  112. package/dist/chunk-DPGFEMVT.cjs.map +0 -1
  113. package/dist/chunk-ETXYVO6E.js +0 -109
  114. package/dist/chunk-ETXYVO6E.js.map +0 -1
  115. package/dist/chunk-GYAUJ4KT.js.map +0 -1
  116. package/dist/chunk-HIJUXAWS.cjs.map +0 -1
  117. package/dist/chunk-MCKOZACC.js +0 -41
  118. package/dist/chunk-MCKOZACC.js.map +0 -1
  119. package/dist/chunk-MIDXCYZB.cjs.map +0 -1
  120. package/dist/chunk-N5X37J3D.js.map +0 -1
  121. package/dist/chunk-OWCEQKAR.cjs.map +0 -1
  122. package/dist/chunk-PROK33G6.js.map +0 -1
  123. package/dist/chunk-S24XEVPS.cjs.map +0 -1
  124. package/dist/chunk-Y5KTM3V5.js.map +0 -1
  125. package/dist/connection/ConnectedNativeDocxEditor.d.ts +0 -6
@@ -0,0 +1,1602 @@
1
+ "use client";
2
+ import { FoldSection, QuickActionDialogHeader, AddFilesFirst, StartTiles, ScopePicker } from './chunk-3RJN2VTL.js';
3
+ import { DocumentPicker, TriStateFilterMenu } from './chunk-KSHKTOY2.js';
4
+ import { useControllableState } from './chunk-RLWIUUQ5.js';
5
+ import { EmptyState } from './chunk-P6GHJSLR.js';
6
+ import { SelectionBar, SelectionBarAction } from './chunk-NUNKSZKU.js';
7
+ import { FilterInput } from './chunk-YU2KUMGE.js';
8
+ import { GridView } from './chunk-N5YEF3LC.js';
9
+ import { TabHeader } from './chunk-4WWM3GQ5.js';
10
+ import { defaultInputs, validateInputs, buildLaunch, isWorkflowScope } from './chunk-TZGBRLPK.js';
11
+ import { TONE_DOT, TONE_SURFACE, TONE_SOLID_BORDER, TONE_BORDER } from './chunk-AUS3KBHJ.js';
12
+ import { testIdOr, prefixedTestId } from './chunk-7F6CBP3Z.js';
13
+ import { initials } from './chunk-OXF2IFXG.js';
14
+ import { useState, useId, useMemo, useEffect, useRef } from 'react';
15
+ import { Loader2, Play, FolderPlus, ImageIcon, X, MoreHorizontal, History, Pencil, Trash2, Workflow, Link2, Clock, Bell, MousePointerClick, Check } from 'lucide-react';
16
+ import { cn, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Dialog, DialogContent, Button, getEntityColor, UserEntity, getEntityColorStyles, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, badgeVariants, VisibilityToggle, Switch, Input, Textarea } from '@arbidocs/react/ui';
17
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
18
+
19
+ var DEFAULT_SCHEMA_FORM_LABELS = {
20
+ optional: "(optional)",
21
+ advanced: "More options",
22
+ errors: {
23
+ required: "This is needed to continue",
24
+ min: "Too small",
25
+ max: "Too large",
26
+ number: "Enter a number"
27
+ }
28
+ };
29
+ var TILE_MAX = 4;
30
+ function FieldControl({
31
+ field,
32
+ value,
33
+ error,
34
+ onChange,
35
+ l,
36
+ idFor,
37
+ renderScope,
38
+ renderDocuments,
39
+ renderIcon,
40
+ onEnterSubmit,
41
+ people
42
+ }) {
43
+ const id = `${idFor()}-control`;
44
+ const testId = idFor();
45
+ switch (field.type) {
46
+ case "text":
47
+ return /* @__PURE__ */ jsx(
48
+ Input,
49
+ {
50
+ id,
51
+ "data-testid": testId,
52
+ value: String(value ?? ""),
53
+ placeholder: field.placeholder,
54
+ "aria-required": field.required || void 0,
55
+ "aria-invalid": error ? true : void 0,
56
+ "aria-describedby": error ? idFor("error") : void 0,
57
+ onChange: (e) => onChange(e.target.value)
58
+ }
59
+ );
60
+ case "longtext":
61
+ return /* @__PURE__ */ jsx(
62
+ Textarea,
63
+ {
64
+ id,
65
+ "data-testid": testId,
66
+ value: String(value ?? ""),
67
+ placeholder: field.placeholder,
68
+ "aria-required": field.required || void 0,
69
+ "aria-invalid": error ? true : void 0,
70
+ "aria-describedby": error ? idFor("error") : void 0,
71
+ className: "min-h-[96px]",
72
+ onChange: (e) => onChange(e.target.value),
73
+ onKeyDown: (e) => {
74
+ if (onEnterSubmit && e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
75
+ e.preventDefault();
76
+ onEnterSubmit();
77
+ }
78
+ }
79
+ }
80
+ );
81
+ case "number":
82
+ return /* @__PURE__ */ jsx(
83
+ Input,
84
+ {
85
+ id,
86
+ "data-testid": testId,
87
+ type: "number",
88
+ inputMode: "decimal",
89
+ min: field.min,
90
+ max: field.max,
91
+ value: value === void 0 ? "" : String(value),
92
+ placeholder: field.placeholder,
93
+ "aria-invalid": error ? true : void 0,
94
+ "aria-describedby": error ? idFor("error") : void 0,
95
+ onChange: (e) => onChange(e.target.value === "" ? "" : Number(e.target.value))
96
+ }
97
+ );
98
+ case "date":
99
+ return /* @__PURE__ */ jsx(
100
+ Input,
101
+ {
102
+ id,
103
+ "data-testid": testId,
104
+ type: "date",
105
+ value: String(value ?? ""),
106
+ "aria-invalid": error ? true : void 0,
107
+ "aria-describedby": error ? idFor("error") : void 0,
108
+ onChange: (e) => onChange(e.target.value)
109
+ }
110
+ );
111
+ case "boolean":
112
+ return /* @__PURE__ */ jsx(
113
+ Switch,
114
+ {
115
+ id,
116
+ "data-testid": testId,
117
+ checked: Boolean(value),
118
+ onCheckedChange: (checked) => onChange(checked)
119
+ }
120
+ );
121
+ case "select": {
122
+ const options = field.options ?? [];
123
+ if (options.length > 0 && options.length <= TILE_MAX) {
124
+ const compact = options.every((o) => !o.icon && !o.description);
125
+ return /* @__PURE__ */ jsx(
126
+ "div",
127
+ {
128
+ role: "radiogroup",
129
+ "aria-label": field.label,
130
+ className: "flex flex-wrap gap-2",
131
+ "data-testid": testId,
132
+ children: options.map((option) => /* @__PURE__ */ jsx(
133
+ ChoiceTile,
134
+ {
135
+ option,
136
+ selected: value === option.value,
137
+ compact,
138
+ renderIcon,
139
+ testId: prefixedTestId(testId, option.value, {
140
+ testId: `workflow-field-${field.name}-${option.value}`
141
+ }),
142
+ onSelect: () => onChange(option.value)
143
+ },
144
+ option.value
145
+ ))
146
+ }
147
+ );
148
+ }
149
+ return /* @__PURE__ */ jsxs(Select, { value: String(value ?? ""), onValueChange: (v) => onChange(v), children: [
150
+ /* @__PURE__ */ jsx(SelectTrigger, { id, "data-testid": testId, className: "pointer-coarse:min-h-11", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: field.placeholder }) }),
151
+ /* @__PURE__ */ jsx(SelectContent, { children: options.map((o) => /* @__PURE__ */ jsx(SelectItem, { value: o.value, children: o.label }, o.value)) })
152
+ ] });
153
+ }
154
+ case "scope": {
155
+ const scope = isWorkflowScope(value) ? value : { folders: [], labels: [] };
156
+ return /* @__PURE__ */ jsx("div", { "data-testid": testId, children: renderScope?.(field, scope, onChange) });
157
+ }
158
+ case "documents": {
159
+ const picked = isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
160
+ return /* @__PURE__ */ jsx("div", { "data-testid": testId, children: renderDocuments?.(field, picked, onChange) });
161
+ }
162
+ case "person":
163
+ return people?.length ? /* @__PURE__ */ jsxs(
164
+ "select",
165
+ {
166
+ id,
167
+ "data-testid": testId,
168
+ value: String(value ?? ""),
169
+ "aria-required": field.required || void 0,
170
+ "aria-invalid": error ? true : void 0,
171
+ onChange: (e) => onChange(e.target.value),
172
+ className: "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm",
173
+ children: [
174
+ /* @__PURE__ */ jsx("option", { value: "", children: field.placeholder ?? "" }),
175
+ people.map((p) => /* @__PURE__ */ jsx("option", { value: p.value, children: p.label }, p.value))
176
+ ]
177
+ }
178
+ ) : /* @__PURE__ */ jsx(
179
+ Input,
180
+ {
181
+ id,
182
+ "data-testid": testId,
183
+ value: String(value ?? ""),
184
+ placeholder: field.placeholder ?? "usr-\u2026",
185
+ "aria-required": field.required || void 0,
186
+ "aria-invalid": error ? true : void 0,
187
+ onChange: (e) => onChange(e.target.value)
188
+ }
189
+ );
190
+ }
191
+ }
192
+ function ChoiceTile({
193
+ option,
194
+ selected,
195
+ compact,
196
+ renderIcon,
197
+ testId,
198
+ onSelect
199
+ }) {
200
+ const tone = option.tone;
201
+ return /* @__PURE__ */ jsxs(
202
+ "button",
203
+ {
204
+ type: "button",
205
+ role: "radio",
206
+ "aria-checked": selected,
207
+ "data-testid": testId,
208
+ "data-tone": tone,
209
+ onClick: onSelect,
210
+ className: cn(
211
+ // Sized to its label (flex-basis auto), growing to share the row, never wider than it.
212
+ "flex max-w-full min-w-[min(4rem,100%)] flex-auto flex-col items-center justify-center gap-1.5 rounded-lg border text-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
213
+ compact ? "min-h-9 px-3 py-1.5 pointer-coarse:min-h-11" : "min-h-24 p-3 pointer-coarse:min-h-28",
214
+ tone ? selected ? cn(TONE_SURFACE[tone], TONE_SOLID_BORDER[tone]) : cn(TONE_BORDER[tone], "bg-card [&:hover]:bg-muted") : selected ? "border-primary bg-primary/10" : "border-border bg-card [&:hover]:border-primary [&:hover]:bg-muted"
215
+ ),
216
+ children: [
217
+ option.icon && renderIcon && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: renderIcon(option.icon) }),
218
+ /* @__PURE__ */ jsxs(
219
+ "span",
220
+ {
221
+ className: cn(
222
+ "flex max-w-full items-center gap-1.5 text-sm font-medium",
223
+ tone && selected ? void 0 : "text-foreground"
224
+ ),
225
+ children: [
226
+ selected ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 shrink-0", "aria-hidden": true }) : tone && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("size-2 shrink-0 rounded-full", TONE_DOT[tone]) }),
227
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 break-words", children: option.label })
228
+ ]
229
+ }
230
+ ),
231
+ option.description && /* @__PURE__ */ jsx("span", { className: "max-w-full text-xs break-words text-muted-foreground", children: option.description })
232
+ ]
233
+ }
234
+ );
235
+ }
236
+ function FormField(props) {
237
+ const { field, error, l, idFor } = props;
238
+ const isBoolean = field.type === "boolean";
239
+ const showOptional = !field.required && field.type !== "boolean" && field.type !== "scope";
240
+ const label = /* @__PURE__ */ jsxs(
241
+ Label,
242
+ {
243
+ htmlFor: `${idFor()}-control`,
244
+ className: isBoolean ? "cursor-pointer font-normal" : void 0,
245
+ children: [
246
+ field.label,
247
+ showOptional && /* @__PURE__ */ jsxs(Fragment, { children: [
248
+ " ",
249
+ /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: l.optional })
250
+ ] })
251
+ ]
252
+ }
253
+ );
254
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", "data-slot": "schema-field", "data-field": field.name, children: [
255
+ isBoolean ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 pointer-coarse:min-h-11", children: [
256
+ /* @__PURE__ */ jsx(FieldControl, { ...props }),
257
+ label
258
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
259
+ field.type !== "scope" && label,
260
+ /* @__PURE__ */ jsx(FieldControl, { ...props })
261
+ ] }),
262
+ field.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: field.description }),
263
+ error && /* @__PURE__ */ jsx(
264
+ "p",
265
+ {
266
+ id: idFor("error"),
267
+ role: "alert",
268
+ className: "text-xs text-destructive",
269
+ "data-testid": idFor("error"),
270
+ children: l.errors[error]
271
+ }
272
+ )
273
+ ] });
274
+ }
275
+ function SchemaForm({
276
+ fields,
277
+ values,
278
+ onChange,
279
+ errors,
280
+ renderScope,
281
+ renderDocuments,
282
+ renderIcon,
283
+ onEnterSubmit,
284
+ people,
285
+ testIdPrefix,
286
+ labels,
287
+ className
288
+ }) {
289
+ const l = {
290
+ ...DEFAULT_SCHEMA_FORM_LABELS,
291
+ ...labels,
292
+ errors: { ...DEFAULT_SCHEMA_FORM_LABELS.errors, ...labels?.errors }
293
+ };
294
+ const [advancedOpen, setAdvancedOpen] = useState(false);
295
+ const common = fields.filter((f) => !f.advanced);
296
+ const advanced = fields.filter((f) => f.advanced);
297
+ const render = (field) => /* @__PURE__ */ jsx(
298
+ FormField,
299
+ {
300
+ field,
301
+ value: values[field.name],
302
+ error: errors?.[field.name],
303
+ onChange: (v) => onChange(field.name, v),
304
+ l,
305
+ idFor: (suffix) => suffix ? `${testIdOr(testIdPrefix, { testId: "workflow-field" })}-${field.name}-${suffix}` : `${testIdOr(testIdPrefix, { testId: "workflow-field" })}-${field.name}`,
306
+ renderScope,
307
+ renderDocuments,
308
+ renderIcon,
309
+ onEnterSubmit,
310
+ people
311
+ },
312
+ field.name
313
+ );
314
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4", className), "data-slot": "schema-form", children: [
315
+ common.map(render),
316
+ advanced.length > 0 && /* @__PURE__ */ jsx(
317
+ FoldSection,
318
+ {
319
+ label: l.advanced,
320
+ open: advancedOpen,
321
+ onOpenChange: setAdvancedOpen,
322
+ testId: `${testIdOr(testIdPrefix, { testId: "workflow-field" })}-advanced-toggle`,
323
+ children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: advanced.map(render) })
324
+ }
325
+ )
326
+ ] });
327
+ }
328
+ var DEFAULT_AGENT_SELECT_LABELS = {
329
+ label: "Run as",
330
+ myAssistant: "My assistant"
331
+ };
332
+ var ME = "__me__";
333
+ function AgentSelect({
334
+ agents,
335
+ value,
336
+ defaultValue = "",
337
+ onValueChange,
338
+ hideLabel,
339
+ disabled,
340
+ className,
341
+ labels,
342
+ testId,
343
+ optionTestId
344
+ }) {
345
+ const l = { ...DEFAULT_AGENT_SELECT_LABELS, ...labels };
346
+ const triggerId = useId();
347
+ const [current, setCurrent] = useControllableState(value, defaultValue, onValueChange);
348
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), "data-slot": "agent-select", children: [
349
+ /* @__PURE__ */ jsx(Label, { htmlFor: triggerId, className: hideLabel ? "sr-only" : void 0, children: l.label }),
350
+ /* @__PURE__ */ jsxs(
351
+ Select,
352
+ {
353
+ value: current === "" ? ME : current,
354
+ onValueChange: (v) => setCurrent(v === ME ? "" : v),
355
+ disabled,
356
+ children: [
357
+ /* @__PURE__ */ jsx(
358
+ SelectTrigger,
359
+ {
360
+ id: triggerId,
361
+ "data-testid": testIdOr(testId, { testId: "agent-select" }),
362
+ className: "pointer-coarse:min-h-11",
363
+ children: /* @__PURE__ */ jsx(SelectValue, {})
364
+ }
365
+ ),
366
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
367
+ /* @__PURE__ */ jsx(
368
+ SelectItem,
369
+ {
370
+ value: ME,
371
+ "data-testid": prefixedTestId(optionTestId, "me", {
372
+ testId: "agent-select-option-me"
373
+ }),
374
+ children: l.myAssistant
375
+ }
376
+ ),
377
+ agents.map((agent) => /* @__PURE__ */ jsx(
378
+ SelectItem,
379
+ {
380
+ value: agent.id,
381
+ "data-testid": prefixedTestId(optionTestId, agent.id, {
382
+ testId: `agent-select-option-${agent.id}`
383
+ }),
384
+ children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
385
+ agent.avatar,
386
+ /* @__PURE__ */ jsx("span", { children: agent.label }),
387
+ agent.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: agent.description })
388
+ ] })
389
+ },
390
+ agent.id
391
+ ))
392
+ ] })
393
+ ]
394
+ }
395
+ )
396
+ ] });
397
+ }
398
+ var DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS = {
399
+ start: "Start",
400
+ starting: "Starting\u2026",
401
+ addFilesReason: "This reads your files, and there is nothing to read yet.",
402
+ agentLabel: "Run as"
403
+ };
404
+ function WorkflowConfigDialog({
405
+ workflow,
406
+ open,
407
+ onOpenChange,
408
+ onLaunch,
409
+ initialInputs,
410
+ inputs: inputsProp,
411
+ onInputsChange,
412
+ scopeSource,
413
+ renderScope,
414
+ renderDocuments,
415
+ renderIcon,
416
+ addFilesAction,
417
+ agents,
418
+ agentId: agentIdProp,
419
+ onAgentChange,
420
+ isLaunching,
421
+ submitLabel,
422
+ fieldPlaceholder,
423
+ renderNotice,
424
+ labels,
425
+ formLabels,
426
+ agentLabels,
427
+ testId,
428
+ startTestId,
429
+ className
430
+ }) {
431
+ const l = { ...DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS, ...labels };
432
+ const initialKey = JSON.stringify(initialInputs ?? {});
433
+ const seedKey = JSON.stringify({ ...defaultInputs(workflow), ...JSON.parse(initialKey) });
434
+ const seed = useMemo(() => JSON.parse(seedKey), [seedKey]);
435
+ const [inputs, setInputs] = useControllableState(inputsProp, seed, onInputsChange);
436
+ const [agentId, setAgentId] = useControllableState(
437
+ agentIdProp,
438
+ workflow.defaultAgentId ?? "",
439
+ onAgentChange
440
+ );
441
+ useEffect(() => {
442
+ if (open && inputsProp === void 0) setInputs(seed);
443
+ }, [open, seed]);
444
+ const setField = (name, value) => setInputs({ ...inputs, [name]: value });
445
+ const errors = validateInputs(workflow, inputs);
446
+ const valid = Object.keys(errors).length === 0;
447
+ const visibleErrors = Object.fromEntries(
448
+ Object.entries(errors).filter(([, e]) => e !== "required")
449
+ );
450
+ const scopeField = workflow.inputs.find((f) => f.type === "scope");
451
+ const rawScope = scopeField ? inputs[scopeField.name] : void 0;
452
+ const scopeValue = rawScope && typeof rawScope === "object" ? rawScope : { folders: [], labels: [] };
453
+ const matchedCount = scopeSource && scopeField ? scopeSource.countMatching(scopeValue) : null;
454
+ const noFiles = Boolean(workflow.requiresFiles && scopeSource && scopeSource.totalCount === 0);
455
+ const blockedByScope = matchedCount !== null && matchedCount === 0 && Boolean(workflow.requiresFiles);
456
+ const showAgent = workflow.run.kind === "prompt" && workflow.options?.agent !== false && agents !== void 0 && agents.length > 0;
457
+ const launch = (values) => {
458
+ Promise.resolve(onLaunch(buildLaunch(workflow, values, agentId))).catch(() => {
459
+ });
460
+ };
461
+ const submit = () => {
462
+ if (!valid || noFiles || blockedByScope || isLaunching) return;
463
+ launch(inputs);
464
+ };
465
+ const fields = useMemo(
466
+ () => workflow.inputs.map((f) => {
467
+ const placeholder = fieldPlaceholder?.(f, inputs, workflow);
468
+ return placeholder === void 0 ? f : { ...f, placeholder };
469
+ }),
470
+ [workflow, fieldPlaceholder, inputs]
471
+ );
472
+ const id = testIdOr(testId, { testId: "workflow-dialog" });
473
+ const formRef = useRef(null);
474
+ const firstField = workflow.inputs.find((f) => !f.advanced);
475
+ const focusPromptFirst = firstField?.type === "text" || firstField?.type === "longtext";
476
+ const defaultScopeRender = scopeSource ? (_field, value, onChange) => /* @__PURE__ */ jsx(
477
+ ScopePicker,
478
+ {
479
+ folders: scopeSource.folders,
480
+ unfiledCount: scopeSource.unfiledCount,
481
+ labels: scopeSource.labels,
482
+ totalCount: scopeSource.totalCount,
483
+ matchedCount: scopeSource.countMatching(value),
484
+ scope: value,
485
+ onScopeChange: onChange
486
+ }
487
+ ) : void 0;
488
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
489
+ DialogContent,
490
+ {
491
+ presentation: "sheet",
492
+ className: `max-h-[calc(100dvh-2rem)] overflow-y-auto sm:max-w-xl ${className ?? ""}`,
493
+ "data-testid": id,
494
+ "data-workflow": workflow.id,
495
+ onOpenAutoFocus: (event) => {
496
+ if (!focusPromptFirst || !firstField) return;
497
+ const control = formRef.current?.querySelector(
498
+ `[data-testid="${id}-field-${firstField.name}"]`
499
+ );
500
+ if (!control) return;
501
+ event.preventDefault();
502
+ control.focus();
503
+ if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) {
504
+ const end = control.value.length;
505
+ control.setSelectionRange(end, end);
506
+ }
507
+ },
508
+ children: [
509
+ /* @__PURE__ */ jsx(
510
+ QuickActionDialogHeader,
511
+ {
512
+ icon: workflow.icon && renderIcon ? renderIcon(workflow.icon) : null,
513
+ title: workflow.title,
514
+ description: workflow.details ?? workflow.description,
515
+ descriptionTestId: `${id}-description`
516
+ }
517
+ ),
518
+ /* @__PURE__ */ jsx(
519
+ "form",
520
+ {
521
+ ref: formRef,
522
+ className: "mt-2 flex flex-col gap-4",
523
+ onSubmit: (event) => {
524
+ event.preventDefault();
525
+ submit();
526
+ },
527
+ children: noFiles ? /* @__PURE__ */ jsx(
528
+ AddFilesFirst,
529
+ {
530
+ reason: l.addFilesReason,
531
+ action: addFilesAction,
532
+ testId: `${id}-empty-state`
533
+ }
534
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
535
+ /* @__PURE__ */ jsx(
536
+ SchemaForm,
537
+ {
538
+ fields,
539
+ values: inputs,
540
+ onChange: setField,
541
+ errors: visibleErrors,
542
+ renderScope: renderScope ?? defaultScopeRender,
543
+ renderDocuments,
544
+ renderIcon,
545
+ labels: formLabels,
546
+ onEnterSubmit: submit,
547
+ testIdPrefix: `${id}-field`
548
+ }
549
+ ),
550
+ renderNotice?.({ workflow, inputs }),
551
+ /* @__PURE__ */ jsxs(
552
+ "div",
553
+ {
554
+ className: "flex flex-col gap-3 border-t border-border pt-3 sm:flex-row sm:items-end sm:justify-between",
555
+ "data-slot": "workflow-footer",
556
+ children: [
557
+ showAgent ? /* @__PURE__ */ jsx(
558
+ AgentSelect,
559
+ {
560
+ agents: agents ?? [],
561
+ value: agentId,
562
+ onValueChange: setAgentId,
563
+ labels: { label: l.agentLabel, ...agentLabels },
564
+ testId: `${id}-agent`,
565
+ className: "sm:w-56"
566
+ }
567
+ ) : /* @__PURE__ */ jsx("span", {}),
568
+ /* @__PURE__ */ jsxs(
569
+ Button,
570
+ {
571
+ type: "submit",
572
+ className: "gap-1.5 px-5 pointer-coarse:min-h-11",
573
+ disabled: !valid || blockedByScope || isLaunching,
574
+ "data-testid": testIdOr(startTestId, { testId: "workflow-start-button" }),
575
+ children: [
576
+ isLaunching ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx(Play, { className: "size-4" }),
577
+ isLaunching ? l.starting : submitLabel?.({ workflow, inputs, matchedCount }) ?? workflow.startLabel ?? l.start
578
+ ]
579
+ }
580
+ )
581
+ ]
582
+ }
583
+ )
584
+ ] })
585
+ }
586
+ )
587
+ ]
588
+ }
589
+ ) });
590
+ }
591
+ function WorkflowLauncher({
592
+ workflows,
593
+ tileWorkflows,
594
+ onLaunch,
595
+ showTiles = true,
596
+ caption,
597
+ captionTestId,
598
+ tileTestId,
599
+ disabledReason,
600
+ activeId: activeIdProp,
601
+ onActiveIdChange,
602
+ initialInputsFor,
603
+ testId,
604
+ extraTiles = [],
605
+ className,
606
+ children,
607
+ renderIcon,
608
+ ...dialog
609
+ }) {
610
+ const [activeId, setActiveId] = useControllableState(
611
+ activeIdProp,
612
+ null,
613
+ onActiveIdChange
614
+ );
615
+ const [isLaunching, setIsLaunching] = useState(false);
616
+ const active = workflows.find((w) => w.id === activeId) ?? null;
617
+ const run = async (launch) => {
618
+ setIsLaunching(true);
619
+ try {
620
+ await onLaunch(launch);
621
+ setActiveId(null);
622
+ } finally {
623
+ setIsLaunching(false);
624
+ }
625
+ };
626
+ const select = (workflow) => {
627
+ if (workflow.run.kind === "operation" && workflow.inputs.length === 0) {
628
+ const inputs = defaultInputs(workflow);
629
+ if (Object.keys(validateInputs(workflow, inputs)).length === 0) {
630
+ Promise.resolve(onLaunch(buildLaunch(workflow, inputs, void 0))).catch(() => {
631
+ });
632
+ return;
633
+ }
634
+ }
635
+ setActiveId(workflow.id);
636
+ };
637
+ const tiles = (tileWorkflows ?? workflows).map((workflow) => {
638
+ const reason = disabledReason?.(workflow);
639
+ return {
640
+ id: workflow.id,
641
+ iconNode: workflow.icon && renderIcon ? renderIcon(workflow.icon) : void 0,
642
+ title: workflow.title,
643
+ description: workflow.description,
644
+ onSelect: () => select(workflow),
645
+ disabled: reason !== void 0,
646
+ disabledReason: reason,
647
+ testId: tileTestId?.(workflow) ?? `workflow-tile-${workflow.id}`
648
+ };
649
+ });
650
+ return /* @__PURE__ */ jsxs("div", { className, "data-slot": "workflow-launcher", children: [
651
+ showTiles && /* @__PURE__ */ jsx(
652
+ StartTiles,
653
+ {
654
+ items: [...tiles, ...extraTiles],
655
+ caption,
656
+ captionTestId,
657
+ testId
658
+ }
659
+ ),
660
+ children,
661
+ active && /* @__PURE__ */ jsx(
662
+ WorkflowConfigDialog,
663
+ {
664
+ ...dialog,
665
+ renderIcon,
666
+ workflow: active,
667
+ open: true,
668
+ onOpenChange: (open) => !open && setActiveId(null),
669
+ onLaunch: run,
670
+ isLaunching,
671
+ initialInputs: initialInputsFor?.(active)
672
+ }
673
+ )
674
+ ] });
675
+ }
676
+ function documentScopeLabels(tags) {
677
+ return tags.filter((tag) => {
678
+ if (tag.kind === "search") return false;
679
+ const onDocs = (tag.doctag_count ?? 0) > 0;
680
+ const onFacts = (tag.facttag_count ?? 0) > 0;
681
+ return onDocs || !onFacts;
682
+ });
683
+ }
684
+ var canonical = (path) => (path ?? "").split("/").map((part) => part.trim()).filter(Boolean).join("/");
685
+ function matchWorkflowScope(docs, scope) {
686
+ if (scope.documents?.length) {
687
+ const ids = new Set(scope.documents);
688
+ return docs.filter((doc) => ids.has(doc.external_id));
689
+ }
690
+ if (!scope.folders.length && !scope.labels.length) return docs;
691
+ const folders = scope.folders.map(canonical);
692
+ const labels = new Set(scope.labels);
693
+ return docs.filter((doc) => {
694
+ const folder = canonical(doc.folder);
695
+ return folders.some(
696
+ (path) => path === "" ? folder === "" : folder === path || folder.startsWith(`${path}/`)
697
+ ) || doc.doctags?.some((tag) => labels.has(tag.tag_ext_id));
698
+ });
699
+ }
700
+ function buildWorkflowScopeSource(docs, labels = []) {
701
+ const counts = /* @__PURE__ */ new Map();
702
+ for (const doc of docs) {
703
+ const parts = canonical(doc.folder).split("/").filter(Boolean);
704
+ for (let i = 1; i <= parts.length; i++) {
705
+ const path = parts.slice(0, i).join("/");
706
+ counts.set(path, (counts.get(path) ?? 0) + 1);
707
+ }
708
+ }
709
+ return {
710
+ folders: [...counts].sort(([a], [b]) => a.localeCompare(b)).map(([path, count]) => ({
711
+ path,
712
+ count,
713
+ label: path.split("/").at(-1),
714
+ depth: path.split("/").length - 1
715
+ })),
716
+ unfiledCount: docs.filter((doc) => !canonical(doc.folder)).length,
717
+ labels: labels.map((label) => ({
718
+ id: label.external_id,
719
+ name: label.name,
720
+ color: label.color ?? getEntityColor(label.external_id, "medium"),
721
+ count: docs.filter((doc) => doc.doctags?.some((tag) => tag.tag_ext_id === label.external_id)).length
722
+ })),
723
+ totalCount: docs.length,
724
+ countMatching: (scope) => matchWorkflowScope(docs, scope).length,
725
+ resolveDocuments: (scope) => matchWorkflowScope(docs, scope).map((doc) => doc.external_id)
726
+ };
727
+ }
728
+ var DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS = {
729
+ pickOne: "Pick a file",
730
+ pickMany: "Pick files",
731
+ allDocuments: "All documents",
732
+ addFiles: "Add files",
733
+ adding: "Adding\u2026",
734
+ empty: "No files in this workspace yet. Drop one here, or add it.",
735
+ remove: (name) => `Remove ${name}`,
736
+ pending: (name, status) => `${name}: ${status}. You can still pick it.`,
737
+ status: {
738
+ queued: "Queued",
739
+ uploading: "Uploading",
740
+ encrypting: "Encrypting",
741
+ processing: "Processing",
742
+ parsing: "Processing",
743
+ indexing: "Indexing",
744
+ analysing: "Analysing"
745
+ }
746
+ };
747
+ var isReady = (status) => !status || ["completed", "done", "ready", "success"].includes(status.toLowerCase());
748
+ var byTitle = (a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase());
749
+ function WorkflowDocumentsField({
750
+ field,
751
+ value,
752
+ onChange,
753
+ documents,
754
+ loaded = true,
755
+ thumbnailOf,
756
+ onAddFiles,
757
+ adding,
758
+ labels
759
+ }) {
760
+ const l = { ...DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS, ...labels };
761
+ const ids = value.documents ?? [];
762
+ const max = field.max ?? 1;
763
+ const multiple = max > 1;
764
+ const [isOver, setIsOver] = useState(false);
765
+ const docOf = (id) => documents.find((d) => d.id === id);
766
+ const nameOf = (id) => docOf(id)?.title || id;
767
+ const set = (next) => onChange({ ...value, documents: next });
768
+ const toggle = (id) => set(ids.includes(id) ? ids.filter((d) => d !== id) : [...ids, id].slice(-max));
769
+ const offered = useMemo(
770
+ () => field.accept === "image" ? documents.filter((d) => d.isImage) : documents,
771
+ [documents, field.accept]
772
+ );
773
+ const awaitingAdd = useRef(false);
774
+ const known = useRef(null);
775
+ const latest = useRef({ ids, set });
776
+ latest.current = { ids, set };
777
+ useEffect(() => {
778
+ if (!loaded) return;
779
+ const current = new Set(documents.map((d) => d.id));
780
+ const before = known.current;
781
+ known.current = current;
782
+ if (!before || !awaitingAdd.current) return;
783
+ const fresh = [...current].filter((id) => !before.has(id));
784
+ if (fresh.length === 0) return;
785
+ awaitingAdd.current = false;
786
+ latest.current.set([...latest.current.ids, ...fresh].slice(-max));
787
+ }, [documents, loaded, max]);
788
+ const addFiles = (files) => {
789
+ if (!onAddFiles) return;
790
+ awaitingAdd.current = true;
791
+ onAddFiles(files?.length ? files : void 0);
792
+ };
793
+ const dropProps = onAddFiles ? {
794
+ onDragOver: (e) => {
795
+ e.preventDefault();
796
+ setIsOver(true);
797
+ },
798
+ onDragLeave: () => setIsOver(false),
799
+ onDrop: (e) => {
800
+ e.preventDefault();
801
+ setIsOver(false);
802
+ const files = Array.from(e.dataTransfer?.files ?? []);
803
+ if (files.length) addFiles(files);
804
+ }
805
+ } : {};
806
+ const dropClass = isOver ? "ring-2 ring-primary" : "";
807
+ const addButton = (className, variant = "outline") => onAddFiles && /* @__PURE__ */ jsx(
808
+ Button,
809
+ {
810
+ type: "button",
811
+ size: "sm",
812
+ variant,
813
+ className,
814
+ disabled: adding,
815
+ onClick: () => addFiles(),
816
+ "data-testid": "workflow-add-files",
817
+ children: adding ? l.adding : l.addFiles
818
+ }
819
+ );
820
+ if (loaded && documents.length === 0) {
821
+ return /* @__PURE__ */ jsxs(
822
+ "div",
823
+ {
824
+ className: cn(
825
+ "flex flex-col items-center gap-2 rounded-lg border border-dashed border-border bg-muted/40 px-4 py-6 text-center",
826
+ dropClass
827
+ ),
828
+ "data-testid": "workflow-documents-empty",
829
+ ...dropProps,
830
+ children: [
831
+ /* @__PURE__ */ jsx(FolderPlus, { className: "size-5 text-muted-foreground", "aria-hidden": true }),
832
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: l.empty }),
833
+ addButton(void 0, "default")
834
+ ]
835
+ }
836
+ );
837
+ }
838
+ const pending = ids.flatMap((id) => {
839
+ const status = docOf(id)?.status;
840
+ return isReady(status) ? [] : [{ id, label: l.status[String(status).toLowerCase()] ?? String(status) }];
841
+ });
842
+ const selected = multiple ? void 0 : docOf(ids[0] ?? "");
843
+ return /* @__PURE__ */ jsxs(
844
+ "div",
845
+ {
846
+ className: cn("flex flex-col gap-3 rounded-lg", dropClass),
847
+ "data-testid": `workflow-documents-${field.name}`,
848
+ ...dropProps,
849
+ children: [
850
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
851
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
852
+ DocumentPicker,
853
+ {
854
+ groups: [{ id: "all", heading: l.allDocuments, docs: [...offered].sort(byTitle) }],
855
+ value: multiple ? "" : ids[0] ?? "",
856
+ onValueChange: (id) => multiple ? toggle(id) : set([id]),
857
+ selected,
858
+ selectedIds: multiple ? ids : void 0,
859
+ labels: { placeholder: field.placeholder ?? (multiple ? l.pickMany : l.pickOne) }
860
+ }
861
+ ) }),
862
+ addButton("shrink-0 pointer-coarse:h-11")
863
+ ] }),
864
+ pending.map((p) => /* @__PURE__ */ jsx(
865
+ "p",
866
+ {
867
+ className: "text-xs text-muted-foreground",
868
+ "data-testid": `workflow-document-status-${p.id}`,
869
+ children: l.pending(nameOf(p.id), p.label)
870
+ },
871
+ p.id
872
+ )),
873
+ multiple && ids.length > 0 && /* @__PURE__ */ jsx(
874
+ "div",
875
+ {
876
+ className: "grid grid-cols-2 gap-3 sm:grid-cols-3",
877
+ "data-testid": "workflow-documents-gallery",
878
+ children: ids.map((id) => {
879
+ const thumbnail = thumbnailOf?.(id);
880
+ return /* @__PURE__ */ jsxs(
881
+ "figure",
882
+ {
883
+ className: "relative overflow-hidden rounded-lg border border-border bg-muted/40",
884
+ "data-testid": `workflow-document-${id}`,
885
+ children: [
886
+ thumbnail ? /* @__PURE__ */ jsx(
887
+ "img",
888
+ {
889
+ src: thumbnail,
890
+ alt: nameOf(id),
891
+ className: "aspect-square w-full object-cover"
892
+ }
893
+ ) : /* @__PURE__ */ jsx("div", { className: "flex aspect-square w-full items-center justify-center text-muted-foreground/50", children: /* @__PURE__ */ jsx(ImageIcon, { className: "size-8" }) }),
894
+ /* @__PURE__ */ jsx("figcaption", { className: "truncate bg-background/90 px-2 py-1 text-xs text-muted-foreground", children: nameOf(id) }),
895
+ /* @__PURE__ */ jsx(
896
+ "button",
897
+ {
898
+ type: "button",
899
+ onClick: () => toggle(id),
900
+ "aria-label": l.remove(nameOf(id)),
901
+ className: "absolute right-1 top-1 flex size-6 items-center justify-center rounded-full bg-background/80 text-muted-foreground hover:text-foreground pointer-coarse:size-11",
902
+ "data-testid": `workflow-document-remove-${id}`,
903
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
904
+ }
905
+ )
906
+ ]
907
+ },
908
+ id
909
+ );
910
+ })
911
+ }
912
+ )
913
+ ]
914
+ }
915
+ );
916
+ }
917
+ function PersonPill({ person, size = "sm", testId }) {
918
+ return /* @__PURE__ */ jsx("span", { "data-testid": testId, className: "inline-flex min-w-0", children: /* @__PURE__ */ jsx(
919
+ UserEntity,
920
+ {
921
+ variant: "pill",
922
+ size,
923
+ interactive: false,
924
+ showTooltip: false,
925
+ initials: initials(person.label),
926
+ displayName: person.label,
927
+ avatarStyle: person.id ? getEntityColorStyles(person.id) : void 0,
928
+ isAgent: person.isAgent,
929
+ isMe: person.isMe
930
+ }
931
+ ) });
932
+ }
933
+ var DEFAULT_TASK_TRIGGER_CHIP_LABELS = {
934
+ after: (name) => `After \u201C${name}\u201D is done`,
935
+ afterUnknown: "After another task is done",
936
+ onDemand: "Manual"
937
+ };
938
+ function TriggerIcon({ type, chained }) {
939
+ const cls = "size-3.5 shrink-0 text-muted-foreground";
940
+ if (chained) return /* @__PURE__ */ jsx(Link2, { className: cls, "aria-hidden": true });
941
+ switch (type) {
942
+ case "on_demand":
943
+ return /* @__PURE__ */ jsx(MousePointerClick, { className: cls, "aria-hidden": true });
944
+ case "recurring":
945
+ return /* @__PURE__ */ jsx(Clock, { className: cls, "aria-hidden": true });
946
+ case "event":
947
+ return /* @__PURE__ */ jsx(Bell, { className: cls, "aria-hidden": true });
948
+ default:
949
+ return /* @__PURE__ */ jsx(Clock, { className: cls, "aria-hidden": true });
950
+ }
951
+ }
952
+ function TaskTriggerChip({
953
+ id,
954
+ triggerType,
955
+ summary,
956
+ afterTaskId,
957
+ afterTaskName,
958
+ testId,
959
+ labels
960
+ }) {
961
+ const l = { ...DEFAULT_TASK_TRIGGER_CHIP_LABELS, ...labels };
962
+ const chained = Boolean(afterTaskId);
963
+ const text = chained ? afterTaskName ? l.after(afterTaskName) : l.afterUnknown : triggerType === "on_demand" ? l.onDemand : summary;
964
+ return /* @__PURE__ */ jsxs(
965
+ "span",
966
+ {
967
+ className: "inline-flex min-w-0 max-w-full items-center gap-1.5 text-sm font-normal text-foreground",
968
+ "data-testid": testIdOr(testId, { testId: `task-trigger-${id}` }),
969
+ "data-trigger": chained ? "task" : triggerType,
970
+ children: [
971
+ /* @__PURE__ */ jsx(TriggerIcon, { type: triggerType, chained }),
972
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: text })
973
+ ]
974
+ }
975
+ );
976
+ }
977
+
978
+ // src/agents/tasks/workflowRows.ts
979
+ var isSkillRow = (row) => row.kind === "skill";
980
+ var hasTrigger = (row) => !row.on_demand && Boolean(row.rrule || row.run_at || row.event_kind || row.after_conversation_ext_id);
981
+ function workflowStatus(row) {
982
+ if (isSkillRow(row) || !hasTrigger(row)) return "on_demand";
983
+ return row.active ? "active" : "paused";
984
+ }
985
+ function workflowTriggerType(workflow) {
986
+ if (workflow.on_demand) return "on_demand";
987
+ if (workflow.after_conversation_ext_id) return "after";
988
+ if (workflow.event_kind) return "event";
989
+ if (workflow.rrule) return "recurring";
990
+ if (workflow.run_at) return "one_time";
991
+ return "on_demand";
992
+ }
993
+ function workflowRunStatusLabel(status) {
994
+ if (!status) return "None";
995
+ const labels = {
996
+ completed: "Success",
997
+ success: "Success",
998
+ failed: "Failed",
999
+ running: "In progress",
1000
+ awaiting_authorization: "Awaiting access"
1001
+ };
1002
+ return labels[status] ?? status.replaceAll("_", " ");
1003
+ }
1004
+ function listedRunStatus(status, threadStatus) {
1005
+ if (threadStatus === "done" && status === "running") return "completed";
1006
+ return status;
1007
+ }
1008
+
1009
+ // src/agents/tasks/workflowColumns.tsx
1010
+ var WORKFLOW_COLUMN_ORDER = [
1011
+ "name",
1012
+ "trigger",
1013
+ "last_run",
1014
+ "result",
1015
+ "status",
1016
+ "shared",
1017
+ "actions"
1018
+ ];
1019
+ function cell(render) {
1020
+ return (params) => params.data ? render(params.data) : null;
1021
+ }
1022
+ var time = (iso) => iso ? Date.parse(iso) : Number.POSITIVE_INFINITY;
1023
+ function createWorkflowColumns(o) {
1024
+ const l = o.labels;
1025
+ const base = {
1026
+ sortable: false,
1027
+ cellStyle: { display: "flex", alignItems: "center" }
1028
+ };
1029
+ return [
1030
+ {
1031
+ ...base,
1032
+ colId: "name",
1033
+ sortable: true,
1034
+ headerName: l.colName,
1035
+ flex: 3,
1036
+ minWidth: 210,
1037
+ valueGetter: (p) => p.data?.name.toLowerCase() ?? "",
1038
+ cellRenderer: cell(o.renderName)
1039
+ },
1040
+ {
1041
+ ...base,
1042
+ colId: "trigger",
1043
+ headerName: l.colTrigger,
1044
+ flex: 2.4,
1045
+ minWidth: 185,
1046
+ valueGetter: (p) => p.data ? o.getTriggerText(p.data) : "",
1047
+ cellRenderer: cell(o.renderTrigger)
1048
+ },
1049
+ {
1050
+ ...base,
1051
+ colId: "last_run",
1052
+ sortable: true,
1053
+ headerName: l.colLastRun,
1054
+ flex: 1.4,
1055
+ minWidth: 140,
1056
+ cellStyle: { display: "flex", alignItems: "center", padding: 0 },
1057
+ valueGetter: (p) => time(p.data?.last_fired_at),
1058
+ cellRenderer: cell(o.renderLastRun)
1059
+ },
1060
+ {
1061
+ ...base,
1062
+ colId: "result",
1063
+ headerName: "Result",
1064
+ width: 130,
1065
+ valueGetter: (p) => p.data?.last_run_status ?? "",
1066
+ cellStyle: { display: "flex", alignItems: "center", padding: 0 },
1067
+ cellRenderer: cell(o.renderResult)
1068
+ },
1069
+ {
1070
+ ...base,
1071
+ colId: "status",
1072
+ sortable: true,
1073
+ headerName: l.colStatus,
1074
+ width: 120,
1075
+ valueGetter: (p) => p.data ? workflowStatus(p.data) : "",
1076
+ cellRenderer: cell(o.renderStatus)
1077
+ },
1078
+ {
1079
+ ...base,
1080
+ colId: "shared",
1081
+ headerName: l.colShared,
1082
+ headerTooltip: l.shared,
1083
+ width: 96,
1084
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "center" },
1085
+ valueGetter: (p) => p.data?.shared ?? false,
1086
+ cellRenderer: cell(o.renderShared)
1087
+ },
1088
+ {
1089
+ ...base,
1090
+ colId: "actions",
1091
+ headerName: "",
1092
+ width: 180,
1093
+ minWidth: 180,
1094
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "flex-end" },
1095
+ cellRenderer: cell(o.renderActions)
1096
+ }
1097
+ ];
1098
+ }
1099
+
1100
+ // src/agents/tasks/workflowTableLabels.ts
1101
+ var DEFAULT_WORKFLOW_LIST_LABELS = {
1102
+ colName: "Name",
1103
+ colType: "Type",
1104
+ colTrigger: "When",
1105
+ colAction: "What it does",
1106
+ colAgent: "Agent",
1107
+ colStatus: "Active",
1108
+ colShared: "Shared",
1109
+ colLastRun: "Last run",
1110
+ colNextRun: "Next run",
1111
+ shared: "Shared with the workspace",
1112
+ sharedOwnerOnly: "Only the creator can change who can see this",
1113
+ deleteOwnerOnly: "Only the creator or workspace owner can delete this",
1114
+ typeSkill: "Skill",
1115
+ typeWorkflow: "Workflow",
1116
+ statusActive: "Active",
1117
+ statusPaused: "Inactive",
1118
+ statusOnDemand: "On demand",
1119
+ activeSwitch: (name) => `Active: \u201C${name}\u201D`,
1120
+ agent: "Agent",
1121
+ myAssistant: "My assistant",
1122
+ me: "Me",
1123
+ someone: "Someone",
1124
+ never: "Never",
1125
+ none: "\u2014",
1126
+ reminder: "Reminder",
1127
+ failed: "Failed",
1128
+ lastRunFailed: "Last run failed",
1129
+ openLastRun: "Open the task this run created",
1130
+ editWorkflow: "Edit",
1131
+ run: "Run",
1132
+ runLater: "Run later",
1133
+ runNow: "Run now",
1134
+ runs: "Runs",
1135
+ delete: "Delete",
1136
+ moreActions: "More actions",
1137
+ searchLabel: "Search workflows",
1138
+ searchPlaceholder: "Search workflows and skills\u2026",
1139
+ emptyTitle: "Nothing to run yet",
1140
+ emptyMessage: "Skills and workflows you can run will appear here.",
1141
+ firstRun: "Run a skill now, or choose Run later to save it as a workflow that runs on its own.",
1142
+ noMatches: "Nothing in this view.",
1143
+ filterAll: "All",
1144
+ filterSkills: "Skills",
1145
+ filterWorkflows: "Workflows",
1146
+ filterActive: "Active",
1147
+ filterPaused: "Inactive",
1148
+ makeActive: "Make active",
1149
+ makePaused: "Deactivate",
1150
+ selectAll: "Select all",
1151
+ selectWorkflow: (name) => `Select ${name}`
1152
+ };
1153
+ var ROW_HEIGHT = 40;
1154
+ function WorkflowsTable(props) {
1155
+ const { workflows, isLoading, busyId, header, testId } = props;
1156
+ const l = { ...DEFAULT_WORKFLOW_LIST_LABELS, ...props.labels };
1157
+ const [filterStates, setFilterStates] = useState(/* @__PURE__ */ new Map());
1158
+ const [filterOpen, setFilterOpen] = useState(false);
1159
+ const [query, setQuery] = useState("");
1160
+ const [selected, setSelected] = useState([]);
1161
+ const apiRef = useRef(null);
1162
+ const q = query.trim().toLowerCase();
1163
+ const matches = (w) => !q || `${w.name} ${w.description ?? ""} ${w.prompt ?? ""} ${w.skill_ref ?? ""}`.toLowerCase().includes(q);
1164
+ const inFilter = (w, f) => f === "all" || f === "skills" && isSkillRow(w) || f === "workflows" && !isSkillRow(w) || f === "active" && workflowStatus(w) === "active" || f === "paused" && workflowStatus(w) === "paused";
1165
+ const counts = useMemo(() => {
1166
+ const out = { all: 0, skills: 0, workflows: 0, active: 0, paused: 0 };
1167
+ for (const w of workflows) {
1168
+ if (!matches(w)) continue;
1169
+ for (const f of Object.keys(out)) if (inFilter(w, f)) out[f] += 1;
1170
+ }
1171
+ return out;
1172
+ }, [workflows, q]);
1173
+ const shown = useMemo(
1174
+ () => workflows.filter((w) => {
1175
+ if (!matches(w)) return false;
1176
+ for (const group of [
1177
+ ["skills", "workflows"],
1178
+ ["active", "paused"]
1179
+ ]) {
1180
+ const included = group.filter((f) => filterStates.get(f) === "include");
1181
+ if (included.length && !included.some((f) => inFilter(w, f))) return false;
1182
+ if (group.some((f) => filterStates.get(f) === "exclude" && inFilter(w, f))) return false;
1183
+ }
1184
+ return true;
1185
+ }),
1186
+ [workflows, filterStates, q]
1187
+ );
1188
+ const renderPerson = props.renderPerson ?? ((p) => /* @__PURE__ */ jsx(PersonPill, { person: p }));
1189
+ const actionText = (w) => {
1190
+ if (w.action)
1191
+ return w.action.type === "email_documents" ? "Email latest documents" : "AI Review";
1192
+ if (isSkillRow(w))
1193
+ return w.description || w.skill_ref && props.skillNames?.[w.skill_ref] || w.name;
1194
+ return w.skill_ref ? props.skillNames?.[w.skill_ref] ?? w.skill_ref : w.prompt?.trim() || l.reminder;
1195
+ };
1196
+ const latest = useRef({ props, l, renderPerson, actionText });
1197
+ latest.current = { props, l, renderPerson, actionText };
1198
+ const columnDefs = useMemo(
1199
+ () => createWorkflowColumns({
1200
+ labels: l,
1201
+ getTriggerText: (w) => isSkillRow(w) ? l.statusOnDemand : latest.current.props.describeTrigger(w),
1202
+ renderName: (w) => {
1203
+ const { l: lb } = latest.current;
1204
+ const skill = isSkillRow(w);
1205
+ const text = skill ? latest.current.actionText(w) : w.description || latest.current.actionText(w);
1206
+ const stem = w.name.replace(/…$/, "").trim();
1207
+ const about = text && text.trim() !== w.name.trim() && text.trim() !== stem ? text : "";
1208
+ return /* @__PURE__ */ jsxs("div", { className: "min-w-0 leading-tight", children: [
1209
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
1210
+ /* @__PURE__ */ jsx(
1211
+ "span",
1212
+ {
1213
+ className: cn(
1214
+ "truncate text-sm font-normal",
1215
+ workflowStatus(w) === "paused" && "text-muted-foreground"
1216
+ ),
1217
+ "data-testid": `workflow-name-${w.external_id}`,
1218
+ children: w.name
1219
+ }
1220
+ ),
1221
+ skill && /* @__PURE__ */ jsx(
1222
+ "span",
1223
+ {
1224
+ className: "shrink-0 rounded-full border border-border px-1.5 text-[11px] text-muted-foreground",
1225
+ "data-testid": `workflow-type-${w.external_id}`,
1226
+ children: lb.typeSkill
1227
+ }
1228
+ )
1229
+ ] }),
1230
+ about && !latest.current.props.automationsOnly && /* @__PURE__ */ jsx(
1231
+ "p",
1232
+ {
1233
+ className: "truncate text-xs text-muted-foreground",
1234
+ "data-testid": `workflow-action-${w.external_id}`,
1235
+ children: about
1236
+ }
1237
+ )
1238
+ ] });
1239
+ },
1240
+ renderTrigger: (w) => {
1241
+ const { props: p } = latest.current;
1242
+ const after = w.after_conversation_ext_id;
1243
+ const skill = isSkillRow(w);
1244
+ return /* @__PURE__ */ jsx("div", { className: "min-w-0 leading-tight", children: /* @__PURE__ */ jsx(
1245
+ TaskTriggerChip,
1246
+ {
1247
+ id: w.external_id,
1248
+ testId: `workflow-trigger-${w.external_id}`,
1249
+ triggerType: workflowTriggerType(w),
1250
+ summary: skill ? "" : p.describeTrigger(w),
1251
+ afterTaskId: after,
1252
+ afterTaskName: after ? p.taskNames?.[after] : void 0,
1253
+ labels: p.triggerChipLabels
1254
+ }
1255
+ ) });
1256
+ },
1257
+ renderStatus: (w) => {
1258
+ const { props: p, l: lb } = latest.current;
1259
+ const canEdit = w.is_owner !== false || Boolean(p.canEditShared);
1260
+ return /* @__PURE__ */ jsx(
1261
+ Switch,
1262
+ {
1263
+ checked: hasTrigger(w) && !isSkillRow(w) && Boolean(w.active),
1264
+ disabled: !hasTrigger(w) || isSkillRow(w) || !canEdit || p.busyId === w.external_id,
1265
+ onCheckedChange: (next) => p.onToggleActive(w, next),
1266
+ className: "disabled:data-[state=unchecked]:bg-muted dark:disabled:data-[state=unchecked]:bg-muted",
1267
+ "aria-label": lb.activeSwitch(w.name),
1268
+ "data-testid": `workflow-active-${w.external_id}`
1269
+ }
1270
+ );
1271
+ },
1272
+ renderShared: (w) => {
1273
+ const { props: p, l: lb } = latest.current;
1274
+ if (!p.onToggleShared || isSkillRow(w)) return null;
1275
+ const isCreator = w.is_owner !== false;
1276
+ return /* @__PURE__ */ jsx(
1277
+ VisibilityToggle,
1278
+ {
1279
+ items: { shared: w.shared ?? false },
1280
+ onToggle: (share) => latest.current.props.onToggleShared?.(w, share),
1281
+ disabled: !isCreator || p.busyId === w.external_id,
1282
+ disabledTooltip: lb.sharedOwnerOnly,
1283
+ showLabel: false,
1284
+ "data-testid": `workflow-shared-${w.external_id}`
1285
+ }
1286
+ );
1287
+ },
1288
+ renderLastRun: (w) => {
1289
+ const { props: p, l: lb } = latest.current;
1290
+ const at = w.last_fired_at ?? p.lastRuns?.[w.external_id]?.at;
1291
+ return /* @__PURE__ */ jsx(
1292
+ "button",
1293
+ {
1294
+ type: "button",
1295
+ className: "h-full w-full truncate px-4 text-left text-sm hover:text-primary",
1296
+ onClick: () => p.onViewRuns?.(w),
1297
+ title: "View run history",
1298
+ "data-testid": `workflow-last-run-${w.external_id}`,
1299
+ children: at ? p.formatDate(at) : lb.never
1300
+ }
1301
+ );
1302
+ },
1303
+ renderResult: (w) => {
1304
+ const status = listedRunStatus(
1305
+ w.last_run_status,
1306
+ latest.current.props.lastRuns?.[w.external_id]?.threadStatus
1307
+ );
1308
+ const label = workflowRunStatusLabel(status);
1309
+ return /* @__PURE__ */ jsx(
1310
+ "button",
1311
+ {
1312
+ type: "button",
1313
+ onClick: () => latest.current.props.onViewRuns?.(w),
1314
+ title: "View run history",
1315
+ className: cn(
1316
+ badgeVariants({ variant: "outline" }),
1317
+ "mx-4 cursor-pointer text-xs font-medium",
1318
+ status === "failed" ? "border-red-border bg-red-bg text-red-text hover:bg-red-bg/80" : status === "completed" || status === "success" ? "border-green-border bg-green-bg text-green-text hover:bg-green-bg/80" : status ? "border-primary/20 bg-primary/10 text-primary hover:bg-primary/15" : "border-border bg-muted text-muted-foreground hover:bg-muted/80"
1319
+ ),
1320
+ "data-testid": `workflow-result-${w.external_id}`,
1321
+ children: label
1322
+ }
1323
+ );
1324
+ },
1325
+ renderActions: (w) => {
1326
+ const { props: p, l: lb } = latest.current;
1327
+ const id = w.external_id;
1328
+ const skill = isSkillRow(w);
1329
+ const busy = p.busyId === id;
1330
+ const isOwner = w.is_owner !== false;
1331
+ const canEdit = isOwner || Boolean(p.canEditShared);
1332
+ const canAdmin = isOwner || Boolean(p.isWorkspaceOwner);
1333
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1", children: [
1334
+ (skill || canEdit) && /* @__PURE__ */ jsxs(
1335
+ Button,
1336
+ {
1337
+ size: "sm",
1338
+ variant: "outline",
1339
+ className: "h-8 gap-1.5 pointer-coarse:h-11",
1340
+ disabled: busy,
1341
+ onClick: () => p.onRun(w),
1342
+ "data-testid": `workflow-run-btn-${id}`,
1343
+ children: [
1344
+ /* @__PURE__ */ jsx(Play, { className: "size-3.5", "aria-hidden": true }),
1345
+ lb.run
1346
+ ]
1347
+ }
1348
+ ),
1349
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1350
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
1351
+ Button,
1352
+ {
1353
+ variant: "ghost",
1354
+ size: "icon",
1355
+ className: "size-8 pointer-coarse:size-11",
1356
+ "aria-label": lb.moreActions,
1357
+ "data-testid": `workflow-menu-${id}`,
1358
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4", "aria-hidden": true })
1359
+ }
1360
+ ) }),
1361
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
1362
+ skill && p.onRunLater && /* @__PURE__ */ jsxs(
1363
+ DropdownMenuItem,
1364
+ {
1365
+ onSelect: () => p.onRunLater?.(w),
1366
+ "data-testid": `workflow-run-later-${id}`,
1367
+ children: [
1368
+ /* @__PURE__ */ jsx(History, { className: "mr-2 size-4", "aria-hidden": true }),
1369
+ lb.runLater
1370
+ ]
1371
+ }
1372
+ ),
1373
+ !skill && canEdit && /* @__PURE__ */ jsxs(
1374
+ DropdownMenuItem,
1375
+ {
1376
+ onSelect: () => p.onEdit(w),
1377
+ "data-testid": `workflow-edit-${id}`,
1378
+ children: [
1379
+ /* @__PURE__ */ jsx(Pencil, { className: "mr-2 size-4", "aria-hidden": true }),
1380
+ lb.editWorkflow
1381
+ ]
1382
+ }
1383
+ ),
1384
+ !skill && p.onViewRuns && /* @__PURE__ */ jsxs(
1385
+ DropdownMenuItem,
1386
+ {
1387
+ onSelect: () => p.onViewRuns?.(w),
1388
+ "data-testid": `workflow-runs-${id}`,
1389
+ children: [
1390
+ /* @__PURE__ */ jsx(History, { className: "mr-2 size-4", "aria-hidden": true }),
1391
+ lb.runs
1392
+ ]
1393
+ }
1394
+ ),
1395
+ !skill && canEdit && /* @__PURE__ */ jsxs(Fragment, { children: [
1396
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
1397
+ /* @__PURE__ */ jsxs(
1398
+ DropdownMenuItem,
1399
+ {
1400
+ disabled: busy || !canAdmin,
1401
+ onSelect: () => p.onDelete(w),
1402
+ title: canAdmin ? void 0 : lb.deleteOwnerOnly,
1403
+ className: "text-destructive focus:text-destructive",
1404
+ "data-testid": `workflow-delete-${id}`,
1405
+ children: [
1406
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-2 size-4", "aria-hidden": true }),
1407
+ lb.delete
1408
+ ]
1409
+ }
1410
+ )
1411
+ ] })
1412
+ ] })
1413
+ ] })
1414
+ ] });
1415
+ }
1416
+ }),
1417
+ // Stable on purpose: only the header texts rebuild the columns (see `latest`).
1418
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1419
+ [
1420
+ l.colName,
1421
+ l.colType,
1422
+ l.colTrigger,
1423
+ l.colAction,
1424
+ l.colAgent,
1425
+ l.colStatus,
1426
+ l.colShared,
1427
+ l.shared,
1428
+ l.colLastRun,
1429
+ l.colNextRun
1430
+ ]
1431
+ );
1432
+ useEffect(() => {
1433
+ apiRef.current?.refreshCells({ force: true });
1434
+ }, [
1435
+ busyId,
1436
+ props.agentNames,
1437
+ props.skillNames,
1438
+ props.taskNames,
1439
+ props.lastRuns,
1440
+ props.renderPerson,
1441
+ props.labels,
1442
+ props.canEditShared,
1443
+ props.isWorkspaceOwner
1444
+ ]);
1445
+ const mine = selected.filter((w) => !isSkillRow(w));
1446
+ const adminSelected = mine.filter((w) => w.is_owner !== false || props.isWorkspaceOwner);
1447
+ const editableSelected = mine.filter(
1448
+ (w) => hasTrigger(w) && (w.is_owner !== false || props.canEditShared)
1449
+ );
1450
+ const clearSelection = () => setSelected([]);
1451
+ return /* @__PURE__ */ jsxs(
1452
+ "div",
1453
+ {
1454
+ className: "flex min-h-0 flex-1 flex-col",
1455
+ "data-testid": testIdOr(testId, { testId: "workflow-list" }),
1456
+ children: [
1457
+ /* @__PURE__ */ jsx(
1458
+ TabHeader,
1459
+ {
1460
+ testId: "automations-tab-header",
1461
+ tabs: [
1462
+ {
1463
+ id: "automations",
1464
+ label: "",
1465
+ count: shown.length,
1466
+ countIcon: /* @__PURE__ */ jsx(Workflow, { className: "size-3.5" }),
1467
+ countPlacement: "leading",
1468
+ presentation: "count",
1469
+ hasActiveFilters: !!q || [...filterStates.values()].some(Boolean)
1470
+ },
1471
+ ...props.tabs ?? []
1472
+ ],
1473
+ activeTabId: props.activeTabId ?? "automations",
1474
+ onTabChange: props.onTabChange ?? (() => {
1475
+ }),
1476
+ firstTabContent: /* @__PURE__ */ jsx(
1477
+ FilterInput,
1478
+ {
1479
+ value: query,
1480
+ onChange: setQuery,
1481
+ fields: ["text"],
1482
+ onFieldsChange: () => {
1483
+ },
1484
+ hideFieldPicker: true,
1485
+ ariaLabel: l.searchLabel,
1486
+ testIds: { input: "workflow-search" },
1487
+ filter: /* @__PURE__ */ jsx(
1488
+ TriStateFilterMenu,
1489
+ {
1490
+ testId: "automations-filter-button",
1491
+ open: filterOpen,
1492
+ onOpenChange: setFilterOpen,
1493
+ filterStates,
1494
+ onFiltersChange: setFilterStates,
1495
+ triggerClassName: "flex h-5 items-center gap-0.5 rounded px-1 text-muted-foreground hover:text-foreground pointer-coarse:h-11! pointer-coarse:min-w-11 pointer-coarse:justify-center",
1496
+ renderChevron: true,
1497
+ disableHoverOpen: true,
1498
+ options: [
1499
+ ...!props.automationsOnly ? [
1500
+ { id: "skills", label: l.filterSkills, count: counts.skills },
1501
+ {
1502
+ id: "workflows",
1503
+ label: l.filterWorkflows,
1504
+ count: counts.workflows
1505
+ }
1506
+ ] : [],
1507
+ { id: "active", label: l.filterActive, count: counts.active },
1508
+ { id: "paused", label: l.filterPaused, count: counts.paused }
1509
+ ]
1510
+ }
1511
+ )
1512
+ }
1513
+ ),
1514
+ rightContent: header
1515
+ }
1516
+ ),
1517
+ props.content ? props.content : workflows.length === 0 && !isLoading ? /* @__PURE__ */ jsx(
1518
+ EmptyState,
1519
+ {
1520
+ icon: Workflow,
1521
+ title: l.emptyTitle,
1522
+ description: l.emptyMessage,
1523
+ testId: "workflow-list-empty"
1524
+ }
1525
+ ) : /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
1526
+ GridView,
1527
+ {
1528
+ testId: "workflow-grid",
1529
+ gridId: props.gridId ?? "workflows-grid-v2",
1530
+ items: shown,
1531
+ columnDefs,
1532
+ getItemId: (w) => w.external_id,
1533
+ getRowTestId: (w) => `workflow-row-${w.external_id}`,
1534
+ isLoading,
1535
+ showEmpty: shown.length === 0,
1536
+ emptyState: { title: l.noMatches },
1537
+ rowHeight: ROW_HEIGHT,
1538
+ height: "100%",
1539
+ onGridReady: ({ api }) => {
1540
+ apiRef.current = api;
1541
+ },
1542
+ onRowClick: (row) => props.onOpenRow?.(row),
1543
+ selection: { mode: "multiple", selected, onSelectionChange: setSelected },
1544
+ gridOptions: GRID_OPTIONS
1545
+ }
1546
+ ) }),
1547
+ !props.content && /* @__PURE__ */ jsx(SelectionBar, { count: selected.length, onClear: clearSelection, children: (isCompact) => /* @__PURE__ */ jsxs(Fragment, { children: [
1548
+ props.onToggleActiveMany && /* @__PURE__ */ jsxs(Fragment, { children: [
1549
+ /* @__PURE__ */ jsx(
1550
+ SelectionBarAction,
1551
+ {
1552
+ icon: Play,
1553
+ label: l.makeActive,
1554
+ onClick: () => {
1555
+ props.onToggleActiveMany?.(editableSelected, true);
1556
+ clearSelection();
1557
+ },
1558
+ disabled: editableSelected.length === 0,
1559
+ isCompact,
1560
+ testId: "workflow-bulk-activate"
1561
+ }
1562
+ ),
1563
+ /* @__PURE__ */ jsx(
1564
+ SelectionBarAction,
1565
+ {
1566
+ icon: Workflow,
1567
+ label: l.makePaused,
1568
+ onClick: () => {
1569
+ props.onToggleActiveMany?.(editableSelected, false);
1570
+ clearSelection();
1571
+ },
1572
+ disabled: editableSelected.length === 0,
1573
+ isCompact,
1574
+ testId: "workflow-bulk-pause"
1575
+ }
1576
+ )
1577
+ ] }),
1578
+ props.onDeleteMany && /* @__PURE__ */ jsx(
1579
+ SelectionBarAction,
1580
+ {
1581
+ icon: Trash2,
1582
+ label: l.delete,
1583
+ onClick: () => {
1584
+ props.onDeleteMany?.(adminSelected);
1585
+ clearSelection();
1586
+ },
1587
+ disabled: adminSelected.length === 0,
1588
+ isCompact,
1589
+ className: "border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
1590
+ testId: "workflow-bulk-delete"
1591
+ }
1592
+ )
1593
+ ] }) })
1594
+ ]
1595
+ }
1596
+ );
1597
+ }
1598
+ var GRID_OPTIONS = { suppressClickEdit: true };
1599
+
1600
+ export { AgentSelect, DEFAULT_AGENT_SELECT_LABELS, DEFAULT_SCHEMA_FORM_LABELS, DEFAULT_TASK_TRIGGER_CHIP_LABELS, DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS, DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS, DEFAULT_WORKFLOW_LIST_LABELS, PersonPill, SchemaForm, TaskTriggerChip, WORKFLOW_COLUMN_ORDER, WorkflowConfigDialog, WorkflowDocumentsField, WorkflowLauncher, WorkflowsTable, buildWorkflowScopeSource, createWorkflowColumns, documentScopeLabels, hasTrigger, isSkillRow, matchWorkflowScope, workflowRunStatusLabel, workflowStatus, workflowTriggerType };
1601
+ //# sourceMappingURL=chunk-A6J2IBUG.js.map
1602
+ //# sourceMappingURL=chunk-A6J2IBUG.js.map