@hot-updater/console 0.36.6 → 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/AnalyticsCapabilityContext-BCke57-7.js +1 -0
- package/.output/public/assets/BundleActivityChart-CnsBe_1J.js +42 -0
- package/.output/public/assets/BundleIdDisplay-Dky75zLU.js +1 -0
- package/.output/public/assets/alert-C-1KvDW8.js +1 -0
- package/.output/public/assets/analytics-Bqz0c-BT.js +1 -0
- package/.output/public/assets/analytics-api-CJdrTLLO.js +1 -0
- package/.output/public/assets/api-B_Rh-uzC.js +1 -0
- package/.output/public/assets/api-keys-BurCFhzH.js +1 -0
- package/.output/public/assets/api-keys-api-BEDJdQg3.js +1 -0
- package/.output/public/assets/badge-Bf0fZ-Gx.js +1 -0
- package/.output/public/assets/chart-no-axes-combined-FaYMGmQS.js +1 -0
- package/.output/public/assets/createServerFn-gM2-LFBy.js +3 -0
- package/.output/public/assets/dialog-BS60BRr2.js +1 -0
- package/.output/public/assets/dist-DspNKfMj.js +1 -0
- package/.output/public/assets/download-O-yNBc9H.js +1 -0
- package/.output/public/assets/field-Buq148-A.js +1 -0
- package/.output/public/assets/index-kFhd2S78.js +10 -0
- package/.output/public/assets/installations-BrQ-od41.js +2 -0
- package/.output/public/assets/installations-CGlZ3ROz.js +1 -0
- package/.output/public/assets/lazyRouteComponent-rPzgA7S-.js +1 -0
- package/.output/public/assets/loader-circle-DCYF-wJl.js +1 -0
- package/.output/public/assets/preload-helper-TKOBYGYD.js +1 -0
- package/.output/public/assets/refresh-cw-n8XYbPPj.js +1 -0
- package/.output/public/assets/routes-CrdokJ80.js +1 -0
- package/.output/public/assets/routes-DcQnVajO.js +2 -0
- package/.output/public/assets/search-DLhbWw3W.js +1 -0
- package/.output/public/assets/shield-check-DE_hVuHu.js +1 -0
- package/.output/public/assets/signing-HRexfjsH.js +1 -0
- package/.output/public/assets/styles-eB4EtvFS.css +2 -0
- package/.output/public/assets/table-D8CLieHX.js +1 -0
- package/.output/public/assets/textarea-YJLTVAoq.js +1 -0
- package/.output/public/assets/useMutation-JsGVjQMY.js +1 -0
- package/.output/public/assets/useOpenInteractionType-4cRD5xO0.js +1 -0
- package/.output/server/__23tanstack-start-server-fn-resolver-DBP9TQ7K.mjs +146 -0
- package/.output/server/_libs/@base-ui/react+[...].mjs +16124 -0
- package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +1554 -0
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +41 -10
- package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +132 -0
- 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 +1134 -0
- package/.output/server/_libs/eventemitter3.mjs +236 -0
- package/.output/server/_libs/immer.mjs +532 -0
- package/.output/server/_libs/lucide-react.mjs +141 -13
- package/.output/server/_libs/next-themes.mjs +2 -2
- package/.output/server/_libs/react-redux+[...].mjs +205 -0
- package/.output/server/_libs/recharts+[...].mjs +14117 -0
- package/.output/server/_libs/sonner.mjs +2 -2
- package/.output/server/_libs/tanstack__query-core.mjs +114 -1
- package/.output/server/_libs/tanstack__react-query.mjs +3 -4
- package/.output/server/_runtime.mjs +10 -1
- package/.output/server/_ssr/AnalyticsCapabilityContext-ui4DX8GO.mjs +15 -0
- package/.output/server/_ssr/BundleActivityChart-BiB9ZORH.mjs +288 -0
- package/.output/server/_ssr/BundleIdDisplay-Czk6iR6p.mjs +13 -0
- package/.output/server/_ssr/alert-Dim3MGY5.mjs +86 -0
- package/.output/server/_ssr/analytics-DtMTn8fn.mjs +858 -0
- package/.output/server/_ssr/analytics-api-Cg1M5v_H.mjs +71 -0
- package/.output/server/_ssr/analytics-input-fRRRn0uA.mjs +96 -0
- package/.output/server/_ssr/analytics-rpc-DY5uXvHT.mjs +155 -0
- package/.output/server/_ssr/api-BTSv1tZb.mjs +282 -0
- package/.output/server/_ssr/api-keys-BnM_o2nS.mjs +300 -0
- package/.output/server/_ssr/api-keys-api-CIywsSF5.mjs +60 -0
- package/.output/server/_ssr/api-keys-rpc-BSp1wkIV.mjs +136 -0
- package/.output/server/_ssr/api-rpc-cG5wd_tO.mjs +1468 -0
- package/.output/server/_ssr/auth-BF8mbAgF.mjs +21 -0
- package/.output/server/_ssr/auth-rpc-BrJ6obHJ.mjs +24 -0
- package/.output/server/_ssr/auth.server-DwKoZoQM.mjs +50 -0
- package/.output/server/_ssr/badge-DCxbEeof.mjs +26 -0
- package/.output/server/_ssr/bundle-signing-rpc-COoQhW8E.mjs +16 -0
- package/.output/server/_ssr/bundle-signing.server-D5u8KkMp.mjs +51 -0
- package/.output/server/_ssr/config-Dv8qLDZ0.mjs +13 -0
- package/.output/server/_ssr/config.server-DEiLhKmy.mjs +361 -0
- package/.output/server/_ssr/{createServerFn-DzU0k62V.mjs → createServerFn-B2hcXoPM.mjs} +1 -1
- package/.output/server/_ssr/createServerRpc-DB29C_5p.mjs +12 -0
- package/.output/server/_ssr/{sidebar-Cv_H0_Jv.mjs → createSsrRpc-9P0S0lJ3.mjs} +68 -50
- package/.output/server/_ssr/databaseRows-CwbNwYSl.mjs +166 -0
- package/.output/server/_ssr/deleteBundle-Cu_XOMt0.mjs +66 -0
- package/.output/server/_ssr/dialog-CQuRMNZ4.mjs +170 -0
- package/.output/server/_ssr/dist-BVSLTpoP.mjs +250 -0
- package/.output/server/_ssr/downloadBundle-CNnYxYO2.mjs +24 -0
- package/.output/server/_ssr/{empty-plugin-adapters-B4HCzgmM.mjs → empty-plugin-adapters-B5QvGpEl.mjs} +1 -1
- package/.output/server/_ssr/field-DRIXKjZG.mjs +74 -0
- package/.output/server/_ssr/{getBundleChildren-CVtSiH5t.mjs → getBundleChildren-BcRMFoDF.mjs} +10 -18
- package/.output/server/_ssr/installations-B-azgAvX.mjs +19 -0
- package/.output/server/_ssr/installations-Ctvzp2JH.mjs +535 -0
- package/.output/server/_ssr/router-C-KUBfOi.mjs +513 -0
- package/.output/server/_ssr/routes-BM4ht9jb.mjs +2286 -0
- package/.output/server/_ssr/routes-Z7TwC6nC.mjs +37 -0
- package/.output/server/_ssr/runtime.server-awTLiiXW.mjs +527 -0
- package/.output/server/_ssr/server-BjzmvXnO.mjs +7468 -0
- package/.output/server/_ssr/signing-k8GxyBDF.mjs +202 -0
- package/.output/server/_ssr/ssr.mjs +4 -5740
- package/.output/server/_ssr/start-DpViQGnt.mjs +4 -0
- package/.output/server/_ssr/table-v1yCvYo7.mjs +53 -0
- package/.output/server/_ssr/textarea-DYHnskhb.mjs +14 -0
- package/.output/server/_ssr/uuidv7-BbJ-9D_I.mjs +31 -0
- package/.output/server/_tanstack-start-manifest_v-CH4StzJu.mjs +108 -0
- package/.output/server/index.mjs +249 -46
- package/README.md +29 -8
- package/lib/index.d.mts +36 -0
- package/lib/index.mjs +4 -0
- package/lib/vite-internal.mjs +127 -0
- package/lib/vite.d.mts +10 -0
- package/lib/vite.mjs +5 -0
- package/package.json +51 -29
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/logo.svg +1 -0
- package/public/manifest.json +30 -0
- package/public/robots.txt +3 -0
- package/src/components/AppSidebar.tsx +159 -0
- package/src/components/BundleIdDisplay.tsx +18 -0
- package/src/components/ChannelBadge.tsx +31 -0
- package/src/components/ConsoleAccessPage.tsx +122 -0
- package/src/components/EnabledStatusIcon.tsx +54 -0
- package/src/components/HashValueDisplay.tsx +85 -0
- package/src/components/HotUpdaterLogo.tsx +30 -0
- package/src/components/NotFoundPage.tsx +33 -0
- package/src/components/PlatformIcon.tsx +39 -0
- package/src/components/RolloutPercentageBadge.tsx +28 -0
- package/src/components/ThemeProvider.tsx +116 -0
- package/src/components/TimestampDisplay.tsx +41 -0
- package/src/components/features/analytics/ActivityChart.tsx +150 -0
- package/src/components/features/analytics/AnalyticsCapabilityContext.tsx +24 -0
- package/src/components/features/analytics/AnalyticsControls.tsx +115 -0
- package/src/components/features/analytics/AnalyticsErrorAlert.tsx +21 -0
- package/src/components/features/analytics/AnalyticsOverview.tsx +208 -0
- package/src/components/features/analytics/BundleDistribution.tsx +133 -0
- package/src/components/features/analytics/BundleSelector.tsx +114 -0
- package/src/components/features/analytics/InstallationHistoryCard.tsx +248 -0
- package/src/components/features/analytics/InstallationMatchesCard.tsx +132 -0
- package/src/components/features/analytics/InstallationPageHeader.tsx +138 -0
- package/src/components/features/analytics/InstallationPagination.tsx +48 -0
- package/src/components/features/analytics/InstallationSearch.tsx +230 -0
- package/src/components/features/analytics/UpdateOutcomes.tsx +147 -0
- package/src/components/features/api-keys/ApiKeysPage.tsx +377 -0
- package/src/components/features/bundles/BundleActivityChart.tsx +193 -0
- package/src/components/features/bundles/BundleAnalyticsSummary.tsx +123 -0
- package/src/components/features/bundles/BundleChildrenPanel.tsx +201 -0
- package/src/components/features/bundles/BundleMetadata.tsx +136 -0
- package/src/components/features/bundles/RolloutCohortsDialog.tsx +201 -0
- package/src/components/features/channels/ChannelManagementDialog.tsx +228 -0
- package/src/components/features/releases/ReleaseEditorSheet.tsx +879 -0
- package/src/components/features/releases/ReleaseStateBadge.tsx +20 -0
- package/src/components/features/signing/BundleSigningPage.tsx +247 -0
- package/src/components/ui/alert-dialog.tsx +185 -0
- package/src/components/ui/alert.tsx +76 -0
- package/src/components/ui/badge.tsx +49 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/card.tsx +89 -0
- package/src/components/ui/chart.tsx +371 -0
- package/src/components/ui/combobox.tsx +303 -0
- package/src/components/ui/dialog.tsx +156 -0
- package/src/components/ui/dropdown-menu.tsx +270 -0
- package/src/components/ui/field.tsx +235 -0
- package/src/components/ui/input-group.tsx +147 -0
- package/src/components/ui/input.tsx +19 -0
- package/src/components/ui/label.tsx +25 -0
- package/src/components/ui/progress.tsx +84 -0
- package/src/components/ui/select.tsx +205 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/sheet.tsx +132 -0
- package/src/components/ui/sidebar.tsx +779 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/slider.tsx +56 -0
- package/src/components/ui/sonner.tsx +45 -0
- package/src/components/ui/switch.tsx +25 -0
- package/src/components/ui/table.tsx +114 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/toggle-group.tsx +89 -0
- package/src/components/ui/toggle.tsx +43 -0
- package/src/components/ui/tooltip.tsx +66 -0
- package/src/hooks/use-mobile.ts +30 -0
- package/src/index.ts +48 -0
- package/src/lib/analytics-api.ts +145 -0
- package/src/lib/analytics-error.ts +19 -0
- package/src/lib/analytics-input.ts +187 -0
- package/src/lib/analytics-overview.ts +170 -0
- package/src/lib/analytics-rpc.ts +218 -0
- package/src/lib/api-keys-api.ts +69 -0
- package/src/lib/api-keys-rpc.ts +87 -0
- package/src/lib/api-rpc.ts +478 -0
- package/src/lib/api.ts +444 -0
- package/src/lib/auth-rpc.ts +16 -0
- package/src/lib/bundle-signing-api.ts +14 -0
- package/src/lib/bundle-signing-rpc.ts +16 -0
- package/src/lib/constants.ts +1 -0
- package/src/lib/git.ts +51 -0
- package/src/lib/server/auth.server.ts +43 -0
- package/src/lib/server/bundle-signing.server.ts +100 -0
- package/src/lib/server/config.server.ts +109 -0
- package/src/lib/server/console-runtime.server.ts +70 -0
- package/src/lib/server/deleteBundle.ts +145 -0
- package/src/lib/server/downloadBundle.ts +46 -0
- package/src/lib/server/getBundleChildren.ts +130 -0
- package/src/lib/server/listReleases.ts +61 -0
- package/src/lib/server/releaseActivity.ts +27 -0
- package/src/lib/server/releaseReachability.ts +95 -0
- package/src/lib/server/runtime.server.ts +172 -0
- package/src/lib/utils.ts +9 -0
- package/src/logo.svg +1 -0
- package/src/routeTree.gen.ts +199 -0
- package/src/router.tsx +21 -0
- package/src/routes/-installations-search.ts +19 -0
- package/src/routes/-releases-search.ts +74 -0
- package/src/routes/__root.tsx +174 -0
- package/src/routes/analytics.tsx +139 -0
- package/src/routes/api/auth/$.ts +19 -0
- package/src/routes/api/bundles/$bundleId/download.ts +17 -0
- package/src/routes/api-keys.tsx +37 -0
- package/src/routes/index.tsx +982 -0
- package/src/routes/installations.tsx +194 -0
- package/src/routes/signing.tsx +37 -0
- package/src/styles.css +152 -0
- package/src/virtual-modules.d.ts +21 -0
- package/src/vite-env.d.ts +1 -0
- package/src/vite-internal.ts +195 -0
- package/src/vite.ts +12 -0
- package/.output/public/assets/dist-DJX53faP.js +0 -3
- package/.output/public/assets/index-Iylis5kY.js +0 -10
- package/.output/public/assets/routes-HT21hs0C.js +0 -54
- package/.output/public/assets/styles-C0Re4quB.css +0 -2
- package/.output/server/__23tanstack-start-server-fn-resolver-CgwgZ0-i.mjs +0 -66
- package/.output/server/_libs/@floating-ui/core+[...].mjs +0 -698
- package/.output/server/_libs/@floating-ui/dom+[...].mjs +0 -644
- package/.output/server/_libs/@floating-ui/react-dom+[...].mjs +0 -839
- package/.output/server/_libs/@radix-ui/react-alert-dialog+[...].mjs +0 -2138
- package/.output/server/_libs/@radix-ui/react-popper+[...].mjs +0 -308
- package/.output/server/_libs/@radix-ui/react-select+[...].mjs +0 -1038
- package/.output/server/_libs/@tanstack/devtools-event-client+[...].mjs +0 -196
- package/.output/server/_libs/@tanstack/form-core+[...].mjs +0 -3228
- package/.output/server/_libs/@tanstack/react-form+[...].mjs +0 -430
- package/.output/server/_libs/@tanstack/react-table+[...].mjs +0 -2382
- package/.output/server/_libs/radix-ui__number.mjs +0 -6
- package/.output/server/_libs/radix-ui__primitive.mjs +0 -9
- package/.output/server/_libs/radix-ui__react-arrow.mjs +0 -23
- package/.output/server/_libs/radix-ui__react-collection.mjs +0 -78
- package/.output/server/_libs/radix-ui__react-direction.mjs +0 -13
- package/.output/server/_libs/radix-ui__react-label.mjs +0 -22
- package/.output/server/_libs/radix-ui__react-separator.mjs +0 -30
- package/.output/server/_libs/radix-ui__react-slider.mjs +0 -510
- package/.output/server/_libs/radix-ui__react-switch.mjs +0 -157
- package/.output/server/_libs/radix-ui__react-tooltip.mjs +0 -493
- package/.output/server/_ssr/api-rpc-BIbDUKSz.mjs +0 -292
- package/.output/server/_ssr/config.server-BSS366KT.mjs +0 -41
- package/.output/server/_ssr/deleteBundle-BgbZTtpW.mjs +0 -141
- package/.output/server/_ssr/dist-KboydRVk.mjs +0 -120
- package/.output/server/_ssr/router-C3hqEy3k.mjs +0 -307
- package/.output/server/_ssr/routes-B0lQvvlC.mjs +0 -3048
- package/.output/server/_ssr/start-02sLteYG.mjs +0 -4
- package/.output/server/_ssr/storageProfile-FVkjPoGb.mjs +0 -9
- package/.output/server/_tanstack-start-manifest_v-Bpx52WOU.mjs +0 -20
- package/.output/server/node_modules/tslib/modules/index.js +0 -70
- package/.output/server/node_modules/tslib/modules/package.json +0 -3
- package/.output/server/node_modules/tslib/package.json +0 -47
- package/.output/server/node_modules/tslib/tslib.js +0 -484
- package/.output/server/package.json +0 -9
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Modern web-based management console for Hot Updater built with **TanStack Start*
|
|
|
17
17
|
## 🛠️ Tech Stack
|
|
18
18
|
|
|
19
19
|
### Frontend
|
|
20
|
+
|
|
20
21
|
- **TanStack Start** - Full-stack React framework with SSR
|
|
21
22
|
- **TanStack Router** - File-based routing with type safety
|
|
22
23
|
- **TanStack Query** - Data fetching and caching
|
|
@@ -25,14 +26,16 @@ Modern web-based management console for Hot Updater built with **TanStack Start*
|
|
|
25
26
|
- **React 19** - Latest React features
|
|
26
27
|
|
|
27
28
|
### UI Components
|
|
29
|
+
|
|
28
30
|
- **shadcn/ui** - High-quality accessible components (Radix Mira style)
|
|
29
31
|
- **Tailwind CSS v4** - Utility-first CSS with oklch color system
|
|
30
32
|
- **Lucide React** - Beautiful icon library
|
|
31
33
|
- **Sonner** - Toast notifications
|
|
32
34
|
|
|
33
35
|
### Backend
|
|
36
|
+
|
|
34
37
|
- **TanStack Start Server Functions** - Type-safe server endpoints
|
|
35
|
-
- **Hot Updater
|
|
38
|
+
- **Hot Updater Integration** - Storage and database plugin integration
|
|
36
39
|
|
|
37
40
|
## 📦 Installation
|
|
38
41
|
|
|
@@ -92,23 +95,26 @@ src/
|
|
|
92
95
|
## 🎨 Key Components
|
|
93
96
|
|
|
94
97
|
### Bundle List Page
|
|
98
|
+
|
|
95
99
|
- **FilterToolbar** - Platform and channel filters with reset button
|
|
96
100
|
- **BundlesTable** - Server-side paginated table (20 per page)
|
|
97
101
|
- **BundleTableColumns** - Column definitions with custom cell renderers
|
|
98
102
|
|
|
99
103
|
### Bundle Editor Sheet
|
|
104
|
+
|
|
100
105
|
- **BundleEditorSheet** - Right-side slide-out panel
|
|
101
106
|
- **BundleEditorForm** - TanStack Form with validation
|
|
102
107
|
- **BundleMetadata** - Read-only bundle information display
|
|
103
108
|
|
|
104
109
|
### Dialogs
|
|
110
|
+
|
|
105
111
|
- **PromoteChannelDialog** - Channel promotion with copy/move toggle
|
|
106
112
|
- **DeleteBundleDialog** - Confirmation dialog with bundle details
|
|
107
113
|
- **EmergencyRollbackButton** - One-click disable + 0% rollout
|
|
108
114
|
|
|
109
115
|
## 🔌 API Integration
|
|
110
116
|
|
|
111
|
-
The console integrates with Hot Updater
|
|
117
|
+
The console integrates with the configured Hot Updater storage and database plugins through TanStack Start server functions:
|
|
112
118
|
|
|
113
119
|
- `getConfig()` - Load console configuration
|
|
114
120
|
- `getChannels()` - List available channels
|
|
@@ -123,15 +129,27 @@ The console integrates with Hot Updater's plugin system through TanStack Start s
|
|
|
123
129
|
Configure Hot Updater in `hot-updater.config.ts`:
|
|
124
130
|
|
|
125
131
|
```typescript
|
|
126
|
-
import {
|
|
132
|
+
import {
|
|
133
|
+
createMockDatabaseData,
|
|
134
|
+
mockDatabase,
|
|
135
|
+
mockStorage,
|
|
136
|
+
} from "@hot-updater/mock";
|
|
137
|
+
import { bundleToRow, type Bundle } from "@hot-updater/plugin-core";
|
|
138
|
+
|
|
139
|
+
const bundles: Bundle[] = [
|
|
140
|
+
// ... your bundles
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
const databaseData = createMockDatabaseData();
|
|
144
|
+
for (const bundle of bundles) {
|
|
145
|
+
databaseData.bundles.set(bundle.id, bundleToRow(bundle));
|
|
146
|
+
}
|
|
127
147
|
|
|
128
148
|
export default {
|
|
129
149
|
storage: mockStorage({}),
|
|
130
150
|
database: mockDatabase({
|
|
131
151
|
latency: { min: 500, max: 700 },
|
|
132
|
-
|
|
133
|
-
// ... your bundles
|
|
134
|
-
],
|
|
152
|
+
data: databaseData,
|
|
135
153
|
}),
|
|
136
154
|
};
|
|
137
155
|
```
|
|
@@ -154,7 +172,7 @@ The console uses Tailwind CSS v4 with oklch color space for accessible colors. T
|
|
|
154
172
|
## 📊 Data Flow
|
|
155
173
|
|
|
156
174
|
1. **URL State** → `useFilterParams()` hook manages filter state in URL
|
|
157
|
-
2. **Server Functions** → TanStack Start server functions call
|
|
175
|
+
2. **Server Functions** → TanStack Start server functions call the configured storage and database plugins
|
|
158
176
|
3. **React Query** → `useBundlesQuery()` fetches and caches data
|
|
159
177
|
4. **UI Components** → Display data with shadcn components
|
|
160
178
|
5. **Mutations** → `useUpdateBundleMutation()` updates data with optimistic updates
|
|
@@ -171,16 +189,19 @@ The console uses Tailwind CSS v4 with oklch color space for accessible colors. T
|
|
|
171
189
|
## 🐛 Troubleshooting
|
|
172
190
|
|
|
173
191
|
### Build Errors
|
|
192
|
+
|
|
174
193
|
- Ensure `.server.ts` files are not imported on the client
|
|
175
194
|
- Check that native modules (`.node`) are excluded from bundling
|
|
176
195
|
|
|
177
196
|
### Development Server
|
|
197
|
+
|
|
178
198
|
- Default port is 3000
|
|
179
199
|
- Change port: `pnpm dev --port 3001`
|
|
180
200
|
|
|
181
201
|
### Hot Updater Config
|
|
202
|
+
|
|
182
203
|
- Ensure `hot-updater.config.ts` is at package root
|
|
183
|
-
- Verify storage and database plugins are correctly initialized
|
|
204
|
+
- Verify the storage and database plugins are correctly initialized
|
|
184
205
|
|
|
185
206
|
## 📝 License
|
|
186
207
|
|
package/lib/index.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ConfigInput } from "@hot-updater/plugin-core";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
type ConsoleAuthProvider = "google" | "github";
|
|
5
|
+
type ConsolePrincipal = Readonly<{
|
|
6
|
+
email: string;
|
|
7
|
+
name?: string | null;
|
|
8
|
+
image?: string | null;
|
|
9
|
+
}>;
|
|
10
|
+
type ConsoleAccess = {
|
|
11
|
+
status: "unauthenticated";
|
|
12
|
+
} | {
|
|
13
|
+
status: "forbidden";
|
|
14
|
+
principal: ConsolePrincipal;
|
|
15
|
+
} | {
|
|
16
|
+
status: "authorized";
|
|
17
|
+
principal: ConsolePrincipal;
|
|
18
|
+
};
|
|
19
|
+
type ConsoleAuthAdapter = Readonly<{
|
|
20
|
+
handle(request: Request): Promise<Response>;
|
|
21
|
+
getAccess(request: Request): Promise<ConsoleAccess>;
|
|
22
|
+
getProviders(request: Request): Promise<readonly ConsoleAuthProvider[]>;
|
|
23
|
+
}>;
|
|
24
|
+
type ConsoleSigningConfig = Readonly<{
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
provider?: string;
|
|
27
|
+
publicKeyPath?: string;
|
|
28
|
+
}>;
|
|
29
|
+
type HotUpdaterConsoleConfig = Readonly<Pick<ConfigInput, "console" | "database" | "signing" | "storage">>;
|
|
30
|
+
type ResolvedHotUpdaterConsoleConfig = Readonly<Omit<HotUpdaterConsoleConfig, "signing"> & {
|
|
31
|
+
signing?: ConsoleSigningConfig;
|
|
32
|
+
}>;
|
|
33
|
+
type HotUpdaterConsoleConfigSource = HotUpdaterConsoleConfig | ((request: Request) => HotUpdaterConsoleConfig | Promise<HotUpdaterConsoleConfig>);
|
|
34
|
+
declare const defineConsoleConfig: <const TConfig extends HotUpdaterConsoleConfigSource>(config: TConfig) => TConfig;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ConsoleAccess, ConsoleAuthAdapter, ConsoleAuthProvider, ConsolePrincipal, ConsoleSigningConfig, HotUpdaterConsoleConfig, HotUpdaterConsoleConfigSource, ResolvedHotUpdaterConsoleConfig, defineConsoleConfig };
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
4
|
+
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
5
|
+
import viteReact from "@vitejs/plugin-react";
|
|
6
|
+
import { nitro } from "nitro/vite";
|
|
7
|
+
//#region src/vite-internal.ts
|
|
8
|
+
const virtualAuthModuleId = "virtual:hot-updater-console/auth";
|
|
9
|
+
const virtualConfigModuleId = "virtual:hot-updater-console/config";
|
|
10
|
+
const virtualPackageRouterModuleId = "virtual:hot-updater-console/package-router";
|
|
11
|
+
const virtualRouteTreeModuleId = "virtual:hot-updater-console/route-tree";
|
|
12
|
+
const resolvedVirtualAuthModuleId = `\0${virtualAuthModuleId}`;
|
|
13
|
+
const resolvedVirtualConfigModuleId = `\0${virtualConfigModuleId}`;
|
|
14
|
+
const resolvedVirtualPackageRouterModuleId = `\0${virtualPackageRouterModuleId}`;
|
|
15
|
+
const packageRoot = path.resolve(import.meta.dirname, "..");
|
|
16
|
+
const packagePublicDirectory = path.join(packageRoot, "public");
|
|
17
|
+
const packageRouterFile = path.join(packageRoot, "src/router.tsx");
|
|
18
|
+
const packageRoutesDirectory = path.join(packageRoot, "src/routes");
|
|
19
|
+
const packageSourceDirectory = path.join(packageRoot, "src");
|
|
20
|
+
const localRouteTreeFile = path.join(packageSourceDirectory, "routeTree.gen.ts");
|
|
21
|
+
const resolveFromRoot = (root, file) => path.isAbsolute(file) ? file : path.resolve(root, file);
|
|
22
|
+
const toImportPath = (file) => file.split(path.sep).join("/");
|
|
23
|
+
const writeFileIfChanged = (file, contents) => {
|
|
24
|
+
if (existsSync(file) && readFileSync(file, "utf8") === contents) return;
|
|
25
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
26
|
+
writeFileSync(file, contents);
|
|
27
|
+
};
|
|
28
|
+
const createConsoleModulesPlugin = (mode) => {
|
|
29
|
+
let authFile = "";
|
|
30
|
+
let configFile = "";
|
|
31
|
+
let generatedRouteTreeFile = localRouteTreeFile;
|
|
32
|
+
return {
|
|
33
|
+
name: `hot-updater-console:${mode.type}-modules`,
|
|
34
|
+
enforce: "pre",
|
|
35
|
+
config(userConfig, configEnvironment) {
|
|
36
|
+
const root = path.resolve(process.cwd(), userConfig.root ?? ".");
|
|
37
|
+
if (mode.type === "hosted") {
|
|
38
|
+
const cacheDirectory = path.join(root, ".hot-updater/console");
|
|
39
|
+
generatedRouteTreeFile = path.join(cacheDirectory, "routeTree.gen.ts");
|
|
40
|
+
authFile = resolveFromRoot(root, mode.options.auth ?? "console.auth.ts");
|
|
41
|
+
configFile = resolveFromRoot(root, mode.options.config ?? "hot-updater.config.ts");
|
|
42
|
+
writeFileIfChanged(path.join(cacheDirectory, "router.ts"), [`export { getRouter } from ${JSON.stringify(virtualPackageRouterModuleId)};`, ""].join("\n"));
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
assetsInclude: ["**/*.node"],
|
|
46
|
+
oxc: { jsx: { development: configEnvironment.command === "serve" } },
|
|
47
|
+
resolve: {
|
|
48
|
+
alias: [{
|
|
49
|
+
find: /^@\//,
|
|
50
|
+
replacement: `${toImportPath(packageSourceDirectory)}/`
|
|
51
|
+
}],
|
|
52
|
+
dedupe: [
|
|
53
|
+
"react",
|
|
54
|
+
"react-dom",
|
|
55
|
+
"@tanstack/react-query",
|
|
56
|
+
"@tanstack/react-router",
|
|
57
|
+
"@tanstack/react-start"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
resolveId(id) {
|
|
63
|
+
if (id === virtualAuthModuleId) return resolvedVirtualAuthModuleId;
|
|
64
|
+
if (id === virtualConfigModuleId) return resolvedVirtualConfigModuleId;
|
|
65
|
+
if (id === virtualPackageRouterModuleId) return resolvedVirtualPackageRouterModuleId;
|
|
66
|
+
if (id === virtualRouteTreeModuleId) return generatedRouteTreeFile;
|
|
67
|
+
},
|
|
68
|
+
load(id) {
|
|
69
|
+
if (id === resolvedVirtualPackageRouterModuleId) return `export { getRouter } from ${JSON.stringify(toImportPath(packageRouterFile))};`;
|
|
70
|
+
if (id === resolvedVirtualConfigModuleId) {
|
|
71
|
+
if (mode.type === "local") return [
|
|
72
|
+
"import { loadConfig } from \"@hot-updater/cli-tools\";",
|
|
73
|
+
"export default async () => {",
|
|
74
|
+
" const config = await loadConfig(null);",
|
|
75
|
+
" return {",
|
|
76
|
+
" console: { gitUrl: config.console.gitUrl },",
|
|
77
|
+
" database: config.database,",
|
|
78
|
+
" signing: config.signing,",
|
|
79
|
+
" storage: config.storage,",
|
|
80
|
+
" };",
|
|
81
|
+
"};"
|
|
82
|
+
].join("\n");
|
|
83
|
+
this.addWatchFile(configFile);
|
|
84
|
+
return `export { default } from ${JSON.stringify(toImportPath(configFile))};`;
|
|
85
|
+
}
|
|
86
|
+
if (id === resolvedVirtualAuthModuleId) {
|
|
87
|
+
if (mode.type === "local") return [
|
|
88
|
+
"const principal = { email: \"local@hot-updater.dev\", name: \"Local Console\" };",
|
|
89
|
+
"export default {",
|
|
90
|
+
" async handle() {",
|
|
91
|
+
" return new Response(\"Not Found\", { status: 404 });",
|
|
92
|
+
" },",
|
|
93
|
+
" async getAccess() {",
|
|
94
|
+
" return { status: \"authorized\", principal };",
|
|
95
|
+
" },",
|
|
96
|
+
" async getProviders() {",
|
|
97
|
+
" return [];",
|
|
98
|
+
" },",
|
|
99
|
+
"};"
|
|
100
|
+
].join("\n");
|
|
101
|
+
this.addWatchFile(authFile);
|
|
102
|
+
return `export { default } from ${JSON.stringify(toImportPath(authFile))};`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
const createHostedConsolePlugins = (options) => [
|
|
108
|
+
createConsoleModulesPlugin({
|
|
109
|
+
type: "hosted",
|
|
110
|
+
options
|
|
111
|
+
}),
|
|
112
|
+
nitro({ publicAssets: [{
|
|
113
|
+
dir: packagePublicDirectory,
|
|
114
|
+
maxAge: 3600 * 24
|
|
115
|
+
}] }),
|
|
116
|
+
tailwindcss(),
|
|
117
|
+
tanstackStart({
|
|
118
|
+
srcDirectory: ".hot-updater/console",
|
|
119
|
+
router: {
|
|
120
|
+
generatedRouteTree: "routeTree.gen.ts",
|
|
121
|
+
routesDirectory: packageRoutesDirectory
|
|
122
|
+
}
|
|
123
|
+
}),
|
|
124
|
+
viteReact()
|
|
125
|
+
];
|
|
126
|
+
//#endregion
|
|
127
|
+
export { createHostedConsolePlugins };
|
package/lib/vite.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PluginOption } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/vite.d.ts
|
|
4
|
+
interface HotUpdaterConsolePluginOptions {
|
|
5
|
+
readonly auth?: string;
|
|
6
|
+
readonly config?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const hotUpdaterConsole: (options?: HotUpdaterConsolePluginOptions) => PluginOption[];
|
|
9
|
+
//#endregion
|
|
10
|
+
export { HotUpdaterConsolePluginOptions, hotUpdaterConsole };
|
package/lib/vite.mjs
ADDED
package/package.json
CHANGED
|
@@ -1,71 +1,93 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/console",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0-rc.0",
|
|
5
5
|
"files": [
|
|
6
6
|
".output",
|
|
7
|
+
"lib",
|
|
8
|
+
"public",
|
|
9
|
+
"src",
|
|
10
|
+
"!src/**/*.spec.ts",
|
|
11
|
+
"!src/**/*.spec.tsx",
|
|
7
12
|
"package.json"
|
|
8
13
|
],
|
|
9
14
|
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./lib/index.d.mts",
|
|
17
|
+
"import": "./lib/index.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./vite": {
|
|
20
|
+
"types": "./lib/vite.d.mts",
|
|
21
|
+
"import": "./lib/vite.mjs"
|
|
22
|
+
},
|
|
10
23
|
"./package.json": "./package.json"
|
|
11
24
|
},
|
|
12
25
|
"peerDependencies": {
|
|
13
|
-
"@hot-updater/cli-tools": "*"
|
|
26
|
+
"@hot-updater/cli-tools": "*",
|
|
27
|
+
"react": "^19.0.0",
|
|
28
|
+
"react-dom": "^19.0.0",
|
|
29
|
+
"vite": "^8.0.0"
|
|
14
30
|
},
|
|
15
|
-
"
|
|
16
|
-
"@hot-updater/
|
|
17
|
-
|
|
31
|
+
"peerDependenciesMeta": {
|
|
32
|
+
"@hot-updater/cli-tools": {
|
|
33
|
+
"optional": true
|
|
34
|
+
}
|
|
18
35
|
},
|
|
19
|
-
"
|
|
36
|
+
"dependencies": {
|
|
20
37
|
"@base-ui/react": "^1.3.0",
|
|
21
38
|
"@fontsource-variable/inter": "^5.2.8",
|
|
22
39
|
"@tailwindcss/vite": "^4.2.1",
|
|
23
|
-
"@tanstack/devtools-vite": "^0.6.0",
|
|
24
40
|
"@tanstack/react-devtools": "^0.10.0",
|
|
25
|
-
"@tanstack/react-form": "^1.28.5",
|
|
26
41
|
"@tanstack/react-query": "^5.90.21",
|
|
27
42
|
"@tanstack/react-router": "^1.167.0",
|
|
28
43
|
"@tanstack/react-router-devtools": "^1.166.7",
|
|
29
44
|
"@tanstack/react-router-ssr-query": "^1.166.7",
|
|
30
45
|
"@tanstack/react-start": "^1.166.11",
|
|
31
|
-
"@tanstack/react-table": "^8.21.3",
|
|
32
|
-
"@tanstack/router-plugin": "^1.166.9",
|
|
33
|
-
"@testing-library/dom": "^10.4.0",
|
|
34
|
-
"@testing-library/react": "^16.3.2",
|
|
35
|
-
"@types/node": "^25.5.0",
|
|
36
|
-
"@types/react": "^19.2.14",
|
|
37
|
-
"@types/react-dom": "^19.2.0",
|
|
38
46
|
"@vitejs/plugin-react": "^6.0.1",
|
|
39
47
|
"class-variance-authority": "^0.7.1",
|
|
40
48
|
"clsx": "^2.1.1",
|
|
41
49
|
"dayjs": "^1.11.20",
|
|
42
|
-
"jsdom": "^29.0.0",
|
|
43
|
-
"jszip": "^3.10.1",
|
|
44
50
|
"lucide-react": "^0.577.0",
|
|
45
51
|
"next-themes": "^0.4.6",
|
|
46
|
-
"nitro": "
|
|
47
|
-
"radix-ui": "^1.4.3",
|
|
48
|
-
"react": "^19.2.4",
|
|
49
|
-
"react-dom": "^19.2.4",
|
|
52
|
+
"nitro": "3.0.260610-beta",
|
|
50
53
|
"react-grab": "^0.1.28",
|
|
54
|
+
"recharts": "3.8.0",
|
|
51
55
|
"shadcn": "^4.0.8",
|
|
52
56
|
"sonner": "^2.0.7",
|
|
53
57
|
"tailwind-merge": "^3.5.0",
|
|
54
58
|
"tailwindcss": "^4.2.1",
|
|
55
|
-
"tar": "^7.5.16",
|
|
56
|
-
"tslib": "^2.8.1",
|
|
57
59
|
"tw-animate-css": "^1.4.0",
|
|
60
|
+
"verkit": "0.3.2",
|
|
61
|
+
"@hot-updater/bsdiff": "1.0.0-rc.0",
|
|
62
|
+
"@hot-updater/core": "1.0.0-rc.0",
|
|
63
|
+
"@hot-updater/server": "1.0.0-rc.0",
|
|
64
|
+
"@hot-updater/plugin-core": "1.0.0-rc.0"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@tanstack/devtools-vite": "^0.6.0",
|
|
68
|
+
"@tanstack/react-form": "^1.28.5",
|
|
69
|
+
"@tanstack/react-table": "^8.21.3",
|
|
70
|
+
"@tanstack/router-plugin": "^1.166.9",
|
|
71
|
+
"@testing-library/dom": "^10.4.0",
|
|
72
|
+
"@testing-library/react": "^16.3.2",
|
|
73
|
+
"@types/node": "^25.5.0",
|
|
74
|
+
"@types/react": "^19.2.14",
|
|
75
|
+
"@types/react-dom": "^19.2.0",
|
|
58
76
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
77
|
+
"jsdom": "^29.0.0",
|
|
78
|
+
"jszip": "^3.10.1",
|
|
79
|
+
"react": "^19.2.4",
|
|
80
|
+
"react-dom": "^19.2.4",
|
|
81
|
+
"tar": "^7.5.16",
|
|
82
|
+
"tsdown": "0.21.6",
|
|
83
|
+
"tslib": "^2.8.1",
|
|
59
84
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
60
|
-
"verkit": "0.3.2",
|
|
61
85
|
"vite": "8.0.8",
|
|
62
86
|
"vite-tsconfig-paths": "^6.1.1",
|
|
63
87
|
"vitest": "4.1.4",
|
|
64
88
|
"web-vitals": "^5.1.0",
|
|
65
|
-
"@hot-updater/
|
|
66
|
-
"@hot-updater/mock": "0.
|
|
67
|
-
"@hot-updater/cli-tools": "0.36.6",
|
|
68
|
-
"@hot-updater/plugin-core": "0.36.6"
|
|
89
|
+
"@hot-updater/cli-tools": "1.0.0-rc.0",
|
|
90
|
+
"@hot-updater/mock": "1.0.0-rc.0"
|
|
69
91
|
},
|
|
70
92
|
"description": "React Native OTA solution for self-hosted",
|
|
71
93
|
"license": "MIT",
|
|
@@ -102,7 +124,7 @@
|
|
|
102
124
|
},
|
|
103
125
|
"scripts": {
|
|
104
126
|
"dev": "vite dev --port 3000",
|
|
105
|
-
"build": "vite build &&
|
|
127
|
+
"build": "NODE_ENV=production vite build && tsdown",
|
|
106
128
|
"check": "oxfmt --write \"**/*.{ts,tsx}\" && oxlint --fix --fix-suggestions --fix-dangerously .",
|
|
107
129
|
"format": "oxfmt --write \"**/*.{ts,tsx}\"",
|
|
108
130
|
"preview": "vite preview",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/public/logo.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg id="hot-updater-layer" data-name="hot-updater-layer" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 447 652"><defs><linearGradient id="hot-updater-gradient" x1="223.54" y1="0.36" x2="223.54" y2="711.23" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ff7f33"/><stop offset="0.4" stop-color="#f9602b"/><stop offset="0.76" stop-color="#f54c25"/><stop offset="1" stop-color="#f44523"/></linearGradient></defs><title>Hotupdater</title><path d="M150.25,8.58c16.28,31.85,42.09,116-68.18,212.22C75.46,226.57,70,233,63.72,239.62c-28.48,30-84.71,114.89-55.82,207,.69,2.18,1.31,4.37,1.91,6.57,5.25,19.33,38.08,121,155.56,157.25a5.14,5.14,0,0,0,6-7.39c-14.72-26.53-46.07-96.89-8.89-162.55,0,0,11.5,44.5,50.5,83.5,6,6,14.72,15.64,19.53,21.23,14.47,16.77,32.24,53.55,1.82,98.18a5.63,5.63,0,0,0,6.85,8.34c75.64-32.1,333.29-164.6,128.68-410.85a7,7,0,0,0-12.46,4.15c-1.77,39.31-14.84,129-96.18,148.06a31.08,31.08,0,0,1-24.3-4.16c-13.34-8.9-25.41-32.06.53-92.3a250.9,250.9,0,0,1,20.12-37.29C282.78,220.56,356.18,79.83,157.33.77A5.64,5.64,0,0,0,150.25,8.58Z" fill="url(#hot-updater-gradient)"/></svg>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"short_name": "Hot Updater",
|
|
3
|
+
"name": "Hot Updater Console",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "favicon.ico",
|
|
7
|
+
"sizes": "64x64 32x32 24x24 16x16",
|
|
8
|
+
"type": "image/x-icon"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"src": "favicon-16x16.png",
|
|
12
|
+
"type": "image/png",
|
|
13
|
+
"sizes": "16x16"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"src": "favicon-32x32.png",
|
|
17
|
+
"type": "image/png",
|
|
18
|
+
"sizes": "32x32"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"src": "apple-touch-icon.png",
|
|
22
|
+
"type": "image/png",
|
|
23
|
+
"sizes": "180x180"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"start_url": ".",
|
|
27
|
+
"display": "standalone",
|
|
28
|
+
"theme_color": "#f97316",
|
|
29
|
+
"background_color": "#ffffff"
|
|
30
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Link, useRouterState } from "@tanstack/react-router";
|
|
2
|
+
import {
|
|
3
|
+
ChartNoAxesCombined,
|
|
4
|
+
KeyRound,
|
|
5
|
+
Moon,
|
|
6
|
+
Package,
|
|
7
|
+
ShieldCheck,
|
|
8
|
+
Sun,
|
|
9
|
+
} from "lucide-react";
|
|
10
|
+
|
|
11
|
+
import { useAnalyticsCapability } from "@/components/features/analytics/AnalyticsCapabilityContext";
|
|
12
|
+
import { HotUpdaterLogo } from "@/components/HotUpdaterLogo";
|
|
13
|
+
import { useTheme } from "@/components/ThemeProvider";
|
|
14
|
+
import {
|
|
15
|
+
Sidebar,
|
|
16
|
+
SidebarContent,
|
|
17
|
+
SidebarFooter,
|
|
18
|
+
SidebarGroup,
|
|
19
|
+
SidebarGroupContent,
|
|
20
|
+
SidebarGroupLabel,
|
|
21
|
+
SidebarHeader,
|
|
22
|
+
SidebarMenu,
|
|
23
|
+
SidebarMenuButton,
|
|
24
|
+
SidebarMenuItem,
|
|
25
|
+
} from "@/components/ui/sidebar";
|
|
26
|
+
import { useApiKeyCapabilityQuery } from "@/lib/api-keys-api";
|
|
27
|
+
|
|
28
|
+
export function AppSidebar() {
|
|
29
|
+
const analyticsCapability = useAnalyticsCapability();
|
|
30
|
+
const apiKeyCapability = useApiKeyCapabilityQuery();
|
|
31
|
+
const { theme, setTheme } = useTheme();
|
|
32
|
+
const routerState = useRouterState();
|
|
33
|
+
const currentPath = routerState.location.pathname;
|
|
34
|
+
|
|
35
|
+
const isBundlesActive = currentPath === "/";
|
|
36
|
+
const isAnalyticsActive =
|
|
37
|
+
currentPath === "/analytics" || currentPath === "/installations";
|
|
38
|
+
const isApiKeysActive = currentPath === "/api-keys";
|
|
39
|
+
const isSigningActive = currentPath === "/signing";
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Sidebar collapsible="icon">
|
|
43
|
+
<SidebarHeader className="h-12 justify-center">
|
|
44
|
+
<Link
|
|
45
|
+
to="/"
|
|
46
|
+
search={{
|
|
47
|
+
afterReleaseId: undefined,
|
|
48
|
+
beforeReleaseId: undefined,
|
|
49
|
+
channelId: undefined,
|
|
50
|
+
enabled: undefined,
|
|
51
|
+
releaseId: undefined,
|
|
52
|
+
platform: undefined,
|
|
53
|
+
targetAppVersion: undefined,
|
|
54
|
+
bundleId: undefined,
|
|
55
|
+
page: undefined,
|
|
56
|
+
}}
|
|
57
|
+
className="flex items-center gap-3 p-1 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:p-2"
|
|
58
|
+
>
|
|
59
|
+
<HotUpdaterLogo className="h-7 w-7 shrink-0" />
|
|
60
|
+
<div className="flex flex-col gap-0 group-data-[collapsible=icon]:hidden">
|
|
61
|
+
<span className="text-sm font-semibold tracking-tight text-sidebar-foreground leading-tight">
|
|
62
|
+
Hot Updater
|
|
63
|
+
</span>
|
|
64
|
+
<span className="text-[10px] text-sidebar-foreground/60 leading-tight">
|
|
65
|
+
Console
|
|
66
|
+
</span>
|
|
67
|
+
</div>
|
|
68
|
+
</Link>
|
|
69
|
+
</SidebarHeader>
|
|
70
|
+
|
|
71
|
+
<SidebarContent>
|
|
72
|
+
<SidebarGroup>
|
|
73
|
+
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
|
|
74
|
+
<SidebarGroupContent>
|
|
75
|
+
<SidebarMenu>
|
|
76
|
+
<SidebarMenuItem>
|
|
77
|
+
<SidebarMenuButton
|
|
78
|
+
isActive={isBundlesActive}
|
|
79
|
+
render={
|
|
80
|
+
<Link
|
|
81
|
+
to="/"
|
|
82
|
+
search={{
|
|
83
|
+
afterReleaseId: undefined,
|
|
84
|
+
beforeReleaseId: undefined,
|
|
85
|
+
channelId: undefined,
|
|
86
|
+
enabled: undefined,
|
|
87
|
+
releaseId: undefined,
|
|
88
|
+
platform: undefined,
|
|
89
|
+
targetAppVersion: undefined,
|
|
90
|
+
bundleId: undefined,
|
|
91
|
+
page: undefined,
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
}
|
|
95
|
+
tooltip="Bundles"
|
|
96
|
+
>
|
|
97
|
+
<Package />
|
|
98
|
+
<span>Bundles</span>
|
|
99
|
+
</SidebarMenuButton>
|
|
100
|
+
</SidebarMenuItem>
|
|
101
|
+
{analyticsCapability.status === "supported" ? (
|
|
102
|
+
<SidebarMenuItem>
|
|
103
|
+
<SidebarMenuButton
|
|
104
|
+
isActive={isAnalyticsActive}
|
|
105
|
+
render={<Link to="/analytics" />}
|
|
106
|
+
tooltip="Analytics"
|
|
107
|
+
>
|
|
108
|
+
<ChartNoAxesCombined />
|
|
109
|
+
<span>Analytics</span>
|
|
110
|
+
</SidebarMenuButton>
|
|
111
|
+
</SidebarMenuItem>
|
|
112
|
+
) : null}
|
|
113
|
+
{apiKeyCapability.data?.apiKeys ? (
|
|
114
|
+
<SidebarMenuItem>
|
|
115
|
+
<SidebarMenuButton
|
|
116
|
+
isActive={isApiKeysActive}
|
|
117
|
+
render={<Link to="/api-keys" />}
|
|
118
|
+
tooltip="API keys"
|
|
119
|
+
>
|
|
120
|
+
<KeyRound />
|
|
121
|
+
<span>API keys</span>
|
|
122
|
+
</SidebarMenuButton>
|
|
123
|
+
</SidebarMenuItem>
|
|
124
|
+
) : null}
|
|
125
|
+
<SidebarMenuItem>
|
|
126
|
+
<SidebarMenuButton
|
|
127
|
+
isActive={isSigningActive}
|
|
128
|
+
render={<Link to="/signing" />}
|
|
129
|
+
tooltip="Bundle signing"
|
|
130
|
+
>
|
|
131
|
+
<ShieldCheck />
|
|
132
|
+
<span>Bundle signing</span>
|
|
133
|
+
</SidebarMenuButton>
|
|
134
|
+
</SidebarMenuItem>
|
|
135
|
+
</SidebarMenu>
|
|
136
|
+
</SidebarGroupContent>
|
|
137
|
+
</SidebarGroup>
|
|
138
|
+
</SidebarContent>
|
|
139
|
+
|
|
140
|
+
<SidebarFooter>
|
|
141
|
+
<SidebarMenu>
|
|
142
|
+
<SidebarMenuItem>
|
|
143
|
+
<SidebarMenuButton
|
|
144
|
+
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
|
145
|
+
tooltip={theme === "dark" ? "Light mode" : "Dark mode"}
|
|
146
|
+
>
|
|
147
|
+
{theme === "dark" ? (
|
|
148
|
+
<Sun className="h-4 w-4" />
|
|
149
|
+
) : (
|
|
150
|
+
<Moon className="h-4 w-4" />
|
|
151
|
+
)}
|
|
152
|
+
<span>{theme === "dark" ? "Light mode" : "Dark mode"}</span>
|
|
153
|
+
</SidebarMenuButton>
|
|
154
|
+
</SidebarMenuItem>
|
|
155
|
+
</SidebarMenu>
|
|
156
|
+
</SidebarFooter>
|
|
157
|
+
</Sidebar>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cn } from "@/lib/utils";
|
|
2
|
+
|
|
3
|
+
interface BundleIdDisplayProps {
|
|
4
|
+
bundleId: string;
|
|
5
|
+
maxLength?: number;
|
|
6
|
+
className?: string;
|
|
7
|
+
fullOnMobile?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export function BundleIdDisplay({ bundleId, className }: BundleIdDisplayProps) {
|
|
10
|
+
return (
|
|
11
|
+
<span
|
|
12
|
+
translate="no"
|
|
13
|
+
className={cn("break-all font-mono text-xs tabular-nums", className)}
|
|
14
|
+
>
|
|
15
|
+
{bundleId}
|
|
16
|
+
</span>
|
|
17
|
+
);
|
|
18
|
+
}
|