diff --git a/.vscode/settings.json b/.vscode/settings.json index d4d338f6..ec2392f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,7 +13,7 @@ }, "editor.defaultFormatter": "esbenp.prettier-vscode", "[vue]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index da980ba1..75528807 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -26,6 +26,7 @@ import { XIcon, } from '@modrinth/assets' import { + Admonition, Avatar, Button, ButtonStyled, @@ -36,8 +37,10 @@ import { ProgressSpinner, provideModrinthClient, provideNotificationManager, + useDebugLogger, } from '@modrinth/ui' import { renderString } from '@modrinth/utils' +import { useQuery } from '@tanstack/vue-query' import { getVersion } from '@tauri-apps/api/app' import { invoke } from '@tauri-apps/api/core' import { getCurrentWindow } from '@tauri-apps/api/window' @@ -71,6 +74,7 @@ import URLConfirmModal from '@/components/ui/URLConfirmModal.vue' import { useCheckDisableMouseover } from '@/composables/macCssFix.js' import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js' import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics' +import { check_reachable } from '@/helpers/auth.js' import { get_user } from '@/helpers/cache.js' import { command_listener, warning_listener } from '@/helpers/events.js' import { useFetch } from '@/helpers/fetch.js' @@ -139,6 +143,27 @@ const criticalErrorMessage = ref() const isMaximized = ref(false) +const authUnreachableDebug = useDebugLogger('AuthReachableChecker') +const authServerQuery = useQuery({ + queryKey: ['authServerReachability'], + queryFn: async () => { + await check_reachable() + authUnreachableDebug('Auth servers are reachable') + return true + }, + refetchInterval: 5 * 60 * 1000, // 5 minutes + retry: false, + refetchOnWindowFocus: false, +}) + +const authUnreachable = computed(() => { + if (authServerQuery.isError.value && !authServerQuery.isLoading.value) { + console.warn('Failed to reach auth servers', authServerQuery.error.value) + return true + } + return false +}) + onMounted(async () => { await useCheckDisableMouseover() @@ -177,6 +202,15 @@ const messages = defineMessages({ id: 'app.update.downloading-update', defaultMessage: 'Downloading update ({percent}%)', }, + authUnreachableHeader: { + id: 'app.auth-servers.unreachable.header', + defaultMessage: 'Cannot reach authentication servers', + }, + authUnreachableBody: { + id: 'app.auth-servers.unreachable.body', + defaultMessage: + 'Minecraft authentication servers may be down right now. Check your internet connection and try again later.', + }, }) async function setupApp() { @@ -325,7 +359,11 @@ const handleClose = async () => { const router = useRouter() router.afterEach((to, from, failure) => { - trackEvent('PageView', { path: to.path, fromPath: from.path, failed: failure }) + trackEvent('PageView', { + path: to.path, + fromPath: from.path, + failed: failure, + }) }) const route = useRoute() @@ -989,16 +1027,25 @@ provideAppUpdateDownloadProgress(appUpdateDownload) width: 'calc(100% - var(--right-bar-width))', }" > -
-

{{ criticalErrorMessage.header }}

-
+ + + {{ formatMessage(messages.authUnreachableBody) }} +