@hot-updater/console 0.31.4 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/dist-BzU1qUss.js +9 -0
- package/.output/public/assets/main-CmNeAg9B.js +10 -0
- package/.output/public/assets/routes-wJZuGodi.js +54 -0
- package/.output/public/assets/styles-DEbMLh52.css +2 -0
- package/.output/server/{__tanstack-start-server-fn-resolver-5wPQ8bZ3.mjs → __tanstack-start-server-fn-resolver-ySzPUDlM.mjs} +13 -13
- package/.output/server/_chunks/ssr-renderer.mjs +2 -2
- package/.output/server/_libs/@tanstack/react-form+[...].mjs +5 -5
- package/.output/server/_libs/lucide-react.mjs +46 -1
- package/.output/server/_libs/unctx.mjs +1 -1
- package/.output/server/_ssr/{api-rpc-BhBKhZqY.mjs → api-rpc-Bwustks9.mjs} +2 -2
- package/.output/server/_ssr/{deleteBundle-D4jF5HeY.mjs → deleteBundle-CXxwjwEZ.mjs} +30 -11
- package/.output/server/_ssr/{router-SkApCyud.mjs → router-1tw3jh6y.mjs} +8 -5
- package/.output/server/_ssr/{routes-BSs-dv4D.mjs → routes-D5CmWxI7.mjs} +544 -269
- package/.output/server/_ssr/sidebar-CgbtXkE2.mjs +1 -1
- package/.output/server/_ssr/ssr.mjs +4 -4
- package/.output/server/_ssr/start-CoRKunFF.mjs +4 -0
- package/.output/server/{_tanstack-start-manifest_v-D2MqgD3d.mjs → _tanstack-start-manifest_v-AftZl081.mjs} +5 -5
- package/.output/server/index.mjs +66 -66
- package/package.json +7 -7
- package/.output/public/assets/dist-B5egZOkC.js +0 -9
- package/.output/public/assets/main-DrVuFR7r.js +0 -10
- package/.output/public/assets/routes-C_bgs7kg.js +0 -54
- package/.output/public/assets/styles-DZ0tCVA1.css +0 -2
- package/.output/server/_ssr/start-D0X4LIsd.mjs +0 -4
|
@@ -3,7 +3,7 @@ import { c as createServerFn, i as TSS_SERVER_FUNCTION } from "./createServerFn-
|
|
|
3
3
|
import { c as getPatchBaseFileHash, d as isValidCohort, f as normalizeCohortValue, l as getPatchFileHash, n as NUMERIC_COHORT_SIZE, o as getNumericCohortRolloutPosition, p as normalizeRolloutCohortCount, s as getPatchBaseBundleId, t as INVALID_COHORT_ERROR_MESSAGE } from "./dist-CRiLZLfa.mjs";
|
|
4
4
|
import { A as Slot, P as require_jsx_runtime, a as Overlay2, c as Title2, d as Description, f as Overlay, g as Trigger, h as Title, i as Description2, l as Close, m as Root, n as Cancel, o as Portal2, p as Portal, r as Content2, s as Root2, t as Action, u as Content } from "../_libs/@radix-ui/react-alert-dialog+[...].mjs";
|
|
5
5
|
import { u as require_react } from "../_libs/@floating-ui/react-dom+[...].mjs";
|
|
6
|
-
import { C as ArrowRight, S as
|
|
6
|
+
import { C as ChevronLeft, E as ArrowRight, S as ChevronRight, T as Check, _ as ExternalLink, a as RotateCcw, b as CircleCheck, c as Package, d as Minus, f as LoaderCircle, g as FingerprintPattern, h as Funnel, n as TriangleAlert, o as Plus, p as List, r as Trash2, t as X, v as Download, w as ChevronDown, x as ChevronUp, y as CircleX } from "../_libs/lucide-react.mjs";
|
|
7
7
|
import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
|
|
8
8
|
import { a as ItemText, c as ScrollDownButton, d as Value, f as Viewport, i as ItemIndicator, l as ScrollUpButton, n as Icon, o as Portal$1, r as Item, s as Root2$1, t as Content2$1, u as Trigger$1 } from "../_libs/@radix-ui/react-select+[...].mjs";
|
|
9
9
|
import { t as Root$1 } from "../_libs/radix-ui__react-label.mjs";
|
|
@@ -14,11 +14,11 @@ import { d as useNavigate, f as useSearch } from "../_libs/@tanstack/react-route
|
|
|
14
14
|
import { n as useStore, t as useForm } from "../_libs/@tanstack/react-form+[...].mjs";
|
|
15
15
|
import { i as useQueryClient, n as useQuery, t as useMutation } from "../_libs/tanstack__react-query.mjs";
|
|
16
16
|
import { n as toast } from "../_libs/sonner.mjs";
|
|
17
|
-
import { t as getServerFnById } from "../__tanstack-start-server-fn-resolver-
|
|
17
|
+
import { t as getServerFnById } from "../__tanstack-start-server-fn-resolver-ySzPUDlM.mjs";
|
|
18
18
|
import { t as require_semver } from "../_libs/semver.mjs";
|
|
19
19
|
import { i as getCoreRowModel, n as useReactTable, r as createColumnHelper, t as flexRender } from "../_libs/@tanstack/react-table+[...].mjs";
|
|
20
20
|
import { n as require_dayjs_min, t as require_relativeTime } from "../_libs/dayjs.mjs";
|
|
21
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/routes-
|
|
21
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/routes-D5CmWxI7.js
|
|
22
22
|
var import_jsx_runtime = require_jsx_runtime();
|
|
23
23
|
var import_semver = /* @__PURE__ */ __toESM(require_semver());
|
|
24
24
|
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
@@ -441,6 +441,17 @@ function replaceBundleInQueryData(data, updatedBundle) {
|
|
|
441
441
|
data: data.data.map((bundle) => bundle.id === updatedBundle.id ? updatedBundle : bundle)
|
|
442
442
|
};
|
|
443
443
|
}
|
|
444
|
+
function removeBundleFromQueryData(data, bundleId) {
|
|
445
|
+
if (!data) return data;
|
|
446
|
+
return {
|
|
447
|
+
...data,
|
|
448
|
+
data: data.data.filter((bundle) => bundle.id !== bundleId)
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
var hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
452
|
+
var invalidateInBackground = (queryClient, queryKey) => {
|
|
453
|
+
queryClient.invalidateQueries({ queryKey }).catch(() => void 0);
|
|
454
|
+
};
|
|
444
455
|
function useConfigQuery() {
|
|
445
456
|
return useQuery({
|
|
446
457
|
queryKey: queryKeys.config,
|
|
@@ -495,15 +506,12 @@ function useUpdateBundleMutation() {
|
|
|
495
506
|
const queryClient = useQueryClient();
|
|
496
507
|
return useMutation({
|
|
497
508
|
mutationFn: (params) => updateBundle({ data: params }),
|
|
498
|
-
onSuccess:
|
|
509
|
+
onSuccess: ({ bundle: updatedBundle }, vars) => {
|
|
499
510
|
queryClient.setQueryData(queryKeys.bundle(vars.bundleId), updatedBundle);
|
|
500
511
|
queryClient.setQueriesData({ queryKey: queryKeys.bundles.all }, (data) => replaceBundleInQueryData(data, updatedBundle));
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
queryClient.invalidateQueries({ queryKey: queryKeys.bundle(vars.bundleId) }),
|
|
505
|
-
queryClient.invalidateQueries({ queryKey: queryKeys.channels })
|
|
506
|
-
]);
|
|
512
|
+
invalidateInBackground(queryClient, queryKeys.bundles.all);
|
|
513
|
+
if (hasOwn(vars.bundle, "patches") || hasOwn(vars.bundle, "channel") || hasOwn(vars.bundle, "platform")) invalidateInBackground(queryClient, queryKeys.bundleChildren.all);
|
|
514
|
+
if (hasOwn(vars.bundle, "channel")) invalidateInBackground(queryClient, queryKeys.channels);
|
|
507
515
|
}
|
|
508
516
|
});
|
|
509
517
|
}
|
|
@@ -528,6 +536,7 @@ function useDeleteBundleMutation() {
|
|
|
528
536
|
mutationFn: (params) => deleteBundle({ data: params }),
|
|
529
537
|
onSuccess: async (_, vars) => {
|
|
530
538
|
queryClient.removeQueries({ queryKey: queryKeys.bundle(vars.bundleId) });
|
|
539
|
+
queryClient.setQueriesData({ queryKey: queryKeys.bundles.all }, (data) => removeBundleFromQueryData(data, vars.bundleId));
|
|
531
540
|
await Promise.all([
|
|
532
541
|
queryClient.invalidateQueries({ queryKey: queryKeys.bundles.all }),
|
|
533
542
|
queryClient.invalidateQueries({ queryKey: queryKeys.bundleChildren.all }),
|
|
@@ -2296,6 +2305,209 @@ var createBundleColumns = ({ expandedBundleId, patchCountsByBundleId, onDetailCl
|
|
|
2296
2305
|
cell: (info) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimestampDisplay, { uuid: info.getValue() })
|
|
2297
2306
|
})
|
|
2298
2307
|
];
|
|
2308
|
+
var statusLabels = {
|
|
2309
|
+
queued: "Queued",
|
|
2310
|
+
deleting: "Deleting",
|
|
2311
|
+
deleted: "Deleted",
|
|
2312
|
+
failed: "Failed"
|
|
2313
|
+
};
|
|
2314
|
+
var getDeleteErrorMessage = (error) => error instanceof Error ? error.message : "Delete request failed";
|
|
2315
|
+
var createDeleteItems = (bundles) => bundles.map((bundle) => ({
|
|
2316
|
+
bundle,
|
|
2317
|
+
status: "queued"
|
|
2318
|
+
}));
|
|
2319
|
+
function getStatusIcon(status) {
|
|
2320
|
+
switch (status) {
|
|
2321
|
+
case "failed": return {
|
|
2322
|
+
className: "size-3.5 text-destructive",
|
|
2323
|
+
Icon: CircleX
|
|
2324
|
+
};
|
|
2325
|
+
case "deleting": return {
|
|
2326
|
+
className: "size-3.5 animate-spin text-primary",
|
|
2327
|
+
Icon: LoaderCircle
|
|
2328
|
+
};
|
|
2329
|
+
case "deleted": return {
|
|
2330
|
+
className: "size-3.5 text-primary",
|
|
2331
|
+
Icon: CircleCheck
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
function DeleteStatusIcon({ status }) {
|
|
2336
|
+
if (status === "queued") return null;
|
|
2337
|
+
const label = statusLabels[status];
|
|
2338
|
+
const { className, Icon } = getStatusIcon(status);
|
|
2339
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Tooltip$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipTrigger, {
|
|
2340
|
+
asChild: true,
|
|
2341
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2342
|
+
"aria-label": label,
|
|
2343
|
+
role: "img",
|
|
2344
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className })
|
|
2345
|
+
})
|
|
2346
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipContent, { children: label })] });
|
|
2347
|
+
}
|
|
2348
|
+
function SelectedBundlesDeleteDialog({ bundles, open, onOpenChange, onComplete }) {
|
|
2349
|
+
const deleteBundleMutation = useDeleteBundleMutation();
|
|
2350
|
+
const [phase, setPhase] = (0, import_react.useState)("confirming");
|
|
2351
|
+
const [items, setItems] = (0, import_react.useState)(() => createDeleteItems(bundles));
|
|
2352
|
+
const isDeleting = phase === "deleting";
|
|
2353
|
+
const totalCount = items.length;
|
|
2354
|
+
const activeCount = items.filter((item) => item.status === "deleted").length + items.filter((item) => item.status === "failed").length;
|
|
2355
|
+
const failedBundleIds = items.filter((item) => item.status === "failed").map((item) => item.bundle.id);
|
|
2356
|
+
const hasFailures = failedBundleIds.length > 0;
|
|
2357
|
+
const title = phase === "confirming" ? "Delete selected bundles?" : "Deleting bundles";
|
|
2358
|
+
const description = phase === "confirming" ? `This action cannot be undone. This will permanently delete ${bundles.length} bundles and remove them from storage.` : `${activeCount} of ${totalCount} delete requests finished.`;
|
|
2359
|
+
const deleteButtonLabel = (0, import_react.useMemo)(() => {
|
|
2360
|
+
if (!isDeleting) return "Delete";
|
|
2361
|
+
return `Deleting ${Math.min(activeCount + 1, totalCount)}/${totalCount}`;
|
|
2362
|
+
}, [
|
|
2363
|
+
activeCount,
|
|
2364
|
+
isDeleting,
|
|
2365
|
+
totalCount
|
|
2366
|
+
]);
|
|
2367
|
+
(0, import_react.useEffect)(() => {
|
|
2368
|
+
if (open && phase === "confirming") setItems(createDeleteItems(bundles));
|
|
2369
|
+
}, [
|
|
2370
|
+
bundles,
|
|
2371
|
+
open,
|
|
2372
|
+
phase
|
|
2373
|
+
]);
|
|
2374
|
+
const handleOpenChange = (nextOpen) => {
|
|
2375
|
+
if (!nextOpen && isDeleting) return;
|
|
2376
|
+
onOpenChange(nextOpen);
|
|
2377
|
+
if (!nextOpen) {
|
|
2378
|
+
setPhase("confirming");
|
|
2379
|
+
setItems(createDeleteItems(bundles));
|
|
2380
|
+
}
|
|
2381
|
+
};
|
|
2382
|
+
const runDeletion = async (bundleIds) => {
|
|
2383
|
+
if (isDeleting || bundleIds.length === 0) return;
|
|
2384
|
+
const bundleIdSet = new Set(bundleIds);
|
|
2385
|
+
const deletedBundleIds = [];
|
|
2386
|
+
const nextFailedBundleIds = [];
|
|
2387
|
+
setPhase("deleting");
|
|
2388
|
+
setItems((currentItems) => currentItems.map((item) => bundleIdSet.has(item.bundle.id) ? {
|
|
2389
|
+
bundle: item.bundle,
|
|
2390
|
+
status: "queued"
|
|
2391
|
+
} : item));
|
|
2392
|
+
for (const bundleId of bundleIds) {
|
|
2393
|
+
setItems((currentItems) => currentItems.map((item) => item.bundle.id === bundleId ? {
|
|
2394
|
+
bundle: item.bundle,
|
|
2395
|
+
status: "deleting"
|
|
2396
|
+
} : item));
|
|
2397
|
+
try {
|
|
2398
|
+
await deleteBundleMutation.mutateAsync({ bundleId });
|
|
2399
|
+
deletedBundleIds.push(bundleId);
|
|
2400
|
+
setItems((currentItems) => currentItems.map((item) => item.bundle.id === bundleId ? {
|
|
2401
|
+
bundle: item.bundle,
|
|
2402
|
+
status: "deleted"
|
|
2403
|
+
} : item));
|
|
2404
|
+
} catch (error) {
|
|
2405
|
+
nextFailedBundleIds.push(bundleId);
|
|
2406
|
+
setItems((currentItems) => currentItems.map((item) => item.bundle.id === bundleId ? {
|
|
2407
|
+
bundle: item.bundle,
|
|
2408
|
+
message: getDeleteErrorMessage(error),
|
|
2409
|
+
status: "failed"
|
|
2410
|
+
} : item));
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
setPhase("complete");
|
|
2414
|
+
onComplete({
|
|
2415
|
+
deletedBundleIds,
|
|
2416
|
+
failedBundleIds: nextFailedBundleIds
|
|
2417
|
+
});
|
|
2418
|
+
if (nextFailedBundleIds.length > 0) {
|
|
2419
|
+
toast.error(`${deletedBundleIds.length} deleted, ${nextFailedBundleIds.length} failed`);
|
|
2420
|
+
return;
|
|
2421
|
+
}
|
|
2422
|
+
toast.success(`${deletedBundleIds.length} bundles deleted successfully`);
|
|
2423
|
+
};
|
|
2424
|
+
const handleDelete = () => {
|
|
2425
|
+
runDeletion(items.map((item) => item.bundle.id));
|
|
2426
|
+
};
|
|
2427
|
+
const handleRetryFailed = () => {
|
|
2428
|
+
runDeletion(failedBundleIds);
|
|
2429
|
+
};
|
|
2430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
|
|
2431
|
+
open,
|
|
2432
|
+
onOpenChange: handleOpenChange,
|
|
2433
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogContent, {
|
|
2434
|
+
showCloseButton: !isDeleting,
|
|
2435
|
+
className: "sm:max-w-lg",
|
|
2436
|
+
onEscapeKeyDown: (event) => {
|
|
2437
|
+
if (isDeleting) event.preventDefault();
|
|
2438
|
+
},
|
|
2439
|
+
onInteractOutside: (event) => {
|
|
2440
|
+
if (isDeleting) event.preventDefault();
|
|
2441
|
+
},
|
|
2442
|
+
children: [
|
|
2443
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: title }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, { children: description })] }),
|
|
2444
|
+
phase === "confirming" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
|
|
2445
|
+
className: "max-h-[50vh] overflow-y-auto p-0",
|
|
2446
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Table, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHeader, {
|
|
2447
|
+
className: "sticky top-0 bg-card",
|
|
2448
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
|
|
2449
|
+
className: "w-12 text-center",
|
|
2450
|
+
children: "Status"
|
|
2451
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, { children: "Bundle" })] })
|
|
2452
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2453
|
+
className: "text-center align-middle",
|
|
2454
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2455
|
+
className: "flex justify-center",
|
|
2456
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeleteStatusIcon, { status: item.status })
|
|
2457
|
+
})
|
|
2458
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2459
|
+
className: "whitespace-normal",
|
|
2460
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2461
|
+
className: "min-w-0",
|
|
2462
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2463
|
+
className: "break-all font-mono text-[11px] text-foreground",
|
|
2464
|
+
children: item.bundle.id
|
|
2465
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2466
|
+
className: "mt-0.5 flex flex-wrap gap-x-2 gap-y-1 text-[11px] text-muted-foreground",
|
|
2467
|
+
children: [
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item.bundle.channel }),
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item.bundle.platform }),
|
|
2470
|
+
item.message ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2471
|
+
className: "text-destructive",
|
|
2472
|
+
children: item.message
|
|
2473
|
+
}) : null
|
|
2474
|
+
]
|
|
2475
|
+
})]
|
|
2476
|
+
})
|
|
2477
|
+
})] }, item.bundle.id)) })] })
|
|
2478
|
+
}) }),
|
|
2479
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogFooter, { children: [
|
|
2480
|
+
phase === "confirming" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
2481
|
+
variant: "outline",
|
|
2482
|
+
onClick: () => handleOpenChange(false),
|
|
2483
|
+
children: "Cancel"
|
|
2484
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2485
|
+
variant: "destructive",
|
|
2486
|
+
onClick: handleDelete,
|
|
2487
|
+
disabled: totalCount === 0,
|
|
2488
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { "data-icon": "inline-start" }), "Delete"]
|
|
2489
|
+
})] }) : null,
|
|
2490
|
+
phase === "deleting" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2491
|
+
variant: "destructive",
|
|
2492
|
+
disabled: true,
|
|
2493
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, {
|
|
2494
|
+
"data-icon": "inline-start",
|
|
2495
|
+
className: "animate-spin"
|
|
2496
|
+
}), deleteButtonLabel]
|
|
2497
|
+
}) : null,
|
|
2498
|
+
phase === "complete" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
2499
|
+
variant: "outline",
|
|
2500
|
+
onClick: () => handleOpenChange(false),
|
|
2501
|
+
children: "Close"
|
|
2502
|
+
}), hasFailures ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2503
|
+
onClick: handleRetryFailed,
|
|
2504
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCcw, { "data-icon": "inline-start" }), "Retry failed"]
|
|
2505
|
+
}) : null] }) : null
|
|
2506
|
+
] })
|
|
2507
|
+
]
|
|
2508
|
+
})
|
|
2509
|
+
});
|
|
2510
|
+
}
|
|
2299
2511
|
function MobileStatusBadge({ enabled, trueLabel, falseLabel, falseIcon = "x", trueTone = "success" }) {
|
|
2300
2512
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
2301
2513
|
className: cn("inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium", enabled ? trueTone === "warning" ? "bg-amber-500/14 text-amber-700 dark:text-amber-300" : "bg-emerald-500/12 text-emerald-700 dark:text-emerald-300" : falseIcon === "minus" ? "bg-muted text-muted-foreground" : "bg-red-500/12 text-red-700 dark:text-red-300"),
|
|
@@ -2310,8 +2522,13 @@ function MobileStatusBadge({ enabled, trueLabel, falseLabel, falseIcon = "x", tr
|
|
|
2310
2522
|
function BundlesTable({ bundles, pagination, expandedBundleId, selectedBundleId, onExpandedBundleChange, onDetailClick }) {
|
|
2311
2523
|
const { setFilters } = useFilterParams();
|
|
2312
2524
|
const isMobile = useIsMobile();
|
|
2525
|
+
const [selectedBundleIds, setSelectedBundleIds] = (0, import_react.useState)([]);
|
|
2526
|
+
const [deleteDialogOpen, setDeleteDialogOpen] = (0, import_react.useState)(false);
|
|
2313
2527
|
const cursorPagination = pagination;
|
|
2314
|
-
const
|
|
2528
|
+
const bundleIds = bundles.map((bundle) => bundle.id);
|
|
2529
|
+
const selectedBundles = bundles.filter((bundle) => selectedBundleIds.includes(bundle.id));
|
|
2530
|
+
const allBundlesSelected = bundles.length > 0 && selectedBundles.length === bundles.length;
|
|
2531
|
+
const { data: patchCountsByBundleId = {} } = useBundleChildCountsQuery(bundleIds);
|
|
2315
2532
|
const { data: childBundles = [], isLoading: isChildBundlesLoading } = useBundleChildrenQuery(expandedBundleId ?? "");
|
|
2316
2533
|
const bundleColumns = createBundleColumns({
|
|
2317
2534
|
expandedBundleId,
|
|
@@ -2346,280 +2563,338 @@ function BundlesTable({ bundles, pagination, expandedBundleId, selectedBundleId,
|
|
|
2346
2563
|
before: void 0
|
|
2347
2564
|
});
|
|
2348
2565
|
};
|
|
2566
|
+
const toggleBundleSelection = (bundleId) => {
|
|
2567
|
+
setSelectedBundleIds((current) => current.includes(bundleId) ? current.filter((selectedBundleId) => selectedBundleId !== bundleId) : [...current, bundleId]);
|
|
2568
|
+
};
|
|
2569
|
+
const handleToggleAllBundles = () => {
|
|
2570
|
+
setSelectedBundleIds(allBundlesSelected ? [] : bundleIds);
|
|
2571
|
+
};
|
|
2349
2572
|
const startEntry = bundles.length === 0 ? 0 : (currentPage - 1) * 20 + 1;
|
|
2350
2573
|
const endEntry = startEntry === 0 ? 0 : startEntry + bundles.length - 1;
|
|
2351
2574
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2352
|
-
className: "flex flex-col gap-4",
|
|
2353
|
-
children: [
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
className: "
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
})]
|
|
2386
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2387
|
-
className: "shrink-0",
|
|
2388
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChannelBadge, { channel: bundle.channel })
|
|
2389
|
-
})]
|
|
2390
|
-
}),
|
|
2391
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2392
|
-
className: "grid grid-cols-2 gap-3 text-sm",
|
|
2393
|
-
children: [
|
|
2394
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2395
|
-
className: "rounded-md bg-muted/40 p-3",
|
|
2396
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2397
|
-
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2398
|
-
children: "Platform"
|
|
2399
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2400
|
-
className: "flex items-center gap-2",
|
|
2401
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlatformIcon, {
|
|
2402
|
-
platform: bundle.platform,
|
|
2403
|
-
className: "h-4 w-4"
|
|
2404
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: bundle.platform === "ios" ? "iOS" : "Android" })]
|
|
2405
|
-
})]
|
|
2406
|
-
}),
|
|
2407
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2408
|
-
className: "rounded-md bg-muted/40 p-3",
|
|
2409
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2410
|
-
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2411
|
-
children: "Created"
|
|
2412
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2413
|
-
className: "text-xs text-foreground",
|
|
2414
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimestampDisplay, { uuid: bundle.id })
|
|
2415
|
-
})]
|
|
2416
|
-
}),
|
|
2417
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2418
|
-
className: "rounded-md bg-muted/40 p-3",
|
|
2419
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2420
|
-
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2421
|
-
children: "Rollout"
|
|
2422
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RolloutPercentageBadge, { percentage: rolloutPercentage })]
|
|
2423
|
-
}),
|
|
2424
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2425
|
-
className: "rounded-md bg-muted/40 p-3",
|
|
2575
|
+
className: "flex min-h-0 min-w-0 flex-1 flex-col gap-4",
|
|
2576
|
+
children: [
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2578
|
+
className: "min-h-0 min-w-0 flex-1 overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm [&_[data-slot=table-container]]:h-full [&_[data-slot=table-container]]:overflow-auto",
|
|
2579
|
+
children: isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2580
|
+
className: "flex h-full flex-col overflow-y-auto",
|
|
2581
|
+
children: bundles.length ? bundles.map((bundle) => {
|
|
2582
|
+
const isExpanded = bundle.id === expandedBundleId;
|
|
2583
|
+
const panelId = `bundle-lineage-panel-${bundle.id}`;
|
|
2584
|
+
const rolloutPercentage = (bundle.rolloutCohortCount ?? 1e3) / 10;
|
|
2585
|
+
const patchCount = patchCountsByBundleId[bundle.id];
|
|
2586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2587
|
+
"data-state": bundle.id === selectedBundleId ? "selected" : void 0,
|
|
2588
|
+
className: cn("border-b border-border/60 last:border-b-0 data-[state=selected]:bg-muted/20", isExpanded && "bg-primary/5"),
|
|
2589
|
+
children: [
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
2591
|
+
className: "flex items-center gap-2 border-b border-border/60 px-4 py-3 text-xs font-medium text-muted-foreground",
|
|
2592
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
2593
|
+
type: "checkbox",
|
|
2594
|
+
checked: selectedBundleIds.includes(bundle.id),
|
|
2595
|
+
className: "size-4 accent-primary",
|
|
2596
|
+
onChange: () => toggleBundleSelection(bundle.id)
|
|
2597
|
+
}), "Select bundle"]
|
|
2598
|
+
}),
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
2600
|
+
type: "button",
|
|
2601
|
+
className: "flex w-full flex-col gap-4 p-4 text-left",
|
|
2602
|
+
onClick: () => onDetailClick(bundle),
|
|
2603
|
+
children: [
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2605
|
+
className: "flex items-start justify-between gap-3",
|
|
2606
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2607
|
+
className: "min-w-0 space-y-2",
|
|
2426
2608
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2427
|
-
className: "
|
|
2428
|
-
children: "
|
|
2609
|
+
className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground/70",
|
|
2610
|
+
children: "Bundle"
|
|
2429
2611
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2430
|
-
className: "
|
|
2431
|
-
children:
|
|
2612
|
+
className: "min-w-0 text-sm font-medium",
|
|
2613
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2614
|
+
bundleId: bundle.id,
|
|
2615
|
+
maxLength: 18,
|
|
2616
|
+
fullOnMobile: true
|
|
2617
|
+
})
|
|
2432
2618
|
})]
|
|
2433
|
-
}),
|
|
2434
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2435
|
-
className: "rounded-md bg-muted/40 p-3",
|
|
2436
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2437
|
-
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2438
|
-
children: "Status"
|
|
2439
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2440
|
-
className: "flex flex-wrap items-center gap-2",
|
|
2441
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MobileStatusBadge, {
|
|
2442
|
-
enabled: bundle.enabled,
|
|
2443
|
-
trueLabel: "Enabled",
|
|
2444
|
-
falseLabel: "Disabled"
|
|
2445
|
-
}), bundle.shouldForceUpdate ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MobileStatusBadge, {
|
|
2446
|
-
enabled: bundle.shouldForceUpdate,
|
|
2447
|
-
trueLabel: "Force update",
|
|
2448
|
-
falseLabel: "Optional",
|
|
2449
|
-
falseIcon: "minus",
|
|
2450
|
-
trueTone: "warning"
|
|
2451
|
-
}) : null]
|
|
2452
|
-
})]
|
|
2453
|
-
})
|
|
2454
|
-
]
|
|
2455
|
-
}),
|
|
2456
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2457
|
-
className: "grid gap-2 rounded-md border border-border/70 bg-background/80 p-3 text-sm",
|
|
2458
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2459
|
-
className: "flex items-center justify-between gap-3",
|
|
2460
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2461
|
-
className: "text-muted-foreground",
|
|
2462
|
-
children: "Target"
|
|
2463
2619
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2464
|
-
className: "
|
|
2465
|
-
children:
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2620
|
+
className: "shrink-0",
|
|
2621
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChannelBadge, { channel: bundle.channel })
|
|
2622
|
+
})]
|
|
2623
|
+
}),
|
|
2624
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2625
|
+
className: "grid grid-cols-2 gap-3 text-sm",
|
|
2626
|
+
children: [
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2628
|
+
className: "rounded-md bg-muted/40 p-3",
|
|
2629
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2630
|
+
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2631
|
+
children: "Platform"
|
|
2632
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2633
|
+
className: "flex items-center gap-2",
|
|
2634
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlatformIcon, {
|
|
2635
|
+
platform: bundle.platform,
|
|
2636
|
+
className: "h-4 w-4"
|
|
2637
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: bundle.platform === "ios" ? "iOS" : "Android" })]
|
|
2638
|
+
})]
|
|
2639
|
+
}),
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2641
|
+
className: "rounded-md bg-muted/40 p-3",
|
|
2642
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2643
|
+
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2644
|
+
children: "Created"
|
|
2645
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2646
|
+
className: "text-xs text-foreground",
|
|
2647
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimestampDisplay, { uuid: bundle.id })
|
|
2648
|
+
})]
|
|
2649
|
+
}),
|
|
2650
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2651
|
+
className: "rounded-md bg-muted/40 p-3",
|
|
2652
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2653
|
+
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2654
|
+
children: "Rollout"
|
|
2655
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RolloutPercentageBadge, { percentage: rolloutPercentage })]
|
|
2656
|
+
}),
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2658
|
+
className: "rounded-md bg-muted/40 p-3",
|
|
2659
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2660
|
+
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2661
|
+
children: "Patches"
|
|
2662
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2663
|
+
className: "text-xs text-foreground",
|
|
2664
|
+
children: patchCount === void 0 ? "Checking" : patchCount > 0 ? `${patchCount} ${patchCount === 1 ? "patch" : "patches"}` : "-"
|
|
2665
|
+
})]
|
|
2666
|
+
}),
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2668
|
+
className: "rounded-md bg-muted/40 p-3",
|
|
2669
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2670
|
+
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2671
|
+
children: "Status"
|
|
2672
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2673
|
+
className: "flex flex-wrap items-center gap-2",
|
|
2674
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MobileStatusBadge, {
|
|
2675
|
+
enabled: bundle.enabled,
|
|
2676
|
+
trueLabel: "Enabled",
|
|
2677
|
+
falseLabel: "Disabled"
|
|
2678
|
+
}), bundle.shouldForceUpdate ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MobileStatusBadge, {
|
|
2679
|
+
enabled: bundle.shouldForceUpdate,
|
|
2680
|
+
trueLabel: "Force update",
|
|
2681
|
+
falseLabel: "Optional",
|
|
2682
|
+
falseIcon: "minus",
|
|
2683
|
+
trueTone: "warning"
|
|
2684
|
+
}) : null]
|
|
2471
2685
|
})]
|
|
2472
|
-
}) : bundle.targetAppVersion ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
2473
|
-
translate: "no",
|
|
2474
|
-
className: "inline-flex items-center gap-2 text-xs",
|
|
2475
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Package, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), bundle.targetAppVersion]
|
|
2476
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2477
|
-
className: "text-xs text-muted-foreground",
|
|
2478
|
-
children: "-"
|
|
2479
2686
|
})
|
|
2687
|
+
]
|
|
2688
|
+
}),
|
|
2689
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2690
|
+
className: "grid gap-2 rounded-md border border-border/70 bg-background/80 p-3 text-sm",
|
|
2691
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2692
|
+
className: "flex items-center justify-between gap-3",
|
|
2693
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2694
|
+
className: "text-muted-foreground",
|
|
2695
|
+
children: "Target"
|
|
2696
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2697
|
+
className: "min-w-0 text-right",
|
|
2698
|
+
children: bundle.fingerprintHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
2699
|
+
translate: "no",
|
|
2700
|
+
className: "inline-flex min-w-0 items-start gap-2 font-mono text-xs",
|
|
2701
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FingerprintPattern, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
2702
|
+
value: bundle.fingerprintHash,
|
|
2703
|
+
maxLength: 12
|
|
2704
|
+
})]
|
|
2705
|
+
}) : bundle.targetAppVersion ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
2706
|
+
translate: "no",
|
|
2707
|
+
className: "inline-flex items-center gap-2 text-xs",
|
|
2708
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Package, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), bundle.targetAppVersion]
|
|
2709
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2710
|
+
className: "text-xs text-muted-foreground",
|
|
2711
|
+
children: "-"
|
|
2712
|
+
})
|
|
2713
|
+
})]
|
|
2714
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2715
|
+
className: "flex items-start justify-between gap-3",
|
|
2716
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2717
|
+
className: "text-muted-foreground",
|
|
2718
|
+
children: "Message"
|
|
2719
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2720
|
+
className: "min-w-0 text-right text-xs text-foreground/80",
|
|
2721
|
+
children: bundle.message || "-"
|
|
2722
|
+
})]
|
|
2480
2723
|
})]
|
|
2481
|
-
})
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2724
|
+
})
|
|
2725
|
+
]
|
|
2726
|
+
}),
|
|
2727
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2728
|
+
className: "border-t border-border/60 px-4 py-3",
|
|
2729
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2730
|
+
type: "button",
|
|
2731
|
+
variant: "ghost",
|
|
2732
|
+
className: "h-9 w-full justify-between px-3 text-sm",
|
|
2733
|
+
"aria-label": isExpanded ? "Hide Lineage" : "Show Lineage",
|
|
2734
|
+
"aria-controls": panelId,
|
|
2735
|
+
"aria-expanded": isExpanded,
|
|
2736
|
+
onClick: () => onExpandedBundleChange(isExpanded ? void 0 : bundle.id),
|
|
2737
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: patchCount === void 0 ? "Patch lineage" : `Patch lineage (${patchCount})` }), isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUp, {
|
|
2738
|
+
className: "h-4 w-4",
|
|
2739
|
+
"aria-hidden": "true"
|
|
2740
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {
|
|
2741
|
+
className: "h-4 w-4",
|
|
2742
|
+
"aria-hidden": "true"
|
|
2490
2743
|
})]
|
|
2491
2744
|
})
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2745
|
+
}),
|
|
2746
|
+
isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleChildrenPanel, {
|
|
2747
|
+
panelId,
|
|
2748
|
+
bundle,
|
|
2749
|
+
bundles: childBundles,
|
|
2750
|
+
loading: isChildBundlesLoading,
|
|
2751
|
+
onDetailClick
|
|
2752
|
+
}) : null
|
|
2753
|
+
]
|
|
2754
|
+
}, bundle.id);
|
|
2755
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2756
|
+
className: "flex h-32 items-center justify-center px-6 text-center text-sm text-muted-foreground",
|
|
2757
|
+
children: "No bundles found matching your filters."
|
|
2758
|
+
})
|
|
2759
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Table, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHeader, {
|
|
2760
|
+
className: "bg-muted/40",
|
|
2761
|
+
children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
|
|
2762
|
+
className: "border-b border-border/60 hover:bg-transparent",
|
|
2763
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
|
|
2764
|
+
className: "w-10",
|
|
2765
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
2766
|
+
type: "checkbox",
|
|
2767
|
+
checked: allBundlesSelected,
|
|
2768
|
+
"aria-label": "Select all bundles",
|
|
2769
|
+
className: "size-4 accent-primary",
|
|
2770
|
+
onChange: handleToggleAllBundles
|
|
2771
|
+
})
|
|
2772
|
+
}), headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
|
|
2773
|
+
className: "h-10 text-xs font-semibold uppercase text-muted-foreground/70",
|
|
2774
|
+
children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())
|
|
2775
|
+
}, header.id))]
|
|
2776
|
+
}, headerGroup.id))
|
|
2777
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => {
|
|
2778
|
+
const isExpanded = row.original.id === expandedBundleId;
|
|
2779
|
+
const panelId = `bundle-lineage-panel-${row.original.id}`;
|
|
2780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
|
|
2781
|
+
"data-state": row.original.id === selectedBundleId ? "selected" : void 0,
|
|
2782
|
+
className: cn("cursor-pointer transition-colors hover:bg-muted/10 focus-within:bg-muted/15 data-[state=selected]:bg-muted/15", isExpanded && "bg-primary/5"),
|
|
2783
|
+
onClick: () => onDetailClick(row.original),
|
|
2784
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2785
|
+
className: "py-3",
|
|
2786
|
+
onClick: (event) => event.stopPropagation(),
|
|
2787
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
2788
|
+
type: "checkbox",
|
|
2789
|
+
checked: selectedBundleIds.includes(row.original.id),
|
|
2790
|
+
"aria-label": `Select bundle ${row.original.id}`,
|
|
2791
|
+
className: "size-4 accent-primary",
|
|
2792
|
+
onChange: () => toggleBundleSelection(row.original.id)
|
|
2793
|
+
})
|
|
2794
|
+
}), row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2795
|
+
className: "py-3",
|
|
2796
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
2797
|
+
}, cell.id))]
|
|
2798
|
+
}), isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, {
|
|
2799
|
+
className: "hover:bg-transparent",
|
|
2800
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2801
|
+
colSpan: bundleColumns.length + 1,
|
|
2802
|
+
className: "border-t-0 p-0",
|
|
2803
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleChildrenPanel, {
|
|
2514
2804
|
panelId,
|
|
2515
|
-
bundle,
|
|
2805
|
+
bundle: row.original,
|
|
2516
2806
|
bundles: childBundles,
|
|
2517
2807
|
loading: isChildBundlesLoading,
|
|
2518
2808
|
onDetailClick
|
|
2519
|
-
})
|
|
2520
|
-
]
|
|
2521
|
-
}, bundle.id);
|
|
2522
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2523
|
-
className: "flex h-32 items-center justify-center px-6 text-center text-sm text-muted-foreground",
|
|
2524
|
-
children: "No bundles found matching your filters."
|
|
2525
|
-
})
|
|
2526
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Table, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHeader, {
|
|
2527
|
-
className: "bg-muted/40",
|
|
2528
|
-
children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, {
|
|
2529
|
-
className: "border-b border-border/60 hover:bg-transparent",
|
|
2530
|
-
children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
|
|
2531
|
-
className: "h-10 text-xs font-semibold uppercase text-muted-foreground/70",
|
|
2532
|
-
children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())
|
|
2533
|
-
}, header.id))
|
|
2534
|
-
}, headerGroup.id))
|
|
2535
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => {
|
|
2536
|
-
const isExpanded = row.original.id === expandedBundleId;
|
|
2537
|
-
const panelId = `bundle-lineage-panel-${row.original.id}`;
|
|
2538
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, {
|
|
2539
|
-
"data-state": row.original.id === selectedBundleId ? "selected" : void 0,
|
|
2540
|
-
className: cn("cursor-pointer transition-colors hover:bg-muted/10 focus-within:bg-muted/15 data-[state=selected]:bg-muted/15", isExpanded && "bg-primary/5"),
|
|
2541
|
-
onClick: () => onDetailClick(row.original),
|
|
2542
|
-
children: row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2543
|
-
className: "py-3",
|
|
2544
|
-
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
2545
|
-
}, cell.id))
|
|
2546
|
-
}), isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, {
|
|
2547
|
-
className: "hover:bg-transparent",
|
|
2548
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2549
|
-
colSpan: bundleColumns.length,
|
|
2550
|
-
className: "border-t-0 p-0",
|
|
2551
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleChildrenPanel, {
|
|
2552
|
-
panelId,
|
|
2553
|
-
bundle: row.original,
|
|
2554
|
-
bundles: childBundles,
|
|
2555
|
-
loading: isChildBundlesLoading,
|
|
2556
|
-
onDetailClick
|
|
2809
|
+
})
|
|
2557
2810
|
})
|
|
2558
|
-
})
|
|
2559
|
-
}) :
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
})
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
"
|
|
2811
|
+
}) : null] }, row.original.id);
|
|
2812
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2813
|
+
colSpan: bundleColumns.length + 1,
|
|
2814
|
+
className: "h-32 text-center text-muted-foreground",
|
|
2815
|
+
children: "No bundles found matching your filters."
|
|
2816
|
+
}) }) })] })
|
|
2817
|
+
}),
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2819
|
+
className: "flex flex-col gap-3 px-2 sm:flex-row sm:items-center sm:justify-between",
|
|
2820
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2821
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
2822
|
+
children: [
|
|
2823
|
+
"Showing ",
|
|
2824
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2825
|
+
className: "text-foreground",
|
|
2826
|
+
children: startEntry
|
|
2827
|
+
}),
|
|
2828
|
+
" to",
|
|
2829
|
+
" ",
|
|
2830
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2831
|
+
className: "text-foreground",
|
|
2832
|
+
children: endEntry
|
|
2833
|
+
}),
|
|
2834
|
+
" entries"
|
|
2835
|
+
]
|
|
2836
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2837
|
+
className: "flex flex-wrap items-center gap-3 sm:justify-end",
|
|
2838
|
+
children: [
|
|
2839
|
+
selectedBundles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2840
|
+
type: "button",
|
|
2841
|
+
variant: "destructive",
|
|
2842
|
+
size: "sm",
|
|
2843
|
+
className: "h-8 flex-1 px-3 text-xs sm:flex-none",
|
|
2844
|
+
onClick: () => setDeleteDialogOpen(true),
|
|
2845
|
+
children: [
|
|
2846
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { "data-icon": "inline-start" }),
|
|
2847
|
+
"Delete selected (",
|
|
2848
|
+
selectedBundles.length,
|
|
2849
|
+
")"
|
|
2850
|
+
]
|
|
2851
|
+
}) : null,
|
|
2852
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2853
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
2854
|
+
children: [
|
|
2855
|
+
"Page ",
|
|
2597
2856
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2598
2857
|
className: "text-foreground",
|
|
2599
|
-
children:
|
|
2600
|
-
})
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2858
|
+
children: currentPage
|
|
2859
|
+
}),
|
|
2860
|
+
totalPages > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2861
|
+
" ",
|
|
2862
|
+
"of ",
|
|
2863
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2864
|
+
className: "text-foreground",
|
|
2865
|
+
children: totalPages
|
|
2866
|
+
})
|
|
2867
|
+
] }) : null
|
|
2868
|
+
]
|
|
2869
|
+
}),
|
|
2870
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2871
|
+
variant: "outline",
|
|
2872
|
+
size: "sm",
|
|
2873
|
+
onClick: handlePreviousPage,
|
|
2874
|
+
disabled: !hasPreviousPage,
|
|
2875
|
+
className: "h-8 flex-1 px-3 text-xs sm:flex-none",
|
|
2876
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronLeft, { "data-icon": "inline-start" }), "Previous"]
|
|
2877
|
+
}),
|
|
2878
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2879
|
+
variant: "outline",
|
|
2880
|
+
size: "sm",
|
|
2881
|
+
onClick: handleNextPage,
|
|
2882
|
+
disabled: !hasNextPage,
|
|
2883
|
+
className: "h-8 flex-1 px-3 text-xs sm:flex-none",
|
|
2884
|
+
children: ["Next", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { "data-icon": "inline-end" })]
|
|
2885
|
+
})
|
|
2886
|
+
]
|
|
2887
|
+
})]
|
|
2888
|
+
}),
|
|
2889
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectedBundlesDeleteDialog, {
|
|
2890
|
+
bundles: selectedBundles,
|
|
2891
|
+
open: deleteDialogOpen,
|
|
2892
|
+
onOpenChange: setDeleteDialogOpen,
|
|
2893
|
+
onComplete: ({ failedBundleIds }) => {
|
|
2894
|
+
setSelectedBundleIds([...failedBundleIds]);
|
|
2895
|
+
}
|
|
2896
|
+
})
|
|
2897
|
+
]
|
|
2623
2898
|
});
|
|
2624
2899
|
}
|
|
2625
2900
|
function FilterToolbar() {
|
|
@@ -2704,7 +2979,7 @@ function BundlesPage() {
|
|
|
2704
2979
|
if (expandedBundleId && !bundles.some((bundle) => bundle.id === expandedBundleId)) setExpandedBundleId(void 0);
|
|
2705
2980
|
}, [bundles, expandedBundleId]);
|
|
2706
2981
|
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2707
|
-
className: "flex flex-col
|
|
2982
|
+
className: "flex h-svh flex-col",
|
|
2708
2983
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterToolbar, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2709
2984
|
className: "flex flex-1 flex-col gap-4 bg-muted/5 p-3 sm:p-6",
|
|
2710
2985
|
children: [
|
|
@@ -2716,11 +2991,11 @@ function BundlesPage() {
|
|
|
2716
2991
|
})]
|
|
2717
2992
|
});
|
|
2718
2993
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2719
|
-
className: "flex
|
|
2994
|
+
className: "flex h-svh min-h-0 flex-col",
|
|
2720
2995
|
children: [
|
|
2721
2996
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterToolbar, {}),
|
|
2722
2997
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2723
|
-
className: "flex flex-1 flex-col gap-6 bg-muted/5 p-3 sm:p-6",
|
|
2998
|
+
className: "flex min-h-0 min-w-0 flex-1 flex-col gap-6 bg-muted/5 p-3 sm:p-6",
|
|
2724
2999
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundlesTable, {
|
|
2725
3000
|
bundles,
|
|
2726
3001
|
pagination,
|