@workflow/web 4.1.1 → 4.1.5

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 (30) hide show
  1. package/build/client/assets/encryption-80GMP4r0.js +26 -0
  2. package/build/client/assets/entry.client-BWsSsWQm.js +11899 -0
  3. package/build/client/assets/highlighted-body-B3W2YXNL-CdV7thm2.js +18 -0
  4. package/build/client/assets/home-BMWyCqWy.js +3984 -0
  5. package/build/client/assets/index-DQa-BExo.js +9432 -0
  6. package/build/client/assets/{manifest-8cfb1d31.js → manifest-c0697365.js} +1 -1
  7. package/build/client/assets/mermaid-3ZIDBTTL-B_qZU5zW.js +48064 -0
  8. package/build/client/assets/root-CLs7COa2.js +690 -0
  9. package/build/client/assets/run-detail-D7xkVxzE.js +6699 -0
  10. package/build/client/assets/worker-CqHKTA7D.js +115 -0
  11. package/build/client/assets/workflow-graph-viewer-D5yEggTb.js +16175 -0
  12. package/build/server/assets/{app-BjALV8M8.js → app-fdUHF124.js} +1 -1
  13. package/build/server/assets/{highlighted-body-B3W2YXNL-CPKrO4kT.js → highlighted-body-B3W2YXNL-2WxWqSYU.js} +2 -2
  14. package/build/server/assets/{index-DbMFm9t3.js → index-C64kz8oy.js} +8 -7
  15. package/build/server/assets/{mermaid-3ZIDBTTL-DGuUhvM4.js → mermaid-3ZIDBTTL-FF5ZIJp-.js} +2 -2
  16. package/build/server/assets/{server-build-DfI2avTQ.js → server-build-Mddyhj54.js} +109 -47
  17. package/build/server/assets/{token-BBou_ahS.js → token-D_Q6dhhy.js} +2 -2
  18. package/build/server/assets/{token-util-CdxtEAt7.js → token-util-BAhz4ocz.js} +2 -2
  19. package/build/server/index.js +1 -1
  20. package/package.json +7 -7
  21. package/build/client/assets/encryption-8OvC6eoJ.js +0 -1
  22. package/build/client/assets/entry.client-BiVEcoV8.js +0 -29
  23. package/build/client/assets/highlighted-body-B3W2YXNL-YMQAPcBs.js +0 -1
  24. package/build/client/assets/home-CBUniDnp.js +0 -40
  25. package/build/client/assets/index-BmZS3y7B.js +0 -59
  26. package/build/client/assets/mermaid-3ZIDBTTL-B00nsi3k.js +0 -210
  27. package/build/client/assets/root-CHWaz-_g.js +0 -26
  28. package/build/client/assets/run-detail-DHdCNGRJ.js +0 -37
  29. package/build/client/assets/worker-D-HfgUMl.js +0 -1
  30. package/build/client/assets/workflow-graph-viewer-Cb_2KEX3.js +0 -161
@@ -0,0 +1,3984 @@
1
+ import { r as reactExports, C as ReactDOM, j as jsxRuntimeExports, z as Link, f as reactDomExports, B as useSearchParams, A as useNavigate, D as useLocation, w as withComponentProps } from "./index-DQa-BExo.js";
2
+ import { R as ResolveHookModal, S as Send, a as Skeleton, u as unwrapOrThrow, W as WorkflowWebAPIError, b as RelativeTime, A as Alert, C as CircleAlert, c as AlertTitle, d as AlertDescription, g as getErrorMessage, e as CopyableText, D as DropdownMenu, f as DropdownMenuTrigger, E as Ellipsis, h as DropdownMenuContent, i as DropdownMenuItem, j as ChevronRight, r as resumeHook, k as createCollection, l as hideOthers, m as ReactRemoveScroll, n as useDirection, o as ChevronDown, p as ChevronUp, q as Check, X, s as useControllableState$1, t as createContextScope$1, P as Primitive$1, v as composeEventHandlers$1, w as Presence, x as useSize, y as cancelRun, z as reenqueueRun, B as parseWorkflowName, F as StatusBadge, Z as Zap, G as CircleX, H as RunActionsDropdownItems, I as unwrapServerActionResult, J as WorkflowGraphViewer, T as Tabs, K as TabsList, L as TabsTrigger, M as TabsContent, N as ErrorBoundary } from "./workflow-graph-viewer-D5yEggTb.js";
3
+ import { g as useLayoutEffect2, P as Primitive, c as createLucideIcon, h as useToast, d as cn, D as DEFAULT_PAGE_SIZE, i as fetchRuns, j as fetchHooks, k as getPaginationDisplay, T as Tooltip, a as TooltipTrigger, B as Button, b as TooltipContent, l as fetchEvents, m as useCallbackRef, n as useComposedRefs, o as createPopperScope, p as createContextScope, A as Anchor, q as composeEventHandlers, s as useId, v as createSlot, w as DismissableLayer, C as Content$1, x as useControllableState, y as Root2$1, V as VISUALLY_HIDDEN_STYLES, z as Arrow, E as useComposedRefs$1, u as useServerConfig, t as toast, L as LoaderCircle, F as fetchRun, G as cva, H as Presence$1, I as createContext2, J as fetchWorkflowsManifest } from "./mermaid-3ZIDBTTL-B_qZU5zW.js";
4
+ var PORTAL_NAME$2 = "Portal";
5
+ var Portal$2 = reactExports.forwardRef((props, forwardedRef) => {
6
+ var _a;
7
+ const { container: containerProp, ...portalProps } = props;
8
+ const [mounted, setMounted] = reactExports.useState(false);
9
+ useLayoutEffect2(() => setMounted(true), []);
10
+ const container = containerProp || mounted && ((_a = globalThis == null ? void 0 : globalThis.document) == null ? void 0 : _a.body);
11
+ return container ? ReactDOM.createPortal(/* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
12
+ });
13
+ Portal$2.displayName = PORTAL_NAME$2;
14
+ /**
15
+ * @license lucide-react v0.575.0 - ISC
16
+ *
17
+ * This source code is licensed under the ISC license.
18
+ * See the LICENSE file in the root directory of this source tree.
19
+ */
20
+ const __iconNode$6 = [
21
+ ["path", { d: "m3 16 4 4 4-4", key: "1co6wj" }],
22
+ ["path", { d: "M7 20V4", key: "1yoxec" }],
23
+ ["path", { d: "M20 8h-5", key: "1vsyxs" }],
24
+ ["path", { d: "M15 10V6.5a2.5 2.5 0 0 1 5 0V10", key: "ag13bf" }],
25
+ ["path", { d: "M15 14h5l-5 6h5", key: "ur5jdg" }]
26
+ ];
27
+ const ArrowDownAZ = createLucideIcon("arrow-down-a-z", __iconNode$6);
28
+ /**
29
+ * @license lucide-react v0.575.0 - ISC
30
+ *
31
+ * This source code is licensed under the ISC license.
32
+ * See the LICENSE file in the root directory of this source tree.
33
+ */
34
+ const __iconNode$5 = [
35
+ ["path", { d: "m3 8 4-4 4 4", key: "11wl7u" }],
36
+ ["path", { d: "M7 4v16", key: "1glfcx" }],
37
+ ["path", { d: "M20 8h-5", key: "1vsyxs" }],
38
+ ["path", { d: "M15 10V6.5a2.5 2.5 0 0 1 5 0V10", key: "ag13bf" }],
39
+ ["path", { d: "M15 14h5l-5 6h5", key: "ur5jdg" }]
40
+ ];
41
+ const ArrowUpAZ = createLucideIcon("arrow-up-a-z", __iconNode$5);
42
+ /**
43
+ * @license lucide-react v0.575.0 - ISC
44
+ *
45
+ * This source code is licensed under the ISC license.
46
+ * See the LICENSE file in the root directory of this source tree.
47
+ */
48
+ const __iconNode$4 = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
49
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$4);
50
+ /**
51
+ * @license lucide-react v0.575.0 - ISC
52
+ *
53
+ * This source code is licensed under the ISC license.
54
+ * See the LICENSE file in the root directory of this source tree.
55
+ */
56
+ const __iconNode$3 = [
57
+ ["path", { d: "M15 6a9 9 0 0 0-9 9V3", key: "1cii5b" }],
58
+ ["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
59
+ ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }]
60
+ ];
61
+ const GitBranch = createLucideIcon("git-branch", __iconNode$3);
62
+ /**
63
+ * @license lucide-react v0.575.0 - ISC
64
+ *
65
+ * This source code is licensed under the ISC license.
66
+ * See the LICENSE file in the root directory of this source tree.
67
+ */
68
+ const __iconNode$2 = [["path", { d: "M5 12h14", key: "1ays0h" }]];
69
+ const Minus = createLucideIcon("minus", __iconNode$2);
70
+ /**
71
+ * @license lucide-react v0.575.0 - ISC
72
+ *
73
+ * This source code is licensed under the ISC license.
74
+ * See the LICENSE file in the root directory of this source tree.
75
+ */
76
+ const __iconNode$1 = [
77
+ ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
78
+ ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
79
+ ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
80
+ ["path", { d: "M8 16H3v5", key: "1cv678" }]
81
+ ];
82
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$1);
83
+ /**
84
+ * @license lucide-react v0.575.0 - ISC
85
+ *
86
+ * This source code is licensed under the ISC license.
87
+ * See the LICENSE file in the root directory of this source tree.
88
+ */
89
+ const __iconNode = [
90
+ ["rect", { width: "8", height: "8", x: "3", y: "3", rx: "2", key: "by2w9f" }],
91
+ ["path", { d: "M7 11v4a2 2 0 0 0 2 2h4", key: "xkn7yn" }],
92
+ ["rect", { width: "8", height: "8", x: "13", y: "13", rx: "2", key: "1cgmvn" }]
93
+ ];
94
+ const Workflow = createLucideIcon("workflow", __iconNode);
95
+ function useHookActions({ onResolve, callbacks }) {
96
+ const toast2 = useToast();
97
+ const [isResolving, setIsResolving] = reactExports.useState(false);
98
+ const [selectedHook, setSelectedHook] = reactExports.useState(null);
99
+ const openResolveModal = reactExports.useCallback((hook) => {
100
+ setSelectedHook(hook);
101
+ }, []);
102
+ const closeResolveModal = reactExports.useCallback(() => {
103
+ setSelectedHook(null);
104
+ }, []);
105
+ const handleResolve = reactExports.useCallback(async (payload) => {
106
+ var _a;
107
+ if (isResolving || !selectedHook)
108
+ return;
109
+ try {
110
+ setIsResolving(true);
111
+ await onResolve(selectedHook, payload);
112
+ toast2.success("Hook resolved", {
113
+ description: "The payload has been sent and the hook resolved."
114
+ });
115
+ setSelectedHook(null);
116
+ (_a = callbacks == null ? void 0 : callbacks.onSuccess) == null ? void 0 : _a.call(callbacks);
117
+ } catch (err) {
118
+ console.error("Failed to resolve hook:", err);
119
+ toast2.error("Failed to resolve hook", {
120
+ description: err instanceof Error ? err.message : "An unknown error occurred"
121
+ });
122
+ } finally {
123
+ setIsResolving(false);
124
+ }
125
+ }, [onResolve, selectedHook, isResolving, callbacks]);
126
+ return {
127
+ isResolving,
128
+ selectedHook,
129
+ openResolveModal,
130
+ closeResolveModal,
131
+ handleResolve
132
+ };
133
+ }
134
+ function ResolveHookDropdownItem({ hook, stopPropagation = false, onResolveClick, DropdownMenuItem: DropdownMenuItem2 }) {
135
+ const handleClick = (e) => {
136
+ if (stopPropagation)
137
+ e.stopPropagation();
138
+ onResolveClick(hook);
139
+ };
140
+ return jsxRuntimeExports.jsxs(DropdownMenuItem2, { onClick: handleClick, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4 mr-2" }), "Resolve Hook"] });
141
+ }
142
+ function HookResolveModalWrapper({ hookActions }) {
143
+ const { selectedHook, closeResolveModal, handleResolve, isResolving } = hookActions;
144
+ return jsxRuntimeExports.jsx(ResolveHookModal, { isOpen: selectedHook !== null, onClose: closeResolveModal, onSubmit: handleResolve, isSubmitting: isResolving });
145
+ }
146
+ const Card = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
147
+ "div",
148
+ {
149
+ ref,
150
+ className: cn(
151
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
152
+ className
153
+ ),
154
+ ...props
155
+ }
156
+ ));
157
+ Card.displayName = "Card";
158
+ const CardHeader = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
159
+ "div",
160
+ {
161
+ ref,
162
+ className: cn("flex flex-col space-y-1.5 p-6", className),
163
+ ...props
164
+ }
165
+ ));
166
+ CardHeader.displayName = "CardHeader";
167
+ const CardTitle = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
168
+ "div",
169
+ {
170
+ ref,
171
+ className: cn(
172
+ "text-2xl font-semibold leading-none tracking-tight",
173
+ className
174
+ ),
175
+ ...props
176
+ }
177
+ ));
178
+ CardTitle.displayName = "CardTitle";
179
+ const CardDescription = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
180
+ "div",
181
+ {
182
+ ref,
183
+ className: cn("text-sm text-muted-foreground", className),
184
+ ...props
185
+ }
186
+ ));
187
+ CardDescription.displayName = "CardDescription";
188
+ const CardContent = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
189
+ CardContent.displayName = "CardContent";
190
+ const CardFooter = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
191
+ "div",
192
+ {
193
+ ref,
194
+ className: cn("flex items-center p-6 pt-0", className),
195
+ ...props
196
+ }
197
+ ));
198
+ CardFooter.displayName = "CardFooter";
199
+ const DocsLink = reactExports.forwardRef(
200
+ ({ className, href, children, ...props }, ref) => {
201
+ const fullHref = href.startsWith("http") ? href : `https://useworkflow.dev/docs/${href.replace(/^\//, "")}`;
202
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
203
+ Link,
204
+ {
205
+ href: fullHref,
206
+ className: cn(
207
+ "font-medium underline underline-offset-4 transition-colors",
208
+ className
209
+ ),
210
+ style: {
211
+ color: "var(--ds-blue-600)"
212
+ },
213
+ target: "_blank",
214
+ rel: "noopener noreferrer",
215
+ ref,
216
+ ...props,
217
+ children
218
+ }
219
+ );
220
+ }
221
+ );
222
+ DocsLink.displayName = "DocsLink";
223
+ const Table = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
224
+ "table",
225
+ {
226
+ ref,
227
+ className: cn("w-full caption-bottom text-sm", className),
228
+ ...props
229
+ }
230
+ ) }));
231
+ Table.displayName = "Table";
232
+ const TableHeader = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
233
+ TableHeader.displayName = "TableHeader";
234
+ const TableBody = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
235
+ "tbody",
236
+ {
237
+ ref,
238
+ className: cn("[&_tr:last-child]:border-0", className),
239
+ ...props
240
+ }
241
+ ));
242
+ TableBody.displayName = "TableBody";
243
+ const TableFooter = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
244
+ "tfoot",
245
+ {
246
+ ref,
247
+ className: cn(
248
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
249
+ className
250
+ ),
251
+ ...props
252
+ }
253
+ ));
254
+ TableFooter.displayName = "TableFooter";
255
+ const TableRow = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
256
+ "tr",
257
+ {
258
+ ref,
259
+ className: cn(
260
+ "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
261
+ className
262
+ ),
263
+ ...props
264
+ }
265
+ ));
266
+ TableRow.displayName = "TableRow";
267
+ const TableHead = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
268
+ "th",
269
+ {
270
+ ref,
271
+ className: cn(
272
+ "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
273
+ className
274
+ ),
275
+ ...props
276
+ }
277
+ ));
278
+ TableHead.displayName = "TableHead";
279
+ const TableCell = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
280
+ "td",
281
+ {
282
+ ref,
283
+ className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className),
284
+ ...props
285
+ }
286
+ ));
287
+ TableCell.displayName = "TableCell";
288
+ const TableCaption = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
289
+ "caption",
290
+ {
291
+ ref,
292
+ className: cn("mt-4 text-sm text-muted-foreground", className),
293
+ ...props
294
+ }
295
+ ));
296
+ TableCaption.displayName = "TableCaption";
297
+ function TableSkeleton({
298
+ rows = DEFAULT_PAGE_SIZE,
299
+ variant = "runs"
300
+ }) {
301
+ const renderRow = (i) => {
302
+ switch (variant) {
303
+ case "runs":
304
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
305
+ "div",
306
+ {
307
+ className: "grid grid-cols-[1fr_1.5fr_0.8fr_1fr_1fr_40px] items-center gap-4 py-3 px-4",
308
+ children: [
309
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
310
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
311
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
312
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-14" }),
313
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-2 w-8" })
314
+ ] }),
315
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
316
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
317
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-6 w-6 rounded" })
318
+ ]
319
+ },
320
+ `skeleton-row-${i}`
321
+ );
322
+ case "hooks":
323
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
324
+ "div",
325
+ {
326
+ className: "grid grid-cols-[1.2fr_1.2fr_0.8fr_1fr_0.5fr_40px] items-center gap-4 py-3 px-4",
327
+ children: [
328
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
329
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
330
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
331
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
332
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-8" }),
333
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-6 w-6 rounded" })
334
+ ]
335
+ },
336
+ `skeleton-row-${i}`
337
+ );
338
+ case "workflows":
339
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
340
+ "div",
341
+ {
342
+ className: "grid grid-cols-[1fr_1.5fr_0.5fr] items-center gap-4 py-3 px-4",
343
+ children: [
344
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
345
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
346
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-5 w-16 rounded-full mx-auto" })
347
+ ]
348
+ },
349
+ `skeleton-row-${i}`
350
+ );
351
+ default:
352
+ return null;
353
+ }
354
+ };
355
+ const renderHeader = () => {
356
+ switch (variant) {
357
+ case "runs":
358
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[1fr_1.5fr_0.8fr_1fr_1fr_40px] items-center gap-4 py-3 px-4 border-b", children: [
359
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
360
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
361
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12" }),
362
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
363
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
364
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6" })
365
+ ] });
366
+ case "hooks":
367
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[1.2fr_1.2fr_0.8fr_1fr_0.5fr_40px] items-center gap-4 py-3 px-4 border-b", children: [
368
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-16" }),
369
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
370
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12" }),
371
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
372
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
373
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6" })
374
+ ] });
375
+ case "workflows":
376
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[1fr_1.5fr_0.5fr] items-center gap-4 py-3 px-4 border-b", children: [
377
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
378
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-10" }),
379
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12 mx-auto" })
380
+ ] });
381
+ default:
382
+ return null;
383
+ }
384
+ };
385
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden mt-4 bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-0", children: [
386
+ renderHeader(),
387
+ Array.from({ length: rows }, (_, i) => renderRow(i))
388
+ ] }) });
389
+ }
390
+ function pluralize(singular, plural, count2) {
391
+ return count2 === 1 ? singular : plural;
392
+ }
393
+ function usePaginatedList(fetchFn) {
394
+ var _a;
395
+ const [cursor, setCursor] = reactExports.useState(void 0);
396
+ const [hasMore, setHasMore] = reactExports.useState(false);
397
+ const [currentPage, setCurrentPage] = reactExports.useState(0);
398
+ const [pageHistory, setPageHistory] = reactExports.useState([
399
+ void 0
400
+ ]);
401
+ const [maxPagesVisited, setMaxPagesVisited] = reactExports.useState(1);
402
+ const [allPageResults, setAllPageResults] = reactExports.useState(/* @__PURE__ */ new Map([[0, { data: null, isLoading: false, error: null }]]));
403
+ const pageCache = reactExports.useRef(/* @__PURE__ */ new Map());
404
+ const fetchPage = reactExports.useCallback(
405
+ async (pageIndex, pageCursor, force = false) => {
406
+ const cacheKey = pageCursor ?? "initial";
407
+ setAllPageResults((prev) => {
408
+ var _a2;
409
+ const newMap = new Map(prev);
410
+ newMap.set(pageIndex, {
411
+ data: ((_a2 = prev.get(pageIndex)) == null ? void 0 : _a2.data) ?? null,
412
+ isLoading: true,
413
+ error: null
414
+ });
415
+ return newMap;
416
+ });
417
+ if (!force && pageCache.current.has(cacheKey)) {
418
+ const cached = pageCache.current.get(cacheKey);
419
+ if (cached) {
420
+ setAllPageResults((prev) => {
421
+ const newMap = new Map(prev);
422
+ newMap.set(pageIndex, {
423
+ data: cached.data,
424
+ isLoading: false,
425
+ error: null
426
+ });
427
+ return newMap;
428
+ });
429
+ setCursor(cached.cursor);
430
+ setHasMore(cached.hasMore);
431
+ return;
432
+ }
433
+ }
434
+ try {
435
+ const result = await fetchFn(pageCursor);
436
+ pageCache.current.set(cacheKey, {
437
+ data: result.data,
438
+ cursor: result.cursor,
439
+ hasMore: result.hasMore
440
+ });
441
+ setAllPageResults((prev) => {
442
+ const newMap = new Map(prev);
443
+ newMap.set(pageIndex, {
444
+ data: result.data,
445
+ isLoading: false,
446
+ error: null
447
+ });
448
+ return newMap;
449
+ });
450
+ setCursor(result.cursor);
451
+ setHasMore(result.hasMore);
452
+ } catch (err) {
453
+ const error = err instanceof Error ? err : new WorkflowWebAPIError(String(err), { layer: "client" });
454
+ setAllPageResults((prev) => {
455
+ var _a2;
456
+ const newMap = new Map(prev);
457
+ newMap.set(pageIndex, {
458
+ data: ((_a2 = prev.get(pageIndex)) == null ? void 0 : _a2.data) ?? null,
459
+ isLoading: false,
460
+ error
461
+ });
462
+ return newMap;
463
+ });
464
+ }
465
+ },
466
+ [fetchFn]
467
+ );
468
+ reactExports.useEffect(() => {
469
+ fetchPage(0, void 0, true);
470
+ }, [fetchPage]);
471
+ const nextPage = reactExports.useCallback(() => {
472
+ if (hasMore && cursor) {
473
+ const newPage = currentPage + 1;
474
+ setPageHistory((prev) => [...prev, cursor]);
475
+ setCurrentPage(newPage);
476
+ setMaxPagesVisited((prev) => Math.max(prev, newPage + 1));
477
+ if (!allPageResults.has(newPage)) {
478
+ setAllPageResults((prev) => {
479
+ const newMap = new Map(prev);
480
+ newMap.set(newPage, { data: null, isLoading: true, error: null });
481
+ return newMap;
482
+ });
483
+ }
484
+ fetchPage(newPage, cursor);
485
+ }
486
+ }, [hasMore, cursor, fetchPage, currentPage, allPageResults]);
487
+ const previousPage = reactExports.useCallback(() => {
488
+ if (currentPage > 0) {
489
+ const newPage = currentPage - 1;
490
+ const prevCursor = pageHistory[newPage];
491
+ setCurrentPage(newPage);
492
+ fetchPage(newPage, prevCursor);
493
+ }
494
+ }, [currentPage, pageHistory, fetchPage]);
495
+ const reload = reactExports.useCallback(() => {
496
+ pageCache.current.clear();
497
+ setAllPageResults(
498
+ /* @__PURE__ */ new Map([[0, { data: null, isLoading: true, error: null }]])
499
+ );
500
+ setCurrentPage(0);
501
+ setPageHistory([void 0]);
502
+ setMaxPagesVisited(1);
503
+ fetchPage(0, void 0, true);
504
+ }, [fetchPage]);
505
+ const refresh = reactExports.useCallback(() => {
506
+ const currentCursor = pageHistory[currentPage];
507
+ const cacheKey = currentCursor ?? "initial";
508
+ pageCache.current.delete(cacheKey);
509
+ fetchPage(currentPage, currentCursor, true);
510
+ }, [fetchPage, currentPage, pageHistory]);
511
+ const currentPageResult = allPageResults.get(currentPage) ?? {
512
+ data: null,
513
+ isLoading: true,
514
+ error: null
515
+ };
516
+ const globalError = ((_a = Array.from(allPageResults.values()).find((p) => p.error)) == null ? void 0 : _a.error) ?? null;
517
+ const globalLoading = Array.from(allPageResults.values()).some(
518
+ (p) => p.isLoading
519
+ );
520
+ const totalPages = hasMore ? currentPage + 2 : currentPage + 1;
521
+ const currentPageNumber = currentPage + 1;
522
+ const isOnLastVisitedPage = currentPageNumber === maxPagesVisited;
523
+ const showPlus = isOnLastVisitedPage && hasMore;
524
+ const pageInfo = getPaginationDisplay(
525
+ currentPageNumber,
526
+ maxPagesVisited,
527
+ showPlus
528
+ );
529
+ return {
530
+ data: currentPageResult,
531
+ allData: Array.from(allPageResults.values()),
532
+ error: globalError,
533
+ isLoading: globalLoading,
534
+ currentPage,
535
+ totalPages,
536
+ nextPage,
537
+ previousPage,
538
+ hasNextPage: hasMore,
539
+ hasPreviousPage: currentPage > 0,
540
+ reload,
541
+ refresh,
542
+ pageInfo
543
+ };
544
+ }
545
+ function useWorkflowRuns(env, params) {
546
+ const { workflowName, status, limit = 10, sortOrder = "desc" } = params;
547
+ const fetchFn = reactExports.useCallback(
548
+ (cursor) => unwrapOrThrow(
549
+ fetchRuns(env, { cursor, sortOrder, limit, workflowName, status })
550
+ ),
551
+ [env, workflowName, limit, sortOrder, status]
552
+ );
553
+ return usePaginatedList(fetchFn);
554
+ }
555
+ function useWorkflowHooks(env, params) {
556
+ const { runId, limit = 10, sortOrder = "desc" } = params;
557
+ const fetchFn = reactExports.useCallback(
558
+ (cursor) => unwrapOrThrow(fetchHooks(env, { runId, cursor, sortOrder, limit })),
559
+ [env, runId, limit, sortOrder]
560
+ );
561
+ return usePaginatedList(fetchFn);
562
+ }
563
+ function HooksTable({
564
+ runId,
565
+ onHookClick,
566
+ selectedHookId
567
+ }) {
568
+ const [lastRefreshTime, setLastRefreshTime] = reactExports.useState(
569
+ () => /* @__PURE__ */ new Date()
570
+ );
571
+ const env = reactExports.useMemo(() => ({}), []);
572
+ const {
573
+ data,
574
+ error,
575
+ nextPage,
576
+ previousPage,
577
+ hasNextPage,
578
+ hasPreviousPage,
579
+ refresh,
580
+ pageInfo
581
+ } = useWorkflowHooks(env, {
582
+ runId,
583
+ sortOrder: "desc"
584
+ });
585
+ const hookActions = useHookActions({
586
+ onResolve: async (hook, payload) => {
587
+ await resumeHook(env, hook.token, payload);
588
+ },
589
+ callbacks: {
590
+ onSuccess: refresh
591
+ }
592
+ });
593
+ const loading = data.isLoading;
594
+ const hooks = data.data ?? [];
595
+ const onRefresh = () => {
596
+ setLastRefreshTime(() => /* @__PURE__ */ new Date());
597
+ refresh();
598
+ };
599
+ const [invocationData, setInvocationData] = reactExports.useState(/* @__PURE__ */ new Map());
600
+ reactExports.useEffect(() => {
601
+ if (!hooks.length || !runId) return;
602
+ const fetchInvocations = async () => {
603
+ const initialData = /* @__PURE__ */ new Map();
604
+ for (const hook of hooks) {
605
+ initialData.set(hook.hookId, {
606
+ count: 0,
607
+ hasMore: false,
608
+ loading: true
609
+ });
610
+ }
611
+ setInvocationData(initialData);
612
+ try {
613
+ const serverResult = await fetchEvents(env, runId, {
614
+ sortOrder: "asc",
615
+ limit: 1e3
616
+ });
617
+ if (!serverResult.success) {
618
+ setInvocationData((prev) => {
619
+ const updated = new Map(prev);
620
+ for (const hook of hooks) {
621
+ updated.set(hook.hookId, { count: 0, hasMore: false, loading: false });
622
+ }
623
+ return updated;
624
+ });
625
+ return;
626
+ }
627
+ const allEvents = serverResult.data.data;
628
+ const hookIds = new Set(hooks.map((h) => h.hookId));
629
+ const counts = /* @__PURE__ */ new Map();
630
+ for (const event of allEvents) {
631
+ if (event.eventType === "hook_received" && event.correlationId && hookIds.has(event.correlationId)) {
632
+ counts.set(
633
+ event.correlationId,
634
+ (counts.get(event.correlationId) ?? 0) + 1
635
+ );
636
+ }
637
+ }
638
+ setInvocationData((prev) => {
639
+ const updated = new Map(prev);
640
+ for (const hook of hooks) {
641
+ updated.set(hook.hookId, {
642
+ count: counts.get(hook.hookId) ?? 0,
643
+ hasMore: serverResult.data.hasMore,
644
+ loading: false
645
+ });
646
+ }
647
+ return updated;
648
+ });
649
+ } catch {
650
+ setInvocationData((prev) => {
651
+ const updated = new Map(prev);
652
+ for (const hook of hooks) {
653
+ updated.set(hook.hookId, { count: 0, hasMore: false, loading: false });
654
+ }
655
+ return updated;
656
+ });
657
+ }
658
+ };
659
+ fetchInvocations();
660
+ }, [hooks, env, runId]);
661
+ const renderInvocationCount = (hook) => {
662
+ const data2 = invocationData.get(hook.hookId);
663
+ if (!data2 || data2.loading) {
664
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground text-xs", children: "..." });
665
+ }
666
+ if (data2.count instanceof Error) {
667
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "Error" });
668
+ }
669
+ if (data2.count === 0) {
670
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "0" });
671
+ }
672
+ const displayText = data2.hasMore ? `${data2.count}+` : `${data2.count}`;
673
+ if (data2.hasMore) {
674
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
675
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold cursor-help", children: displayText }) }),
676
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { className: "max-w-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs", children: "Showing first 100 invocations. There may be more." }) })
677
+ ] });
678
+ }
679
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold", children: displayText });
680
+ };
681
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
682
+ /* @__PURE__ */ jsxRuntimeExports.jsx(HookResolveModalWrapper, { hookActions }),
683
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
684
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end gap-2", children: [
685
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "Last refreshed" }),
686
+ lastRefreshTime && /* @__PURE__ */ jsxRuntimeExports.jsx(
687
+ RelativeTime,
688
+ {
689
+ date: lastRefreshTime,
690
+ className: "text-sm text-muted-foreground",
691
+ type: "distance"
692
+ }
693
+ )
694
+ ] }),
695
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
696
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
697
+ Button,
698
+ {
699
+ variant: "outline",
700
+ size: "sm",
701
+ onClick: onRefresh,
702
+ disabled: loading,
703
+ children: [
704
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: loading ? "animate-spin" : "" }),
705
+ "Refresh"
706
+ ]
707
+ }
708
+ ) }),
709
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Note that this resets pages" })
710
+ ] }) })
711
+ ] }),
712
+ error ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", children: [
713
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
714
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error loading hooks" }),
715
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
716
+ ] }) : !loading && (!hooks || hooks.length === 0) ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
717
+ "No active hooks found. ",
718
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
719
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DocsLink, { href: "https://useworkflow.dev/docs/api-reference/workflow/create-hook", children: "Learn how to create a hook" })
720
+ ] }) : loading && !(data == null ? void 0 : data.data) ? /* @__PURE__ */ jsxRuntimeExports.jsx(TableSkeleton, { variant: "hooks" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
721
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden mt-4 bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-0 max-h-[calc(100vh-280px)] overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Table, { children: [
722
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(TableRow, { children: [
723
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Hook ID" }),
724
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Run ID" }),
725
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Token" }),
726
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Created" }),
727
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Invocations" }),
728
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10" })
729
+ ] }) }),
730
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableBody, { children: hooks.map((hook) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
731
+ TableRow,
732
+ {
733
+ className: "cursor-pointer group relative",
734
+ onClick: () => onHookClick(hook.hookId, hook.runId),
735
+ "data-selected": hook.hookId === selectedHookId,
736
+ children: [
737
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: hook.hookId, overlay: true, children: hook.hookId }) }),
738
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: hook.runId, overlay: true, children: hook.runId }) }),
739
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: hook.token, overlay: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "••••••••••••" }) }) }),
740
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: hook.createdAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: hook.createdAt }) : "-" }),
741
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: renderInvocationCount(hook) }),
742
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { children: [
743
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
744
+ Button,
745
+ {
746
+ variant: "ghost",
747
+ size: "icon",
748
+ className: "h-8 w-8",
749
+ onClick: (e) => e.stopPropagation(),
750
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Ellipsis, { className: "h-4 w-4" })
751
+ }
752
+ ) }),
753
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
754
+ ResolveHookDropdownItem,
755
+ {
756
+ hook,
757
+ stopPropagation: true,
758
+ onResolveClick: hookActions.openResolveModal,
759
+ DropdownMenuItem
760
+ }
761
+ ) })
762
+ ] }) })
763
+ ]
764
+ },
765
+ hook.hookId
766
+ )) })
767
+ ] }) }) }),
768
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mt-4", children: [
769
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-muted-foreground", children: pageInfo }),
770
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 items-center", children: [
771
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
772
+ Button,
773
+ {
774
+ variant: "outline",
775
+ size: "sm",
776
+ onClick: previousPage,
777
+ disabled: !hasPreviousPage,
778
+ children: [
779
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, {}),
780
+ "Previous"
781
+ ]
782
+ }
783
+ ),
784
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
785
+ Button,
786
+ {
787
+ variant: "outline",
788
+ size: "sm",
789
+ onClick: nextPage,
790
+ disabled: !hasNextPage,
791
+ children: [
792
+ "Next",
793
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, {})
794
+ ]
795
+ }
796
+ )
797
+ ] })
798
+ ] })
799
+ ] })
800
+ ] });
801
+ }
802
+ function clamp(value, [min, max]) {
803
+ return Math.min(max, Math.max(min, value));
804
+ }
805
+ var count = 0;
806
+ function useFocusGuards() {
807
+ reactExports.useEffect(() => {
808
+ const edgeGuards = document.querySelectorAll("[data-radix-focus-guard]");
809
+ document.body.insertAdjacentElement("afterbegin", edgeGuards[0] ?? createFocusGuard());
810
+ document.body.insertAdjacentElement("beforeend", edgeGuards[1] ?? createFocusGuard());
811
+ count++;
812
+ return () => {
813
+ if (count === 1) {
814
+ document.querySelectorAll("[data-radix-focus-guard]").forEach((node) => node.remove());
815
+ }
816
+ count--;
817
+ };
818
+ }, []);
819
+ }
820
+ function createFocusGuard() {
821
+ const element = document.createElement("span");
822
+ element.setAttribute("data-radix-focus-guard", "");
823
+ element.tabIndex = 0;
824
+ element.style.outline = "none";
825
+ element.style.opacity = "0";
826
+ element.style.position = "fixed";
827
+ element.style.pointerEvents = "none";
828
+ return element;
829
+ }
830
+ var AUTOFOCUS_ON_MOUNT = "focusScope.autoFocusOnMount";
831
+ var AUTOFOCUS_ON_UNMOUNT = "focusScope.autoFocusOnUnmount";
832
+ var EVENT_OPTIONS = { bubbles: false, cancelable: true };
833
+ var FOCUS_SCOPE_NAME = "FocusScope";
834
+ var FocusScope = reactExports.forwardRef((props, forwardedRef) => {
835
+ const {
836
+ loop = false,
837
+ trapped = false,
838
+ onMountAutoFocus: onMountAutoFocusProp,
839
+ onUnmountAutoFocus: onUnmountAutoFocusProp,
840
+ ...scopeProps
841
+ } = props;
842
+ const [container, setContainer] = reactExports.useState(null);
843
+ const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);
844
+ const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);
845
+ const lastFocusedElementRef = reactExports.useRef(null);
846
+ const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));
847
+ const focusScope = reactExports.useRef({
848
+ paused: false,
849
+ pause() {
850
+ this.paused = true;
851
+ },
852
+ resume() {
853
+ this.paused = false;
854
+ }
855
+ }).current;
856
+ reactExports.useEffect(() => {
857
+ if (trapped) {
858
+ let handleFocusIn2 = function(event) {
859
+ if (focusScope.paused || !container) return;
860
+ const target = event.target;
861
+ if (container.contains(target)) {
862
+ lastFocusedElementRef.current = target;
863
+ } else {
864
+ focus(lastFocusedElementRef.current, { select: true });
865
+ }
866
+ }, handleFocusOut2 = function(event) {
867
+ if (focusScope.paused || !container) return;
868
+ const relatedTarget = event.relatedTarget;
869
+ if (relatedTarget === null) return;
870
+ if (!container.contains(relatedTarget)) {
871
+ focus(lastFocusedElementRef.current, { select: true });
872
+ }
873
+ }, handleMutations2 = function(mutations) {
874
+ const focusedElement = document.activeElement;
875
+ if (focusedElement !== document.body) return;
876
+ for (const mutation of mutations) {
877
+ if (mutation.removedNodes.length > 0) focus(container);
878
+ }
879
+ };
880
+ document.addEventListener("focusin", handleFocusIn2);
881
+ document.addEventListener("focusout", handleFocusOut2);
882
+ const mutationObserver = new MutationObserver(handleMutations2);
883
+ if (container) mutationObserver.observe(container, { childList: true, subtree: true });
884
+ return () => {
885
+ document.removeEventListener("focusin", handleFocusIn2);
886
+ document.removeEventListener("focusout", handleFocusOut2);
887
+ mutationObserver.disconnect();
888
+ };
889
+ }
890
+ }, [trapped, container, focusScope.paused]);
891
+ reactExports.useEffect(() => {
892
+ if (container) {
893
+ focusScopesStack.add(focusScope);
894
+ const previouslyFocusedElement = document.activeElement;
895
+ const hasFocusedCandidate = container.contains(previouslyFocusedElement);
896
+ if (!hasFocusedCandidate) {
897
+ const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);
898
+ container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
899
+ container.dispatchEvent(mountEvent);
900
+ if (!mountEvent.defaultPrevented) {
901
+ focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });
902
+ if (document.activeElement === previouslyFocusedElement) {
903
+ focus(container);
904
+ }
905
+ }
906
+ }
907
+ return () => {
908
+ container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
909
+ setTimeout(() => {
910
+ const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
911
+ container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
912
+ container.dispatchEvent(unmountEvent);
913
+ if (!unmountEvent.defaultPrevented) {
914
+ focus(previouslyFocusedElement ?? document.body, { select: true });
915
+ }
916
+ container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
917
+ focusScopesStack.remove(focusScope);
918
+ }, 0);
919
+ };
920
+ }
921
+ }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);
922
+ const handleKeyDown = reactExports.useCallback(
923
+ (event) => {
924
+ if (!loop && !trapped) return;
925
+ if (focusScope.paused) return;
926
+ const isTabKey = event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
927
+ const focusedElement = document.activeElement;
928
+ if (isTabKey && focusedElement) {
929
+ const container2 = event.currentTarget;
930
+ const [first, last] = getTabbableEdges(container2);
931
+ const hasTabbableElementsInside = first && last;
932
+ if (!hasTabbableElementsInside) {
933
+ if (focusedElement === container2) event.preventDefault();
934
+ } else {
935
+ if (!event.shiftKey && focusedElement === last) {
936
+ event.preventDefault();
937
+ if (loop) focus(first, { select: true });
938
+ } else if (event.shiftKey && focusedElement === first) {
939
+ event.preventDefault();
940
+ if (loop) focus(last, { select: true });
941
+ }
942
+ }
943
+ }
944
+ },
945
+ [loop, trapped, focusScope.paused]
946
+ );
947
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.div, { tabIndex: -1, ...scopeProps, ref: composedRefs, onKeyDown: handleKeyDown });
948
+ });
949
+ FocusScope.displayName = FOCUS_SCOPE_NAME;
950
+ function focusFirst(candidates, { select = false } = {}) {
951
+ const previouslyFocusedElement = document.activeElement;
952
+ for (const candidate of candidates) {
953
+ focus(candidate, { select });
954
+ if (document.activeElement !== previouslyFocusedElement) return;
955
+ }
956
+ }
957
+ function getTabbableEdges(container) {
958
+ const candidates = getTabbableCandidates(container);
959
+ const first = findVisible(candidates, container);
960
+ const last = findVisible(candidates.reverse(), container);
961
+ return [first, last];
962
+ }
963
+ function getTabbableCandidates(container) {
964
+ const nodes = [];
965
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
966
+ acceptNode: (node) => {
967
+ const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
968
+ if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
969
+ return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
970
+ }
971
+ });
972
+ while (walker.nextNode()) nodes.push(walker.currentNode);
973
+ return nodes;
974
+ }
975
+ function findVisible(elements, container) {
976
+ for (const element of elements) {
977
+ if (!isHidden(element, { upTo: container })) return element;
978
+ }
979
+ }
980
+ function isHidden(node, { upTo }) {
981
+ if (getComputedStyle(node).visibility === "hidden") return true;
982
+ while (node) {
983
+ if (upTo !== void 0 && node === upTo) return false;
984
+ if (getComputedStyle(node).display === "none") return true;
985
+ node = node.parentElement;
986
+ }
987
+ return false;
988
+ }
989
+ function isSelectableInput(element) {
990
+ return element instanceof HTMLInputElement && "select" in element;
991
+ }
992
+ function focus(element, { select = false } = {}) {
993
+ if (element && element.focus) {
994
+ const previouslyFocusedElement = document.activeElement;
995
+ element.focus({ preventScroll: true });
996
+ if (element !== previouslyFocusedElement && isSelectableInput(element) && select)
997
+ element.select();
998
+ }
999
+ }
1000
+ var focusScopesStack = createFocusScopesStack();
1001
+ function createFocusScopesStack() {
1002
+ let stack = [];
1003
+ return {
1004
+ add(focusScope) {
1005
+ const activeFocusScope = stack[0];
1006
+ if (focusScope !== activeFocusScope) {
1007
+ activeFocusScope == null ? void 0 : activeFocusScope.pause();
1008
+ }
1009
+ stack = arrayRemove(stack, focusScope);
1010
+ stack.unshift(focusScope);
1011
+ },
1012
+ remove(focusScope) {
1013
+ var _a;
1014
+ stack = arrayRemove(stack, focusScope);
1015
+ (_a = stack[0]) == null ? void 0 : _a.resume();
1016
+ }
1017
+ };
1018
+ }
1019
+ function arrayRemove(array, item) {
1020
+ const updatedArray = [...array];
1021
+ const index = updatedArray.indexOf(item);
1022
+ if (index !== -1) {
1023
+ updatedArray.splice(index, 1);
1024
+ }
1025
+ return updatedArray;
1026
+ }
1027
+ function removeLinks(items) {
1028
+ return items.filter((item) => item.tagName !== "A");
1029
+ }
1030
+ function usePrevious$1(value) {
1031
+ const ref = reactExports.useRef({ value, previous: value });
1032
+ return reactExports.useMemo(() => {
1033
+ if (ref.current.value !== value) {
1034
+ ref.current.previous = ref.current.value;
1035
+ ref.current.value = value;
1036
+ }
1037
+ return ref.current.previous;
1038
+ }, [value]);
1039
+ }
1040
+ var OPEN_KEYS = [" ", "Enter", "ArrowUp", "ArrowDown"];
1041
+ var SELECTION_KEYS = [" ", "Enter"];
1042
+ var SELECT_NAME = "Select";
1043
+ var [Collection, useCollection, createCollectionScope] = createCollection(SELECT_NAME);
1044
+ var [createSelectContext] = createContextScope(SELECT_NAME, [
1045
+ createCollectionScope,
1046
+ createPopperScope
1047
+ ]);
1048
+ var usePopperScope = createPopperScope();
1049
+ var [SelectProvider, useSelectContext] = createSelectContext(SELECT_NAME);
1050
+ var [SelectNativeOptionsProvider, useSelectNativeOptionsContext] = createSelectContext(SELECT_NAME);
1051
+ var Select$1 = (props) => {
1052
+ const {
1053
+ __scopeSelect,
1054
+ children,
1055
+ open: openProp,
1056
+ defaultOpen,
1057
+ onOpenChange,
1058
+ value: valueProp,
1059
+ defaultValue,
1060
+ onValueChange,
1061
+ dir,
1062
+ name,
1063
+ autoComplete,
1064
+ disabled,
1065
+ required,
1066
+ form
1067
+ } = props;
1068
+ const popperScope = usePopperScope(__scopeSelect);
1069
+ const [trigger, setTrigger] = reactExports.useState(null);
1070
+ const [valueNode, setValueNode] = reactExports.useState(null);
1071
+ const [valueNodeHasChildren, setValueNodeHasChildren] = reactExports.useState(false);
1072
+ const direction = useDirection(dir);
1073
+ const [open, setOpen] = useControllableState({
1074
+ prop: openProp,
1075
+ defaultProp: defaultOpen ?? false,
1076
+ onChange: onOpenChange,
1077
+ caller: SELECT_NAME
1078
+ });
1079
+ const [value, setValue] = useControllableState({
1080
+ prop: valueProp,
1081
+ defaultProp: defaultValue,
1082
+ onChange: onValueChange,
1083
+ caller: SELECT_NAME
1084
+ });
1085
+ const triggerPointerDownPosRef = reactExports.useRef(null);
1086
+ const isFormControl = trigger ? form || !!trigger.closest("form") : true;
1087
+ const [nativeOptionsSet, setNativeOptionsSet] = reactExports.useState(/* @__PURE__ */ new Set());
1088
+ const nativeSelectKey = Array.from(nativeOptionsSet).map((option) => option.props.value).join(";");
1089
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Root2$1, { ...popperScope, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1090
+ SelectProvider,
1091
+ {
1092
+ required,
1093
+ scope: __scopeSelect,
1094
+ trigger,
1095
+ onTriggerChange: setTrigger,
1096
+ valueNode,
1097
+ onValueNodeChange: setValueNode,
1098
+ valueNodeHasChildren,
1099
+ onValueNodeHasChildrenChange: setValueNodeHasChildren,
1100
+ contentId: useId(),
1101
+ value,
1102
+ onValueChange: setValue,
1103
+ open,
1104
+ onOpenChange: setOpen,
1105
+ dir: direction,
1106
+ triggerPointerDownPosRef,
1107
+ disabled,
1108
+ children: [
1109
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Collection.Provider, { scope: __scopeSelect, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1110
+ SelectNativeOptionsProvider,
1111
+ {
1112
+ scope: props.__scopeSelect,
1113
+ onNativeOptionAdd: reactExports.useCallback((option) => {
1114
+ setNativeOptionsSet((prev) => new Set(prev).add(option));
1115
+ }, []),
1116
+ onNativeOptionRemove: reactExports.useCallback((option) => {
1117
+ setNativeOptionsSet((prev) => {
1118
+ const optionsSet = new Set(prev);
1119
+ optionsSet.delete(option);
1120
+ return optionsSet;
1121
+ });
1122
+ }, []),
1123
+ children
1124
+ }
1125
+ ) }),
1126
+ isFormControl ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1127
+ SelectBubbleInput,
1128
+ {
1129
+ "aria-hidden": true,
1130
+ required,
1131
+ tabIndex: -1,
1132
+ name,
1133
+ autoComplete,
1134
+ value,
1135
+ onChange: (event) => setValue(event.target.value),
1136
+ disabled,
1137
+ form,
1138
+ children: [
1139
+ value === void 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "" }) : null,
1140
+ Array.from(nativeOptionsSet)
1141
+ ]
1142
+ },
1143
+ nativeSelectKey
1144
+ ) : null
1145
+ ]
1146
+ }
1147
+ ) });
1148
+ };
1149
+ Select$1.displayName = SELECT_NAME;
1150
+ var TRIGGER_NAME$1 = "SelectTrigger";
1151
+ var SelectTrigger$1 = reactExports.forwardRef(
1152
+ (props, forwardedRef) => {
1153
+ const { __scopeSelect, disabled = false, ...triggerProps } = props;
1154
+ const popperScope = usePopperScope(__scopeSelect);
1155
+ const context = useSelectContext(TRIGGER_NAME$1, __scopeSelect);
1156
+ const isDisabled = context.disabled || disabled;
1157
+ const composedRefs = useComposedRefs(forwardedRef, context.onTriggerChange);
1158
+ const getItems = useCollection(__scopeSelect);
1159
+ const pointerTypeRef = reactExports.useRef("touch");
1160
+ const [searchRef, handleTypeaheadSearch, resetTypeahead] = useTypeaheadSearch((search) => {
1161
+ const enabledItems = getItems().filter((item) => !item.disabled);
1162
+ const currentItem = enabledItems.find((item) => item.value === context.value);
1163
+ const nextItem = findNextItem(enabledItems, search, currentItem);
1164
+ if (nextItem !== void 0) {
1165
+ context.onValueChange(nextItem.value);
1166
+ }
1167
+ });
1168
+ const handleOpen = (pointerEvent) => {
1169
+ if (!isDisabled) {
1170
+ context.onOpenChange(true);
1171
+ resetTypeahead();
1172
+ }
1173
+ if (pointerEvent) {
1174
+ context.triggerPointerDownPosRef.current = {
1175
+ x: Math.round(pointerEvent.pageX),
1176
+ y: Math.round(pointerEvent.pageY)
1177
+ };
1178
+ }
1179
+ };
1180
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Anchor, { asChild: true, ...popperScope, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1181
+ Primitive.button,
1182
+ {
1183
+ type: "button",
1184
+ role: "combobox",
1185
+ "aria-controls": context.contentId,
1186
+ "aria-expanded": context.open,
1187
+ "aria-required": context.required,
1188
+ "aria-autocomplete": "none",
1189
+ dir: context.dir,
1190
+ "data-state": context.open ? "open" : "closed",
1191
+ disabled: isDisabled,
1192
+ "data-disabled": isDisabled ? "" : void 0,
1193
+ "data-placeholder": shouldShowPlaceholder(context.value) ? "" : void 0,
1194
+ ...triggerProps,
1195
+ ref: composedRefs,
1196
+ onClick: composeEventHandlers(triggerProps.onClick, (event) => {
1197
+ event.currentTarget.focus();
1198
+ if (pointerTypeRef.current !== "mouse") {
1199
+ handleOpen(event);
1200
+ }
1201
+ }),
1202
+ onPointerDown: composeEventHandlers(triggerProps.onPointerDown, (event) => {
1203
+ pointerTypeRef.current = event.pointerType;
1204
+ const target = event.target;
1205
+ if (target.hasPointerCapture(event.pointerId)) {
1206
+ target.releasePointerCapture(event.pointerId);
1207
+ }
1208
+ if (event.button === 0 && event.ctrlKey === false && event.pointerType === "mouse") {
1209
+ handleOpen(event);
1210
+ event.preventDefault();
1211
+ }
1212
+ }),
1213
+ onKeyDown: composeEventHandlers(triggerProps.onKeyDown, (event) => {
1214
+ const isTypingAhead = searchRef.current !== "";
1215
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
1216
+ if (!isModifierKey && event.key.length === 1) handleTypeaheadSearch(event.key);
1217
+ if (isTypingAhead && event.key === " ") return;
1218
+ if (OPEN_KEYS.includes(event.key)) {
1219
+ handleOpen();
1220
+ event.preventDefault();
1221
+ }
1222
+ })
1223
+ }
1224
+ ) });
1225
+ }
1226
+ );
1227
+ SelectTrigger$1.displayName = TRIGGER_NAME$1;
1228
+ var VALUE_NAME = "SelectValue";
1229
+ var SelectValue$1 = reactExports.forwardRef(
1230
+ (props, forwardedRef) => {
1231
+ const { __scopeSelect, className, style, children, placeholder = "", ...valueProps } = props;
1232
+ const context = useSelectContext(VALUE_NAME, __scopeSelect);
1233
+ const { onValueNodeHasChildrenChange } = context;
1234
+ const hasChildren = children !== void 0;
1235
+ const composedRefs = useComposedRefs(forwardedRef, context.onValueNodeChange);
1236
+ useLayoutEffect2(() => {
1237
+ onValueNodeHasChildrenChange(hasChildren);
1238
+ }, [onValueNodeHasChildrenChange, hasChildren]);
1239
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1240
+ Primitive.span,
1241
+ {
1242
+ ...valueProps,
1243
+ ref: composedRefs,
1244
+ style: { pointerEvents: "none" },
1245
+ children: shouldShowPlaceholder(context.value) ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: placeholder }) : children
1246
+ }
1247
+ );
1248
+ }
1249
+ );
1250
+ SelectValue$1.displayName = VALUE_NAME;
1251
+ var ICON_NAME = "SelectIcon";
1252
+ var SelectIcon = reactExports.forwardRef(
1253
+ (props, forwardedRef) => {
1254
+ const { __scopeSelect, children, ...iconProps } = props;
1255
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.span, { "aria-hidden": true, ...iconProps, ref: forwardedRef, children: children || "▼" });
1256
+ }
1257
+ );
1258
+ SelectIcon.displayName = ICON_NAME;
1259
+ var PORTAL_NAME$1 = "SelectPortal";
1260
+ var SelectPortal = (props) => {
1261
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { asChild: true, ...props });
1262
+ };
1263
+ SelectPortal.displayName = PORTAL_NAME$1;
1264
+ var CONTENT_NAME$1 = "SelectContent";
1265
+ var SelectContent$1 = reactExports.forwardRef(
1266
+ (props, forwardedRef) => {
1267
+ const context = useSelectContext(CONTENT_NAME$1, props.__scopeSelect);
1268
+ const [fragment, setFragment] = reactExports.useState();
1269
+ useLayoutEffect2(() => {
1270
+ setFragment(new DocumentFragment());
1271
+ }, []);
1272
+ if (!context.open) {
1273
+ const frag = fragment;
1274
+ return frag ? reactDomExports.createPortal(
1275
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContentProvider, { scope: props.__scopeSelect, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Collection.Slot, { scope: props.__scopeSelect, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: props.children }) }) }),
1276
+ frag
1277
+ ) : null;
1278
+ }
1279
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContentImpl, { ...props, ref: forwardedRef });
1280
+ }
1281
+ );
1282
+ SelectContent$1.displayName = CONTENT_NAME$1;
1283
+ var CONTENT_MARGIN = 10;
1284
+ var [SelectContentProvider, useSelectContentContext] = createSelectContext(CONTENT_NAME$1);
1285
+ var CONTENT_IMPL_NAME = "SelectContentImpl";
1286
+ var Slot$1 = createSlot("SelectContent.RemoveScroll");
1287
+ var SelectContentImpl = reactExports.forwardRef(
1288
+ (props, forwardedRef) => {
1289
+ const {
1290
+ __scopeSelect,
1291
+ position = "item-aligned",
1292
+ onCloseAutoFocus,
1293
+ onEscapeKeyDown,
1294
+ onPointerDownOutside,
1295
+ //
1296
+ // PopperContent props
1297
+ side,
1298
+ sideOffset,
1299
+ align,
1300
+ alignOffset,
1301
+ arrowPadding,
1302
+ collisionBoundary,
1303
+ collisionPadding,
1304
+ sticky,
1305
+ hideWhenDetached,
1306
+ avoidCollisions,
1307
+ //
1308
+ ...contentProps
1309
+ } = props;
1310
+ const context = useSelectContext(CONTENT_NAME$1, __scopeSelect);
1311
+ const [content, setContent] = reactExports.useState(null);
1312
+ const [viewport, setViewport] = reactExports.useState(null);
1313
+ const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node));
1314
+ const [selectedItem, setSelectedItem] = reactExports.useState(null);
1315
+ const [selectedItemText, setSelectedItemText] = reactExports.useState(
1316
+ null
1317
+ );
1318
+ const getItems = useCollection(__scopeSelect);
1319
+ const [isPositioned, setIsPositioned] = reactExports.useState(false);
1320
+ const firstValidItemFoundRef = reactExports.useRef(false);
1321
+ reactExports.useEffect(() => {
1322
+ if (content) return hideOthers(content);
1323
+ }, [content]);
1324
+ useFocusGuards();
1325
+ const focusFirst2 = reactExports.useCallback(
1326
+ (candidates) => {
1327
+ const [firstItem, ...restItems] = getItems().map((item) => item.ref.current);
1328
+ const [lastItem] = restItems.slice(-1);
1329
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
1330
+ for (const candidate of candidates) {
1331
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
1332
+ candidate == null ? void 0 : candidate.scrollIntoView({ block: "nearest" });
1333
+ if (candidate === firstItem && viewport) viewport.scrollTop = 0;
1334
+ if (candidate === lastItem && viewport) viewport.scrollTop = viewport.scrollHeight;
1335
+ candidate == null ? void 0 : candidate.focus();
1336
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
1337
+ }
1338
+ },
1339
+ [getItems, viewport]
1340
+ );
1341
+ const focusSelectedItem = reactExports.useCallback(
1342
+ () => focusFirst2([selectedItem, content]),
1343
+ [focusFirst2, selectedItem, content]
1344
+ );
1345
+ reactExports.useEffect(() => {
1346
+ if (isPositioned) {
1347
+ focusSelectedItem();
1348
+ }
1349
+ }, [isPositioned, focusSelectedItem]);
1350
+ const { onOpenChange, triggerPointerDownPosRef } = context;
1351
+ reactExports.useEffect(() => {
1352
+ if (content) {
1353
+ let pointerMoveDelta = { x: 0, y: 0 };
1354
+ const handlePointerMove = (event) => {
1355
+ var _a, _b;
1356
+ pointerMoveDelta = {
1357
+ x: Math.abs(Math.round(event.pageX) - (((_a = triggerPointerDownPosRef.current) == null ? void 0 : _a.x) ?? 0)),
1358
+ y: Math.abs(Math.round(event.pageY) - (((_b = triggerPointerDownPosRef.current) == null ? void 0 : _b.y) ?? 0))
1359
+ };
1360
+ };
1361
+ const handlePointerUp = (event) => {
1362
+ if (pointerMoveDelta.x <= 10 && pointerMoveDelta.y <= 10) {
1363
+ event.preventDefault();
1364
+ } else {
1365
+ if (!content.contains(event.target)) {
1366
+ onOpenChange(false);
1367
+ }
1368
+ }
1369
+ document.removeEventListener("pointermove", handlePointerMove);
1370
+ triggerPointerDownPosRef.current = null;
1371
+ };
1372
+ if (triggerPointerDownPosRef.current !== null) {
1373
+ document.addEventListener("pointermove", handlePointerMove);
1374
+ document.addEventListener("pointerup", handlePointerUp, { capture: true, once: true });
1375
+ }
1376
+ return () => {
1377
+ document.removeEventListener("pointermove", handlePointerMove);
1378
+ document.removeEventListener("pointerup", handlePointerUp, { capture: true });
1379
+ };
1380
+ }
1381
+ }, [content, onOpenChange, triggerPointerDownPosRef]);
1382
+ reactExports.useEffect(() => {
1383
+ const close = () => onOpenChange(false);
1384
+ window.addEventListener("blur", close);
1385
+ window.addEventListener("resize", close);
1386
+ return () => {
1387
+ window.removeEventListener("blur", close);
1388
+ window.removeEventListener("resize", close);
1389
+ };
1390
+ }, [onOpenChange]);
1391
+ const [searchRef, handleTypeaheadSearch] = useTypeaheadSearch((search) => {
1392
+ const enabledItems = getItems().filter((item) => !item.disabled);
1393
+ const currentItem = enabledItems.find((item) => item.ref.current === document.activeElement);
1394
+ const nextItem = findNextItem(enabledItems, search, currentItem);
1395
+ if (nextItem) {
1396
+ setTimeout(() => nextItem.ref.current.focus());
1397
+ }
1398
+ });
1399
+ const itemRefCallback = reactExports.useCallback(
1400
+ (node, value, disabled) => {
1401
+ const isFirstValidItem = !firstValidItemFoundRef.current && !disabled;
1402
+ const isSelectedItem = context.value !== void 0 && context.value === value;
1403
+ if (isSelectedItem || isFirstValidItem) {
1404
+ setSelectedItem(node);
1405
+ if (isFirstValidItem) firstValidItemFoundRef.current = true;
1406
+ }
1407
+ },
1408
+ [context.value]
1409
+ );
1410
+ const handleItemLeave = reactExports.useCallback(() => content == null ? void 0 : content.focus(), [content]);
1411
+ const itemTextRefCallback = reactExports.useCallback(
1412
+ (node, value, disabled) => {
1413
+ const isFirstValidItem = !firstValidItemFoundRef.current && !disabled;
1414
+ const isSelectedItem = context.value !== void 0 && context.value === value;
1415
+ if (isSelectedItem || isFirstValidItem) {
1416
+ setSelectedItemText(node);
1417
+ }
1418
+ },
1419
+ [context.value]
1420
+ );
1421
+ const SelectPosition = position === "popper" ? SelectPopperPosition : SelectItemAlignedPosition;
1422
+ const popperContentProps = SelectPosition === SelectPopperPosition ? {
1423
+ side,
1424
+ sideOffset,
1425
+ align,
1426
+ alignOffset,
1427
+ arrowPadding,
1428
+ collisionBoundary,
1429
+ collisionPadding,
1430
+ sticky,
1431
+ hideWhenDetached,
1432
+ avoidCollisions
1433
+ } : {};
1434
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1435
+ SelectContentProvider,
1436
+ {
1437
+ scope: __scopeSelect,
1438
+ content,
1439
+ viewport,
1440
+ onViewportChange: setViewport,
1441
+ itemRefCallback,
1442
+ selectedItem,
1443
+ onItemLeave: handleItemLeave,
1444
+ itemTextRefCallback,
1445
+ focusSelectedItem,
1446
+ selectedItemText,
1447
+ position,
1448
+ isPositioned,
1449
+ searchRef,
1450
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ReactRemoveScroll, { as: Slot$1, allowPinchZoom: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1451
+ FocusScope,
1452
+ {
1453
+ asChild: true,
1454
+ trapped: context.open,
1455
+ onMountAutoFocus: (event) => {
1456
+ event.preventDefault();
1457
+ },
1458
+ onUnmountAutoFocus: composeEventHandlers(onCloseAutoFocus, (event) => {
1459
+ var _a;
1460
+ (_a = context.trigger) == null ? void 0 : _a.focus({ preventScroll: true });
1461
+ event.preventDefault();
1462
+ }),
1463
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1464
+ DismissableLayer,
1465
+ {
1466
+ asChild: true,
1467
+ disableOutsidePointerEvents: true,
1468
+ onEscapeKeyDown,
1469
+ onPointerDownOutside,
1470
+ onFocusOutside: (event) => event.preventDefault(),
1471
+ onDismiss: () => context.onOpenChange(false),
1472
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1473
+ SelectPosition,
1474
+ {
1475
+ role: "listbox",
1476
+ id: context.contentId,
1477
+ "data-state": context.open ? "open" : "closed",
1478
+ dir: context.dir,
1479
+ onContextMenu: (event) => event.preventDefault(),
1480
+ ...contentProps,
1481
+ ...popperContentProps,
1482
+ onPlaced: () => setIsPositioned(true),
1483
+ ref: composedRefs,
1484
+ style: {
1485
+ // flex layout so we can place the scroll buttons properly
1486
+ display: "flex",
1487
+ flexDirection: "column",
1488
+ // reset the outline by default as the content MAY get focused
1489
+ outline: "none",
1490
+ ...contentProps.style
1491
+ },
1492
+ onKeyDown: composeEventHandlers(contentProps.onKeyDown, (event) => {
1493
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
1494
+ if (event.key === "Tab") event.preventDefault();
1495
+ if (!isModifierKey && event.key.length === 1) handleTypeaheadSearch(event.key);
1496
+ if (["ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
1497
+ const items = getItems().filter((item) => !item.disabled);
1498
+ let candidateNodes = items.map((item) => item.ref.current);
1499
+ if (["ArrowUp", "End"].includes(event.key)) {
1500
+ candidateNodes = candidateNodes.slice().reverse();
1501
+ }
1502
+ if (["ArrowUp", "ArrowDown"].includes(event.key)) {
1503
+ const currentElement = event.target;
1504
+ const currentIndex = candidateNodes.indexOf(currentElement);
1505
+ candidateNodes = candidateNodes.slice(currentIndex + 1);
1506
+ }
1507
+ setTimeout(() => focusFirst2(candidateNodes));
1508
+ event.preventDefault();
1509
+ }
1510
+ })
1511
+ }
1512
+ )
1513
+ }
1514
+ )
1515
+ }
1516
+ ) })
1517
+ }
1518
+ );
1519
+ }
1520
+ );
1521
+ SelectContentImpl.displayName = CONTENT_IMPL_NAME;
1522
+ var ITEM_ALIGNED_POSITION_NAME = "SelectItemAlignedPosition";
1523
+ var SelectItemAlignedPosition = reactExports.forwardRef((props, forwardedRef) => {
1524
+ const { __scopeSelect, onPlaced, ...popperProps } = props;
1525
+ const context = useSelectContext(CONTENT_NAME$1, __scopeSelect);
1526
+ const contentContext = useSelectContentContext(CONTENT_NAME$1, __scopeSelect);
1527
+ const [contentWrapper, setContentWrapper] = reactExports.useState(null);
1528
+ const [content, setContent] = reactExports.useState(null);
1529
+ const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node));
1530
+ const getItems = useCollection(__scopeSelect);
1531
+ const shouldExpandOnScrollRef = reactExports.useRef(false);
1532
+ const shouldRepositionRef = reactExports.useRef(true);
1533
+ const { viewport, selectedItem, selectedItemText, focusSelectedItem } = contentContext;
1534
+ const position = reactExports.useCallback(() => {
1535
+ if (context.trigger && context.valueNode && contentWrapper && content && viewport && selectedItem && selectedItemText) {
1536
+ const triggerRect = context.trigger.getBoundingClientRect();
1537
+ const contentRect = content.getBoundingClientRect();
1538
+ const valueNodeRect = context.valueNode.getBoundingClientRect();
1539
+ const itemTextRect = selectedItemText.getBoundingClientRect();
1540
+ if (context.dir !== "rtl") {
1541
+ const itemTextOffset = itemTextRect.left - contentRect.left;
1542
+ const left = valueNodeRect.left - itemTextOffset;
1543
+ const leftDelta = triggerRect.left - left;
1544
+ const minContentWidth = triggerRect.width + leftDelta;
1545
+ const contentWidth = Math.max(minContentWidth, contentRect.width);
1546
+ const rightEdge = window.innerWidth - CONTENT_MARGIN;
1547
+ const clampedLeft = clamp(left, [
1548
+ CONTENT_MARGIN,
1549
+ // Prevents the content from going off the starting edge of the
1550
+ // viewport. It may still go off the ending edge, but this can be
1551
+ // controlled by the user since they may want to manage overflow in a
1552
+ // specific way.
1553
+ // https://github.com/radix-ui/primitives/issues/2049
1554
+ Math.max(CONTENT_MARGIN, rightEdge - contentWidth)
1555
+ ]);
1556
+ contentWrapper.style.minWidth = minContentWidth + "px";
1557
+ contentWrapper.style.left = clampedLeft + "px";
1558
+ } else {
1559
+ const itemTextOffset = contentRect.right - itemTextRect.right;
1560
+ const right = window.innerWidth - valueNodeRect.right - itemTextOffset;
1561
+ const rightDelta = window.innerWidth - triggerRect.right - right;
1562
+ const minContentWidth = triggerRect.width + rightDelta;
1563
+ const contentWidth = Math.max(minContentWidth, contentRect.width);
1564
+ const leftEdge = window.innerWidth - CONTENT_MARGIN;
1565
+ const clampedRight = clamp(right, [
1566
+ CONTENT_MARGIN,
1567
+ Math.max(CONTENT_MARGIN, leftEdge - contentWidth)
1568
+ ]);
1569
+ contentWrapper.style.minWidth = minContentWidth + "px";
1570
+ contentWrapper.style.right = clampedRight + "px";
1571
+ }
1572
+ const items = getItems();
1573
+ const availableHeight = window.innerHeight - CONTENT_MARGIN * 2;
1574
+ const itemsHeight = viewport.scrollHeight;
1575
+ const contentStyles = window.getComputedStyle(content);
1576
+ const contentBorderTopWidth = parseInt(contentStyles.borderTopWidth, 10);
1577
+ const contentPaddingTop = parseInt(contentStyles.paddingTop, 10);
1578
+ const contentBorderBottomWidth = parseInt(contentStyles.borderBottomWidth, 10);
1579
+ const contentPaddingBottom = parseInt(contentStyles.paddingBottom, 10);
1580
+ const fullContentHeight = contentBorderTopWidth + contentPaddingTop + itemsHeight + contentPaddingBottom + contentBorderBottomWidth;
1581
+ const minContentHeight = Math.min(selectedItem.offsetHeight * 5, fullContentHeight);
1582
+ const viewportStyles = window.getComputedStyle(viewport);
1583
+ const viewportPaddingTop = parseInt(viewportStyles.paddingTop, 10);
1584
+ const viewportPaddingBottom = parseInt(viewportStyles.paddingBottom, 10);
1585
+ const topEdgeToTriggerMiddle = triggerRect.top + triggerRect.height / 2 - CONTENT_MARGIN;
1586
+ const triggerMiddleToBottomEdge = availableHeight - topEdgeToTriggerMiddle;
1587
+ const selectedItemHalfHeight = selectedItem.offsetHeight / 2;
1588
+ const itemOffsetMiddle = selectedItem.offsetTop + selectedItemHalfHeight;
1589
+ const contentTopToItemMiddle = contentBorderTopWidth + contentPaddingTop + itemOffsetMiddle;
1590
+ const itemMiddleToContentBottom = fullContentHeight - contentTopToItemMiddle;
1591
+ const willAlignWithoutTopOverflow = contentTopToItemMiddle <= topEdgeToTriggerMiddle;
1592
+ if (willAlignWithoutTopOverflow) {
1593
+ const isLastItem = items.length > 0 && selectedItem === items[items.length - 1].ref.current;
1594
+ contentWrapper.style.bottom = "0px";
1595
+ const viewportOffsetBottom = content.clientHeight - viewport.offsetTop - viewport.offsetHeight;
1596
+ const clampedTriggerMiddleToBottomEdge = Math.max(
1597
+ triggerMiddleToBottomEdge,
1598
+ selectedItemHalfHeight + // viewport might have padding bottom, include it to avoid a scrollable viewport
1599
+ (isLastItem ? viewportPaddingBottom : 0) + viewportOffsetBottom + contentBorderBottomWidth
1600
+ );
1601
+ const height = contentTopToItemMiddle + clampedTriggerMiddleToBottomEdge;
1602
+ contentWrapper.style.height = height + "px";
1603
+ } else {
1604
+ const isFirstItem = items.length > 0 && selectedItem === items[0].ref.current;
1605
+ contentWrapper.style.top = "0px";
1606
+ const clampedTopEdgeToTriggerMiddle = Math.max(
1607
+ topEdgeToTriggerMiddle,
1608
+ contentBorderTopWidth + viewport.offsetTop + // viewport might have padding top, include it to avoid a scrollable viewport
1609
+ (isFirstItem ? viewportPaddingTop : 0) + selectedItemHalfHeight
1610
+ );
1611
+ const height = clampedTopEdgeToTriggerMiddle + itemMiddleToContentBottom;
1612
+ contentWrapper.style.height = height + "px";
1613
+ viewport.scrollTop = contentTopToItemMiddle - topEdgeToTriggerMiddle + viewport.offsetTop;
1614
+ }
1615
+ contentWrapper.style.margin = `${CONTENT_MARGIN}px 0`;
1616
+ contentWrapper.style.minHeight = minContentHeight + "px";
1617
+ contentWrapper.style.maxHeight = availableHeight + "px";
1618
+ onPlaced == null ? void 0 : onPlaced();
1619
+ requestAnimationFrame(() => shouldExpandOnScrollRef.current = true);
1620
+ }
1621
+ }, [
1622
+ getItems,
1623
+ context.trigger,
1624
+ context.valueNode,
1625
+ contentWrapper,
1626
+ content,
1627
+ viewport,
1628
+ selectedItem,
1629
+ selectedItemText,
1630
+ context.dir,
1631
+ onPlaced
1632
+ ]);
1633
+ useLayoutEffect2(() => position(), [position]);
1634
+ const [contentZIndex, setContentZIndex] = reactExports.useState();
1635
+ useLayoutEffect2(() => {
1636
+ if (content) setContentZIndex(window.getComputedStyle(content).zIndex);
1637
+ }, [content]);
1638
+ const handleScrollButtonChange = reactExports.useCallback(
1639
+ (node) => {
1640
+ if (node && shouldRepositionRef.current === true) {
1641
+ position();
1642
+ focusSelectedItem == null ? void 0 : focusSelectedItem();
1643
+ shouldRepositionRef.current = false;
1644
+ }
1645
+ },
1646
+ [position, focusSelectedItem]
1647
+ );
1648
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1649
+ SelectViewportProvider,
1650
+ {
1651
+ scope: __scopeSelect,
1652
+ contentWrapper,
1653
+ shouldExpandOnScrollRef,
1654
+ onScrollButtonChange: handleScrollButtonChange,
1655
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1656
+ "div",
1657
+ {
1658
+ ref: setContentWrapper,
1659
+ style: {
1660
+ display: "flex",
1661
+ flexDirection: "column",
1662
+ position: "fixed",
1663
+ zIndex: contentZIndex
1664
+ },
1665
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1666
+ Primitive.div,
1667
+ {
1668
+ ...popperProps,
1669
+ ref: composedRefs,
1670
+ style: {
1671
+ // When we get the height of the content, it includes borders. If we were to set
1672
+ // the height without having `boxSizing: 'border-box'` it would be too big.
1673
+ boxSizing: "border-box",
1674
+ // We need to ensure the content doesn't get taller than the wrapper
1675
+ maxHeight: "100%",
1676
+ ...popperProps.style
1677
+ }
1678
+ }
1679
+ )
1680
+ }
1681
+ )
1682
+ }
1683
+ );
1684
+ });
1685
+ SelectItemAlignedPosition.displayName = ITEM_ALIGNED_POSITION_NAME;
1686
+ var POPPER_POSITION_NAME = "SelectPopperPosition";
1687
+ var SelectPopperPosition = reactExports.forwardRef((props, forwardedRef) => {
1688
+ const {
1689
+ __scopeSelect,
1690
+ align = "start",
1691
+ collisionPadding = CONTENT_MARGIN,
1692
+ ...popperProps
1693
+ } = props;
1694
+ const popperScope = usePopperScope(__scopeSelect);
1695
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1696
+ Content$1,
1697
+ {
1698
+ ...popperScope,
1699
+ ...popperProps,
1700
+ ref: forwardedRef,
1701
+ align,
1702
+ collisionPadding,
1703
+ style: {
1704
+ // Ensure border-box for floating-ui calculations
1705
+ boxSizing: "border-box",
1706
+ ...popperProps.style,
1707
+ // re-namespace exposed content custom properties
1708
+ ...{
1709
+ "--radix-select-content-transform-origin": "var(--radix-popper-transform-origin)",
1710
+ "--radix-select-content-available-width": "var(--radix-popper-available-width)",
1711
+ "--radix-select-content-available-height": "var(--radix-popper-available-height)",
1712
+ "--radix-select-trigger-width": "var(--radix-popper-anchor-width)",
1713
+ "--radix-select-trigger-height": "var(--radix-popper-anchor-height)"
1714
+ }
1715
+ }
1716
+ }
1717
+ );
1718
+ });
1719
+ SelectPopperPosition.displayName = POPPER_POSITION_NAME;
1720
+ var [SelectViewportProvider, useSelectViewportContext] = createSelectContext(CONTENT_NAME$1, {});
1721
+ var VIEWPORT_NAME = "SelectViewport";
1722
+ var SelectViewport = reactExports.forwardRef(
1723
+ (props, forwardedRef) => {
1724
+ const { __scopeSelect, nonce, ...viewportProps } = props;
1725
+ const contentContext = useSelectContentContext(VIEWPORT_NAME, __scopeSelect);
1726
+ const viewportContext = useSelectViewportContext(VIEWPORT_NAME, __scopeSelect);
1727
+ const composedRefs = useComposedRefs(forwardedRef, contentContext.onViewportChange);
1728
+ const prevScrollTopRef = reactExports.useRef(0);
1729
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1730
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1731
+ "style",
1732
+ {
1733
+ dangerouslySetInnerHTML: {
1734
+ __html: `[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}`
1735
+ },
1736
+ nonce
1737
+ }
1738
+ ),
1739
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Collection.Slot, { scope: __scopeSelect, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1740
+ Primitive.div,
1741
+ {
1742
+ "data-radix-select-viewport": "",
1743
+ role: "presentation",
1744
+ ...viewportProps,
1745
+ ref: composedRefs,
1746
+ style: {
1747
+ // we use position: 'relative' here on the `viewport` so that when we call
1748
+ // `selectedItem.offsetTop` in calculations, the offset is relative to the viewport
1749
+ // (independent of the scrollUpButton).
1750
+ position: "relative",
1751
+ flex: 1,
1752
+ // Viewport should only be scrollable in the vertical direction.
1753
+ // This won't work in vertical writing modes, so we'll need to
1754
+ // revisit this if/when that is supported
1755
+ // https://developer.chrome.com/blog/vertical-form-controls
1756
+ overflow: "hidden auto",
1757
+ ...viewportProps.style
1758
+ },
1759
+ onScroll: composeEventHandlers(viewportProps.onScroll, (event) => {
1760
+ const viewport = event.currentTarget;
1761
+ const { contentWrapper, shouldExpandOnScrollRef } = viewportContext;
1762
+ if ((shouldExpandOnScrollRef == null ? void 0 : shouldExpandOnScrollRef.current) && contentWrapper) {
1763
+ const scrolledBy = Math.abs(prevScrollTopRef.current - viewport.scrollTop);
1764
+ if (scrolledBy > 0) {
1765
+ const availableHeight = window.innerHeight - CONTENT_MARGIN * 2;
1766
+ const cssMinHeight = parseFloat(contentWrapper.style.minHeight);
1767
+ const cssHeight = parseFloat(contentWrapper.style.height);
1768
+ const prevHeight = Math.max(cssMinHeight, cssHeight);
1769
+ if (prevHeight < availableHeight) {
1770
+ const nextHeight = prevHeight + scrolledBy;
1771
+ const clampedNextHeight = Math.min(availableHeight, nextHeight);
1772
+ const heightDiff = nextHeight - clampedNextHeight;
1773
+ contentWrapper.style.height = clampedNextHeight + "px";
1774
+ if (contentWrapper.style.bottom === "0px") {
1775
+ viewport.scrollTop = heightDiff > 0 ? heightDiff : 0;
1776
+ contentWrapper.style.justifyContent = "flex-end";
1777
+ }
1778
+ }
1779
+ }
1780
+ }
1781
+ prevScrollTopRef.current = viewport.scrollTop;
1782
+ })
1783
+ }
1784
+ ) })
1785
+ ] });
1786
+ }
1787
+ );
1788
+ SelectViewport.displayName = VIEWPORT_NAME;
1789
+ var GROUP_NAME = "SelectGroup";
1790
+ var [SelectGroupContextProvider, useSelectGroupContext] = createSelectContext(GROUP_NAME);
1791
+ var SelectGroup = reactExports.forwardRef(
1792
+ (props, forwardedRef) => {
1793
+ const { __scopeSelect, ...groupProps } = props;
1794
+ const groupId = useId();
1795
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SelectGroupContextProvider, { scope: __scopeSelect, id: groupId, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.div, { role: "group", "aria-labelledby": groupId, ...groupProps, ref: forwardedRef }) });
1796
+ }
1797
+ );
1798
+ SelectGroup.displayName = GROUP_NAME;
1799
+ var LABEL_NAME = "SelectLabel";
1800
+ var SelectLabel$1 = reactExports.forwardRef(
1801
+ (props, forwardedRef) => {
1802
+ const { __scopeSelect, ...labelProps } = props;
1803
+ const groupContext = useSelectGroupContext(LABEL_NAME, __scopeSelect);
1804
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.div, { id: groupContext.id, ...labelProps, ref: forwardedRef });
1805
+ }
1806
+ );
1807
+ SelectLabel$1.displayName = LABEL_NAME;
1808
+ var ITEM_NAME = "SelectItem";
1809
+ var [SelectItemContextProvider, useSelectItemContext] = createSelectContext(ITEM_NAME);
1810
+ var SelectItem$1 = reactExports.forwardRef(
1811
+ (props, forwardedRef) => {
1812
+ const {
1813
+ __scopeSelect,
1814
+ value,
1815
+ disabled = false,
1816
+ textValue: textValueProp,
1817
+ ...itemProps
1818
+ } = props;
1819
+ const context = useSelectContext(ITEM_NAME, __scopeSelect);
1820
+ const contentContext = useSelectContentContext(ITEM_NAME, __scopeSelect);
1821
+ const isSelected = context.value === value;
1822
+ const [textValue, setTextValue] = reactExports.useState(textValueProp ?? "");
1823
+ const [isFocused, setIsFocused] = reactExports.useState(false);
1824
+ const composedRefs = useComposedRefs(
1825
+ forwardedRef,
1826
+ (node) => {
1827
+ var _a;
1828
+ return (_a = contentContext.itemRefCallback) == null ? void 0 : _a.call(contentContext, node, value, disabled);
1829
+ }
1830
+ );
1831
+ const textId = useId();
1832
+ const pointerTypeRef = reactExports.useRef("touch");
1833
+ const handleSelect = () => {
1834
+ if (!disabled) {
1835
+ context.onValueChange(value);
1836
+ context.onOpenChange(false);
1837
+ }
1838
+ };
1839
+ if (value === "") {
1840
+ throw new Error(
1841
+ "A <Select.Item /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder."
1842
+ );
1843
+ }
1844
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1845
+ SelectItemContextProvider,
1846
+ {
1847
+ scope: __scopeSelect,
1848
+ value,
1849
+ disabled,
1850
+ textId,
1851
+ isSelected,
1852
+ onItemTextChange: reactExports.useCallback((node) => {
1853
+ setTextValue((prevTextValue) => prevTextValue || ((node == null ? void 0 : node.textContent) ?? "").trim());
1854
+ }, []),
1855
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1856
+ Collection.ItemSlot,
1857
+ {
1858
+ scope: __scopeSelect,
1859
+ value,
1860
+ disabled,
1861
+ textValue,
1862
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1863
+ Primitive.div,
1864
+ {
1865
+ role: "option",
1866
+ "aria-labelledby": textId,
1867
+ "data-highlighted": isFocused ? "" : void 0,
1868
+ "aria-selected": isSelected && isFocused,
1869
+ "data-state": isSelected ? "checked" : "unchecked",
1870
+ "aria-disabled": disabled || void 0,
1871
+ "data-disabled": disabled ? "" : void 0,
1872
+ tabIndex: disabled ? void 0 : -1,
1873
+ ...itemProps,
1874
+ ref: composedRefs,
1875
+ onFocus: composeEventHandlers(itemProps.onFocus, () => setIsFocused(true)),
1876
+ onBlur: composeEventHandlers(itemProps.onBlur, () => setIsFocused(false)),
1877
+ onClick: composeEventHandlers(itemProps.onClick, () => {
1878
+ if (pointerTypeRef.current !== "mouse") handleSelect();
1879
+ }),
1880
+ onPointerUp: composeEventHandlers(itemProps.onPointerUp, () => {
1881
+ if (pointerTypeRef.current === "mouse") handleSelect();
1882
+ }),
1883
+ onPointerDown: composeEventHandlers(itemProps.onPointerDown, (event) => {
1884
+ pointerTypeRef.current = event.pointerType;
1885
+ }),
1886
+ onPointerMove: composeEventHandlers(itemProps.onPointerMove, (event) => {
1887
+ var _a;
1888
+ pointerTypeRef.current = event.pointerType;
1889
+ if (disabled) {
1890
+ (_a = contentContext.onItemLeave) == null ? void 0 : _a.call(contentContext);
1891
+ } else if (pointerTypeRef.current === "mouse") {
1892
+ event.currentTarget.focus({ preventScroll: true });
1893
+ }
1894
+ }),
1895
+ onPointerLeave: composeEventHandlers(itemProps.onPointerLeave, (event) => {
1896
+ var _a;
1897
+ if (event.currentTarget === document.activeElement) {
1898
+ (_a = contentContext.onItemLeave) == null ? void 0 : _a.call(contentContext);
1899
+ }
1900
+ }),
1901
+ onKeyDown: composeEventHandlers(itemProps.onKeyDown, (event) => {
1902
+ var _a;
1903
+ const isTypingAhead = ((_a = contentContext.searchRef) == null ? void 0 : _a.current) !== "";
1904
+ if (isTypingAhead && event.key === " ") return;
1905
+ if (SELECTION_KEYS.includes(event.key)) handleSelect();
1906
+ if (event.key === " ") event.preventDefault();
1907
+ })
1908
+ }
1909
+ )
1910
+ }
1911
+ )
1912
+ }
1913
+ );
1914
+ }
1915
+ );
1916
+ SelectItem$1.displayName = ITEM_NAME;
1917
+ var ITEM_TEXT_NAME = "SelectItemText";
1918
+ var SelectItemText = reactExports.forwardRef(
1919
+ (props, forwardedRef) => {
1920
+ const { __scopeSelect, className, style, ...itemTextProps } = props;
1921
+ const context = useSelectContext(ITEM_TEXT_NAME, __scopeSelect);
1922
+ const contentContext = useSelectContentContext(ITEM_TEXT_NAME, __scopeSelect);
1923
+ const itemContext = useSelectItemContext(ITEM_TEXT_NAME, __scopeSelect);
1924
+ const nativeOptionsContext = useSelectNativeOptionsContext(ITEM_TEXT_NAME, __scopeSelect);
1925
+ const [itemTextNode, setItemTextNode] = reactExports.useState(null);
1926
+ const composedRefs = useComposedRefs(
1927
+ forwardedRef,
1928
+ (node) => setItemTextNode(node),
1929
+ itemContext.onItemTextChange,
1930
+ (node) => {
1931
+ var _a;
1932
+ return (_a = contentContext.itemTextRefCallback) == null ? void 0 : _a.call(contentContext, node, itemContext.value, itemContext.disabled);
1933
+ }
1934
+ );
1935
+ const textContent = itemTextNode == null ? void 0 : itemTextNode.textContent;
1936
+ const nativeOption = reactExports.useMemo(
1937
+ () => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: itemContext.value, disabled: itemContext.disabled, children: textContent }, itemContext.value),
1938
+ [itemContext.disabled, itemContext.value, textContent]
1939
+ );
1940
+ const { onNativeOptionAdd, onNativeOptionRemove } = nativeOptionsContext;
1941
+ useLayoutEffect2(() => {
1942
+ onNativeOptionAdd(nativeOption);
1943
+ return () => onNativeOptionRemove(nativeOption);
1944
+ }, [onNativeOptionAdd, onNativeOptionRemove, nativeOption]);
1945
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1946
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.span, { id: itemContext.textId, ...itemTextProps, ref: composedRefs }),
1947
+ itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren ? reactDomExports.createPortal(itemTextProps.children, context.valueNode) : null
1948
+ ] });
1949
+ }
1950
+ );
1951
+ SelectItemText.displayName = ITEM_TEXT_NAME;
1952
+ var ITEM_INDICATOR_NAME = "SelectItemIndicator";
1953
+ var SelectItemIndicator = reactExports.forwardRef(
1954
+ (props, forwardedRef) => {
1955
+ const { __scopeSelect, ...itemIndicatorProps } = props;
1956
+ const itemContext = useSelectItemContext(ITEM_INDICATOR_NAME, __scopeSelect);
1957
+ return itemContext.isSelected ? /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.span, { "aria-hidden": true, ...itemIndicatorProps, ref: forwardedRef }) : null;
1958
+ }
1959
+ );
1960
+ SelectItemIndicator.displayName = ITEM_INDICATOR_NAME;
1961
+ var SCROLL_UP_BUTTON_NAME = "SelectScrollUpButton";
1962
+ var SelectScrollUpButton$1 = reactExports.forwardRef((props, forwardedRef) => {
1963
+ const contentContext = useSelectContentContext(SCROLL_UP_BUTTON_NAME, props.__scopeSelect);
1964
+ const viewportContext = useSelectViewportContext(SCROLL_UP_BUTTON_NAME, props.__scopeSelect);
1965
+ const [canScrollUp, setCanScrollUp] = reactExports.useState(false);
1966
+ const composedRefs = useComposedRefs(forwardedRef, viewportContext.onScrollButtonChange);
1967
+ useLayoutEffect2(() => {
1968
+ if (contentContext.viewport && contentContext.isPositioned) {
1969
+ let handleScroll2 = function() {
1970
+ const canScrollUp2 = viewport.scrollTop > 0;
1971
+ setCanScrollUp(canScrollUp2);
1972
+ };
1973
+ const viewport = contentContext.viewport;
1974
+ handleScroll2();
1975
+ viewport.addEventListener("scroll", handleScroll2);
1976
+ return () => viewport.removeEventListener("scroll", handleScroll2);
1977
+ }
1978
+ }, [contentContext.viewport, contentContext.isPositioned]);
1979
+ return canScrollUp ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1980
+ SelectScrollButtonImpl,
1981
+ {
1982
+ ...props,
1983
+ ref: composedRefs,
1984
+ onAutoScroll: () => {
1985
+ const { viewport, selectedItem } = contentContext;
1986
+ if (viewport && selectedItem) {
1987
+ viewport.scrollTop = viewport.scrollTop - selectedItem.offsetHeight;
1988
+ }
1989
+ }
1990
+ }
1991
+ ) : null;
1992
+ });
1993
+ SelectScrollUpButton$1.displayName = SCROLL_UP_BUTTON_NAME;
1994
+ var SCROLL_DOWN_BUTTON_NAME = "SelectScrollDownButton";
1995
+ var SelectScrollDownButton$1 = reactExports.forwardRef((props, forwardedRef) => {
1996
+ const contentContext = useSelectContentContext(SCROLL_DOWN_BUTTON_NAME, props.__scopeSelect);
1997
+ const viewportContext = useSelectViewportContext(SCROLL_DOWN_BUTTON_NAME, props.__scopeSelect);
1998
+ const [canScrollDown, setCanScrollDown] = reactExports.useState(false);
1999
+ const composedRefs = useComposedRefs(forwardedRef, viewportContext.onScrollButtonChange);
2000
+ useLayoutEffect2(() => {
2001
+ if (contentContext.viewport && contentContext.isPositioned) {
2002
+ let handleScroll2 = function() {
2003
+ const maxScroll = viewport.scrollHeight - viewport.clientHeight;
2004
+ const canScrollDown2 = Math.ceil(viewport.scrollTop) < maxScroll;
2005
+ setCanScrollDown(canScrollDown2);
2006
+ };
2007
+ const viewport = contentContext.viewport;
2008
+ handleScroll2();
2009
+ viewport.addEventListener("scroll", handleScroll2);
2010
+ return () => viewport.removeEventListener("scroll", handleScroll2);
2011
+ }
2012
+ }, [contentContext.viewport, contentContext.isPositioned]);
2013
+ return canScrollDown ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2014
+ SelectScrollButtonImpl,
2015
+ {
2016
+ ...props,
2017
+ ref: composedRefs,
2018
+ onAutoScroll: () => {
2019
+ const { viewport, selectedItem } = contentContext;
2020
+ if (viewport && selectedItem) {
2021
+ viewport.scrollTop = viewport.scrollTop + selectedItem.offsetHeight;
2022
+ }
2023
+ }
2024
+ }
2025
+ ) : null;
2026
+ });
2027
+ SelectScrollDownButton$1.displayName = SCROLL_DOWN_BUTTON_NAME;
2028
+ var SelectScrollButtonImpl = reactExports.forwardRef((props, forwardedRef) => {
2029
+ const { __scopeSelect, onAutoScroll, ...scrollIndicatorProps } = props;
2030
+ const contentContext = useSelectContentContext("SelectScrollButton", __scopeSelect);
2031
+ const autoScrollTimerRef = reactExports.useRef(null);
2032
+ const getItems = useCollection(__scopeSelect);
2033
+ const clearAutoScrollTimer = reactExports.useCallback(() => {
2034
+ if (autoScrollTimerRef.current !== null) {
2035
+ window.clearInterval(autoScrollTimerRef.current);
2036
+ autoScrollTimerRef.current = null;
2037
+ }
2038
+ }, []);
2039
+ reactExports.useEffect(() => {
2040
+ return () => clearAutoScrollTimer();
2041
+ }, [clearAutoScrollTimer]);
2042
+ useLayoutEffect2(() => {
2043
+ var _a;
2044
+ const activeItem = getItems().find((item) => item.ref.current === document.activeElement);
2045
+ (_a = activeItem == null ? void 0 : activeItem.ref.current) == null ? void 0 : _a.scrollIntoView({ block: "nearest" });
2046
+ }, [getItems]);
2047
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2048
+ Primitive.div,
2049
+ {
2050
+ "aria-hidden": true,
2051
+ ...scrollIndicatorProps,
2052
+ ref: forwardedRef,
2053
+ style: { flexShrink: 0, ...scrollIndicatorProps.style },
2054
+ onPointerDown: composeEventHandlers(scrollIndicatorProps.onPointerDown, () => {
2055
+ if (autoScrollTimerRef.current === null) {
2056
+ autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50);
2057
+ }
2058
+ }),
2059
+ onPointerMove: composeEventHandlers(scrollIndicatorProps.onPointerMove, () => {
2060
+ var _a;
2061
+ (_a = contentContext.onItemLeave) == null ? void 0 : _a.call(contentContext);
2062
+ if (autoScrollTimerRef.current === null) {
2063
+ autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50);
2064
+ }
2065
+ }),
2066
+ onPointerLeave: composeEventHandlers(scrollIndicatorProps.onPointerLeave, () => {
2067
+ clearAutoScrollTimer();
2068
+ })
2069
+ }
2070
+ );
2071
+ });
2072
+ var SEPARATOR_NAME = "SelectSeparator";
2073
+ var SelectSeparator$1 = reactExports.forwardRef(
2074
+ (props, forwardedRef) => {
2075
+ const { __scopeSelect, ...separatorProps } = props;
2076
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.div, { "aria-hidden": true, ...separatorProps, ref: forwardedRef });
2077
+ }
2078
+ );
2079
+ SelectSeparator$1.displayName = SEPARATOR_NAME;
2080
+ var ARROW_NAME = "SelectArrow";
2081
+ var SelectArrow = reactExports.forwardRef(
2082
+ (props, forwardedRef) => {
2083
+ const { __scopeSelect, ...arrowProps } = props;
2084
+ const popperScope = usePopperScope(__scopeSelect);
2085
+ const context = useSelectContext(ARROW_NAME, __scopeSelect);
2086
+ const contentContext = useSelectContentContext(ARROW_NAME, __scopeSelect);
2087
+ return context.open && contentContext.position === "popper" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Arrow, { ...popperScope, ...arrowProps, ref: forwardedRef }) : null;
2088
+ }
2089
+ );
2090
+ SelectArrow.displayName = ARROW_NAME;
2091
+ var BUBBLE_INPUT_NAME = "SelectBubbleInput";
2092
+ var SelectBubbleInput = reactExports.forwardRef(
2093
+ ({ __scopeSelect, value, ...props }, forwardedRef) => {
2094
+ const ref = reactExports.useRef(null);
2095
+ const composedRefs = useComposedRefs(forwardedRef, ref);
2096
+ const prevValue = usePrevious$1(value);
2097
+ reactExports.useEffect(() => {
2098
+ const select = ref.current;
2099
+ if (!select) return;
2100
+ const selectProto = window.HTMLSelectElement.prototype;
2101
+ const descriptor = Object.getOwnPropertyDescriptor(
2102
+ selectProto,
2103
+ "value"
2104
+ );
2105
+ const setValue = descriptor.set;
2106
+ if (prevValue !== value && setValue) {
2107
+ const event = new Event("change", { bubbles: true });
2108
+ setValue.call(select, value);
2109
+ select.dispatchEvent(event);
2110
+ }
2111
+ }, [prevValue, value]);
2112
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2113
+ Primitive.select,
2114
+ {
2115
+ ...props,
2116
+ style: { ...VISUALLY_HIDDEN_STYLES, ...props.style },
2117
+ ref: composedRefs,
2118
+ defaultValue: value
2119
+ }
2120
+ );
2121
+ }
2122
+ );
2123
+ SelectBubbleInput.displayName = BUBBLE_INPUT_NAME;
2124
+ function shouldShowPlaceholder(value) {
2125
+ return value === "" || value === void 0;
2126
+ }
2127
+ function useTypeaheadSearch(onSearchChange) {
2128
+ const handleSearchChange = useCallbackRef(onSearchChange);
2129
+ const searchRef = reactExports.useRef("");
2130
+ const timerRef = reactExports.useRef(0);
2131
+ const handleTypeaheadSearch = reactExports.useCallback(
2132
+ (key) => {
2133
+ const search = searchRef.current + key;
2134
+ handleSearchChange(search);
2135
+ (function updateSearch(value) {
2136
+ searchRef.current = value;
2137
+ window.clearTimeout(timerRef.current);
2138
+ if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
2139
+ })(search);
2140
+ },
2141
+ [handleSearchChange]
2142
+ );
2143
+ const resetTypeahead = reactExports.useCallback(() => {
2144
+ searchRef.current = "";
2145
+ window.clearTimeout(timerRef.current);
2146
+ }, []);
2147
+ reactExports.useEffect(() => {
2148
+ return () => window.clearTimeout(timerRef.current);
2149
+ }, []);
2150
+ return [searchRef, handleTypeaheadSearch, resetTypeahead];
2151
+ }
2152
+ function findNextItem(items, search, currentItem) {
2153
+ const isRepeated = search.length > 1 && Array.from(search).every((char) => char === search[0]);
2154
+ const normalizedSearch = isRepeated ? search[0] : search;
2155
+ const currentItemIndex = currentItem ? items.indexOf(currentItem) : -1;
2156
+ let wrappedItems = wrapArray(items, Math.max(currentItemIndex, 0));
2157
+ const excludeCurrentItem = normalizedSearch.length === 1;
2158
+ if (excludeCurrentItem) wrappedItems = wrappedItems.filter((v) => v !== currentItem);
2159
+ const nextItem = wrappedItems.find(
2160
+ (item) => item.textValue.toLowerCase().startsWith(normalizedSearch.toLowerCase())
2161
+ );
2162
+ return nextItem !== currentItem ? nextItem : void 0;
2163
+ }
2164
+ function wrapArray(array, startIndex) {
2165
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
2166
+ }
2167
+ var Root2 = Select$1;
2168
+ var Trigger = SelectTrigger$1;
2169
+ var Value = SelectValue$1;
2170
+ var Icon = SelectIcon;
2171
+ var Portal$1 = SelectPortal;
2172
+ var Content2 = SelectContent$1;
2173
+ var Viewport = SelectViewport;
2174
+ var Label = SelectLabel$1;
2175
+ var Item = SelectItem$1;
2176
+ var ItemText = SelectItemText;
2177
+ var ItemIndicator = SelectItemIndicator;
2178
+ var ScrollUpButton = SelectScrollUpButton$1;
2179
+ var ScrollDownButton = SelectScrollDownButton$1;
2180
+ var Separator = SelectSeparator$1;
2181
+ const Select = Root2;
2182
+ const SelectValue = Value;
2183
+ const SelectTrigger = reactExports.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
2184
+ Trigger,
2185
+ {
2186
+ ref,
2187
+ className: cn(
2188
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2189
+ className
2190
+ ),
2191
+ ...props,
2192
+ children: [
2193
+ children,
2194
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
2195
+ ]
2196
+ }
2197
+ ));
2198
+ SelectTrigger.displayName = Trigger.displayName;
2199
+ const SelectScrollUpButton = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
2200
+ ScrollUpButton,
2201
+ {
2202
+ ref,
2203
+ className: cn(
2204
+ "flex cursor-default items-center justify-center py-1",
2205
+ className
2206
+ ),
2207
+ ...props,
2208
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { className: "h-4 w-4" })
2209
+ }
2210
+ ));
2211
+ SelectScrollUpButton.displayName = ScrollUpButton.displayName;
2212
+ const SelectScrollDownButton = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
2213
+ ScrollDownButton,
2214
+ {
2215
+ ref,
2216
+ className: cn(
2217
+ "flex cursor-default items-center justify-center py-1",
2218
+ className
2219
+ ),
2220
+ ...props,
2221
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "h-4 w-4" })
2222
+ }
2223
+ ));
2224
+ SelectScrollDownButton.displayName = ScrollDownButton.displayName;
2225
+ const SelectContent = reactExports.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2226
+ Content2,
2227
+ {
2228
+ ref,
2229
+ className: cn(
2230
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
2231
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
2232
+ className
2233
+ ),
2234
+ position,
2235
+ ...props,
2236
+ children: [
2237
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectScrollUpButton, {}),
2238
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
2239
+ Viewport,
2240
+ {
2241
+ className: cn(
2242
+ "p-1",
2243
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
2244
+ ),
2245
+ children
2246
+ }
2247
+ ),
2248
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectScrollDownButton, {})
2249
+ ]
2250
+ }
2251
+ ) }));
2252
+ SelectContent.displayName = Content2.displayName;
2253
+ const SelectLabel = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
2254
+ Label,
2255
+ {
2256
+ ref,
2257
+ className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className),
2258
+ ...props
2259
+ }
2260
+ ));
2261
+ SelectLabel.displayName = Label.displayName;
2262
+ const SelectItem = reactExports.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
2263
+ Item,
2264
+ {
2265
+ ref,
2266
+ className: cn(
2267
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
2268
+ className
2269
+ ),
2270
+ ...props,
2271
+ children: [
2272
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ItemIndicator, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "h-4 w-4" }) }) }),
2273
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ItemText, { children })
2274
+ ]
2275
+ }
2276
+ ));
2277
+ SelectItem.displayName = Item.displayName;
2278
+ const SelectSeparator = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
2279
+ Separator,
2280
+ {
2281
+ ref,
2282
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
2283
+ ...props
2284
+ }
2285
+ ));
2286
+ SelectSeparator.displayName = Separator.displayName;
2287
+ function useTableSelection({
2288
+ getItemId
2289
+ }) {
2290
+ const [selectedIds, setSelectedIds] = reactExports.useState(/* @__PURE__ */ new Set());
2291
+ const isSelected = reactExports.useCallback(
2292
+ (item) => selectedIds.has(getItemId(item)),
2293
+ [selectedIds, getItemId]
2294
+ );
2295
+ const toggleSelection = reactExports.useCallback(
2296
+ (item) => {
2297
+ const id = getItemId(item);
2298
+ setSelectedIds((prev) => {
2299
+ const next = new Set(prev);
2300
+ if (next.has(id)) {
2301
+ next.delete(id);
2302
+ } else {
2303
+ next.add(id);
2304
+ }
2305
+ return next;
2306
+ });
2307
+ },
2308
+ [getItemId]
2309
+ );
2310
+ const selectAll = reactExports.useCallback(
2311
+ (items) => {
2312
+ setSelectedIds(new Set(items.map(getItemId)));
2313
+ },
2314
+ [getItemId]
2315
+ );
2316
+ const clearSelection = reactExports.useCallback(() => {
2317
+ setSelectedIds(/* @__PURE__ */ new Set());
2318
+ }, []);
2319
+ const isAllSelected = reactExports.useCallback(
2320
+ (items) => {
2321
+ if (items.length === 0) return false;
2322
+ return items.every((item) => selectedIds.has(getItemId(item)));
2323
+ },
2324
+ [selectedIds, getItemId]
2325
+ );
2326
+ const isSomeSelected = reactExports.useCallback(
2327
+ (items) => {
2328
+ if (items.length === 0) return false;
2329
+ const someSelected = items.some(
2330
+ (item) => selectedIds.has(getItemId(item))
2331
+ );
2332
+ const allSelected = items.every(
2333
+ (item) => selectedIds.has(getItemId(item))
2334
+ );
2335
+ return someSelected && !allSelected;
2336
+ },
2337
+ [selectedIds, getItemId]
2338
+ );
2339
+ const toggleSelectAll = reactExports.useCallback(
2340
+ (items) => {
2341
+ if (isAllSelected(items)) {
2342
+ clearSelection();
2343
+ } else {
2344
+ selectAll(items);
2345
+ }
2346
+ },
2347
+ [isAllSelected, clearSelection, selectAll]
2348
+ );
2349
+ const selectById = reactExports.useCallback((id) => {
2350
+ setSelectedIds((prev) => {
2351
+ const next = new Set(prev);
2352
+ next.add(id);
2353
+ return next;
2354
+ });
2355
+ }, []);
2356
+ const deselectById = reactExports.useCallback((id) => {
2357
+ setSelectedIds((prev) => {
2358
+ const next = new Set(prev);
2359
+ next.delete(id);
2360
+ return next;
2361
+ });
2362
+ }, []);
2363
+ const selectionCount = selectedIds.size;
2364
+ return reactExports.useMemo(
2365
+ () => ({
2366
+ selectedIds,
2367
+ isSelected,
2368
+ toggleSelection,
2369
+ selectAll,
2370
+ clearSelection,
2371
+ toggleSelectAll,
2372
+ selectionCount,
2373
+ isAllSelected,
2374
+ isSomeSelected,
2375
+ selectById,
2376
+ deselectById
2377
+ }),
2378
+ [
2379
+ selectedIds,
2380
+ isSelected,
2381
+ toggleSelection,
2382
+ selectAll,
2383
+ clearSelection,
2384
+ toggleSelectAll,
2385
+ selectionCount,
2386
+ isAllSelected,
2387
+ isSomeSelected,
2388
+ selectById,
2389
+ deselectById
2390
+ ]
2391
+ );
2392
+ }
2393
+ function SelectionBar({
2394
+ selectionCount,
2395
+ onClearSelection,
2396
+ actions,
2397
+ itemLabel = "items",
2398
+ className
2399
+ }) {
2400
+ if (selectionCount === 0) {
2401
+ return null;
2402
+ }
2403
+ const label = selectionCount === 1 ? itemLabel.replace(/s$/, "") : itemLabel;
2404
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
2405
+ "div",
2406
+ {
2407
+ className: cn(
2408
+ "fixed bottom-6 left-1/2 -translate-x-1/2 z-50",
2409
+ "flex items-center gap-3 px-4 py-2.5 rounded-lg",
2410
+ "bg-primary text-primary-foreground shadow-lg",
2411
+ "animate-in fade-in slide-in-from-bottom-4 duration-200",
2412
+ className
2413
+ ),
2414
+ children: [
2415
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm font-medium", children: [
2416
+ selectionCount,
2417
+ " ",
2418
+ label,
2419
+ " selected"
2420
+ ] }),
2421
+ actions && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 border-l border-primary-foreground/20 pl-3", children: actions }),
2422
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2423
+ Button,
2424
+ {
2425
+ variant: "ghost",
2426
+ size: "sm",
2427
+ className: "h-7 px-2 text-primary-foreground hover:bg-primary-foreground/10 hover:text-primary-foreground",
2428
+ onClick: onClearSelection,
2429
+ children: [
2430
+ /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "h-4 w-4" }),
2431
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Clear selection" })
2432
+ ]
2433
+ }
2434
+ )
2435
+ ]
2436
+ }
2437
+ );
2438
+ }
2439
+ function usePrevious(value) {
2440
+ const ref = reactExports.useRef({ value, previous: value });
2441
+ return reactExports.useMemo(() => {
2442
+ if (ref.current.value !== value) {
2443
+ ref.current.previous = ref.current.value;
2444
+ ref.current.value = value;
2445
+ }
2446
+ return ref.current.previous;
2447
+ }, [value]);
2448
+ }
2449
+ var CHECKBOX_NAME = "Checkbox";
2450
+ var [createCheckboxContext] = createContextScope$1(CHECKBOX_NAME);
2451
+ var [CheckboxProvider, useCheckboxContext] = createCheckboxContext(CHECKBOX_NAME);
2452
+ var Checkbox$1 = reactExports.forwardRef(
2453
+ (props, forwardedRef) => {
2454
+ const {
2455
+ __scopeCheckbox,
2456
+ name,
2457
+ checked: checkedProp,
2458
+ defaultChecked,
2459
+ required,
2460
+ disabled,
2461
+ value = "on",
2462
+ onCheckedChange,
2463
+ form,
2464
+ ...checkboxProps
2465
+ } = props;
2466
+ const [button, setButton] = reactExports.useState(null);
2467
+ const composedRefs = useComposedRefs$1(forwardedRef, (node) => setButton(node));
2468
+ const hasConsumerStoppedPropagationRef = reactExports.useRef(false);
2469
+ const isFormControl = button ? form || !!button.closest("form") : true;
2470
+ const [checked = false, setChecked] = useControllableState$1({
2471
+ prop: checkedProp,
2472
+ defaultProp: defaultChecked,
2473
+ onChange: onCheckedChange
2474
+ });
2475
+ const initialCheckedStateRef = reactExports.useRef(checked);
2476
+ reactExports.useEffect(() => {
2477
+ const form2 = button == null ? void 0 : button.form;
2478
+ if (form2) {
2479
+ const reset = () => setChecked(initialCheckedStateRef.current);
2480
+ form2.addEventListener("reset", reset);
2481
+ return () => form2.removeEventListener("reset", reset);
2482
+ }
2483
+ }, [button, setChecked]);
2484
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(CheckboxProvider, { scope: __scopeCheckbox, state: checked, disabled, children: [
2485
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
2486
+ Primitive$1.button,
2487
+ {
2488
+ type: "button",
2489
+ role: "checkbox",
2490
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
2491
+ "aria-required": required,
2492
+ "data-state": getState$1(checked),
2493
+ "data-disabled": disabled ? "" : void 0,
2494
+ disabled,
2495
+ value,
2496
+ ...checkboxProps,
2497
+ ref: composedRefs,
2498
+ onKeyDown: composeEventHandlers$1(props.onKeyDown, (event) => {
2499
+ if (event.key === "Enter") event.preventDefault();
2500
+ }),
2501
+ onClick: composeEventHandlers$1(props.onClick, (event) => {
2502
+ setChecked((prevChecked) => isIndeterminate(prevChecked) ? true : !prevChecked);
2503
+ if (isFormControl) {
2504
+ hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
2505
+ if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
2506
+ }
2507
+ })
2508
+ }
2509
+ ),
2510
+ isFormControl && /* @__PURE__ */ jsxRuntimeExports.jsx(
2511
+ BubbleInput,
2512
+ {
2513
+ control: button,
2514
+ bubbles: !hasConsumerStoppedPropagationRef.current,
2515
+ name,
2516
+ value,
2517
+ checked,
2518
+ required,
2519
+ disabled,
2520
+ form,
2521
+ style: { transform: "translateX(-100%)" },
2522
+ defaultChecked: isIndeterminate(defaultChecked) ? false : defaultChecked
2523
+ }
2524
+ )
2525
+ ] });
2526
+ }
2527
+ );
2528
+ Checkbox$1.displayName = CHECKBOX_NAME;
2529
+ var INDICATOR_NAME = "CheckboxIndicator";
2530
+ var CheckboxIndicator = reactExports.forwardRef(
2531
+ (props, forwardedRef) => {
2532
+ const { __scopeCheckbox, forceMount, ...indicatorProps } = props;
2533
+ const context = useCheckboxContext(INDICATOR_NAME, __scopeCheckbox);
2534
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Presence, { present: forceMount || isIndeterminate(context.state) || context.state === true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2535
+ Primitive$1.span,
2536
+ {
2537
+ "data-state": getState$1(context.state),
2538
+ "data-disabled": context.disabled ? "" : void 0,
2539
+ ...indicatorProps,
2540
+ ref: forwardedRef,
2541
+ style: { pointerEvents: "none", ...props.style }
2542
+ }
2543
+ ) });
2544
+ }
2545
+ );
2546
+ CheckboxIndicator.displayName = INDICATOR_NAME;
2547
+ var BubbleInput = (props) => {
2548
+ const { control, checked, bubbles = true, defaultChecked, ...inputProps } = props;
2549
+ const ref = reactExports.useRef(null);
2550
+ const prevChecked = usePrevious(checked);
2551
+ const controlSize = useSize(control);
2552
+ reactExports.useEffect(() => {
2553
+ const input = ref.current;
2554
+ const inputProto = window.HTMLInputElement.prototype;
2555
+ const descriptor = Object.getOwnPropertyDescriptor(inputProto, "checked");
2556
+ const setChecked = descriptor.set;
2557
+ if (prevChecked !== checked && setChecked) {
2558
+ const event = new Event("click", { bubbles });
2559
+ input.indeterminate = isIndeterminate(checked);
2560
+ setChecked.call(input, isIndeterminate(checked) ? false : checked);
2561
+ input.dispatchEvent(event);
2562
+ }
2563
+ }, [prevChecked, checked, bubbles]);
2564
+ const defaultCheckedRef = reactExports.useRef(isIndeterminate(checked) ? false : checked);
2565
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2566
+ "input",
2567
+ {
2568
+ type: "checkbox",
2569
+ "aria-hidden": true,
2570
+ defaultChecked: defaultChecked ?? defaultCheckedRef.current,
2571
+ ...inputProps,
2572
+ tabIndex: -1,
2573
+ ref,
2574
+ style: {
2575
+ ...props.style,
2576
+ ...controlSize,
2577
+ position: "absolute",
2578
+ pointerEvents: "none",
2579
+ opacity: 0,
2580
+ margin: 0
2581
+ }
2582
+ }
2583
+ );
2584
+ };
2585
+ function isIndeterminate(checked) {
2586
+ return checked === "indeterminate";
2587
+ }
2588
+ function getState$1(checked) {
2589
+ return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
2590
+ }
2591
+ var Root$1 = Checkbox$1;
2592
+ var Indicator = CheckboxIndicator;
2593
+ const Checkbox = reactExports.forwardRef(({ className, checked, indeterminate, onCheckedChange, ...props }, ref) => {
2594
+ const id = reactExports.useId();
2595
+ const checkboxId = props.id ?? id;
2596
+ const checkedState = indeterminate ? "indeterminate" : checked ?? false;
2597
+ return (
2598
+ // Label provides the click grace area and proper a11y association
2599
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
2600
+ "label",
2601
+ {
2602
+ htmlFor: checkboxId,
2603
+ className: "p-2 -m-2 inline-flex items-center justify-center cursor-pointer",
2604
+ onClick: (e) => e.stopPropagation(),
2605
+ onKeyDown: (e) => e.stopPropagation(),
2606
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2607
+ Root$1,
2608
+ {
2609
+ ref,
2610
+ id: checkboxId,
2611
+ checked: checkedState,
2612
+ onCheckedChange: (state) => {
2613
+ onCheckedChange == null ? void 0 : onCheckedChange(state === true);
2614
+ },
2615
+ className: cn(
2616
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow",
2617
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2618
+ "disabled:cursor-not-allowed disabled:opacity-50",
2619
+ "data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
2620
+ "data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
2621
+ className
2622
+ ),
2623
+ ...props,
2624
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Indicator, { className: "flex items-center justify-center text-current", children: indeterminate ? /* @__PURE__ */ jsxRuntimeExports.jsx(Minus, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "h-3.5 w-3.5" }) })
2625
+ }
2626
+ )
2627
+ }
2628
+ )
2629
+ );
2630
+ });
2631
+ Checkbox.displayName = "Checkbox";
2632
+ function RunActionsDropdownContentInner({
2633
+ env,
2634
+ runId,
2635
+ runStatus,
2636
+ onSuccess
2637
+ }) {
2638
+ const [events, setEvents] = reactExports.useState(void 0);
2639
+ const [isLoading, setIsLoading] = reactExports.useState(true);
2640
+ const [run, setRun] = reactExports.useState(void 0);
2641
+ const status = (run == null ? void 0 : run.status) || runStatus;
2642
+ reactExports.useEffect(() => {
2643
+ setIsLoading(true);
2644
+ Promise.all([
2645
+ fetchRun(env, runId, "none"),
2646
+ fetchEvents(env, runId, { limit: 1e3, sortOrder: "desc" })
2647
+ ]).then(([runResult, eventsResult]) => {
2648
+ if (runResult.success) {
2649
+ setRun(runResult.data);
2650
+ }
2651
+ if (eventsResult.success) {
2652
+ setEvents(eventsResult.data.data);
2653
+ }
2654
+ }).catch((err) => {
2655
+ console.error("Failed to fetch run or events:", err);
2656
+ }).finally(() => {
2657
+ setIsLoading(false);
2658
+ });
2659
+ }, [env, runId]);
2660
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2661
+ RunActionsDropdownItems,
2662
+ {
2663
+ env,
2664
+ runId,
2665
+ runStatus: status,
2666
+ events,
2667
+ eventsLoading: isLoading,
2668
+ stopPropagation: true,
2669
+ callbacks: { onSuccess }
2670
+ }
2671
+ );
2672
+ }
2673
+ function LazyDropdownMenu({
2674
+ env,
2675
+ runId,
2676
+ runStatus,
2677
+ onSuccess
2678
+ }) {
2679
+ const [isOpen, setIsOpen] = reactExports.useState(false);
2680
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
2681
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2682
+ Button,
2683
+ {
2684
+ variant: "ghost",
2685
+ size: "icon",
2686
+ className: "h-8 w-8",
2687
+ onClick: (e) => e.stopPropagation(),
2688
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Ellipsis, { className: "h-4 w-4" })
2689
+ }
2690
+ ) }),
2691
+ isOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2692
+ RunActionsDropdownContentInner,
2693
+ {
2694
+ env,
2695
+ runId,
2696
+ runStatus,
2697
+ onSuccess
2698
+ }
2699
+ ) })
2700
+ ] });
2701
+ }
2702
+ const statusMap = {
2703
+ pending: { label: "Pending", color: "bg-neutral-600 dark:bg-neutral-400" },
2704
+ running: { label: "Running", color: "bg-blue-600 dark:bg-blue-400" },
2705
+ completed: { label: "Completed", color: "bg-green-600 dark:bg-green-400" },
2706
+ failed: { label: "Failed", color: "bg-red-600 dark:bg-red-400" },
2707
+ cancelled: { label: "Cancelled", color: "bg-gray-600 dark:bg-gray-400" }
2708
+ };
2709
+ function useWorkflowFilter() {
2710
+ const navigate = useNavigate();
2711
+ const { pathname } = useLocation();
2712
+ const [searchParams] = useSearchParams();
2713
+ return reactExports.useCallback(
2714
+ (value) => {
2715
+ const params = new URLSearchParams(searchParams.toString());
2716
+ if (value === "all") {
2717
+ params.delete("workflow");
2718
+ params.delete("status");
2719
+ } else {
2720
+ params.set("workflow", value);
2721
+ }
2722
+ navigate(`${pathname}?${params.toString()}`);
2723
+ },
2724
+ [navigate, pathname, searchParams]
2725
+ );
2726
+ }
2727
+ function useStatusFilter() {
2728
+ const navigate = useNavigate();
2729
+ const { pathname } = useLocation();
2730
+ const [searchParams] = useSearchParams();
2731
+ return reactExports.useCallback(
2732
+ (value) => {
2733
+ const params = new URLSearchParams(searchParams.toString());
2734
+ if (value === "all") {
2735
+ params.delete("status");
2736
+ } else {
2737
+ params.set("status", value);
2738
+ }
2739
+ navigate(`${pathname}?${params.toString()}`);
2740
+ },
2741
+ [navigate, pathname, searchParams]
2742
+ );
2743
+ }
2744
+ function FilterControls({
2745
+ workflowNameFilter,
2746
+ status,
2747
+ seenWorkflowNames,
2748
+ sortOrder,
2749
+ loading,
2750
+ statusFilterRequiresWorkflowNameFilter,
2751
+ onWorkflowChange,
2752
+ onStatusChange,
2753
+ onSortToggle,
2754
+ onRefresh,
2755
+ lastRefreshTime
2756
+ }) {
2757
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
2758
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end gap-2", children: [
2759
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "Last refreshed" }),
2760
+ lastRefreshTime && /* @__PURE__ */ jsxRuntimeExports.jsx(
2761
+ RelativeTime,
2762
+ {
2763
+ date: lastRefreshTime,
2764
+ className: "text-sm text-muted-foreground",
2765
+ type: "distance"
2766
+ }
2767
+ )
2768
+ ] }),
2769
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
2770
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2771
+ Select,
2772
+ {
2773
+ value: workflowNameFilter ?? "all",
2774
+ onValueChange: onWorkflowChange,
2775
+ disabled: loading,
2776
+ children: [
2777
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[180px] h-9", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Filter by workflow" }) }),
2778
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
2779
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "all", children: "All Workflows" }),
2780
+ Array.from(seenWorkflowNames).sort().map((name) => {
2781
+ var _a;
2782
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: name, children: ((_a = parseWorkflowName(name)) == null ? void 0 : _a.shortName) || name }, name);
2783
+ })
2784
+ ] })
2785
+ ]
2786
+ }
2787
+ ),
2788
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2789
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2790
+ Select,
2791
+ {
2792
+ value: status || "all",
2793
+ onValueChange: onStatusChange,
2794
+ disabled: loading || statusFilterRequiresWorkflowNameFilter && !workflowNameFilter,
2795
+ children: [
2796
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[140px] h-9", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Filter by status" }) }),
2797
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
2798
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "all", children: "Any status" }),
2799
+ Object.entries(statusMap).map(
2800
+ ([status2, { label, color }]) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: status2, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center", children: [
2801
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
2802
+ "span",
2803
+ {
2804
+ className: `${color} size-1.5 rounded-full mr-2`
2805
+ }
2806
+ ),
2807
+ label
2808
+ ] }) }, status2)
2809
+ )
2810
+ ] })
2811
+ ]
2812
+ }
2813
+ ) }) }),
2814
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: statusFilterRequiresWorkflowNameFilter && workflowNameFilter === "all" ? "Select a workflow first to filter by status" : "Filter runs by status" })
2815
+ ] }),
2816
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2817
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2818
+ Button,
2819
+ {
2820
+ variant: "outline",
2821
+ size: "sm",
2822
+ onClick: onSortToggle,
2823
+ disabled: loading,
2824
+ children: [
2825
+ sortOrder === "desc" ? /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowDownAZ, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowUpAZ, { className: "h-4 w-4" }),
2826
+ sortOrder === "desc" ? "Newest" : "Oldest"
2827
+ ]
2828
+ }
2829
+ ) }),
2830
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: sortOrder === "desc" ? "Showing newest first" : "Showing oldest first" })
2831
+ ] }),
2832
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2833
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2834
+ Button,
2835
+ {
2836
+ variant: "outline",
2837
+ size: "sm",
2838
+ onClick: onRefresh,
2839
+ disabled: loading,
2840
+ children: [
2841
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: loading ? "animate-spin" : "" }),
2842
+ "Refresh"
2843
+ ]
2844
+ }
2845
+ ) }),
2846
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Note that this resets pages" })
2847
+ ] })
2848
+ ] })
2849
+ ] });
2850
+ }
2851
+ function RunsTable({ onRunClick }) {
2852
+ var _a, _b, _c, _d;
2853
+ const [searchParams] = useSearchParams();
2854
+ const handleWorkflowFilter = useWorkflowFilter();
2855
+ const handleStatusFilter = useStatusFilter();
2856
+ const { serverConfig } = useServerConfig();
2857
+ const rawStatus = searchParams.get("status");
2858
+ const validStatuses = Object.keys(statusMap);
2859
+ const status = rawStatus === "all" || rawStatus && validStatuses.includes(rawStatus) ? rawStatus : void 0;
2860
+ const workflowNameFilter = searchParams.get("workflow");
2861
+ const [sortOrder, setSortOrder] = reactExports.useState("desc");
2862
+ const [lastRefreshTime, setLastRefreshTime] = reactExports.useState(
2863
+ () => /* @__PURE__ */ new Date()
2864
+ );
2865
+ const [hasLoadedOnce, setHasLoadedOnce] = reactExports.useState(false);
2866
+ const env = reactExports.useMemo(() => ({}), []);
2867
+ const isLocal = serverConfig.backendId === "local" || serverConfig.backendId === "@workflow/world-local";
2868
+ const localDataDirPath = (_a = serverConfig.displayInfo) == null ? void 0 : _a["local.dataDirPath"];
2869
+ const localShortName = (_b = serverConfig.displayInfo) == null ? void 0 : _b["local.shortName"];
2870
+ const statusFilterRequiresWorkflowNameFilter = ((_c = serverConfig.backendId) == null ? void 0 : _c.includes("vercel")) || false;
2871
+ const [seenWorkflowNames, setSeenWorkflowNames] = reactExports.useState(
2872
+ /* @__PURE__ */ new Set()
2873
+ );
2874
+ const {
2875
+ data,
2876
+ error,
2877
+ nextPage,
2878
+ previousPage,
2879
+ hasNextPage,
2880
+ hasPreviousPage,
2881
+ reload,
2882
+ refresh,
2883
+ pageInfo
2884
+ } = useWorkflowRuns(env, {
2885
+ sortOrder,
2886
+ workflowName: workflowNameFilter === "all" ? void 0 : workflowNameFilter,
2887
+ status: status === "all" ? void 0 : status
2888
+ });
2889
+ const selection = useTableSelection({
2890
+ getItemId: (run) => run.runId
2891
+ });
2892
+ const runs = data.data ?? [];
2893
+ const [isBulkCancelling, setIsBulkCancelling] = reactExports.useState(false);
2894
+ const [isBulkReenqueuing, setIsBulkReenqueuing] = reactExports.useState(false);
2895
+ const isLocalAndHasMissingData = isLocal && (!localDataDirPath || !((_d = data == null ? void 0 : data.data) == null ? void 0 : _d.length));
2896
+ reactExports.useEffect(() => {
2897
+ if (data.data && data.data.length > 0) {
2898
+ const newNames = new Set(data.data.map((run) => run.workflowName));
2899
+ setSeenWorkflowNames((prev) => {
2900
+ const updated = new Set(prev);
2901
+ for (const name of newNames) {
2902
+ updated.add(name);
2903
+ }
2904
+ return updated;
2905
+ });
2906
+ }
2907
+ }, [data.data]);
2908
+ const loading = data.isLoading;
2909
+ reactExports.useEffect(() => {
2910
+ if (!loading && !hasLoadedOnce) {
2911
+ setHasLoadedOnce(true);
2912
+ }
2913
+ }, [loading, hasLoadedOnce]);
2914
+ reactExports.useEffect(() => {
2915
+ setHasLoadedOnce(false);
2916
+ }, [workflowNameFilter, status, sortOrder]);
2917
+ const onReload = reactExports.useCallback(() => {
2918
+ setLastRefreshTime(() => /* @__PURE__ */ new Date());
2919
+ setHasLoadedOnce(false);
2920
+ reload();
2921
+ }, [reload]);
2922
+ const onRefresh = reactExports.useCallback(() => {
2923
+ setLastRefreshTime(() => /* @__PURE__ */ new Date());
2924
+ refresh();
2925
+ }, [refresh]);
2926
+ const selectedRuns = reactExports.useMemo(() => {
2927
+ return runs.filter((run) => selection.selectedIds.has(run.runId));
2928
+ }, [runs, selection.selectedIds]);
2929
+ const cancellableSelectedRuns = reactExports.useMemo(() => {
2930
+ return selectedRuns.filter(
2931
+ (run) => run.status === "pending" || run.status === "running"
2932
+ );
2933
+ }, [selectedRuns]);
2934
+ const hasCancellableSelection = cancellableSelectedRuns.length > 0;
2935
+ const handleBulkCancel = reactExports.useCallback(async () => {
2936
+ if (isBulkCancelling || cancellableSelectedRuns.length === 0) return;
2937
+ setIsBulkCancelling(true);
2938
+ try {
2939
+ const results = await Promise.allSettled(
2940
+ cancellableSelectedRuns.map((run) => cancelRun(env, run.runId))
2941
+ );
2942
+ const succeeded = results.filter((r) => r.status === "fulfilled").length;
2943
+ const failed = results.filter((r) => r.status === "rejected").length;
2944
+ if (failed === 0) {
2945
+ toast.success(
2946
+ `Cancelled ${succeeded} run${succeeded !== 1 ? "s" : ""}`
2947
+ );
2948
+ } else if (succeeded === 0) {
2949
+ toast.error(`Failed to cancel ${failed} run${failed !== 1 ? "s" : ""}`);
2950
+ } else {
2951
+ toast.warning(
2952
+ `Cancelled ${succeeded} run${succeeded !== 1 ? "s" : ""}, ${failed} failed`
2953
+ );
2954
+ }
2955
+ selection.clearSelection();
2956
+ onReload();
2957
+ } catch (err) {
2958
+ toast.error("Failed to cancel runs", {
2959
+ description: err instanceof Error ? err.message : "Unknown error"
2960
+ });
2961
+ } finally {
2962
+ setIsBulkCancelling(false);
2963
+ }
2964
+ }, [env, cancellableSelectedRuns, isBulkCancelling, selection, onReload]);
2965
+ const handleBulkReenqueue = reactExports.useCallback(async () => {
2966
+ if (isBulkReenqueuing || selectedRuns.length === 0) return;
2967
+ setIsBulkReenqueuing(true);
2968
+ try {
2969
+ const results = await Promise.allSettled(
2970
+ selectedRuns.map((run) => reenqueueRun(env, run.runId))
2971
+ );
2972
+ const succeeded = results.filter((r) => r.status === "fulfilled").length;
2973
+ const failed = results.filter((r) => r.status === "rejected").length;
2974
+ if (failed === 0) {
2975
+ toast.success(
2976
+ `Re-enqueued ${succeeded} run${succeeded !== 1 ? "s" : ""}`
2977
+ );
2978
+ } else if (succeeded === 0) {
2979
+ toast.error(
2980
+ `Failed to re-enqueue ${failed} run${failed !== 1 ? "s" : ""}`
2981
+ );
2982
+ } else {
2983
+ toast.warning(
2984
+ `Re-enqueued ${succeeded} run${succeeded !== 1 ? "s" : ""}, ${failed} failed`
2985
+ );
2986
+ }
2987
+ selection.clearSelection();
2988
+ onReload();
2989
+ } catch (err) {
2990
+ toast.error("Failed to re-enqueue runs", {
2991
+ description: err instanceof Error ? err.message : "Unknown error"
2992
+ });
2993
+ } finally {
2994
+ setIsBulkReenqueuing(false);
2995
+ }
2996
+ }, [env, selectedRuns, isBulkReenqueuing, selection, onReload]);
2997
+ const toggleSortOrder = () => {
2998
+ setSortOrder((prev) => prev === "desc" ? "asc" : "desc");
2999
+ };
3000
+ reactExports.useEffect(() => {
3001
+ if (isLocalAndHasMissingData) {
3002
+ const interval = setInterval(() => {
3003
+ onRefresh();
3004
+ }, 5e3);
3005
+ return () => clearInterval(interval);
3006
+ }
3007
+ }, [isLocalAndHasMissingData, onRefresh]);
3008
+ reactExports.useEffect(() => {
3009
+ const handleVisibilityChange = () => {
3010
+ if (document.visibilityState === "visible" && lastRefreshTime) {
3011
+ const timeSinceLastRefresh = Date.now() - lastRefreshTime.getTime();
3012
+ if (timeSinceLastRefresh >= 1e4) {
3013
+ onReload();
3014
+ }
3015
+ }
3016
+ };
3017
+ document.addEventListener("visibilitychange", handleVisibilityChange);
3018
+ return () => {
3019
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
3020
+ };
3021
+ }, [lastRefreshTime, onReload]);
3022
+ const localDirText = /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: localShortName || "current directory" });
3023
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3024
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3025
+ FilterControls,
3026
+ {
3027
+ workflowNameFilter,
3028
+ status,
3029
+ seenWorkflowNames,
3030
+ sortOrder,
3031
+ loading,
3032
+ statusFilterRequiresWorkflowNameFilter,
3033
+ onWorkflowChange: handleWorkflowFilter,
3034
+ onStatusChange: handleStatusFilter,
3035
+ onSortToggle: toggleSortOrder,
3036
+ onRefresh: onReload,
3037
+ lastRefreshTime
3038
+ }
3039
+ ),
3040
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden mt-4 bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-0 max-h-[calc(100vh-280px)] overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Table, { children: [
3041
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(TableRow, { children: [
3042
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3043
+ Checkbox,
3044
+ {
3045
+ checked: selection.isAllSelected(runs),
3046
+ indeterminate: selection.isSomeSelected(runs),
3047
+ onCheckedChange: () => selection.toggleSelectAll(runs),
3048
+ "aria-label": "Select all runs",
3049
+ disabled: !runs.length
3050
+ }
3051
+ ) }),
3052
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Workflow" }),
3053
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Run ID" }),
3054
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Status" }),
3055
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Started" }),
3056
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Completed" }),
3057
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10" })
3058
+ ] }) }),
3059
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableBody, { children: error ? /* @__PURE__ */ jsxRuntimeExports.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { colSpan: 7, className: "h-[400px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", className: "max-w-md", children: [
3060
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
3061
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error loading runs" }),
3062
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
3063
+ ] }) }) }) }) : loading && !hasLoadedOnce ? /* @__PURE__ */ jsxRuntimeExports.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { colSpan: 7, className: "h-[400px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-8 w-8 animate-spin text-muted-foreground" }) }) }) }) : !data.data || data.data.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { colSpan: 7, className: "h-[400px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-center text-muted-foreground flex flex-col items-center justify-center gap-3 h-full", children: [
3064
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm", children: [
3065
+ "No workflow runs found",
3066
+ isLocalAndHasMissingData ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3067
+ " in ",
3068
+ localDirText
3069
+ ] }) : "",
3070
+ "."
3071
+ ] }),
3072
+ isLocalAndHasMissingData && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm flex items-center gap-2", children: "This view will update once you run a workflow." })
3073
+ ] }) }) }) : runs.map((run) => {
3074
+ var _a2;
3075
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
3076
+ TableRow,
3077
+ {
3078
+ className: "cursor-pointer group relative",
3079
+ onClick: () => onRunClick(run.runId),
3080
+ "data-selected": selection.isSelected(run),
3081
+ children: [
3082
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3083
+ Checkbox,
3084
+ {
3085
+ checked: selection.isSelected(run),
3086
+ onCheckedChange: () => selection.toggleSelection(run),
3087
+ "aria-label": `Select run ${run.runId}`
3088
+ }
3089
+ ) }),
3090
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: run.workflowName, overlay: true, children: ((_a2 = parseWorkflowName(run.workflowName)) == null ? void 0 : _a2.shortName) || "?" }) }),
3091
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: run.runId, overlay: true, children: run.runId }) }),
3092
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3093
+ StatusBadge,
3094
+ {
3095
+ status: run.status,
3096
+ context: run,
3097
+ durationMs: run.startedAt ? (run.completedAt ? new Date(run.completedAt).getTime() : Date.now()) - new Date(run.startedAt).getTime() : void 0
3098
+ }
3099
+ ) }),
3100
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: run.startedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.startedAt }) : "-" }),
3101
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: run.completedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.completedAt }) : "-" }),
3102
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3103
+ LazyDropdownMenu,
3104
+ {
3105
+ env,
3106
+ runId: run.runId,
3107
+ runStatus: run.status,
3108
+ onSuccess: onReload
3109
+ }
3110
+ ) })
3111
+ ]
3112
+ },
3113
+ run.runId
3114
+ );
3115
+ }) })
3116
+ ] }) }) }),
3117
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mt-4", children: [
3118
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-muted-foreground", children: pageInfo }),
3119
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 items-center", children: [
3120
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
3121
+ Button,
3122
+ {
3123
+ variant: "outline",
3124
+ size: "sm",
3125
+ onClick: previousPage,
3126
+ disabled: !hasPreviousPage,
3127
+ children: [
3128
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, {}),
3129
+ "Previous"
3130
+ ]
3131
+ }
3132
+ ),
3133
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
3134
+ Button,
3135
+ {
3136
+ variant: "outline",
3137
+ size: "sm",
3138
+ onClick: nextPage,
3139
+ disabled: !hasNextPage,
3140
+ children: [
3141
+ "Next",
3142
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, {})
3143
+ ]
3144
+ }
3145
+ )
3146
+ ] })
3147
+ ] }),
3148
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3149
+ SelectionBar,
3150
+ {
3151
+ selectionCount: selection.selectionCount,
3152
+ onClearSelection: selection.clearSelection,
3153
+ itemLabel: "runs",
3154
+ actions: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3155
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3156
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
3157
+ Button,
3158
+ {
3159
+ variant: "ghost",
3160
+ size: "sm",
3161
+ className: "h-7 text-primary-foreground hover:bg-primary-foreground/10 hover:text-primary-foreground",
3162
+ onClick: handleBulkReenqueue,
3163
+ disabled: isBulkReenqueuing || selectedRuns.length === 0,
3164
+ children: [
3165
+ isBulkReenqueuing ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-4 w-4 mr-1 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "h-4 w-4 mr-1" }),
3166
+ isBulkReenqueuing ? "Re-enqueuing..." : "Re-enqueue"
3167
+ ]
3168
+ }
3169
+ ) }),
3170
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-enqueue the workflow orchestration layer for selected runs. Useful if workflows appear stuck." })
3171
+ ] }),
3172
+ hasCancellableSelection && /* @__PURE__ */ jsxRuntimeExports.jsxs(
3173
+ Button,
3174
+ {
3175
+ variant: "ghost",
3176
+ size: "sm",
3177
+ className: "h-7 text-primary-foreground hover:bg-primary-foreground/10 hover:text-primary-foreground",
3178
+ onClick: handleBulkCancel,
3179
+ disabled: isBulkCancelling,
3180
+ children: [
3181
+ isBulkCancelling ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-4 w-4 mr-1 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "h-4 w-4 mr-1" }),
3182
+ "Cancel",
3183
+ " ",
3184
+ cancellableSelectedRuns.length !== selection.selectionCount ? `${cancellableSelectedRuns.length} ` : "",
3185
+ isBulkCancelling ? "cancelling..." : ""
3186
+ ]
3187
+ }
3188
+ )
3189
+ ] })
3190
+ }
3191
+ )
3192
+ ] });
3193
+ }
3194
+ const badgeVariants = cva(
3195
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
3196
+ {
3197
+ variants: {
3198
+ variant: {
3199
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
3200
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
3201
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
3202
+ outline: "text-foreground"
3203
+ }
3204
+ },
3205
+ defaultVariants: {
3206
+ variant: "default"
3207
+ }
3208
+ }
3209
+ );
3210
+ function Badge({ className, variant, ...props }) {
3211
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
3212
+ }
3213
+ var DIALOG_NAME = "Dialog";
3214
+ var [createDialogContext] = createContextScope(DIALOG_NAME);
3215
+ var [DialogProvider, useDialogContext] = createDialogContext(DIALOG_NAME);
3216
+ var Dialog = (props) => {
3217
+ const {
3218
+ __scopeDialog,
3219
+ children,
3220
+ open: openProp,
3221
+ defaultOpen,
3222
+ onOpenChange,
3223
+ modal = true
3224
+ } = props;
3225
+ const triggerRef = reactExports.useRef(null);
3226
+ const contentRef = reactExports.useRef(null);
3227
+ const [open, setOpen] = useControllableState({
3228
+ prop: openProp,
3229
+ defaultProp: defaultOpen ?? false,
3230
+ onChange: onOpenChange,
3231
+ caller: DIALOG_NAME
3232
+ });
3233
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3234
+ DialogProvider,
3235
+ {
3236
+ scope: __scopeDialog,
3237
+ triggerRef,
3238
+ contentRef,
3239
+ contentId: useId(),
3240
+ titleId: useId(),
3241
+ descriptionId: useId(),
3242
+ open,
3243
+ onOpenChange: setOpen,
3244
+ onOpenToggle: reactExports.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
3245
+ modal,
3246
+ children
3247
+ }
3248
+ );
3249
+ };
3250
+ Dialog.displayName = DIALOG_NAME;
3251
+ var TRIGGER_NAME = "DialogTrigger";
3252
+ var DialogTrigger = reactExports.forwardRef(
3253
+ (props, forwardedRef) => {
3254
+ const { __scopeDialog, ...triggerProps } = props;
3255
+ const context = useDialogContext(TRIGGER_NAME, __scopeDialog);
3256
+ const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);
3257
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3258
+ Primitive.button,
3259
+ {
3260
+ type: "button",
3261
+ "aria-haspopup": "dialog",
3262
+ "aria-expanded": context.open,
3263
+ "aria-controls": context.contentId,
3264
+ "data-state": getState(context.open),
3265
+ ...triggerProps,
3266
+ ref: composedTriggerRef,
3267
+ onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
3268
+ }
3269
+ );
3270
+ }
3271
+ );
3272
+ DialogTrigger.displayName = TRIGGER_NAME;
3273
+ var PORTAL_NAME = "DialogPortal";
3274
+ var [PortalProvider, usePortalContext] = createDialogContext(PORTAL_NAME, {
3275
+ forceMount: void 0
3276
+ });
3277
+ var DialogPortal = (props) => {
3278
+ const { __scopeDialog, forceMount, children, container } = props;
3279
+ const context = useDialogContext(PORTAL_NAME, __scopeDialog);
3280
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(PortalProvider, { scope: __scopeDialog, forceMount, children: reactExports.Children.map(children, (child) => /* @__PURE__ */ jsxRuntimeExports.jsx(Presence$1, { present: forceMount || context.open, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { asChild: true, container, children: child }) })) });
3281
+ };
3282
+ DialogPortal.displayName = PORTAL_NAME;
3283
+ var OVERLAY_NAME = "DialogOverlay";
3284
+ var DialogOverlay = reactExports.forwardRef(
3285
+ (props, forwardedRef) => {
3286
+ const portalContext = usePortalContext(OVERLAY_NAME, props.__scopeDialog);
3287
+ const { forceMount = portalContext.forceMount, ...overlayProps } = props;
3288
+ const context = useDialogContext(OVERLAY_NAME, props.__scopeDialog);
3289
+ return context.modal ? /* @__PURE__ */ jsxRuntimeExports.jsx(Presence$1, { present: forceMount || context.open, children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogOverlayImpl, { ...overlayProps, ref: forwardedRef }) }) : null;
3290
+ }
3291
+ );
3292
+ DialogOverlay.displayName = OVERLAY_NAME;
3293
+ var Slot = createSlot("DialogOverlay.RemoveScroll");
3294
+ var DialogOverlayImpl = reactExports.forwardRef(
3295
+ (props, forwardedRef) => {
3296
+ const { __scopeDialog, ...overlayProps } = props;
3297
+ const context = useDialogContext(OVERLAY_NAME, __scopeDialog);
3298
+ return (
3299
+ // Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`
3300
+ // ie. when `Overlay` and `Content` are siblings
3301
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ReactRemoveScroll, { as: Slot, allowPinchZoom: true, shards: [context.contentRef], children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3302
+ Primitive.div,
3303
+ {
3304
+ "data-state": getState(context.open),
3305
+ ...overlayProps,
3306
+ ref: forwardedRef,
3307
+ style: { pointerEvents: "auto", ...overlayProps.style }
3308
+ }
3309
+ ) })
3310
+ );
3311
+ }
3312
+ );
3313
+ var CONTENT_NAME = "DialogContent";
3314
+ var DialogContent = reactExports.forwardRef(
3315
+ (props, forwardedRef) => {
3316
+ const portalContext = usePortalContext(CONTENT_NAME, props.__scopeDialog);
3317
+ const { forceMount = portalContext.forceMount, ...contentProps } = props;
3318
+ const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
3319
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Presence$1, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsxRuntimeExports.jsx(DialogContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsxRuntimeExports.jsx(DialogContentNonModal, { ...contentProps, ref: forwardedRef }) });
3320
+ }
3321
+ );
3322
+ DialogContent.displayName = CONTENT_NAME;
3323
+ var DialogContentModal = reactExports.forwardRef(
3324
+ (props, forwardedRef) => {
3325
+ const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
3326
+ const contentRef = reactExports.useRef(null);
3327
+ const composedRefs = useComposedRefs(forwardedRef, context.contentRef, contentRef);
3328
+ reactExports.useEffect(() => {
3329
+ const content = contentRef.current;
3330
+ if (content) return hideOthers(content);
3331
+ }, []);
3332
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3333
+ DialogContentImpl,
3334
+ {
3335
+ ...props,
3336
+ ref: composedRefs,
3337
+ trapFocus: context.open,
3338
+ disableOutsidePointerEvents: true,
3339
+ onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {
3340
+ var _a;
3341
+ event.preventDefault();
3342
+ (_a = context.triggerRef.current) == null ? void 0 : _a.focus();
3343
+ }),
3344
+ onPointerDownOutside: composeEventHandlers(props.onPointerDownOutside, (event) => {
3345
+ const originalEvent = event.detail.originalEvent;
3346
+ const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
3347
+ const isRightClick = originalEvent.button === 2 || ctrlLeftClick;
3348
+ if (isRightClick) event.preventDefault();
3349
+ }),
3350
+ onFocusOutside: composeEventHandlers(
3351
+ props.onFocusOutside,
3352
+ (event) => event.preventDefault()
3353
+ )
3354
+ }
3355
+ );
3356
+ }
3357
+ );
3358
+ var DialogContentNonModal = reactExports.forwardRef(
3359
+ (props, forwardedRef) => {
3360
+ const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
3361
+ const hasInteractedOutsideRef = reactExports.useRef(false);
3362
+ const hasPointerDownOutsideRef = reactExports.useRef(false);
3363
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3364
+ DialogContentImpl,
3365
+ {
3366
+ ...props,
3367
+ ref: forwardedRef,
3368
+ trapFocus: false,
3369
+ disableOutsidePointerEvents: false,
3370
+ onCloseAutoFocus: (event) => {
3371
+ var _a, _b;
3372
+ (_a = props.onCloseAutoFocus) == null ? void 0 : _a.call(props, event);
3373
+ if (!event.defaultPrevented) {
3374
+ if (!hasInteractedOutsideRef.current) (_b = context.triggerRef.current) == null ? void 0 : _b.focus();
3375
+ event.preventDefault();
3376
+ }
3377
+ hasInteractedOutsideRef.current = false;
3378
+ hasPointerDownOutsideRef.current = false;
3379
+ },
3380
+ onInteractOutside: (event) => {
3381
+ var _a, _b;
3382
+ (_a = props.onInteractOutside) == null ? void 0 : _a.call(props, event);
3383
+ if (!event.defaultPrevented) {
3384
+ hasInteractedOutsideRef.current = true;
3385
+ if (event.detail.originalEvent.type === "pointerdown") {
3386
+ hasPointerDownOutsideRef.current = true;
3387
+ }
3388
+ }
3389
+ const target = event.target;
3390
+ const targetIsTrigger = (_b = context.triggerRef.current) == null ? void 0 : _b.contains(target);
3391
+ if (targetIsTrigger) event.preventDefault();
3392
+ if (event.detail.originalEvent.type === "focusin" && hasPointerDownOutsideRef.current) {
3393
+ event.preventDefault();
3394
+ }
3395
+ }
3396
+ }
3397
+ );
3398
+ }
3399
+ );
3400
+ var DialogContentImpl = reactExports.forwardRef(
3401
+ (props, forwardedRef) => {
3402
+ const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;
3403
+ const context = useDialogContext(CONTENT_NAME, __scopeDialog);
3404
+ const contentRef = reactExports.useRef(null);
3405
+ const composedRefs = useComposedRefs(forwardedRef, contentRef);
3406
+ useFocusGuards();
3407
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3408
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3409
+ FocusScope,
3410
+ {
3411
+ asChild: true,
3412
+ loop: true,
3413
+ trapped: trapFocus,
3414
+ onMountAutoFocus: onOpenAutoFocus,
3415
+ onUnmountAutoFocus: onCloseAutoFocus,
3416
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3417
+ DismissableLayer,
3418
+ {
3419
+ role: "dialog",
3420
+ id: context.contentId,
3421
+ "aria-describedby": context.descriptionId,
3422
+ "aria-labelledby": context.titleId,
3423
+ "data-state": getState(context.open),
3424
+ ...contentProps,
3425
+ ref: composedRefs,
3426
+ onDismiss: () => context.onOpenChange(false)
3427
+ }
3428
+ )
3429
+ }
3430
+ ),
3431
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3432
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleWarning, { titleId: context.titleId }),
3433
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DescriptionWarning, { contentRef, descriptionId: context.descriptionId })
3434
+ ] })
3435
+ ] });
3436
+ }
3437
+ );
3438
+ var TITLE_NAME = "DialogTitle";
3439
+ var DialogTitle = reactExports.forwardRef(
3440
+ (props, forwardedRef) => {
3441
+ const { __scopeDialog, ...titleProps } = props;
3442
+ const context = useDialogContext(TITLE_NAME, __scopeDialog);
3443
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.h2, { id: context.titleId, ...titleProps, ref: forwardedRef });
3444
+ }
3445
+ );
3446
+ DialogTitle.displayName = TITLE_NAME;
3447
+ var DESCRIPTION_NAME = "DialogDescription";
3448
+ var DialogDescription = reactExports.forwardRef(
3449
+ (props, forwardedRef) => {
3450
+ const { __scopeDialog, ...descriptionProps } = props;
3451
+ const context = useDialogContext(DESCRIPTION_NAME, __scopeDialog);
3452
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.p, { id: context.descriptionId, ...descriptionProps, ref: forwardedRef });
3453
+ }
3454
+ );
3455
+ DialogDescription.displayName = DESCRIPTION_NAME;
3456
+ var CLOSE_NAME = "DialogClose";
3457
+ var DialogClose = reactExports.forwardRef(
3458
+ (props, forwardedRef) => {
3459
+ const { __scopeDialog, ...closeProps } = props;
3460
+ const context = useDialogContext(CLOSE_NAME, __scopeDialog);
3461
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3462
+ Primitive.button,
3463
+ {
3464
+ type: "button",
3465
+ ...closeProps,
3466
+ ref: forwardedRef,
3467
+ onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))
3468
+ }
3469
+ );
3470
+ }
3471
+ );
3472
+ DialogClose.displayName = CLOSE_NAME;
3473
+ function getState(open) {
3474
+ return open ? "open" : "closed";
3475
+ }
3476
+ var TITLE_WARNING_NAME = "DialogTitleWarning";
3477
+ var [WarningProvider, useWarningContext] = createContext2(TITLE_WARNING_NAME, {
3478
+ contentName: CONTENT_NAME,
3479
+ titleName: TITLE_NAME,
3480
+ docsSlug: "dialog"
3481
+ });
3482
+ var TitleWarning = ({ titleId }) => {
3483
+ const titleWarningContext = useWarningContext(TITLE_WARNING_NAME);
3484
+ const MESSAGE = `\`${titleWarningContext.contentName}\` requires a \`${titleWarningContext.titleName}\` for the component to be accessible for screen reader users.
3485
+
3486
+ If you want to hide the \`${titleWarningContext.titleName}\`, you can wrap it with our VisuallyHidden component.
3487
+
3488
+ For more information, see https://radix-ui.com/primitives/docs/components/${titleWarningContext.docsSlug}`;
3489
+ reactExports.useEffect(() => {
3490
+ if (titleId) {
3491
+ const hasTitle = document.getElementById(titleId);
3492
+ if (!hasTitle) console.error(MESSAGE);
3493
+ }
3494
+ }, [MESSAGE, titleId]);
3495
+ return null;
3496
+ };
3497
+ var DESCRIPTION_WARNING_NAME = "DialogDescriptionWarning";
3498
+ var DescriptionWarning = ({ contentRef, descriptionId }) => {
3499
+ const descriptionWarningContext = useWarningContext(DESCRIPTION_WARNING_NAME);
3500
+ const MESSAGE = `Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${descriptionWarningContext.contentName}}.`;
3501
+ reactExports.useEffect(() => {
3502
+ var _a;
3503
+ const describedById = (_a = contentRef.current) == null ? void 0 : _a.getAttribute("aria-describedby");
3504
+ if (descriptionId && describedById) {
3505
+ const hasDescription = document.getElementById(descriptionId);
3506
+ if (!hasDescription) console.warn(MESSAGE);
3507
+ }
3508
+ }, [MESSAGE, contentRef, descriptionId]);
3509
+ return null;
3510
+ };
3511
+ var Root = Dialog;
3512
+ var Portal = DialogPortal;
3513
+ var Overlay = DialogOverlay;
3514
+ var Content = DialogContent;
3515
+ var Title = DialogTitle;
3516
+ var Description = DialogDescription;
3517
+ var Close = DialogClose;
3518
+ function Sheet({ ...props }) {
3519
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Root, { "data-slot": "sheet", ...props });
3520
+ }
3521
+ function SheetPortal({
3522
+ ...props
3523
+ }) {
3524
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal, { "data-slot": "sheet-portal", ...props });
3525
+ }
3526
+ function SheetOverlay({
3527
+ className,
3528
+ ...props
3529
+ }) {
3530
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3531
+ Overlay,
3532
+ {
3533
+ "data-slot": "sheet-overlay",
3534
+ className: cn(
3535
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
3536
+ className
3537
+ ),
3538
+ ...props
3539
+ }
3540
+ );
3541
+ }
3542
+ function SheetContent({
3543
+ className,
3544
+ children,
3545
+ side = "right",
3546
+ ...props
3547
+ }) {
3548
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(SheetPortal, { children: [
3549
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SheetOverlay, {}),
3550
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
3551
+ Content,
3552
+ {
3553
+ "data-slot": "sheet-content",
3554
+ onSubmit: (e) => e.preventDefault(),
3555
+ className: cn(
3556
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
3557
+ side === "right" && "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
3558
+ side === "left" && "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
3559
+ side === "top" && "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
3560
+ side === "bottom" && "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
3561
+ className
3562
+ ),
3563
+ ...props,
3564
+ children: [
3565
+ children,
3566
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none", children: [
3567
+ /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-4" }),
3568
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Close" })
3569
+ ] })
3570
+ ]
3571
+ }
3572
+ )
3573
+ ] });
3574
+ }
3575
+ function SheetHeader({ className, ...props }) {
3576
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3577
+ "div",
3578
+ {
3579
+ "data-slot": "sheet-header",
3580
+ className: cn("flex flex-col gap-1.5 p-4", className),
3581
+ ...props
3582
+ }
3583
+ );
3584
+ }
3585
+ function SheetTitle({
3586
+ className,
3587
+ ...props
3588
+ }) {
3589
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3590
+ Title,
3591
+ {
3592
+ "data-slot": "sheet-title",
3593
+ className: cn("text-foreground font-semibold", className),
3594
+ ...props
3595
+ }
3596
+ );
3597
+ }
3598
+ function SheetDescription({
3599
+ className,
3600
+ ...props
3601
+ }) {
3602
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3603
+ Description,
3604
+ {
3605
+ "data-slot": "sheet-description",
3606
+ className: cn("text-muted-foreground text-sm", className),
3607
+ ...props
3608
+ }
3609
+ );
3610
+ }
3611
+ const LAYOUT = {
3612
+ HORIZONTAL_SPACING: 280,
3613
+ VERTICAL_SPACING: 320,
3614
+ START_X: 250,
3615
+ START_Y: 50
3616
+ };
3617
+ function calculateNodePositions(rawNodes, edges) {
3618
+ if (rawNodes.length === 0) return [];
3619
+ const outgoing = /* @__PURE__ */ new Map();
3620
+ const incoming = /* @__PURE__ */ new Map();
3621
+ for (const edge of edges) {
3622
+ const out = outgoing.get(edge.source) || [];
3623
+ out.push(edge.target);
3624
+ outgoing.set(edge.source, out);
3625
+ const inc = incoming.get(edge.target) || [];
3626
+ inc.push(edge.source);
3627
+ incoming.set(edge.target, inc);
3628
+ }
3629
+ const startNode = rawNodes.find((n) => n.data.nodeKind === "workflow_start");
3630
+ if (!startNode) {
3631
+ return rawNodes.map((node, idx) => ({
3632
+ id: node.id,
3633
+ type: node.type,
3634
+ data: {
3635
+ label: node.data.label,
3636
+ nodeKind: node.data.nodeKind,
3637
+ stepId: node.data.stepId
3638
+ },
3639
+ metadata: node.metadata,
3640
+ position: {
3641
+ x: LAYOUT.START_X,
3642
+ y: LAYOUT.START_Y + idx * LAYOUT.VERTICAL_SPACING
3643
+ }
3644
+ }));
3645
+ }
3646
+ const layers = /* @__PURE__ */ new Map();
3647
+ const visited = /* @__PURE__ */ new Set();
3648
+ const queue = [startNode.id];
3649
+ layers.set(startNode.id, 0);
3650
+ while (queue.length > 0) {
3651
+ const nodeId = queue.shift();
3652
+ if (visited.has(nodeId)) continue;
3653
+ visited.add(nodeId);
3654
+ const currentLayer = layers.get(nodeId);
3655
+ const targets = outgoing.get(nodeId) || [];
3656
+ for (const target of targets) {
3657
+ if (target === nodeId || visited.has(target)) continue;
3658
+ if (!layers.has(target)) {
3659
+ layers.set(target, currentLayer + 1);
3660
+ queue.push(target);
3661
+ } else {
3662
+ const existingLayer = layers.get(target);
3663
+ if (currentLayer + 1 > existingLayer) {
3664
+ layers.set(target, currentLayer + 1);
3665
+ if (!queue.includes(target)) {
3666
+ queue.push(target);
3667
+ }
3668
+ }
3669
+ }
3670
+ }
3671
+ }
3672
+ let maxLayer = Math.max(...Array.from(layers.values()), 0);
3673
+ for (const node of rawNodes) {
3674
+ if (!layers.has(node.id)) {
3675
+ maxLayer++;
3676
+ layers.set(node.id, maxLayer);
3677
+ }
3678
+ }
3679
+ const nodesByLayer = /* @__PURE__ */ new Map();
3680
+ for (const node of rawNodes) {
3681
+ const layer = layers.get(node.id) ?? 0;
3682
+ const layerNodes = nodesByLayer.get(layer) || [];
3683
+ layerNodes.push(node);
3684
+ nodesByLayer.set(layer, layerNodes);
3685
+ }
3686
+ const positioned = [];
3687
+ for (const node of rawNodes) {
3688
+ const layer = layers.get(node.id) ?? 0;
3689
+ const layerNodes = nodesByLayer.get(layer) || [node];
3690
+ const indexInLayer = layerNodes.findIndex((n) => n.id === node.id);
3691
+ const layerWidth = layerNodes.length;
3692
+ const totalWidth = (layerWidth - 1) * LAYOUT.HORIZONTAL_SPACING;
3693
+ const startX = LAYOUT.START_X - totalWidth / 2;
3694
+ positioned.push({
3695
+ id: node.id,
3696
+ type: node.type,
3697
+ data: {
3698
+ label: node.data.label,
3699
+ nodeKind: node.data.nodeKind,
3700
+ stepId: node.data.stepId
3701
+ },
3702
+ metadata: node.metadata,
3703
+ position: {
3704
+ x: startX + indexInLayer * LAYOUT.HORIZONTAL_SPACING,
3705
+ y: LAYOUT.START_Y + layer * LAYOUT.VERTICAL_SPACING
3706
+ }
3707
+ });
3708
+ }
3709
+ return positioned;
3710
+ }
3711
+ function adaptManifest(raw) {
3712
+ const workflows = {};
3713
+ console.log("[adaptManifest] Raw manifest version:", raw == null ? void 0 : raw.version);
3714
+ console.log(
3715
+ "[adaptManifest] Raw workflows keys:",
3716
+ Object.keys((raw == null ? void 0 : raw.workflows) || {})
3717
+ );
3718
+ if (!(raw == null ? void 0 : raw.workflows)) {
3719
+ console.log("[adaptManifest] No workflows in manifest, returning empty");
3720
+ return { version: (raw == null ? void 0 : raw.version) || "1.0.0", workflows: {} };
3721
+ }
3722
+ for (const [filePath, workflowsInFile] of Object.entries(raw.workflows)) {
3723
+ for (const [workflowName, entry] of Object.entries(workflowsInFile)) {
3724
+ const positionedNodes = calculateNodePositions(
3725
+ entry.graph.nodes,
3726
+ entry.graph.edges
3727
+ );
3728
+ const workflowGraph = {
3729
+ workflowId: entry.workflowId,
3730
+ workflowName,
3731
+ filePath,
3732
+ nodes: positionedNodes,
3733
+ edges: entry.graph.edges
3734
+ };
3735
+ workflows[entry.workflowId] = workflowGraph;
3736
+ }
3737
+ }
3738
+ console.log(
3739
+ "[adaptManifest] Adapted workflows count:",
3740
+ Object.keys(workflows).length
3741
+ );
3742
+ return {
3743
+ version: raw.version,
3744
+ workflows
3745
+ };
3746
+ }
3747
+ function useWorkflowGraphManifest() {
3748
+ const [manifest, setManifest] = reactExports.useState(null);
3749
+ const [loading, setLoading] = reactExports.useState(true);
3750
+ const [error, setError] = reactExports.useState(null);
3751
+ const isFetchingRef = reactExports.useRef(false);
3752
+ const env = reactExports.useMemo(() => ({}), []);
3753
+ const fetchManifest = reactExports.useCallback(async () => {
3754
+ if (isFetchingRef.current) {
3755
+ return;
3756
+ }
3757
+ isFetchingRef.current = true;
3758
+ setLoading(true);
3759
+ setError(null);
3760
+ try {
3761
+ console.log("[useWorkflowGraphManifest] Fetching with env:", env);
3762
+ const { result: rawManifest, error: error2 } = await unwrapServerActionResult(
3763
+ fetchWorkflowsManifest(env)
3764
+ );
3765
+ if (error2) {
3766
+ setError(error2);
3767
+ return;
3768
+ }
3769
+ console.log(
3770
+ "[useWorkflowGraphManifest] Raw manifest after unwrap:",
3771
+ rawManifest
3772
+ );
3773
+ console.log(
3774
+ "[useWorkflowGraphManifest] Workflows in raw:",
3775
+ Object.keys((rawManifest == null ? void 0 : rawManifest.workflows) || {})
3776
+ );
3777
+ const adaptedManifest = adaptManifest(rawManifest);
3778
+ console.log(
3779
+ "[useWorkflowGraphManifest] Adapted manifest workflows:",
3780
+ Object.keys(adaptedManifest.workflows)
3781
+ );
3782
+ setManifest(adaptedManifest);
3783
+ } catch (err) {
3784
+ const error2 = err instanceof WorkflowWebAPIError ? err : err instanceof Error ? new WorkflowWebAPIError(err.message, {
3785
+ cause: err,
3786
+ layer: "client"
3787
+ }) : new WorkflowWebAPIError(String(err), { layer: "client" });
3788
+ setError(error2);
3789
+ setManifest(null);
3790
+ } finally {
3791
+ setLoading(false);
3792
+ isFetchingRef.current = false;
3793
+ }
3794
+ }, [env]);
3795
+ reactExports.useEffect(() => {
3796
+ fetchManifest();
3797
+ }, [fetchManifest]);
3798
+ return {
3799
+ manifest,
3800
+ loading,
3801
+ error,
3802
+ refetch: fetchManifest
3803
+ };
3804
+ }
3805
+ function WorkflowsList({ onWorkflowSelect }) {
3806
+ const [sheetOpen, setSheetOpen] = reactExports.useState(false);
3807
+ const [selectedWorkflow, setSelectedWorkflow] = reactExports.useState(null);
3808
+ const {
3809
+ manifest: graphManifest,
3810
+ loading,
3811
+ error: graphError
3812
+ } = useWorkflowGraphManifest();
3813
+ const workflows = graphManifest ? Object.values(graphManifest.workflows) : [];
3814
+ const sortedWorkflows = reactExports.useMemo(
3815
+ () => [...workflows].sort(
3816
+ (a, b) => a.workflowName.localeCompare(b.workflowName)
3817
+ ),
3818
+ [workflows]
3819
+ );
3820
+ const selectedWorkflowStepCount = reactExports.useMemo(
3821
+ () => (selectedWorkflow == null ? void 0 : selectedWorkflow.nodes.filter((node) => node.data.nodeKind === "step").length) ?? 0,
3822
+ [selectedWorkflow]
3823
+ );
3824
+ const handleViewWorkflow = (workflow) => {
3825
+ setSelectedWorkflow(workflow);
3826
+ setSheetOpen(true);
3827
+ onWorkflowSelect == null ? void 0 : onWorkflowSelect(workflow.workflowName);
3828
+ };
3829
+ if (loading) {
3830
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(TableSkeleton, { variant: "workflows", rows: 6 });
3831
+ }
3832
+ if (graphError) {
3833
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", children: [
3834
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
3835
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error Loading Workflows" }),
3836
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: graphError.message })
3837
+ ] });
3838
+ }
3839
+ if (workflows.length === 0) {
3840
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-12 text-center", children: [
3841
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Workflow, { className: "mx-auto h-12 w-12 text-muted-foreground mb-4" }),
3842
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold mb-2", children: "No Workflows Found" }),
3843
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "No workflow definitions were found in the graph manifest." })
3844
+ ] }) });
3845
+ }
3846
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3847
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-0 max-h-[calc(100vh-200px)] overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Table, { children: [
3848
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(TableRow, { children: [
3849
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Workflow" }),
3850
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "File" }),
3851
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "text-center sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Steps" })
3852
+ ] }) }),
3853
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableBody, { children: sortedWorkflows.map((workflow) => {
3854
+ const stepCount = workflow.nodes.filter(
3855
+ (node) => node.data.nodeKind === "step"
3856
+ ).length;
3857
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
3858
+ TableRow,
3859
+ {
3860
+ className: "cursor-pointer",
3861
+ onClick: () => handleViewWorkflow(workflow),
3862
+ children: [
3863
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: workflow.workflowName }) }),
3864
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-xs text-muted-foreground", children: workflow.filePath }) }),
3865
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "text-center py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "secondary", className: "gap-1", children: [
3866
+ /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "h-3 w-3" }),
3867
+ stepCount,
3868
+ " ",
3869
+ pluralize("step", "steps", stepCount)
3870
+ ] }) })
3871
+ ]
3872
+ },
3873
+ workflow.workflowId
3874
+ );
3875
+ }) })
3876
+ ] }) }) }),
3877
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Sheet, { open: sheetOpen, onOpenChange: setSheetOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
3878
+ SheetContent,
3879
+ {
3880
+ side: "right",
3881
+ className: "w-[75vw] max-w-[75vw] sm:max-w-[75vw]",
3882
+ children: [
3883
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SheetHeader, { children: [
3884
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SheetTitle, { className: "flex items-center gap-2", children: [
3885
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Workflow, { className: "h-5 w-5" }),
3886
+ selectedWorkflow == null ? void 0 : selectedWorkflow.workflowName
3887
+ ] }),
3888
+ selectedWorkflow && /* @__PURE__ */ jsxRuntimeExports.jsx(SheetDescription, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
3889
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-xs", children: selectedWorkflow.filePath }),
3890
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "outline", className: "gap-1", children: [
3891
+ /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "h-3 w-3" }),
3892
+ selectedWorkflowStepCount,
3893
+ " ",
3894
+ pluralize("step", "steps", selectedWorkflowStepCount)
3895
+ ] }) })
3896
+ ] }) })
3897
+ ] }),
3898
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-6 h-[calc(100vh-180px)]", children: selectedWorkflow && /* @__PURE__ */ jsxRuntimeExports.jsx(WorkflowGraphViewer, { workflow: selectedWorkflow }) })
3899
+ ]
3900
+ }
3901
+ ) })
3902
+ ] });
3903
+ }
3904
+ const home = withComponentProps(function Home() {
3905
+ const navigate = useNavigate();
3906
+ const {
3907
+ serverConfig
3908
+ } = useServerConfig();
3909
+ const [searchParams, setSearchParams] = useSearchParams();
3910
+ const sidebar = searchParams.get("sidebar");
3911
+ const hookId = searchParams.get("hookId");
3912
+ const tab = searchParams.get("tab") || "runs";
3913
+ const setTab = (value) => {
3914
+ setSearchParams((prev) => {
3915
+ prev.set("tab", value);
3916
+ return prev;
3917
+ }, {
3918
+ replace: true
3919
+ });
3920
+ };
3921
+ const selectedHookId = sidebar === "hook" && hookId ? hookId : void 0;
3922
+ const isLocalBackend = serverConfig.backendId === "local" || serverConfig.backendId === "@workflow/world-local";
3923
+ const handleRunClick = (runId, streamId) => {
3924
+ if (!streamId) {
3925
+ navigate(`/run/${runId}`);
3926
+ } else {
3927
+ navigate(`/run/${runId}/streams/${streamId}`);
3928
+ }
3929
+ };
3930
+ const handleHookSelect = (hookId2, runId) => {
3931
+ if (hookId2) {
3932
+ navigate(`/run/${runId}?sidebar=hook&hookId=${hookId2}`);
3933
+ } else {
3934
+ navigate(`/run/${runId}`);
3935
+ }
3936
+ };
3937
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
3938
+ className: "max-w-7xl mx-auto px-4",
3939
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, {
3940
+ value: tab,
3941
+ onValueChange: setTab,
3942
+ className: "w-full",
3943
+ children: [/* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, {
3944
+ className: "mb-4",
3945
+ children: [/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, {
3946
+ value: "runs",
3947
+ children: "Runs"
3948
+ }), /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, {
3949
+ value: "hooks",
3950
+ children: "Hooks"
3951
+ }), isLocalBackend && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, {
3952
+ value: "workflows",
3953
+ children: "Workflows"
3954
+ })]
3955
+ }), /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, {
3956
+ value: "runs",
3957
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, {
3958
+ title: "Failed to load workflow runs",
3959
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(RunsTable, {
3960
+ onRunClick: handleRunClick
3961
+ })
3962
+ })
3963
+ }), /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, {
3964
+ value: "hooks",
3965
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, {
3966
+ title: "Failed to load hooks",
3967
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(HooksTable, {
3968
+ onHookClick: handleHookSelect,
3969
+ selectedHookId
3970
+ })
3971
+ })
3972
+ }), isLocalBackend && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, {
3973
+ value: "workflows",
3974
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, {
3975
+ title: "Failed to load workflow graph data",
3976
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(WorkflowsList, {})
3977
+ })
3978
+ })]
3979
+ })
3980
+ });
3981
+ });
3982
+ export {
3983
+ home as default
3984
+ };