From 5fb3ea465f0f9710cdbb68810f575b6a1da45c78 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Fri, 13 Jan 2023 17:04:59 -0500 Subject: [PATCH] fix(web): login error handling (#1322) --- web/src/app.d.ts | 6 + web/src/hooks.server.ts | 12 +- .../lib/components/forms/login-form.svelte | 24 ++-- .../notification/notification-card.svelte | 4 +- web/src/lib/utils/handle-error.ts | 8 +- web/src/routes/+error.svelte | 133 +++++++++++++++--- web/src/routes/+layout.svelte | 2 +- 7 files changed, 154 insertions(+), 35 deletions(-) diff --git a/web/src/app.d.ts b/web/src/app.d.ts index 13619596b..46398aad3 100644 --- a/web/src/app.d.ts +++ b/web/src/app.d.ts @@ -8,6 +8,12 @@ declare namespace App { } // interface Platform {} + + interface Error { + message: string; + stack?: string; + code?: string; + } } // Source: https://stackoverflow.com/questions/63814432/typescript-typing-of-non-standard-window-event-in-svelte diff --git a/web/src/hooks.server.ts b/web/src/hooks.server.ts index f06128448..0ed93b7b9 100644 --- a/web/src/hooks.server.ts +++ b/web/src/hooks.server.ts @@ -1,5 +1,15 @@ -import type { Handle } from '@sveltejs/kit'; +import type { Handle, HandleServerError } from '@sveltejs/kit'; +import { AxiosError } from 'axios'; export const handle: Handle = async ({ event, resolve }) => { return await resolve(event); }; + +export const handleError: HandleServerError = async ({ error }) => { + const httpError = error as AxiosError; + return { + message: httpError?.message || 'Hmm, not sure about that. Check the logs or open a ticket?', + stack: httpError?.stack, + code: httpError.code || '500' + }; +}; diff --git a/web/src/lib/components/forms/login-form.svelte b/web/src/lib/components/forms/login-form.svelte index 07ebf88c7..33ba0598a 100644 --- a/web/src/lib/components/forms/login-form.svelte +++ b/web/src/lib/components/forms/login-form.svelte @@ -2,6 +2,7 @@ import { goto } from '$app/navigation'; import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import { loginPageMessage } from '$lib/constants'; + import { handleError } from '$lib/utils/handle-error'; import { api, oauth, OAuthConfigResponseDto } from '@api'; import { createEventDispatcher, onMount } from 'svelte'; @@ -9,7 +10,7 @@ let email = ''; let password = ''; let oauthError: string; - let oauthConfig: OAuthConfigResponseDto = { enabled: false, passwordLoginEnabled: false }; + let authConfig: OAuthConfigResponseDto = { enabled: false, passwordLoginEnabled: false }; let loading = true; const dispatch = createEventDispatcher(); @@ -30,17 +31,18 @@ try { const { data } = await oauth.getConfig(window.location); - oauthConfig = data; + authConfig = data; - const { enabled, url, autoLaunch } = oauthConfig; + const { enabled, url, autoLaunch } = authConfig; if (enabled && url && autoLaunch && !oauth.isAutoLaunchDisabled(window.location)) { await goto('/auth/login?autoLaunch=0', { replaceState: true }); await goto(url); return; } - } catch (e) { - console.error('Error [login-form] [oauth.generateConfig]', e); + } catch (error) { + authConfig.passwordLoginEnabled = true; + handleError(error, 'Unable to connect!'); } loading = false; @@ -92,7 +94,7 @@ {:else} - {#if oauthConfig.passwordLoginEnabled} + {#if authConfig.passwordLoginEnabled}
@@ -133,26 +135,26 @@ {/if} - {#if oauthConfig.enabled} + {#if authConfig.enabled}
- {#if oauthConfig.passwordLoginEnabled} + {#if authConfig.passwordLoginEnabled}
{/if} {#if oauthError}

{oauthError}

{/if} - + {authConfig.buttonText || 'Login with OAuth'}
{/if} - {#if !oauthConfig.enabled && !oauthConfig.passwordLoginEnabled} + {#if !authConfig.enabled && !authConfig.passwordLoginEnabled}

Login has been disabled.

{/if} {/if} diff --git a/web/src/lib/components/shared-components/notification/notification-card.svelte b/web/src/lib/components/shared-components/notification/notification-card.svelte index fdf843e72..91d713aa2 100644 --- a/web/src/lib/components/shared-components/notification/notification-card.svelte +++ b/web/src/lib/components/shared-components/notification/notification-card.svelte @@ -90,5 +90,7 @@
-

{@html notificationInfo.message}

+

+ {@html notificationInfo.message} +

diff --git a/web/src/lib/utils/handle-error.ts b/web/src/lib/utils/handle-error.ts index 786719759..77c1d6b2f 100644 --- a/web/src/lib/utils/handle-error.ts +++ b/web/src/lib/utils/handle-error.ts @@ -6,8 +6,14 @@ import { export function handleError(error: unknown, message: string) { console.error(`[handleError]: ${message}`, error); + + let serverMessage = (error as ApiError)?.response?.data?.message; + if (serverMessage) { + serverMessage = `${String(serverMessage).slice(0, 50)}\n(Immich Server Error)`; + } + notificationController.show({ - message: (error as ApiError)?.response?.data?.message || message, + message: serverMessage || message, type: NotificationType.Error }); } diff --git a/web/src/routes/+error.svelte b/web/src/routes/+error.svelte index 902d3218f..d0b25f87e 100644 --- a/web/src/routes/+error.svelte +++ b/web/src/routes/+error.svelte @@ -1,29 +1,122 @@ -
-
- Error code {$page.status} -
- - {$page.error?.message} - -
-
-

Verbose

-
{JSON.stringify($page.error)}
+
+
+ +
- - +
+
- +
+
+

+ 🚨 Error - Something went wrong +

+
+ +
+
+ +
+ +
+
+

{$page.error?.message} - {$page.error?.code}

+ {#if $page.error?.stack} + +
{$page.error?.stack || 'No stack'}
+ {/if} +
+
+ +
+ + +
+
+
diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 2965b59cf..c9c1300a2 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -78,7 +78,7 @@ - {$page.data.meta?.title} - Immich + {$page.data.meta?.title || 'Web'} - Immich {#if $page.data.meta}