mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-26 02:29:08 +01:00
refactor: enforce eslint rules
This commit is contained in:
@@ -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'}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-1
@@ -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}
|
||||
|
||||
+4
-6
@@ -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({
|
||||
|
||||
+1
-1
@@ -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">
|
||||
|
||||
+3
-4
@@ -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-->
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user