@hot-updater/console 1.0.0-rc.2 → 1.0.0-rc.20
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/ConsoleFeatureUnavailable-B9VYGA3N.js +1 -0
- package/.output/public/assets/HashValueDisplay-D880zntR.js +1 -0
- package/.output/public/assets/InsightsInfo-By_sPjTE.js +1 -0
- package/.output/public/assets/InsightsPageHeader-9_kx_LL7.js +1 -0
- package/.output/public/assets/NotFoundPage-Dys8C0cW.js +1 -0
- package/.output/public/assets/api-CtarlV0l.js +1 -0
- package/.output/public/assets/api-keys-DFF_QqtN.js +1 -0
- package/.output/public/assets/api-keys-evfsQ4sN.js +1 -0
- package/.output/public/assets/arrow-left-BP9D-ta_.js +1 -0
- package/.output/public/assets/arrow-up-right-CDP9Tevw.js +1 -0
- package/.output/public/assets/card-DzCPSRsh.js +1 -0
- package/.output/public/assets/console-features-api-yv7rm3DX.js +1 -0
- package/.output/public/assets/dialog-BDvCy_QO.js +1 -0
- package/.output/public/assets/dist-Clb6cQ9l.js +1 -0
- package/.output/public/assets/empty-C5x9mn_s.js +1 -0
- package/.output/public/assets/field-Bou7shoO.js +1 -0
- package/.output/public/assets/index-0eg3l8aC.js +10 -0
- package/.output/public/assets/input-group-DVtWFUUF.js +1 -0
- package/.output/public/assets/insights-2MbdiSNv.js +1 -0
- package/.output/public/assets/insights-C6tmCZHk.js +2 -0
- package/.output/public/assets/insights-CadS_aIA.js +42 -0
- package/.output/public/assets/insights-recovery-rpc-wvdyM4LD.js +1 -0
- package/.output/public/assets/insights-search-KIF7mRtB.js +1 -0
- package/.output/public/assets/insights-usage-rpc-qUkNtrWr.js +1 -0
- package/.output/public/assets/insights_.distribution-BhBs6PNA.js +1 -0
- package/.output/public/assets/insights_.distribution-CItZw3-8.js +1 -0
- package/.output/public/assets/insights_.distribution-CJUH_wAS.js +2 -0
- package/.output/public/assets/installations-CH2H7JQt.js +2 -0
- package/.output/public/assets/installations-DMeMuwsW.js +1 -0
- package/.output/public/assets/installations-DnvxI9Dt.js +1 -0
- package/.output/public/assets/loader-circle-Ca7C9YY1.js +1 -0
- package/.output/public/assets/mutation-x9L28_CD.js +1 -0
- package/.output/public/assets/preload-helper-BN-UkjOE.js +1 -0
- package/.output/public/assets/refresh-cw-CVGqvy8Z.js +1 -0
- package/.output/public/assets/routes-BhK8DuZA.js +1 -0
- package/.output/public/assets/routes-veKtDW39.js +2 -0
- package/.output/public/assets/sidebar-B45aMqRm.js +3 -0
- package/.output/public/assets/styles-Dn0pK1EX.css +2 -0
- package/.output/public/assets/table-CwLnN6KX.js +1 -0
- package/.output/public/assets/useCompositeListItem-CF7vsfcA.js +1 -0
- package/.output/public/assets/useMutation-CN1ygYEr.js +1 -0
- package/.output/public/assets/useOpenInteractionType-AnAMWYIY.js +1 -0
- package/.output/public/assets/valueToPercent-C-t8FT0y.js +1 -0
- package/.output/server/{__23tanstack-start-server-fn-resolver-B7ioJhtE.mjs → __23tanstack-start-server-fn-resolver-CUQLz7hs.mjs} +52 -40
- package/.output/server/_libs/@base-ui/react+[...].mjs +7044 -3622
- package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +1554 -0
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +49 -3
- package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +4 -4
- package/.output/server/_libs/d3-array.mjs +231 -0
- package/.output/server/_libs/d3-color.mjs +330 -0
- package/.output/server/_libs/d3-format.mjs +252 -0
- package/.output/server/_libs/d3-interpolate.mjs +207 -0
- package/.output/server/_libs/d3-path.mjs +77 -0
- package/.output/server/_libs/d3-scale+[...].mjs +1907 -0
- package/.output/server/_libs/d3-shape.mjs +818 -0
- package/.output/server/_libs/decimal.js-light.mjs +884 -0
- package/.output/server/_libs/es-toolkit.mjs +1159 -0
- package/.output/server/_libs/eventemitter3.mjs +236 -0
- package/.output/server/_libs/immer.mjs +532 -0
- package/.output/server/_libs/lucide-react.mjs +46 -32
- package/.output/server/_libs/next-themes.mjs +2 -2
- package/.output/server/_libs/react-redux+[...].mjs +205 -0
- package/.output/server/_libs/recharts+[...].mjs +14350 -0
- package/.output/server/_libs/sonner.mjs +2 -2
- package/.output/server/_libs/tanstack__react-query.mjs +8 -3
- package/.output/server/_libs/verkit.mjs +99 -1
- package/.output/server/_runtime.mjs +10 -1
- package/.output/server/_ssr/ConsoleFeatureUnavailable-DoxET2AT.mjs +58 -0
- package/.output/server/_ssr/{HashValueDisplay-DwpGLfrl.mjs → HashValueDisplay-BplboHEb.mjs} +3 -3
- package/.output/server/_ssr/InsightsInfo-o2YPd5Qc.mjs +37 -0
- package/.output/server/_ssr/InsightsPageHeader-NExCJL1I.mjs +154 -0
- package/.output/server/_ssr/NotFoundPage-Cd-A8ock.mjs +37 -0
- package/.output/server/_ssr/api-B1Ro0uys.mjs +202 -0
- package/.output/server/_ssr/api-C0G9MTMI.mjs +4205 -0
- package/.output/server/_ssr/{api-keys-CZeTPQys.mjs → api-keys-CT3HG7KT.mjs} +49 -9
- package/.output/server/_ssr/api-keys-Dvvy1sem.mjs +5 -0
- package/.output/server/_ssr/api-keys-rpc-b1qTTFfG.mjs +52 -0
- package/.output/server/_ssr/api-rpc-Cbns2MGx.mjs +338 -0
- package/.output/server/_ssr/{auth-rpc-DUaeOWKK.mjs → auth-rpc-DChS7m9y.mjs} +6 -6
- package/.output/server/_ssr/auth.server-Ccqz2iVv.mjs +37 -0
- package/.output/server/_ssr/bundleActivity-D17Pb_h5.mjs +19 -0
- package/.output/server/_ssr/card-DMbcvlPz.mjs +49 -0
- package/.output/server/_ssr/config-DMEJdhoW.mjs +13 -0
- package/.output/server/_ssr/config.server-DyypN6cQ.mjs +60 -0
- package/.output/server/_ssr/console-access-KpPv5lin.mjs +17 -0
- package/.output/server/_ssr/console-features-CsbyHYfK.mjs +55 -0
- package/.output/server/_ssr/console-features-api-B-KVuo4p.mjs +43 -0
- package/.output/server/_ssr/console-features-rpc-Djyo5740.mjs +19 -0
- package/.output/server/_ssr/{createServerFn-B2hcXoPM.mjs → createMiddleware-B_I3Ll4M.mjs} +28 -2
- package/.output/server/_ssr/{createServerRpc-DB29C_5p.mjs → createServerRpc-DuNm5mmo.mjs} +2 -2
- package/.output/server/_ssr/databaseRows-CXxf_VIB.mjs +132 -0
- package/.output/server/_ssr/{deleteBundle-BTGwBgzx.mjs → deleteBundle-Dcc21Lbd.mjs} +9 -19
- package/.output/server/_ssr/{dialog-DS-nw-pA.mjs → dialog-cOmLTUV2.mjs} +2 -2
- package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-B-r4u3Lg.mjs} +28 -5
- package/.output/server/_ssr/{downloadBundle-CNnYxYO2.mjs → downloadBundle-CexOFoZ4.mjs} +6 -7
- package/.output/server/_ssr/empty-BHoY_5jt.mjs +49 -0
- package/.output/server/_ssr/{table-CnZmon_Z.mjs → field-mjhcNEXD.mjs} +63 -51
- package/.output/server/_ssr/getBundleChildren-DbDXe9wB.mjs +22 -0
- package/.output/server/_ssr/{input-group-BpsnmvZw.mjs → input-group-96H30HWC.mjs} +2 -2
- package/.output/server/_ssr/insights-D25VDVaz.mjs +5 -0
- package/.output/server/_ssr/insights-D359GJFL.mjs +14 -0
- package/.output/server/_ssr/insights-DgFv1NsO.mjs +1238 -0
- package/.output/server/_ssr/insights-api-ChAKrbhG.mjs +105 -0
- package/.output/server/_ssr/insights-failures-WQ-ttjOx.mjs +44 -0
- package/.output/server/_ssr/insights-failures-rpc-BFsqlltN.mjs +21 -0
- package/.output/server/_ssr/insights-recovery-DkL6bxMW.mjs +28 -0
- package/.output/server/_ssr/insights-recovery-rpc-2P5m8F62.mjs +46 -0
- package/.output/server/_ssr/insights-recovery-rpc-Tj8vNC19.mjs +20 -0
- package/.output/server/_ssr/{insights-rpc-38DujK0G.mjs → insights-rpc-DrkVmV9o.mjs} +22 -14
- package/.output/server/_ssr/insights-search-BsalnNw-.mjs +25 -0
- package/.output/server/_ssr/insights-usage-1nVTQrLy.mjs +29 -0
- package/.output/server/_ssr/insights-usage-rpc-Ct_4xHhZ.mjs +29 -0
- package/.output/server/_ssr/insights-usage-rpc-DaYIRtFK.mjs +41 -0
- package/.output/server/_ssr/insightsRecovery-CpGucWN1.mjs +45 -0
- package/.output/server/_ssr/insightsUsage-JYpKZAF7.mjs +56 -0
- package/.output/server/_ssr/insights_.distribution-Bcu6uYs_.mjs +5 -0
- package/.output/server/_ssr/insights_.distribution-D3Csuyjw.mjs +14 -0
- package/.output/server/_ssr/insights_.distribution-jQZEF07J.mjs +335 -0
- package/.output/server/_ssr/installations-B8Vh54lH.mjs +69 -0
- package/.output/server/_ssr/installations-BI5kelHv.mjs +5 -0
- package/.output/server/_ssr/{installations-DiVKEF5T.mjs → installations-Cxikllmx.mjs} +517 -54
- package/.output/server/_ssr/listReleases-DqU9t1l3.mjs +79 -0
- package/.output/server/_ssr/releaseManagement-B3e7I8J9.mjs +11 -0
- package/.output/server/_ssr/{router-B9wG_9f8.mjs → router-CRkm-wHD.mjs} +117 -124
- package/.output/server/_ssr/routes-B3IJo_jL.mjs +292 -0
- package/.output/server/_ssr/{routes-D7Yh_jfj.mjs → routes-CNAi0Mmv.mjs} +176 -455
- package/.output/server/_ssr/runtime.server-NucbYjc7.mjs +1372 -0
- package/.output/server/_ssr/select-BkPAJFL7.mjs +107 -0
- package/.output/server/_ssr/{server-D_C2rMzf.mjs → server-DKJYsaCP.mjs} +6 -32
- package/.output/server/_ssr/{createSsrRpc-DjWNJ0uc.mjs → sidebar-Cw1VuC7d.mjs} +117 -63
- package/.output/server/_ssr/ssr.mjs +1 -1
- package/.output/server/_ssr/table-q0P9wz7x.mjs +53 -0
- package/.output/server/_ssr/updateFailures-DMU9f0pK.mjs +24 -0
- package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-BzSO-fr-.mjs} +2 -2
- package/.output/server/_tanstack-start-manifest_v-Bb0gKDbb.mjs +124 -0
- package/.output/server/index.mjs +273 -168
- package/README.md +71 -65
- package/lib/index.d.mts +13 -11
- package/lib/vite-internal.mjs +6 -3
- package/package.json +8 -8
- package/src/components/AppSidebar.tsx +91 -71
- package/src/components/ConsoleAccessPage.tsx +5 -1
- package/src/components/ConsoleFeatureUnavailable.tsx +82 -0
- package/src/components/NotFoundPage.tsx +7 -7
- package/src/components/features/FeatureSlots.tsx +99 -0
- package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
- package/src/components/features/bundles/BundleMetadata.tsx +7 -4
- package/src/components/features/channels/ChannelManagementDialog.tsx +2 -5
- package/src/components/features/insights/AppUsage.tsx +370 -0
- package/src/components/features/insights/EstimatedCount.tsx +18 -0
- package/src/components/features/insights/EventDetails.tsx +117 -37
- package/src/components/features/insights/EventHistoryCard.tsx +112 -26
- package/src/components/features/insights/EventHistoryList.tsx +2 -2
- package/src/components/features/insights/InsightsControls.tsx +265 -102
- package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
- package/src/components/features/insights/InsightsInfo.tsx +48 -0
- package/src/components/features/insights/InsightsOverview.tsx +176 -173
- package/src/components/features/insights/InsightsPageHeader.tsx +35 -20
- package/src/components/features/insights/InsightsPeriodSelector.tsx +89 -0
- package/src/components/features/insights/InstallationHistoryCard.tsx +52 -10
- package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
- package/src/components/features/insights/ReleaseActivity.tsx +188 -0
- package/src/components/features/insights/ReportingDevicesSummary.tsx +65 -0
- package/src/components/features/insights/UpdateFailures.tsx +319 -0
- package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
- package/src/components/features/releases/ReleaseEditorSheet.tsx +24 -1
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/empty.tsx +101 -0
- package/src/components/ui/scroll-area.tsx +52 -0
- package/src/components/ui/sidebar.tsx +22 -29
- package/src/components/ui/tabs.tsx +81 -0
- package/src/index.ts +12 -17
- package/src/lib/api-keys-api.ts +0 -28
- package/src/lib/api-keys-rpc.ts +27 -38
- package/src/lib/api-rpc.ts +197 -221
- package/src/lib/api.ts +11 -13
- package/src/lib/bundle-activity.ts +31 -0
- package/src/lib/console-access.ts +20 -0
- package/src/lib/console-features-api.ts +68 -0
- package/src/lib/console-features-rpc.ts +13 -0
- package/src/lib/console-features.ts +91 -0
- package/src/lib/insights-api.ts +37 -1
- package/src/lib/insights-failures-rpc.ts +21 -0
- package/src/lib/insights-failures.ts +129 -0
- package/src/lib/insights-recovery-rpc.ts +51 -0
- package/src/lib/insights-recovery.ts +68 -0
- package/src/lib/insights-retention.ts +21 -0
- package/src/lib/insights-rpc.ts +30 -12
- package/src/lib/insights-search.ts +58 -0
- package/src/lib/insights-usage-rpc.ts +29 -0
- package/src/lib/insights-usage.ts +74 -0
- package/src/lib/insights-view.ts +38 -2
- package/src/lib/scroll-restoration.ts +21 -0
- package/src/lib/server/adminInsights.ts +124 -0
- package/src/lib/server/auth.server.ts +13 -5
- package/src/lib/server/bundleActivity.ts +37 -0
- package/src/lib/server/config.server.ts +16 -32
- package/src/lib/server/console-feature-apis.ts +59 -0
- package/src/lib/server/console-runtime.server.ts +6 -40
- package/src/lib/server/deleteBundle.ts +16 -25
- package/src/lib/server/downloadBundle.ts +7 -10
- package/src/lib/server/getBundleChildren.ts +31 -122
- package/src/lib/server/insightsRecovery.ts +55 -0
- package/src/lib/server/insightsUsage.ts +63 -0
- package/src/lib/server/listReleases.ts +109 -44
- package/src/lib/server/releaseReachability.ts +4 -3
- package/src/lib/server/runtime.server.ts +132 -31
- package/src/lib/server/updateFailures.ts +31 -0
- package/src/routeTree.gen.ts +21 -21
- package/src/router.tsx +3 -2
- package/src/routes/-installations-search.ts +32 -8
- package/src/routes/-releases-search.ts +76 -29
- package/src/routes/__root.tsx +10 -4
- package/src/routes/api/bundles/$bundleId/download.ts +2 -5
- package/src/routes/api-keys.tsx +5 -2
- package/src/routes/index.tsx +167 -104
- package/src/routes/insights.tsx +100 -59
- package/src/routes/insights_.distribution.tsx +398 -0
- package/src/routes/installations.tsx +98 -41
- package/src/vite-internal.ts +6 -3
- package/.output/public/assets/HashValueDisplay-CB0Eskit.js +0 -1
- package/.output/public/assets/InsightsPageHeader-Car5LNiZ.js +0 -1
- package/.output/public/assets/api-keys-BzKocqRy.js +0 -1
- package/.output/public/assets/api-keys-api-BHcODB7q.js +0 -1
- package/.output/public/assets/card-Dhr_eFYj.js +0 -1
- package/.output/public/assets/chart-no-axes-combined-Dy4WJv2U.js +0 -1
- package/.output/public/assets/composite-Bp98A0Ld.js +0 -1
- package/.output/public/assets/createServerFn-CA8fs7QD.js +0 -3
- package/.output/public/assets/dialog-CUTrcPlB.js +0 -1
- package/.output/public/assets/dist-C_NydL0e.js +0 -1
- package/.output/public/assets/index-DdAz-CXv.js +0 -10
- package/.output/public/assets/input-group-cSOG4wh_.js +0 -1
- package/.output/public/assets/insights-C0PBSZ-n.js +0 -1
- package/.output/public/assets/installations-CE33wgbY.js +0 -2
- package/.output/public/assets/installations-CStZja8x.js +0 -1
- package/.output/public/assets/lazyRouteComponent-Ccp3bwBY.js +0 -1
- package/.output/public/assets/link-CI8idAUi.js +0 -1
- package/.output/public/assets/loader-circle-BoxLrsOu.js +0 -1
- package/.output/public/assets/preload-helper-CQ36nxok.js +0 -1
- package/.output/public/assets/refresh-cw-Bqc72UZG.js +0 -1
- package/.output/public/assets/routes-DGVXdzpw.js +0 -2
- package/.output/public/assets/routes-DTlwOr8I.js +0 -1
- package/.output/public/assets/shield-check-uK3MHWJZ.js +0 -1
- package/.output/public/assets/signing-CMf4aqDO.js +0 -1
- package/.output/public/assets/styles-BCvbtKsm.css +0 -2
- package/.output/public/assets/table-2vcV89QB.js +0 -1
- package/.output/public/assets/useCompositeListItem-CHLITE_4.js +0 -1
- package/.output/public/assets/x-DCd0j8c6.js +0 -1
- package/.output/server/_ssr/InsightsPageHeader-Df4Brj8u.mjs +0 -484
- package/.output/server/_ssr/api-keys-api-BUPQVSpk.mjs +0 -60
- package/.output/server/_ssr/api-keys-rpc-Cs7tS5_j.mjs +0 -136
- package/.output/server/_ssr/api-rpc-tAupfGQm.mjs +0 -1399
- package/.output/server/_ssr/auth.server-DW71WzsD.mjs +0 -47
- package/.output/server/_ssr/bundle-signing-rpc-BhnBw0-d.mjs +0 -16
- package/.output/server/_ssr/bundle-signing.server-C4NW5mWx.mjs +0 -12
- package/.output/server/_ssr/card-BRiPmi0C.mjs +0 -108
- package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
- package/.output/server/_ssr/config.server-afDuAwaG.mjs +0 -368
- package/.output/server/_ssr/databaseJsonValue-d6I3nAS4.mjs +0 -45
- package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
- package/.output/server/_ssr/getBundleChildren-C0vh4ZvE.mjs +0 -50
- package/.output/server/_ssr/insights-BdS364Xu.mjs +0 -460
- package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +0 -303
- package/.output/server/_ssr/installations-CtA59MQG.mjs +0 -29
- package/.output/server/_ssr/routes-CKrrS2q2.mjs +0 -37
- package/.output/server/_ssr/runtime.server-DacU1TBV.mjs +0 -438
- package/.output/server/_ssr/signing-Dz1WkZOf.mjs +0 -133
- package/.output/server/_tanstack-start-manifest_v-2MjTyxil.mjs +0 -97
- package/src/components/features/insights/InsightsBundleReports.tsx +0 -51
- package/src/components/features/signing/BundleSigningPage.tsx +0 -139
- package/src/lib/bundle-signing-api.ts +0 -14
- package/src/lib/bundle-signing-rpc.ts +0 -16
- package/src/lib/server/bundle-signing.server.ts +0 -23
- package/src/routes/signing.tsx +0 -37
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readUpdateFailuresInput,
|
|
3
|
+
type UpdateFailuresInput,
|
|
4
|
+
type UpdateFailuresReport,
|
|
5
|
+
} from "../insights-failures";
|
|
6
|
+
import { insightsPeriodEnd, recoveryWindows } from "../insights-recovery";
|
|
7
|
+
import type { ConsoleInsightsReads } from "./adminInsights";
|
|
8
|
+
|
|
9
|
+
/** A release's or a channel's update failures over a period that ends with the current hour. */
|
|
10
|
+
export async function getUpdateFailuresReport(
|
|
11
|
+
reads: Pick<ConsoleInsightsReads, "getUpdateFailures">,
|
|
12
|
+
input: UpdateFailuresInput,
|
|
13
|
+
now = Date.now(),
|
|
14
|
+
): Promise<UpdateFailuresReport> {
|
|
15
|
+
readUpdateFailuresInput(input);
|
|
16
|
+
const end = insightsPeriodEnd(now);
|
|
17
|
+
const timeRange =
|
|
18
|
+
input.window === undefined
|
|
19
|
+
? undefined
|
|
20
|
+
: {
|
|
21
|
+
start: Math.max(0, end - recoveryWindows[input.window].durationMs),
|
|
22
|
+
end,
|
|
23
|
+
};
|
|
24
|
+
const failures = await reads.getUpdateFailures({
|
|
25
|
+
platform: input.platform,
|
|
26
|
+
channel: input.channel,
|
|
27
|
+
...(input.releaseId === undefined ? {} : { releaseId: input.releaseId }),
|
|
28
|
+
...(timeRange === undefined ? {} : { timeRange }),
|
|
29
|
+
});
|
|
30
|
+
return { ...failures, startMs: timeRange?.start ?? null, endMs: end };
|
|
31
|
+
}
|
package/src/routeTree.gen.ts
CHANGED
|
@@ -9,19 +9,14 @@
|
|
|
9
9
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
10
10
|
|
|
11
11
|
import { Route as rootRouteImport } from './routes/__root'
|
|
12
|
-
import { Route as SigningRouteImport } from './routes/signing'
|
|
13
12
|
import { Route as InstallationsRouteImport } from './routes/installations'
|
|
14
13
|
import { Route as InsightsRouteImport } from './routes/insights'
|
|
15
14
|
import { Route as ApiKeysRouteImport } from './routes/api-keys'
|
|
16
15
|
import { Route as IndexRouteImport } from './routes/index'
|
|
16
|
+
import { Route as InsightsDistributionRouteImport } from './routes/insights_.distribution'
|
|
17
17
|
import { Route as ApiAuthSplatRouteImport } from './routes/api/auth/$'
|
|
18
18
|
import { Route as ApiBundlesBundleIdDownloadRouteImport } from './routes/api/bundles/$bundleId/download'
|
|
19
19
|
|
|
20
|
-
const SigningRoute = SigningRouteImport.update({
|
|
21
|
-
id: '/signing',
|
|
22
|
-
path: '/signing',
|
|
23
|
-
getParentRoute: () => rootRouteImport,
|
|
24
|
-
} as any)
|
|
25
20
|
const InstallationsRoute = InstallationsRouteImport.update({
|
|
26
21
|
id: '/installations',
|
|
27
22
|
path: '/installations',
|
|
@@ -42,6 +37,11 @@ const IndexRoute = IndexRouteImport.update({
|
|
|
42
37
|
path: '/',
|
|
43
38
|
getParentRoute: () => rootRouteImport,
|
|
44
39
|
} as any)
|
|
40
|
+
const InsightsDistributionRoute = InsightsDistributionRouteImport.update({
|
|
41
|
+
id: '/insights_/distribution',
|
|
42
|
+
path: '/insights/distribution',
|
|
43
|
+
getParentRoute: () => rootRouteImport,
|
|
44
|
+
} as any)
|
|
45
45
|
const ApiAuthSplatRoute = ApiAuthSplatRouteImport.update({
|
|
46
46
|
id: '/api/auth/$',
|
|
47
47
|
path: '/api/auth/$',
|
|
@@ -59,7 +59,7 @@ export interface FileRoutesByFullPath {
|
|
|
59
59
|
'/api-keys': typeof ApiKeysRoute
|
|
60
60
|
'/insights': typeof InsightsRoute
|
|
61
61
|
'/installations': typeof InstallationsRoute
|
|
62
|
-
'/
|
|
62
|
+
'/insights/distribution': typeof InsightsDistributionRoute
|
|
63
63
|
'/api/auth/$': typeof ApiAuthSplatRoute
|
|
64
64
|
'/api/bundles/$bundleId/download': typeof ApiBundlesBundleIdDownloadRoute
|
|
65
65
|
}
|
|
@@ -68,7 +68,7 @@ export interface FileRoutesByTo {
|
|
|
68
68
|
'/api-keys': typeof ApiKeysRoute
|
|
69
69
|
'/insights': typeof InsightsRoute
|
|
70
70
|
'/installations': typeof InstallationsRoute
|
|
71
|
-
'/
|
|
71
|
+
'/insights/distribution': typeof InsightsDistributionRoute
|
|
72
72
|
'/api/auth/$': typeof ApiAuthSplatRoute
|
|
73
73
|
'/api/bundles/$bundleId/download': typeof ApiBundlesBundleIdDownloadRoute
|
|
74
74
|
}
|
|
@@ -78,7 +78,7 @@ export interface FileRoutesById {
|
|
|
78
78
|
'/api-keys': typeof ApiKeysRoute
|
|
79
79
|
'/insights': typeof InsightsRoute
|
|
80
80
|
'/installations': typeof InstallationsRoute
|
|
81
|
-
'/
|
|
81
|
+
'/insights_/distribution': typeof InsightsDistributionRoute
|
|
82
82
|
'/api/auth/$': typeof ApiAuthSplatRoute
|
|
83
83
|
'/api/bundles/$bundleId/download': typeof ApiBundlesBundleIdDownloadRoute
|
|
84
84
|
}
|
|
@@ -89,7 +89,7 @@ export interface FileRouteTypes {
|
|
|
89
89
|
| '/api-keys'
|
|
90
90
|
| '/insights'
|
|
91
91
|
| '/installations'
|
|
92
|
-
| '/
|
|
92
|
+
| '/insights/distribution'
|
|
93
93
|
| '/api/auth/$'
|
|
94
94
|
| '/api/bundles/$bundleId/download'
|
|
95
95
|
fileRoutesByTo: FileRoutesByTo
|
|
@@ -98,7 +98,7 @@ export interface FileRouteTypes {
|
|
|
98
98
|
| '/api-keys'
|
|
99
99
|
| '/insights'
|
|
100
100
|
| '/installations'
|
|
101
|
-
| '/
|
|
101
|
+
| '/insights/distribution'
|
|
102
102
|
| '/api/auth/$'
|
|
103
103
|
| '/api/bundles/$bundleId/download'
|
|
104
104
|
id:
|
|
@@ -107,7 +107,7 @@ export interface FileRouteTypes {
|
|
|
107
107
|
| '/api-keys'
|
|
108
108
|
| '/insights'
|
|
109
109
|
| '/installations'
|
|
110
|
-
| '/
|
|
110
|
+
| '/insights_/distribution'
|
|
111
111
|
| '/api/auth/$'
|
|
112
112
|
| '/api/bundles/$bundleId/download'
|
|
113
113
|
fileRoutesById: FileRoutesById
|
|
@@ -117,20 +117,13 @@ export interface RootRouteChildren {
|
|
|
117
117
|
ApiKeysRoute: typeof ApiKeysRoute
|
|
118
118
|
InsightsRoute: typeof InsightsRoute
|
|
119
119
|
InstallationsRoute: typeof InstallationsRoute
|
|
120
|
-
|
|
120
|
+
InsightsDistributionRoute: typeof InsightsDistributionRoute
|
|
121
121
|
ApiAuthSplatRoute: typeof ApiAuthSplatRoute
|
|
122
122
|
ApiBundlesBundleIdDownloadRoute: typeof ApiBundlesBundleIdDownloadRoute
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
declare module '@tanstack/react-router' {
|
|
126
126
|
interface FileRoutesByPath {
|
|
127
|
-
'/signing': {
|
|
128
|
-
id: '/signing'
|
|
129
|
-
path: '/signing'
|
|
130
|
-
fullPath: '/signing'
|
|
131
|
-
preLoaderRoute: typeof SigningRouteImport
|
|
132
|
-
parentRoute: typeof rootRouteImport
|
|
133
|
-
}
|
|
134
127
|
'/installations': {
|
|
135
128
|
id: '/installations'
|
|
136
129
|
path: '/installations'
|
|
@@ -159,6 +152,13 @@ declare module '@tanstack/react-router' {
|
|
|
159
152
|
preLoaderRoute: typeof IndexRouteImport
|
|
160
153
|
parentRoute: typeof rootRouteImport
|
|
161
154
|
}
|
|
155
|
+
'/insights_/distribution': {
|
|
156
|
+
id: '/insights_/distribution'
|
|
157
|
+
path: '/insights/distribution'
|
|
158
|
+
fullPath: '/insights/distribution'
|
|
159
|
+
preLoaderRoute: typeof InsightsDistributionRouteImport
|
|
160
|
+
parentRoute: typeof rootRouteImport
|
|
161
|
+
}
|
|
162
162
|
'/api/auth/$': {
|
|
163
163
|
id: '/api/auth/$'
|
|
164
164
|
path: '/api/auth/$'
|
|
@@ -181,7 +181,7 @@ const rootRouteChildren: RootRouteChildren = {
|
|
|
181
181
|
ApiKeysRoute: ApiKeysRoute,
|
|
182
182
|
InsightsRoute: InsightsRoute,
|
|
183
183
|
InstallationsRoute: InstallationsRoute,
|
|
184
|
-
|
|
184
|
+
InsightsDistributionRoute: InsightsDistributionRoute,
|
|
185
185
|
ApiAuthSplatRoute: ApiAuthSplatRoute,
|
|
186
186
|
ApiBundlesBundleIdDownloadRoute: ApiBundlesBundleIdDownloadRoute,
|
|
187
187
|
}
|
package/src/router.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query
|
|
|
4
4
|
// Import the route tree selected by the local or hosted Vite integration.
|
|
5
5
|
import { routeTree } from "virtual:hot-updater-console/route-tree";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { routeScrollRestorationKey } from "./lib/scroll-restoration";
|
|
8
8
|
|
|
9
9
|
// Create a new router instance
|
|
10
10
|
export const getRouter = () => {
|
|
@@ -14,7 +14,8 @@ export const getRouter = () => {
|
|
|
14
14
|
context: { queryClient },
|
|
15
15
|
|
|
16
16
|
scrollRestoration: true,
|
|
17
|
-
getScrollRestorationKey:
|
|
17
|
+
getScrollRestorationKey: (location): string =>
|
|
18
|
+
routeScrollRestorationKey(router, location),
|
|
18
19
|
defaultPreloadStaleTime: 0,
|
|
19
20
|
});
|
|
20
21
|
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import type { ParsedLocation } from "@tanstack/react-router";
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_EVENT_RANGE,
|
|
5
|
+
EVENT_RANGES,
|
|
6
|
+
type EventRange,
|
|
7
|
+
} from "../lib/insights-view";
|
|
8
|
+
|
|
9
|
+
export type InsightsPaginationState = {
|
|
10
|
+
readonly eventsBack?: readonly string[];
|
|
11
|
+
readonly searchBack?: readonly string[];
|
|
12
|
+
readonly historyBack?: readonly string[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
declare module "@tanstack/react-router" {
|
|
16
|
+
interface HistoryState {
|
|
17
|
+
insightsPagination?: InsightsPaginationState;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
3
21
|
const readCursor = (value: unknown): string | undefined =>
|
|
4
22
|
typeof value === "string" && value.length > 0 ? value : undefined;
|
|
5
23
|
|
|
@@ -8,14 +26,19 @@ const readTimestamp = (value: unknown): number | undefined =>
|
|
|
8
26
|
? value
|
|
9
27
|
: undefined;
|
|
10
28
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
const readEventRange = (value: unknown): EventRange | undefined =>
|
|
30
|
+
EVENT_RANGES.find((range) => range === value);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The installations route's scroll-restoration key: every visit to one page
|
|
34
|
+
* of the event list shares its scroll position, and a lookup keeps its own
|
|
35
|
+
* for each history entry.
|
|
36
|
+
*/
|
|
37
|
+
export function installationsScrollRestorationKey(location: ParsedLocation) {
|
|
38
|
+
const search = validateInstallationsSearch(location.search);
|
|
39
|
+
return search.query === undefined && search.installId === undefined
|
|
40
|
+
? `/installations?eventsBefore=${search.eventsBefore ?? "new"}&eventsRange=${search.eventsRange ?? DEFAULT_EVENT_RANGE}&eventsCursor=${search.eventsCursor ?? "first"}`
|
|
41
|
+
: location.state.__TSR_key!;
|
|
19
42
|
}
|
|
20
43
|
|
|
21
44
|
export function validateInstallationsSearch(search: Record<string, unknown>) {
|
|
@@ -25,6 +48,7 @@ export function validateInstallationsSearch(search: Record<string, unknown>) {
|
|
|
25
48
|
typeof search.installId === "string" ? search.installId : undefined,
|
|
26
49
|
eventsCursor: readCursor(search.eventsCursor),
|
|
27
50
|
eventsBefore: readTimestamp(search.eventsBefore),
|
|
51
|
+
eventsRange: readEventRange(search.eventsRange),
|
|
28
52
|
searchCursor: readCursor(search.searchCursor),
|
|
29
53
|
historyCursor: readCursor(search.historyCursor),
|
|
30
54
|
historyBefore: readTimestamp(search.historyBefore),
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import type { ReleaseFilter } from "@hot-updater/plugin-core";
|
|
2
|
+
|
|
1
3
|
export interface ReleaseSearch {
|
|
4
|
+
/** Releases newer than this id: the previous page. */
|
|
2
5
|
afterReleaseId?: string;
|
|
6
|
+
/** Releases older than this id: the next page. */
|
|
3
7
|
beforeReleaseId?: string;
|
|
4
8
|
bundleId?: string;
|
|
5
9
|
channelId?: string;
|
|
6
10
|
enabled?: boolean;
|
|
7
|
-
page?: number;
|
|
8
11
|
platform?: "ios" | "android";
|
|
9
12
|
releaseId?: string;
|
|
10
|
-
|
|
13
|
+
/** One catalog scope: a channel, platform, and target kind. */
|
|
14
|
+
scopeKey?: string;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
const optionalString = (value: unknown) =>
|
|
@@ -15,15 +19,14 @@ const optionalString = (value: unknown) =>
|
|
|
15
19
|
? value.trim()
|
|
16
20
|
: undefined;
|
|
17
21
|
|
|
22
|
+
/**
|
|
23
|
+
* The search a URL holds, reduced to one of the filter sets the release
|
|
24
|
+
* indexes serve: a bundle, a scope (with enabled), or a channel with its
|
|
25
|
+
* platform (with enabled). A channel without a platform lists iOS.
|
|
26
|
+
*/
|
|
18
27
|
export function validateReleaseSearch(
|
|
19
28
|
search: Record<string, unknown>,
|
|
20
29
|
): ReleaseSearch {
|
|
21
|
-
const parsedPage =
|
|
22
|
-
typeof search.page === "number"
|
|
23
|
-
? search.page
|
|
24
|
-
: typeof search.page === "string"
|
|
25
|
-
? Number(search.page)
|
|
26
|
-
: undefined;
|
|
27
30
|
const beforeReleaseId = optionalString(search.beforeReleaseId);
|
|
28
31
|
const afterReleaseId = beforeReleaseId
|
|
29
32
|
? undefined
|
|
@@ -34,41 +37,85 @@ export function validateReleaseSearch(
|
|
|
34
37
|
: search.enabled === false || search.enabled === "false"
|
|
35
38
|
? false
|
|
36
39
|
: undefined;
|
|
40
|
+
const bundleId = optionalString(search.bundleId);
|
|
41
|
+
const scopeKey = bundleId ? undefined : optionalString(search.scopeKey);
|
|
42
|
+
const channelId =
|
|
43
|
+
bundleId || scopeKey ? undefined : optionalString(search.channelId);
|
|
44
|
+
const platform =
|
|
45
|
+
channelId === undefined
|
|
46
|
+
? undefined
|
|
47
|
+
: search.platform === "android"
|
|
48
|
+
? "android"
|
|
49
|
+
: "ios";
|
|
37
50
|
|
|
38
51
|
return {
|
|
39
52
|
afterReleaseId,
|
|
40
53
|
beforeReleaseId,
|
|
41
|
-
bundleId
|
|
42
|
-
channelId
|
|
43
|
-
enabled,
|
|
44
|
-
|
|
45
|
-
parsedPage !== undefined && Number.isInteger(parsedPage) && parsedPage > 1
|
|
46
|
-
? parsedPage
|
|
47
|
-
: undefined,
|
|
48
|
-
platform:
|
|
49
|
-
search.platform === "ios" || search.platform === "android"
|
|
50
|
-
? search.platform
|
|
51
|
-
: undefined,
|
|
54
|
+
bundleId,
|
|
55
|
+
channelId,
|
|
56
|
+
enabled: scopeKey || channelId ? enabled : undefined,
|
|
57
|
+
platform,
|
|
52
58
|
releaseId: optionalString(search.releaseId),
|
|
53
|
-
|
|
59
|
+
scopeKey,
|
|
54
60
|
};
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
export function releaseFilterOf(search: ReleaseSearch): ReleaseFilter {
|
|
64
|
+
const enabled =
|
|
65
|
+
search.enabled === undefined ? {} : { enabled: search.enabled };
|
|
66
|
+
if (search.bundleId) return { kind: "bundle", bundleId: search.bundleId };
|
|
67
|
+
if (search.scopeKey) {
|
|
68
|
+
return { kind: "scope", scopeKey: search.scopeKey, ...enabled };
|
|
69
|
+
}
|
|
70
|
+
if (search.channelId && search.platform) {
|
|
71
|
+
return {
|
|
72
|
+
kind: "channelPlatform",
|
|
73
|
+
channelId: search.channelId,
|
|
74
|
+
platform: search.platform,
|
|
75
|
+
...enabled,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { kind: "all" };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function hasReleaseFilters(search: ReleaseSearch): boolean {
|
|
82
|
+
return releaseFilterOf(search).kind !== "all";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A new filter starts from the first page. A bundle or scope filter replaces
|
|
87
|
+
* the others, and choosing a channel or platform clears them.
|
|
88
|
+
*/
|
|
57
89
|
export function updateReleaseFilters(
|
|
58
90
|
current: ReleaseSearch,
|
|
59
91
|
filters: Partial<
|
|
60
92
|
Pick<
|
|
61
93
|
ReleaseSearch,
|
|
62
|
-
"bundleId" | "channelId" | "enabled" | "platform" | "
|
|
94
|
+
"bundleId" | "channelId" | "enabled" | "platform" | "scopeKey"
|
|
63
95
|
>
|
|
64
96
|
>,
|
|
65
97
|
): ReleaseSearch {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
const next = { ...current, ...filters };
|
|
99
|
+
if (filters.bundleId)
|
|
100
|
+
return validateReleaseSearch({ bundleId: next.bundleId });
|
|
101
|
+
if (filters.scopeKey) {
|
|
102
|
+
return validateReleaseSearch({
|
|
103
|
+
scopeKey: next.scopeKey,
|
|
104
|
+
enabled: next.enabled,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if ("channelId" in filters || "platform" in filters) {
|
|
108
|
+
return validateReleaseSearch({
|
|
109
|
+
channelId: next.channelId,
|
|
110
|
+
enabled: next.enabled,
|
|
111
|
+
platform: next.platform,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return validateReleaseSearch({
|
|
115
|
+
bundleId: next.bundleId,
|
|
116
|
+
channelId: next.channelId,
|
|
117
|
+
enabled: next.enabled,
|
|
118
|
+
platform: next.platform,
|
|
119
|
+
scopeKey: next.scopeKey,
|
|
120
|
+
});
|
|
74
121
|
}
|
package/src/routes/__root.tsx
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
getConsoleAccessRpc,
|
|
19
19
|
getConsoleAuthProvidersRpc,
|
|
20
20
|
} from "@/lib/auth-rpc";
|
|
21
|
+
import { consoleFeaturesQueryOptions } from "@/lib/console-features-api";
|
|
21
22
|
|
|
22
23
|
import appCss from "../styles.css?url";
|
|
23
24
|
|
|
@@ -60,11 +61,16 @@ export const Route = createRootRouteWithContext<{
|
|
|
60
61
|
],
|
|
61
62
|
}),
|
|
62
63
|
|
|
63
|
-
loader: async () => {
|
|
64
|
+
loader: async ({ context }) => {
|
|
64
65
|
const [access, providers] = await Promise.all([
|
|
65
66
|
getConsoleAccessRpc(),
|
|
66
67
|
getConsoleAuthProvidersRpc(),
|
|
67
68
|
]);
|
|
69
|
+
// The authorized layout's navigation shows only the features on, so they
|
|
70
|
+
// load with it; the query keeps them for the visit.
|
|
71
|
+
if (access.status === "authorized") {
|
|
72
|
+
await context.queryClient.prefetchQuery(consoleFeaturesQueryOptions());
|
|
73
|
+
}
|
|
68
74
|
return { access, providers };
|
|
69
75
|
},
|
|
70
76
|
|
|
@@ -140,10 +146,10 @@ function RootLayout() {
|
|
|
140
146
|
return <ConsoleAccessPage access={access} providers={providers} />;
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
return <AuthorizedConsole />;
|
|
149
|
+
return <AuthorizedConsole canSignOut={providers.length > 0} />;
|
|
144
150
|
}
|
|
145
151
|
|
|
146
|
-
function AuthorizedConsole() {
|
|
152
|
+
function AuthorizedConsole({ canSignOut }: { canSignOut: boolean }) {
|
|
147
153
|
useEffect(() => {
|
|
148
154
|
if (
|
|
149
155
|
import.meta.env.DEV &&
|
|
@@ -155,7 +161,7 @@ function AuthorizedConsole() {
|
|
|
155
161
|
}, []);
|
|
156
162
|
return (
|
|
157
163
|
<SidebarProvider>
|
|
158
|
-
<AppSidebar />
|
|
164
|
+
<AppSidebar canSignOut={canSignOut} />
|
|
159
165
|
<SidebarInset className="min-h-0 min-w-0 overflow-hidden">
|
|
160
166
|
<Outlet />
|
|
161
167
|
</SidebarInset>
|
|
@@ -6,11 +6,8 @@ export const Route = createFileRoute("/api/bundles/$bundleId/download")({
|
|
|
6
6
|
GET: async ({ params, request }) => {
|
|
7
7
|
const { prepareConfig } = await import("@/lib/server/config.server");
|
|
8
8
|
const { downloadBundle } = await import("@/lib/server/downloadBundle");
|
|
9
|
-
const {
|
|
10
|
-
return downloadBundle(params.bundleId, {
|
|
11
|
-
databaseClient,
|
|
12
|
-
storagePlugin,
|
|
13
|
-
});
|
|
9
|
+
const { core, storagePlugin } = await prepareConfig(request);
|
|
10
|
+
return downloadBundle(params.bundleId, { core, storagePlugin });
|
|
14
11
|
},
|
|
15
12
|
},
|
|
16
13
|
},
|
package/src/routes/api-keys.tsx
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { KeyRound } from "lucide-react";
|
|
3
3
|
|
|
4
|
+
import { ConsoleFeatureUnavailable } from "@/components/ConsoleFeatureUnavailable";
|
|
4
5
|
import { ApiKeysPage } from "@/components/features/api-keys/ApiKeysPage";
|
|
5
6
|
import { SidebarTrigger } from "@/components/ui/sidebar";
|
|
6
|
-
import {
|
|
7
|
+
import { requireConsoleFeature } from "@/lib/console-features-api";
|
|
7
8
|
|
|
8
9
|
export const Route = createFileRoute("/api-keys")({
|
|
9
|
-
beforeLoad: ({ context }) =>
|
|
10
|
+
beforeLoad: ({ context }) =>
|
|
11
|
+
requireConsoleFeature(context.queryClient, "apiKeys"),
|
|
12
|
+
notFoundComponent: ConsoleFeatureUnavailable,
|
|
10
13
|
component: ApiKeysRoute,
|
|
11
14
|
});
|
|
12
15
|
|