@hot-updater/console 1.0.0-rc.0 → 1.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/HashValueDisplay-CB0Eskit.js +1 -0
  3. package/.output/public/assets/InsightsPageHeader-Car5LNiZ.js +1 -0
  4. package/.output/public/assets/api-keys-BzKocqRy.js +1 -0
  5. package/.output/public/assets/api-keys-api-BHcODB7q.js +1 -0
  6. package/.output/public/assets/card-Dhr_eFYj.js +1 -0
  7. package/.output/public/assets/{chart-no-axes-combined-FaYMGmQS.js → chart-no-axes-combined-Dy4WJv2U.js} +1 -1
  8. package/.output/public/assets/composite-Bp98A0Ld.js +1 -0
  9. package/.output/public/assets/createServerFn-CA8fs7QD.js +3 -0
  10. package/.output/public/assets/dialog-CUTrcPlB.js +1 -0
  11. package/.output/public/assets/{dist-DspNKfMj.js → dist-C_NydL0e.js} +1 -1
  12. package/.output/public/assets/index-DdAz-CXv.js +10 -0
  13. package/.output/public/assets/input-group-cSOG4wh_.js +1 -0
  14. package/.output/public/assets/insights-C0PBSZ-n.js +1 -0
  15. package/.output/public/assets/installations-CE33wgbY.js +2 -0
  16. package/.output/public/assets/installations-CStZja8x.js +1 -0
  17. package/.output/public/assets/lazyRouteComponent-Ccp3bwBY.js +1 -0
  18. package/.output/public/assets/link-CI8idAUi.js +1 -0
  19. package/.output/public/assets/loader-circle-BoxLrsOu.js +1 -0
  20. package/.output/public/assets/refresh-cw-Bqc72UZG.js +1 -0
  21. package/.output/public/assets/{routes-DcQnVajO.js → routes-DGVXdzpw.js} +2 -2
  22. package/.output/public/assets/routes-DTlwOr8I.js +1 -0
  23. package/.output/public/assets/{shield-check-DE_hVuHu.js → shield-check-uK3MHWJZ.js} +1 -1
  24. package/.output/public/assets/signing-CMf4aqDO.js +1 -0
  25. package/.output/public/assets/styles-BCvbtKsm.css +2 -0
  26. package/.output/public/assets/table-2vcV89QB.js +1 -0
  27. package/.output/public/assets/useCompositeListItem-CHLITE_4.js +1 -0
  28. package/.output/public/assets/x-DCd0j8c6.js +1 -0
  29. package/.output/server/{__23tanstack-start-server-fn-resolver-DBP9TQ7K.mjs → __23tanstack-start-server-fn-resolver-B7ioJhtE.mjs} +44 -52
  30. package/.output/server/_libs/@base-ui/react+[...].mjs +1906 -4040
  31. package/.output/server/_libs/@tanstack/react-router+[...].mjs +52 -4
  32. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +2 -2
  33. package/.output/server/_libs/lucide-react.mjs +36 -3
  34. package/.output/server/_libs/next-themes.mjs +2 -2
  35. package/.output/server/_libs/sonner.mjs +2 -2
  36. package/.output/server/_libs/tanstack__react-query.mjs +2 -2
  37. package/.output/server/_libs/verkit.mjs +20 -15
  38. package/.output/server/_runtime.mjs +1 -10
  39. package/.output/server/_ssr/HashValueDisplay-DwpGLfrl.mjs +55 -0
  40. package/.output/server/_ssr/InsightsPageHeader-Df4Brj8u.mjs +484 -0
  41. package/.output/server/_ssr/{api-keys-BnM_o2nS.mjs → api-keys-CZeTPQys.mjs} +11 -13
  42. package/.output/server/_ssr/{api-keys-api-CIywsSF5.mjs → api-keys-api-BUPQVSpk.mjs} +2 -2
  43. package/.output/server/_ssr/{api-keys-rpc-BSp1wkIV.mjs → api-keys-rpc-Cs7tS5_j.mjs} +5 -5
  44. package/.output/server/_ssr/{api-rpc-cG5wd_tO.mjs → api-rpc-tAupfGQm.mjs} +73 -142
  45. package/.output/server/_ssr/{auth-rpc-BrJ6obHJ.mjs → auth-rpc-DUaeOWKK.mjs} +4 -4
  46. package/.output/server/_ssr/{auth.server-DwKoZoQM.mjs → auth.server-DW71WzsD.mjs} +2 -5
  47. package/.output/server/_ssr/{bundle-signing-rpc-COoQhW8E.mjs → bundle-signing-rpc-BhnBw0-d.mjs} +2 -2
  48. package/.output/server/_ssr/bundle-signing.server-C4NW5mWx.mjs +12 -0
  49. package/.output/server/_ssr/{alert-Dim3MGY5.mjs → card-BRiPmi0C.mjs} +61 -39
  50. package/.output/server/_ssr/{config.server-DEiLhKmy.mjs → config.server-afDuAwaG.mjs} +15 -8
  51. package/.output/server/_ssr/{createSsrRpc-9P0S0lJ3.mjs → createSsrRpc-DjWNJ0uc.mjs} +6 -6
  52. package/.output/server/_ssr/databaseJsonValue-d6I3nAS4.mjs +45 -0
  53. package/.output/server/_ssr/{databaseRows-CwbNwYSl.mjs → databaseRows-5bCRTxm-.mjs} +4 -44
  54. package/.output/server/_ssr/{deleteBundle-Cu_XOMt0.mjs → deleteBundle-BTGwBgzx.mjs} +2 -2
  55. package/.output/server/_ssr/{dialog-CQuRMNZ4.mjs → dialog-DS-nw-pA.mjs} +2 -2
  56. package/.output/server/_ssr/{dist-BVSLTpoP.mjs → dist-CyzPaI5v.mjs} +2 -2
  57. package/.output/server/_ssr/{getBundleChildren-BcRMFoDF.mjs → getBundleChildren-C0vh4ZvE.mjs} +2 -2
  58. package/.output/server/_ssr/input-group-BpsnmvZw.mjs +70 -0
  59. package/.output/server/_ssr/insights-BdS364Xu.mjs +460 -0
  60. package/.output/server/_ssr/insights-rpc-38DujK0G.mjs +57 -0
  61. package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +303 -0
  62. package/.output/server/_ssr/installations-CtA59MQG.mjs +29 -0
  63. package/.output/server/_ssr/installations-DiVKEF5T.mjs +627 -0
  64. package/.output/server/_ssr/{router-C-KUBfOi.mjs → router-B9wG_9f8.mjs} +37 -46
  65. package/.output/server/_ssr/{routes-Z7TwC6nC.mjs → routes-CKrrS2q2.mjs} +3 -3
  66. package/.output/server/_ssr/{routes-BM4ht9jb.mjs → routes-D7Yh_jfj.mjs} +402 -390
  67. package/.output/server/_ssr/runtime.server-DacU1TBV.mjs +438 -0
  68. package/.output/server/_ssr/{server-BjzmvXnO.mjs → server-D_C2rMzf.mjs} +5 -5
  69. package/.output/server/_ssr/{signing-k8GxyBDF.mjs → signing-Dz1WkZOf.mjs} +16 -85
  70. package/.output/server/_ssr/ssr.mjs +1 -1
  71. package/.output/server/_ssr/{field-DRIXKjZG.mjs → table-CnZmon_Z.mjs} +51 -5
  72. package/.output/server/_ssr/{uuidv7-BbJ-9D_I.mjs → uuidv7-D0QFkPL_.mjs} +3 -3
  73. package/.output/server/_tanstack-start-manifest_v-2MjTyxil.mjs +97 -0
  74. package/.output/server/index.mjs +168 -203
  75. package/lib/index.d.mts +4 -4
  76. package/lib/vite-internal.mjs +1 -1
  77. package/lib/vite.d.mts +0 -1
  78. package/package.json +8 -8
  79. package/src/components/AppSidebar.tsx +12 -16
  80. package/src/components/ConsoleAccessPage.tsx +1 -1
  81. package/src/components/HashValueDisplay.tsx +11 -2
  82. package/src/components/features/api-keys/ApiKeysPage.tsx +1 -1
  83. package/src/components/features/bundles/BundleChildrenPanel.tsx +7 -6
  84. package/src/components/features/bundles/BundleMetadata.tsx +1 -20
  85. package/src/components/features/channels/ChannelManagementDialog.tsx +1 -1
  86. package/src/components/features/insights/EventDetails.tsx +151 -0
  87. package/src/components/features/insights/EventHistoryCard.tsx +245 -0
  88. package/src/components/features/insights/EventHistoryList.tsx +63 -0
  89. package/src/components/features/insights/InsightsBundleReports.tsx +51 -0
  90. package/src/components/features/insights/InsightsControls.tsx +121 -0
  91. package/src/components/features/{analytics/AnalyticsErrorAlert.tsx → insights/InsightsErrorAlert.tsx} +6 -6
  92. package/src/components/features/insights/InsightsOverview.tsx +203 -0
  93. package/src/components/features/insights/InsightsPageHeader.tsx +48 -0
  94. package/src/components/features/insights/InsightsPagination.tsx +52 -0
  95. package/src/components/features/insights/InstallationHistoryCard.tsx +250 -0
  96. package/src/components/features/insights/InstallationMatchesCard.tsx +178 -0
  97. package/src/components/features/insights/InstallationPageHeader.tsx +90 -0
  98. package/src/components/features/releases/ReleaseEditorSheet.tsx +24 -24
  99. package/src/components/features/signing/BundleSigningPage.tsx +18 -126
  100. package/src/components/ui/badge.tsx +2 -0
  101. package/src/components/ui/combobox.tsx +1 -0
  102. package/src/components/ui/skeleton.tsx +4 -1
  103. package/src/components/ui/tooltip.tsx +1 -1
  104. package/src/index.ts +7 -3
  105. package/src/lib/api-rpc.ts +19 -90
  106. package/src/lib/api.ts +0 -99
  107. package/src/lib/insights-api.ts +100 -0
  108. package/src/lib/insights-rpc.ts +88 -0
  109. package/src/lib/insights-view.ts +15 -0
  110. package/src/lib/public-bundle-error.ts +19 -0
  111. package/src/lib/server/bundle-signing.server.ts +5 -82
  112. package/src/lib/server/console-runtime.server.ts +0 -9
  113. package/src/lib/server/releaseReachability.ts +1 -4
  114. package/src/lib/server/runtime.server.ts +6 -142
  115. package/src/routeTree.gen.ts +21 -21
  116. package/src/router.tsx +3 -0
  117. package/src/routes/-installations-search.ts +25 -12
  118. package/src/routes/__root.tsx +6 -16
  119. package/src/routes/api-keys.tsx +1 -1
  120. package/src/routes/index.tsx +21 -81
  121. package/src/routes/insights.tsx +84 -0
  122. package/src/routes/installations.tsx +294 -142
  123. package/src/styles.css +6 -0
  124. package/.output/public/assets/AnalyticsCapabilityContext-BCke57-7.js +0 -1
  125. package/.output/public/assets/BundleActivityChart-CnsBe_1J.js +0 -42
  126. package/.output/public/assets/BundleIdDisplay-Dky75zLU.js +0 -1
  127. package/.output/public/assets/alert-C-1KvDW8.js +0 -1
  128. package/.output/public/assets/analytics-Bqz0c-BT.js +0 -1
  129. package/.output/public/assets/analytics-api-CJdrTLLO.js +0 -1
  130. package/.output/public/assets/api-B_Rh-uzC.js +0 -1
  131. package/.output/public/assets/api-keys-BurCFhzH.js +0 -1
  132. package/.output/public/assets/api-keys-api-BEDJdQg3.js +0 -1
  133. package/.output/public/assets/badge-Bf0fZ-Gx.js +0 -1
  134. package/.output/public/assets/createServerFn-gM2-LFBy.js +0 -3
  135. package/.output/public/assets/dialog-BS60BRr2.js +0 -1
  136. package/.output/public/assets/download-O-yNBc9H.js +0 -1
  137. package/.output/public/assets/field-Buq148-A.js +0 -1
  138. package/.output/public/assets/index-kFhd2S78.js +0 -10
  139. package/.output/public/assets/installations-BrQ-od41.js +0 -2
  140. package/.output/public/assets/installations-CGlZ3ROz.js +0 -1
  141. package/.output/public/assets/lazyRouteComponent-rPzgA7S-.js +0 -1
  142. package/.output/public/assets/loader-circle-DCYF-wJl.js +0 -1
  143. package/.output/public/assets/refresh-cw-n8XYbPPj.js +0 -1
  144. package/.output/public/assets/routes-CrdokJ80.js +0 -1
  145. package/.output/public/assets/search-DLhbWw3W.js +0 -1
  146. package/.output/public/assets/signing-HRexfjsH.js +0 -1
  147. package/.output/public/assets/styles-eB4EtvFS.css +0 -2
  148. package/.output/public/assets/table-D8CLieHX.js +0 -1
  149. package/.output/public/assets/textarea-YJLTVAoq.js +0 -1
  150. package/.output/public/assets/useMutation-JsGVjQMY.js +0 -1
  151. package/.output/public/assets/useOpenInteractionType-4cRD5xO0.js +0 -1
  152. package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +0 -1554
  153. package/.output/server/_libs/d3-array.mjs +0 -231
  154. package/.output/server/_libs/d3-color.mjs +0 -330
  155. package/.output/server/_libs/d3-format.mjs +0 -252
  156. package/.output/server/_libs/d3-interpolate.mjs +0 -207
  157. package/.output/server/_libs/d3-path.mjs +0 -77
  158. package/.output/server/_libs/d3-scale+[...].mjs +0 -1907
  159. package/.output/server/_libs/d3-shape.mjs +0 -818
  160. package/.output/server/_libs/decimal.js-light.mjs +0 -884
  161. package/.output/server/_libs/es-toolkit.mjs +0 -1134
  162. package/.output/server/_libs/eventemitter3.mjs +0 -236
  163. package/.output/server/_libs/immer.mjs +0 -532
  164. package/.output/server/_libs/react-redux+[...].mjs +0 -205
  165. package/.output/server/_libs/recharts+[...].mjs +0 -14117
  166. package/.output/server/_ssr/AnalyticsCapabilityContext-ui4DX8GO.mjs +0 -15
  167. package/.output/server/_ssr/BundleActivityChart-BiB9ZORH.mjs +0 -288
  168. package/.output/server/_ssr/BundleIdDisplay-Czk6iR6p.mjs +0 -13
  169. package/.output/server/_ssr/analytics-DtMTn8fn.mjs +0 -858
  170. package/.output/server/_ssr/analytics-api-Cg1M5v_H.mjs +0 -71
  171. package/.output/server/_ssr/analytics-input-fRRRn0uA.mjs +0 -96
  172. package/.output/server/_ssr/analytics-rpc-DY5uXvHT.mjs +0 -155
  173. package/.output/server/_ssr/api-BTSv1tZb.mjs +0 -282
  174. package/.output/server/_ssr/badge-DCxbEeof.mjs +0 -26
  175. package/.output/server/_ssr/bundle-signing.server-D5u8KkMp.mjs +0 -51
  176. package/.output/server/_ssr/installations-B-azgAvX.mjs +0 -19
  177. package/.output/server/_ssr/installations-Ctvzp2JH.mjs +0 -535
  178. package/.output/server/_ssr/runtime.server-awTLiiXW.mjs +0 -527
  179. package/.output/server/_ssr/table-v1yCvYo7.mjs +0 -53
  180. package/.output/server/_ssr/textarea-DYHnskhb.mjs +0 -14
  181. package/.output/server/_tanstack-start-manifest_v-CH4StzJu.mjs +0 -108
  182. package/src/components/features/analytics/ActivityChart.tsx +0 -150
  183. package/src/components/features/analytics/AnalyticsCapabilityContext.tsx +0 -24
  184. package/src/components/features/analytics/AnalyticsControls.tsx +0 -115
  185. package/src/components/features/analytics/AnalyticsOverview.tsx +0 -208
  186. package/src/components/features/analytics/BundleDistribution.tsx +0 -133
  187. package/src/components/features/analytics/BundleSelector.tsx +0 -114
  188. package/src/components/features/analytics/InstallationHistoryCard.tsx +0 -248
  189. package/src/components/features/analytics/InstallationMatchesCard.tsx +0 -132
  190. package/src/components/features/analytics/InstallationPageHeader.tsx +0 -138
  191. package/src/components/features/analytics/InstallationPagination.tsx +0 -48
  192. package/src/components/features/analytics/InstallationSearch.tsx +0 -230
  193. package/src/components/features/analytics/UpdateOutcomes.tsx +0 -147
  194. package/src/components/features/bundles/BundleActivityChart.tsx +0 -193
  195. package/src/components/features/bundles/BundleAnalyticsSummary.tsx +0 -123
  196. package/src/lib/analytics-api.ts +0 -145
  197. package/src/lib/analytics-error.ts +0 -19
  198. package/src/lib/analytics-input.ts +0 -187
  199. package/src/lib/analytics-overview.ts +0 -170
  200. package/src/lib/analytics-rpc.ts +0 -218
  201. package/src/lib/server/releaseActivity.ts +0 -27
  202. package/src/routes/analytics.tsx +0 -139
  203. /package/.output/public/assets/{preload-helper-TKOBYGYD.js → preload-helper-CQ36nxok.js} +0 -0
@@ -1,51 +0,0 @@
1
- import { createHash, createPublicKey } from "node:crypto";
2
- import path from "node:path";
3
- import { readFile, stat } from "node:fs/promises";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/bundle-signing.server-D5u8KkMp.js
5
- var MAX_PUBLIC_KEY_BYTES = 16 * 1024;
6
- var DEFAULT_PROVIDER = "Configured provider";
7
- var PUBLIC_KEY_HEADER = "-----BEGIN PUBLIC KEY-----";
8
- var PUBLIC_KEY_FOOTER = "-----END PUBLIC KEY-----";
9
- var misconfigured = (provider, message) => ({
10
- message,
11
- provider,
12
- status: "misconfigured"
13
- });
14
- var isSpkiPublicKeyPem = (value) => {
15
- const trimmed = value.trim();
16
- return trimmed.startsWith(PUBLIC_KEY_HEADER) && trimmed.endsWith(PUBLIC_KEY_FOOTER) && !trimmed.includes("PRIVATE KEY");
17
- };
18
- var inspectBundleSigning = async (signing) => {
19
- if (!signing?.enabled) return { status: "disabled" };
20
- const provider = signing.provider ?? DEFAULT_PROVIDER;
21
- if (!signing.publicKeyPath) return misconfigured(provider, "A public key file is not configured.");
22
- try {
23
- const publicKeyPath = path.isAbsolute(signing.publicKeyPath) ? signing.publicKeyPath : path.resolve(process.cwd(), signing.publicKeyPath);
24
- const publicKeyStat = await stat(publicKeyPath);
25
- if (!publicKeyStat.isFile() || publicKeyStat.size > MAX_PUBLIC_KEY_BYTES) return misconfigured(provider, "The configured public key could not be loaded.");
26
- const publicKeyPem = await readFile(publicKeyPath, "utf8");
27
- if (!isSpkiPublicKeyPem(publicKeyPem)) return misconfigured(provider, "The configured public key is not a valid SPKI public key.");
28
- const publicKey = createPublicKey(publicKeyPem);
29
- if (publicKey.asymmetricKeyType !== "rsa") return misconfigured(provider, "The configured public key is not an RSA public key.");
30
- if ((publicKey.asymmetricKeyDetails?.modulusLength ?? 0) < 2048) return misconfigured(provider, "The configured RSA public key must be at least 2048 bits.");
31
- const canonicalDer = publicKey.export({
32
- format: "der",
33
- type: "spki"
34
- });
35
- const canonicalPem = publicKey.export({
36
- format: "pem",
37
- type: "spki"
38
- });
39
- return {
40
- algorithm: "RSA-SHA256",
41
- fingerprint: createHash("sha256").update(canonicalDer).digest("hex"),
42
- provider,
43
- publicKey: canonicalPem.toString().trim(),
44
- status: "enabled"
45
- };
46
- } catch {
47
- return misconfigured(provider, "The configured public key could not be loaded.");
48
- }
49
- };
50
- //#endregion
51
- export { inspectBundleSigning };
@@ -1,19 +0,0 @@
1
- import { d as createFileRoute, u as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
- import { t as ensureAnalyticsRouteAccess } from "./analytics-api-Cg1M5v_H.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/installations-B-azgAvX.js
4
- function validateInstallationsSearch(search) {
5
- return {
6
- query: typeof search.query === "string" ? search.query : void 0,
7
- installId: typeof search.installId === "string" ? search.installId : void 0,
8
- searchOffset: typeof search.searchOffset === "number" && Number.isSafeInteger(search.searchOffset) && search.searchOffset >= 0 ? search.searchOffset : 0,
9
- historyOffset: typeof search.historyOffset === "number" && Number.isSafeInteger(search.historyOffset) && search.historyOffset >= 0 ? search.historyOffset : 0
10
- };
11
- }
12
- var $$splitComponentImporter = () => import("./installations-Ctvzp2JH.mjs");
13
- var Route = createFileRoute("/installations")({
14
- beforeLoad: ({ context }) => ensureAnalyticsRouteAccess(context.queryClient),
15
- component: lazyRouteComponent($$splitComponentImporter, "component"),
16
- validateSearch: validateInstallationsSearch
17
- });
18
- //#endregion
19
- export { Route as t };
@@ -1,535 +0,0 @@
1
- import { i as __toESM } from "../_runtime.mjs";
2
- import { at as require_react, it as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
- import { n as useAnalyticsCapability } from "./AnalyticsCapabilityContext-ui4DX8GO.mjs";
4
- import { I as ArrowLeft, N as Check, l as Search, n as TriangleAlert, t as X } from "../_libs/lucide-react.mjs";
5
- import { S as buttonVariants, _ as Skeleton, g as SidebarTrigger, r as Separator$1, t as Button$1 } from "./createSsrRpc-9P0S0lJ3.mjs";
6
- import { p as Link } from "../_libs/@tanstack/react-router+[...].mjs";
7
- import { r as isAnalyticsQueryEnabled } from "./analytics-api-Cg1M5v_H.mjs";
8
- import { a as FieldLabel, i as FieldGroup, n as FieldDescription, t as Field } from "./field-DRIXKjZG.mjs";
9
- import { g as useInstallationSearchQuery, h as useInstallationHistoryQuery, i as InputGroupInput, n as InputGroupAddon, r as InputGroupButton, t as InputGroup } from "./api-BTSv1tZb.mjs";
10
- import { a as Card, i as AlertTitle, l as CardHeader, o as CardContent, r as AlertDescription, s as CardDescription, t as Alert, u as CardTitle } from "./alert-Dim3MGY5.mjs";
11
- import { t as Badge } from "./badge-DCxbEeof.mjs";
12
- import { a as TableHeader, i as TableHead, n as TableBody, o as TableRow, r as TableCell, t as Table } from "./table-v1yCvYo7.mjs";
13
- import { t as Route } from "./installations-B-azgAvX.mjs";
14
- import { t as BundleIdDisplay } from "./BundleIdDisplay-Czk6iR6p.mjs";
15
- //#region node_modules/.nitro/vite/services/ssr/assets/installations-Ctvzp2JH.js
16
- var import_react = /* @__PURE__ */ __toESM(require_react());
17
- var import_jsx_runtime = require_jsx_runtime();
18
- function InstallationPagination({ label, limit, offset, pageLength, total, onOffsetChange }) {
19
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", {
20
- "aria-label": `${label} pagination`,
21
- className: "flex items-center justify-between gap-4 border-t px-5 py-5",
22
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
23
- className: "text-xs text-muted-foreground",
24
- children: [
25
- offset + 1,
26
- "–",
27
- Math.min(offset + pageLength, total),
28
- " of ",
29
- total
30
- ]
31
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
32
- className: "flex gap-2",
33
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
34
- disabled: offset === 0,
35
- onClick: () => onOffsetChange(Math.max(0, offset - limit)),
36
- size: "sm",
37
- type: "button",
38
- variant: "outline",
39
- children: "Previous"
40
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
41
- disabled: offset + pageLength >= total,
42
- onClick: () => onOffsetChange(offset + limit),
43
- size: "sm",
44
- type: "button",
45
- variant: "outline",
46
- children: "Next"
47
- })]
48
- })]
49
- });
50
- }
51
- var formatDateTime = (value) => {
52
- if (!value) return "—";
53
- const date = value instanceof Date ? value : new Date(value);
54
- if (Number.isNaN(date.getTime())) return "—";
55
- return new Intl.DateTimeFormat(void 0, {
56
- year: "numeric",
57
- month: "2-digit",
58
- day: "2-digit",
59
- hour: "2-digit",
60
- minute: "2-digit",
61
- second: "2-digit",
62
- hour12: false,
63
- timeZone: "UTC"
64
- }).format(date);
65
- };
66
- var getUserLabel$1 = (event) => event.userId ?? event.username ?? "—";
67
- var getLastKnownBundleId$1 = (event) => "lastKnownBundleId" in event ? event.lastKnownBundleId : event.toBundleId ?? event.fromBundleId;
68
- function InstallationHistoryCard({ error, history, isLoading, limit, offset, onOffsetChange, selectedEvent, selectedInstallId }) {
69
- const lastKnownBundleId = selectedEvent ? getLastKnownBundleId$1(selectedEvent) : void 0;
70
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
71
- className: "min-h-0 min-w-0",
72
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardHeader, {
73
- className: "p-6 pb-5",
74
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
75
- className: "flex items-start justify-between gap-4",
76
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
77
- className: "flex min-w-0 flex-col gap-1.5",
78
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
79
- className: "text-sm font-medium",
80
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: selectedInstallId ? "Installation history" : "Select an installation" })
81
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: selectedInstallId ? "Recorded bundle changes for this installation." : "Choose a match to view its recorded bundle changes." })]
82
- }), history && history.pagination.total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
83
- variant: "outline",
84
- children: [history.pagination.total, " events"]
85
- }) : null]
86
- })
87
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
88
- className: "min-h-0 p-0",
89
- children: selectedInstallId ? isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
90
- className: "flex flex-col gap-3 p-5",
91
- children: [
92
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }),
93
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" }),
94
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-10 w-full" })
95
- ]
96
- }) : history && history.data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
97
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
98
- "aria-labelledby": "latest-installation-state",
99
- className: "px-6 pb-6",
100
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
101
- className: "text-xs font-medium",
102
- id: "latest-installation-state",
103
- children: "Latest reported state"
104
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
105
- className: "mt-4 grid gap-6 xl:grid-cols-3",
106
- children: [
107
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
108
- className: "min-w-0",
109
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
110
- className: "text-xs text-muted-foreground",
111
- children: "Installation"
112
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
113
- className: "mt-1 font-mono text-xs",
114
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, { bundleId: selectedInstallId })
115
- })]
116
- }),
117
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
118
- className: "min-w-0",
119
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
120
- className: "text-xs text-muted-foreground",
121
- children: "User ID"
122
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
123
- className: "mt-1 truncate text-xs font-medium",
124
- children: selectedEvent ? getUserLabel$1(selectedEvent) : "—"
125
- })]
126
- }),
127
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
128
- className: "min-w-0",
129
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
130
- className: "text-xs text-muted-foreground",
131
- children: "Last known bundle"
132
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
133
- className: "mt-1 font-mono text-xs",
134
- children: lastKnownBundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, { bundleId: lastKnownBundleId }) : "—"
135
- })]
136
- })
137
- ]
138
- })]
139
- }),
140
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Separator$1, {}),
141
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Table, {
142
- className: "min-w-3xl table-fixed",
143
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
144
- className: "hover:bg-transparent [&>th]:h-12 [&>th]:px-5",
145
- children: [
146
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
147
- className: "w-1/5 whitespace-normal",
148
- children: "Reported (UTC)"
149
- }),
150
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
151
- className: "w-1/6 whitespace-normal",
152
- children: "App version"
153
- }),
154
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
155
- className: "w-1/5 whitespace-normal",
156
- children: "Change"
157
- }),
158
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableHead, {
159
- className: "whitespace-normal",
160
- children: "Bundle transition"
161
- })
162
- ]
163
- }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, { children: history.data.map((event) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
164
- className: "[&>td]:px-5 [&>td]:py-4",
165
- children: [
166
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
167
- className: "whitespace-normal align-top text-sm text-muted-foreground",
168
- children: formatDateTime(event.receivedAtMs)
169
- }),
170
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
171
- className: "whitespace-normal align-top font-mono text-xs",
172
- children: event.appVersion
173
- }),
174
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
175
- className: "whitespace-normal align-top",
176
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
177
- variant: "secondary",
178
- children: event.type === "UPDATE_APPLIED" ? "Bundle applied" : "Recovered"
179
- })
180
- }),
181
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, {
182
- className: "whitespace-normal align-top",
183
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
184
- className: "grid grid-cols-[2rem_minmax(0,1fr)] gap-x-3 gap-y-3",
185
- children: [
186
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
187
- className: "text-muted-foreground",
188
- children: "From"
189
- }),
190
- event.fromBundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, { bundleId: event.fromBundleId }) : "—",
191
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
192
- className: "text-muted-foreground",
193
- children: "To"
194
- }),
195
- event.toBundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, { bundleId: event.toBundleId }) : "—"
196
- ]
197
- })
198
- })
199
- ]
200
- }, event.id)) })]
201
- }),
202
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationPagination, {
203
- label: "Installation history",
204
- limit,
205
- offset,
206
- pageLength: history.data.length,
207
- total: history.pagination.total,
208
- onOffsetChange
209
- })
210
- ] }) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
211
- className: "p-5 pt-0",
212
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, {
213
- variant: "destructive",
214
- children: [
215
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { "aria-hidden": "true" }),
216
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "Installation history unavailable" }),
217
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: error instanceof Error ? error.message : "Failed to load installation history." })
218
- ]
219
- })
220
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
221
- className: "p-5 pt-0 text-sm text-muted-foreground",
222
- children: "No history is available for this installation."
223
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
224
- className: "p-5 pt-0 text-sm text-muted-foreground",
225
- children: "Choose an installation to inspect its update history."
226
- })
227
- })]
228
- });
229
- }
230
- var getLastKnownBundleId = (event) => event.lastKnownBundleId;
231
- var getUserLabel = (event) => event.userId ?? event.username ?? "—";
232
- function InstallationMatchesCard({ error, limit, offset, onOffsetChange, onSelect, results, selectedInstallId }) {
233
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
234
- className: "min-h-0 min-w-0",
235
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardHeader, {
236
- className: "p-6 pb-5",
237
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
238
- className: "flex items-start justify-between gap-4",
239
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
240
- className: "flex min-w-0 flex-col gap-1.5",
241
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
242
- className: "text-sm font-medium",
243
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "Matching installations" })
244
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Select a row to review its bundle history." })]
245
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
246
- variant: "outline",
247
- children: results?.pagination.total ?? 0
248
- })]
249
- })
250
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardContent, {
251
- className: "min-h-0 p-0",
252
- children: [results && results.data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
253
- "aria-label": "Matching installations",
254
- className: "divide-y",
255
- children: results.data.map((event) => {
256
- const currentBundleId = getLastKnownBundleId(event);
257
- const isSelected = event.installId === selectedInstallId;
258
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
259
- "aria-pressed": isSelected,
260
- className: "group flex w-full min-w-0 flex-col gap-4 border-l-2 border-transparent px-6 py-5 text-left outline-none transition-colors hover:bg-muted/40 focus-visible:border-ring focus-visible:bg-muted/40 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/30 aria-pressed:border-primary aria-pressed:bg-muted/60",
261
- onClick: () => onSelect(event.installId),
262
- type: "button",
263
- children: [
264
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
265
- className: "flex w-full min-w-0 items-center justify-between gap-3",
266
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
267
- className: "min-w-0 truncate text-sm font-medium",
268
- children: getUserLabel(event)
269
- }), isSelected ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
270
- className: "flex shrink-0 items-center gap-1 text-xs font-medium text-primary",
271
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, {
272
- "aria-hidden": "true",
273
- className: "size-3.5"
274
- }), "Selected"]
275
- }) : null]
276
- }),
277
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, {
278
- bundleId: event.installId,
279
- className: "block text-muted-foreground"
280
- }),
281
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
282
- className: "min-w-0",
283
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
284
- className: "mb-1 block text-xs text-muted-foreground",
285
- children: "Last known bundle"
286
- }), currentBundleId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BundleIdDisplay, { bundleId: currentBundleId }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
287
- className: "text-sm text-muted-foreground",
288
- children: "—"
289
- })]
290
- })
291
- ]
292
- }) }, event.installId);
293
- })
294
- }) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
295
- className: "p-5",
296
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, {
297
- variant: "destructive",
298
- children: [
299
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { "aria-hidden": "true" }),
300
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "Installation search unavailable" }),
301
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: error instanceof Error ? error.message : "Failed to load installations." })
302
- ]
303
- })
304
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
305
- className: "p-5 text-sm text-muted-foreground",
306
- children: "No installations matched that query."
307
- }), results && results.pagination.total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationPagination, {
308
- label: "Installation results",
309
- limit,
310
- offset,
311
- pageLength: results.data.length,
312
- total: results.pagination.total,
313
- onOffsetChange
314
- }) : null]
315
- })]
316
- });
317
- }
318
- function InstallationPageHeader() {
319
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
320
- className: "sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-x-2 gap-y-1 border-b bg-background px-3 py-3 sm:min-h-12 sm:flex-nowrap sm:bg-card/70 sm:px-4 sm:backdrop-blur-sm",
321
- children: [
322
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SidebarTrigger, { className: "-ml-1" }),
323
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
324
- className: buttonVariants({
325
- size: "sm",
326
- variant: "ghost"
327
- }),
328
- to: "/analytics",
329
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, {
330
- "aria-hidden": "true",
331
- "data-icon": "inline-start"
332
- }), "Back to Analytics"]
333
- }),
334
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Separator$1, {
335
- className: "mx-1 hidden h-4 sm:block",
336
- orientation: "vertical"
337
- }),
338
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
339
- className: "basis-full pl-9 sm:basis-auto sm:pl-0",
340
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
341
- className: "text-sm font-medium",
342
- children: "Installation history"
343
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
344
- className: "text-xs text-muted-foreground",
345
- children: "Review the last known bundle and recorded changes."
346
- })]
347
- })
348
- ]
349
- });
350
- }
351
- function InstallationSearchPanel({ draftQuery, onDraftQueryChange, onSubmit, onClear, hasQuery }) {
352
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardContent, {
353
- className: "grid gap-4 p-4 lg:grid-cols-[minmax(12rem,0.45fr)_minmax(0,1.55fr)] lg:items-start",
354
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
355
- className: "flex min-w-0 flex-col gap-1.5",
356
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
357
- className: "text-sm font-medium",
358
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "Find an installation" })
359
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "Search by either identifier to inspect its bundle history." })]
360
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("form", {
361
- onSubmit: (event) => {
362
- event.preventDefault();
363
- onSubmit();
364
- },
365
- role: "search",
366
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Field, { children: [
367
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldLabel, {
368
- htmlFor: "installation-history-search",
369
- children: "User ID or install ID"
370
- }),
371
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
372
- className: "flex flex-col gap-2 sm:flex-row",
373
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InputGroup, {
374
- className: "h-8",
375
- children: [
376
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputGroupAddon, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Search, { "aria-hidden": "true" }) }),
377
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputGroupInput, {
378
- id: "installation-history-search",
379
- onChange: (event) => onDraftQueryChange(event.target.value),
380
- placeholder: "Enter a user ID or install ID",
381
- type: "search",
382
- value: draftQuery
383
- }),
384
- draftQuery.length > 0 || hasQuery ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputGroupAddon, {
385
- align: "inline-end",
386
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputGroupButton, {
387
- "aria-label": "Clear search",
388
- onClick: onClear,
389
- size: "icon-xs",
390
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { "aria-hidden": "true" })
391
- })
392
- }) : null
393
- ]
394
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
395
- className: "w-full sm:w-auto",
396
- disabled: draftQuery.trim().length === 0,
397
- size: "lg",
398
- type: "submit",
399
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Search, {
400
- "aria-hidden": "true",
401
- "data-icon": "inline-start"
402
- }), "Search history"]
403
- })]
404
- }),
405
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldDescription, { children: "A user ID may return more than one installation. An install ID opens one installation directly." })
406
- ] }) })
407
- })]
408
- }) });
409
- }
410
- function InstallationResultsSkeleton() {
411
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
412
- className: "grid items-stretch gap-6 lg:min-h-96 lg:grid-cols-[minmax(18rem,20rem)_minmax(0,1fr)]",
413
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-64 w-full lg:h-full" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, { className: "h-64 w-full lg:h-full" })]
414
- });
415
- }
416
- var SEARCH_LIMIT = 20;
417
- var HISTORY_LIMIT = 50;
418
- function InstallationsPage() {
419
- const analyticsQueriesEnabled = isAnalyticsQueryEnabled(useAnalyticsCapability());
420
- const search = Route.useSearch();
421
- const navigate = Route.useNavigate();
422
- const [draftQuery, setDraftQuery] = (0, import_react.useState)(search.query ?? "");
423
- (0, import_react.useEffect)(() => {
424
- setDraftQuery(search.query ?? "");
425
- }, [search.query]);
426
- const query = search.query?.trim() ?? "";
427
- const { data: results, error: searchError, isLoading: isSearchLoading } = useInstallationSearchQuery({
428
- query,
429
- limit: SEARCH_LIMIT,
430
- offset: search.searchOffset
431
- }, analyticsQueriesEnabled);
432
- const selectedInstallId = search.installId ?? "";
433
- const firstMatchingInstallId = results?.data[0]?.installId;
434
- (0, import_react.useEffect)(() => {
435
- if (selectedInstallId || !firstMatchingInstallId) return;
436
- navigate({
437
- to: "/installations",
438
- search: {
439
- query: search.query,
440
- installId: firstMatchingInstallId,
441
- searchOffset: search.searchOffset,
442
- historyOffset: 0
443
- },
444
- replace: true
445
- });
446
- }, [
447
- firstMatchingInstallId,
448
- navigate,
449
- search.query,
450
- search.searchOffset,
451
- selectedInstallId
452
- ]);
453
- const { data: history, error: historyError, isLoading: isHistoryLoading } = useInstallationHistoryQuery({
454
- installId: selectedInstallId,
455
- limit: HISTORY_LIMIT,
456
- offset: search.historyOffset
457
- }, analyticsQueriesEnabled);
458
- const selectedEvent = (0, import_react.useMemo)(() => results?.data.find((event) => event.installId === selectedInstallId) ?? null, [results?.data, selectedInstallId]) ?? history?.data[0];
459
- const updateSearch = (nextSearch, replace = false) => {
460
- navigate({
461
- to: "/installations",
462
- search: {
463
- query: nextSearch.query,
464
- installId: nextSearch.installId,
465
- searchOffset: nextSearch.searchOffset ?? 0,
466
- historyOffset: nextSearch.historyOffset ?? 0
467
- },
468
- replace
469
- });
470
- };
471
- const hasQuery = query.length > 0 || selectedInstallId.length > 0;
472
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
473
- className: "flex h-svh min-h-0 flex-col",
474
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationPageHeader, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
475
- className: "min-h-0 min-w-0 flex-1 overflow-y-auto bg-muted/5 p-3 sm:p-6",
476
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
477
- className: "mx-auto flex w-full max-w-7xl flex-col gap-6",
478
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationSearchPanel, {
479
- draftQuery,
480
- hasQuery,
481
- onClear: () => {
482
- setDraftQuery("");
483
- updateSearch({
484
- query: void 0,
485
- installId: void 0
486
- });
487
- },
488
- onDraftQueryChange: setDraftQuery,
489
- onSubmit: () => {
490
- updateSearch({
491
- query: draftQuery.trim() || void 0,
492
- installId: void 0
493
- });
494
- }
495
- }), !hasQuery ? null : isSearchLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationResultsSkeleton, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
496
- className: "grid min-h-0 min-w-0 items-stretch gap-6 lg:min-h-96 lg:grid-cols-[minmax(18rem,20rem)_minmax(0,1fr)]",
497
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationMatchesCard, {
498
- error: searchError,
499
- limit: SEARCH_LIMIT,
500
- offset: search.searchOffset,
501
- results,
502
- selectedInstallId,
503
- onOffsetChange: (searchOffset) => updateSearch({
504
- query: search.query,
505
- installId: void 0,
506
- searchOffset,
507
- historyOffset: 0
508
- }),
509
- onSelect: (installId) => updateSearch({
510
- query: search.query,
511
- installId,
512
- searchOffset: search.searchOffset
513
- })
514
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstallationHistoryCard, {
515
- error: historyError,
516
- history,
517
- isLoading: isHistoryLoading,
518
- limit: HISTORY_LIMIT,
519
- offset: search.historyOffset,
520
- selectedEvent,
521
- selectedInstallId,
522
- onOffsetChange: (historyOffset) => updateSearch({
523
- query: search.query,
524
- installId: selectedInstallId,
525
- searchOffset: search.searchOffset,
526
- historyOffset
527
- })
528
- })]
529
- })]
530
- })
531
- })]
532
- });
533
- }
534
- //#endregion
535
- export { InstallationsPage as component };