@hot-updater/console 0.30.12 → 0.31.1
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/BaseTanStackRouterDevtoolsPanel-Bmws3ikM-q5p5qKUx.js +486 -0
- package/.output/public/assets/FloatingTanStackRouterDevtools-B7vy70jP-Bzs2Gthe.js +1 -0
- package/.output/public/assets/clsx-CbprLf2V.js +1 -0
- package/.output/public/assets/dist-B5egZOkC.js +9 -0
- package/.output/public/assets/main-DrVuFR7r.js +10 -0
- package/.output/public/assets/preload-helper-C5ST2IKa.js +1 -0
- package/.output/public/assets/routes-C_bgs7kg.js +54 -0
- package/.output/public/assets/styles-DZ0tCVA1.css +2 -0
- package/.output/server/{__tanstack-start-server-fn-resolver-rXMsqALt.mjs → __tanstack-start-server-fn-resolver-5wPQ8bZ3.mjs} +19 -11
- 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 +8 -1
- package/.output/server/_libs/unctx.mjs +1 -1
- package/.output/server/_ssr/{api-rpc-DYKuUgOh.mjs → api-rpc-BhBKhZqY.mjs} +61 -18
- package/.output/server/_ssr/{config.server-8YQWTTc0.mjs → config.server-xu3W-WAK.mjs} +3 -1
- package/.output/server/_ssr/deleteBundle-D4jF5HeY.mjs +96 -0
- package/.output/server/_ssr/dist-CRiLZLfa.mjs +120 -0
- package/.output/server/_ssr/getBundleChildren-DFqZ6XMp.mjs +58 -0
- package/.output/server/_ssr/{router-D-WWsYjv.mjs → router-SkApCyud.mjs} +57 -15
- package/.output/server/_ssr/{routes-DyUhibF4.mjs → routes-BSs-dv4D.mjs} +1120 -472
- package/.output/server/_ssr/{sidebar-DXng0IOP.mjs → sidebar-CgbtXkE2.mjs} +65 -85
- package/.output/server/_ssr/ssr.mjs +4 -4
- package/.output/server/_ssr/start-D0X4LIsd.mjs +4 -0
- package/.output/server/_ssr/storageProfile-wICk5nZZ.mjs +9 -0
- package/.output/server/{_tanstack-start-manifest_v-xpdCj2Ct.mjs → _tanstack-start-manifest_v-D2MqgD3d.mjs} +9 -4
- package/.output/server/index.mjs +70 -42
- package/package.json +10 -6
- package/.output/public/assets/dist-BKho179_.js +0 -53
- package/.output/public/assets/main-5MdOCmsM.js +0 -10
- package/.output/public/assets/routes-BmbL4goz.js +0 -10
- package/.output/public/assets/styles-M2W42JQb.css +0 -2
- package/.output/server/_ssr/deleteBundle-BiJvjt0k.mjs +0 -22
- package/.output/server/_ssr/start-DsRb6TkZ.mjs +0 -4
|
@@ -1,28 +1,198 @@
|
|
|
1
1
|
import { r as __toESM } from "../_runtime.mjs";
|
|
2
2
|
import { c as createServerFn, i as TSS_SERVER_FUNCTION } from "./createServerFn-CdeRXnVy.mjs";
|
|
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";
|
|
3
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";
|
|
4
5
|
import { u as require_react } from "../_libs/@floating-ui/react-dom+[...].mjs";
|
|
5
|
-
import { S as Check, b as ChevronLeft, d as List, g as Download, h as ExternalLink, i as Plus, l as Minus, m as FingerprintPattern, n as TriangleAlert, o as Package, p as Funnel, t as X, v as ChevronUp, x as ChevronDown, y as ChevronRight } from "../_libs/lucide-react.mjs";
|
|
6
|
+
import { C as ArrowRight, S as Check, b as ChevronLeft, d as List, g as Download, h as ExternalLink, i as Plus, l as Minus, m as FingerprintPattern, n as TriangleAlert, o as Package, p as Funnel, t as X, v as ChevronUp, x as ChevronDown, y as ChevronRight } from "../_libs/lucide-react.mjs";
|
|
6
7
|
import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
|
|
7
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";
|
|
8
9
|
import { t as Root$1 } from "../_libs/radix-ui__react-label.mjs";
|
|
9
10
|
import { i as Track, n as Root$2, r as Thumb, t as Range } from "../_libs/radix-ui__react-slider.mjs";
|
|
10
11
|
import { n as Thumb$1, t as Root$3 } from "../_libs/radix-ui__react-switch.mjs";
|
|
11
|
-
import { C as
|
|
12
|
+
import { C as useIsMobile, S as cn, _ as Skeleton, g as SidebarTrigger, n as Input, r as Separator$1, t as Button, v as Tooltip$1, x as TooltipTrigger, y as TooltipContent } from "./sidebar-CgbtXkE2.mjs";
|
|
12
13
|
import { d as useNavigate, f as useSearch } from "../_libs/@tanstack/react-router+[...].mjs";
|
|
13
14
|
import { n as useStore, t as useForm } from "../_libs/@tanstack/react-form+[...].mjs";
|
|
14
15
|
import { i as useQueryClient, n as useQuery, t as useMutation } from "../_libs/tanstack__react-query.mjs";
|
|
15
16
|
import { n as toast } from "../_libs/sonner.mjs";
|
|
16
|
-
import { t as getServerFnById } from "../__tanstack-start-server-fn-resolver-
|
|
17
|
+
import { t as getServerFnById } from "../__tanstack-start-server-fn-resolver-5wPQ8bZ3.mjs";
|
|
17
18
|
import { t as require_semver } from "../_libs/semver.mjs";
|
|
18
19
|
import { i as getCoreRowModel, n as useReactTable, r as createColumnHelper, t as flexRender } from "../_libs/@tanstack/react-table+[...].mjs";
|
|
19
20
|
import { n as require_dayjs_min, t as require_relativeTime } from "../_libs/dayjs.mjs";
|
|
20
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/routes-
|
|
21
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/routes-BSs-dv4D.js
|
|
21
22
|
var import_jsx_runtime = require_jsx_runtime();
|
|
22
|
-
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
23
23
|
var import_semver = /* @__PURE__ */ __toESM(require_semver());
|
|
24
|
+
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
24
25
|
var import_dayjs_min = /* @__PURE__ */ __toESM(require_dayjs_min());
|
|
25
26
|
var import_relativeTime = /* @__PURE__ */ __toESM(require_relativeTime());
|
|
27
|
+
var extractTimestampFromUUIDv7 = (uuid) => {
|
|
28
|
+
const timestampHex = uuid.split("-").join("").slice(0, 12);
|
|
29
|
+
return Number.parseInt(timestampHex, 16);
|
|
30
|
+
};
|
|
31
|
+
function createUUIDv7FromTimestampHex(timestampHex) {
|
|
32
|
+
const randomBytes = new Uint8Array(10);
|
|
33
|
+
crypto.getRandomValues(randomBytes);
|
|
34
|
+
const randomHex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
35
|
+
const randA = randomHex.slice(0, 3);
|
|
36
|
+
const randBHex = randomHex.slice(3, 19);
|
|
37
|
+
const versionAndRandA = `7${randA}`;
|
|
38
|
+
const variantAndFirstRandB = (128 | parseInt(randBHex.slice(0, 2), 16) & 63).toString(16).padStart(2, "0");
|
|
39
|
+
return [
|
|
40
|
+
timestampHex.slice(0, 8),
|
|
41
|
+
timestampHex.slice(8, 12),
|
|
42
|
+
versionAndRandA,
|
|
43
|
+
variantAndFirstRandB + randBHex.slice(2, 4),
|
|
44
|
+
randBHex.slice(4, 16)
|
|
45
|
+
].join("-");
|
|
46
|
+
}
|
|
47
|
+
var createUUIDv7 = () => createUUIDv7FromTimestampHex(Date.now().toString(16).padStart(12, "0"));
|
|
48
|
+
function Dialog$1({ ...props }) {
|
|
49
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Root, {
|
|
50
|
+
"data-slot": "dialog",
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function DialogTrigger({ ...props }) {
|
|
55
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trigger, {
|
|
56
|
+
"data-slot": "dialog-trigger",
|
|
57
|
+
...props
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function DialogPortal({ ...props }) {
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portal, {
|
|
62
|
+
"data-slot": "dialog-portal",
|
|
63
|
+
...props
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function DialogOverlay({ className, ...props }) {
|
|
67
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overlay, {
|
|
68
|
+
"data-slot": "dialog-overlay",
|
|
69
|
+
className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className),
|
|
70
|
+
...props
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function DialogContent({ className, children, showCloseButton = true, ...props }) {
|
|
74
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogPortal, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogOverlay, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Content, {
|
|
75
|
+
"data-slot": "dialog-content",
|
|
76
|
+
className: cn("bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2", className),
|
|
77
|
+
...props,
|
|
78
|
+
children: [children, showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Close, {
|
|
79
|
+
"data-slot": "dialog-close",
|
|
80
|
+
asChild: true,
|
|
81
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
82
|
+
variant: "ghost",
|
|
83
|
+
className: "absolute top-2 right-2",
|
|
84
|
+
size: "icon-sm",
|
|
85
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
86
|
+
className: "sr-only",
|
|
87
|
+
children: "Close"
|
|
88
|
+
})]
|
|
89
|
+
})
|
|
90
|
+
})]
|
|
91
|
+
})] });
|
|
92
|
+
}
|
|
93
|
+
function DialogHeader({ className, ...props }) {
|
|
94
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
95
|
+
"data-slot": "dialog-header",
|
|
96
|
+
className: cn("gap-1 flex flex-col", className),
|
|
97
|
+
...props
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function DialogFooter({ className, showCloseButton = false, children, ...props }) {
|
|
101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
102
|
+
"data-slot": "dialog-footer",
|
|
103
|
+
className: cn("gap-2 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
104
|
+
...props,
|
|
105
|
+
children: [children, showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Close, {
|
|
106
|
+
asChild: true,
|
|
107
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
108
|
+
variant: "outline",
|
|
109
|
+
children: "Close"
|
|
110
|
+
})
|
|
111
|
+
})]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function DialogTitle({ className, ...props }) {
|
|
115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Title, {
|
|
116
|
+
"data-slot": "dialog-title",
|
|
117
|
+
className: cn("text-sm font-medium", className),
|
|
118
|
+
...props
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function DialogDescription({ className, ...props }) {
|
|
122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Description, {
|
|
123
|
+
"data-slot": "dialog-description",
|
|
124
|
+
className: cn("text-muted-foreground *:[a]:hover:text-foreground text-xs/relaxed *:[a]:underline *:[a]:underline-offset-3", className),
|
|
125
|
+
...props
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function Sheet({ ...props }) {
|
|
129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Root, {
|
|
130
|
+
"data-slot": "sheet",
|
|
131
|
+
...props
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function SheetPortal({ ...props }) {
|
|
135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portal, {
|
|
136
|
+
"data-slot": "sheet-portal",
|
|
137
|
+
...props
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function SheetOverlay({ className, ...props }) {
|
|
141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overlay, {
|
|
142
|
+
"data-slot": "sheet-overlay",
|
|
143
|
+
className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50", className),
|
|
144
|
+
...props
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function SheetContent({ className, children, overlayClassName, side = "right", showCloseButton = true, ...props }) {
|
|
148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SheetPortal, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SheetOverlay, { className: overlayClassName }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Content, {
|
|
149
|
+
"data-slot": "sheet-content",
|
|
150
|
+
"data-side": side,
|
|
151
|
+
className: cn("bg-background data-open:animate-in data-closed:animate-out data-[side=right]:data-closed:slide-out-to-right-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=top]:data-closed:slide-out-to-top-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:fade-out-0 data-open:fade-in-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=bottom]:data-open:slide-in-from-bottom-10 fixed z-50 flex flex-col bg-clip-padding text-xs/relaxed shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm", className),
|
|
152
|
+
...props,
|
|
153
|
+
children: [children, showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Close, {
|
|
154
|
+
"data-slot": "sheet-close",
|
|
155
|
+
asChild: true,
|
|
156
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
157
|
+
variant: "ghost",
|
|
158
|
+
className: "absolute top-4 right-4",
|
|
159
|
+
size: "icon-sm",
|
|
160
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
161
|
+
className: "sr-only",
|
|
162
|
+
children: "Close"
|
|
163
|
+
})]
|
|
164
|
+
})
|
|
165
|
+
})]
|
|
166
|
+
})] });
|
|
167
|
+
}
|
|
168
|
+
function SheetHeader({ className, ...props }) {
|
|
169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
170
|
+
"data-slot": "sheet-header",
|
|
171
|
+
className: cn("gap-1.5 p-6 flex flex-col", className),
|
|
172
|
+
...props
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function SheetTitle({ className, ...props }) {
|
|
176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Title, {
|
|
177
|
+
"data-slot": "sheet-title",
|
|
178
|
+
className: cn("text-foreground text-sm font-medium", className),
|
|
179
|
+
...props
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function SheetDescription({ className, ...props }) {
|
|
183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Description, {
|
|
184
|
+
"data-slot": "sheet-description",
|
|
185
|
+
className: cn("text-muted-foreground text-xs/relaxed", className),
|
|
186
|
+
...props
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function BundleIdDisplay({ bundleId, className }) {
|
|
190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
191
|
+
translate: "no",
|
|
192
|
+
className: cn("break-all font-mono text-xs tabular-nums", className),
|
|
193
|
+
children: bundleId
|
|
194
|
+
});
|
|
195
|
+
}
|
|
26
196
|
function AppleIcon({ className }) {
|
|
27
197
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
|
|
28
198
|
role: "img",
|
|
@@ -51,131 +221,59 @@ function PlatformIcon({ platform, className }) {
|
|
|
51
221
|
}
|
|
52
222
|
function BundleBasicInfo({ bundle }) {
|
|
53
223
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
54
|
-
className: "flex flex-col gap-3 text-sm
|
|
224
|
+
className: "mt-1 flex flex-col gap-3 text-sm",
|
|
55
225
|
children: [
|
|
226
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
227
|
+
className: "flex flex-wrap items-center gap-2",
|
|
228
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
229
|
+
className: "flex items-center gap-2",
|
|
230
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlatformIcon, {
|
|
231
|
+
platform: bundle.platform,
|
|
232
|
+
className: "h-4 w-4"
|
|
233
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
234
|
+
className: "font-medium",
|
|
235
|
+
children: bundle.platform === "ios" ? "iOS" : "Android"
|
|
236
|
+
})]
|
|
237
|
+
})
|
|
238
|
+
}),
|
|
56
239
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
57
|
-
className: "flex items-
|
|
58
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
59
|
-
|
|
60
|
-
|
|
240
|
+
className: "flex flex-wrap items-start gap-2",
|
|
241
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
242
|
+
className: "font-medium text-muted-foreground",
|
|
243
|
+
children: "Bundle"
|
|
61
244
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
62
|
-
className: "
|
|
63
|
-
children:
|
|
245
|
+
className: "min-w-0 basis-full sm:basis-auto",
|
|
246
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
247
|
+
bundleId: bundle.id,
|
|
248
|
+
maxLength: 18,
|
|
249
|
+
fullOnMobile: true
|
|
250
|
+
})
|
|
64
251
|
})]
|
|
65
252
|
}),
|
|
66
253
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
67
|
-
className: "flex items-center gap-2",
|
|
254
|
+
className: "flex flex-wrap items-center gap-2",
|
|
68
255
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
69
256
|
className: "font-medium text-muted-foreground",
|
|
70
|
-
children: "
|
|
257
|
+
children: "Channel"
|
|
71
258
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
72
259
|
className: "text-xs text-foreground",
|
|
73
|
-
|
|
260
|
+
translate: "no",
|
|
261
|
+
children: bundle.channel
|
|
74
262
|
})]
|
|
75
263
|
}),
|
|
76
264
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
77
|
-
className: "flex items-center gap-2",
|
|
265
|
+
className: "flex flex-wrap items-center gap-2",
|
|
78
266
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
79
267
|
className: "font-medium text-muted-foreground",
|
|
80
|
-
children: "
|
|
268
|
+
children: "Platform"
|
|
81
269
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
82
270
|
className: "text-xs text-foreground",
|
|
83
|
-
children: bundle.
|
|
271
|
+
children: bundle.platform === "ios" ? "iOS" : "Android"
|
|
84
272
|
})]
|
|
85
273
|
})
|
|
86
274
|
]
|
|
87
275
|
});
|
|
88
276
|
}
|
|
89
|
-
var NUMERIC_COHORT_SIZE = 1e3;
|
|
90
|
-
var DEFAULT_ROLLOUT_COHORT_COUNT = NUMERIC_COHORT_SIZE;
|
|
91
|
-
var INVALID_COHORT_ERROR_MESSAGE = `Invalid cohort. Use 1-1000 or a lowercase slug without spaces, up to 64 characters.`;
|
|
92
|
-
var CUSTOM_COHORT_PATTERN = /^[a-z0-9-]+$/;
|
|
93
|
-
function parseNumericCohortValue(cohort) {
|
|
94
|
-
if (!/^\d+$/.test(cohort)) return null;
|
|
95
|
-
const parsed = Number.parseInt(cohort, 10);
|
|
96
|
-
if (Number.isNaN(parsed) || parsed < 1 || parsed > 1e3) return null;
|
|
97
|
-
return parsed;
|
|
98
|
-
}
|
|
99
|
-
function positiveMod(value, modulus) {
|
|
100
|
-
return (value % modulus + modulus) % modulus;
|
|
101
|
-
}
|
|
102
|
-
function hashString(value) {
|
|
103
|
-
let hash = 0;
|
|
104
|
-
for (let i = 0; i < value.length; i++) {
|
|
105
|
-
const char = value.charCodeAt(i);
|
|
106
|
-
hash = (hash << 5) - hash + char;
|
|
107
|
-
hash |= 0;
|
|
108
|
-
}
|
|
109
|
-
return hash;
|
|
110
|
-
}
|
|
111
|
-
function gcd(a, b) {
|
|
112
|
-
let x = Math.abs(a);
|
|
113
|
-
let y = Math.abs(b);
|
|
114
|
-
while (y !== 0) {
|
|
115
|
-
const next = x % y;
|
|
116
|
-
x = y;
|
|
117
|
-
y = next;
|
|
118
|
-
}
|
|
119
|
-
return x;
|
|
120
|
-
}
|
|
121
|
-
function modularInverse(value, modulus) {
|
|
122
|
-
let t = 0;
|
|
123
|
-
let newT = 1;
|
|
124
|
-
let r = modulus;
|
|
125
|
-
let newR = positiveMod(value, modulus);
|
|
126
|
-
while (newR !== 0) {
|
|
127
|
-
const quotient = Math.floor(r / newR);
|
|
128
|
-
[t, newT] = [newT, t - quotient * newT];
|
|
129
|
-
[r, newR] = [newR, r - quotient * newR];
|
|
130
|
-
}
|
|
131
|
-
if (r > 1) throw new Error(`No modular inverse for ${value} mod ${modulus}`);
|
|
132
|
-
return positiveMod(t, modulus);
|
|
133
|
-
}
|
|
134
|
-
function getRolloutShuffleParameters(bundleId) {
|
|
135
|
-
let multiplier = positiveMod(hashString(`${bundleId}:multiplier`), 997);
|
|
136
|
-
if (multiplier === 0) multiplier = 1;
|
|
137
|
-
while (gcd(multiplier, NUMERIC_COHORT_SIZE) !== 1) {
|
|
138
|
-
multiplier = positiveMod(multiplier + 1, NUMERIC_COHORT_SIZE);
|
|
139
|
-
if (multiplier === 0) multiplier = 1;
|
|
140
|
-
}
|
|
141
|
-
const offset = positiveMod(hashString(`${bundleId}:offset`), NUMERIC_COHORT_SIZE);
|
|
142
|
-
return {
|
|
143
|
-
multiplier,
|
|
144
|
-
offset,
|
|
145
|
-
inverseMultiplier: modularInverse(multiplier, NUMERIC_COHORT_SIZE)
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
function normalizeRolloutCohortCount(rolloutCohortCount) {
|
|
149
|
-
if (rolloutCohortCount === null || rolloutCohortCount === void 0) return DEFAULT_ROLLOUT_COHORT_COUNT;
|
|
150
|
-
if (rolloutCohortCount <= 0) return 0;
|
|
151
|
-
if (rolloutCohortCount >= 1e3) return NUMERIC_COHORT_SIZE;
|
|
152
|
-
return Math.floor(rolloutCohortCount);
|
|
153
|
-
}
|
|
154
|
-
function normalizeCohortValue(cohort) {
|
|
155
|
-
const normalized = cohort.trim().toLowerCase();
|
|
156
|
-
const numericCohort = parseNumericCohortValue(normalized);
|
|
157
|
-
if (numericCohort !== null) return String(numericCohort);
|
|
158
|
-
return normalized;
|
|
159
|
-
}
|
|
160
|
-
function getNumericCohortValue(cohort) {
|
|
161
|
-
return parseNumericCohortValue(normalizeCohortValue(cohort));
|
|
162
|
-
}
|
|
163
|
-
function isNumericCohort(cohort) {
|
|
164
|
-
return getNumericCohortValue(cohort) !== null;
|
|
165
|
-
}
|
|
166
|
-
function isCustomCohort(cohort) {
|
|
167
|
-
const normalized = normalizeCohortValue(cohort);
|
|
168
|
-
return normalized.length > 0 && normalized.length <= 64 && !/^\d+$/.test(normalized) && CUSTOM_COHORT_PATTERN.test(normalized);
|
|
169
|
-
}
|
|
170
|
-
function isValidCohort(cohort) {
|
|
171
|
-
const normalized = normalizeCohortValue(cohort);
|
|
172
|
-
return isNumericCohort(normalized) || isCustomCohort(normalized);
|
|
173
|
-
}
|
|
174
|
-
function getNumericCohortRolloutPosition(bundleId, cohortValue) {
|
|
175
|
-
if (cohortValue < 1 || cohortValue > 1e3) throw new Error(`Invalid numeric cohort: ${cohortValue}`);
|
|
176
|
-
const { offset, inverseMultiplier } = getRolloutShuffleParameters(bundleId);
|
|
177
|
-
return positiveMod(inverseMultiplier * (cohortValue - 1 - offset), NUMERIC_COHORT_SIZE);
|
|
178
|
-
}
|
|
179
277
|
var badgeVariants = cva("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", {
|
|
180
278
|
variants: { variant: {
|
|
181
279
|
default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
|
@@ -309,6 +407,8 @@ var getChannels = createServerFn().handler(createSsrRpc("79ada05964de8f2123bfcd6
|
|
|
309
407
|
createServerFn().handler(createSsrRpc("f8bdca3d0579adb812d6404f55d9261a89cdb025e920b1fcad82883646a5fe9e"));
|
|
310
408
|
var getBundles = createServerFn({ method: "GET" }).inputValidator((input) => input).handler(createSsrRpc("00ccacb4a0212c83ec29f4d11719046ad91ea8291cfc557d514dbf00d3bd7f5f"));
|
|
311
409
|
var getBundle = createServerFn({ method: "GET" }).inputValidator((input) => input).handler(createSsrRpc("1bd85c2a50e24785cb6abb023a247a9f048f37ddfa85cbb1c57e579563bad013"));
|
|
410
|
+
var getBundleChildren = createServerFn({ method: "GET" }).inputValidator((input) => input).handler(createSsrRpc("4370f1bf70b91f1168d85379d3008449a1bedb915e9878ca4ef89d5f3a80fa7f"));
|
|
411
|
+
var getBundleChildCounts = createServerFn({ method: "GET" }).inputValidator((input) => input).handler(createSsrRpc("4ca367070b00f58179a572f0bb8196a4ccdd3881e9b1dbfe33deee0cb6e1f549"));
|
|
312
412
|
var getBundleDownloadUrl = createServerFn({ method: "GET" }).inputValidator((input) => input).handler(createSsrRpc("e000081a14772a0496dfdf615232fbbb1a23b89191d0e32f89a05dd67a1916f7"));
|
|
313
413
|
var updateBundle = createServerFn({ method: "POST" }).inputValidator((input) => input).handler(createSsrRpc("67f90ce4cd10fd0226cd9d77cdcd8d0f25a59a6ac406360b655e44296bc4208b"));
|
|
314
414
|
var promoteBundle = createServerFn({ method: "POST" }).inputValidator((input) => input).handler(createSsrRpc("c4ef3bbb77ea8a4410623fd18a4741e2ff0668b1a97510bcdd032a8428eaa5da"));
|
|
@@ -323,6 +423,15 @@ var queryKeys = {
|
|
|
323
423
|
all: bundleListQueryKey,
|
|
324
424
|
list: (filters) => [...bundleListQueryKey, filters ?? {}]
|
|
325
425
|
},
|
|
426
|
+
bundleChildren: {
|
|
427
|
+
all: ["bundle-children"],
|
|
428
|
+
list: (baseBundleId) => ["bundle-children", baseBundleId],
|
|
429
|
+
counts: (bundleIds) => [
|
|
430
|
+
"bundle-children",
|
|
431
|
+
"counts",
|
|
432
|
+
...bundleIds
|
|
433
|
+
]
|
|
434
|
+
},
|
|
326
435
|
bundle: (bundleId) => ["bundle", bundleId]
|
|
327
436
|
};
|
|
328
437
|
function replaceBundleInQueryData(data, updatedBundle) {
|
|
@@ -362,6 +471,23 @@ function useBundleQuery(bundleId) {
|
|
|
362
471
|
enabled: !!bundleId
|
|
363
472
|
});
|
|
364
473
|
}
|
|
474
|
+
function useBundleChildrenQuery(baseBundleId) {
|
|
475
|
+
return useQuery({
|
|
476
|
+
queryKey: queryKeys.bundleChildren.list(baseBundleId),
|
|
477
|
+
queryFn: () => getBundleChildren({ data: { baseBundleId } }),
|
|
478
|
+
staleTime: Infinity,
|
|
479
|
+
enabled: !!baseBundleId
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
function useBundleChildCountsQuery(bundleIds) {
|
|
483
|
+
const normalizedBundleIds = [...bundleIds].sort((left, right) => left.localeCompare(right));
|
|
484
|
+
return useQuery({
|
|
485
|
+
queryKey: queryKeys.bundleChildren.counts(normalizedBundleIds),
|
|
486
|
+
queryFn: () => getBundleChildCounts({ data: { bundleIds: normalizedBundleIds } }),
|
|
487
|
+
staleTime: Infinity,
|
|
488
|
+
enabled: normalizedBundleIds.length > 0
|
|
489
|
+
});
|
|
490
|
+
}
|
|
365
491
|
function useBundleDownloadUrlMutation() {
|
|
366
492
|
return useMutation({ mutationFn: (params) => getBundleDownloadUrl({ data: params }) });
|
|
367
493
|
}
|
|
@@ -374,6 +500,7 @@ function useUpdateBundleMutation() {
|
|
|
374
500
|
queryClient.setQueriesData({ queryKey: queryKeys.bundles.all }, (data) => replaceBundleInQueryData(data, updatedBundle));
|
|
375
501
|
await Promise.all([
|
|
376
502
|
queryClient.invalidateQueries({ queryKey: queryKeys.bundles.all }),
|
|
503
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.bundleChildren.all }),
|
|
377
504
|
queryClient.invalidateQueries({ queryKey: queryKeys.bundle(vars.bundleId) }),
|
|
378
505
|
queryClient.invalidateQueries({ queryKey: queryKeys.channels })
|
|
379
506
|
]);
|
|
@@ -388,6 +515,7 @@ function usePromoteBundleMutation() {
|
|
|
388
515
|
queryClient.setQueryData(queryKeys.bundle(bundle.id), bundle);
|
|
389
516
|
await Promise.all([
|
|
390
517
|
queryClient.invalidateQueries({ queryKey: queryKeys.bundles.all }),
|
|
518
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.bundleChildren.all }),
|
|
391
519
|
queryClient.invalidateQueries({ queryKey: queryKeys.channels }),
|
|
392
520
|
queryClient.invalidateQueries({ queryKey: queryKeys.bundle(bundle.id) })
|
|
393
521
|
]);
|
|
@@ -400,7 +528,11 @@ function useDeleteBundleMutation() {
|
|
|
400
528
|
mutationFn: (params) => deleteBundle({ data: params }),
|
|
401
529
|
onSuccess: async (_, vars) => {
|
|
402
530
|
queryClient.removeQueries({ queryKey: queryKeys.bundle(vars.bundleId) });
|
|
403
|
-
await Promise.all([
|
|
531
|
+
await Promise.all([
|
|
532
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.bundles.all }),
|
|
533
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.bundleChildren.all }),
|
|
534
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.channels })
|
|
535
|
+
]);
|
|
404
536
|
}
|
|
405
537
|
});
|
|
406
538
|
}
|
|
@@ -548,107 +680,6 @@ function DeleteBundleDialog({ bundle, open, onOpenChange, onSuccess }) {
|
|
|
548
680
|
})
|
|
549
681
|
});
|
|
550
682
|
}
|
|
551
|
-
var extractTimestampFromUUIDv7 = (uuid) => {
|
|
552
|
-
const timestampHex = uuid.split("-").join("").slice(0, 12);
|
|
553
|
-
return Number.parseInt(timestampHex, 16);
|
|
554
|
-
};
|
|
555
|
-
function createUUIDv7FromTimestampHex(timestampHex) {
|
|
556
|
-
const randomBytes = new Uint8Array(10);
|
|
557
|
-
crypto.getRandomValues(randomBytes);
|
|
558
|
-
const randomHex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
559
|
-
const randA = randomHex.slice(0, 3);
|
|
560
|
-
const randBHex = randomHex.slice(3, 19);
|
|
561
|
-
const versionAndRandA = `7${randA}`;
|
|
562
|
-
const variantAndFirstRandB = (128 | parseInt(randBHex.slice(0, 2), 16) & 63).toString(16).padStart(2, "0");
|
|
563
|
-
return [
|
|
564
|
-
timestampHex.slice(0, 8),
|
|
565
|
-
timestampHex.slice(8, 12),
|
|
566
|
-
versionAndRandA,
|
|
567
|
-
variantAndFirstRandB + randBHex.slice(2, 4),
|
|
568
|
-
randBHex.slice(4, 16)
|
|
569
|
-
].join("-");
|
|
570
|
-
}
|
|
571
|
-
var createUUIDv7 = () => createUUIDv7FromTimestampHex(Date.now().toString(16).padStart(12, "0"));
|
|
572
|
-
function Dialog$1({ ...props }) {
|
|
573
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Root, {
|
|
574
|
-
"data-slot": "dialog",
|
|
575
|
-
...props
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
function DialogTrigger({ ...props }) {
|
|
579
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trigger, {
|
|
580
|
-
"data-slot": "dialog-trigger",
|
|
581
|
-
...props
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
function DialogPortal({ ...props }) {
|
|
585
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portal, {
|
|
586
|
-
"data-slot": "dialog-portal",
|
|
587
|
-
...props
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
function DialogOverlay({ className, ...props }) {
|
|
591
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overlay, {
|
|
592
|
-
"data-slot": "dialog-overlay",
|
|
593
|
-
className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className),
|
|
594
|
-
...props
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
function DialogContent({ className, children, showCloseButton = true, ...props }) {
|
|
598
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogPortal, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogOverlay, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Content, {
|
|
599
|
-
"data-slot": "dialog-content",
|
|
600
|
-
className: cn("bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2", className),
|
|
601
|
-
...props,
|
|
602
|
-
children: [children, showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Close, {
|
|
603
|
-
"data-slot": "dialog-close",
|
|
604
|
-
asChild: true,
|
|
605
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
606
|
-
variant: "ghost",
|
|
607
|
-
className: "absolute top-2 right-2",
|
|
608
|
-
size: "icon-sm",
|
|
609
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
610
|
-
className: "sr-only",
|
|
611
|
-
children: "Close"
|
|
612
|
-
})]
|
|
613
|
-
})
|
|
614
|
-
})]
|
|
615
|
-
})] });
|
|
616
|
-
}
|
|
617
|
-
function DialogHeader({ className, ...props }) {
|
|
618
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
619
|
-
"data-slot": "dialog-header",
|
|
620
|
-
className: cn("gap-1 flex flex-col", className),
|
|
621
|
-
...props
|
|
622
|
-
});
|
|
623
|
-
}
|
|
624
|
-
function DialogFooter({ className, showCloseButton = false, children, ...props }) {
|
|
625
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
626
|
-
"data-slot": "dialog-footer",
|
|
627
|
-
className: cn("gap-2 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
628
|
-
...props,
|
|
629
|
-
children: [children, showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Close, {
|
|
630
|
-
asChild: true,
|
|
631
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
632
|
-
variant: "outline",
|
|
633
|
-
children: "Close"
|
|
634
|
-
})
|
|
635
|
-
})]
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
function DialogTitle({ className, ...props }) {
|
|
639
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Title, {
|
|
640
|
-
"data-slot": "dialog-title",
|
|
641
|
-
className: cn("text-sm font-medium", className),
|
|
642
|
-
...props
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
function DialogDescription({ className, ...props }) {
|
|
646
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Description, {
|
|
647
|
-
"data-slot": "dialog-description",
|
|
648
|
-
className: cn("text-muted-foreground *:[a]:hover:text-foreground text-xs/relaxed *:[a]:underline *:[a]:underline-offset-3", className),
|
|
649
|
-
...props
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
683
|
function Select$1({ ...props }) {
|
|
653
684
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Root2$1, {
|
|
654
685
|
"data-slot": "select",
|
|
@@ -728,10 +759,12 @@ function useFilterParams() {
|
|
|
728
759
|
before: search.before
|
|
729
760
|
};
|
|
730
761
|
const bundleId = search.bundleId;
|
|
731
|
-
const
|
|
762
|
+
const expandedBundleId = search.expandedBundleId;
|
|
763
|
+
const navigateWithSearch = (nextSearch, options) => {
|
|
732
764
|
navigate({
|
|
733
765
|
to: "/",
|
|
734
|
-
search: nextSearch
|
|
766
|
+
search: nextSearch,
|
|
767
|
+
resetScroll: options?.resetScroll
|
|
735
768
|
});
|
|
736
769
|
};
|
|
737
770
|
const getNextFilters = (newFilters) => {
|
|
@@ -753,14 +786,23 @@ function useFilterParams() {
|
|
|
753
786
|
const setFilters = (newFilters) => {
|
|
754
787
|
navigateWithSearch({
|
|
755
788
|
...getNextFilters(newFilters),
|
|
756
|
-
bundleId: void 0
|
|
789
|
+
bundleId: void 0,
|
|
790
|
+
expandedBundleId: void 0
|
|
757
791
|
});
|
|
758
792
|
};
|
|
759
793
|
const setBundleId = (nextBundleId, newFilters = {}) => {
|
|
760
794
|
navigateWithSearch({
|
|
761
795
|
...getNextFilters(newFilters),
|
|
762
|
-
bundleId: nextBundleId
|
|
763
|
-
|
|
796
|
+
bundleId: nextBundleId,
|
|
797
|
+
expandedBundleId: void 0
|
|
798
|
+
}, { resetScroll: false });
|
|
799
|
+
};
|
|
800
|
+
const setExpandedBundleId = (nextExpandedBundleId, newFilters = {}) => {
|
|
801
|
+
navigateWithSearch({
|
|
802
|
+
...getNextFilters(newFilters),
|
|
803
|
+
bundleId,
|
|
804
|
+
expandedBundleId: nextExpandedBundleId
|
|
805
|
+
}, { resetScroll: false });
|
|
764
806
|
};
|
|
765
807
|
const resetFilters = () => {
|
|
766
808
|
navigateWithSearch({
|
|
@@ -769,14 +811,17 @@ function useFilterParams() {
|
|
|
769
811
|
page: void 0,
|
|
770
812
|
after: void 0,
|
|
771
813
|
before: void 0,
|
|
772
|
-
bundleId: void 0
|
|
814
|
+
bundleId: void 0,
|
|
815
|
+
expandedBundleId: void 0
|
|
773
816
|
});
|
|
774
817
|
};
|
|
775
818
|
return {
|
|
776
819
|
filters,
|
|
777
820
|
bundleId,
|
|
821
|
+
expandedBundleId,
|
|
778
822
|
setFilters,
|
|
779
823
|
setBundleId,
|
|
824
|
+
setExpandedBundleId,
|
|
780
825
|
resetFilters
|
|
781
826
|
};
|
|
782
827
|
}
|
|
@@ -1016,6 +1061,78 @@ function RolloutCohortsDialog({ bundleId, rolloutCohortCount, targetCohorts, tri
|
|
|
1016
1061
|
const rolloutCohorts = Array.from({ length: NUMERIC_COHORT_SIZE }, (_, index) => index + 1).filter((cohortValue) => getNumericCohortRolloutPosition(bundleId, cohortValue) < normalizedRolloutCount);
|
|
1017
1062
|
const rolloutPercentage = (normalizedRolloutCount / 10).toFixed(1);
|
|
1018
1063
|
const excludedCount = NUMERIC_COHORT_SIZE - rolloutCohorts.length;
|
|
1064
|
+
const isMobile = useIsMobile();
|
|
1065
|
+
const dialogBody = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1066
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1067
|
+
className: "grid gap-3 grid-cols-2 sm:grid-cols-3",
|
|
1068
|
+
children: [
|
|
1069
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1070
|
+
className: "p-4",
|
|
1071
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Selected Cohorts" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1072
|
+
className: "font-mono text-xl",
|
|
1073
|
+
children: rolloutCohorts.length
|
|
1074
|
+
})]
|
|
1075
|
+
}) }),
|
|
1076
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1077
|
+
className: "p-4",
|
|
1078
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Excluded Cohorts" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1079
|
+
className: "font-mono text-xl",
|
|
1080
|
+
children: excludedCount
|
|
1081
|
+
})]
|
|
1082
|
+
}) }),
|
|
1083
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, {
|
|
1084
|
+
className: "col-span-2 sm:col-span-1",
|
|
1085
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1086
|
+
className: "p-4",
|
|
1087
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Bundle ID" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1088
|
+
className: "font-mono text-xs break-all leading-relaxed",
|
|
1089
|
+
children: bundleId
|
|
1090
|
+
})]
|
|
1091
|
+
})
|
|
1092
|
+
})
|
|
1093
|
+
]
|
|
1094
|
+
}),
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1096
|
+
className: "p-4 pb-3",
|
|
1097
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1098
|
+
className: "text-sm",
|
|
1099
|
+
children: "Numeric Cohorts"
|
|
1100
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Listed in ascending order for readability." })]
|
|
1101
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
|
|
1102
|
+
className: "p-4 pt-0",
|
|
1103
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1104
|
+
className: "max-h-[50vh] overflow-y-auto rounded-lg border bg-muted/20 p-3 sm:max-h-[45vh]",
|
|
1105
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1106
|
+
className: "grid grid-cols-3 gap-2 sm:grid-cols-6 lg:grid-cols-8",
|
|
1107
|
+
children: rolloutCohorts.map((cohortValue) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
1108
|
+
variant: "outline",
|
|
1109
|
+
className: "justify-center font-mono",
|
|
1110
|
+
children: cohortValue
|
|
1111
|
+
}, cohortValue))
|
|
1112
|
+
})
|
|
1113
|
+
})
|
|
1114
|
+
})] }),
|
|
1115
|
+
hasTargetCohorts ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1116
|
+
className: "p-4 pb-3",
|
|
1117
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1118
|
+
className: "text-sm",
|
|
1119
|
+
children: "Target Cohorts"
|
|
1120
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "These cohorts are also included, even if they are outside the numeric rollout." })]
|
|
1121
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
|
|
1122
|
+
className: "p-4 pt-0",
|
|
1123
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1124
|
+
className: "flex flex-wrap gap-2 rounded-lg border bg-muted/20 p-3",
|
|
1125
|
+
children: normalizedTargetCohorts.map((cohort) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
1126
|
+
variant: "secondary",
|
|
1127
|
+
className: "max-w-full font-mono",
|
|
1128
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1129
|
+
className: "truncate",
|
|
1130
|
+
children: cohort
|
|
1131
|
+
})
|
|
1132
|
+
}, cohort))
|
|
1133
|
+
})
|
|
1134
|
+
})] }) : null
|
|
1135
|
+
] });
|
|
1019
1136
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Dialog$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTrigger, {
|
|
1020
1137
|
asChild: true,
|
|
1021
1138
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
@@ -1026,84 +1143,50 @@ function RolloutCohortsDialog({ bundleId, rolloutCohortCount, targetCohorts, tri
|
|
|
1026
1143
|
onClick: (event) => event.stopPropagation(),
|
|
1027
1144
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(List, { className: "h-3.5 w-3.5" }), triggerLabel]
|
|
1028
1145
|
})
|
|
1029
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.
|
|
1030
|
-
className: "sm:max-w-3xl",
|
|
1031
|
-
children:
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
children: rolloutCohorts.length
|
|
1050
|
-
})]
|
|
1051
|
-
}) }),
|
|
1052
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1053
|
-
className: "p-4",
|
|
1054
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Excluded Cohorts" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1055
|
-
className: "font-mono text-xl",
|
|
1056
|
-
children: excludedCount
|
|
1057
|
-
})]
|
|
1058
|
-
}) }),
|
|
1059
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1060
|
-
className: "p-4",
|
|
1061
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Bundle ID" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1062
|
-
className: "font-mono text-xs break-all leading-relaxed",
|
|
1063
|
-
children: bundleId
|
|
1064
|
-
})]
|
|
1065
|
-
}) })
|
|
1066
|
-
]
|
|
1067
|
-
}),
|
|
1068
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
1069
|
-
className: "p-4 pb-3",
|
|
1070
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1071
|
-
className: "text-sm",
|
|
1072
|
-
children: "Numeric Cohorts"
|
|
1073
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Listed in ascending order for readability." })]
|
|
1074
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
|
|
1075
|
-
className: "p-4 pt-0",
|
|
1076
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1077
|
-
className: "max-h-[50vh] overflow-y-auto rounded-lg border bg-muted/20 p-3",
|
|
1146
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogContent, {
|
|
1147
|
+
className: isMobile ? "top-0 left-0 h-dvh max-w-none translate-x-0 translate-y-0 rounded-none border-0 p-0" : "sm:max-w-3xl",
|
|
1148
|
+
children: isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1149
|
+
className: "flex h-full flex-col overflow-hidden",
|
|
1150
|
+
children: [
|
|
1151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, {
|
|
1152
|
+
className: "shrink-0 border-b border-border/70 px-4 py-4",
|
|
1153
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: "Rolled Out Cohorts" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogDescription, { children: [
|
|
1154
|
+
rolloutPercentage,
|
|
1155
|
+
"% rollout currently targets",
|
|
1156
|
+
" ",
|
|
1157
|
+
rolloutCohorts.length,
|
|
1158
|
+
" of ",
|
|
1159
|
+
NUMERIC_COHORT_SIZE,
|
|
1160
|
+
" numeric cohorts. The selected set stays stable for this bundle as you expand or shrink rollout.",
|
|
1161
|
+
hasTargetCohorts ? " Target Cohorts are added on top of this numeric rollout." : ""
|
|
1162
|
+
] })]
|
|
1163
|
+
}),
|
|
1164
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1165
|
+
className: "flex-1 overflow-y-auto px-4 py-4",
|
|
1078
1166
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1079
|
-
className: "
|
|
1080
|
-
children:
|
|
1081
|
-
variant: "outline",
|
|
1082
|
-
className: "justify-center font-mono",
|
|
1083
|
-
children: cohortValue
|
|
1084
|
-
}, cohortValue))
|
|
1167
|
+
className: "flex flex-col gap-4",
|
|
1168
|
+
children: dialogBody
|
|
1085
1169
|
})
|
|
1170
|
+
}),
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogFooter, {
|
|
1172
|
+
className: "shrink-0 border-t border-border/70 px-4 py-3",
|
|
1173
|
+
showCloseButton: true
|
|
1086
1174
|
})
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
className: "font-mono",
|
|
1101
|
-
children: cohort
|
|
1102
|
-
}, cohort))
|
|
1103
|
-
})
|
|
1104
|
-
})] }) : null,
|
|
1175
|
+
]
|
|
1176
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: "Rolled Out Cohorts" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogDescription, { children: [
|
|
1178
|
+
rolloutPercentage,
|
|
1179
|
+
"% rollout currently targets",
|
|
1180
|
+
" ",
|
|
1181
|
+
rolloutCohorts.length,
|
|
1182
|
+
" of ",
|
|
1183
|
+
NUMERIC_COHORT_SIZE,
|
|
1184
|
+
" numeric cohorts. The selected set stays stable for this bundle as you expand or shrink rollout.",
|
|
1185
|
+
hasTargetCohorts ? " Target Cohorts are added on top of this numeric rollout." : ""
|
|
1186
|
+
] })] }),
|
|
1187
|
+
dialogBody,
|
|
1105
1188
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogFooter, { showCloseButton: true })
|
|
1106
|
-
]
|
|
1189
|
+
] })
|
|
1107
1190
|
})] });
|
|
1108
1191
|
}
|
|
1109
1192
|
var MIN_ROLLOUT_COHORT_COUNT = 10;
|
|
@@ -1532,6 +1615,53 @@ function BundleEditorForm({ bundle, onClose, onBusyChange }) {
|
|
|
1532
1615
|
]
|
|
1533
1616
|
});
|
|
1534
1617
|
}
|
|
1618
|
+
function HashValueDisplay({ value, maxLength = 12, className }) {
|
|
1619
|
+
const isTruncated = value.length > maxLength;
|
|
1620
|
+
const truncated = isTruncated ? value.slice(0, maxLength) : value;
|
|
1621
|
+
const copyValue = async () => {
|
|
1622
|
+
try {
|
|
1623
|
+
await navigator.clipboard.writeText(value);
|
|
1624
|
+
toast.success("Copied to clipboard", { description: value });
|
|
1625
|
+
} catch {
|
|
1626
|
+
toast.error("Failed to copy value");
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
const handleClick = (event) => {
|
|
1630
|
+
event.preventDefault();
|
|
1631
|
+
event.stopPropagation();
|
|
1632
|
+
copyValue();
|
|
1633
|
+
};
|
|
1634
|
+
const handleKeyDown = (event) => {
|
|
1635
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
1636
|
+
event.preventDefault();
|
|
1637
|
+
event.stopPropagation();
|
|
1638
|
+
copyValue();
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1641
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1642
|
+
translate: "no",
|
|
1643
|
+
className: cn("font-mono text-xs tabular-nums whitespace-nowrap", className),
|
|
1644
|
+
children: truncated
|
|
1645
|
+
});
|
|
1646
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Tooltip$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipTrigger, {
|
|
1647
|
+
asChild: true,
|
|
1648
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
1649
|
+
type: "button",
|
|
1650
|
+
translate: "no",
|
|
1651
|
+
className: cn("ring-ring/30 bg-muted/40 border-border/70 inline-flex min-w-0 max-w-full cursor-pointer items-center rounded-md border px-1.5 py-0.5 align-top shadow-xs outline-none transition-[background-color,border-color,transform,box-shadow]", "hover:bg-muted/70 active:scale-[0.98] active:bg-muted/85 focus-visible:ring-[2px]", "touch-manipulation select-none", !isTruncated && "cursor-copy"),
|
|
1652
|
+
onClick: handleClick,
|
|
1653
|
+
onKeyDown: handleKeyDown,
|
|
1654
|
+
children: content
|
|
1655
|
+
})
|
|
1656
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipContent, {
|
|
1657
|
+
hidden: !isTruncated,
|
|
1658
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
1659
|
+
translate: "no",
|
|
1660
|
+
className: "break-all font-mono text-xs tabular-nums",
|
|
1661
|
+
children: value
|
|
1662
|
+
})
|
|
1663
|
+
})] });
|
|
1664
|
+
}
|
|
1535
1665
|
var normalizeGitUrl = (gitUrl) => {
|
|
1536
1666
|
const trimmedGitUrl = gitUrl.trim();
|
|
1537
1667
|
if (trimmedGitUrl.startsWith("git@")) {
|
|
@@ -1556,71 +1686,115 @@ var getCommitUrl = (gitUrl, commitHash) => {
|
|
|
1556
1686
|
} catch {}
|
|
1557
1687
|
return `${normalizedGitUrl}/commit/${commitHash}`;
|
|
1558
1688
|
};
|
|
1689
|
+
function Row({ label, value }) {
|
|
1690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1691
|
+
className: "flex flex-col gap-1.5 sm:flex-row sm:items-start sm:justify-between sm:gap-4",
|
|
1692
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1693
|
+
className: "text-muted-foreground",
|
|
1694
|
+
children: label
|
|
1695
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1696
|
+
className: "min-w-0 text-left text-sm sm:text-right",
|
|
1697
|
+
children: value
|
|
1698
|
+
})]
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1559
1701
|
function BundleMetadata({ bundle }) {
|
|
1560
1702
|
const { data: configData, isFetched } = useConfigQuery();
|
|
1561
|
-
const
|
|
1703
|
+
const patchBaseBundleId = getPatchBaseBundleId(bundle);
|
|
1704
|
+
const hbcPatchFileHash = getPatchFileHash(bundle);
|
|
1705
|
+
const hbcPatchBaseFileHash = getPatchBaseFileHash(bundle);
|
|
1706
|
+
const hasMetadata = bundle.targetAppVersion || bundle.fingerprintHash || bundle.gitCommitHash || bundle.fileHash || patchBaseBundleId || hbcPatchBaseFileHash || hbcPatchFileHash;
|
|
1562
1707
|
const gitCommitUrl = bundle.gitCommitHash && isFetched ? getCommitUrl(configData?.console.gitUrl, bundle.gitCommitHash) : null;
|
|
1563
1708
|
if (!hasMetadata) return null;
|
|
1564
1709
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
1565
1710
|
className: "text-sm font-medium",
|
|
1566
1711
|
children: "Metadata"
|
|
1567
1712
|
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardContent, {
|
|
1568
|
-
className: "
|
|
1713
|
+
className: "flex flex-col gap-3 text-sm",
|
|
1569
1714
|
children: [
|
|
1570
|
-
bundle.targetAppVersion
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
children: "App Version"
|
|
1575
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1715
|
+
bundle.targetAppVersion ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1716
|
+
label: "App Version",
|
|
1717
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1718
|
+
translate: "no",
|
|
1576
1719
|
className: "font-mono",
|
|
1577
1720
|
children: bundle.targetAppVersion
|
|
1578
|
-
})
|
|
1579
|
-
}),
|
|
1580
|
-
bundle.fingerprintHash
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
})
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1721
|
+
})
|
|
1722
|
+
}) : null,
|
|
1723
|
+
bundle.fingerprintHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1724
|
+
label: "Fingerprint",
|
|
1725
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
1726
|
+
value: bundle.fingerprintHash,
|
|
1727
|
+
maxLength: 16
|
|
1728
|
+
})
|
|
1729
|
+
}) : null,
|
|
1730
|
+
bundle.gitCommitHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1731
|
+
label: "Git Commit",
|
|
1732
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1733
|
+
className: "flex items-center justify-start gap-1 sm:justify-end",
|
|
1734
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
1735
|
+
value: bundle.gitCommitHash,
|
|
1736
|
+
maxLength: 12,
|
|
1737
|
+
className: gitCommitUrl ? "text-primary" : void 0
|
|
1738
|
+
}), gitCommitUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
|
|
1739
|
+
href: gitCommitUrl,
|
|
1740
|
+
target: "_blank",
|
|
1741
|
+
rel: "noopener noreferrer",
|
|
1742
|
+
className: "shrink-0 text-primary hover:underline",
|
|
1743
|
+
"aria-label": "Open git commit",
|
|
1744
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExternalLink, {
|
|
1745
|
+
"aria-hidden": "true",
|
|
1746
|
+
className: "h-3 w-3"
|
|
1747
|
+
})
|
|
1748
|
+
}) : null]
|
|
1749
|
+
})
|
|
1750
|
+
}) : null,
|
|
1751
|
+
bundle.fileHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1752
|
+
label: "Bundle Hash",
|
|
1753
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
1754
|
+
value: bundle.fileHash,
|
|
1755
|
+
maxLength: 16
|
|
1756
|
+
})
|
|
1757
|
+
}) : null,
|
|
1758
|
+
patchBaseBundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1759
|
+
label: "Patch Base",
|
|
1760
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
1761
|
+
bundleId: patchBaseBundleId,
|
|
1762
|
+
maxLength: 18,
|
|
1763
|
+
fullOnMobile: true
|
|
1764
|
+
})
|
|
1765
|
+
}) : null,
|
|
1766
|
+
hbcPatchBaseFileHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1767
|
+
label: "Base Hash",
|
|
1768
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
1769
|
+
value: hbcPatchBaseFileHash,
|
|
1770
|
+
maxLength: 16
|
|
1771
|
+
})
|
|
1772
|
+
}) : null,
|
|
1773
|
+
hbcPatchFileHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, {
|
|
1774
|
+
label: "Patch Hash",
|
|
1775
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
1776
|
+
value: hbcPatchFileHash,
|
|
1777
|
+
maxLength: 16
|
|
1778
|
+
})
|
|
1779
|
+
}) : null
|
|
1616
1780
|
]
|
|
1617
1781
|
})] });
|
|
1618
1782
|
}
|
|
1619
1783
|
function BundleEditorSheet({ bundleId, bundle, loading = false, open, onOpenChange }) {
|
|
1620
1784
|
const [isSaving, setIsSaving] = (0, import_react.useState)(false);
|
|
1785
|
+
const isMobile = useIsMobile();
|
|
1621
1786
|
(0, import_react.useEffect)(() => {
|
|
1622
1787
|
if (!open) setIsSaving(false);
|
|
1623
1788
|
}, [open]);
|
|
1789
|
+
(0, import_react.useEffect)(() => {
|
|
1790
|
+
if (typeof window === "undefined") return;
|
|
1791
|
+
const refreshThemeChrome = () => {
|
|
1792
|
+
window.dispatchEvent(new Event("hot-updater:refresh-theme-chrome"));
|
|
1793
|
+
};
|
|
1794
|
+
refreshThemeChrome();
|
|
1795
|
+
const timeoutId = window.setTimeout(refreshThemeChrome, 180);
|
|
1796
|
+
return () => window.clearTimeout(timeoutId);
|
|
1797
|
+
}, [open]);
|
|
1624
1798
|
const handleOpenChange = (nextOpen) => {
|
|
1625
1799
|
if (!nextOpen && isSaving) return;
|
|
1626
1800
|
if (!nextOpen) setIsSaving(false);
|
|
@@ -1630,11 +1804,70 @@ function BundleEditorSheet({ bundleId, bundle, loading = false, open, onOpenChan
|
|
|
1630
1804
|
setIsSaving(false);
|
|
1631
1805
|
onOpenChange(false);
|
|
1632
1806
|
};
|
|
1807
|
+
const headerContent = bundle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleBasicInfo, { bundle }) : loading ? bundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
1808
|
+
translate: "no",
|
|
1809
|
+
className: "font-mono text-xs",
|
|
1810
|
+
children: [
|
|
1811
|
+
"Loading ",
|
|
1812
|
+
bundleId,
|
|
1813
|
+
"…"
|
|
1814
|
+
]
|
|
1815
|
+
}) : "Loading bundle details…" : bundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
1816
|
+
translate: "no",
|
|
1817
|
+
className: "font-mono text-xs",
|
|
1818
|
+
children: ["Bundle not found: ", bundleId]
|
|
1819
|
+
}) : "Bundle details unavailable";
|
|
1820
|
+
const bodyContent = bundle ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1821
|
+
className: "flex flex-col gap-6 px-4 pb-4 sm:px-6 sm:pb-6",
|
|
1822
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleEditorForm, {
|
|
1823
|
+
bundle,
|
|
1824
|
+
onClose: closeSheet,
|
|
1825
|
+
onBusyChange: setIsSaving
|
|
1826
|
+
}, bundle.id), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleMetadata, { bundle })]
|
|
1827
|
+
}) : loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1828
|
+
className: "flex flex-col gap-4 px-4 pb-4 sm:px-6 sm:pb-6",
|
|
1829
|
+
children: [
|
|
1830
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }),
|
|
1831
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-28 w-full" }),
|
|
1832
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }),
|
|
1833
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" })
|
|
1834
|
+
]
|
|
1835
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1836
|
+
className: "px-4 pb-4 text-sm text-muted-foreground sm:px-6 sm:pb-6",
|
|
1837
|
+
children: "The requested bundle could not be loaded."
|
|
1838
|
+
});
|
|
1839
|
+
if (isMobile) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
|
|
1840
|
+
open,
|
|
1841
|
+
onOpenChange: handleOpenChange,
|
|
1842
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogContent, {
|
|
1843
|
+
className: "top-0 left-0 h-dvh max-w-none translate-x-0 translate-y-0 rounded-none border-0 p-0",
|
|
1844
|
+
showCloseButton: !isSaving,
|
|
1845
|
+
onEscapeKeyDown: (event) => {
|
|
1846
|
+
if (isSaving) event.preventDefault();
|
|
1847
|
+
},
|
|
1848
|
+
onInteractOutside: (event) => {
|
|
1849
|
+
if (isSaving) event.preventDefault();
|
|
1850
|
+
},
|
|
1851
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1852
|
+
className: "flex h-full flex-col overflow-hidden",
|
|
1853
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, {
|
|
1854
|
+
className: "shrink-0 border-b border-border/70 px-4 py-4 sm:px-6",
|
|
1855
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: bundle ? "Bundle Detail" : "Bundle Details" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, {
|
|
1856
|
+
asChild: true,
|
|
1857
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: headerContent })
|
|
1858
|
+
})]
|
|
1859
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1860
|
+
className: "flex-1 overflow-y-auto",
|
|
1861
|
+
children: bodyContent
|
|
1862
|
+
})]
|
|
1863
|
+
})
|
|
1864
|
+
})
|
|
1865
|
+
});
|
|
1633
1866
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Sheet, {
|
|
1634
1867
|
open,
|
|
1635
1868
|
onOpenChange: handleOpenChange,
|
|
1636
1869
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SheetContent, {
|
|
1637
|
-
className: "w-[600px] sm:max-w-[600px]
|
|
1870
|
+
className: "w-[600px] overflow-y-auto sm:max-w-[600px]",
|
|
1638
1871
|
showCloseButton: !isSaving,
|
|
1639
1872
|
onEscapeKeyDown: (event) => {
|
|
1640
1873
|
if (isSaving) event.preventDefault();
|
|
@@ -1642,34 +1875,63 @@ function BundleEditorSheet({ bundleId, bundle, loading = false, open, onOpenChan
|
|
|
1642
1875
|
onInteractOutside: (event) => {
|
|
1643
1876
|
if (isSaving) event.preventDefault();
|
|
1644
1877
|
},
|
|
1645
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SheetHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SheetTitle, { children: bundle ? "
|
|
1646
|
-
className: "font-mono text-xs",
|
|
1647
|
-
children: ["Loading ", bundleId]
|
|
1648
|
-
}) : "Loading bundle details" : bundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
1649
|
-
className: "font-mono text-xs",
|
|
1650
|
-
children: ["Bundle not found: ", bundleId]
|
|
1651
|
-
}) : "Bundle details unavailable" })] }), bundle ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1652
|
-
className: "px-6 pb-6 space-y-6",
|
|
1653
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleEditorForm, {
|
|
1654
|
-
bundle,
|
|
1655
|
-
onClose: closeSheet,
|
|
1656
|
-
onBusyChange: setIsSaving
|
|
1657
|
-
}, bundle.id), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleMetadata, { bundle })]
|
|
1658
|
-
}) : loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1659
|
-
className: "px-6 pb-6 space-y-4",
|
|
1660
|
-
children: [
|
|
1661
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }),
|
|
1662
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-28 w-full" }),
|
|
1663
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }),
|
|
1664
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" })
|
|
1665
|
-
]
|
|
1666
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1667
|
-
className: "px-6 pb-6 text-sm text-muted-foreground",
|
|
1668
|
-
children: "The requested bundle could not be loaded."
|
|
1669
|
-
})]
|
|
1878
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SheetHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SheetTitle, { children: bundle ? "Bundle Detail" : "Bundle Details" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SheetDescription, { children: headerContent })] }), bodyContent]
|
|
1670
1879
|
})
|
|
1671
1880
|
});
|
|
1672
1881
|
}
|
|
1882
|
+
var channelColors = {
|
|
1883
|
+
production: "bg-green-500/10 text-green-700 dark:text-green-400 border-green-500/20",
|
|
1884
|
+
dev: "bg-blue-500/10 text-blue-700 dark:text-blue-400 border-blue-500/20",
|
|
1885
|
+
staging: "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 border-yellow-500/20"
|
|
1886
|
+
};
|
|
1887
|
+
function ChannelBadge({ channel, className }) {
|
|
1888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
1889
|
+
variant: "outline",
|
|
1890
|
+
className: cn(channelColors[channel.toLowerCase()] || "bg-gray-500/10 text-gray-700 dark:text-gray-400 border-gray-500/20", className),
|
|
1891
|
+
children: channel
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
function EnabledStatusIcon({ enabled, className, falseIcon = "x", colorMode = "semantic" }) {
|
|
1895
|
+
const iconColorClassName = colorMode === "inherit" ? "text-current" : void 0;
|
|
1896
|
+
if (enabled) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: cn("h-4 w-4", iconColorClassName ?? "text-green-600 dark:text-green-400", className) });
|
|
1897
|
+
if (falseIcon === "minus") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minus, { className: cn("h-4 w-4", iconColorClassName ?? "text-muted-foreground", className) });
|
|
1898
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { className: cn("h-4 w-4", iconColorClassName ?? "text-red-600 dark:text-red-400", className) });
|
|
1899
|
+
}
|
|
1900
|
+
function RolloutPercentageBadge({ percentage, className }) {
|
|
1901
|
+
const isPartialRollout = percentage < 100;
|
|
1902
|
+
const formattedPercentage = percentage.toFixed(1);
|
|
1903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
|
|
1904
|
+
variant: isPartialRollout ? "secondary" : "default",
|
|
1905
|
+
className: cn("gap-1", className),
|
|
1906
|
+
children: [
|
|
1907
|
+
isPartialRollout && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-3 w-3" }),
|
|
1908
|
+
formattedPercentage,
|
|
1909
|
+
"%"
|
|
1910
|
+
]
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
import_dayjs_min.default.extend(import_relativeTime.default);
|
|
1914
|
+
function TimestampDisplay({ uuid, format = "relative" }) {
|
|
1915
|
+
const date = (0, import_dayjs_min.default)(extractTimestampFromUUIDv7(uuid));
|
|
1916
|
+
if (format === "relative") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1917
|
+
className: "text-sm text-muted-foreground",
|
|
1918
|
+
children: date.fromNow()
|
|
1919
|
+
});
|
|
1920
|
+
if (format === "absolute") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1921
|
+
className: "text-sm text-muted-foreground",
|
|
1922
|
+
children: date.format("YYYY-MM-DD HH:mm:ss")
|
|
1923
|
+
});
|
|
1924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1925
|
+
className: "flex flex-col",
|
|
1926
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1927
|
+
className: "text-sm",
|
|
1928
|
+
children: date.fromNow()
|
|
1929
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1930
|
+
className: "text-xs text-muted-foreground",
|
|
1931
|
+
children: date.format("YYYY-MM-DD HH:mm:ss")
|
|
1932
|
+
})]
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1673
1935
|
function Table({ className, ...props }) {
|
|
1674
1936
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1675
1937
|
"data-slot": "table-container",
|
|
@@ -1716,80 +1978,230 @@ function TableCell({ className, ...props }) {
|
|
|
1716
1978
|
...props
|
|
1717
1979
|
});
|
|
1718
1980
|
}
|
|
1719
|
-
function
|
|
1720
|
-
const
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1981
|
+
function BundleChildrenPanel({ panelId, bundle, bundles, loading, onDetailClick }) {
|
|
1982
|
+
const isMobile = useIsMobile();
|
|
1983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1984
|
+
id: panelId,
|
|
1985
|
+
className: "border-t bg-muted/10 p-3 sm:p-4",
|
|
1986
|
+
"aria-live": "polite",
|
|
1987
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1988
|
+
className: "flex flex-col gap-4",
|
|
1989
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1990
|
+
className: "flex flex-wrap items-center justify-between gap-3",
|
|
1991
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1992
|
+
className: "flex min-w-0 items-start gap-2 text-sm sm:items-center",
|
|
1993
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1994
|
+
className: "text-muted-foreground",
|
|
1995
|
+
children: "Base bundle"
|
|
1996
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
1997
|
+
bundleId: bundle.id,
|
|
1998
|
+
maxLength: 18,
|
|
1999
|
+
fullOnMobile: true
|
|
2000
|
+
})]
|
|
2001
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
|
|
2002
|
+
variant: "outline",
|
|
2003
|
+
children: [
|
|
2004
|
+
bundles.length,
|
|
2005
|
+
" ",
|
|
2006
|
+
bundles.length === 1 ? "patch" : "patches"
|
|
2007
|
+
]
|
|
2008
|
+
})]
|
|
2009
|
+
}), loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2010
|
+
className: "flex flex-col gap-2",
|
|
2011
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" })]
|
|
2012
|
+
}) : bundles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2013
|
+
className: "flex flex-col gap-2",
|
|
2014
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2015
|
+
className: "text-xs font-semibold uppercase text-muted-foreground/70",
|
|
2016
|
+
children: "Patch bundles from this base"
|
|
2017
|
+
}), isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2018
|
+
className: "flex flex-col gap-2",
|
|
2019
|
+
children: bundles.map((childBundle) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2020
|
+
className: "rounded-md border bg-background p-3",
|
|
2021
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2022
|
+
className: "flex flex-col gap-3",
|
|
2023
|
+
children: [
|
|
2024
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2025
|
+
className: "space-y-1",
|
|
2026
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2027
|
+
className: "text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2028
|
+
children: "Patch Bundle"
|
|
2029
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2030
|
+
bundleId: childBundle.id,
|
|
2031
|
+
maxLength: 18,
|
|
2032
|
+
fullOnMobile: true
|
|
2033
|
+
})]
|
|
2034
|
+
}),
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2036
|
+
className: "space-y-1",
|
|
2037
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2038
|
+
className: "text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2039
|
+
children: "Relation"
|
|
2040
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2041
|
+
className: "flex flex-col items-start gap-1 text-sm",
|
|
2042
|
+
children: [
|
|
2043
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2044
|
+
bundleId: bundle.id,
|
|
2045
|
+
maxLength: 12,
|
|
2046
|
+
fullOnMobile: true
|
|
2047
|
+
}),
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowRight, { className: "h-4 w-4 rotate-90 text-muted-foreground" }),
|
|
2049
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2050
|
+
bundleId: childBundle.id,
|
|
2051
|
+
maxLength: 12,
|
|
2052
|
+
fullOnMobile: true
|
|
2053
|
+
})
|
|
2054
|
+
]
|
|
2055
|
+
})]
|
|
2056
|
+
}),
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2058
|
+
className: "flex items-center justify-between gap-3",
|
|
2059
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2060
|
+
className: "space-y-1",
|
|
2061
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2062
|
+
className: "text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2063
|
+
children: "Artifact"
|
|
2064
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
2065
|
+
variant: "secondary",
|
|
2066
|
+
children: "bsdiff"
|
|
2067
|
+
})]
|
|
2068
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2069
|
+
className: "space-y-1 text-right",
|
|
2070
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2071
|
+
className: "text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2072
|
+
children: "Created"
|
|
2073
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2074
|
+
className: "text-xs tabular-nums text-foreground",
|
|
2075
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimestampDisplay, { uuid: childBundle.id })
|
|
2076
|
+
})]
|
|
2077
|
+
})]
|
|
2078
|
+
}),
|
|
2079
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
2080
|
+
type: "button",
|
|
2081
|
+
variant: "outline",
|
|
2082
|
+
size: "sm",
|
|
2083
|
+
className: "w-full",
|
|
2084
|
+
onClick: () => onDetailClick(childBundle),
|
|
2085
|
+
children: "Detail"
|
|
2086
|
+
})
|
|
2087
|
+
]
|
|
2088
|
+
})
|
|
2089
|
+
}, childBundle.id))
|
|
2090
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2091
|
+
className: "overflow-x-auto rounded-md border bg-background",
|
|
2092
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Table, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
|
|
2093
|
+
className: "hover:bg-transparent",
|
|
2094
|
+
children: [
|
|
2095
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, { children: "Patch Bundle" }),
|
|
2096
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, { children: "Relation" }),
|
|
2097
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, { children: "Artifact" }),
|
|
2098
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, { children: "Created" }),
|
|
2099
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
|
|
2100
|
+
className: "w-[96px] text-right",
|
|
2101
|
+
children: "Detail"
|
|
2102
|
+
})
|
|
2103
|
+
]
|
|
2104
|
+
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: bundles.map((childBundle) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, { children: [
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2106
|
+
bundleId: childBundle.id,
|
|
2107
|
+
maxLength: 18,
|
|
2108
|
+
fullOnMobile: true
|
|
2109
|
+
}) }),
|
|
2110
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2111
|
+
className: "flex min-w-[280px] flex-col items-start gap-1 sm:flex-row sm:items-center sm:gap-2",
|
|
2112
|
+
children: [
|
|
2113
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2114
|
+
bundleId: bundle.id,
|
|
2115
|
+
maxLength: 12,
|
|
2116
|
+
fullOnMobile: true
|
|
2117
|
+
}),
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowRight, { className: "h-4 w-4 shrink-0 rotate-90 text-muted-foreground sm:rotate-0" }),
|
|
2119
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2120
|
+
bundleId: childBundle.id,
|
|
2121
|
+
maxLength: 12,
|
|
2122
|
+
fullOnMobile: true
|
|
2123
|
+
})
|
|
2124
|
+
]
|
|
2125
|
+
}) }),
|
|
2126
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
2127
|
+
variant: "secondary",
|
|
2128
|
+
children: "bsdiff"
|
|
2129
|
+
}) }),
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2131
|
+
className: "tabular-nums",
|
|
2132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimestampDisplay, { uuid: childBundle.id })
|
|
2133
|
+
}),
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
2135
|
+
className: "text-right",
|
|
2136
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
2137
|
+
type: "button",
|
|
2138
|
+
variant: "outline",
|
|
2139
|
+
size: "sm",
|
|
2140
|
+
onClick: () => onDetailClick(childBundle),
|
|
2141
|
+
children: "Detail"
|
|
2142
|
+
})
|
|
2143
|
+
})
|
|
2144
|
+
] }, childBundle.id)) })] })
|
|
2145
|
+
})]
|
|
2146
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2147
|
+
className: "flex flex-col gap-2",
|
|
2148
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2149
|
+
className: "text-xs font-semibold uppercase text-muted-foreground/70",
|
|
2150
|
+
children: "Patch bundles from this base"
|
|
2151
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2152
|
+
className: "rounded-md border bg-background p-3 text-sm text-muted-foreground",
|
|
2153
|
+
children: "No direct patch bundles."
|
|
2154
|
+
})]
|
|
2155
|
+
})]
|
|
1730
2156
|
})
|
|
1731
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
1732
|
-
className: "font-mono text-xs",
|
|
1733
|
-
children: bundleId
|
|
1734
|
-
}) })] }) });
|
|
1735
|
-
}
|
|
1736
|
-
var channelColors = {
|
|
1737
|
-
production: "bg-green-500/10 text-green-700 dark:text-green-400 border-green-500/20",
|
|
1738
|
-
dev: "bg-blue-500/10 text-blue-700 dark:text-blue-400 border-blue-500/20",
|
|
1739
|
-
staging: "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 border-yellow-500/20"
|
|
1740
|
-
};
|
|
1741
|
-
function ChannelBadge({ channel, className }) {
|
|
1742
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
1743
|
-
variant: "outline",
|
|
1744
|
-
className: cn(channelColors[channel.toLowerCase()] || "bg-gray-500/10 text-gray-700 dark:text-gray-400 border-gray-500/20", className),
|
|
1745
|
-
children: channel
|
|
1746
|
-
});
|
|
1747
|
-
}
|
|
1748
|
-
function EnabledStatusIcon({ enabled, className, falseIcon = "x" }) {
|
|
1749
|
-
if (enabled) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: cn("h-4 w-4 text-green-600 dark:text-green-400", className) });
|
|
1750
|
-
if (falseIcon === "minus") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minus, { className: cn("h-4 w-4 text-muted-foreground", className) });
|
|
1751
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { className: cn("h-4 w-4 text-red-600 dark:text-red-400", className) });
|
|
1752
|
-
}
|
|
1753
|
-
function RolloutPercentageBadge({ percentage, className }) {
|
|
1754
|
-
const isPartialRollout = percentage < 100;
|
|
1755
|
-
const formattedPercentage = percentage.toFixed(1);
|
|
1756
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
|
|
1757
|
-
variant: isPartialRollout ? "secondary" : "default",
|
|
1758
|
-
className: cn("gap-1", className),
|
|
1759
|
-
children: [
|
|
1760
|
-
isPartialRollout && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-3 w-3" }),
|
|
1761
|
-
formattedPercentage,
|
|
1762
|
-
"%"
|
|
1763
|
-
]
|
|
1764
2157
|
});
|
|
1765
2158
|
}
|
|
1766
|
-
|
|
1767
|
-
function
|
|
1768
|
-
const
|
|
1769
|
-
|
|
1770
|
-
className: "text-sm text-muted-foreground",
|
|
1771
|
-
children: date.fromNow()
|
|
1772
|
-
});
|
|
1773
|
-
if (format === "absolute") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1774
|
-
className: "text-sm text-muted-foreground",
|
|
1775
|
-
children: date.format("YYYY-MM-DD HH:mm:ss")
|
|
1776
|
-
});
|
|
2159
|
+
var columnHelper = createColumnHelper();
|
|
2160
|
+
function BundleIdCell({ bundle, expandedBundleId, onDetailClick, onToggleExpand }) {
|
|
2161
|
+
const isExpanded = bundle.id === expandedBundleId;
|
|
2162
|
+
const panelId = `bundle-lineage-panel-${bundle.id}`;
|
|
1777
2163
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1778
|
-
className: "flex
|
|
1779
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
className: "
|
|
1784
|
-
|
|
2164
|
+
className: "flex min-w-[240px] items-center gap-3",
|
|
2165
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
2166
|
+
type: "button",
|
|
2167
|
+
variant: "ghost",
|
|
2168
|
+
size: "icon",
|
|
2169
|
+
className: "size-8 shrink-0 touch-manipulation",
|
|
2170
|
+
"aria-label": isExpanded ? "Hide Lineage" : "Show Lineage",
|
|
2171
|
+
"aria-controls": panelId,
|
|
2172
|
+
"aria-expanded": isExpanded,
|
|
2173
|
+
onClick: (event) => {
|
|
2174
|
+
event.stopPropagation();
|
|
2175
|
+
onToggleExpand(bundle);
|
|
2176
|
+
},
|
|
2177
|
+
children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { "aria-hidden": "true" })
|
|
2178
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
2179
|
+
type: "button",
|
|
2180
|
+
className: cn("flex min-w-0 flex-col items-start rounded-sm text-left transition-colors", "focus-visible:ring-ring/30 focus-visible:ring-[2px] outline-none", "text-muted-foreground hover:text-foreground"),
|
|
2181
|
+
"aria-label": `Open details for bundle ${bundle.id}`,
|
|
2182
|
+
onClick: (event) => {
|
|
2183
|
+
event.stopPropagation();
|
|
2184
|
+
onDetailClick(bundle);
|
|
2185
|
+
},
|
|
2186
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2187
|
+
className: "min-w-0 text-foreground",
|
|
2188
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2189
|
+
bundleId: bundle.id,
|
|
2190
|
+
fullOnMobile: true
|
|
2191
|
+
})
|
|
2192
|
+
})
|
|
1785
2193
|
})]
|
|
1786
2194
|
});
|
|
1787
2195
|
}
|
|
1788
|
-
var
|
|
1789
|
-
var bundleColumns = [
|
|
2196
|
+
var createBundleColumns = ({ expandedBundleId, patchCountsByBundleId, onDetailClick, onToggleExpand }) => [
|
|
1790
2197
|
columnHelper.accessor("id", {
|
|
1791
2198
|
header: "Bundle ID",
|
|
1792
|
-
cell: (info) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2199
|
+
cell: (info) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdCell, {
|
|
2200
|
+
bundle: info.row.original,
|
|
2201
|
+
expandedBundleId,
|
|
2202
|
+
onDetailClick,
|
|
2203
|
+
onToggleExpand
|
|
2204
|
+
})
|
|
1793
2205
|
}),
|
|
1794
2206
|
columnHelper.accessor("channel", {
|
|
1795
2207
|
header: "Channel",
|
|
@@ -1805,27 +2217,45 @@ var bundleColumns = [
|
|
|
1805
2217
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: info.getValue() === "ios" ? "iOS" : "Android" })]
|
|
1806
2218
|
})
|
|
1807
2219
|
}),
|
|
2220
|
+
columnHelper.display({
|
|
2221
|
+
id: "patches",
|
|
2222
|
+
header: "Patches",
|
|
2223
|
+
cell: (info) => {
|
|
2224
|
+
const count = patchCountsByBundleId[info.row.original.id];
|
|
2225
|
+
if (count === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2226
|
+
className: "text-sm text-muted-foreground",
|
|
2227
|
+
children: "Checking"
|
|
2228
|
+
});
|
|
2229
|
+
if (count === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2230
|
+
className: "text-sm text-muted-foreground",
|
|
2231
|
+
children: "-"
|
|
2232
|
+
});
|
|
2233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
|
|
2234
|
+
variant: "secondary",
|
|
2235
|
+
children: [
|
|
2236
|
+
count,
|
|
2237
|
+
" ",
|
|
2238
|
+
count === 1 ? "patch" : "patches"
|
|
2239
|
+
]
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
}),
|
|
1808
2243
|
columnHelper.display({
|
|
1809
2244
|
id: "target",
|
|
1810
2245
|
header: "Target",
|
|
1811
2246
|
cell: (info) => {
|
|
1812
2247
|
const row = info.row.original;
|
|
1813
|
-
if (row.fingerprintHash) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1814
|
-
|
|
1815
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
})]
|
|
1821
|
-
})
|
|
1822
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
1823
|
-
className: "font-mono text-xs",
|
|
1824
|
-
children: row.fingerprintHash
|
|
1825
|
-
}) })] });
|
|
2248
|
+
if (row.fingerprintHash) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2249
|
+
className: "flex min-w-[220px] items-start gap-2",
|
|
2250
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FingerprintPattern, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HashValueDisplay, {
|
|
2251
|
+
value: row.fingerprintHash,
|
|
2252
|
+
maxLength: 12
|
|
2253
|
+
})]
|
|
2254
|
+
});
|
|
1826
2255
|
if (row.targetAppVersion) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1827
2256
|
className: "flex items-center gap-2",
|
|
1828
2257
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Package, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2258
|
+
translate: "no",
|
|
1829
2259
|
className: "text-sm",
|
|
1830
2260
|
children: row.targetAppVersion
|
|
1831
2261
|
})]
|
|
@@ -1866,8 +2296,29 @@ var bundleColumns = [
|
|
|
1866
2296
|
cell: (info) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimestampDisplay, { uuid: info.getValue() })
|
|
1867
2297
|
})
|
|
1868
2298
|
];
|
|
1869
|
-
function
|
|
2299
|
+
function MobileStatusBadge({ enabled, trueLabel, falseLabel, falseIcon = "x", trueTone = "success" }) {
|
|
2300
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
2301
|
+
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"),
|
|
2302
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnabledStatusIcon, {
|
|
2303
|
+
enabled,
|
|
2304
|
+
falseIcon,
|
|
2305
|
+
colorMode: "inherit",
|
|
2306
|
+
className: "h-3.5 w-3.5"
|
|
2307
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: enabled ? trueLabel : falseLabel })]
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
function BundlesTable({ bundles, pagination, expandedBundleId, selectedBundleId, onExpandedBundleChange, onDetailClick }) {
|
|
1870
2311
|
const { setFilters } = useFilterParams();
|
|
2312
|
+
const isMobile = useIsMobile();
|
|
2313
|
+
const cursorPagination = pagination;
|
|
2314
|
+
const { data: patchCountsByBundleId = {} } = useBundleChildCountsQuery(bundles.map((bundle) => bundle.id));
|
|
2315
|
+
const { data: childBundles = [], isLoading: isChildBundlesLoading } = useBundleChildrenQuery(expandedBundleId ?? "");
|
|
2316
|
+
const bundleColumns = createBundleColumns({
|
|
2317
|
+
expandedBundleId,
|
|
2318
|
+
patchCountsByBundleId,
|
|
2319
|
+
onDetailClick,
|
|
2320
|
+
onToggleExpand: (bundle) => onExpandedBundleChange(expandedBundleId === bundle.id ? void 0 : bundle.id)
|
|
2321
|
+
});
|
|
1871
2322
|
const table = useReactTable({
|
|
1872
2323
|
data: bundles,
|
|
1873
2324
|
columns: bundleColumns,
|
|
@@ -1878,7 +2329,7 @@ function BundlesTable({ bundles, pagination, selectedBundleId, onRowClick }) {
|
|
|
1878
2329
|
const currentPage = pagination?.currentPage ?? 1;
|
|
1879
2330
|
const totalPages = pagination?.totalPages ?? 0;
|
|
1880
2331
|
const handlePreviousPage = () => {
|
|
1881
|
-
const previousCursor =
|
|
2332
|
+
const previousCursor = cursorPagination?.previousCursor ?? bundles[0]?.id;
|
|
1882
2333
|
if (!previousCursor) return;
|
|
1883
2334
|
setFilters({
|
|
1884
2335
|
page: Math.max(1, currentPage - 1),
|
|
@@ -1887,7 +2338,7 @@ function BundlesTable({ bundles, pagination, selectedBundleId, onRowClick }) {
|
|
|
1887
2338
|
});
|
|
1888
2339
|
};
|
|
1889
2340
|
const handleNextPage = () => {
|
|
1890
|
-
const nextCursor =
|
|
2341
|
+
const nextCursor = cursorPagination?.nextCursor ?? bundles.at(-1)?.id;
|
|
1891
2342
|
if (!nextCursor) return;
|
|
1892
2343
|
setFilters({
|
|
1893
2344
|
page: currentPage + 1,
|
|
@@ -1898,35 +2349,223 @@ function BundlesTable({ bundles, pagination, selectedBundleId, onRowClick }) {
|
|
|
1898
2349
|
const startEntry = bundles.length === 0 ? 0 : (currentPage - 1) * 20 + 1;
|
|
1899
2350
|
const endEntry = startEntry === 0 ? 0 : startEntry + bundles.length - 1;
|
|
1900
2351
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1901
|
-
className: "
|
|
2352
|
+
className: "flex flex-col gap-4",
|
|
1902
2353
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1903
|
-
className: "rounded-lg border bg-card text-card-foreground shadow-sm
|
|
1904
|
-
children:
|
|
2354
|
+
className: "overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
2355
|
+
children: isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2356
|
+
className: "flex flex-col",
|
|
2357
|
+
children: bundles.length ? bundles.map((bundle) => {
|
|
2358
|
+
const isExpanded = bundle.id === expandedBundleId;
|
|
2359
|
+
const panelId = `bundle-lineage-panel-${bundle.id}`;
|
|
2360
|
+
const rolloutPercentage = (bundle.rolloutCohortCount ?? 1e3) / 10;
|
|
2361
|
+
const patchCount = patchCountsByBundleId[bundle.id];
|
|
2362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2363
|
+
"data-state": bundle.id === selectedBundleId ? "selected" : void 0,
|
|
2364
|
+
className: cn("border-b border-border/60 last:border-b-0 data-[state=selected]:bg-muted/20", isExpanded && "bg-primary/5"),
|
|
2365
|
+
children: [
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
2367
|
+
type: "button",
|
|
2368
|
+
className: "flex w-full flex-col gap-4 p-4 text-left",
|
|
2369
|
+
onClick: () => onDetailClick(bundle),
|
|
2370
|
+
children: [
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2372
|
+
className: "flex items-start justify-between gap-3",
|
|
2373
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2374
|
+
className: "min-w-0 space-y-2",
|
|
2375
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2376
|
+
className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground/70",
|
|
2377
|
+
children: "Bundle"
|
|
2378
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2379
|
+
className: "min-w-0 text-sm font-medium",
|
|
2380
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
|
|
2381
|
+
bundleId: bundle.id,
|
|
2382
|
+
maxLength: 18,
|
|
2383
|
+
fullOnMobile: true
|
|
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",
|
|
2426
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2427
|
+
className: "mb-1 text-[11px] font-medium uppercase text-muted-foreground/70",
|
|
2428
|
+
children: "Patches"
|
|
2429
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2430
|
+
className: "text-xs text-foreground",
|
|
2431
|
+
children: patchCount === void 0 ? "Checking" : patchCount > 0 ? `${patchCount} ${patchCount === 1 ? "patch" : "patches"}` : "-"
|
|
2432
|
+
})]
|
|
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
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2464
|
+
className: "min-w-0 text-right",
|
|
2465
|
+
children: bundle.fingerprintHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
2466
|
+
translate: "no",
|
|
2467
|
+
className: "inline-flex min-w-0 items-start gap-2 font-mono text-xs",
|
|
2468
|
+
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, {
|
|
2469
|
+
value: bundle.fingerprintHash,
|
|
2470
|
+
maxLength: 12
|
|
2471
|
+
})]
|
|
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
|
+
})
|
|
2480
|
+
})]
|
|
2481
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2482
|
+
className: "flex items-start justify-between gap-3",
|
|
2483
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2484
|
+
className: "text-muted-foreground",
|
|
2485
|
+
children: "Message"
|
|
2486
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2487
|
+
className: "min-w-0 text-right text-xs text-foreground/80",
|
|
2488
|
+
children: bundle.message || "-"
|
|
2489
|
+
})]
|
|
2490
|
+
})]
|
|
2491
|
+
})
|
|
2492
|
+
]
|
|
2493
|
+
}),
|
|
2494
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2495
|
+
className: "border-t border-border/60 px-4 py-3",
|
|
2496
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
2497
|
+
type: "button",
|
|
2498
|
+
variant: "ghost",
|
|
2499
|
+
className: "h-9 w-full justify-between px-3 text-sm",
|
|
2500
|
+
"aria-label": isExpanded ? "Hide Lineage" : "Show Lineage",
|
|
2501
|
+
"aria-controls": panelId,
|
|
2502
|
+
"aria-expanded": isExpanded,
|
|
2503
|
+
onClick: () => onExpandedBundleChange(isExpanded ? void 0 : bundle.id),
|
|
2504
|
+
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, {
|
|
2505
|
+
className: "h-4 w-4",
|
|
2506
|
+
"aria-hidden": "true"
|
|
2507
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {
|
|
2508
|
+
className: "h-4 w-4",
|
|
2509
|
+
"aria-hidden": "true"
|
|
2510
|
+
})]
|
|
2511
|
+
})
|
|
2512
|
+
}),
|
|
2513
|
+
isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleChildrenPanel, {
|
|
2514
|
+
panelId,
|
|
2515
|
+
bundle,
|
|
2516
|
+
bundles: childBundles,
|
|
2517
|
+
loading: isChildBundlesLoading,
|
|
2518
|
+
onDetailClick
|
|
2519
|
+
}) : null
|
|
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, {
|
|
1905
2527
|
className: "bg-muted/40",
|
|
1906
2528
|
children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, {
|
|
1907
|
-
className: "
|
|
2529
|
+
className: "border-b border-border/60 hover:bg-transparent",
|
|
1908
2530
|
children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
|
|
1909
2531
|
className: "h-10 text-xs font-semibold uppercase text-muted-foreground/70",
|
|
1910
2532
|
children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())
|
|
1911
2533
|
}, header.id))
|
|
1912
2534
|
}, headerGroup.id))
|
|
1913
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) =>
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
className: "
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
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
|
|
2557
|
+
})
|
|
2558
|
+
})
|
|
2559
|
+
}) : null] }, row.original.id);
|
|
2560
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
|
|
1922
2561
|
colSpan: bundleColumns.length,
|
|
1923
2562
|
className: "h-32 text-center text-muted-foreground",
|
|
1924
2563
|
children: "No bundles found matching your filters."
|
|
1925
2564
|
}) }) })] })
|
|
1926
2565
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1927
|
-
className: "flex items-center justify-between
|
|
2566
|
+
className: "flex flex-col gap-3 px-2 sm:flex-row sm:items-center sm:justify-between",
|
|
1928
2567
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1929
|
-
className: "text-xs text-muted-foreground
|
|
2568
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
1930
2569
|
children: [
|
|
1931
2570
|
"Showing ",
|
|
1932
2571
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
@@ -1942,10 +2581,10 @@ function BundlesTable({ bundles, pagination, selectedBundleId, onRowClick }) {
|
|
|
1942
2581
|
" entries"
|
|
1943
2582
|
]
|
|
1944
2583
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1945
|
-
className: "flex items-center gap-3",
|
|
2584
|
+
className: "flex flex-wrap items-center gap-3 sm:justify-end",
|
|
1946
2585
|
children: [
|
|
1947
2586
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1948
|
-
className: "text-xs text-muted-foreground
|
|
2587
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
1949
2588
|
children: [
|
|
1950
2589
|
"Page ",
|
|
1951
2590
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
@@ -1967,16 +2606,16 @@ function BundlesTable({ bundles, pagination, selectedBundleId, onRowClick }) {
|
|
|
1967
2606
|
size: "sm",
|
|
1968
2607
|
onClick: handlePreviousPage,
|
|
1969
2608
|
disabled: !hasPreviousPage,
|
|
1970
|
-
className: "h-8 px-3 text-xs",
|
|
1971
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronLeft, {
|
|
2609
|
+
className: "h-8 flex-1 px-3 text-xs sm:flex-none",
|
|
2610
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronLeft, { "data-icon": "inline-start" }), "Previous"]
|
|
1972
2611
|
}),
|
|
1973
2612
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
1974
2613
|
variant: "outline",
|
|
1975
2614
|
size: "sm",
|
|
1976
2615
|
onClick: handleNextPage,
|
|
1977
2616
|
disabled: !hasNextPage,
|
|
1978
|
-
className: "h-8 px-3 text-xs",
|
|
1979
|
-
children: ["Next", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, {
|
|
2617
|
+
className: "h-8 flex-1 px-3 text-xs sm:flex-none",
|
|
2618
|
+
children: ["Next", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { "data-icon": "inline-end" })]
|
|
1980
2619
|
})
|
|
1981
2620
|
]
|
|
1982
2621
|
})]
|
|
@@ -1988,11 +2627,11 @@ function FilterToolbar() {
|
|
|
1988
2627
|
const { data: channels = [] } = useChannelsQuery();
|
|
1989
2628
|
const hasActiveFilters = filters.channel || filters.platform;
|
|
1990
2629
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
1991
|
-
className: "
|
|
2630
|
+
className: "sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-2 border-b bg-background px-3 py-3 sm:h-12 sm:flex-nowrap sm:bg-card/70 sm:px-4 sm:py-0 sm:backdrop-blur-sm",
|
|
1992
2631
|
children: [
|
|
1993
2632
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SidebarTrigger, { className: "-ml-1" }),
|
|
1994
2633
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1995
|
-
className: "flex items-center gap-1.5 text-muted-foreground ml-2",
|
|
2634
|
+
className: "ml-1 flex items-center gap-1.5 text-muted-foreground sm:ml-2",
|
|
1996
2635
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Funnel, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1997
2636
|
className: "text-xs font-medium",
|
|
1998
2637
|
children: "Filters"
|
|
@@ -2002,7 +2641,7 @@ function FilterToolbar() {
|
|
|
2002
2641
|
value: filters.platform || "all",
|
|
2003
2642
|
onValueChange: (value) => setFilters({ platform: value === "all" ? void 0 : value }),
|
|
2004
2643
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
2005
|
-
className: "w-[
|
|
2644
|
+
className: "h-8 w-[calc(50%-0.25rem)] min-w-[132px] text-xs sm:w-[140px]",
|
|
2006
2645
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { placeholder: "All Platforms" })
|
|
2007
2646
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [
|
|
2008
2647
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
@@ -2023,7 +2662,7 @@ function FilterToolbar() {
|
|
|
2023
2662
|
value: filters.channel || "all",
|
|
2024
2663
|
onValueChange: (value) => setFilters({ channel: value === "all" ? void 0 : value }),
|
|
2025
2664
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
2026
|
-
className: "w-[
|
|
2665
|
+
className: "h-8 w-[calc(50%-0.25rem)] min-w-[132px] text-xs sm:w-[140px]",
|
|
2027
2666
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { placeholder: "All Channels" })
|
|
2028
2667
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
2029
2668
|
value: "all",
|
|
@@ -2037,7 +2676,7 @@ function FilterToolbar() {
|
|
|
2037
2676
|
variant: "ghost",
|
|
2038
2677
|
size: "sm",
|
|
2039
2678
|
onClick: resetFilters,
|
|
2040
|
-
className: "h-8 px-2 text-xs text-muted-foreground hover:text-foreground",
|
|
2679
|
+
className: "h-8 px-2 text-xs text-muted-foreground hover:text-foreground sm:ml-auto",
|
|
2041
2680
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { className: "h-3.5 w-3.5 mr-1" }), "Clear"]
|
|
2042
2681
|
})
|
|
2043
2682
|
]
|
|
@@ -2045,6 +2684,7 @@ function FilterToolbar() {
|
|
|
2045
2684
|
}
|
|
2046
2685
|
function BundlesPage() {
|
|
2047
2686
|
const { filters, bundleId, setBundleId } = useFilterParams();
|
|
2687
|
+
const [expandedBundleId, setExpandedBundleId] = (0, import_react.useState)();
|
|
2048
2688
|
const activeBundleId = bundleId ?? "";
|
|
2049
2689
|
const { data: bundlesData, isLoading } = useBundlesQuery({
|
|
2050
2690
|
channel: filters.channel,
|
|
@@ -2060,10 +2700,13 @@ function BundlesPage() {
|
|
|
2060
2700
|
const { data: selectedBundleFromQuery, isPending: isSelectedBundlePending } = useBundleQuery(activeBundleId);
|
|
2061
2701
|
const selectedBundle = selectedBundleFromQuery ?? selectedBundleFromList;
|
|
2062
2702
|
const isSelectedBundleLoading = Boolean(activeBundleId) && !selectedBundle && isSelectedBundlePending;
|
|
2703
|
+
(0, import_react.useEffect)(() => {
|
|
2704
|
+
if (expandedBundleId && !bundles.some((bundle) => bundle.id === expandedBundleId)) setExpandedBundleId(void 0);
|
|
2705
|
+
}, [bundles, expandedBundleId]);
|
|
2063
2706
|
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2064
2707
|
className: "flex flex-col h-full",
|
|
2065
2708
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterToolbar, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2066
|
-
className: "flex-1
|
|
2709
|
+
className: "flex flex-1 flex-col gap-4 bg-muted/5 p-3 sm:p-6",
|
|
2067
2710
|
children: [
|
|
2068
2711
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-12 w-full" }),
|
|
2069
2712
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-12 w-full" }),
|
|
@@ -2077,12 +2720,17 @@ function BundlesPage() {
|
|
|
2077
2720
|
children: [
|
|
2078
2721
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterToolbar, {}),
|
|
2079
2722
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2080
|
-
className: "flex-1
|
|
2723
|
+
className: "flex flex-1 flex-col gap-6 bg-muted/5 p-3 sm:p-6",
|
|
2081
2724
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundlesTable, {
|
|
2082
2725
|
bundles,
|
|
2083
2726
|
pagination,
|
|
2727
|
+
expandedBundleId,
|
|
2084
2728
|
selectedBundleId: bundleId,
|
|
2085
|
-
|
|
2729
|
+
onExpandedBundleChange: setExpandedBundleId,
|
|
2730
|
+
onDetailClick: (bundle) => {
|
|
2731
|
+
setExpandedBundleId(void 0);
|
|
2732
|
+
setBundleId(bundle.id);
|
|
2733
|
+
}
|
|
2086
2734
|
})
|
|
2087
2735
|
}),
|
|
2088
2736
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleEditorSheet, {
|