@hot-updater/console 1.1.4 → 1.2.0-rc.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/-native-builds-search-C-TGpFAm.js +1 -0
- package/.output/public/assets/{ConsoleFeatureUnavailable-C0KfsKWL.js → ConsoleFeatureUnavailable-CUtcXuY2.js} +1 -1
- package/.output/public/assets/EventDetails-Dl2RvPAk.js +1 -0
- package/.output/public/assets/HashValueDisplay-6lNRxDJX.js +1 -0
- package/.output/public/assets/InsightsPageHeader-DHhqY3DT.js +1 -0
- package/.output/public/assets/NotFoundPage-DZ3DxyRA.js +1 -0
- package/.output/public/assets/PlatformIcon-BBWQlWm9.js +1 -0
- package/.output/public/assets/RolloutPercentageBadge-Cxogpi8F.js +1 -0
- package/.output/public/assets/StoreSubmission-JpngSvHS.js +1 -0
- package/.output/public/assets/alert-dialog-BqYScr9y.js +1 -0
- package/.output/public/assets/api-P2g8dCNg.js +1 -0
- package/.output/public/assets/api-keys-DWQC2q6y.js +1 -0
- package/.output/public/assets/api-keys-FueRkF9q.js +1 -0
- package/.output/public/assets/arrow-left-g9cKqXuC.js +1 -0
- package/.output/public/assets/arrow-right-CNII8TYn.js +1 -0
- package/.output/public/assets/arrow-up-right-DK8Zdg40.js +1 -0
- package/.output/public/assets/badge-DWFcDWho.js +1 -0
- package/.output/public/assets/check-CXVR3s3X.js +1 -0
- package/.output/public/assets/chevron-right-BoUXo82O.js +1 -0
- package/.output/public/assets/circle-off-C7Muo0ss.js +1 -0
- package/.output/public/assets/{clipboard-DTkrlIMn.js → clipboard-DQbOcrL7.js} +1 -1
- package/.output/public/assets/console-features-api-DEXSwFtc.js +1 -0
- package/.output/public/assets/copy-DsuLj3oj.js +1 -0
- package/.output/public/assets/dialog-CNUPxNxH.js +1 -0
- package/.output/public/assets/{dist-dDj-R6uh.js → dist-CPlO6ko9.js} +1 -1
- package/.output/public/assets/download-Cf24LBde.js +1 -0
- package/.output/public/assets/{empty-Bf4DanOL.js → empty-B3Uwdd6k.js} +1 -1
- package/.output/public/assets/{field-GxF9SyUo.js → field-D-2-mnNh.js} +1 -1
- package/.output/public/assets/history-DqHlgSuV.js +1 -0
- package/.output/public/assets/index-BWU6owTG.js +10 -0
- package/.output/public/assets/{input-group-B4nrqIh0.js → input-group-D3OUBk4n.js} +1 -1
- package/.output/public/assets/insights-B-0odqpt.js +42 -0
- package/.output/public/assets/insights-BSVGfxSL.js +1 -0
- package/.output/public/assets/insights-NK5B6ReS.js +2 -0
- package/.output/public/assets/insights-api-BVCXJsoV.js +1 -0
- package/.output/public/assets/insights-search-DghCbEnk.js +1 -0
- package/.output/public/assets/insights-usage-rpc-CKQH0pUS.js +1 -0
- package/.output/public/assets/insights_.distribution-CJvgwcVZ.js +2 -0
- package/.output/public/assets/insights_.distribution-DblZM0mO.js +1 -0
- package/.output/public/assets/insights_.distribution-dvk6vYDM.js +1 -0
- package/.output/public/assets/installations-B674P5Z5.js +2 -0
- package/.output/public/assets/installations-BWxczZ2t.js +1 -0
- package/.output/public/assets/installations-Dv4kWQYz.js +1 -0
- package/.output/public/assets/{key-round-B4fI1psK.js → key-round-DwNKkHhy.js} +1 -1
- package/.output/public/assets/link-DTEyW70e.js +2 -0
- package/.output/public/assets/{list-Dtj7TtzV.js → list--NIee1FZ.js} +1 -1
- package/.output/public/assets/native-builds-BOC71grI.js +1 -0
- package/.output/public/assets/native-builds-BswZazmc.js +1 -0
- package/.output/public/assets/native-builds-c4BpOLAe.js +2 -0
- package/.output/public/assets/native-builds_._buildId-D_Spjl10.js +1 -0
- package/.output/public/assets/native-builds_._buildId-DtoXD8rz.js +2 -0
- package/.output/public/assets/plus-BReVKct-.js +1 -0
- package/.output/public/assets/preload-helper-B44EvKhG.js +1 -0
- package/.output/public/assets/{refresh-cw-DjIKjmrS.js → refresh-cw-B9HHjLej.js} +1 -1
- package/.output/public/assets/relativeTime-YQt84dYr.js +1 -0
- package/.output/public/assets/remote-config-B7ujqhLa.js +6 -0
- package/.output/public/assets/remote-config-WjpozBG5.js +1 -0
- package/.output/public/assets/remote-config-gXeH6PBW.js +1 -0
- package/.output/public/assets/rotate-cw-Cv2aVbYr.js +1 -0
- package/.output/public/assets/routes-BDdBIxYS.js +1 -0
- package/.output/public/assets/routes-CCD33Azv.js +2 -0
- package/.output/public/assets/search-BCel4Oy6.js +1 -0
- package/.output/public/assets/select-CBIU0_M1.js +1 -0
- package/.output/public/assets/{sidebar-BqX460IW.js → sidebar-Di9SN47G.js} +1 -1
- package/.output/public/assets/smartphone-CMaSy_ir.js +1 -0
- package/.output/public/assets/styles-Ccxthuz1.css +2 -0
- package/.output/public/assets/switch-BpdiHL_t.js +1 -0
- package/.output/public/assets/{table-ek1DmRHq.js → table-Bpy3SvSo.js} +1 -1
- package/.output/public/assets/{tabs-CgEH_fMT.js → tabs-Xmt7tZeG.js} +1 -1
- package/.output/public/assets/{undo-2-DxXx9Zvr.js → undo-2-CUX96_BG.js} +1 -1
- package/.output/public/assets/useCompositeListItem-JmyDfo3-.js +1 -0
- package/.output/public/assets/useInfiniteQuery-DX4WpBRG.js +1 -0
- package/.output/public/assets/useMutation-DbYw7boA.js +1 -0
- package/.output/public/assets/uuidv7-zXMtwR9Q.js +1 -0
- package/.output/public/assets/{valueToPercent-B44vDssN.js → valueToPercent-BLwGy_xK.js} +1 -1
- package/.output/server/{__23tanstack-start-server-fn-resolver-KpQ5Z_24.mjs → __23tanstack-start-server-fn-resolver-CygMPYHZ.mjs} +64 -40
- package/.output/server/_chunks/ssr-renderer.mjs +2 -2
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
- package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +1 -1
- package/.output/server/_libs/lucide-react.mjs +88 -1
- package/.output/server/_libs/uqr.mjs +858 -0
- package/.output/server/_ssr/-native-builds-search-CwNcoXf4.mjs +37 -0
- package/.output/server/_ssr/{BundleIdDisplay-CjSnY65J.mjs → BundleIdDisplay-DOPz4pUS.mjs} +2 -2
- package/.output/server/_ssr/{ConsoleFeatureUnavailable-CHxn9f-w.mjs → ConsoleFeatureUnavailable-Xb1JKqcc.mjs} +7 -7
- package/.output/server/_ssr/{EventDetails-l6dF54zp.mjs → EventDetails-D7MejFCN.mjs} +8 -8
- package/.output/server/_ssr/{HashValueDisplay-Zs7ABoOi.mjs → HashValueDisplay-Dd-wu5rY.mjs} +2 -2
- package/.output/server/_ssr/{InsightsPageHeader-ZlAlDxQy.mjs → InsightsPageHeader-CWf1n4Vt.mjs} +13 -11
- package/.output/server/_ssr/{NotFoundPage-u28ndvp1.mjs → NotFoundPage-C5rFdUpg.mjs} +2 -2
- package/.output/server/_ssr/PlatformIcon-CFLiTjh1.mjs +29 -0
- package/.output/server/_ssr/RolloutPercentageBadge-g0Bhfl3M.mjs +21 -0
- package/.output/server/_ssr/StoreSubmission-JZ2Zltak.mjs +139 -0
- package/.output/server/_ssr/{alert-dialog-B8AqlJwo.mjs → alert-dialog-CvNvTvIJ.mjs} +1 -1
- package/.output/server/_ssr/{api-C_0B7NXM.mjs → api-0vtwA5vY.mjs} +126 -7
- package/.output/server/_ssr/{api-keys-pRNvn2-9.mjs → api-keys-D5dyA4D1.mjs} +10 -10
- package/.output/server/_ssr/{api-keys-rpc-wecWs0nA.mjs → api-keys-rpc-BOIUHhDi.mjs} +5 -5
- package/.output/server/_ssr/{api-keys-CLH38u9B.mjs → api-keys-yFlQDwQF.mjs} +2 -2
- package/.output/server/_ssr/{api-rpc-DWN8eOHS.mjs → api-rpc-COeFOpYi.mjs} +79 -12
- package/.output/server/_ssr/{auth-UP0wXs4i.mjs → auth-Z-wLddzh.mjs} +1 -1
- package/.output/server/_ssr/{auth-rpc-CLRArbIl.mjs → auth-rpc-D1ss2GUI.mjs} +6 -6
- package/.output/server/_ssr/{auth.server-DR9zc0EU.mjs → auth.server-DYS1OJ6P.mjs} +771 -641
- package/.output/server/_ssr/{badge-BpT7r-ng.mjs → badge-CEdVRgyl.mjs} +1 -1
- package/.output/server/_ssr/{bundleActivity-0qFIcvqt.mjs → bundleActivity-MLrjNJCT.mjs} +1 -1
- package/.output/server/_ssr/{config-WVX4IxSR.mjs → config-CjIBFhJX.mjs} +1 -1
- package/.output/server/_ssr/config.server-NnMFjMFX.mjs +43 -0
- package/.output/server/_ssr/{console-access-aUpQs49I.mjs → console-access-33BNlH97.mjs} +3 -3
- package/.output/server/_ssr/{console-features-4xAGfZHw.mjs → console-features-BTV-XuhQ.mjs} +1 -1
- package/.output/server/_ssr/{console-features-api-DSSgCV3v.mjs → console-features-api-v1fSycue.mjs} +6 -6
- package/.output/server/_ssr/{console-features-rpc-D6kMlR2A.mjs → console-features-rpc-C7XNVqm0.mjs} +5 -5
- package/.output/server/_ssr/createCsrfMiddleware-BwHbC8n-.mjs +159 -0
- package/.output/server/_ssr/createMiddleware-C3ACsfuG.mjs +24 -0
- package/.output/server/_ssr/{createMiddleware-B1iPez7u.mjs → createServerFn-AQvBMBjJ.mjs} +2 -23
- package/.output/server/_ssr/{createServerRpc-BaDJLGBx.mjs → createServerRpc-BVvRVOz5.mjs} +2 -2
- package/.output/server/_ssr/{databaseConfig-C5SkAyUy.mjs → databaseConfig-B_Bg7qS5.mjs} +1 -1
- package/.output/server/_ssr/{databaseJsonValue-Csbuzc9Q.mjs → databaseJsonValue-kS7cvEtz.mjs} +1 -1
- package/.output/server/_ssr/{databaseRows-CPphvbag.mjs → databaseRows-B6H8Cmgq.mjs} +3 -3
- package/.output/server/_ssr/{dialog-B4ALf7NJ.mjs → dialog-C8CS8RMt.mjs} +1 -1
- package/.output/server/_ssr/{dist-CbQbBIw-.mjs → dist-TEpM_UAD.mjs} +125 -125
- package/.output/server/_ssr/{downloadBundle-94jPBGSO.mjs → downloadBundle-DCmr7vsj.mjs} +1 -1
- package/.output/server/_ssr/{empty-Bh1FEeYF.mjs → empty-CkdEAvCY.mjs} +2 -2
- package/.output/server/_ssr/{empty-plugin-adapters-CpCHi1TV.mjs → empty-plugin-adapters-zrZ0xs6n.mjs} +1 -1
- package/.output/server/_ssr/{failureReports-Bh22wois.mjs → failureReports-Cn_zU9S8.mjs} +3 -3
- package/.output/server/_ssr/{field-HKCaPH3e.mjs → field-CW08sZXd.mjs} +2 -2
- package/.output/server/_ssr/{getBundleChildren-DfxB2K8D.mjs → getBundleChildren-rtkEEJw5.mjs} +2 -2
- package/.output/server/_ssr/git-CTA8Aqr0.mjs +56 -0
- package/.output/server/_ssr/{input-group-xm3LzDuq.mjs → input-group-D-TpFPuG.mjs} +1 -1
- package/.output/server/_ssr/{insights-BKZpJ_K4.mjs → insights-CMyzPs8l.mjs} +28 -27
- package/.output/server/_ssr/{insights-CCyTACIw.mjs → insights-CYeBl8N9.mjs} +5 -5
- package/.output/server/_ssr/{insights-CNqWQLJR.mjs → insights-DAi9KknT.mjs} +2 -2
- package/.output/server/_ssr/{insights-api-DtRFz5X3.mjs → insights-api-BFARQ5ct.mjs} +6 -6
- package/.output/server/_ssr/{insights-errors-Iy-lBaM7.mjs → insights-errors-7BCwFybo.mjs} +2 -2
- package/.output/server/_ssr/{insights-failures-BJN3RfLu.mjs → insights-failures-B9VPkzZE.mjs} +2 -2
- package/.output/server/_ssr/{insights-failures-rpc-DLZ91uOG.mjs → insights-failures-rpc-Q4WNNJkU.mjs} +12 -12
- package/.output/server/_ssr/{insights-recovery-BUuQdlA3.mjs → insights-recovery-BtXVU3ro.mjs} +1 -1
- package/.output/server/_ssr/{insights-recovery-rpc-BQHUhPi7.mjs → insights-recovery-rpc-CY5RYJKa.mjs} +8 -8
- package/.output/server/_ssr/{insights-rpc-C6Vukyn7.mjs → insights-rpc-BO7_evvs.mjs} +5 -5
- package/.output/server/_ssr/{insights-search-CBYoxT7v.mjs → insights-search-DKfxgHD3.mjs} +5 -5
- package/.output/server/_ssr/{insights-usage-CHqvtehH.mjs → insights-usage-DiGnuxW8.mjs} +1 -1
- package/.output/server/_ssr/{insights-usage-rpc-BJ7a-xco.mjs → insights-usage-rpc-B4czku50.mjs} +8 -8
- package/.output/server/_ssr/{insights-usage-rpc-C-lNUIsD.mjs → insights-usage-rpc-CUCTFska.mjs} +5 -5
- package/.output/server/_ssr/{insightsUsage-COUG-_-U.mjs → insightsUsage-ClAmoUz8.mjs} +3 -3
- package/.output/server/_ssr/{insights_.distribution-DmLW8I8a.mjs → insights_.distribution-BDeUhZGj.mjs} +2 -2
- package/.output/server/_ssr/{insights_.distribution-CTwilMPm.mjs → insights_.distribution-BRrbZN1X.mjs} +5 -5
- package/.output/server/_ssr/{insights_.distribution-DztDyrBj.mjs → insights_.distribution-C2MXpzKd.mjs} +15 -14
- package/.output/server/_ssr/{installations-Bct7ag5y.mjs → installations-BVk7okiY.mjs} +4 -4
- package/.output/server/_ssr/{installations-B6MK5iA8.mjs → installations-BjLMgBoH.mjs} +2 -2
- package/.output/server/_ssr/{installations-_N4PtYFl.mjs → installations-DxGZEC5G.mjs} +12 -12
- package/.output/server/_ssr/{listReleases-BfUBlCHo.mjs → listReleases-D_GY00SQ.mjs} +1 -1
- package/.output/server/_ssr/native-builds-CSCgFB21.mjs +10 -0
- package/.output/server/_ssr/native-builds-CdlyAldW.mjs +569 -0
- package/.output/server/_ssr/native-builds-DhXL5zf_.mjs +137 -0
- package/.output/server/_ssr/native-builds_._buildId-CMp1h8dT.mjs +10 -0
- package/.output/server/_ssr/native-builds_._buildId-GHpGaYyE.mjs +813 -0
- package/.output/server/_ssr/nativeBuildQr-84cnFQPX.mjs +59 -0
- package/.output/server/_ssr/nativeBuilds-B_7BPjt_.mjs +133 -0
- package/.output/server/_ssr/{plugins-BaD1slHx.mjs → plugins-RIryUNWj.mjs} +6 -5
- package/.output/server/_ssr/qr-code-C7kNRIDX.mjs +22 -0
- package/.output/server/_ssr/{release-adoption-DuYJTGuX.mjs → release-adoption-DoAtNPED.mjs} +2 -2
- package/.output/server/_ssr/{release-adoption-rpc-CHl7G_Zy.mjs → release-adoption-rpc-BJXZvtoQ.mjs} +10 -10
- package/.output/server/_ssr/{releaseAdoption-B39cpvfo.mjs → releaseAdoption-a2byXMfz.mjs} +4 -4
- package/.output/server/_ssr/releaseCatalogCompiler-DLcean2k.mjs +364 -0
- package/.output/server/_ssr/{releaseManagement-DFMUnDF5.mjs → releaseManagement-DHUux2az.mjs} +1 -1
- package/.output/server/_ssr/{releaseReachability-bFsuElSS.mjs → releaseReachability-DZOK_dH-.mjs} +2 -2
- package/.output/server/_ssr/{remote-config-Mj05qVYZ.mjs → remote-config-DjsEl270.mjs} +20 -19
- package/.output/server/_ssr/{remote-config-10-obSZ0.mjs → remote-config-DlyyohL2.mjs} +2 -2
- package/.output/server/_ssr/{remote-config-Dj1eTYi4.mjs → remote-config-XdYuByHz.mjs} +2 -2
- package/.output/server/_ssr/{remote-config-rpc-lteqDSLn.mjs → remote-config-rpc-GMLPb-90.mjs} +6 -6
- package/.output/server/_ssr/request-guard-CPdRBuGW.mjs +108 -0
- package/.output/server/_ssr/{router-Dr4jjjhx.mjs → router-vpxd56RW.mjs} +317 -71
- package/.output/server/_ssr/{routes-BZbrY_qw.mjs → routes-DyEM4b3x.mjs} +14 -14
- package/.output/server/_ssr/{routes-B5KrCDwk.mjs → routes-dQe3XhiS.mjs} +99 -81
- package/.output/server/_ssr/{runtime.server-DsHqVqTr.mjs → runtime.server-BdMY1blX.mjs} +4 -4
- package/.output/server/_ssr/schema-ChlRtZIo.mjs +23 -0
- package/.output/server/_ssr/schema-migration-rpc-BfGzEK_o.mjs +65 -0
- package/.output/server/_ssr/{select-BtdGNSmp.mjs → select-DM1uwtk9.mjs} +3 -27
- package/.output/server/_ssr/{server-BxaHSwHh.mjs → server-BUUKNSPI.mjs} +7 -161
- package/.output/server/_ssr/{sidebar-CVsgosaD.mjs → sidebar-DB2YQlok.mjs} +4 -4
- package/.output/server/_ssr/ssr.mjs +1 -1
- package/.output/server/_ssr/start-BvDsQehg.mjs +49 -0
- package/.output/server/_ssr/{switch-BmARgkUP.mjs → switch-DLD58zLy.mjs} +2 -2
- package/.output/server/_ssr/{table-M5P3YUfY.mjs → table-P4TnAZhl.mjs} +1 -1
- package/.output/server/_ssr/{tabs-CrmfOlJj.mjs → tabs-B7ZeLicF.mjs} +2 -2
- package/.output/server/_ssr/{updateFailures-z1IQy_4q.mjs → updateFailures-n-tGv90S.mjs} +3 -3
- package/.output/server/_ssr/{uuidv7-C88s9jWF.mjs → uuidv7-BIF4nb_q.mjs} +2 -2
- package/.output/server/_ssr/{schema-BiAVyEj2.mjs → version-CQ98ZBpL-CWSkTT9J.mjs} +2 -22
- package/.output/server/_tanstack-start-manifest_v-C-KC63Zq.mjs +184 -0
- package/.output/server/index.mjs +432 -271
- package/lib/vite-internal.mjs +32 -1
- package/package.json +8 -7
- package/src/components/AppSidebar.tsx +12 -1
- package/src/components/ConsoleAccessPage.tsx +49 -3
- package/src/components/QrCode.tsx +35 -0
- package/src/components/SchemaMigrationRequired.tsx +139 -0
- package/src/components/features/insights/BuiltinBundle.tsx +5 -3
- package/src/components/features/native-builds/BuiltInBundleCard.tsx +163 -0
- package/src/components/features/native-builds/CommitLink.tsx +30 -0
- package/src/components/features/native-builds/CopyableText.tsx +48 -0
- package/src/components/features/native-builds/ImportBuild.tsx +91 -0
- package/src/components/features/native-builds/InstallCard.tsx +205 -0
- package/src/components/features/native-builds/NativeBuildDetailPage.tsx +175 -0
- package/src/components/features/native-builds/NativeBuildsPage.tsx +151 -0
- package/src/components/features/native-builds/NativeBuildsTable.tsx +426 -0
- package/src/components/features/native-builds/PatchesCard.tsx +222 -0
- package/src/components/features/native-builds/ReleaseNativeBuildLink.tsx +101 -0
- package/src/components/features/native-builds/ServedNowCard.tsx +214 -0
- package/src/components/features/native-builds/ShortHash.tsx +41 -0
- package/src/components/features/native-builds/StoreSubmission.tsx +73 -0
- package/src/components/features/releases/ReleaseEditorSheet.tsx +8 -0
- package/src/lib/api-rpc.ts +98 -0
- package/src/lib/api.ts +120 -0
- package/src/lib/native-builds.ts +162 -0
- package/src/lib/qr-code.ts +16 -0
- package/src/lib/schema-migration-api.ts +54 -0
- package/src/lib/schema-migration-rpc.ts +26 -0
- package/src/lib/schema-migration.ts +101 -0
- package/src/lib/server/config.server.ts +23 -14
- package/src/lib/server/console-runtime.server.ts +4 -6
- package/src/lib/server/local-console.ts +164 -0
- package/src/lib/server/nativeBuildQr.ts +73 -0
- package/src/lib/server/nativeBuilds.ts +288 -0
- package/src/lib/shell.ts +9 -0
- package/src/routeTree.gen.ts +88 -1
- package/src/router.tsx +11 -1
- package/src/routes/-native-builds-search.ts +51 -0
- package/src/routes/[_]hot-updater/native-builds/qr.ts +14 -0
- package/src/routes/__root.tsx +11 -1
- package/src/routes/api/native-builds/$buildId/download.ts +50 -0
- package/src/routes/native-builds.tsx +21 -0
- package/src/routes/native-builds_.$buildId.tsx +23 -0
- package/src/start.ts +33 -0
- package/src/virtual-modules.d.ts +18 -0
- package/src/vite-internal.ts +57 -1
- package/.output/public/assets/EventDetails-gbD_fCqc.js +0 -1
- package/.output/public/assets/HashValueDisplay-BGkDPaYi.js +0 -1
- package/.output/public/assets/InsightsPageHeader-BRw8XkJW.js +0 -1
- package/.output/public/assets/NotFoundPage-Cei6W2lm.js +0 -1
- package/.output/public/assets/alert-dialog-BtVg50WQ.js +0 -1
- package/.output/public/assets/api-DoicFJfd.js +0 -1
- package/.output/public/assets/api-keys-D81VHHNM.js +0 -1
- package/.output/public/assets/api-keys-Dia6i8K1.js +0 -1
- package/.output/public/assets/arrow-left-DsivSewE.js +0 -1
- package/.output/public/assets/arrow-up-right-B5aM0F7f.js +0 -1
- package/.output/public/assets/badge-Bqf3UDee.js +0 -1
- package/.output/public/assets/circle-off-BsbZQtsF.js +0 -1
- package/.output/public/assets/console-features-api-DPE4C06Y.js +0 -2
- package/.output/public/assets/dialog-CGKPxz3n.js +0 -1
- package/.output/public/assets/index-DrkdiRIn.js +0 -10
- package/.output/public/assets/insights-C-5t8wh2.js +0 -2
- package/.output/public/assets/insights-D_ngQdiz.js +0 -1
- package/.output/public/assets/insights-KigRBDgC.js +0 -42
- package/.output/public/assets/insights-api-1ZjVu3Sb.js +0 -1
- package/.output/public/assets/insights-search-aT8BVCci.js +0 -1
- package/.output/public/assets/insights-usage-rpc-DqTiXI1_.js +0 -1
- package/.output/public/assets/insights_.distribution-Bzl6RFBR.js +0 -2
- package/.output/public/assets/insights_.distribution-Cthgttqb.js +0 -1
- package/.output/public/assets/insights_.distribution-D2c2v1bu.js +0 -1
- package/.output/public/assets/installations-2Nx8Htf-.js +0 -1
- package/.output/public/assets/installations-BskJ1xQr.js +0 -2
- package/.output/public/assets/installations-K2iJ_r0h.js +0 -1
- package/.output/public/assets/remote-config-D9X3NiwV.js +0 -6
- package/.output/public/assets/remote-config-DzOOiBIO.js +0 -1
- package/.output/public/assets/remote-config-ikg7kak0.js +0 -1
- package/.output/public/assets/routes-9rb9P5Y7.js +0 -2
- package/.output/public/assets/routes-P7683vKQ.js +0 -1
- package/.output/public/assets/search-DuI1FBpg.js +0 -1
- package/.output/public/assets/select-M3H2gxCc.js +0 -1
- package/.output/public/assets/smartphone-CtsHuiIC.js +0 -1
- package/.output/public/assets/styles-CpiW_YdW.css +0 -2
- package/.output/public/assets/switch-By_vfm8I.js +0 -1
- package/.output/public/assets/useCompositeListItem-B-UkrDlu.js +0 -1
- package/.output/server/_ssr/config.server-DTdsG47T.mjs +0 -35
- package/.output/server/_ssr/start-B6ECIE_7.mjs +0 -4
- package/.output/server/_tanstack-start-manifest_v-_BY9hYTm.mjs +0 -136
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ArrowUpRight, FileUp } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import { Button, buttonVariants } from "@/components/ui/button";
|
|
4
|
+
import {
|
|
5
|
+
Dialog,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogDescription,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
DialogTrigger,
|
|
11
|
+
} from "@/components/ui/dialog";
|
|
12
|
+
|
|
13
|
+
import { CopyableText } from "./CopyableText";
|
|
14
|
+
|
|
15
|
+
/** The command that tracks a build made elsewhere. */
|
|
16
|
+
export const IMPORT_COMMAND =
|
|
17
|
+
"npx hot-updater native-build import <path-to-.ipa|.aab|.apk|.app|.app.zip>";
|
|
18
|
+
|
|
19
|
+
/** `native-build import`'s section of the native build guide. */
|
|
20
|
+
export const IMPORT_GUIDE_URL =
|
|
21
|
+
"https://hot-updater.dev/docs/guides/native-build#import-a-build-made-elsewhere";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* How to track a build made elsewhere: the CLI command, which reads the
|
|
25
|
+
* artifact on the machine that has it. The Console uploads nothing, since a
|
|
26
|
+
* host may cap a request's body far below an `.ipa`.
|
|
27
|
+
*/
|
|
28
|
+
export function ImportBuildSteps() {
|
|
29
|
+
return (
|
|
30
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
31
|
+
<p className="text-xs text-muted-foreground">
|
|
32
|
+
Track an <code className="font-mono">.ipa</code>,{" "}
|
|
33
|
+
<code className="font-mono">.aab</code>,{" "}
|
|
34
|
+
<code className="font-mono">.apk</code> or simulator{" "}
|
|
35
|
+
<code className="font-mono">.app</code> (or its{" "}
|
|
36
|
+
<code className="font-mono">.app.zip</code>) built elsewhere, such as by
|
|
37
|
+
EAS, Xcode Cloud or Fastlane, so the OTAs you deploy after it patch from
|
|
38
|
+
its built-in bundle. Run in the app's project:
|
|
39
|
+
</p>
|
|
40
|
+
<CopyableText label="the import command" value={IMPORT_COMMAND} wrap />
|
|
41
|
+
<p className="text-xs text-muted-foreground">
|
|
42
|
+
Add <code className="font-mono">-c <channel></code> (
|
|
43
|
+
<code className="font-mono">--channel</code>) when the app reports
|
|
44
|
+
another channel than the one it was built with, such as one its code
|
|
45
|
+
sets or switches to at runtime.
|
|
46
|
+
</p>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The toolbar's "Import a build" button and the command it shows. */
|
|
52
|
+
export function ImportBuildDialog() {
|
|
53
|
+
return (
|
|
54
|
+
<Dialog>
|
|
55
|
+
<DialogTrigger
|
|
56
|
+
render={
|
|
57
|
+
<Button
|
|
58
|
+
aria-label="Import a build"
|
|
59
|
+
className="min-h-11 sm:min-h-7"
|
|
60
|
+
size="sm"
|
|
61
|
+
variant="outline"
|
|
62
|
+
/>
|
|
63
|
+
}
|
|
64
|
+
>
|
|
65
|
+
<FileUp data-icon="inline-start" />
|
|
66
|
+
<span className="hidden sm:inline">Import a build</span>
|
|
67
|
+
</DialogTrigger>
|
|
68
|
+
<DialogContent className="sm:max-w-lg">
|
|
69
|
+
<DialogHeader>
|
|
70
|
+
<DialogTitle>Import a build</DialogTitle>
|
|
71
|
+
<DialogDescription>
|
|
72
|
+
The build appears here once the command tracks it.
|
|
73
|
+
</DialogDescription>
|
|
74
|
+
</DialogHeader>
|
|
75
|
+
<ImportBuildSteps />
|
|
76
|
+
<a
|
|
77
|
+
className={buttonVariants({
|
|
78
|
+
className: "min-h-11 w-full sm:min-h-8 sm:w-fit",
|
|
79
|
+
variant: "outline",
|
|
80
|
+
})}
|
|
81
|
+
href={IMPORT_GUIDE_URL}
|
|
82
|
+
rel="noreferrer"
|
|
83
|
+
target="_blank"
|
|
84
|
+
>
|
|
85
|
+
Import guide
|
|
86
|
+
<ArrowUpRight data-icon="inline-end" />
|
|
87
|
+
</a>
|
|
88
|
+
</DialogContent>
|
|
89
|
+
</Dialog>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { NativeBuildRow } from "@hot-updater/plugin-core";
|
|
2
|
+
import { AlertTriangle, Download } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { QrCode } from "@/components/QrCode";
|
|
5
|
+
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
6
|
+
import { buttonVariants } from "@/components/ui/button";
|
|
7
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
8
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
9
|
+
import { useNativeBuildDownloadUrlQuery } from "@/lib/api";
|
|
10
|
+
import {
|
|
11
|
+
apkInstallCommand,
|
|
12
|
+
nativeBuildDownloadPath,
|
|
13
|
+
nativeBuildFileName,
|
|
14
|
+
simulatorInstallCommand,
|
|
15
|
+
} from "@/lib/native-builds";
|
|
16
|
+
|
|
17
|
+
import { CopyableText } from "./CopyableText";
|
|
18
|
+
import { isSubmitted } from "./StoreSubmission";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* What an artifact installs on, where the file alone isn't enough: the card
|
|
22
|
+
* says it once, under the QR code, or without one, in its place.
|
|
23
|
+
*/
|
|
24
|
+
const INSTALL_LIMITS: Partial<Record<NativeBuildRow["artifact_kind"], string>> =
|
|
25
|
+
{
|
|
26
|
+
ipa: "The .ipa installs only on devices its signing profile allows (development or ad hoc); an App Store export reaches testers through TestFlight.",
|
|
27
|
+
aab: "The .aab installs through Google Play or bundletool, not from the file.",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* What scanning a build's QR code gets, by its artifact. The install steps
|
|
32
|
+
* beside it add only what this doesn't say, so the card says each thing once.
|
|
33
|
+
*/
|
|
34
|
+
const QR_CAPTIONS: Record<NativeBuildRow["artifact_kind"], string> = {
|
|
35
|
+
apk: "Scan with an Android phone's camera, then open the APK to install it.",
|
|
36
|
+
ipa: `Scan to download. ${INSTALL_LIMITS.ipa}`,
|
|
37
|
+
aab: `Scan to download. ${INSTALL_LIMITS.aab}`,
|
|
38
|
+
app: "Scan to download the .app.zip on a Mac.",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The QR code of the build's download: the storage's URL, which a phone
|
|
43
|
+
* opens without the console's sign-in, read again before it expires.
|
|
44
|
+
*/
|
|
45
|
+
function DownloadQrCode({ build }: { readonly build: NativeBuildRow }) {
|
|
46
|
+
const downloadUrl = useNativeBuildDownloadUrlQuery(build.id, true);
|
|
47
|
+
const url = downloadUrl.data?.url;
|
|
48
|
+
|
|
49
|
+
// A storage without download URLs serves the build only through the
|
|
50
|
+
// console, which a phone that scans isn't signed in to.
|
|
51
|
+
if (url === null) {
|
|
52
|
+
const limits = INSTALL_LIMITS[build.artifact_kind];
|
|
53
|
+
return (
|
|
54
|
+
<div className="flex flex-col gap-2 text-xs text-muted-foreground">
|
|
55
|
+
<p>
|
|
56
|
+
This storage gives no download link a phone can open without signing
|
|
57
|
+
in, so there is no QR code. Download the build here, or open this page
|
|
58
|
+
on the phone signed in to the console.
|
|
59
|
+
</p>
|
|
60
|
+
{limits ? <p>{limits}</p> : null}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div className="flex flex-col items-center gap-2">
|
|
67
|
+
{url === undefined ? (
|
|
68
|
+
downloadUrl.isError ? (
|
|
69
|
+
<Alert variant="destructive">
|
|
70
|
+
<AlertTriangle />
|
|
71
|
+
<AlertTitle>The download link couldn't be created</AlertTitle>
|
|
72
|
+
<AlertDescription>{downloadUrl.error.message}</AlertDescription>
|
|
73
|
+
</Alert>
|
|
74
|
+
) : (
|
|
75
|
+
<Skeleton className="size-48" />
|
|
76
|
+
)
|
|
77
|
+
) : (
|
|
78
|
+
<QrCode
|
|
79
|
+
className="size-48"
|
|
80
|
+
label={`Download ${nativeBuildFileName(build)}`}
|
|
81
|
+
value={url}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
<p className="max-w-56 text-center text-xs text-muted-foreground">
|
|
85
|
+
{QR_CAPTIONS[build.artifact_kind]}
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The store's label of a submitted build. */
|
|
92
|
+
function SubmittedVersion({ build }: { readonly build: NativeBuildRow }) {
|
|
93
|
+
return (
|
|
94
|
+
<span className="font-mono text-foreground" translate="no">
|
|
95
|
+
{build.submitted_version ?? "this build"}
|
|
96
|
+
</span>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* How else the artifact installs, beside its QR code's caption and its
|
|
102
|
+
* download: none of it repeats the caption.
|
|
103
|
+
*/
|
|
104
|
+
function InstallSteps({ build }: { readonly build: NativeBuildRow }) {
|
|
105
|
+
switch (build.artifact_kind) {
|
|
106
|
+
case "apk":
|
|
107
|
+
return (
|
|
108
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
109
|
+
<p className="text-xs text-muted-foreground">
|
|
110
|
+
On an emulator or a phone over USB, download the APK and install it:
|
|
111
|
+
</p>
|
|
112
|
+
<CopyableText
|
|
113
|
+
label="the install command"
|
|
114
|
+
value={apkInstallCommand(build)}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
case "app":
|
|
119
|
+
return (
|
|
120
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
121
|
+
<p className="text-xs text-muted-foreground">
|
|
122
|
+
It runs only in the iOS Simulator. Install it on the booted one:
|
|
123
|
+
</p>
|
|
124
|
+
<CopyableText
|
|
125
|
+
label="the install command"
|
|
126
|
+
value={simulatorInstallCommand(build)}
|
|
127
|
+
/>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
case "aab":
|
|
131
|
+
return isSubmitted(build) ? (
|
|
132
|
+
<p className="text-xs text-muted-foreground">
|
|
133
|
+
Submitted to Google Play internal testing as{" "}
|
|
134
|
+
<SubmittedVersion build={build} />. Testers get it once its release is
|
|
135
|
+
rolled out; on an app Play Console hasn't published, the release is a
|
|
136
|
+
draft you roll out in Play Console.
|
|
137
|
+
</p>
|
|
138
|
+
) : (
|
|
139
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
140
|
+
<p className="text-xs text-muted-foreground">
|
|
141
|
+
For testers, build and release to internal testing:
|
|
142
|
+
</p>
|
|
143
|
+
<CopyableText
|
|
144
|
+
label="the Google Play command"
|
|
145
|
+
value="npx hot-updater google-play upload"
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
case "ipa":
|
|
150
|
+
return isSubmitted(build) ? (
|
|
151
|
+
<p className="text-xs text-muted-foreground">
|
|
152
|
+
On TestFlight as <SubmittedVersion build={build} />.
|
|
153
|
+
</p>
|
|
154
|
+
) : (
|
|
155
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
156
|
+
<p className="text-xs text-muted-foreground">
|
|
157
|
+
Over USB, Xcode or Apple Configurator installs it. For testers:
|
|
158
|
+
</p>
|
|
159
|
+
<CopyableText
|
|
160
|
+
label="the TestFlight command"
|
|
161
|
+
value="npx hot-updater testflight"
|
|
162
|
+
/>
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Installs one native build: every artifact by a QR code of its download,
|
|
170
|
+
* which a phone scans, and by download here; an APK also with `adb`, a
|
|
171
|
+
* simulator app with `xcrun simctl`, and an IPA's or an AAB's testers through
|
|
172
|
+
* its store.
|
|
173
|
+
*/
|
|
174
|
+
export function InstallCard({ build }: { readonly build: NativeBuildRow }) {
|
|
175
|
+
const fileName = nativeBuildFileName(build);
|
|
176
|
+
return (
|
|
177
|
+
<Card className="overflow-hidden shadow-sm">
|
|
178
|
+
<CardHeader className="border-b px-4 py-3">
|
|
179
|
+
<CardTitle className="text-sm">
|
|
180
|
+
<h2>Install</h2>
|
|
181
|
+
</CardTitle>
|
|
182
|
+
</CardHeader>
|
|
183
|
+
<CardContent className="grid gap-6 p-4 sm:grid-cols-[12rem_minmax(0,1fr)] sm:p-6">
|
|
184
|
+
<DownloadQrCode build={build} />
|
|
185
|
+
<div className="flex min-w-0 flex-col gap-4">
|
|
186
|
+
<InstallSteps build={build} />
|
|
187
|
+
<a
|
|
188
|
+
className={buttonVariants({
|
|
189
|
+
className:
|
|
190
|
+
"h-auto min-h-11 w-full min-w-0 py-2 whitespace-normal sm:min-h-8 sm:w-fit",
|
|
191
|
+
variant: "outline",
|
|
192
|
+
})}
|
|
193
|
+
download
|
|
194
|
+
href={nativeBuildDownloadPath(build.id)}
|
|
195
|
+
>
|
|
196
|
+
<Download data-icon="inline-start" />
|
|
197
|
+
<span className="text-left [overflow-wrap:anywhere]">
|
|
198
|
+
Download {fileName}
|
|
199
|
+
</span>
|
|
200
|
+
</a>
|
|
201
|
+
</div>
|
|
202
|
+
</CardContent>
|
|
203
|
+
</Card>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Link } from "@tanstack/react-router";
|
|
2
|
+
import { AlertTriangle, ChevronLeft, HardDrive, RefreshCw } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { PlatformIcon } from "@/components/PlatformIcon";
|
|
5
|
+
import {
|
|
6
|
+
Alert,
|
|
7
|
+
AlertAction,
|
|
8
|
+
AlertDescription,
|
|
9
|
+
AlertTitle,
|
|
10
|
+
} from "@/components/ui/alert";
|
|
11
|
+
import { Button, buttonVariants } from "@/components/ui/button";
|
|
12
|
+
import {
|
|
13
|
+
Empty,
|
|
14
|
+
EmptyContent,
|
|
15
|
+
EmptyDescription,
|
|
16
|
+
EmptyHeader,
|
|
17
|
+
EmptyMedia,
|
|
18
|
+
EmptyTitle,
|
|
19
|
+
} from "@/components/ui/empty";
|
|
20
|
+
import { SidebarTrigger } from "@/components/ui/sidebar";
|
|
21
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
22
|
+
import { type KeysetPage, useNativeBuildDetailQuery } from "@/lib/api";
|
|
23
|
+
import {
|
|
24
|
+
formatByteSize,
|
|
25
|
+
nativeBuildArtifacts,
|
|
26
|
+
platformLabel,
|
|
27
|
+
} from "@/lib/native-builds";
|
|
28
|
+
|
|
29
|
+
import { BuiltInBundleCard } from "./BuiltInBundleCard";
|
|
30
|
+
import { InstallCard } from "./InstallCard";
|
|
31
|
+
import { PatchesCard } from "./PatchesCard";
|
|
32
|
+
import { ServedNowCard } from "./ServedNowCard";
|
|
33
|
+
|
|
34
|
+
export interface NativeBuildDetailSearch {
|
|
35
|
+
/** Patches older than this target bundle: the next page. */
|
|
36
|
+
readonly patchesBefore?: string;
|
|
37
|
+
/** Patches newer than this target bundle: the previous page. */
|
|
38
|
+
readonly patchesAfter?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* One native build: how to install it, its built-in bundle as the base its
|
|
43
|
+
* OTAs patch from, what an install is served now, and the patches from it.
|
|
44
|
+
* The patch page is in the URL, so a link opens it.
|
|
45
|
+
*/
|
|
46
|
+
export function NativeBuildDetailPage({
|
|
47
|
+
buildId,
|
|
48
|
+
search,
|
|
49
|
+
onSearchChange,
|
|
50
|
+
}: {
|
|
51
|
+
readonly buildId: string;
|
|
52
|
+
readonly search: NativeBuildDetailSearch;
|
|
53
|
+
readonly onSearchChange: (search: NativeBuildDetailSearch) => void;
|
|
54
|
+
}) {
|
|
55
|
+
const query = useNativeBuildDetailQuery(buildId);
|
|
56
|
+
const detail = query.data;
|
|
57
|
+
const page: KeysetPage = {
|
|
58
|
+
...(search.patchesBefore === undefined
|
|
59
|
+
? {}
|
|
60
|
+
: { before: search.patchesBefore }),
|
|
61
|
+
...(search.patchesAfter === undefined
|
|
62
|
+
? {}
|
|
63
|
+
: { after: search.patchesAfter }),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className="flex h-svh min-h-0 flex-col">
|
|
68
|
+
<header className="sticky top-0 z-10 flex shrink-0 items-center gap-x-2 border-b bg-background px-3 py-3 sm:min-h-12 sm:bg-card/70 sm:px-4 sm:backdrop-blur-sm">
|
|
69
|
+
<SidebarTrigger className="-ml-1 size-11 lg:size-7" />
|
|
70
|
+
<Link
|
|
71
|
+
className={buttonVariants({
|
|
72
|
+
className: "min-h-11 sm:min-h-7",
|
|
73
|
+
size: "sm",
|
|
74
|
+
variant: "ghost",
|
|
75
|
+
})}
|
|
76
|
+
to="/native-builds"
|
|
77
|
+
>
|
|
78
|
+
<ChevronLeft data-icon="inline-start" />
|
|
79
|
+
Native builds
|
|
80
|
+
</Link>
|
|
81
|
+
{detail ? (
|
|
82
|
+
<h1 className="flex min-w-0 items-center gap-1.5 text-sm font-medium">
|
|
83
|
+
<PlatformIcon
|
|
84
|
+
className="size-3.5 shrink-0 text-muted-foreground"
|
|
85
|
+
platform={detail.build.platform}
|
|
86
|
+
/>
|
|
87
|
+
<span className="min-w-0 [overflow-wrap:anywhere]">
|
|
88
|
+
{platformLabel(detail.build.platform)}{" "}
|
|
89
|
+
{nativeBuildArtifacts[detail.build.artifact_kind].label} ·{" "}
|
|
90
|
+
<span translate="no">{detail.channel}</span>
|
|
91
|
+
</span>
|
|
92
|
+
<span className="hidden text-xs font-normal text-muted-foreground tabular-nums sm:inline">
|
|
93
|
+
{formatByteSize(detail.build.byte_size)}
|
|
94
|
+
</span>
|
|
95
|
+
</h1>
|
|
96
|
+
) : (
|
|
97
|
+
<h1 className="sr-only">Native build</h1>
|
|
98
|
+
)}
|
|
99
|
+
</header>
|
|
100
|
+
|
|
101
|
+
<div className="min-h-0 min-w-0 flex-1 overflow-y-auto bg-muted/5 p-3 sm:p-6">
|
|
102
|
+
<div className="mx-auto flex w-full max-w-5xl flex-col gap-4 sm:gap-6">
|
|
103
|
+
{query.isError ? (
|
|
104
|
+
<Alert variant="destructive">
|
|
105
|
+
<AlertTriangle />
|
|
106
|
+
<AlertTitle>The native build couldn't be loaded</AlertTitle>
|
|
107
|
+
<AlertDescription>{query.error.message}</AlertDescription>
|
|
108
|
+
<AlertAction>
|
|
109
|
+
<Button
|
|
110
|
+
onClick={() => void query.refetch()}
|
|
111
|
+
size="xs"
|
|
112
|
+
variant="outline"
|
|
113
|
+
>
|
|
114
|
+
<RefreshCw data-icon="inline-start" />
|
|
115
|
+
Retry
|
|
116
|
+
</Button>
|
|
117
|
+
</AlertAction>
|
|
118
|
+
</Alert>
|
|
119
|
+
) : detail === undefined ? (
|
|
120
|
+
<>
|
|
121
|
+
<span className="sr-only">Loading the native build</span>
|
|
122
|
+
<Skeleton className="h-56 w-full rounded-xl" />
|
|
123
|
+
<Skeleton className="h-64 w-full rounded-xl" />
|
|
124
|
+
</>
|
|
125
|
+
) : detail === null ? (
|
|
126
|
+
<Empty className="border py-16">
|
|
127
|
+
<EmptyHeader>
|
|
128
|
+
<EmptyMedia variant="icon">
|
|
129
|
+
<HardDrive />
|
|
130
|
+
</EmptyMedia>
|
|
131
|
+
<EmptyTitle>Native build not found</EmptyTitle>
|
|
132
|
+
<EmptyDescription>
|
|
133
|
+
No native build has this ID. It may have been deleted with{" "}
|
|
134
|
+
<code className="font-mono">native-build delete</code>, or be
|
|
135
|
+
from another console.
|
|
136
|
+
</EmptyDescription>
|
|
137
|
+
</EmptyHeader>
|
|
138
|
+
<EmptyContent>
|
|
139
|
+
<Link
|
|
140
|
+
className={buttonVariants({
|
|
141
|
+
className: "min-h-11 sm:min-h-8",
|
|
142
|
+
variant: "outline",
|
|
143
|
+
})}
|
|
144
|
+
to="/native-builds"
|
|
145
|
+
>
|
|
146
|
+
Show all native builds
|
|
147
|
+
</Link>
|
|
148
|
+
</EmptyContent>
|
|
149
|
+
</Empty>
|
|
150
|
+
) : (
|
|
151
|
+
<>
|
|
152
|
+
<InstallCard build={detail.build} />
|
|
153
|
+
<BuiltInBundleCard detail={detail} />
|
|
154
|
+
<ServedNowCard detail={detail} />
|
|
155
|
+
<PatchesCard
|
|
156
|
+
detail={detail}
|
|
157
|
+
onPage={(next) =>
|
|
158
|
+
onSearchChange({
|
|
159
|
+
...(next.before === undefined
|
|
160
|
+
? {}
|
|
161
|
+
: { patchesBefore: next.before }),
|
|
162
|
+
...(next.after === undefined
|
|
163
|
+
? {}
|
|
164
|
+
: { patchesAfter: next.after }),
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
page={page}
|
|
168
|
+
/>
|
|
169
|
+
</>
|
|
170
|
+
)}
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { HardDrive, RefreshCw } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { Card, CardContent } from "@/components/ui/card";
|
|
5
|
+
import {
|
|
6
|
+
Select,
|
|
7
|
+
SelectContent,
|
|
8
|
+
SelectGroup,
|
|
9
|
+
SelectItem,
|
|
10
|
+
SelectTrigger,
|
|
11
|
+
SelectValue,
|
|
12
|
+
} from "@/components/ui/select";
|
|
13
|
+
import { SidebarTrigger } from "@/components/ui/sidebar";
|
|
14
|
+
import {
|
|
15
|
+
type NativeBuildPage,
|
|
16
|
+
useChannelsQuery,
|
|
17
|
+
useNativeBuildsQuery,
|
|
18
|
+
} from "@/lib/api";
|
|
19
|
+
|
|
20
|
+
import { ImportBuildDialog } from "./ImportBuild";
|
|
21
|
+
import { NativeBuildsTable } from "./NativeBuildsTable";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The filter's values: a channel's is its name behind a prefix, so no channel
|
|
25
|
+
* name, `all` included, can be taken for "All channels".
|
|
26
|
+
*/
|
|
27
|
+
const ALL_CHANNELS = "all";
|
|
28
|
+
const CHANNEL_VALUE_PREFIX = "channel:";
|
|
29
|
+
const channelValue = (name: string) => `${CHANNEL_VALUE_PREFIX}${name}`;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The native builds Hot Updater tracks: one page at a time, newest first,
|
|
33
|
+
* optionally only those that embed one channel. The page and the channel
|
|
34
|
+
* are in the URL, so a pull request links to its channel's builds.
|
|
35
|
+
*/
|
|
36
|
+
export function NativeBuildsPage({
|
|
37
|
+
search,
|
|
38
|
+
onSearchChange,
|
|
39
|
+
}: {
|
|
40
|
+
readonly search: NativeBuildPage;
|
|
41
|
+
readonly onSearchChange: (search: NativeBuildPage) => void;
|
|
42
|
+
}) {
|
|
43
|
+
const { channel, before, after } = search;
|
|
44
|
+
const builds = useNativeBuildsQuery(search);
|
|
45
|
+
// The filter's choices; the rows decode their channel from its ID.
|
|
46
|
+
const channels = useChannelsQuery();
|
|
47
|
+
const channelNames = channels.data?.map(({ name }) => name) ?? [];
|
|
48
|
+
// A filtered channel may be gone, or not loaded yet: it stays a choice.
|
|
49
|
+
const choices =
|
|
50
|
+
channel === undefined || channelNames.includes(channel)
|
|
51
|
+
? channelNames
|
|
52
|
+
: [channel, ...channelNames];
|
|
53
|
+
const filterBy = (next: string | undefined) =>
|
|
54
|
+
onSearchChange(next === undefined ? {} : { channel: next });
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="flex h-svh min-h-0 flex-col">
|
|
58
|
+
<header className="sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-x-3 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">
|
|
59
|
+
<SidebarTrigger className="-ml-1 size-11 lg:size-7" />
|
|
60
|
+
<div className="flex items-center gap-1.5">
|
|
61
|
+
<HardDrive
|
|
62
|
+
aria-hidden="true"
|
|
63
|
+
className="size-3.5 text-muted-foreground"
|
|
64
|
+
/>
|
|
65
|
+
<h1 className="text-sm font-medium">Native builds</h1>
|
|
66
|
+
</div>
|
|
67
|
+
<p className="basis-full pl-12 text-xs text-muted-foreground sm:basis-auto sm:pl-0">
|
|
68
|
+
Store and test builds, each the built-in bundle its OTAs patch from.
|
|
69
|
+
</p>
|
|
70
|
+
</header>
|
|
71
|
+
|
|
72
|
+
<div className="min-h-0 min-w-0 flex-1 overflow-y-auto bg-muted/5 p-3 sm:p-6">
|
|
73
|
+
<Card className="mx-auto w-full max-w-6xl overflow-hidden shadow-sm">
|
|
74
|
+
<div className="flex items-center gap-2 border-b px-4 py-3">
|
|
75
|
+
<Select
|
|
76
|
+
items={[
|
|
77
|
+
{ label: "All channels", value: ALL_CHANNELS },
|
|
78
|
+
...choices.map((name) => ({
|
|
79
|
+
label: name,
|
|
80
|
+
value: channelValue(name),
|
|
81
|
+
})),
|
|
82
|
+
]}
|
|
83
|
+
onOpenChange={(open) => {
|
|
84
|
+
// A pull request's channel appears while the page is open.
|
|
85
|
+
if (open) void channels.refetch();
|
|
86
|
+
}}
|
|
87
|
+
onValueChange={(value) =>
|
|
88
|
+
filterBy(
|
|
89
|
+
value?.startsWith(CHANNEL_VALUE_PREFIX)
|
|
90
|
+
? value.slice(CHANNEL_VALUE_PREFIX.length)
|
|
91
|
+
: undefined,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
value={
|
|
95
|
+
channel === undefined ? ALL_CHANNELS : channelValue(channel)
|
|
96
|
+
}
|
|
97
|
+
>
|
|
98
|
+
<SelectTrigger
|
|
99
|
+
aria-label="Channel"
|
|
100
|
+
className="h-11 min-w-0 flex-1 text-xs sm:h-8 sm:w-48 sm:flex-none"
|
|
101
|
+
>
|
|
102
|
+
<SelectValue />
|
|
103
|
+
</SelectTrigger>
|
|
104
|
+
<SelectContent>
|
|
105
|
+
<SelectGroup>
|
|
106
|
+
<SelectItem value={ALL_CHANNELS}>All channels</SelectItem>
|
|
107
|
+
{choices.map((name) => (
|
|
108
|
+
<SelectItem
|
|
109
|
+
key={name}
|
|
110
|
+
translate="no"
|
|
111
|
+
value={channelValue(name)}
|
|
112
|
+
>
|
|
113
|
+
{name}
|
|
114
|
+
</SelectItem>
|
|
115
|
+
))}
|
|
116
|
+
</SelectGroup>
|
|
117
|
+
</SelectContent>
|
|
118
|
+
</Select>
|
|
119
|
+
<div className="ml-auto">
|
|
120
|
+
<ImportBuildDialog />
|
|
121
|
+
</div>
|
|
122
|
+
<Button
|
|
123
|
+
aria-label="Refresh native builds"
|
|
124
|
+
className="size-11 sm:size-7"
|
|
125
|
+
disabled={builds.isLoading}
|
|
126
|
+
onClick={() => void builds.refetch()}
|
|
127
|
+
size="icon-sm"
|
|
128
|
+
variant="ghost"
|
|
129
|
+
>
|
|
130
|
+
<RefreshCw aria-hidden="true" />
|
|
131
|
+
</Button>
|
|
132
|
+
</div>
|
|
133
|
+
<CardContent className="p-0">
|
|
134
|
+
<NativeBuildsTable
|
|
135
|
+
builds={builds}
|
|
136
|
+
channel={channel}
|
|
137
|
+
onChannel={filterBy}
|
|
138
|
+
onPage={(page) =>
|
|
139
|
+
onSearchChange({
|
|
140
|
+
...(channel === undefined ? {} : { channel }),
|
|
141
|
+
...page,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
paged={before !== undefined || after !== undefined}
|
|
145
|
+
/>
|
|
146
|
+
</CardContent>
|
|
147
|
+
</Card>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|