Skip to content

Commit 7ccc326

Browse files
IMB11Prospector
andauthored
feat: start of cross platform page system (#4731)
* feat: abstract api-client DI into ui package * feat: cross platform page system * feat: tanstack as cross platform useAsyncData * feat: archon servers routes + labrinth billing routes * fix: dont use partial * feat: migrate server list page to tanstack + api-client + re-enabled broken features! * feat: migrate servers manage page to api-client before page system * feat: migrate manage page to page system * fix: type issues * fix: upgrade wrapper bugs * refactor: move state types into api-client * feat: disable financial stuff on app frontend * feat: finalize cross platform page system for now * fix: lint * fix: build issues * feat: remove papaparse * fix: lint * fix: interface error --------- Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
1 parent 26feaf7 commit 7ccc326

File tree

79 files changed

+2631
-1259
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2631
-1259
lines changed

apps/app-frontend/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
"test": "vue-tsc --noEmit"
1414
},
1515
"dependencies": {
16-
"@sfirew/minecraft-motd-parser": "^1.1.6",
16+
"@modrinth/api-client": "workspace:^",
1717
"@modrinth/assets": "workspace:*",
1818
"@modrinth/ui": "workspace:*",
1919
"@modrinth/utils": "workspace:*",
2020
"@sentry/vue": "^8.27.0",
21+
"@sfirew/minecraft-motd-parser": "^1.1.6",
22+
"@tanstack/vue-query": "^5.90.7",
2123
"@tauri-apps/api": "^2.5.0",
2224
"@tauri-apps/plugin-dialog": "^2.2.1",
2325
"@tauri-apps/plugin-http": "^2.5.0",
@@ -41,9 +43,9 @@
4143
"vue-virtual-scroller": "v2.0.0-beta.8"
4244
},
4345
"devDependencies": {
44-
"@modrinth/tooling-config": "workspace:*",
4546
"@eslint/compat": "^1.1.1",
4647
"@formatjs/cli": "^6.2.12",
48+
"@modrinth/tooling-config": "workspace:*",
4749
"@nuxt/eslint-config": "^0.5.6",
4850
"@taijased/vue-render-tracker": "^1.0.7",
4951
"@vitejs/plugin-vue": "^5.0.4",

apps/app-frontend/src/App.vue

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup>
2+
import { AuthFeature, TauriModrinthClient } from '@modrinth/api-client'
23
import {
34
ArrowBigUpDashIcon,
45
ChangeSkinIcon,
@@ -18,6 +19,7 @@ import {
1819
RefreshCwIcon,
1920
RestoreIcon,
2021
RightArrowIcon,
22+
ServerIcon,
2123
SettingsIcon,
2224
UserIcon,
2325
WorldIcon,
@@ -32,6 +34,7 @@ import {
3234
NotificationPanel,
3335
OverflowMenu,
3436
ProgressSpinner,
37+
provideModrinthClient,
3538
provideNotificationManager,
3639
} from '@modrinth/ui'
3740
import { renderString } from '@modrinth/utils'
@@ -102,6 +105,16 @@ const notificationManager = new AppNotificationManager()
102105
provideNotificationManager(notificationManager)
103106
const { handleError, addNotification } = notificationManager
104107
108+
const tauriApiClient = new TauriModrinthClient({
109+
userAgent: `modrinth/theseus/${getVersion()} (support@modrinth.com)`,
110+
features: [
111+
new AuthFeature({
112+
token: async () => (await getCreds()).session,
113+
}),
114+
],
115+
})
116+
provideModrinthClient(tauriApiClient)
117+
105118
const news = ref([])
106119
const availableSurvey = ref(false)
107120
@@ -742,6 +755,13 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
742755
<NavButton v-if="themeStore.featureFlags.worlds_tab" v-tooltip.right="'Worlds'" to="/worlds">
743756
<WorldIcon />
744757
</NavButton>
758+
<NavButton
759+
v-if="themeStore.featureFlags.servers_in_app"
760+
v-tooltip.right="'Servers'"
761+
to="/servers/manage"
762+
>
763+
<ServerIcon />
764+
</NavButton>
745765
<NavButton
746766
v-tooltip.right="'Discover content'"
747767
to="/browse/modpack"

apps/app-frontend/src/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'floating-vue/dist/style.css'
22

33
import * as Sentry from '@sentry/vue'
44
import { VueScanPlugin } from '@taijased/vue-render-tracker'
5+
import { VueQueryPlugin } from '@tanstack/vue-query'
56
import { createPlugin } from '@vintl/vintl/plugin'
67
import FloatingVue from 'floating-vue'
78
import { createPinia } from 'pinia'
@@ -45,6 +46,7 @@ Sentry.init({
4546
tracesSampleRate: 0.1,
4647
})
4748

49+
app.use(VueQueryPlugin)
4850
app.use(vueScan)
4951
app.use(router)
5052
app.use(pinia)

apps/app-frontend/src/routes.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ServersManagePageIndex } from '@modrinth/ui'
12
import { createRouter, createWebHistory } from 'vue-router'
23

34
import * as Pages from '@/pages'
@@ -27,6 +28,14 @@ export default new createRouter({
2728
breadcrumb: [{ name: 'Worlds' }],
2829
},
2930
},
31+
{
32+
path: '/servers/manage/',
33+
name: 'Servers',
34+
component: ServersManagePageIndex,
35+
meta: {
36+
breadcrumb: [{ name: 'Servers' }],
37+
},
38+
},
3039
{
3140
path: '/browse/:projectType',
3241
name: 'Discover content',

apps/app-frontend/src/store/theme.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const DEFAULT_FEATURE_FLAGS = {
55
page_path: false,
66
worlds_tab: false,
77
worlds_in_home: true,
8+
servers_in_app: false,
89
}
910

1011
export const THEME_OPTIONS = ['dark', 'light', 'oled', 'system'] as const

apps/frontend/nuxt.config.ts

Lines changed: 11 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
import { pathToFileURL } from 'node:url'
22

33
import { match as matchLocale } from '@formatjs/intl-localematcher'
4+
import { GenericModrinthClient, type Labrinth } from '@modrinth/api-client'
45
import serverSidedVue from '@vitejs/plugin-vue'
56
import { consola } from 'consola'
67
import { promises as fs } from 'fs'
78
import { globIterate } from 'glob'
89
import { defineNuxtConfig } from 'nuxt/config'
9-
import { $fetch } from 'ofetch'
10-
import Papa from 'papaparse'
1110
import { basename, relative, resolve } from 'pathe'
1211
import svgLoader from 'vite-svg-loader'
1312

14-
import type { GeneratedState } from './src/composables/generated'
15-
1613
const STAGING_API_URL = 'https://staging-api.modrinth.com/v2/'
17-
// ISO 3166 data from https://github.com/ipregistry/iso3166
18-
// Licensed under CC BY-SA 4.0
19-
const ISO3166_REPO = 'https://raw.githubusercontent.com/ipregistry/iso3166/master'
2014

2115
const preloadedFonts = [
2216
'inter/Inter-Regular.woff2',
@@ -139,7 +133,7 @@ export default defineNuxtConfig({
139133
// 30 minutes
140134
const TTL = 30 * 60 * 1000
141135

142-
let state: Partial<GeneratedState> = {}
136+
let state: Partial<Labrinth.State.GeneratedState & Record<string, any>> = {}
143137

144138
try {
145139
state = JSON.parse(await fs.readFile('./src/generated/state.json', 'utf8'))
@@ -165,124 +159,19 @@ export default defineNuxtConfig({
165159
return
166160
}
167161

168-
state.lastGenerated = new Date().toISOString()
162+
const client = new GenericModrinthClient({
163+
labrinthBaseUrl: API_URL.replace('/v2/', ''),
164+
userAgent: 'Knossos generator (support@modrinth.com)',
165+
})
169166

167+
const generatedState = await client.labrinth.state.build()
168+
state.lastGenerated = new Date().toISOString()
170169
state.apiUrl = API_URL
171-
172-
const headers = {
173-
headers: {
174-
'user-agent': 'Knossos generator (support@modrinth.com)',
175-
},
176-
}
177-
178-
const caughtErrorCodes = new Set<number>()
179-
180-
function handleFetchError(err: any, defaultValue: any) {
181-
console.error('Error generating state: ', err)
182-
caughtErrorCodes.add(err.status)
183-
return defaultValue
170+
state = {
171+
...state,
172+
...generatedState,
184173
}
185174

186-
const [
187-
categories,
188-
loaders,
189-
gameVersions,
190-
donationPlatforms,
191-
reportTypes,
192-
homePageProjects,
193-
homePageSearch,
194-
homePageNotifs,
195-
products,
196-
muralBankDetails,
197-
countriesCSV,
198-
subdivisionsCSV,
199-
] = await Promise.all([
200-
$fetch(`${API_URL}tag/category`, headers).catch((err) => handleFetchError(err, [])),
201-
$fetch(`${API_URL}tag/loader`, headers).catch((err) => handleFetchError(err, [])),
202-
$fetch(`${API_URL}tag/game_version`, headers).catch((err) => handleFetchError(err, [])),
203-
$fetch(`${API_URL}tag/donation_platform`, headers).catch((err) =>
204-
handleFetchError(err, []),
205-
),
206-
$fetch(`${API_URL}tag/report_type`, headers).catch((err) => handleFetchError(err, [])),
207-
$fetch(`${API_URL}projects_random?count=60`, headers).catch((err) =>
208-
handleFetchError(err, []),
209-
),
210-
$fetch(`${API_URL}search?limit=3&query=leave&index=relevance`, headers).catch((err) =>
211-
handleFetchError(err, {}),
212-
),
213-
$fetch(`${API_URL}search?limit=3&query=&index=updated`, headers).catch((err) =>
214-
handleFetchError(err, {}),
215-
),
216-
$fetch(`${API_URL.replace('/v2/', '/_internal/')}billing/products`, headers).catch((err) =>
217-
handleFetchError(err, []),
218-
),
219-
$fetch(`${API_URL.replace('/v2/', '/_internal/')}mural/bank-details`, headers).catch(
220-
(err) => handleFetchError(err, null),
221-
),
222-
$fetch<string>(`${ISO3166_REPO}/countries.csv`, {
223-
...headers,
224-
responseType: 'text',
225-
}).catch((err) => handleFetchError(err, '')),
226-
$fetch<string>(`${ISO3166_REPO}/subdivisions.csv`, {
227-
...headers,
228-
responseType: 'text',
229-
}).catch((err) => handleFetchError(err, '')),
230-
])
231-
232-
const countriesData = Papa.parse(countriesCSV, {
233-
header: true,
234-
skipEmptyLines: true,
235-
transformHeader: (header) => (header.startsWith('#') ? header.slice(1) : header),
236-
}).data
237-
const subdivisionsData = Papa.parse(subdivisionsCSV, {
238-
header: true,
239-
skipEmptyLines: true,
240-
transformHeader: (header) => (header.startsWith('#') ? header.slice(1) : header),
241-
}).data
242-
243-
const subdivisionsByCountry = (subdivisionsData as any[]).reduce(
244-
(acc, sub) => {
245-
const countryCode = sub.country_code_alpha2
246-
247-
if (!countryCode || typeof countryCode !== 'string' || countryCode.trim() === '') {
248-
return acc
249-
}
250-
251-
if (!acc[countryCode]) acc[countryCode] = []
252-
253-
acc[countryCode].push({
254-
code: sub['subdivision_code_iso3166-2'],
255-
name: sub.subdivision_name,
256-
localVariant: sub.localVariant || null,
257-
category: sub.category,
258-
parent: sub.parent_subdivision || null,
259-
language: sub.language_code,
260-
})
261-
return acc
262-
},
263-
{} as Record<string, any[]>,
264-
)
265-
266-
state.categories = categories
267-
state.loaders = loaders
268-
state.gameVersions = gameVersions
269-
state.donationPlatforms = donationPlatforms
270-
state.reportTypes = reportTypes
271-
state.homePageProjects = homePageProjects
272-
state.homePageSearch = homePageSearch
273-
state.homePageNotifs = homePageNotifs
274-
state.products = products
275-
state.muralBankDetails = muralBankDetails.bankDetails
276-
state.countries = (countriesData as any[]).map((c) => ({
277-
alpha2: c.country_code_alpha2,
278-
alpha3: c.country_code_alpha3,
279-
numeric: c.numeric_code,
280-
nameShort: c.name_short,
281-
nameLong: c.name_long,
282-
}))
283-
state.subdivisions = subdivisionsByCountry
284-
state.errors = [...caughtErrorCodes]
285-
286175
await fs.writeFile('./src/generated/state.json', JSON.stringify(state))
287176

288177
console.log('Tags generated!')

apps/frontend/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
"@nuxt/devtools": "^1.3.3",
1919
"@types/dompurify": "^3.0.5",
2020
"@types/node": "^20.1.0",
21-
"@types/papaparse": "^5.3.15",
2221
"@vintl/compact-number": "^2.0.5",
2322
"@vintl/how-ago": "^3.0.1",
2423
"@vintl/nuxt": "^1.9.2",
@@ -38,13 +37,14 @@
3837
"@formatjs/intl-localematcher": "^0.5.4",
3938
"@intercom/messenger-js-sdk": "^0.0.14",
4039
"@ltd/j-toml": "^1.38.0",
40+
"@modrinth/api-client": "workspace:*",
4141
"@modrinth/assets": "workspace:*",
4242
"@modrinth/blog": "workspace:*",
4343
"@modrinth/moderation": "workspace:*",
4444
"@modrinth/ui": "workspace:*",
4545
"@modrinth/utils": "workspace:*",
46-
"@modrinth/api-client": "workspace:*",
4746
"@pinia/nuxt": "^0.5.1",
47+
"@tanstack/vue-query": "^5.90.7",
4848
"@types/three": "^0.172.0",
4949
"@vintl/vintl": "^4.4.1",
5050
"@vitejs/plugin-vue": "^5.0.4",
@@ -61,7 +61,6 @@
6161
"js-yaml": "^4.1.0",
6262
"jszip": "^3.10.1",
6363
"markdown-it": "14.1.0",
64-
"papaparse": "^5.4.1",
6564
"pathe": "^1.1.2",
6665
"pinia": "^2.1.7",
6766
"pinia-plugin-persistedstate": "^4.4.1",

apps/frontend/src/app.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
</NuxtLayout>
77
</template>
88
<script setup lang="ts">
9-
import { NotificationPanel, provideNotificationManager } from '@modrinth/ui'
9+
import { NotificationPanel, provideModrinthClient, provideNotificationManager } from '@modrinth/ui'
1010
1111
import ModrinthLoadingIndicator from '~/components/ui/modrinth-loading-indicator.ts'
12-
13-
import { createModrinthClient, provideModrinthClient } from './providers/api-client.ts'
14-
import { FrontendNotificationManager } from './providers/frontend-notifications.ts'
12+
import { createModrinthClient } from '~/helpers/api.ts'
13+
import { FrontendNotificationManager } from '~/providers/frontend-notifications.ts'
1514
1615
const auth = await useAuth()
1716
const config = useRuntimeConfig()

apps/frontend/src/components/ui/servers/PanelServerActionButton.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ import {
120120
UpdatedIcon,
121121
XIcon,
122122
} from '@modrinth/assets'
123-
import { ButtonStyled, Checkbox, NewModal } from '@modrinth/ui'
123+
import { ButtonStyled, Checkbox, NewModal, ServerInfoLabels } from '@modrinth/ui'
124124
import type { PowerAction as ServerPowerAction, ServerState } from '@modrinth/utils'
125125
import { useStorage } from '@vueuse/core'
126126
import { computed, ref } from 'vue'
@@ -130,7 +130,6 @@ import type { BackupInProgressReason } from '~/pages/servers/manage/[id].vue'
130130
131131
import LoadingIcon from './icons/LoadingIcon.vue'
132132
import PanelSpinner from './PanelSpinner.vue'
133-
import ServerInfoLabels from './ServerInfoLabels.vue'
134133
import TeleportOverflowMenu from './TeleportOverflowMenu.vue'
135134
136135
const flags = useFeatureFlags()

apps/frontend/src/components/ui/servers/ServerListingSkeleton.vue

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)