refactor: enforce eslint rules

This commit is contained in:
Elias Schneider
2026-07-28 23:51:16 +02:00
parent d5eb3fe62c
commit 9060291475
52 changed files with 174 additions and 178 deletions
+4 -2
View File
@@ -28,11 +28,13 @@ export default [
}
},
{
ignores: ['build/', '.svelte-kit/', 'dist/']
ignores: ['build/', '.svelte-kit/', 'dist/', 'src/lib/paraglide/', 'src/paraglide/']
},
{
rules: {
'@typescript-eslint/no-explicit-any': 'off'
'@typescript-eslint/no-explicit-any': 'off',
// Pocket ID does not support deployments under a SvelteKit base path
'svelte/no-navigation-without-resolve': 'off'
}
}
];
+66 -65
View File
@@ -1,67 +1,68 @@
{
"name": "pocket-id-frontend",
"version": "2.11.0",
"private": true,
"type": "module",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "vite dev --port 3000",
"build": "vite build",
"preview": "vite preview --port 3000",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"dependencies": {
"@opentelemetry/api": "^1.9.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.220.0",
"@opentelemetry/resources": "^2.8.0",
"@opentelemetry/sdk-trace-web": "^2.8.0",
"@opentelemetry/semantic-conventions": "^1.41.1",
"@simplewebauthn/browser": "^13.3.0",
"@tailwindcss/vite": "^4.3.0",
"axios": "^1.16.1",
"clsx": "^2.1.1",
"date-fns": "^4.2.1",
"qrcode": "^1.5.4",
"runed": "^0.37.1",
"sveltekit-superforms": "^2.30.1",
"tailwind-merge": "^3.6.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@inlang/paraglide-js": "^2.18.0",
"@inlang/plugin-m-function-matcher": "^2.2.6",
"@inlang/plugin-message-format": "^4.4.0",
"@internationalized/date": "^3.12.1",
"@lucide/svelte": "^1.16.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.60.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@types/node": "^25.9.0",
"@types/qrcode": "^1.5.6",
"bits-ui": "^2.18.1",
"eslint": "^10.4.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.17.1",
"formsnap": "^2.0.1",
"globals": "^17.6.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.8.3",
"prettier-plugin-svelte": "^3.5.2",
"prettier-plugin-tailwindcss": "^0.8.0",
"shadcn-svelte": "^1.3.0",
"svelte": "^5.55.8",
"svelte-check": "^4.4.8",
"svelte-sonner": "^1.1.1",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.3.0",
"tslib": "^2.8.1",
"tw-animate-css": "^1.4.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.4",
"vite": "^8.0.16",
"vite-plugin-compression": "^0.5.1"
}
"name": "pocket-id-frontend",
"version": "2.11.0",
"private": true,
"type": "module",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "vite dev --port 3000",
"build": "vite build",
"preview": "vite preview --port 3000",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"dependencies": {
"@opentelemetry/api": "^1.9.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.220.0",
"@opentelemetry/resources": "^2.8.0",
"@opentelemetry/sdk-trace-web": "^2.8.0",
"@opentelemetry/semantic-conventions": "^1.41.1",
"@simplewebauthn/browser": "^13.3.0",
"@tailwindcss/vite": "^4.3.0",
"axios": "^1.16.1",
"clsx": "^2.1.1",
"date-fns": "^4.2.1",
"qrcode": "^1.5.4",
"runed": "^0.37.1",
"sveltekit-superforms": "^2.30.1",
"tailwind-merge": "^3.6.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@inlang/paraglide-js": "^2.18.0",
"@inlang/plugin-m-function-matcher": "^2.2.6",
"@inlang/plugin-message-format": "^4.4.0",
"@internationalized/date": "^3.12.1",
"@lucide/svelte": "^1.16.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.60.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@types/node": "^25.9.0",
"@types/qrcode": "^1.5.6",
"bits-ui": "^2.18.1",
"eslint": "^10.4.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.17.1",
"formsnap": "^2.0.1",
"globals": "^17.6.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.8.3",
"prettier-plugin-svelte": "^3.5.2",
"prettier-plugin-tailwindcss": "^0.8.0",
"shadcn-svelte": "^1.3.0",
"svelte": "^5.55.8",
"svelte-check": "^4.4.8",
"svelte-sonner": "^1.1.1",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.3.0",
"tslib": "^2.8.1",
"tw-animate-css": "^1.4.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.4",
"vite": "^8.0.16",
"vite-plugin-compression": "^0.5.1"
}
}
@@ -68,10 +68,10 @@
$effect(() => {
if (filters) {
filters.userID;
filters.event;
filters.location;
filters.clientName;
void filters.userID;
void filters.event;
void filters.location;
void filters.clientName;
untrack(() => tableRef?.refresh());
}
});
@@ -94,7 +94,7 @@
if (!filters) return undefined;
return Object.fromEntries(
Object.entries(filters)
.filter(([_, value]) => value !== undefined && value !== null && value !== '')
.filter(([, value]) => value !== undefined && value !== null && value !== '')
.map(([key, value]) => [key, [value]])
);
}
@@ -16,7 +16,7 @@
let containerNode: HTMLElement | null = $state(null);
$effect(() => {
page.route;
void page.route;
applyAnimationDelays();
});
@@ -91,7 +91,7 @@
avoidCollisions={false}
strategy="absolute"
>
{#each filteredSuggestions as suggestion, index}
{#each filteredSuggestions as suggestion, index (suggestion)}
<div
role="button"
tabindex="0"
@@ -39,14 +39,14 @@
<div {...restProps}>
<FormInput>
<div class="flex flex-col gap-y-2">
{#each customClaims as _, i}
{#each customClaims as customClaim, i (customClaim)}
<div class="flex gap-x-2">
<AutoCompleteInput
placeholder={m.key()}
suggestions={filteredSuggestions}
bind:value={customClaims[i].key}
bind:value={customClaim.key}
/>
<Input placeholder={m.value()} bind:value={customClaims[i].value} />
<Input placeholder={m.value()} bind:value={customClaim.value} />
<Button
variant="outline"
size="sm"
@@ -33,7 +33,7 @@
<DropdownMenu.Trigger>
{#snippet child({ props })}
<Button {...props} variant="outline">
{#each items.filter((item) => selectedItems.includes(item.value)) as item}
{#each items.filter((item) => selectedItems.includes(item.value)) as item (item.value)}
<Badge variant="secondary">
{item.label}
</Badge>
@@ -43,7 +43,7 @@
{/snippet}
</DropdownMenu.Trigger>
<DropdownMenu.Content align="start" class="w-[var(--bits-dropdown-menu-anchor-width)]">
{#each items as item}
{#each items as item (item.value)}
<DropdownMenu.CheckboxItem
checked={selectedItems.includes(item.value)}
onCheckedChange={() => handleItemSelect(item.value)}
@@ -86,7 +86,7 @@
<div class="flex items-center justify-between w-full">
<div class="flex flex-wrap items-center gap-1">
{#if selectedItems.length > 0}
{#each selectedLabels as label}
{#each selectedLabels as label, i (i)}
<Badge variant="secondary">{label}</Badge>
{/each}
{:else}
@@ -118,7 +118,7 @@
{/if}
</Command.Empty>
<Command.Group class="max-h-60 overflow-y-auto">
{#each filteredItems as item}
{#each filteredItems as item (item.value)}
<Command.Item
aria-checked={selectedItems.includes(item.value)}
value={item.value}
@@ -100,7 +100,7 @@
{/if}
</Command.Empty>
<Command.Group>
{#each filteredItems as item}
{#each filteredItems as item (item.value)}
<Command.Item
value={item.value}
onSelect={() => {
@@ -79,7 +79,7 @@
{#if typeof parsedContent === 'string'}
{parsedContent}
{:else}
{#each parsedContent as part}
{#each parsedContent as part, i (i)}
{#if part.type === 'text'}
{part.content}
{:else if part.type === 'bold'}
+1 -1
View File
@@ -7,7 +7,7 @@
let error = $state(false);
$effect(() => {
props.src;
void props.src;
error = false;
});
</script>
@@ -89,7 +89,7 @@
{selectedExpiration}
</Select.Trigger>
<Select.Content>
{#each Object.keys(availableExpirations) as key}
{#each Object.keys(availableExpirations) as key (key)}
<Select.Item value={key}>{key}</Select.Item>
{/each}
</Select.Content>
@@ -33,7 +33,7 @@
description={m.view_the_groups_you_are_a_member_of()}
/>
{/if}
{#each customScopes as scope}
{#each customScopes as scope (scope)}
<ScopeItem
icon={LucideKeyRound}
name={infoByKey.get(scope)?.name ?? scope}
+2 -2
View File
@@ -82,7 +82,7 @@
aria-label={m.settings()}
data-sveltekit-keepfocus
>
{#each items as item, i}
{#each items as item, i (groupId(item, i))}
{#if item.children?.length}
{@const id = groupId(item, i)}
<div class="group">
@@ -110,7 +110,7 @@
class="border-border/50 ml-2 border-l pl-2"
transition:slide|local={{ duration: 120 }}
>
{#each item.children as child, j}
{#each item.children as child, j (child.href ?? child.label)}
<li>
<a
href={child.href}
@@ -5,17 +5,14 @@
import type { UserSignUp } from '$lib/types/user.type';
import { preventDefault } from '$lib/utils/event-util';
import { createForm } from '$lib/utils/form-util';
import { tryCatch } from '$lib/utils/try-catch-util';
import { emptyToUndefined, usernameSchema } from '$lib/utils/zod-util';
import { get } from 'svelte/store';
import { z } from 'zod/v4';
let {
callback,
isLoading
callback
}: {
callback: (user: UserSignUp) => Promise<boolean>;
isLoading: boolean;
} = $props();
const initialData: UserSignUp = {
@@ -35,18 +32,11 @@
const { inputs, ...form } = createForm<FormSchema>(formSchema, initialData);
let userData: UserSignUp | null = $state(null);
async function onSubmit() {
const data = form.validate();
if (!data) return;
isLoading = true;
const result = await tryCatch(callback(data));
if (result.data) {
userData = data;
isLoading = false;
}
await callback(data);
}
</script>
@@ -121,7 +121,7 @@
}
];
const actions: CreateAdvancedTableActions<SignupToken> = (_) => [
const actions: CreateAdvancedTableActions<SignupToken> = () => [
{
label: m.copy(),
icon: Copy,
@@ -140,7 +140,7 @@
{getExpirationLabel($inputs.ttl.value)}
</Select.Trigger>
<Select.Content>
{#each availableExpirations as expiration}
{#each availableExpirations as expiration (expiration.value)}
<Select.Item value={expiration.value.toString()}>
{expiration.label}
</Select.Item>
@@ -1,4 +1,4 @@
<script lang="ts" generics="TData, TValue">
<script lang="ts">
import { Badge } from '$lib/components/ui/badge/index.js';
import { Button } from '$lib/components/ui/button/index.js';
import * as Command from '$lib/components/ui/command/index.js';
@@ -15,7 +15,7 @@
options,
selectedValues = new Set<string | boolean>(),
showCheckboxes = true,
onChanged = (selected: Set<string | boolean>) => {}
onChanged = () => {}
}: {
title: string;
options: {
@@ -54,7 +54,7 @@
/>
{/if}
{#each filterableColumns as col}
{#each filterableColumns as col (col.column)}
<AdvancedTableFilter
title={col.name}
options={col.options}
@@ -201,7 +201,7 @@
{:else}
{#if !items}
<div>
{#each Array((tablePreferences.current.length || 10) + 1) as _}
{#each Array.from({ length: (tablePreferences.current.length || 10) + 1 }, (_, i) => i) as i (i)}
<div>
<Skeleton class="mt-3 h-[45px] w-full rounded-lg" />
</div>
@@ -222,7 +222,7 @@
</Table.Head>
{/if}
{#each visibleColumns as column}
{#each visibleColumns as column (column.key ?? column.column ?? column.label)}
<Table.Head
class={cn(column.sortable && 'p-0')}
aria-sort={column.sortable
@@ -266,7 +266,7 @@
</Table.Row>
</Table.Header>
<Table.Body>
{#each items.data as item}
{#each items.data as item (item.id)}
<Table.Row
class={{
'bg-muted/20': selectedIds?.includes(item.id),
@@ -283,7 +283,7 @@
/>
</Table.Cell>
{/if}
{#each visibleColumns as column}
{#each visibleColumns as column (column.key ?? column.column ?? column.label)}
<Table.Cell>
{#if column.value}
{column.value(item)}
@@ -306,7 +306,7 @@
<span class="sr-only">{m.toggle_menu()}</span>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
{#each actions(item).filter((a) => !a.hidden) as action}
{#each actions(item).filter((a) => !a.hidden) as action (action.label)}
<DropdownMenu.Item
onclick={() => action.onClick(item)}
disabled={action.disabled}
@@ -342,7 +342,7 @@
{items?.pagination.itemsPerPage}
</Select.Trigger>
<Select.Content>
{#each availablePageSizes as size}
{#each availablePageSizes as size (size)}
<Select.Item value={size.toString()}>{size}</Select.Item>
{/each}
</Select.Content>
@@ -22,7 +22,7 @@
function onTabChange(newValue: string) {
if (useHash && page.url.hash !== newValue) {
history.replaceState(history.state, "",location.pathname + location.search + `#${newValue}`);
history.replaceState(history.state, '', location.pathname + location.search + `#${newValue}`);
}
}
</script>
@@ -108,7 +108,9 @@ function parseValue(value: string) {
return parsed;
}
value = String(parsed);
} catch {}
} catch {
// Keep the original string when the value is not valid JSON
}
// Handle rest of the types
if (value === 'true') {
-2
View File
@@ -5,9 +5,7 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, 'child'> : T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, 'children'> : T;
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
+2 -2
View File
@@ -237,13 +237,13 @@
>
{#snippet children({ cells })}
<InputOTP.Group>
{#each cells.slice(0, 4) as cell}
{#each cells.slice(0, 4) as cell (cell)}
<InputOTP.Slot {cell} />
{/each}
</InputOTP.Group>
<InputOTP.Separator />
<InputOTP.Group>
{#each cells.slice(4) as cell}
{#each cells.slice(4) as cell (cell)}
<InputOTP.Slot {cell} />
{/each}
</InputOTP.Group>
@@ -2,15 +2,9 @@
import SignInWrapper from '$lib/components/login-wrapper.svelte';
import { Button } from '$lib/components/ui/button';
import { m } from '$lib/paraglide/messages';
import OidcService from '$lib/services/oidc-service';
import WebAuthnService from '$lib/services/webauthn-service';
import userStore from '$lib/stores/user-store';
import ClientProviderImages from '../../authorize/components/client-provider-images.svelte';
import type { PageProps } from './$types';
const webauthnService = new WebAuthnService();
const oidcService = new OidcService();
let { data }: PageProps = $props();
let { error } = data;
</script>
@@ -51,7 +51,7 @@
{m.if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods()}
</p>
<Item.Group class="mt-5 gap-3">
{#each methods as method}
{#each methods as method (method.href)}
<Item.Root variant="outline" class="gap-5">
{#snippet child({ props })}
<a href={method.href + page.url.search} {...props}>
@@ -41,7 +41,7 @@
try {
goto(data.redirect);
} catch (e) {
} catch {
error = m.invalid_redirect_url();
}
} catch (e) {
@@ -94,7 +94,7 @@
<InputOTP.Root maxlength={6} bind:value={code} autofocus>
{#snippet children({ cells })}
<InputOTP.Group>
{#each cells as cell}
{#each cells as cell (cell)}
<InputOTP.Slot {cell} />
{/each}
</InputOTP.Group>
+4 -1
View File
@@ -36,7 +36,10 @@
{ href: '/settings/admin/oidc-clients', label: m.oidc_clients() },
{ href: '/settings/admin/apis', label: m.apis() },
{ href: '/settings/admin/api-keys', label: m.api_keys() },
{ href: '/settings/admin/application-configuration', label: m.application_configuration() }
{
href: '/settings/admin/application-configuration',
label: m.application_configuration()
}
];
if (user?.isAdmin || $userStore?.isAdmin) {
+1 -1
View File
@@ -7,7 +7,7 @@ export const load: LayoutLoad = async () => {
const currentVersion = versionService.getCurrentVersion();
let newestVersion = null;
let isUpToDate = true;
let isUpToDate: boolean;
try {
newestVersion = await versionService.getNewestVersion();
// If newestVersion is empty, it means the check is disabled or failed.
@@ -10,7 +10,7 @@
import appConfigStore from '$lib/stores/application-configuration-store';
import userStore from '$lib/stores/user-store';
import type { Passkey } from '$lib/types/passkey.type';
import type { AccountUpdate, UserCreate } from '$lib/types/user.type';
import type { AccountUpdate } from '$lib/types/user.type';
import { axiosErrorToast, getWebauthnErrorMessage } from '$lib/utils/error-util';
import {
KeyRound,
@@ -50,7 +50,7 @@
{locales[currentLocale]}
</Select.Trigger>
<Select.Content class="max-h-100">
{#each Object.entries(locales) as [value, label]}
{#each Object.entries(locales) as [value, label] (value)}
<Select.Item {value}>{label}</Select.Item>
{/each}
</Select.Content>
@@ -38,7 +38,7 @@
</script>
<Item.Group class="mt-3">
{#each passkeys as passkey}
{#each passkeys as passkey (passkey.id)}
<GlassRowItem
label={passkey.name}
description={m.added_on() + ' ' + new Date(passkey.createdAt).toLocaleDateString()}
@@ -6,6 +6,7 @@
import { preventDefault } from '$lib/utils/event-util';
import { createForm } from '$lib/utils/form-util';
import { emptyToUndefined } from '$lib/utils/zod-util';
import { SvelteDate } from 'svelte/reactivity';
import { z } from 'zod/v4';
let {
@@ -17,7 +18,7 @@
let isLoading = $state(false);
// Set default expiration to 30 days from now
const defaultExpiry = new Date();
const defaultExpiry = new SvelteDate();
defaultExpiry.setDate(defaultExpiry.getDate() + 30);
defaultExpiry.setHours(0, 0, 0, 0);
@@ -11,15 +11,15 @@
</script>
<div class="flex flex-col gap-y-3">
{#each permissions as _, i}
{#each permissions as permission, i (permission)}
<div class="flex flex-col gap-2 sm:flex-row sm:items-center">
<Input
class="font-mono sm:w-1/3"
placeholder={m.api_permission_key()}
bind:value={permissions[i].key}
bind:value={permission.key}
/>
<Input class="sm:w-1/4" placeholder={m.name()} bind:value={permissions[i].name} />
<Input placeholder={m.description()} bind:value={permissions[i].description} />
<Input class="sm:w-1/4" placeholder={m.name()} bind:value={permission.name} />
<Input placeholder={m.description()} bind:value={permission.description} />
<Button
variant="outline"
size="sm"
@@ -27,7 +27,7 @@
{ label: m.api_permissions(), key: 'permissions', value: (item) => item.permissions.length }
];
const actions: CreateAdvancedTableActions<Api> = (api) => [
const actions: CreateAdvancedTableActions<Api> = () => [
{
label: m.edit(),
primary: true,
@@ -42,7 +42,7 @@
}
}}
>
{#each accentColors as accent}
{#each accentColors as accent (accent.color)}
{@render colorOption(accent.label, accent.color, selectedColor === accent.color)}
{/each}
{#if isCustomColor || isPreviousColorCustom}
@@ -95,17 +95,15 @@
await callback(data);
// Update the app config to don't display the unsaved changes warning
Object.entries(data).forEach(([key, value]) => {
// @ts-ignore
appConfig[key] = value;
});
Object.assign(appConfig, data);
toast.success(m.email_configuration_updated_successfully());
return true;
}
async function onTestEmail() {
// @ts-ignore
const hasChanges = Object.keys($inputs).some((key) => $inputs[key].value !== appConfig[key]);
const hasChanges = Object.entries($inputs).some(
([key, input]) => input.value !== appConfig[key as keyof AllAppConfig]
);
if (hasChanges) {
openConfirmDialog({
@@ -83,7 +83,7 @@
?.label ?? $inputs.homePageUrl.value}
</Select.Trigger>
<Select.Content>
{#each homePageUrlOptions as option}
{#each homePageUrlOptions as option (option.value)}
<Select.Item value={option.value}>
{option.label}
</Select.Item>
@@ -294,7 +294,7 @@
{/if}
{#if showAllDetails}
<div transition:slide>
{#each Object.entries(setupDetails) as [key, value]}
{#each Object.entries(setupDetails) as [key, value] (key)}
<div class="mb-2 flex flex-col sm:flex-row sm:items-center">
<Field.Label class="w-52">{key}</Field.Label>
<CopyToClipboard {value}>
@@ -93,7 +93,7 @@
</Table.Row>
</Table.Header>
<Table.Body>
{#each apis as api}
{#each apis as api (api.id)}
<Table.Row>
<Table.Cell>
<div class="flex flex-col gap-1">
@@ -66,10 +66,9 @@
}
async function onSync() {
const hasChanges = Object.keys($inputs).some(
// @ts-ignore
(key) => $inputs[key].value !== (existingProvider as any)[key]
);
const hasChanges =
$inputs.endpoint.value !== existingProvider?.endpoint ||
($inputs.token?.value ?? '') !== (existingProvider?.token ?? '');
if (hasChanges) {
openConfirmDialog({
@@ -5,19 +5,17 @@
import * as Field from '$lib/components/ui/field';
import { Input } from '$lib/components/ui/input';
import { m } from '$lib/paraglide/messages';
import type { OidcClient, OidcClientFederatedIdentity } from '$lib/types/oidc.type';
import type { OidcClientFederatedIdentity } from '$lib/types/oidc.type';
import { LucideMinus, LucidePlus } from '@lucide/svelte';
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
import { z } from 'zod/v4';
let {
client,
federatedIdentities = $bindable([]),
errors,
...restProps
}: HTMLAttributes<HTMLDivElement> & {
client?: OidcClient;
federatedIdentities: OidcClientFederatedIdentity[];
errors?: z.core.$ZodIssue[];
@@ -66,7 +64,7 @@
docsLink="https://pocket-id.org/docs/guides/oidc-client-authentication"
>
<div class="space-y-4">
{#each federatedIdentities as identity, i}
{#each federatedIdentities as identity, i (identity)}
<div class="space-y-3 rounded-lg border p-4">
<div class="flex items-center justify-between">
<Field.Label>Identity {i + 1}</Field.Label>
@@ -26,7 +26,7 @@
<div {...restProps}>
<FormInput {label} {description}>
<div class="flex flex-col gap-y-2">
{#each callbackURLs as _, i}
{#each callbackURLs.keys() as i (i)}
<div class="flex gap-x-2">
<Input
aria-invalid={!!error}
@@ -154,7 +154,9 @@
darkLogo = input;
darkLogoDataURL = URL.createObjectURL(input);
}
logoUrlInput && (logoUrlInput.value = '');
if (logoUrlInput) {
logoUrlInput.value = '';
}
}
}
@@ -162,11 +164,15 @@
if (light) {
logo = null;
logoDataURL = null;
$inputs.logoUrl && ($inputs.logoUrl.value = '');
if ($inputs.logoUrl) {
$inputs.logoUrl.value = '';
}
} else {
darkLogo = null;
darkLogoDataURL = null;
$inputs.darkLogoUrl && ($inputs.darkLogoUrl.value = '');
if ($inputs.darkLogoUrl) {
$inputs.darkLogoUrl.value = '';
}
}
}
@@ -317,7 +323,6 @@
/>
{/if}
<FederatedIdentitiesInput
client={existingClient}
bind:federatedIdentities={$inputs.credentials.value.federatedIdentities}
errors={getFederatedIdentityErrors($errors)}
/>
@@ -79,7 +79,7 @@
}
];
const actions: CreateAdvancedTableActions<OidcClientWithAllowedUserGroupsCount> = (_) => [
const actions: CreateAdvancedTableActions<OidcClientWithAllowedUserGroupsCount> = () => [
{
label: m.edit(),
primary: true,
@@ -190,7 +190,7 @@
</CopyToClipboard>
</div>
<div class="space-y-3">
{#each Object.entries(data || {}) as [key, value]}
{#each Object.entries(data || {}) as [key, value] (key)}
<div class="grid grid-cols-1 items-start gap-4 border-b pb-3 md:grid-cols-[200px_1fr]">
<Field.Label class="pt-1">{key}</Field.Label>
<div class="min-w-0">
@@ -39,7 +39,7 @@
}
}
function onNameInput(_: Event) {
function onNameInput() {
hasManualNameEdit = true;
}
@@ -45,7 +45,7 @@
</script>
<Item.Group class="mt-3">
{#each [...passkeys].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) as passkey}
{#each [...passkeys].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) as passkey (passkey.id)}
<PasskeyRow
label={passkey.name}
description={m.added_on() + ' ' + new Date(passkey.createdAt).toLocaleDateString()}
@@ -80,7 +80,7 @@
class="grid gap-3"
style="grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));"
>
{#each clients.data as client}
{#each clients.data as client (client.id)}
<AuthorizedOidcClientCard {client} onRevoke={revokeAuthorizedClient} />
{/each}
<!-- Gap fix if two elements are present-->
+1 -6
View File
@@ -18,22 +18,17 @@
let { data } = $props();
const userService = new UserService();
let isLoading = $state(false);
let error: string | undefined = $state();
async function handleSignup(userData: UserSignUp) {
isLoading = true;
const result = await tryCatch(userService.signup({ ...userData, token: data.token }));
if (result.error) {
error = getAxiosErrorMessage(result.error);
isLoading = false;
return false;
}
await userStore.setUser(result.data);
isLoading = false;
goto('/signup/add-passkey');
return true;
@@ -75,7 +70,7 @@
</p>
{/if}
{#if $appConfigStore.allowUserSignups === 'open' || data.token}
<SignupForm callback={handleSignup} {isLoading} />
<SignupForm callback={handleSignup} />
<div class="mt-10 flex w-full items-center justify-between gap-2">
<a class="text-muted-foreground mt-5 flex text-sm" href="/login"
><LucideChevronLeft class="size-5" /> {m.back()}</a
@@ -13,25 +13,19 @@
import { fade } from 'svelte/transition';
import LoginLogoErrorSuccessIndicator from '../../login/components/login-logo-error-success-indicator.svelte';
let { data } = $props();
const userService = new UserService();
let isLoading = $state(false);
let error: string | undefined = $state();
async function handleSignup(userData: UserSignUp) {
isLoading = true;
const result = await tryCatch(userService.signupInitialUser(userData));
if (result.error) {
error = getAxiosErrorMessage(result.error);
isLoading = false;
return false;
}
await userStore.setUser(result.data);
isLoading = false;
goto('/signup/add-passkey');
return true;
@@ -61,7 +55,7 @@
</p>
{/if}
<SignupForm callback={handleSignup} {isLoading} />
<SignupForm callback={handleSignup} />
<div class="mt-10 flex w-full justify-end">
<Button type="submit" form="sign-up-form" onclick={() => (error = undefined)}
>{m.signup()}</Button
+16
View File
@@ -111,6 +111,9 @@ importers:
specifier: ^4.4.3
version: 4.4.3
devDependencies:
'@eslint/js':
specifier: ^10.0.1
version: 10.0.1(eslint@10.7.0(jiti@2.7.0))
'@inlang/paraglide-js':
specifier: ^2.18.0
version: 2.22.0(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.5)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.1)(yaml@2.9.0))
@@ -483,6 +486,15 @@ packages:
resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
'@eslint/js@10.0.1':
resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
peerDependencies:
eslint: ^10.0.0
peerDependenciesMeta:
eslint:
optional: true
'@eslint/object-schema@3.0.5':
resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
@@ -3366,6 +3378,10 @@ snapshots:
dependencies:
'@types/json-schema': 7.0.15
'@eslint/js@10.0.1(eslint@10.7.0(jiti@2.7.0))':
optionalDependencies:
eslint: 10.7.0(jiti@2.7.0)
'@eslint/object-schema@3.0.5': {}
'@eslint/plugin-kit@0.7.2':