@workflow/web 5.0.0-beta.4 → 5.0.0-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -0
  2. package/build/client/assets/app-BkGXg64e.css +1 -0
  3. package/build/client/assets/arrow-up-right-Br49goey.js +15 -0
  4. package/build/client/assets/{entry.client-BWsSsWQm.js → entry.client-LwI3HNYl.js} +25 -25
  5. package/build/client/assets/{highlighted-body-B3W2YXNL-B7T9pqeb.js → highlighted-body-B3W2YXNL-B5pbFkUr.js} +2 -2
  6. package/build/client/assets/{home-BIQJMe_Q.js → home-DrXIdsG5.js} +1762 -290
  7. package/build/client/assets/index-HqNj_XIX.js +200 -0
  8. package/build/client/assets/{index-DQa-BExo.js → index-PFjW8YjQ.js} +24 -24
  9. package/build/client/assets/loader-circle-3PJSFf84.js +12 -0
  10. package/build/client/assets/manifest-0c933230.js +1 -0
  11. package/build/client/assets/mermaid-3ZIDBTTL-D8CjRQta.css +1 -0
  12. package/build/client/assets/{mermaid-3ZIDBTTL-w46Kr90n.js → mermaid-3ZIDBTTL-qqUSEahK.js} +6160 -4616
  13. package/build/client/assets/root-ZRjqDhEN.css +1 -0
  14. package/build/client/assets/{root-sXuXrryl.js → root-n7Zz0dTX.js} +17 -42
  15. package/build/client/assets/run-detail-CWoGxu_0.css +1 -0
  16. package/build/client/assets/{run-detail-7Pj2mQLs.js → run-detail-DHeMEsdg.js} +1970 -1587
  17. package/build/client/assets/{workflow-graph-viewer-De9JQkZc.js → workflow-graph-viewer-DWdsfF3d.js} +5109 -5110
  18. package/build/client/assets/zstd-B5R2yJjB.wasm +0 -0
  19. package/build/client/assets/zstd-browser-decoder-DemK2pIP.js +27 -0
  20. package/build/server/assets/{server-build-DT0Hg0Yf.js → app-BJXoDV4n.js} +75323 -54239
  21. package/build/server/assets/{highlighted-body-B3W2YXNL-uaucauLI.js → highlighted-body-B3W2YXNL-Kki0lKyo.js} +12 -8
  22. package/build/server/assets/index-7-uV1dU1.js +1262 -0
  23. package/build/server/assets/index-BfLBLRRi.js +204 -0
  24. package/build/server/assets/index-CETb4fkq.js +1164 -0
  25. package/build/server/assets/index-XksKPyou.js +143 -0
  26. package/build/server/assets/{mermaid-3ZIDBTTL-DrZ5V6uv.js → mermaid-3ZIDBTTL-Bh_zbSQ-.js} +13 -9
  27. package/build/server/assets/{token-D7_Lld85.js → token-D8pb4TJ8.js} +5 -2
  28. package/build/server/assets/{token-util-CfY4anoc.js → token-util-DPJj3x0B.js} +5 -2
  29. package/build/server/assets/wrapper-CsxTXsPR.js +3708 -0
  30. package/build/server/assets/zstd-browser-decoder-CWJVPmcb.js +69 -0
  31. package/build/server/index.js +47 -2
  32. package/handler.d.ts +22 -0
  33. package/handler.js +186 -0
  34. package/package.json +27 -12
  35. package/registry.d.ts +29 -0
  36. package/registry.js +89 -0
  37. package/build/client/assets/encryption-80GMP4r0.js +0 -26
  38. package/build/client/assets/manifest-77894282.js +0 -1
  39. package/build/client/assets/mermaid-3ZIDBTTL-DKxHcEOp.css +0 -1
  40. package/build/client/assets/root-C0Tu5TVN.css +0 -1
  41. package/build/client/assets/server-build-DqaxIrF0.css +0 -1
  42. package/build/client/assets/worker-CqHKTA7D.js +0 -115
  43. package/build/server/assets/app-CtOg8_v5.js +0 -9213
  44. package/build/server/assets/index-D02biwxV.js +0 -82
  45. package/build/server/assets/index-meg9qk8y.js +0 -1282
@@ -1,60 +1,43 @@
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 Check, X, q as useControllableState$1, P as Primitive$1, s as composeEventHandlers$1, t as Presence, v as useSize, w as createContextScope$1, x as cancelRun, y as reenqueueRun, z as parseWorkflowName, B as StatusBadge, Z as Zap, F as CircleX, G as RunActionsDropdownItems, H as unwrapServerActionResult, I as WorkflowGraphViewer, T as Tabs, J as TabsList, K as TabsTrigger, L as TabsContent, M as ErrorBoundary } from "./workflow-graph-viewer-De9JQkZc.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-w46Kr90n.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;
1
+ import { r as reactExports, j as jsxRuntimeExports, c as Link, R as ReactExports, o as reactDomExports, e as useSearchParams, d as useNavigate, C as useLocation, w as withComponentProps } from "./index-PFjW8YjQ.js";
2
+ import { R as ResolveHookModal, S as Send, r as requireShim, u as unwrapOrThrow, W as WorkflowWebAPIError, f as fetchHookToken, a as Skeleton, b as RelativeTime, A as Alert, C as CircleAlert, c as AlertTitle, g as getErrorTitle, d as AlertDescription, e as getErrorMessage, h as CopyableText, D as DropdownMenu, i as DropdownMenuTrigger, E as Ellipsis, j as DropdownMenuContent, k as DropdownMenuItem, l as resumeHook, m as createCollection, n as hideOthers, o as ReactRemoveScroll, p as useDirection, q as ChevronUp, 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 bulkCancelRuns, 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-DWdsfF3d.js";
3
+ import { c as createLucideIcon, h as useToast, e as cn, i as fetchRuns, j as fetchHooks, k as getPaginationDisplay, T as Tooltip, a as TooltipTrigger, C as Check, l as Copy, b as TooltipContent, D as DEFAULT_PAGE_SIZE, B as Button, m as ChevronRight, n as fetchEvents, o as useCallbackRef, p as useComposedRefs, P as Primitive, A as Anchor, q as composeEventHandlers, s as useLayoutEffect2, v as Portal$2, w as useId, x as createPopperScope, y as DismissableLayer, z as createContextScope, E as createSlot, F as Content$1, G as useControllableState, H as Root2$1, V as VISUALLY_HIDDEN_STYLES, I as Arrow, J as ChevronDown, L as useComposedRefs$1, u as useServerConfig, M as BULK_CANCEL_MAX_RUN_IDS, t as toast, N as fetchRun, O as cva, U as Presence$1, W as createContext2, X as fetchWorkflowsManifest } from "./mermaid-3ZIDBTTL-qqUSEahK.js";
4
+ import { L as LoaderCircle } from "./loader-circle-3PJSFf84.js";
14
5
  /**
15
6
  * @license lucide-react v0.575.0 - ISC
16
7
  *
17
8
  * This source code is licensed under the ISC license.
18
9
  * See the LICENSE file in the root directory of this source tree.
19
10
  */
20
- const __iconNode$7 = [
11
+ const __iconNode$6 = [
21
12
  ["path", { d: "m3 16 4 4 4-4", key: "1co6wj" }],
22
13
  ["path", { d: "M7 20V4", key: "1yoxec" }],
23
14
  ["path", { d: "M20 8h-5", key: "1vsyxs" }],
24
15
  ["path", { d: "M15 10V6.5a2.5 2.5 0 0 1 5 0V10", key: "ag13bf" }],
25
16
  ["path", { d: "M15 14h5l-5 6h5", key: "ur5jdg" }]
26
17
  ];
27
- const ArrowDownAZ = createLucideIcon("arrow-down-a-z", __iconNode$7);
18
+ const ArrowDownAZ = createLucideIcon("arrow-down-a-z", __iconNode$6);
28
19
  /**
29
20
  * @license lucide-react v0.575.0 - ISC
30
21
  *
31
22
  * This source code is licensed under the ISC license.
32
23
  * See the LICENSE file in the root directory of this source tree.
33
24
  */
34
- const __iconNode$6 = [
25
+ const __iconNode$5 = [
35
26
  ["path", { d: "m3 8 4-4 4 4", key: "11wl7u" }],
36
27
  ["path", { d: "M7 4v16", key: "1glfcx" }],
37
28
  ["path", { d: "M20 8h-5", key: "1vsyxs" }],
38
29
  ["path", { d: "M15 10V6.5a2.5 2.5 0 0 1 5 0V10", key: "ag13bf" }],
39
30
  ["path", { d: "M15 14h5l-5 6h5", key: "ur5jdg" }]
40
31
  ];
41
- const ArrowUpAZ = createLucideIcon("arrow-up-a-z", __iconNode$6);
32
+ const ArrowUpAZ = createLucideIcon("arrow-up-a-z", __iconNode$5);
42
33
  /**
43
34
  * @license lucide-react v0.575.0 - ISC
44
35
  *
45
36
  * This source code is licensed under the ISC license.
46
37
  * See the LICENSE file in the root directory of this source tree.
47
38
  */
48
- const __iconNode$5 = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
49
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$5);
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$4 = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
57
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$4);
39
+ const __iconNode$4 = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
40
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$4);
58
41
  /**
59
42
  * @license lucide-react v0.575.0 - ISC
60
43
  *
@@ -100,6 +83,9 @@ const __iconNode = [
100
83
  ["rect", { width: "8", height: "8", x: "13", y: "13", rx: "2", key: "1cgmvn" }]
101
84
  ];
102
85
  const Workflow = createLucideIcon("workflow", __iconNode);
86
+ function pluralize(singular, plural, count2) {
87
+ return count2 === 1 ? singular : plural;
88
+ }
103
89
  function useHookActions({ onResolve, callbacks }) {
104
90
  const toast2 = useToast();
105
91
  const [isResolving, setIsResolving] = reactExports.useState(false);
@@ -302,101 +288,1309 @@ const TableCaption = reactExports.forwardRef(({ className, ...props }, ref) => /
302
288
  }
303
289
  ));
304
290
  TableCaption.displayName = "TableCaption";
305
- function TableSkeleton({
306
- rows = DEFAULT_PAGE_SIZE,
307
- variant = "runs"
308
- }) {
309
- const renderRow = (i) => {
310
- switch (variant) {
311
- case "runs":
312
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
313
- "div",
314
- {
315
- className: "grid grid-cols-[1fr_1.5fr_0.8fr_1fr_1fr_40px] items-center gap-4 py-3 px-4",
316
- children: [
317
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
318
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
319
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
320
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-14" }),
321
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-2 w-8" })
322
- ] }),
323
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
324
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
325
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-6 w-6 rounded" })
326
- ]
327
- },
328
- `skeleton-row-${i}`
329
- );
330
- case "hooks":
331
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
332
- "div",
333
- {
334
- className: "grid grid-cols-[1.2fr_1.2fr_0.8fr_1fr_0.5fr_40px] items-center gap-4 py-3 px-4",
335
- children: [
336
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
337
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
338
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
339
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
340
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-8" }),
341
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-6 w-6 rounded" })
342
- ]
343
- },
344
- `skeleton-row-${i}`
345
- );
346
- case "workflows":
347
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
348
- "div",
349
- {
350
- className: "grid grid-cols-[1fr_1.5fr_0.5fr] items-center gap-4 py-3 px-4",
351
- children: [
352
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
353
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
354
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-5 w-16 rounded-full mx-auto" })
355
- ]
356
- },
357
- `skeleton-row-${i}`
358
- );
359
- default:
360
- return null;
291
+ var shimExports = requireShim();
292
+ const FOCUS_EVENT = 0;
293
+ const RECONNECT_EVENT = 1;
294
+ const MUTATE_EVENT = 2;
295
+ const ERROR_REVALIDATE_EVENT = 3;
296
+ var has = Object.prototype.hasOwnProperty;
297
+ function dequal(foo, bar) {
298
+ var ctor, len;
299
+ if (foo === bar) return true;
300
+ if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
301
+ if (ctor === Date) return foo.getTime() === bar.getTime();
302
+ if (ctor === RegExp) return foo.toString() === bar.toString();
303
+ if (ctor === Array) {
304
+ if ((len = foo.length) === bar.length) {
305
+ while (len-- && dequal(foo[len], bar[len])) ;
306
+ }
307
+ return len === -1;
308
+ }
309
+ if (!ctor || typeof foo === "object") {
310
+ len = 0;
311
+ for (ctor in foo) {
312
+ if (has.call(foo, ctor) && ++len && !has.call(bar, ctor)) return false;
313
+ if (!(ctor in bar) || !dequal(foo[ctor], bar[ctor])) return false;
314
+ }
315
+ return Object.keys(bar).length === len;
316
+ }
317
+ }
318
+ return foo !== foo && bar !== bar;
319
+ }
320
+ const SWRGlobalState = /* @__PURE__ */ new WeakMap();
321
+ const noop$1 = () => {
322
+ };
323
+ const UNDEFINED$1 = (
324
+ /*#__NOINLINE__*/
325
+ noop$1()
326
+ );
327
+ const OBJECT$1 = Object;
328
+ const isUndefined$1 = (v) => v === UNDEFINED$1;
329
+ const isFunction$1 = (v) => typeof v == "function";
330
+ const mergeObjects = (a, b) => ({
331
+ ...a,
332
+ ...b
333
+ });
334
+ const isPromiseLike = (x) => isFunction$1(x.then);
335
+ const EMPTY_CACHE = {};
336
+ const INITIAL_CACHE = {};
337
+ const STR_UNDEFINED = "undefined";
338
+ const isWindowDefined = typeof window != STR_UNDEFINED;
339
+ const isDocumentDefined = typeof document != STR_UNDEFINED;
340
+ const isLegacyDeno = isWindowDefined && "Deno" in window;
341
+ const hasRequestAnimationFrame = () => isWindowDefined && typeof window["requestAnimationFrame"] != STR_UNDEFINED;
342
+ const createCacheHelper = (cache2, key) => {
343
+ const state = SWRGlobalState.get(cache2);
344
+ return [
345
+ // Getter
346
+ () => !isUndefined$1(key) && cache2.get(key) || EMPTY_CACHE,
347
+ // Setter
348
+ (info) => {
349
+ if (!isUndefined$1(key)) {
350
+ const prev = cache2.get(key);
351
+ if (!(key in INITIAL_CACHE)) {
352
+ INITIAL_CACHE[key] = prev;
353
+ }
354
+ state[5](key, mergeObjects(prev, info), prev || EMPTY_CACHE);
355
+ }
356
+ },
357
+ // Subscriber
358
+ state[6],
359
+ // Get server cache snapshot
360
+ () => {
361
+ if (!isUndefined$1(key)) {
362
+ if (key in INITIAL_CACHE) return INITIAL_CACHE[key];
363
+ }
364
+ return !isUndefined$1(key) && cache2.get(key) || EMPTY_CACHE;
361
365
  }
366
+ ];
367
+ };
368
+ let online = true;
369
+ const isOnline = () => online;
370
+ const [onWindowEvent, offWindowEvent] = isWindowDefined && window.addEventListener ? [
371
+ window.addEventListener.bind(window),
372
+ window.removeEventListener.bind(window)
373
+ ] : [
374
+ noop$1,
375
+ noop$1
376
+ ];
377
+ const isVisible = () => {
378
+ const visibilityState = isDocumentDefined && document.visibilityState;
379
+ return isUndefined$1(visibilityState) || visibilityState !== "hidden";
380
+ };
381
+ const initFocus = (callback) => {
382
+ if (isDocumentDefined) {
383
+ document.addEventListener("visibilitychange", callback);
384
+ }
385
+ onWindowEvent("focus", callback);
386
+ return () => {
387
+ if (isDocumentDefined) {
388
+ document.removeEventListener("visibilitychange", callback);
389
+ }
390
+ offWindowEvent("focus", callback);
362
391
  };
363
- const renderHeader = () => {
364
- switch (variant) {
365
- case "runs":
366
- 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: [
367
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
368
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
369
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12" }),
370
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
371
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
372
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6" })
373
- ] });
374
- case "hooks":
375
- 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: [
376
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-16" }),
377
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
378
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12" }),
379
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
380
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
381
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6" })
382
- ] });
383
- case "workflows":
384
- 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: [
385
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
386
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-10" }),
387
- /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12 mx-auto" })
388
- ] });
389
- default:
390
- return null;
392
+ };
393
+ const initReconnect = (callback) => {
394
+ const onOnline = () => {
395
+ online = true;
396
+ callback();
397
+ };
398
+ const onOffline = () => {
399
+ online = false;
400
+ };
401
+ onWindowEvent("online", onOnline);
402
+ onWindowEvent("offline", onOffline);
403
+ return () => {
404
+ offWindowEvent("online", onOnline);
405
+ offWindowEvent("offline", onOffline);
406
+ };
407
+ };
408
+ const preset = {
409
+ isOnline,
410
+ isVisible
411
+ };
412
+ const defaultConfigOptions = {
413
+ initFocus,
414
+ initReconnect
415
+ };
416
+ const IS_REACT_LEGACY = !ReactExports.useId;
417
+ const IS_SERVER = !isWindowDefined || isLegacyDeno;
418
+ const rAF = (f) => hasRequestAnimationFrame() ? window["requestAnimationFrame"](f) : setTimeout(f, 1);
419
+ const useIsomorphicLayoutEffect = IS_SERVER ? reactExports.useEffect : reactExports.useLayoutEffect;
420
+ const navigatorConnection = typeof navigator !== "undefined" && navigator.connection;
421
+ const slowConnection = !IS_SERVER && navigatorConnection && ([
422
+ "slow-2g",
423
+ "2g"
424
+ ].includes(navigatorConnection.effectiveType) || navigatorConnection.saveData);
425
+ const table$1 = /* @__PURE__ */ new WeakMap();
426
+ const getTypeName$1 = (value) => OBJECT$1.prototype.toString.call(value);
427
+ const isObjectTypeName$1 = (typeName, type) => typeName === `[object ${type}]`;
428
+ let counter$1 = 0;
429
+ const stableHash$1 = (arg) => {
430
+ const type = typeof arg;
431
+ const typeName = getTypeName$1(arg);
432
+ const isDate = isObjectTypeName$1(typeName, "Date");
433
+ const isRegex = isObjectTypeName$1(typeName, "RegExp");
434
+ const isPlainObject = isObjectTypeName$1(typeName, "Object");
435
+ let result;
436
+ let index;
437
+ if (OBJECT$1(arg) === arg && !isDate && !isRegex) {
438
+ result = table$1.get(arg);
439
+ if (result) return result;
440
+ result = ++counter$1 + "~";
441
+ table$1.set(arg, result);
442
+ if (Array.isArray(arg)) {
443
+ result = "@";
444
+ for (index = 0; index < arg.length; index++) {
445
+ result += stableHash$1(arg[index]) + ",";
446
+ }
447
+ table$1.set(arg, result);
448
+ }
449
+ if (isPlainObject) {
450
+ result = "#";
451
+ const keys = OBJECT$1.keys(arg).sort();
452
+ while (!isUndefined$1(index = keys.pop())) {
453
+ if (!isUndefined$1(arg[index])) {
454
+ result += index + ":" + stableHash$1(arg[index]) + ",";
455
+ }
456
+ }
457
+ table$1.set(arg, result);
391
458
  }
459
+ } else {
460
+ result = isDate ? arg.toJSON() : type == "symbol" ? arg.toString() : type == "string" ? JSON.stringify(arg) : "" + arg;
461
+ }
462
+ return result;
463
+ };
464
+ const serialize$1 = (key) => {
465
+ if (isFunction$1(key)) {
466
+ try {
467
+ key = key();
468
+ } catch (err) {
469
+ key = "";
470
+ }
471
+ }
472
+ const args = key;
473
+ key = typeof key == "string" ? key : (Array.isArray(key) ? key.length : key) ? stableHash$1(key) : "";
474
+ return [
475
+ key,
476
+ args
477
+ ];
478
+ };
479
+ let __timestamp = 0;
480
+ const getTimestamp = () => ++__timestamp;
481
+ async function internalMutate(...args) {
482
+ const [cache2, _key, _data, _opts] = args;
483
+ const options = mergeObjects({
484
+ populateCache: true,
485
+ throwOnError: true
486
+ }, typeof _opts === "boolean" ? {
487
+ revalidate: _opts
488
+ } : _opts || {});
489
+ let populateCache = options.populateCache;
490
+ const rollbackOnErrorOption = options.rollbackOnError;
491
+ let optimisticData = options.optimisticData;
492
+ const rollbackOnError = (error) => {
493
+ return typeof rollbackOnErrorOption === "function" ? rollbackOnErrorOption(error) : rollbackOnErrorOption !== false;
392
494
  };
393
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden mt-4 bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-0", children: [
394
- renderHeader(),
395
- Array.from({ length: rows }, (_, i) => renderRow(i))
396
- ] }) });
495
+ const throwOnError = options.throwOnError;
496
+ if (isFunction$1(_key)) {
497
+ const keyFilter = _key;
498
+ const matchedKeys = [];
499
+ const it = cache2.keys();
500
+ for (const key of it) {
501
+ if (
502
+ // Skip the special useSWRInfinite and useSWRSubscription keys.
503
+ !/^\$(inf|sub)\$/.test(key) && keyFilter(cache2.get(key)._k)
504
+ ) {
505
+ matchedKeys.push(key);
506
+ }
507
+ }
508
+ return Promise.all(matchedKeys.map(mutateByKey));
509
+ }
510
+ return mutateByKey(_key);
511
+ async function mutateByKey(_k) {
512
+ const [key] = serialize$1(_k);
513
+ if (!key) return;
514
+ const [get, set] = createCacheHelper(cache2, key);
515
+ const [EVENT_REVALIDATORS, MUTATION, FETCH, PRELOAD] = SWRGlobalState.get(cache2);
516
+ const startRevalidate = () => {
517
+ const revalidators = EVENT_REVALIDATORS[key];
518
+ const revalidate = isFunction$1(options.revalidate) ? options.revalidate(get().data, _k) : options.revalidate !== false;
519
+ if (revalidate) {
520
+ delete FETCH[key];
521
+ delete PRELOAD[key];
522
+ if (revalidators && revalidators[0]) {
523
+ return revalidators[0](MUTATE_EVENT).then(() => get().data);
524
+ }
525
+ }
526
+ return get().data;
527
+ };
528
+ if (args.length < 3) {
529
+ return startRevalidate();
530
+ }
531
+ let data = _data;
532
+ let error;
533
+ let isError = false;
534
+ const beforeMutationTs = getTimestamp();
535
+ MUTATION[key] = [
536
+ beforeMutationTs,
537
+ 0
538
+ ];
539
+ const hasOptimisticData = !isUndefined$1(optimisticData);
540
+ const state = get();
541
+ const displayedData = state.data;
542
+ const currentData = state._c;
543
+ const committedData = isUndefined$1(currentData) ? displayedData : currentData;
544
+ if (hasOptimisticData) {
545
+ optimisticData = isFunction$1(optimisticData) ? optimisticData(committedData, displayedData) : optimisticData;
546
+ set({
547
+ data: optimisticData,
548
+ _c: committedData
549
+ });
550
+ }
551
+ if (isFunction$1(data)) {
552
+ try {
553
+ data = data(committedData);
554
+ } catch (err) {
555
+ error = err;
556
+ isError = true;
557
+ }
558
+ }
559
+ if (data && isPromiseLike(data)) {
560
+ data = await data.catch((err) => {
561
+ error = err;
562
+ isError = true;
563
+ });
564
+ if (beforeMutationTs !== MUTATION[key][0]) {
565
+ if (isError) throw error;
566
+ return data;
567
+ } else if (isError && hasOptimisticData && rollbackOnError(error)) {
568
+ populateCache = true;
569
+ set({
570
+ data: committedData,
571
+ _c: UNDEFINED$1
572
+ });
573
+ }
574
+ }
575
+ if (populateCache) {
576
+ if (!isError) {
577
+ if (isFunction$1(populateCache)) {
578
+ const populateCachedData = populateCache(data, committedData);
579
+ set({
580
+ data: populateCachedData,
581
+ error: UNDEFINED$1,
582
+ _c: UNDEFINED$1
583
+ });
584
+ } else {
585
+ set({
586
+ data,
587
+ error: UNDEFINED$1,
588
+ _c: UNDEFINED$1
589
+ });
590
+ }
591
+ }
592
+ }
593
+ MUTATION[key][1] = getTimestamp();
594
+ Promise.resolve(startRevalidate()).then(() => {
595
+ set({
596
+ _c: UNDEFINED$1
597
+ });
598
+ });
599
+ if (isError) {
600
+ if (throwOnError) throw error;
601
+ return;
602
+ }
603
+ return data;
604
+ }
397
605
  }
398
- function pluralize(singular, plural, count2) {
399
- return count2 === 1 ? singular : plural;
606
+ const revalidateAllKeys = (revalidators, type) => {
607
+ for (const key in revalidators) {
608
+ if (revalidators[key][0]) revalidators[key][0](type);
609
+ }
610
+ };
611
+ const initCache = (provider, options) => {
612
+ if (!SWRGlobalState.has(provider)) {
613
+ const opts = mergeObjects(defaultConfigOptions, options);
614
+ const EVENT_REVALIDATORS = /* @__PURE__ */ Object.create(null);
615
+ const mutate2 = internalMutate.bind(UNDEFINED$1, provider);
616
+ let unmount = noop$1;
617
+ const subscriptions = /* @__PURE__ */ Object.create(null);
618
+ const subscribe = (key, callback) => {
619
+ const subs = subscriptions[key] || [];
620
+ subscriptions[key] = subs;
621
+ subs.push(callback);
622
+ return () => subs.splice(subs.indexOf(callback), 1);
623
+ };
624
+ const setter = (key, value, prev) => {
625
+ provider.set(key, value);
626
+ const subs = subscriptions[key];
627
+ if (subs) {
628
+ for (const fn of subs) {
629
+ fn(value, prev);
630
+ }
631
+ }
632
+ };
633
+ const initProvider = () => {
634
+ if (!SWRGlobalState.has(provider)) {
635
+ SWRGlobalState.set(provider, [
636
+ EVENT_REVALIDATORS,
637
+ /* @__PURE__ */ Object.create(null),
638
+ /* @__PURE__ */ Object.create(null),
639
+ /* @__PURE__ */ Object.create(null),
640
+ mutate2,
641
+ setter,
642
+ subscribe
643
+ ]);
644
+ if (!IS_SERVER) {
645
+ const releaseFocus = opts.initFocus(setTimeout.bind(UNDEFINED$1, revalidateAllKeys.bind(UNDEFINED$1, EVENT_REVALIDATORS, FOCUS_EVENT)));
646
+ const releaseReconnect = opts.initReconnect(setTimeout.bind(UNDEFINED$1, revalidateAllKeys.bind(UNDEFINED$1, EVENT_REVALIDATORS, RECONNECT_EVENT)));
647
+ unmount = () => {
648
+ releaseFocus && releaseFocus();
649
+ releaseReconnect && releaseReconnect();
650
+ SWRGlobalState.delete(provider);
651
+ };
652
+ }
653
+ }
654
+ };
655
+ initProvider();
656
+ return [
657
+ provider,
658
+ mutate2,
659
+ initProvider,
660
+ unmount
661
+ ];
662
+ }
663
+ return [
664
+ provider,
665
+ SWRGlobalState.get(provider)[4]
666
+ ];
667
+ };
668
+ const onErrorRetry = (_, __, config, revalidate, opts) => {
669
+ const maxRetryCount = config.errorRetryCount;
670
+ const currentRetryCount = opts.retryCount;
671
+ const timeout = ~~((Math.random() + 0.5) * (1 << (currentRetryCount < 8 ? currentRetryCount : 8))) * config.errorRetryInterval;
672
+ if (!isUndefined$1(maxRetryCount) && currentRetryCount > maxRetryCount) {
673
+ return;
674
+ }
675
+ setTimeout(revalidate, timeout, opts);
676
+ };
677
+ const compare = dequal;
678
+ const [cache, mutate] = initCache(/* @__PURE__ */ new Map());
679
+ const defaultConfig = mergeObjects(
680
+ {
681
+ // events
682
+ onLoadingSlow: noop$1,
683
+ onSuccess: noop$1,
684
+ onError: noop$1,
685
+ onErrorRetry,
686
+ onDiscarded: noop$1,
687
+ // switches
688
+ revalidateOnFocus: true,
689
+ revalidateOnReconnect: true,
690
+ revalidateIfStale: true,
691
+ shouldRetryOnError: true,
692
+ // timeouts
693
+ errorRetryInterval: slowConnection ? 1e4 : 5e3,
694
+ focusThrottleInterval: 5 * 1e3,
695
+ dedupingInterval: 2 * 1e3,
696
+ loadingTimeout: slowConnection ? 5e3 : 3e3,
697
+ // providers
698
+ compare,
699
+ isPaused: () => false,
700
+ cache,
701
+ mutate,
702
+ fallback: {}
703
+ },
704
+ // use web preset by default
705
+ preset
706
+ );
707
+ const mergeConfigs = (a, b) => {
708
+ const v = mergeObjects(a, b);
709
+ if (b) {
710
+ const { use: u1, fallback: f1 } = a;
711
+ const { use: u2, fallback: f2 } = b;
712
+ if (u1 && u2) {
713
+ v.use = u1.concat(u2);
714
+ }
715
+ if (f1 && f2) {
716
+ v.fallback = mergeObjects(f1, f2);
717
+ }
718
+ }
719
+ return v;
720
+ };
721
+ const SWRConfigContext = reactExports.createContext({});
722
+ const INFINITE_PREFIX = "$inf$";
723
+ const enableDevtools = isWindowDefined && window.__SWR_DEVTOOLS_USE__;
724
+ const use$1 = enableDevtools ? window.__SWR_DEVTOOLS_USE__ : [];
725
+ const setupDevTools = () => {
726
+ if (enableDevtools) {
727
+ window.__SWR_DEVTOOLS_REACT__ = ReactExports;
728
+ }
729
+ };
730
+ const normalize = (args) => {
731
+ return isFunction$1(args[1]) ? [
732
+ args[0],
733
+ args[1],
734
+ args[2] || {}
735
+ ] : [
736
+ args[0],
737
+ null,
738
+ (args[1] === null ? args[2] : args[1]) || {}
739
+ ];
740
+ };
741
+ const useSWRConfig = () => {
742
+ const parentConfig = reactExports.useContext(SWRConfigContext);
743
+ const mergedConfig = reactExports.useMemo(() => mergeObjects(defaultConfig, parentConfig), [
744
+ parentConfig
745
+ ]);
746
+ return mergedConfig;
747
+ };
748
+ const middleware = (useSWRNext) => (key_, fetcher_, config) => {
749
+ const fetcher = fetcher_ && ((...args) => {
750
+ const [key] = serialize$1(key_);
751
+ const [, , , PRELOAD] = SWRGlobalState.get(cache);
752
+ if (key.startsWith(INFINITE_PREFIX)) {
753
+ return fetcher_(...args);
754
+ }
755
+ const req = PRELOAD[key];
756
+ if (isUndefined$1(req)) return fetcher_(...args);
757
+ delete PRELOAD[key];
758
+ return req;
759
+ });
760
+ return useSWRNext(key_, fetcher, config);
761
+ };
762
+ const BUILT_IN_MIDDLEWARE = use$1.concat(middleware);
763
+ const withArgs = (hook) => {
764
+ return function useSWRArgs(...args) {
765
+ const fallbackConfig = useSWRConfig();
766
+ const [key, fn, _config] = normalize(args);
767
+ const config = mergeConfigs(fallbackConfig, _config);
768
+ let next = hook;
769
+ const { use: use2 } = config;
770
+ const middleware2 = (use2 || []).concat(BUILT_IN_MIDDLEWARE);
771
+ for (let i = middleware2.length; i--; ) {
772
+ next = middleware2[i](next);
773
+ }
774
+ return next(key, fn || config.fetcher || null, config);
775
+ };
776
+ };
777
+ const subscribeCallback = (key, callbacks, callback) => {
778
+ const keyedRevalidators = callbacks[key] || (callbacks[key] = []);
779
+ keyedRevalidators.push(callback);
780
+ return () => {
781
+ const index = keyedRevalidators.indexOf(callback);
782
+ if (index >= 0) {
783
+ keyedRevalidators[index] = keyedRevalidators[keyedRevalidators.length - 1];
784
+ keyedRevalidators.pop();
785
+ }
786
+ };
787
+ };
788
+ const withMiddleware = (useSWR2, middleware2) => {
789
+ return (...args) => {
790
+ const [key, fn, config] = normalize(args);
791
+ const uses = (config.use || []).concat(middleware2);
792
+ return useSWR2(key, fn, {
793
+ ...config,
794
+ use: uses
795
+ });
796
+ };
797
+ };
798
+ setupDevTools();
799
+ const use = ReactExports.use || // This extra generic is to avoid TypeScript mixing up the generic and JSX sytax
800
+ // and emitting an error.
801
+ // We assume that this is only for the `use(thenable)` case, not `use(context)`.
802
+ // https://github.com/facebook/react/blob/aed00dacfb79d17c53218404c52b1c7aa59c4a89/packages/react-server/src/ReactFizzThenable.js#L45
803
+ ((thenable) => {
804
+ switch (thenable.status) {
805
+ case "pending":
806
+ throw thenable;
807
+ case "fulfilled":
808
+ return thenable.value;
809
+ case "rejected":
810
+ throw thenable.reason;
811
+ default:
812
+ thenable.status = "pending";
813
+ thenable.then((v) => {
814
+ thenable.status = "fulfilled";
815
+ thenable.value = v;
816
+ }, (e) => {
817
+ thenable.status = "rejected";
818
+ thenable.reason = e;
819
+ });
820
+ throw thenable;
821
+ }
822
+ });
823
+ const WITH_DEDUPE = {
824
+ dedupe: true
825
+ };
826
+ const resolvedUndef = Promise.resolve(UNDEFINED$1);
827
+ const useSWRHandler = (_key, fetcher, config) => {
828
+ const { cache: cache2, compare: compare2, suspense, fallbackData, revalidateOnMount, revalidateIfStale, refreshInterval, refreshWhenHidden, refreshWhenOffline, keepPreviousData } = config;
829
+ const [EVENT_REVALIDATORS, MUTATION, FETCH, PRELOAD] = SWRGlobalState.get(cache2);
830
+ const [key, fnArg] = serialize$1(_key);
831
+ const initialMountedRef = reactExports.useRef(false);
832
+ const unmountedRef = reactExports.useRef(false);
833
+ const keyRef = reactExports.useRef(key);
834
+ const fetcherRef = reactExports.useRef(fetcher);
835
+ const configRef = reactExports.useRef(config);
836
+ const getConfig = () => configRef.current;
837
+ const isActive = () => getConfig().isVisible() && getConfig().isOnline();
838
+ const [getCache, setCache, subscribeCache, getInitialCache] = createCacheHelper(cache2, key);
839
+ const stateDependencies = reactExports.useRef({}).current;
840
+ const fallback = isUndefined$1(fallbackData) ? isUndefined$1(config.fallback) ? UNDEFINED$1 : config.fallback[key] : fallbackData;
841
+ const isEqual = (prev, current) => {
842
+ for (const _ in stateDependencies) {
843
+ const t = _;
844
+ if (t === "data") {
845
+ if (!compare2(prev[t], current[t])) {
846
+ if (!isUndefined$1(prev[t])) {
847
+ return false;
848
+ }
849
+ if (!compare2(returnedData, current[t])) {
850
+ return false;
851
+ }
852
+ }
853
+ } else {
854
+ if (current[t] !== prev[t]) {
855
+ return false;
856
+ }
857
+ }
858
+ }
859
+ return true;
860
+ };
861
+ const getSnapshot = reactExports.useMemo(() => {
862
+ const shouldStartRequest = (() => {
863
+ if (!key) return false;
864
+ if (!fetcher) return false;
865
+ if (!isUndefined$1(revalidateOnMount)) return revalidateOnMount;
866
+ if (getConfig().isPaused()) return false;
867
+ if (suspense) return false;
868
+ return revalidateIfStale !== false;
869
+ })();
870
+ const getSelectedCache = (state) => {
871
+ const snapshot = mergeObjects(state);
872
+ delete snapshot._k;
873
+ if (!shouldStartRequest) {
874
+ return snapshot;
875
+ }
876
+ return {
877
+ isValidating: true,
878
+ isLoading: true,
879
+ ...snapshot
880
+ };
881
+ };
882
+ const cachedData2 = getCache();
883
+ const initialData = getInitialCache();
884
+ const clientSnapshot = getSelectedCache(cachedData2);
885
+ const serverSnapshot = cachedData2 === initialData ? clientSnapshot : getSelectedCache(initialData);
886
+ let memorizedSnapshot = clientSnapshot;
887
+ return [
888
+ () => {
889
+ const newSnapshot = getSelectedCache(getCache());
890
+ const compareResult = isEqual(newSnapshot, memorizedSnapshot);
891
+ if (compareResult) {
892
+ memorizedSnapshot.data = newSnapshot.data;
893
+ memorizedSnapshot.isLoading = newSnapshot.isLoading;
894
+ memorizedSnapshot.isValidating = newSnapshot.isValidating;
895
+ memorizedSnapshot.error = newSnapshot.error;
896
+ return memorizedSnapshot;
897
+ } else {
898
+ memorizedSnapshot = newSnapshot;
899
+ return newSnapshot;
900
+ }
901
+ },
902
+ () => serverSnapshot
903
+ ];
904
+ }, [
905
+ cache2,
906
+ key
907
+ ]);
908
+ const cached = shimExports.useSyncExternalStore(reactExports.useCallback(
909
+ (callback) => subscribeCache(key, (current, prev) => {
910
+ if (!isEqual(prev, current)) callback();
911
+ }),
912
+ // eslint-disable-next-line react-hooks/exhaustive-deps
913
+ [
914
+ cache2,
915
+ key
916
+ ]
917
+ ), getSnapshot[0], getSnapshot[1]);
918
+ const isInitialMount = !initialMountedRef.current;
919
+ const hasRevalidator = EVENT_REVALIDATORS[key] && EVENT_REVALIDATORS[key].length > 0;
920
+ const cachedData = cached.data;
921
+ const data = isUndefined$1(cachedData) ? fallback && isPromiseLike(fallback) ? use(fallback) : fallback : cachedData;
922
+ const error = cached.error;
923
+ const laggyDataRef = reactExports.useRef(data);
924
+ const returnedData = keepPreviousData ? isUndefined$1(cachedData) ? isUndefined$1(laggyDataRef.current) ? data : laggyDataRef.current : cachedData : data;
925
+ const shouldDoInitialRevalidation = (() => {
926
+ if (hasRevalidator && !isUndefined$1(error)) return false;
927
+ if (isInitialMount && !isUndefined$1(revalidateOnMount)) return revalidateOnMount;
928
+ if (getConfig().isPaused()) return false;
929
+ if (suspense) return isUndefined$1(data) ? false : revalidateIfStale;
930
+ return isUndefined$1(data) || revalidateIfStale;
931
+ })();
932
+ const defaultValidatingState = !!(key && fetcher && isInitialMount && shouldDoInitialRevalidation);
933
+ const isValidating = isUndefined$1(cached.isValidating) ? defaultValidatingState : cached.isValidating;
934
+ const isLoading = isUndefined$1(cached.isLoading) ? defaultValidatingState : cached.isLoading;
935
+ const revalidate = reactExports.useCallback(
936
+ async (revalidateOpts) => {
937
+ const currentFetcher = fetcherRef.current;
938
+ if (!key || !currentFetcher || unmountedRef.current || getConfig().isPaused()) {
939
+ return false;
940
+ }
941
+ let newData;
942
+ let startAt;
943
+ let loading = true;
944
+ const opts = revalidateOpts || {};
945
+ const shouldStartNewRequest = !FETCH[key] || !opts.dedupe;
946
+ const callbackSafeguard = () => {
947
+ if (IS_REACT_LEGACY) {
948
+ return !unmountedRef.current && key === keyRef.current && initialMountedRef.current;
949
+ }
950
+ return key === keyRef.current;
951
+ };
952
+ const finalState = {
953
+ isValidating: false,
954
+ isLoading: false
955
+ };
956
+ const finishRequestAndUpdateState = () => {
957
+ setCache(finalState);
958
+ };
959
+ const cleanupState = () => {
960
+ const requestInfo = FETCH[key];
961
+ if (requestInfo && requestInfo[1] === startAt) {
962
+ delete FETCH[key];
963
+ }
964
+ };
965
+ const initialState = {
966
+ isValidating: true
967
+ };
968
+ if (isUndefined$1(getCache().data)) {
969
+ initialState.isLoading = true;
970
+ }
971
+ try {
972
+ if (shouldStartNewRequest) {
973
+ setCache(initialState);
974
+ if (config.loadingTimeout && isUndefined$1(getCache().data)) {
975
+ setTimeout(() => {
976
+ if (loading && callbackSafeguard()) {
977
+ getConfig().onLoadingSlow(key, config);
978
+ }
979
+ }, config.loadingTimeout);
980
+ }
981
+ FETCH[key] = [
982
+ currentFetcher(fnArg),
983
+ getTimestamp()
984
+ ];
985
+ }
986
+ ;
987
+ [newData, startAt] = FETCH[key];
988
+ newData = await newData;
989
+ if (shouldStartNewRequest) {
990
+ setTimeout(cleanupState, config.dedupingInterval);
991
+ }
992
+ if (!FETCH[key] || FETCH[key][1] !== startAt) {
993
+ if (shouldStartNewRequest) {
994
+ if (callbackSafeguard()) {
995
+ getConfig().onDiscarded(key);
996
+ }
997
+ }
998
+ return false;
999
+ }
1000
+ finalState.error = UNDEFINED$1;
1001
+ const mutationInfo = MUTATION[key];
1002
+ if (!isUndefined$1(mutationInfo) && // case 1
1003
+ (startAt <= mutationInfo[0] || // case 2
1004
+ startAt <= mutationInfo[1] || // case 3
1005
+ mutationInfo[1] === 0)) {
1006
+ finishRequestAndUpdateState();
1007
+ if (shouldStartNewRequest) {
1008
+ if (callbackSafeguard()) {
1009
+ getConfig().onDiscarded(key);
1010
+ }
1011
+ }
1012
+ return false;
1013
+ }
1014
+ const cacheData = getCache().data;
1015
+ finalState.data = compare2(cacheData, newData) ? cacheData : newData;
1016
+ if (shouldStartNewRequest) {
1017
+ if (callbackSafeguard()) {
1018
+ getConfig().onSuccess(newData, key, config);
1019
+ }
1020
+ }
1021
+ } catch (err) {
1022
+ cleanupState();
1023
+ const currentConfig = getConfig();
1024
+ const { shouldRetryOnError } = currentConfig;
1025
+ if (!currentConfig.isPaused()) {
1026
+ finalState.error = err;
1027
+ if (shouldStartNewRequest && callbackSafeguard()) {
1028
+ currentConfig.onError(err, key, currentConfig);
1029
+ if (shouldRetryOnError === true || isFunction$1(shouldRetryOnError) && shouldRetryOnError(err)) {
1030
+ if (!getConfig().revalidateOnFocus || !getConfig().revalidateOnReconnect || isActive()) {
1031
+ currentConfig.onErrorRetry(err, key, currentConfig, (_opts) => {
1032
+ const revalidators = EVENT_REVALIDATORS[key];
1033
+ if (revalidators && revalidators[0]) {
1034
+ revalidators[0](ERROR_REVALIDATE_EVENT, _opts);
1035
+ }
1036
+ }, {
1037
+ retryCount: (opts.retryCount || 0) + 1,
1038
+ dedupe: true
1039
+ });
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+ }
1045
+ loading = false;
1046
+ finishRequestAndUpdateState();
1047
+ return true;
1048
+ },
1049
+ // `setState` is immutable, and `eventsCallback`, `fnArg`, and
1050
+ // `keyValidating` are depending on `key`, so we can exclude them from
1051
+ // the deps array.
1052
+ //
1053
+ // FIXME:
1054
+ // `fn` and `config` might be changed during the lifecycle,
1055
+ // but they might be changed every render like this.
1056
+ // `useSWR('key', () => fetch('/api/'), { suspense: true })`
1057
+ // So we omit the values from the deps array
1058
+ // even though it might cause unexpected behaviors.
1059
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1060
+ [
1061
+ key,
1062
+ cache2
1063
+ ]
1064
+ );
1065
+ const boundMutate = reactExports.useCallback(
1066
+ // Use callback to make sure `keyRef.current` returns latest result every time
1067
+ (...args) => {
1068
+ return internalMutate(cache2, keyRef.current, ...args);
1069
+ },
1070
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1071
+ []
1072
+ );
1073
+ useIsomorphicLayoutEffect(() => {
1074
+ fetcherRef.current = fetcher;
1075
+ configRef.current = config;
1076
+ if (!isUndefined$1(cachedData)) {
1077
+ laggyDataRef.current = cachedData;
1078
+ }
1079
+ });
1080
+ useIsomorphicLayoutEffect(() => {
1081
+ if (!key) return;
1082
+ const softRevalidate = revalidate.bind(UNDEFINED$1, WITH_DEDUPE);
1083
+ let nextFocusRevalidatedAt = 0;
1084
+ if (getConfig().revalidateOnFocus) {
1085
+ const initNow = Date.now();
1086
+ nextFocusRevalidatedAt = initNow + getConfig().focusThrottleInterval;
1087
+ }
1088
+ const onRevalidate = (type, opts = {}) => {
1089
+ if (type == FOCUS_EVENT) {
1090
+ const now = Date.now();
1091
+ if (getConfig().revalidateOnFocus && now > nextFocusRevalidatedAt && isActive()) {
1092
+ nextFocusRevalidatedAt = now + getConfig().focusThrottleInterval;
1093
+ softRevalidate();
1094
+ }
1095
+ } else if (type == RECONNECT_EVENT) {
1096
+ if (getConfig().revalidateOnReconnect && isActive()) {
1097
+ softRevalidate();
1098
+ }
1099
+ } else if (type == MUTATE_EVENT) {
1100
+ return revalidate();
1101
+ } else if (type == ERROR_REVALIDATE_EVENT) {
1102
+ return revalidate(opts);
1103
+ }
1104
+ return;
1105
+ };
1106
+ const unsubEvents = subscribeCallback(key, EVENT_REVALIDATORS, onRevalidate);
1107
+ unmountedRef.current = false;
1108
+ keyRef.current = key;
1109
+ initialMountedRef.current = true;
1110
+ setCache({
1111
+ _k: fnArg
1112
+ });
1113
+ if (shouldDoInitialRevalidation) {
1114
+ if (!FETCH[key]) {
1115
+ if (isUndefined$1(data) || IS_SERVER) {
1116
+ softRevalidate();
1117
+ } else {
1118
+ rAF(softRevalidate);
1119
+ }
1120
+ }
1121
+ }
1122
+ return () => {
1123
+ unmountedRef.current = true;
1124
+ unsubEvents();
1125
+ };
1126
+ }, [
1127
+ key
1128
+ ]);
1129
+ useIsomorphicLayoutEffect(() => {
1130
+ let timer;
1131
+ function next() {
1132
+ const interval = isFunction$1(refreshInterval) ? refreshInterval(getCache().data) : refreshInterval;
1133
+ if (interval && timer !== -1) {
1134
+ timer = setTimeout(execute, interval);
1135
+ }
1136
+ }
1137
+ function execute() {
1138
+ if (!getCache().error && (refreshWhenHidden || getConfig().isVisible()) && (refreshWhenOffline || getConfig().isOnline())) {
1139
+ revalidate(WITH_DEDUPE).then(next);
1140
+ } else {
1141
+ next();
1142
+ }
1143
+ }
1144
+ next();
1145
+ return () => {
1146
+ if (timer) {
1147
+ clearTimeout(timer);
1148
+ timer = -1;
1149
+ }
1150
+ };
1151
+ }, [
1152
+ refreshInterval,
1153
+ refreshWhenHidden,
1154
+ refreshWhenOffline,
1155
+ key
1156
+ ]);
1157
+ reactExports.useDebugValue(returnedData);
1158
+ if (suspense) {
1159
+ const hasKeyButNoData = key && isUndefined$1(data);
1160
+ if (!IS_REACT_LEGACY && IS_SERVER && hasKeyButNoData) {
1161
+ throw new Error("Fallback data is required when using Suspense in SSR.");
1162
+ }
1163
+ if (hasKeyButNoData) {
1164
+ fetcherRef.current = fetcher;
1165
+ configRef.current = config;
1166
+ unmountedRef.current = false;
1167
+ }
1168
+ const req = PRELOAD[key];
1169
+ const mutateReq = !isUndefined$1(req) && hasKeyButNoData ? boundMutate(req) : resolvedUndef;
1170
+ use(mutateReq);
1171
+ if (!isUndefined$1(error) && hasKeyButNoData) {
1172
+ throw error;
1173
+ }
1174
+ const revalidation = hasKeyButNoData ? revalidate(WITH_DEDUPE) : resolvedUndef;
1175
+ if (!isUndefined$1(returnedData) && hasKeyButNoData) {
1176
+ revalidation.status = "fulfilled";
1177
+ revalidation.value = true;
1178
+ }
1179
+ use(revalidation);
1180
+ }
1181
+ const swrResponse = {
1182
+ mutate: boundMutate,
1183
+ get data() {
1184
+ stateDependencies.data = true;
1185
+ return returnedData;
1186
+ },
1187
+ get error() {
1188
+ stateDependencies.error = true;
1189
+ return error;
1190
+ },
1191
+ get isValidating() {
1192
+ stateDependencies.isValidating = true;
1193
+ return isValidating;
1194
+ },
1195
+ get isLoading() {
1196
+ stateDependencies.isLoading = true;
1197
+ return isLoading;
1198
+ }
1199
+ };
1200
+ return swrResponse;
1201
+ };
1202
+ const useSWR = withArgs(useSWRHandler);
1203
+ const noop = () => {
1204
+ };
1205
+ const UNDEFINED = (
1206
+ /*#__NOINLINE__*/
1207
+ noop()
1208
+ );
1209
+ const OBJECT = Object;
1210
+ const isUndefined = (v) => v === UNDEFINED;
1211
+ const isFunction = (v) => typeof v == "function";
1212
+ const table = /* @__PURE__ */ new WeakMap();
1213
+ const getTypeName = (value) => OBJECT.prototype.toString.call(value);
1214
+ const isObjectTypeName = (typeName, type) => typeName === `[object ${type}]`;
1215
+ let counter = 0;
1216
+ const stableHash = (arg) => {
1217
+ const type = typeof arg;
1218
+ const typeName = getTypeName(arg);
1219
+ const isDate = isObjectTypeName(typeName, "Date");
1220
+ const isRegex = isObjectTypeName(typeName, "RegExp");
1221
+ const isPlainObject = isObjectTypeName(typeName, "Object");
1222
+ let result;
1223
+ let index;
1224
+ if (OBJECT(arg) === arg && !isDate && !isRegex) {
1225
+ result = table.get(arg);
1226
+ if (result) return result;
1227
+ result = ++counter + "~";
1228
+ table.set(arg, result);
1229
+ if (Array.isArray(arg)) {
1230
+ result = "@";
1231
+ for (index = 0; index < arg.length; index++) {
1232
+ result += stableHash(arg[index]) + ",";
1233
+ }
1234
+ table.set(arg, result);
1235
+ }
1236
+ if (isPlainObject) {
1237
+ result = "#";
1238
+ const keys = OBJECT.keys(arg).sort();
1239
+ while (!isUndefined(index = keys.pop())) {
1240
+ if (!isUndefined(arg[index])) {
1241
+ result += index + ":" + stableHash(arg[index]) + ",";
1242
+ }
1243
+ }
1244
+ table.set(arg, result);
1245
+ }
1246
+ } else {
1247
+ result = isDate ? arg.toJSON() : type == "symbol" ? arg.toString() : type == "string" ? JSON.stringify(arg) : "" + arg;
1248
+ }
1249
+ return result;
1250
+ };
1251
+ const serialize = (key) => {
1252
+ if (isFunction(key)) {
1253
+ try {
1254
+ key = key();
1255
+ } catch (err) {
1256
+ key = "";
1257
+ }
1258
+ }
1259
+ const args = key;
1260
+ key = typeof key == "string" ? key : (Array.isArray(key) ? key.length : key) ? stableHash(key) : "";
1261
+ return [
1262
+ key,
1263
+ args
1264
+ ];
1265
+ };
1266
+ const getFirstPageKey = (getKey) => {
1267
+ return serialize(getKey ? getKey(0, null) : null)[0];
1268
+ };
1269
+ const EMPTY_PROMISE = Promise.resolve();
1270
+ const infinite = (useSWRNext) => (getKey, fn, config) => {
1271
+ const didMountRef = reactExports.useRef(false);
1272
+ const { cache: cache$1, initialSize = 1, revalidateAll = false, persistSize = false, revalidateFirstPage = true, revalidateOnMount = false, parallel = false } = config;
1273
+ const [, , , PRELOAD] = SWRGlobalState.get(cache);
1274
+ let infiniteKey;
1275
+ try {
1276
+ infiniteKey = getFirstPageKey(getKey);
1277
+ if (infiniteKey) infiniteKey = INFINITE_PREFIX + infiniteKey;
1278
+ } catch (err) {
1279
+ }
1280
+ const [get, set, subscribeCache] = createCacheHelper(cache$1, infiniteKey);
1281
+ const getSnapshot = reactExports.useCallback(() => {
1282
+ const size = isUndefined$1(get()._l) ? initialSize : get()._l;
1283
+ return size;
1284
+ }, [
1285
+ cache$1,
1286
+ infiniteKey,
1287
+ initialSize
1288
+ ]);
1289
+ shimExports.useSyncExternalStore(reactExports.useCallback(
1290
+ (callback) => {
1291
+ if (infiniteKey) return subscribeCache(infiniteKey, () => {
1292
+ callback();
1293
+ });
1294
+ return () => {
1295
+ };
1296
+ },
1297
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1298
+ [
1299
+ cache$1,
1300
+ infiniteKey
1301
+ ]
1302
+ ), getSnapshot, getSnapshot);
1303
+ const resolvePageSize = reactExports.useCallback(() => {
1304
+ const cachedPageSize = get()._l;
1305
+ return isUndefined$1(cachedPageSize) ? initialSize : cachedPageSize;
1306
+ }, [
1307
+ infiniteKey,
1308
+ initialSize
1309
+ ]);
1310
+ const lastPageSizeRef = reactExports.useRef(resolvePageSize());
1311
+ useIsomorphicLayoutEffect(() => {
1312
+ if (!didMountRef.current) {
1313
+ didMountRef.current = true;
1314
+ return;
1315
+ }
1316
+ if (infiniteKey) {
1317
+ set({
1318
+ _l: persistSize ? lastPageSizeRef.current : resolvePageSize()
1319
+ });
1320
+ }
1321
+ }, [
1322
+ infiniteKey,
1323
+ cache$1
1324
+ ]);
1325
+ const shouldRevalidateOnMount = revalidateOnMount && !didMountRef.current;
1326
+ const swr = useSWRNext(infiniteKey, async (key) => {
1327
+ const forceRevalidateAll = get()._i;
1328
+ const shouldRevalidatePage = get()._r;
1329
+ set({
1330
+ _r: UNDEFINED$1
1331
+ });
1332
+ const data = [];
1333
+ const pageSize = resolvePageSize();
1334
+ const [getCache] = createCacheHelper(cache$1, key);
1335
+ const cacheData = getCache().data;
1336
+ const revalidators = [];
1337
+ let previousPageData = null;
1338
+ for (let i = 0; i < pageSize; ++i) {
1339
+ const [pageKey, pageArg] = serialize$1(getKey(i, parallel ? null : previousPageData));
1340
+ if (!pageKey) {
1341
+ break;
1342
+ }
1343
+ const [getSWRCache, setSWRCache] = createCacheHelper(cache$1, pageKey);
1344
+ let pageData = getSWRCache().data;
1345
+ const shouldFetchPage = revalidateAll || forceRevalidateAll || isUndefined$1(pageData) || revalidateFirstPage && !i && !isUndefined$1(cacheData) || shouldRevalidateOnMount || cacheData && !isUndefined$1(cacheData[i]) && !config.compare(cacheData[i], pageData);
1346
+ if (fn && (typeof shouldRevalidatePage === "function" ? shouldRevalidatePage(pageData, pageArg) : shouldFetchPage)) {
1347
+ const revalidate = async () => {
1348
+ const hasPreloadedRequest = pageKey in PRELOAD;
1349
+ if (!hasPreloadedRequest) {
1350
+ pageData = await fn(pageArg);
1351
+ } else {
1352
+ const req = PRELOAD[pageKey];
1353
+ delete PRELOAD[pageKey];
1354
+ pageData = await req;
1355
+ }
1356
+ setSWRCache({
1357
+ data: pageData,
1358
+ _k: pageArg
1359
+ });
1360
+ data[i] = pageData;
1361
+ };
1362
+ if (parallel) {
1363
+ revalidators.push(revalidate);
1364
+ } else {
1365
+ await revalidate();
1366
+ }
1367
+ } else {
1368
+ data[i] = pageData;
1369
+ }
1370
+ if (!parallel) {
1371
+ previousPageData = pageData;
1372
+ }
1373
+ }
1374
+ if (parallel) {
1375
+ await Promise.all(revalidators.map((r) => r()));
1376
+ }
1377
+ set({
1378
+ _i: UNDEFINED$1
1379
+ });
1380
+ return data;
1381
+ }, config);
1382
+ const mutate2 = reactExports.useCallback(
1383
+ // eslint-disable-next-line func-names
1384
+ function(data, opts) {
1385
+ const options = typeof opts === "boolean" ? {
1386
+ revalidate: opts
1387
+ } : opts || {};
1388
+ const shouldRevalidate = options.revalidate !== false;
1389
+ if (!infiniteKey) return EMPTY_PROMISE;
1390
+ if (shouldRevalidate) {
1391
+ if (!isUndefined$1(data)) {
1392
+ set({
1393
+ _i: false,
1394
+ _r: options.revalidate
1395
+ });
1396
+ } else {
1397
+ set({
1398
+ _i: true,
1399
+ _r: options.revalidate
1400
+ });
1401
+ }
1402
+ }
1403
+ return arguments.length ? swr.mutate(data, {
1404
+ ...options,
1405
+ revalidate: shouldRevalidate
1406
+ }) : swr.mutate();
1407
+ },
1408
+ // swr.mutate is always the same reference
1409
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1410
+ [
1411
+ infiniteKey,
1412
+ cache$1
1413
+ ]
1414
+ );
1415
+ const setSize = reactExports.useCallback(
1416
+ (arg) => {
1417
+ if (!infiniteKey) return EMPTY_PROMISE;
1418
+ const [, changeSize] = createCacheHelper(cache$1, infiniteKey);
1419
+ let size;
1420
+ if (isFunction$1(arg)) {
1421
+ size = arg(resolvePageSize());
1422
+ } else if (typeof arg == "number") {
1423
+ size = arg;
1424
+ }
1425
+ if (typeof size != "number") return EMPTY_PROMISE;
1426
+ changeSize({
1427
+ _l: size
1428
+ });
1429
+ lastPageSizeRef.current = size;
1430
+ const data = [];
1431
+ const [getInfiniteCache] = createCacheHelper(cache$1, infiniteKey);
1432
+ let previousPageData = null;
1433
+ for (let i = 0; i < size; ++i) {
1434
+ const [pageKey] = serialize$1(getKey(i, previousPageData));
1435
+ const [getCache] = createCacheHelper(cache$1, pageKey);
1436
+ const pageData = pageKey ? getCache().data : UNDEFINED$1;
1437
+ if (isUndefined$1(pageData)) {
1438
+ return mutate2(getInfiniteCache().data);
1439
+ }
1440
+ data.push(pageData);
1441
+ previousPageData = pageData;
1442
+ }
1443
+ return mutate2(data);
1444
+ },
1445
+ // exclude getKey from the dependencies, which isn't allowed to change during the lifecycle
1446
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1447
+ [
1448
+ infiniteKey,
1449
+ cache$1,
1450
+ mutate2,
1451
+ resolvePageSize
1452
+ ]
1453
+ );
1454
+ return {
1455
+ size: resolvePageSize(),
1456
+ setSize,
1457
+ mutate: mutate2,
1458
+ get data() {
1459
+ return swr.data;
1460
+ },
1461
+ get error() {
1462
+ return swr.error;
1463
+ },
1464
+ get isValidating() {
1465
+ return swr.isValidating;
1466
+ },
1467
+ get isLoading() {
1468
+ return swr.isLoading;
1469
+ }
1470
+ };
1471
+ };
1472
+ const useSWRInfinite = withMiddleware(useSWR, infinite);
1473
+ function useInfiniteList(cacheKey, fetchFn, getItemKey) {
1474
+ var _a;
1475
+ const getKey = reactExports.useCallback(
1476
+ (_index, prev) => {
1477
+ if (prev && (!prev.hasMore || !prev.cursor)) return null;
1478
+ return [cacheKey, (prev == null ? void 0 : prev.cursor) ?? null];
1479
+ },
1480
+ [cacheKey]
1481
+ );
1482
+ const {
1483
+ data: pages,
1484
+ error,
1485
+ isLoading,
1486
+ isValidating,
1487
+ size,
1488
+ setSize,
1489
+ mutate: mutate2
1490
+ } = useSWRInfinite(
1491
+ getKey,
1492
+ ([, cursor]) => fetchFn(cursor ?? void 0),
1493
+ {
1494
+ revalidateFirstPage: false,
1495
+ revalidateIfStale: false,
1496
+ revalidateOnFocus: false,
1497
+ keepPreviousData: true
1498
+ }
1499
+ );
1500
+ const items = reactExports.useMemo(() => {
1501
+ if (!pages) return [];
1502
+ const seen = /* @__PURE__ */ new Set();
1503
+ const result = [];
1504
+ for (const page of pages) {
1505
+ for (const item of page.data) {
1506
+ const key = getItemKey(item);
1507
+ if (seen.has(key)) continue;
1508
+ seen.add(key);
1509
+ result.push(item);
1510
+ }
1511
+ }
1512
+ return result;
1513
+ }, [pages, getItemKey]);
1514
+ const lastPage = pages == null ? void 0 : pages[pages.length - 1];
1515
+ const hasMore = Boolean((lastPage == null ? void 0 : lastPage.hasMore) && (lastPage == null ? void 0 : lastPage.cursor));
1516
+ const isLoadingMore = size > 0 && Boolean(pages) && pages.length < size;
1517
+ const loadMore = reactExports.useCallback(() => {
1518
+ if (isValidating || !hasMore) return;
1519
+ void setSize((s) => s + 1);
1520
+ }, [isValidating, hasMore, setSize]);
1521
+ const reload = reactExports.useCallback(() => {
1522
+ void setSize(1);
1523
+ void mutate2();
1524
+ }, [setSize, mutate2]);
1525
+ const normalizedError = error ? error instanceof Error ? error : new WorkflowWebAPIError(String(error), { layer: "client" }) : null;
1526
+ return {
1527
+ items,
1528
+ error: normalizedError,
1529
+ isLoading,
1530
+ isLoadingMore,
1531
+ hasMore,
1532
+ loadMore,
1533
+ reload,
1534
+ refresh: reload,
1535
+ pageInfo: (_a = pages == null ? void 0 : pages[0]) == null ? void 0 : _a.pageInfo
1536
+ };
1537
+ }
1538
+ function useWorkflowRunsInfinite(env, params) {
1539
+ const {
1540
+ workflowName,
1541
+ status,
1542
+ limit = 25,
1543
+ sortOrder = "desc",
1544
+ startTime,
1545
+ endTime
1546
+ } = params;
1547
+ const cacheKey = `workflow-runs:${workflowName ?? ""}:${status ?? ""}:${sortOrder}:${limit}:${startTime ?? ""}:${endTime ?? ""}`;
1548
+ const fetchFn = reactExports.useCallback(
1549
+ (cursor) => unwrapOrThrow(
1550
+ fetchRuns(env, {
1551
+ cursor,
1552
+ sortOrder,
1553
+ limit,
1554
+ workflowName,
1555
+ status,
1556
+ startTime,
1557
+ endTime
1558
+ })
1559
+ ),
1560
+ [env, workflowName, limit, sortOrder, status, startTime, endTime]
1561
+ );
1562
+ const getItemKey = reactExports.useCallback((run) => run.runId, []);
1563
+ return useInfiniteList(cacheKey, fetchFn, getItemKey);
1564
+ }
1565
+ function useLoadMoreOnScroll(loadMore, {
1566
+ hasMore,
1567
+ isLoadingMore,
1568
+ root = null,
1569
+ rootMargin = "400px"
1570
+ }) {
1571
+ const sentinelRef = reactExports.useRef(null);
1572
+ const loadMoreRef = reactExports.useRef(loadMore);
1573
+ reactExports.useEffect(() => {
1574
+ loadMoreRef.current = loadMore;
1575
+ }, [loadMore]);
1576
+ reactExports.useEffect(() => {
1577
+ const sentinel = sentinelRef.current;
1578
+ if (!sentinel || !hasMore || isLoadingMore) return;
1579
+ const observer = new IntersectionObserver(
1580
+ (entries) => {
1581
+ for (const entry of entries) {
1582
+ if (entry.isIntersecting) {
1583
+ loadMoreRef.current();
1584
+ break;
1585
+ }
1586
+ }
1587
+ },
1588
+ { root, rootMargin, threshold: 0 }
1589
+ );
1590
+ observer.observe(sentinel);
1591
+ return () => observer.disconnect();
1592
+ }, [hasMore, isLoadingMore, root, rootMargin]);
1593
+ return sentinelRef;
400
1594
  }
401
1595
  function usePaginatedList(fetchFn) {
402
1596
  var _a;
@@ -430,7 +1624,8 @@ function usePaginatedList(fetchFn) {
430
1624
  newMap.set(pageIndex, {
431
1625
  data: cached.data,
432
1626
  isLoading: false,
433
- error: null
1627
+ error: null,
1628
+ pageInfo: cached.pageInfo
434
1629
  });
435
1630
  return newMap;
436
1631
  });
@@ -444,14 +1639,16 @@ function usePaginatedList(fetchFn) {
444
1639
  pageCache.current.set(cacheKey, {
445
1640
  data: result.data,
446
1641
  cursor: result.cursor,
447
- hasMore: result.hasMore
1642
+ hasMore: result.hasMore,
1643
+ pageInfo: result.pageInfo
448
1644
  });
449
1645
  setAllPageResults((prev) => {
450
1646
  const newMap = new Map(prev);
451
1647
  newMap.set(pageIndex, {
452
1648
  data: result.data,
453
1649
  isLoading: false,
454
- error: null
1650
+ error: null,
1651
+ pageInfo: result.pageInfo
455
1652
  });
456
1653
  return newMap;
457
1654
  });
@@ -547,19 +1744,10 @@ function usePaginatedList(fetchFn) {
547
1744
  hasPreviousPage: currentPage > 0,
548
1745
  reload,
549
1746
  refresh,
550
- pageInfo
1747
+ pageInfo,
1748
+ analyticsPageInfo: currentPageResult.pageInfo
551
1749
  };
552
1750
  }
553
- function useWorkflowRuns(env, params) {
554
- const { workflowName, status, limit = 10, sortOrder = "desc" } = params;
555
- const fetchFn = reactExports.useCallback(
556
- (cursor) => unwrapOrThrow(
557
- fetchRuns(env, { cursor, sortOrder, limit, workflowName, status })
558
- ),
559
- [env, workflowName, limit, sortOrder, status]
560
- );
561
- return usePaginatedList(fetchFn);
562
- }
563
1751
  function useWorkflowHooks(env, params) {
564
1752
  const { runId, limit = 10, sortOrder = "desc" } = params;
565
1753
  const fetchFn = reactExports.useCallback(
@@ -568,6 +1756,137 @@ function useWorkflowHooks(env, params) {
568
1756
  );
569
1757
  return usePaginatedList(fetchFn);
570
1758
  }
1759
+ function HookTokenCell({ env, runId, hookId }) {
1760
+ const [status, setStatus] = reactExports.useState("idle");
1761
+ const [error, setError] = reactExports.useState(null);
1762
+ const handleCopy = async (e) => {
1763
+ e.stopPropagation();
1764
+ if (status === "loading") return;
1765
+ setStatus("loading");
1766
+ setError(null);
1767
+ try {
1768
+ const token = await fetchHookToken(env, runId, hookId);
1769
+ await navigator.clipboard.writeText(token);
1770
+ setStatus("copied");
1771
+ setTimeout(() => setStatus("idle"), 2e3);
1772
+ } catch (err) {
1773
+ console.error("Failed to copy hook token:", err);
1774
+ setError("Failed to copy token");
1775
+ setStatus("idle");
1776
+ }
1777
+ };
1778
+ const tooltip = error ? error : status === "copied" ? "Copied!" : status === "loading" ? "Fetching token…" : "Copy token";
1779
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "relative group/copy inline-block", children: [
1780
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "••••••••••••" }),
1781
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1782
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1783
+ "button",
1784
+ {
1785
+ type: "button",
1786
+ onClick: handleCopy,
1787
+ disabled: status === "loading",
1788
+ className: "absolute right-0 top-1/2 -translate-y-1/2 opacity-0 group-hover/copy:opacity-100 transition-opacity bg-background/80 backdrop-blur-sm p-1 rounded",
1789
+ "aria-label": "Copy token",
1790
+ children: status === "loading" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-3 w-3 text-muted-foreground animate-spin" }) : status === "copied" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "h-3 w-3 text-muted-foreground hover:text-foreground" })
1791
+ }
1792
+ ) }),
1793
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: tooltip }) })
1794
+ ] })
1795
+ ] });
1796
+ }
1797
+ function TableSkeleton({
1798
+ rows = DEFAULT_PAGE_SIZE,
1799
+ variant = "runs"
1800
+ }) {
1801
+ const renderRow = (i) => {
1802
+ switch (variant) {
1803
+ case "runs":
1804
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1805
+ "div",
1806
+ {
1807
+ className: "grid grid-cols-[1fr_1.5fr_0.8fr_1fr_1fr_40px] items-center gap-4 py-3 px-4",
1808
+ children: [
1809
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
1810
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
1811
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
1812
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-14" }),
1813
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-2 w-8" })
1814
+ ] }),
1815
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
1816
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
1817
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-6 w-6 rounded" })
1818
+ ]
1819
+ },
1820
+ `skeleton-row-${i}`
1821
+ );
1822
+ case "hooks":
1823
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1824
+ "div",
1825
+ {
1826
+ className: "grid grid-cols-[1.2fr_1.2fr_0.8fr_1fr_0.5fr_40px] items-center gap-4 py-3 px-4",
1827
+ children: [
1828
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
1829
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
1830
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
1831
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3 w-3/4" }),
1832
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-8" }),
1833
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-6 w-6 rounded" })
1834
+ ]
1835
+ },
1836
+ `skeleton-row-${i}`
1837
+ );
1838
+ case "workflows":
1839
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1840
+ "div",
1841
+ {
1842
+ className: "grid grid-cols-[1fr_1.5fr_0.5fr] items-center gap-4 py-3 px-4",
1843
+ children: [
1844
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-3/4" }),
1845
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-4/5" }),
1846
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-5 w-16 rounded-full mx-auto" })
1847
+ ]
1848
+ },
1849
+ `skeleton-row-${i}`
1850
+ );
1851
+ default:
1852
+ return null;
1853
+ }
1854
+ };
1855
+ const renderHeader = () => {
1856
+ switch (variant) {
1857
+ case "runs":
1858
+ 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: [
1859
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
1860
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
1861
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12" }),
1862
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
1863
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
1864
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6" })
1865
+ ] });
1866
+ case "hooks":
1867
+ 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: [
1868
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-16" }),
1869
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
1870
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12" }),
1871
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-14" }),
1872
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
1873
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6" })
1874
+ ] });
1875
+ case "workflows":
1876
+ 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: [
1877
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
1878
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-10" }),
1879
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-12 mx-auto" })
1880
+ ] });
1881
+ default:
1882
+ return null;
1883
+ }
1884
+ };
1885
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden mt-4 bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "p-0", children: [
1886
+ renderHeader(),
1887
+ Array.from({ length: rows }, (_, i) => renderRow(i))
1888
+ ] }) });
1889
+ }
571
1890
  function HooksTable({
572
1891
  runId,
573
1892
  onHookClick,
@@ -592,7 +1911,8 @@ function HooksTable({
592
1911
  });
593
1912
  const hookActions = useHookActions({
594
1913
  onResolve: async (hook, payload) => {
595
- await resumeHook(env, hook.token, payload);
1914
+ const token = await fetchHookToken(env, hook.runId, hook.hookId);
1915
+ await resumeHook(env, token, payload);
596
1916
  },
597
1917
  callbacks: {
598
1918
  onSuccess: refresh
@@ -727,7 +2047,7 @@ function HooksTable({
727
2047
  ] }),
728
2048
  error ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", children: [
729
2049
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
730
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error loading hooks" }),
2050
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: getErrorTitle(error, "Error loading hooks") }),
731
2051
  /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
732
2052
  ] }) : !loading && (!hooks || hooks.length === 0) ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
733
2053
  "No active hooks found. ",
@@ -752,7 +2072,14 @@ function HooksTable({
752
2072
  children: [
753
2073
  /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: hook.hookId, overlay: true, children: hook.hookId }) }),
754
2074
  /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: hook.runId, overlay: true, children: hook.runId }) }),
755
- /* @__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: "••••••••••••" }) }) }),
2075
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2076
+ HookTokenCell,
2077
+ {
2078
+ env,
2079
+ runId: hook.runId,
2080
+ hookId: hook.hookId
2081
+ }
2082
+ ) }),
756
2083
  /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: hook.createdAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: hook.createdAt }) : "-" }),
757
2084
  /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: renderInvocationCount(hook) }),
758
2085
  /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { children: [
@@ -2300,6 +3627,37 @@ const SelectSeparator = reactExports.forwardRef(({ className, ...props }, ref) =
2300
3627
  }
2301
3628
  ));
2302
3629
  SelectSeparator.displayName = Separator.displayName;
3630
+ function bulkCancelToastSeverity(summary) {
3631
+ const succeeded = summary.cancelled + summary.alreadyCancelled;
3632
+ const hadProblem = summary.failed + summary.notCancellable + summary.notFound > 0;
3633
+ if (succeeded === 0) return "error";
3634
+ if (hadProblem) return "warning";
3635
+ return "success";
3636
+ }
3637
+ function shouldRetainSelectionAfterBulkCancel(result) {
3638
+ return result.outcome === "failed" && result.retryable;
3639
+ }
3640
+ const windows = /* @__PURE__ */ new Map();
3641
+ function createWindow(periodMs) {
3642
+ const end = Date.now();
3643
+ return {
3644
+ startTime: new Date(end - periodMs).toISOString(),
3645
+ endTime: new Date(end).toISOString()
3646
+ };
3647
+ }
3648
+ function getListingWindow(periodId, periodMs) {
3649
+ let window2 = windows.get(periodId);
3650
+ if (!window2) {
3651
+ window2 = createWindow(periodMs);
3652
+ windows.set(periodId, window2);
3653
+ }
3654
+ return window2;
3655
+ }
3656
+ function advanceListingWindow(periodId, periodMs) {
3657
+ const window2 = createWindow(periodMs);
3658
+ windows.set(periodId, window2);
3659
+ return window2;
3660
+ }
2303
3661
  function useTableSelection({
2304
3662
  getItemId
2305
3663
  }) {
@@ -2722,6 +4080,20 @@ const statusMap = {
2722
4080
  failed: { label: "Failed", color: "bg-red-600 dark:bg-red-400" },
2723
4081
  cancelled: { label: "Cancelled", color: "bg-gray-600 dark:bg-gray-400" }
2724
4082
  };
4083
+ const HOUR_MS = 60 * 60 * 1e3;
4084
+ const DAY_MS = 24 * HOUR_MS;
4085
+ const PERIOD_PRESETS = [
4086
+ { id: "1h", label: "Last hour", ms: HOUR_MS },
4087
+ { id: "6h", label: "Last 6 hours", ms: 6 * HOUR_MS },
4088
+ { id: "24h", label: "Last 24 hours", ms: DAY_MS },
4089
+ { id: "3d", label: "Last 3 days", ms: 3 * DAY_MS },
4090
+ { id: "7d", label: "Last 7 days", ms: 7 * DAY_MS },
4091
+ { id: "30d", label: "Last 30 days", ms: 30 * DAY_MS }
4092
+ ];
4093
+ const DEFAULT_PERIOD = "24h";
4094
+ function isPeriodId(value) {
4095
+ return PERIOD_PRESETS.some((preset2) => preset2.id === value);
4096
+ }
2725
4097
  function useWorkflowFilter() {
2726
4098
  const navigate = useNavigate();
2727
4099
  const { pathname } = useLocation();
@@ -2757,15 +4129,36 @@ function useStatusFilter() {
2757
4129
  [navigate, pathname, searchParams]
2758
4130
  );
2759
4131
  }
4132
+ function usePeriodFilter() {
4133
+ const navigate = useNavigate();
4134
+ const { pathname } = useLocation();
4135
+ const [searchParams] = useSearchParams();
4136
+ return reactExports.useCallback(
4137
+ (value) => {
4138
+ const params = new URLSearchParams(searchParams.toString());
4139
+ if (value === DEFAULT_PERIOD) {
4140
+ params.delete("period");
4141
+ } else {
4142
+ params.set("period", value);
4143
+ }
4144
+ navigate(`${pathname}?${params.toString()}`);
4145
+ },
4146
+ [navigate, pathname, searchParams]
4147
+ );
4148
+ }
2760
4149
  function FilterControls({
2761
4150
  workflowNameFilter,
2762
4151
  status,
2763
4152
  seenWorkflowNames,
2764
4153
  sortOrder,
2765
4154
  loading,
2766
- statusFilterRequiresWorkflowNameFilter,
4155
+ period,
4156
+ showPeriodPicker,
4157
+ planWindowMs,
4158
+ planUpgradeAvailable,
2767
4159
  onWorkflowChange,
2768
4160
  onStatusChange,
4161
+ onPeriodChange,
2769
4162
  onSortToggle,
2770
4163
  onRefresh,
2771
4164
  lastRefreshTime
@@ -2783,6 +4176,35 @@ function FilterControls({
2783
4176
  )
2784
4177
  ] }),
2785
4178
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
4179
+ showPeriodPicker && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
4180
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4181
+ Select,
4182
+ {
4183
+ value: period,
4184
+ onValueChange: onPeriodChange,
4185
+ disabled: loading,
4186
+ children: [
4187
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[150px] h-9", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Time window" }) }),
4188
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContent, { children: PERIOD_PRESETS.map((preset2) => {
4189
+ const beyondPlan = planWindowMs !== void 0 && preset2.ms > planWindowMs;
4190
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4191
+ SelectItem,
4192
+ {
4193
+ value: preset2.id,
4194
+ disabled: beyondPlan,
4195
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4196
+ preset2.label,
4197
+ beyondPlan && planUpgradeAvailable && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground", children: "Observability Plus" })
4198
+ ] })
4199
+ },
4200
+ preset2.id
4201
+ );
4202
+ }) })
4203
+ ]
4204
+ }
4205
+ ) }) }),
4206
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: planUpgradeAvailable ? "Time window for the runs list. Longer windows require Observability Plus." : "Time window for the runs list" })
4207
+ ] }),
2786
4208
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
2787
4209
  Select,
2788
4210
  {
@@ -2807,7 +4229,7 @@ function FilterControls({
2807
4229
  {
2808
4230
  value: status || "all",
2809
4231
  onValueChange: onStatusChange,
2810
- disabled: loading || statusFilterRequiresWorkflowNameFilter && !workflowNameFilter,
4232
+ disabled: loading,
2811
4233
  children: [
2812
4234
  /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "w-[140px] h-9", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Filter by status" }) }),
2813
4235
  /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
@@ -2827,7 +4249,7 @@ function FilterControls({
2827
4249
  ]
2828
4250
  }
2829
4251
  ) }) }),
2830
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: statusFilterRequiresWorkflowNameFilter && workflowNameFilter === "all" ? "Select a workflow first to filter by status" : "Filter runs by status" })
4252
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Filter runs by status" })
2831
4253
  ] }),
2832
4254
  /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2833
4255
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -2865,7 +4287,7 @@ function FilterControls({
2865
4287
  ] });
2866
4288
  }
2867
4289
  function RunsTable({ onRunClick }) {
2868
- var _a, _b, _c, _d;
4290
+ var _a, _b, _c;
2869
4291
  const [searchParams] = useSearchParams();
2870
4292
  const handleWorkflowFilter = useWorkflowFilter();
2871
4293
  const handleStatusFilter = useStatusFilter();
@@ -2874,6 +4296,10 @@ function RunsTable({ onRunClick }) {
2874
4296
  const validStatuses = Object.keys(statusMap);
2875
4297
  const status = rawStatus === "all" || rawStatus && validStatuses.includes(rawStatus) ? rawStatus : void 0;
2876
4298
  const workflowNameFilter = searchParams.get("workflow");
4299
+ const rawPeriod = searchParams.get("period");
4300
+ const period = isPeriodId(rawPeriod) ? rawPeriod : DEFAULT_PERIOD;
4301
+ const periodPreset = PERIOD_PRESETS.find((preset2) => preset2.id === period) ?? PERIOD_PRESETS[2];
4302
+ const handlePeriodFilter = usePeriodFilter();
2877
4303
  const [sortOrder, setSortOrder] = reactExports.useState("desc");
2878
4304
  const [lastRefreshTime, setLastRefreshTime] = reactExports.useState(
2879
4305
  () => /* @__PURE__ */ new Date()
@@ -2883,35 +4309,62 @@ function RunsTable({ onRunClick }) {
2883
4309
  const isLocal = serverConfig.backendId === "local" || serverConfig.backendId === "@workflow/world-local";
2884
4310
  const localDataDirPath = (_a = serverConfig.displayInfo) == null ? void 0 : _a["local.dataDirPath"];
2885
4311
  const localShortName = (_b = serverConfig.displayInfo) == null ? void 0 : _b["local.shortName"];
2886
- const statusFilterRequiresWorkflowNameFilter = ((_c = serverConfig.backendId) == null ? void 0 : _c.includes("vercel")) || false;
2887
4312
  const [seenWorkflowNames, setSeenWorkflowNames] = reactExports.useState(
2888
4313
  /* @__PURE__ */ new Set()
2889
4314
  );
4315
+ const isVercelBackend = ((_c = serverConfig.backendId) == null ? void 0 : _c.includes("vercel")) ?? false;
4316
+ const [listingWindow, setListingWindow] = reactExports.useState(
4317
+ () => isVercelBackend ? getListingWindow(period, periodPreset.ms) : void 0
4318
+ );
4319
+ reactExports.useEffect(() => {
4320
+ setListingWindow(
4321
+ isVercelBackend ? getListingWindow(period, periodPreset.ms) : void 0
4322
+ );
4323
+ }, [isVercelBackend, period, periodPreset.ms]);
4324
+ const refreshListingWindow = reactExports.useCallback(() => {
4325
+ if (isVercelBackend) {
4326
+ setListingWindow(advanceListingWindow(period, periodPreset.ms));
4327
+ }
4328
+ }, [isVercelBackend, period, periodPreset.ms]);
2890
4329
  const {
2891
- data,
4330
+ items: runs,
2892
4331
  error,
2893
- nextPage,
2894
- previousPage,
2895
- hasNextPage,
2896
- hasPreviousPage,
4332
+ isLoading,
4333
+ isLoadingMore,
4334
+ hasMore,
4335
+ loadMore,
2897
4336
  reload,
2898
4337
  refresh,
2899
- pageInfo
2900
- } = useWorkflowRuns(env, {
4338
+ pageInfo: analyticsPageInfo
4339
+ } = useWorkflowRunsInfinite(env, {
2901
4340
  sortOrder,
2902
4341
  workflowName: workflowNameFilter === "all" ? void 0 : workflowNameFilter,
2903
- status: status === "all" ? void 0 : status
4342
+ status: status === "all" ? void 0 : status,
4343
+ startTime: listingWindow == null ? void 0 : listingWindow.startTime,
4344
+ endTime: listingWindow == null ? void 0 : listingWindow.endTime
4345
+ });
4346
+ const [planInfo, setPlanInfo] = reactExports.useState(void 0);
4347
+ reactExports.useEffect(() => {
4348
+ if (analyticsPageInfo) {
4349
+ setPlanInfo(analyticsPageInfo);
4350
+ }
4351
+ }, [analyticsPageInfo]);
4352
+ const planWindowMs = planInfo !== void 0 ? planInfo.currentLookbackDays * DAY_MS : void 0;
4353
+ const [scrollRoot, setScrollRoot] = reactExports.useState(null);
4354
+ const sentinelRef = useLoadMoreOnScroll(loadMore, {
4355
+ hasMore,
4356
+ isLoadingMore,
4357
+ root: scrollRoot
2904
4358
  });
2905
4359
  const selection = useTableSelection({
2906
4360
  getItemId: (run) => run.runId
2907
4361
  });
2908
- const runs = data.data ?? [];
2909
4362
  const [isBulkCancelling, setIsBulkCancelling] = reactExports.useState(false);
2910
4363
  const [isBulkReenqueuing, setIsBulkReenqueuing] = reactExports.useState(false);
2911
- const isLocalAndHasMissingData = isLocal && (!localDataDirPath || !((_d = data == null ? void 0 : data.data) == null ? void 0 : _d.length));
4364
+ const isLocalAndHasMissingData = isLocal && (!localDataDirPath || !runs.length);
2912
4365
  reactExports.useEffect(() => {
2913
- if (data.data && data.data.length > 0) {
2914
- const newNames = new Set(data.data.map((run) => run.workflowName));
4366
+ if (runs.length > 0) {
4367
+ const newNames = new Set(runs.map((run) => run.workflowName));
2915
4368
  setSeenWorkflowNames((prev) => {
2916
4369
  const updated = new Set(prev);
2917
4370
  for (const name of newNames) {
@@ -2920,8 +4373,8 @@ function RunsTable({ onRunClick }) {
2920
4373
  return updated;
2921
4374
  });
2922
4375
  }
2923
- }, [data.data]);
2924
- const loading = data.isLoading;
4376
+ }, [runs]);
4377
+ const loading = isLoading;
2925
4378
  reactExports.useEffect(() => {
2926
4379
  if (!loading && !hasLoadedOnce) {
2927
4380
  setHasLoadedOnce(true);
@@ -2933,12 +4386,14 @@ function RunsTable({ onRunClick }) {
2933
4386
  const onReload = reactExports.useCallback(() => {
2934
4387
  setLastRefreshTime(() => /* @__PURE__ */ new Date());
2935
4388
  setHasLoadedOnce(false);
4389
+ refreshListingWindow();
2936
4390
  reload();
2937
- }, [reload]);
4391
+ }, [reload, refreshListingWindow]);
2938
4392
  const onRefresh = reactExports.useCallback(() => {
2939
4393
  setLastRefreshTime(() => /* @__PURE__ */ new Date());
4394
+ refreshListingWindow();
2940
4395
  refresh();
2941
- }, [refresh]);
4396
+ }, [refresh, refreshListingWindow]);
2942
4397
  const selectedRuns = reactExports.useMemo(() => {
2943
4398
  return runs.filter((run) => selection.selectedIds.has(run.runId));
2944
4399
  }, [runs, selection.selectedIds]);
@@ -2948,27 +4403,39 @@ function RunsTable({ onRunClick }) {
2948
4403
  );
2949
4404
  }, [selectedRuns]);
2950
4405
  const hasCancellableSelection = cancellableSelectedRuns.length > 0;
4406
+ const exceedsBulkCancelLimit = cancellableSelectedRuns.length > BULK_CANCEL_MAX_RUN_IDS;
2951
4407
  const handleBulkCancel = reactExports.useCallback(async () => {
2952
- if (isBulkCancelling || cancellableSelectedRuns.length === 0) return;
4408
+ if (isBulkCancelling || cancellableSelectedRuns.length === 0 || cancellableSelectedRuns.length > BULK_CANCEL_MAX_RUN_IDS) {
4409
+ return;
4410
+ }
2953
4411
  setIsBulkCancelling(true);
2954
4412
  try {
2955
- const results = await Promise.allSettled(
2956
- cancellableSelectedRuns.map((run) => cancelRun(env, run.runId))
4413
+ const { summary, results } = await bulkCancelRuns(
4414
+ env,
4415
+ cancellableSelectedRuns.map((run) => run.runId)
2957
4416
  );
2958
- const succeeded = results.filter((r) => r.status === "fulfilled").length;
2959
- const failed = results.filter((r) => r.status === "rejected").length;
2960
- if (failed === 0) {
2961
- toast.success(
2962
- `Cancelled ${succeeded} run${succeeded !== 1 ? "s" : ""}`
2963
- );
2964
- } else if (succeeded === 0) {
2965
- toast.error(`Failed to cancel ${failed} run${failed !== 1 ? "s" : ""}`);
4417
+ const parts = [];
4418
+ if (summary.cancelled > 0) parts.push(`${summary.cancelled} cancelled`);
4419
+ if (summary.alreadyCancelled > 0)
4420
+ parts.push(`${summary.alreadyCancelled} already cancelled`);
4421
+ if (summary.notCancellable > 0)
4422
+ parts.push(`${summary.notCancellable} not cancellable`);
4423
+ if (summary.notFound > 0) parts.push(`${summary.notFound} not found`);
4424
+ if (summary.failed > 0) parts.push(`${summary.failed} failed`);
4425
+ const message = parts.join(", ") || "No runs cancelled";
4426
+ const severity = bulkCancelToastSeverity(summary);
4427
+ if (severity === "error") {
4428
+ toast.error(message);
4429
+ } else if (severity === "warning") {
4430
+ toast.warning(message);
2966
4431
  } else {
2967
- toast.warning(
2968
- `Cancelled ${succeeded} run${succeeded !== 1 ? "s" : ""}, ${failed} failed`
2969
- );
4432
+ toast.success(message);
4433
+ }
4434
+ for (const result of results) {
4435
+ if (!shouldRetainSelectionAfterBulkCancel(result)) {
4436
+ selection.deselectById(result.runId);
4437
+ }
2970
4438
  }
2971
- selection.clearSelection();
2972
4439
  onReload();
2973
4440
  } catch (err) {
2974
4441
  toast.error("Failed to cancel runs", {
@@ -3045,120 +4512,122 @@ function RunsTable({ onRunClick }) {
3045
4512
  seenWorkflowNames,
3046
4513
  sortOrder,
3047
4514
  loading,
3048
- statusFilterRequiresWorkflowNameFilter,
4515
+ period,
4516
+ showPeriodPicker: isVercelBackend,
4517
+ planWindowMs,
4518
+ planUpgradeAvailable: (planInfo == null ? void 0 : planInfo.upgradeAvailable) ?? false,
3049
4519
  onWorkflowChange: handleWorkflowFilter,
3050
4520
  onStatusChange: handleStatusFilter,
4521
+ onPeriodChange: handlePeriodFilter,
3051
4522
  onSortToggle: toggleSortOrder,
3052
4523
  onRefresh: onReload,
3053
4524
  lastRefreshTime
3054
4525
  }
3055
4526
  ),
3056
- /* @__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: [
3057
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(TableRow, { children: [
3058
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3059
- Checkbox,
3060
- {
3061
- checked: selection.isAllSelected(runs),
3062
- indeterminate: selection.isSomeSelected(runs),
3063
- onCheckedChange: () => selection.toggleSelectAll(runs),
3064
- "aria-label": "Select all runs",
3065
- disabled: !runs.length
3066
- }
3067
- ) }),
3068
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Workflow" }),
3069
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Run ID" }),
3070
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Status" }),
3071
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Started" }),
3072
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Completed" }),
3073
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10" })
3074
- ] }) }),
3075
- /* @__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: [
3076
- /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
3077
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error loading runs" }),
3078
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
3079
- ] }) }) }) }) : 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: [
3080
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm", children: [
3081
- "No workflow runs found",
3082
- isLocalAndHasMissingData ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3083
- " in ",
3084
- localDirText
3085
- ] }) : "",
3086
- "."
3087
- ] }),
3088
- isLocalAndHasMissingData && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm flex items-center gap-2", children: "This view will update once you run a workflow." })
3089
- ] }) }) }) : runs.map((run) => {
3090
- var _a2;
3091
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
3092
- TableRow,
3093
- {
3094
- className: "cursor-pointer group relative",
3095
- onClick: () => onRunClick(run.runId),
3096
- "data-selected": selection.isSelected(run),
3097
- children: [
3098
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4527
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "overflow-hidden mt-4 bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4528
+ CardContent,
4529
+ {
4530
+ ref: setScrollRoot,
4531
+ className: "p-0 max-h-[calc(100vh-280px)] overflow-auto",
4532
+ children: [
4533
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Table, { children: [
4534
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(TableRow, { children: [
4535
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3099
4536
  Checkbox,
3100
4537
  {
3101
- checked: selection.isSelected(run),
3102
- onCheckedChange: () => selection.toggleSelection(run),
3103
- "aria-label": `Select run ${run.runId}`
4538
+ checked: selection.isAllSelected(runs),
4539
+ indeterminate: selection.isSomeSelected(runs),
4540
+ onCheckedChange: () => selection.toggleSelectAll(runs),
4541
+ "aria-label": "Select all runs",
4542
+ disabled: !runs.length
3104
4543
  }
3105
4544
  ) }),
3106
- /* @__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) || "?" }) }),
3107
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: run.runId, overlay: true, children: run.runId }) }),
3108
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3109
- StatusBadge,
3110
- {
3111
- status: run.status,
3112
- context: run,
3113
- durationMs: run.startedAt ? (run.completedAt ? new Date(run.completedAt).getTime() : Date.now()) - new Date(run.startedAt).getTime() : void 0
3114
- }
3115
- ) }),
3116
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: run.startedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.startedAt }) : "-" }),
3117
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: run.completedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.completedAt }) : "-" }),
3118
- /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3119
- LazyDropdownMenu,
3120
- {
3121
- env,
3122
- runId: run.runId,
3123
- runStatus: run.status,
3124
- onSuccess: onReload
3125
- }
3126
- ) })
3127
- ]
3128
- },
3129
- run.runId
3130
- );
3131
- }) })
3132
- ] }) }) }),
3133
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mt-4", children: [
3134
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-muted-foreground", children: pageInfo }),
3135
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 items-center", children: [
3136
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
3137
- Button,
3138
- {
3139
- variant: "outline",
3140
- size: "sm",
3141
- onClick: previousPage,
3142
- disabled: !hasPreviousPage,
3143
- children: [
3144
- /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, {}),
3145
- "Previous"
3146
- ]
3147
- }
3148
- ),
3149
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
3150
- Button,
3151
- {
3152
- variant: "outline",
3153
- size: "sm",
3154
- onClick: nextPage,
3155
- disabled: !hasNextPage,
3156
- children: [
3157
- "Next",
3158
- /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, {})
3159
- ]
3160
- }
3161
- )
4545
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Workflow" }),
4546
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Run ID" }),
4547
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Status" }),
4548
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Started" }),
4549
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10", children: "Completed" }),
4550
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableHead, { className: "sticky top-0 bg-background z-10 border-b shadow-sm h-10 w-10" })
4551
+ ] }) }),
4552
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(TableBody, { children: [
4553
+ 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: [
4554
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
4555
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: getErrorTitle(error, "Error loading runs") }),
4556
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: getErrorMessage(error) })
4557
+ ] }) }) }) }) : 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" }) }) }) }) : runs.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: [
4558
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm", children: [
4559
+ "No workflow runs found",
4560
+ isLocalAndHasMissingData ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4561
+ " in ",
4562
+ localDirText
4563
+ ] }) : "",
4564
+ "."
4565
+ ] }),
4566
+ isLocalAndHasMissingData && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm flex items-center gap-2", children: "This view will update once you run a workflow." })
4567
+ ] }) }) }) : runs.map((run) => {
4568
+ var _a2;
4569
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
4570
+ TableRow,
4571
+ {
4572
+ className: "cursor-pointer group relative",
4573
+ onClick: () => onRunClick(run.runId),
4574
+ "data-selected": selection.isSelected(run),
4575
+ children: [
4576
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4577
+ Checkbox,
4578
+ {
4579
+ checked: selection.isSelected(run),
4580
+ onCheckedChange: () => selection.toggleSelection(run),
4581
+ "aria-label": `Select run ${run.runId}`
4582
+ }
4583
+ ) }),
4584
+ /* @__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) || "?" }) }),
4585
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "font-mono text-xs py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableText, { text: run.runId, overlay: true, children: run.runId }) }),
4586
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4587
+ StatusBadge,
4588
+ {
4589
+ status: run.status,
4590
+ context: run,
4591
+ durationMs: run.startedAt ? (run.completedAt ? new Date(run.completedAt).getTime() : Date.now()) - new Date(run.startedAt).getTime() : void 0
4592
+ }
4593
+ ) }),
4594
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: run.startedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.startedAt }) : "-" }),
4595
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2 text-muted-foreground text-xs", children: run.completedAt ? /* @__PURE__ */ jsxRuntimeExports.jsx(RelativeTime, { date: run.completedAt }) : "-" }),
4596
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { className: "py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4597
+ LazyDropdownMenu,
4598
+ {
4599
+ env,
4600
+ runId: run.runId,
4601
+ runStatus: run.status,
4602
+ onSuccess: onReload
4603
+ }
4604
+ ) })
4605
+ ]
4606
+ },
4607
+ run.runId
4608
+ );
4609
+ }),
4610
+ isLoadingMore && /* @__PURE__ */ jsxRuntimeExports.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(TableCell, { colSpan: 7, className: "py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center gap-2 text-sm text-muted-foreground", children: [
4611
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" }),
4612
+ "Loading more runs…"
4613
+ ] }) }) })
4614
+ ] })
4615
+ ] }),
4616
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: sentinelRef, "aria-hidden": true, className: "h-px" })
4617
+ ]
4618
+ }
4619
+ ) }),
4620
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mt-4 text-sm text-muted-foreground", children: [
4621
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: runs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4622
+ "Showing ",
4623
+ runs.length,
4624
+ " run",
4625
+ runs.length === 1 ? "" : "s",
4626
+ !hasMore && !loading ? " · end of list" : ""
4627
+ ] }) }),
4628
+ isVercelBackend && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4629
+ periodPreset.label,
4630
+ (planInfo == null ? void 0 : planInfo.upgradeAvailable) ? ` · plan window ${planInfo.currentLookbackDays} day${planInfo.currentLookbackDays === 1 ? "" : "s"}` : ""
3162
4631
  ] })
3163
4632
  ] }),
3164
4633
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -3185,23 +4654,26 @@ function RunsTable({ onRunClick }) {
3185
4654
  ) }),
3186
4655
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-enqueue the workflow orchestration layer for selected runs. Useful if workflows appear stuck." })
3187
4656
  ] }),
3188
- hasCancellableSelection && /* @__PURE__ */ jsxRuntimeExports.jsxs(
3189
- Button,
3190
- {
3191
- variant: "ghost",
3192
- size: "sm",
3193
- className: "h-7 text-primary-foreground hover:bg-primary-foreground/10 hover:text-primary-foreground",
3194
- onClick: handleBulkCancel,
3195
- disabled: isBulkCancelling,
3196
- children: [
3197
- 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" }),
3198
- "Cancel",
3199
- " ",
3200
- cancellableSelectedRuns.length !== selection.selectionCount ? `${cancellableSelectedRuns.length} ` : "",
3201
- isBulkCancelling ? "cancelling..." : ""
3202
- ]
3203
- }
3204
- )
4657
+ hasCancellableSelection && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
4658
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4659
+ Button,
4660
+ {
4661
+ variant: "ghost",
4662
+ size: "sm",
4663
+ className: "h-7 text-primary-foreground hover:bg-primary-foreground/10 hover:text-primary-foreground",
4664
+ onClick: handleBulkCancel,
4665
+ disabled: isBulkCancelling || exceedsBulkCancelLimit,
4666
+ children: [
4667
+ 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" }),
4668
+ "Cancel",
4669
+ " ",
4670
+ cancellableSelectedRuns.length !== selection.selectionCount ? `${cancellableSelectedRuns.length} ` : "",
4671
+ isBulkCancelling ? "cancelling..." : ""
4672
+ ]
4673
+ }
4674
+ ) }) }),
4675
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: exceedsBulkCancelLimit ? `Select up to ${BULK_CANCEL_MAX_RUN_IDS} runs at a time.` : "Cancel the selected pending and running runs." })
4676
+ ] })
3205
4677
  ] })
3206
4678
  }
3207
4679
  )