@workflow/web 5.0.0-beta.1 → 5.0.0-beta.2

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