Compare commits

...

3 Commits

Author SHA1 Message Date
Elias Schneider
daced661c4 release: 0.21.0 2024-12-17 19:58:55 +01:00
Elias Schneider
0716c38fb8 feat: improve error state design for login page 2024-12-17 19:36:47 +01:00
Elias Schneider
789d9394a5 fix: OIDC client logo gets removed if other properties get updated 2024-12-17 19:00:33 +01:00
8 changed files with 66 additions and 17 deletions

View File

@@ -1 +1 @@
0.20.1 0.21.0

View File

@@ -1,3 +1,15 @@
## [](https://github.com/stonith404/pocket-id/compare/v0.20.1...v) (2024-12-17)
### Features
* improve error state design for login page ([0716c38](https://github.com/stonith404/pocket-id/commit/0716c38fb8ce7fa719c7fe0df750bdb213786c21))
### Bug Fixes
* OIDC client logo gets removed if other properties get updated ([789d939](https://github.com/stonith404/pocket-id/commit/789d9394a533831e7e2fb8dc3f6b338787336ad8))
## [](https://github.com/stonith404/pocket-id/compare/v0.20.0...v) (2024-12-13) ## [](https://github.com/stonith404/pocket-id/compare/v0.20.0...v) (2024-12-13)

View File

@@ -1,6 +1,6 @@
{ {
"name": "pocket-id-frontend", "name": "pocket-id-frontend",
"version": "0.20.1", "version": "0.21.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev --port 3000", "dev": "vite dev --port 3000",

View File

@@ -10,7 +10,7 @@ export type OidcClient = {
export type OidcClientCreate = Omit<OidcClient, 'id' | 'logoURL' | 'hasLogo'>; export type OidcClientCreate = Omit<OidcClient, 'id' | 'logoURL' | 'hasLogo'>;
export type OidcClientCreateWithLogo = OidcClientCreate & { export type OidcClientCreateWithLogo = OidcClientCreate & {
logo: File | null; logo: File | null | undefined;
}; };
export type AuthorizeResponse = { export type AuthorizeResponse = {

View File

@@ -1,19 +1,21 @@
<script> <script lang="ts">
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import SignInWrapper from '$lib/components/login-wrapper.svelte'; import SignInWrapper from '$lib/components/login-wrapper.svelte';
import Logo from '$lib/components/logo.svelte';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import WebAuthnService from '$lib/services/webauthn-service'; import WebAuthnService from '$lib/services/webauthn-service';
import appConfigStore from '$lib/stores/application-configuration-store'; import appConfigStore from '$lib/stores/application-configuration-store';
import userStore from '$lib/stores/user-store'; import userStore from '$lib/stores/user-store';
import { getWebauthnErrorMessage } from '$lib/utils/error-util'; import { getWebauthnErrorMessage } from '$lib/utils/error-util';
import { startAuthentication } from '@simplewebauthn/browser'; import { startAuthentication } from '@simplewebauthn/browser';
import { toast } from 'svelte-sonner'; import { fade } from 'svelte/transition';
import LoginLogoErrorIndicator from './components/login-logo-error-indicator.svelte';
const webauthnService = new WebAuthnService(); const webauthnService = new WebAuthnService();
let isLoading = $state(false); let isLoading = $state(false);
let error: string | undefined = $state(undefined);
async function authenticate() { async function authenticate() {
error = undefined;
isLoading = true; isLoading = true;
try { try {
const loginOptions = await webauthnService.getLoginOptions(); const loginOptions = await webauthnService.getLoginOptions();
@@ -23,7 +25,7 @@
userStore.setUser(user); userStore.setUser(user);
goto('/settings'); goto('/settings');
} catch (e) { } catch (e) {
toast.error(getWebauthnErrorMessage(e)); error = getWebauthnErrorMessage(e);
} }
isLoading = false; isLoading = false;
} }
@@ -35,15 +37,21 @@
<SignInWrapper> <SignInWrapper>
<div class="flex justify-center"> <div class="flex justify-center">
<div class="bg-muted rounded-2xl p-3"> <LoginLogoErrorIndicator error={!!error} />
<Logo class="h-10 w-10" />
</div>
</div> </div>
<h1 class="font-playfair mt-5 text-3xl font-bold sm:text-4xl"> <h1 class="font-playfair mt-5 text-3xl font-bold sm:text-4xl">
Sign in to {$appConfigStore.appName} Sign in to {$appConfigStore.appName}
</h1> </h1>
<p class="text-muted-foreground mt-2"> {#if error}
Authenticate yourself with your passkey to access the admin panel <p class="text-muted-foreground mt-2" in:fade>
</p> {error}. Please try to sign in again.
<Button class="mt-5" {isLoading} on:click={authenticate}>Authenticate</Button> </p>
{:else}
<p class="text-muted-foreground mt-2" in:fade>
Authenticate yourself with your passkey to access the admin panel.
</p>
{/if}
<Button class="mt-10" {isLoading} on:click={authenticate}
>{error ? 'Try again' : 'Authenticate'}</Button
>
</SignInWrapper> </SignInWrapper>

View File

@@ -0,0 +1,26 @@
<script lang="ts">
import Logo from '$lib/components/logo.svelte';
import CrossAnimated from '$lib/icons/cross-animated.svelte';
import { fade } from 'svelte/transition';
const {
error
}: {
error: boolean;
} = $props();
</script>
<div
class="rounded-2xl p-3 transition-[background-color] duration-300
{error ? 'bg-red-200' : 'bg-muted'}"
>
{#if error}
<div class="flex h-10 w-10 items-center justify-center">
<CrossAnimated class="h-5 w-5" />
</div>
{:else}
<div in:fade={{ duration: 300 }}>
<Logo class="h-10 w-10" />
</div>
{/if}
</div>

View File

@@ -33,7 +33,10 @@
async function updateClient(updatedClient: OidcClientCreateWithLogo) { async function updateClient(updatedClient: OidcClientCreateWithLogo) {
let success = true; let success = true;
const dataPromise = oidcService.updateClient(client.id, updatedClient); const dataPromise = oidcService.updateClient(client.id, updatedClient);
const imagePromise = oidcService.updateClientLogo(client, updatedClient.logo); const imagePromise =
updatedClient.logo !== undefined
? oidcService.updateClientLogo(client, updatedClient.logo)
: Promise.resolve();
client.isPublic = updatedClient.isPublic; client.isPublic = updatedClient.isPublic;

View File

@@ -22,7 +22,7 @@
} = $props(); } = $props();
let isLoading = $state(false); let isLoading = $state(false);
let logo = $state<File | null>(null); let logo = $state<File | null | undefined>();
let logoDataURL: string | null = $state( let logoDataURL: string | null = $state(
existingClient?.hasLogo ? `/api/oidc/clients/${existingClient!.id}/logo` : null existingClient?.hasLogo ? `/api/oidc/clients/${existingClient!.id}/logo` : null
); );
@@ -108,7 +108,7 @@
onchange={onLogoChange} onchange={onLogoChange}
> >
<Button variant="secondary"> <Button variant="secondary">
{existingClient?.hasLogo ? 'Change Logo' : 'Upload Logo'} {logoDataURL ? 'Change Logo' : 'Upload Logo'}
</Button> </Button>
</FileInput> </FileInput>
{#if logoDataURL} {#if logoDataURL}