@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.
- package/README.md +1 -1
- package/build/client/assets/encryption-80GMP4r0.js +26 -0
- package/build/client/assets/entry.client-BWsSsWQm.js +11899 -0
- package/build/client/assets/highlighted-body-B3W2YXNL-DPWdt39H.js +18 -0
- package/build/client/assets/home-OcN-ARTU.js +3992 -0
- package/build/client/assets/index-DQa-BExo.js +9432 -0
- package/build/client/assets/{manifest-2d7ab41e.js → manifest-62352cd9.js} +1 -1
- package/build/client/assets/mermaid-3ZIDBTTL-B9v3aKRl.js +48141 -0
- package/build/client/assets/root-BrnNveEi.css +1 -0
- package/build/client/assets/root-ClRrWHkX.js +690 -0
- package/build/client/assets/run-detail-BdYMODbi.js +6710 -0
- package/build/client/assets/{server-build-CiTtikBY.css → server-build-DKWv59Tp.css} +1 -1
- package/build/client/assets/worker-CqHKTA7D.js +115 -0
- package/build/client/assets/workflow-graph-viewer-BdFIMYrh.js +16175 -0
- package/build/server/assets/{app-DaJqmGT8.js → app-coxrYAYu.js} +1 -1
- package/build/server/assets/{highlighted-body-B3W2YXNL-xowfciga.js → highlighted-body-B3W2YXNL-DhGWas67.js} +2 -2
- package/build/server/assets/{index-CFBIzXaR.js → index-DJ8Yt9MV.js} +30 -29
- package/build/server/assets/{mermaid-3ZIDBTTL-nU8V7hWp.js → mermaid-3ZIDBTTL-DJkW_cc4.js} +3 -3
- package/build/server/assets/{server-build-rhQJXUIP.js → server-build-dCNkWo2d.js} +420 -95
- package/build/server/assets/{token-BZ35B6LQ.js → token-Bi1ru9oe.js} +2 -2
- package/build/server/assets/{token-util-vRsmZMJV.js → token-util-Bwj_Mj31.js} +2 -2
- package/build/server/index.js +1 -1
- package/package.json +6 -6
- package/build/client/assets/encryption-8OvC6eoJ.js +0 -1
- package/build/client/assets/entry.client-BiVEcoV8.js +0 -29
- package/build/client/assets/highlighted-body-B3W2YXNL-epbVCzUZ.js +0 -1
- package/build/client/assets/home-cYqw84jW.js +0 -40
- package/build/client/assets/index-BmZS3y7B.js +0 -59
- package/build/client/assets/mermaid-3ZIDBTTL-CCXSRVd3.js +0 -210
- package/build/client/assets/root-aMfmV5uh.css +0 -1
- package/build/client/assets/root-kDmPgm4u.js +0 -26
- package/build/client/assets/run-detail-B5k2OYOu.js +0 -37
- package/build/client/assets/worker-D-HfgUMl.js +0 -1
- 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
|
+
};
|