1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-14 17:02:27 +00:00

refactor: migrate shadcn-components to Svelte 5 and TW4 (#551)

Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Kyle Mendell
2025-05-21 12:15:27 -05:00
committed by Elias Schneider
parent 05b443d984
commit 28c85990ba
197 changed files with 8142 additions and 7471 deletions

View File

@@ -5,7 +5,7 @@
import appConfigStore from '$lib/stores/application-configuration-store';
import userStore from '$lib/stores/user-store';
import { cn } from '$lib/utils/style';
import { LucideExternalLink, LucideSettings } from 'lucide-svelte';
import { LucideExternalLink, LucideSettings } from '@lucide/svelte';
import type { Snippet } from 'svelte';
import { fade, fly } from 'svelte/transition';
import type { LayoutData } from './$types';
@@ -41,14 +41,14 @@
<section>
<div class="bg-muted/40 flex min-h-[calc(100vh-64px)] w-full flex-col justify-between">
<main
in:fade={{ duration: 300 }}
in:fade={{ duration: 200 }}
class="mx-auto flex w-full max-w-[1640px] flex-col gap-x-8 gap-y-8 overflow-hidden p-4 md:p-8 lg:flex-row"
>
<div class="min-w-[200px] xl:min-w-[250px]">
<div in:fly={{ x: -15, duration: 300 }} class="sticky top-6">
<div in:fly={{ x: -15, duration: 200 }} class="sticky top-6">
<div class="mx-auto grid w-full gap-2">
<h1 class="mb-4 flex items-center gap-2 text-2xl font-semibold">
<LucideSettings class="h-5 w-5" />
<LucideSettings class="size-5" />
{m.settings()}
</h1>
</div>
@@ -62,7 +62,7 @@
? 'text-primary bg-card rounded-md px-3 py-1.5 font-medium shadow-sm transition-all'
: 'hover:text-foreground hover:bg-muted/70 rounded-md px-3 py-1.5 transition-all hover:-translate-y-[2px] hover:shadow-sm'
)}
style={`animation-delay: ${150 + i * 75}ms;`}
style={`animation-delay: ${150 + i * 50}ms;`}
>
{label}
</a>
@@ -75,7 +75,7 @@
style={`animation-delay: ${150 + links.length * 75}ms;`}
>
{m.update_pocket_id()}
<LucideExternalLink class="my-auto inline-block h-3 w-3" />
<LucideExternalLink class="my-auto inline-block size-3" />
</a>
{/if}
</nav>

View File

@@ -16,7 +16,7 @@
LucideAlertTriangle,
RectangleEllipsis,
UserCog
} from 'lucide-svelte';
} from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import AccountForm from './account-form.svelte';
import LocalePicker from './locale-picker.svelte';
@@ -49,7 +49,7 @@
async function createPasskey() {
try {
const opts = await webauthnService.getRegistrationOptions();
const attResp = await startRegistration({optionsJSON: opts});
const attResp = await startRegistration({ optionsJSON: opts });
const passkey = await webauthnService.finishRegistration(attResp);
passkeys = await webauthnService.listCredentials();
@@ -75,7 +75,7 @@
</Alert.Description>
</div>
<div>
<Button class="mt-2 md:mt-0" on:click={createPasskey}>
<Button class="mt-2 md:mt-0" onclick={createPasskey}>
{m.add_passkey()}
</Button>
</div>
@@ -100,7 +100,7 @@
<div class="flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
<div>
<Card.Title>
<RectangleEllipsis class="text-primary/80 h-5 w-5" />
<RectangleEllipsis class="text-primary/80 size-5" />
{m.login_code()}
</Card.Title>
<Card.Description>
@@ -108,7 +108,7 @@
</Card.Description>
</div>
<Button variant="outline" class="w-full" on:click={() => (showLoginCodeModal = true)}>
<Button variant="outline" class="w-full" onclick={() => (showLoginCodeModal = true)}>
{m.create()}
</Button>
</div>
@@ -124,7 +124,7 @@
<Card.Root>
<Card.Header>
<Card.Title>
<UserCog class="text-primary/80 h-5 w-5" />
<UserCog class="text-primary/80 size-5" />
{m.account_details()}
</Card.Title>
</Card.Header>
@@ -146,14 +146,14 @@
<div class="flex items-center justify-between">
<div>
<Card.Title>
<KeyRound class="text-primary/80 h-5 w-5" />
<KeyRound class="text-primary/80 size-5" />
{m.passkeys()}
</Card.Title>
<Card.Description>
{m.manage_your_passkeys_that_you_can_use_to_authenticate_yourself()}
</Card.Description>
</div>
<Button variant="outline" class="ml-3" on:click={createPasskey}>
<Button variant="outline" class="ml-3" onclick={createPasskey}>
{m.add_passkey()}
</Button>
</div>
@@ -173,14 +173,14 @@
<div class="flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
<div>
<Card.Title>
<RectangleEllipsis class="text-primary/80 h-5 w-5" />
<RectangleEllipsis class="text-primary/80 size-5" />
{m.login_code()}
</Card.Title>
<Card.Description>
{m.create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey()}
</Card.Description>
</div>
<Button variant="outline" on:click={() => (showLoginCodeModal = true)}>
<Button variant="outline" onclick={() => (showLoginCodeModal = true)}>
{m.create()}
</Button>
</div>
@@ -195,10 +195,9 @@
<div class="flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
<div>
<Card.Title>
<Languages class="text-primary/80 h-5 w-5" />
<Languages class="text-primary/80 size-5" />
{m.language()}
</Card.Title>
<Card.Description>
{m.select_the_language_you_want_to_use()}
</Card.Description>

View File

@@ -29,15 +29,9 @@
}
</script>
<Select.Root
selected={{
label: locales[currentLocale],
value: currentLocale
}}
onSelectedChange={(v) => updateLocale(v!.value)}
>
<Select.Root type="single" value={currentLocale} onValueChange={(v) => updateLocale(v as Locale)}>
<Select.Trigger class="h-9 max-w-[200px]" aria-label="Select locale">
<Select.Value>{locales[currentLocale]}</Select.Value>
{locales[currentLocale]}
</Select.Trigger>
<Select.Content>
{#each Object.entries(locales) as [value, label]}

View File

@@ -42,7 +42,7 @@
</script>
<Dialog.Root open={!!code} {onOpenChange}>
<Dialog.Content class="max-w-md">
<Dialog.Content class="max-w-md" onOpenAutoFocus={(e) => e.preventDefault()}>
<Dialog.Header>
<Dialog.Title>{m.login_code()}</Dialog.Title>
<Dialog.Description
@@ -64,8 +64,8 @@
class="mb-2"
value={loginCodeLink}
size={180}
color={$mode === 'dark' ? '#FFFFFF' : '#000000'}
backgroundColor={$mode === 'dark' ? '#000000' : '#FFFFFF'}
color={mode.current === 'dark' ? '#FFFFFF' : '#000000'}
backgroundColor={mode.current === 'dark' ? '#000000' : '#FFFFFF'}
/>
<CopyToClipboard value={loginCodeLink!}>
<p data-testId="login-code-link">{loginCodeLink!}</p>

View File

@@ -5,7 +5,7 @@
import WebauthnService from '$lib/services/webauthn-service';
import type { Passkey } from '$lib/types/passkey.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideKeyRound } from 'lucide-svelte';
import { LucideKeyRound } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import RenamePasskeyModal from './rename-passkey-modal.svelte';

View File

@@ -5,7 +5,7 @@
import ApiKeyService from '$lib/services/api-key-service';
import type { ApiKeyCreate, ApiKeyResponse } from '$lib/types/api-key.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideMinus, ShieldEllipsis, ShieldPlus } from 'lucide-svelte';
import { LucideMinus, ShieldEllipsis, ShieldPlus } from '@lucide/svelte';
import { slide } from 'svelte/transition';
import ApiKeyDialog from './api-key-dialog.svelte';
import ApiKeyForm from './api-key-form.svelte';
@@ -45,16 +45,16 @@
<div class="flex items-center justify-between">
<div>
<Card.Title>
<ShieldPlus class="text-primary/80 h-5 w-5" />
<ShieldPlus class="text-primary/80 size-5" />
{m.create_api_key()}
</Card.Title>
<Card.Description>{m.add_a_new_api_key_for_programmatic_access()}</Card.Description>
</div>
{#if !expandAddApiKey}
<Button on:click={() => (expandAddApiKey = true)}>{m.add_api_key()}</Button>
<Button onclick={() => (expandAddApiKey = true)}>{m.add_api_key()}</Button>
{:else}
<Button class="h-8 p-3" variant="ghost" on:click={() => (expandAddApiKey = false)}>
<LucideMinus class="h-5 w-5" />
<Button class="h-8 p-3" variant="ghost" onclick={() => (expandAddApiKey = false)}>
<LucideMinus class="size-5" />
</Button>
{/if}
</div>
@@ -73,7 +73,7 @@
<Card.Root>
<Card.Header>
<Card.Title>
<ShieldEllipsis class="text-primary/80 h-5 w-5" />
<ShieldEllipsis class="text-primary/80 size-5" />
{m.manage_api_keys()}
</Card.Title>
</Card.Header>

View File

@@ -19,7 +19,7 @@
</script>
<Dialog.Root open={!!apiKeyResponse} {onOpenChange}>
<Dialog.Content class="max-w-md" closeButton={false}>
<Dialog.Content class="max-w-md">
<Dialog.Header>
<Dialog.Title>{m.api_key_created()}</Dialog.Title>
<Dialog.Description>
@@ -45,7 +45,7 @@
</div>
{/if}
<Dialog.Footer class="mt-3">
<Button variant="default" on:click={() => onOpenChange(false)}>{m.close()}</Button>
<Button variant="default" onclick={() => onOpenChange(false)}>{m.close()}</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>

View File

@@ -8,7 +8,7 @@
import type { ApiKey } from '$lib/types/api-key.type';
import type { Paginated, SearchPaginationSortRequest } from '$lib/types/pagination.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideBan } from 'lucide-svelte';
import { LucideBan } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
let {
@@ -68,11 +68,8 @@
<Table.Cell>{formatDate(item.expiresAt)}</Table.Cell>
<Table.Cell>{formatDate(item.lastUsedAt)}</Table.Cell>
<Table.Cell class="flex justify-end">
<Button
on:click={() => revokeApiKey(item)}
size="sm"
variant="outline"
aria-label={m.revoke()}><LucideBan class="h-3 w-3 text-red-500" /></Button
<Button onclick={() => revokeApiKey(item)} size="sm" variant="outline" aria-label={m.revoke()}
><LucideBan class="size-3 text-red-500" /></Button
>
</Table.Cell>
{/snippet}

View File

@@ -5,7 +5,7 @@
import appConfigStore from '$lib/stores/application-configuration-store';
import type { AllAppConfig } from '$lib/types/application-configuration';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideImage, Mail, SlidersHorizontal, UserSearch } from 'lucide-svelte';
import { LucideImage, Mail, SlidersHorizontal, UserSearch } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import AppConfigEmailForm from './forms/app-config-email-form.svelte';
import AppConfigGeneralForm from './forms/app-config-general-form.svelte';

View File

@@ -106,11 +106,12 @@
<div class="grid gap-2">
<Label class="mb-0" for="smtp-tls">{m.smtp_tls_option()}</Label>
<Select.Root
selected={{ value: $inputs.smtpTls.value, label: tlsOptions[$inputs.smtpTls.value] }}
onSelectedChange={(v) => ($inputs.smtpTls.value = v!.value)}
type="single"
value={$inputs.smtpTls.value}
onValueChange={(v) => ($inputs.smtpTls.value = v as typeof $inputs.smtpTls.value)}
>
<Select.Trigger>
<Select.Value placeholder={m.email_tls_option()} />
<Select.Trigger class="w-full" placeholder={m.email_tls_option()}>
{tlsOptions[$inputs.smtpTls.value]}
</Select.Trigger>
<Select.Content>
<Select.Item value="none" label="None" />

View File

@@ -23,7 +23,7 @@
<div class="flex flex-col gap-8">
<ApplicationImage
id="favicon"
imageClass="h-14 w-14 p-2"
imageClass="size-14 p-2"
label={m.favicon()}
bind:image={favicon}
imageURL="/api/application-configuration/favicon"
@@ -31,7 +31,7 @@
/>
<ApplicationImage
id="logo-light"
imageClass="h-32 w-32"
imageClass="size-32"
label={m.light_mode_logo()}
bind:image={logoLight}
imageURL="/api/application-configuration/logo?light=true"
@@ -39,7 +39,7 @@
/>
<ApplicationImage
id="logo-dark"
imageClass="h-32 w-32"
imageClass="size-32"
label={m.dark_mode_logo()}
bind:image={logoDark}
imageURL="/api/application-configuration/logo?light=false"

View File

@@ -8,7 +8,7 @@
import clientSecretStore from '$lib/stores/client-secret-store';
import type { OidcClientCreateWithLogo } from '$lib/types/oidc.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideMinus, ShieldCheck, ShieldPlus } from 'lucide-svelte';
import { LucideMinus, ShieldCheck, ShieldPlus } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import { slide } from 'svelte/transition';
import OIDCClientForm from './oidc-client-form.svelte';
@@ -49,7 +49,7 @@
<div class="flex items-center justify-between">
<div>
<Card.Title>
<ShieldPlus class="text-primary/80 h-5 w-5" />
<ShieldPlus class="text-primary/80 size-5" />
{m.create_oidc_client()}
</Card.Title>
<Card.Description
@@ -59,10 +59,10 @@
>
</div>
{#if !expandAddClient}
<Button on:click={() => (expandAddClient = true)}>{m.add_oidc_client()}</Button>
<Button onclick={() => (expandAddClient = true)}>{m.add_oidc_client()}</Button>
{:else}
<Button class="h-8 p-3" variant="ghost" on:click={() => (expandAddClient = false)}>
<LucideMinus class="h-5 w-5" />
<Button class="h-8 p-3" variant="ghost" onclick={() => (expandAddClient = false)}>
<LucideMinus class="size-5" />
</Button>
{/if}
</div>
@@ -81,7 +81,7 @@
<Card.Root>
<Card.Header>
<Card.Title>
<ShieldCheck class="text-primary/80 h-5 w-5" />
<ShieldCheck class="text-primary/80 size-5" />
{m.manage_oidc_clients()}
</Card.Title>
</Card.Header>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { beforeNavigate } from '$app/navigation';
import { page } from '$app/stores';
import { page } from '$app/state';
import CollapsibleCard from '$lib/components/collapsible-card.svelte';
import { openConfirmDialog } from '$lib/components/confirm-dialog';
import CopyToClipboard from '$lib/components/copy-to-clipboard.svelte';
@@ -12,7 +12,7 @@
import clientSecretStore from '$lib/stores/client-secret-store';
import type { OidcClientCreateWithLogo } from '$lib/types/oidc.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideChevronLeft, LucideRefreshCcw } from 'lucide-svelte';
import { LucideChevronLeft, LucideRefreshCcw } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import { slide } from 'svelte/transition';
import OidcForm from '../oidc-client-form.svelte';
@@ -28,12 +28,12 @@
const oidcService = new OidcService();
const setupDetails = $state({
[m.authorization_url()]: `https://${$page.url.hostname}/authorize`,
[m.oidc_discovery_url()]: `https://${$page.url.hostname}/.well-known/openid-configuration`,
[m.token_url()]: `https://${$page.url.hostname}/api/oidc/token`,
[m.userinfo_url()]: `https://${$page.url.hostname}/api/oidc/userinfo`,
[m.logout_url()]: `https://${$page.url.hostname}/api/oidc/end-session`,
[m.certificate_url()]: `https://${$page.url.hostname}/.well-known/jwks.json`,
[m.authorization_url()]: `https://${page.url.hostname}/authorize`,
[m.oidc_discovery_url()]: `https://${page.url.hostname}/.well-known/openid-configuration`,
[m.token_url()]: `https://${page.url.hostname}/api/oidc/token`,
[m.userinfo_url()]: `https://${page.url.hostname}/api/oidc/userinfo`,
[m.logout_url()]: `https://${page.url.hostname}/api/oidc/end-session`,
[m.certificate_url()]: `https://${page.url.hostname}/.well-known/jwks.json`,
[m.pkce()]: client.pkceEnabled ? m.enabled() : m.disabled()
});
@@ -102,7 +102,7 @@
<div>
<a class="text-muted-foreground flex text-sm" href="/settings/admin/oidc-clients"
><LucideChevronLeft class="h-5 w-5" /> {m.back()}</a
><LucideChevronLeft class="size-5" /> {m.back()}</a
>
</div>
<Card.Root>
@@ -136,7 +136,7 @@
onclick={createClientSecret}
size="sm"
variant="ghost"
aria-label="Create new client secret"><LucideRefreshCcw class="h-3 w-3" /></Button
aria-label="Create new client secret"><LucideRefreshCcw class="size-3" /></Button
>
</div>
{/if}
@@ -157,7 +157,7 @@
{#if !showAllDetails}
<div class="mt-4 flex justify-center">
<Button on:click={() => (showAllDetails = true)} size="sm" variant="ghost"
<Button onclick={() => (showAllDetails = true)} size="sm" variant="ghost"
>{m.show_more_details()}</Button
>
</div>
@@ -177,6 +177,6 @@
>
<UserGroupSelection bind:selectedGroupIds={client.allowedUserGroupIds} />
<div class="mt-5 flex justify-end">
<Button on:click={() => updateUserGroupClients(client.allowedUserGroupIds)}>{m.save()}</Button>
<Button onclick={() => updateUserGroupClients(client.allowedUserGroupIds)}>{m.save()}</Button>
</div>
</CollapsibleCard>

View File

@@ -3,7 +3,7 @@
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { m } from '$lib/paraglide/messages';
import { LucideMinus, LucidePlus } from 'lucide-svelte';
import { LucideMinus, LucidePlus } from '@lucide/svelte';
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
@@ -27,14 +27,18 @@
<div class="flex flex-col gap-y-2">
{#each callbackURLs as _, i}
<div class="flex gap-x-2">
<Input data-testid={`callback-url-${i + 1}`} bind:value={callbackURLs[i]} />
<Input
aria-invalid={!!error}
data-testid={`callback-url-${i + 1}`}
bind:value={callbackURLs[i]}
/>
{#if callbackURLs.length > 1 || allowEmpty}
<Button
variant="outline"
size="sm"
on:click={() => (callbackURLs = callbackURLs.filter((_, index) => index !== i))}
onclick={() => (callbackURLs = callbackURLs.filter((_, index) => index !== i))}
>
<LucideMinus class="h-4 w-4" />
<LucideMinus class="size-4" />
</Button>
{/if}
</div>
@@ -42,15 +46,15 @@
</div>
</FormInput>
{#if error}
<p class="mt-1 text-sm text-red-500">{error}</p>
<p class="text-destructive mt-1 text-xs">{error}</p>
{/if}
<Button
class="mt-2"
variant="secondary"
size="sm"
on:click={() => (callbackURLs = [...callbackURLs, ''])}
onclick={() => (callbackURLs = [...callbackURLs, ''])}
>
<LucidePlus class="mr-1 h-4 w-4" />
<LucidePlus class="mr-1 size-4" />
{callbackURLs.length === 0 ? m.add() : m.add_another()}
</Button>
</div>

View File

@@ -112,7 +112,7 @@
<Label for="logo">{m.logo()}</Label>
<div class="mt-2 flex items-end gap-3">
{#if logoDataURL}
<div class="bg-muted h-32 w-32 rounded-2xl p-3">
<div class="bg-muted size-32 rounded-2xl p-3">
<img
class="m-auto max-h-full max-w-full object-contain"
src={logoDataURL}
@@ -132,7 +132,7 @@
</Button>
</FileInput>
{#if logoDataURL}
<Button variant="outline" on:click={resetLogo}>{m.remove_logo()}</Button>
<Button variant="outline" onclick={resetLogo}>{m.remove_logo()}</Button>
{/if}
</div>
</div>

View File

@@ -8,7 +8,7 @@
import type { OidcClient } from '$lib/types/oidc.type';
import type { Paginated, SearchPaginationSortRequest } from '$lib/types/pagination.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucidePencil, LucideTrash } from 'lucide-svelte';
import { LucidePencil, LucideTrash } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
let {
@@ -56,7 +56,7 @@
<Table.Cell class="w-8 font-medium">
{#if item.hasLogo}
<div class="bg-secondary rounded-2xl p-3">
<div class="h-8 w-8">
<div class="size-8">
<img
class="m-auto max-h-full max-w-full object-contain"
src="/api/oidc/clients/{item.id}/logo"
@@ -72,13 +72,10 @@
href="/settings/admin/oidc-clients/{item.id}"
size="sm"
variant="outline"
aria-label={m.edit()}><LucidePencil class="h-3 w-3 " /></Button
aria-label={m.edit()}><LucidePencil class="size-3 " /></Button
>
<Button
on:click={() => deleteClient(item)}
size="sm"
variant="outline"
aria-label={m.delete()}><LucideTrash class="h-3 w-3 text-red-500" /></Button
<Button onclick={() => deleteClient(item)} size="sm" variant="outline" aria-label={m.delete()}
><LucideTrash class="size-3 text-red-500" /></Button
>
</Table.Cell>
{/snippet}

View File

@@ -6,7 +6,7 @@
import UserGroupService from '$lib/services/user-group-service';
import type { UserGroupCreate } from '$lib/types/user-group.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideMinus, UserCog, UserPlus } from 'lucide-svelte';
import { LucideMinus, UserCog, UserPlus } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import { slide } from 'svelte/transition';
import UserGroupForm from './user-group-form.svelte';
@@ -45,17 +45,17 @@
<div class="flex items-center justify-between">
<div>
<Card.Title>
<UserPlus class="text-primary/80 h-5 w-5" />
<UserPlus class="text-primary/80 size-5" />
{m.create_user_group()}
</Card.Title>
<Card.Description>{m.create_a_new_group_that_can_be_assigned_to_users()}</Card.Description
>
</div>
{#if !expandAddUserGroup}
<Button on:click={() => (expandAddUserGroup = true)}>{m.add_group()}</Button>
<Button onclick={() => (expandAddUserGroup = true)}>{m.add_group()}</Button>
{:else}
<Button class="h-8 p-3" variant="ghost" on:click={() => (expandAddUserGroup = false)}>
<LucideMinus class="h-5 w-5" />
<Button class="h-8 p-3" variant="ghost" onclick={() => (expandAddUserGroup = false)}>
<LucideMinus class="size-5" />
</Button>
{/if}
</div>
@@ -74,7 +74,7 @@
<Card.Root>
<Card.Header>
<Card.Title>
<UserCog class="text-primary/80 h-5 w-5" />
<UserCog class="text-primary/80 size-5" />
{m.manage_user_groups()}
</Card.Title>
</Card.Header>

View File

@@ -9,7 +9,7 @@
import appConfigStore from '$lib/stores/application-configuration-store';
import type { UserGroupCreate } from '$lib/types/user-group.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideChevronLeft } from 'lucide-svelte';
import { LucideChevronLeft } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import UserGroupForm from '../user-group-form.svelte';
import UserSelection from '../user-selection.svelte';
@@ -62,10 +62,10 @@
<div class="flex items-center justify-between">
<a class="text-muted-foreground flex text-sm" href="/settings/admin/user-groups"
><LucideChevronLeft class="h-5 w-5" /> {m.back()}</a
><LucideChevronLeft class="size-5" /> {m.back()}</a
>
{#if !!userGroup.ldapId}
<Badge variant="default" class="">{m.ldap()}</Badge>
<Badge class="rounded-full" variant="default">{m.ldap()}</Badge>
{/if}
</div>
<Card.Root>
@@ -92,7 +92,7 @@
<div class="mt-5 flex justify-end">
<Button
disabled={!!userGroup.ldapId && $appConfigStore.ldapEnabled}
on:click={() => updateUserGroupUsers(userGroup.userIds)}>{m.save()}</Button
onclick={() => updateUserGroupUsers(userGroup.userIds)}>{m.save()}</Button
>
</div>
</Card.Content>

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { goto } from '$app/navigation';
import AdvancedTable from '$lib/components/advanced-table.svelte';
import { openConfirmDialog } from '$lib/components/confirm-dialog/';
import { Badge } from '$lib/components/ui/badge/index';
@@ -11,8 +12,8 @@
import type { Paginated, SearchPaginationSortRequest } from '$lib/types/pagination.type';
import type { UserGroup, UserGroupWithUserCount } from '$lib/types/user-group.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucidePencil, LucideTrash } from 'lucide-svelte';
import Ellipsis from 'lucide-svelte/icons/ellipsis';
import { LucidePencil, LucideTrash } from '@lucide/svelte';
import Ellipsis from '@lucide/svelte/icons/ellipsis';
import { toast } from 'svelte-sonner';
let {
@@ -64,28 +65,28 @@
<Table.Cell>{item.userCount}</Table.Cell>
{#if $appConfigStore.ldapEnabled}
<Table.Cell>
<Badge variant={item.ldapId ? 'default' : 'outline'}
<Badge class="rounded-full" variant={item.ldapId ? 'default' : 'outline'}
>{item.ldapId ? m.ldap() : m.local()}</Badge
>
</Table.Cell>
{/if}
<Table.Cell class="flex justify-end">
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild let:builder>
<Button aria-haspopup="true" size="icon" variant="ghost" builders={[builder]}>
<Ellipsis class="h-4 w-4" />
<DropdownMenu.Trigger>
<Button aria-haspopup="true" size="icon" variant="ghost">
<Ellipsis class="size-4" />
<span class="sr-only">{m.toggle_menu()}</span>
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<DropdownMenu.Item href="/settings/admin/user-groups/{item.id}"
><LucidePencil class="mr-2 h-4 w-4" /> {m.edit()}</DropdownMenu.Item
<DropdownMenu.Item onclick={() => goto(`/settings/admin/user-groups/${item.id}}`)}
><LucidePencil class="mr-2 size-4" /> {m.edit()}</DropdownMenu.Item
>
{#if !item.ldapId || !$appConfigStore.ldapEnabled}
<DropdownMenu.Item
class="text-red-500 focus:!text-red-700"
on:click={() => deleteUserGroup(item)}
><LucideTrash class="mr-2 h-4 w-4" />{m.delete()}</DropdownMenu.Item
onclick={() => deleteUserGroup(item)}
><LucideTrash class="mr-2 size-4" />{m.delete()}</DropdownMenu.Item
>
{/if}
</DropdownMenu.Content>

View File

@@ -6,7 +6,7 @@
import appConfigStore from '$lib/stores/application-configuration-store';
import type { UserCreate } from '$lib/types/user.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideMinus, UserPen, UserPlus } from 'lucide-svelte';
import { LucideMinus, UserPen, UserPlus } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import { slide } from 'svelte/transition';
import UserForm from './user-form.svelte';
@@ -45,7 +45,7 @@
<div class="flex items-center justify-between">
<div>
<Card.Title>
<UserPlus class="text-primary/80 h-5 w-5" />
<UserPlus class="text-primary/80 size-5" />
{m.create_user()}
</Card.Title>
<Card.Description
@@ -55,10 +55,10 @@
>
</div>
{#if !expandAddUser}
<Button on:click={() => (expandAddUser = true)}>{m.add_user()}</Button>
<Button onclick={() => (expandAddUser = true)}>{m.add_user()}</Button>
{:else}
<Button class="h-8 p-3" variant="ghost" on:click={() => (expandAddUser = false)}>
<LucideMinus class="h-5 w-5" />
<Button class="h-8 p-3" variant="ghost" onclick={() => (expandAddUser = false)}>
<LucideMinus class="size-5" />
</Button>
{/if}
</div>
@@ -77,7 +77,7 @@
<Card.Root>
<Card.Header>
<Card.Title>
<UserPen class="text-primary/80 h-5 w-5" />
<UserPen class="text-primary/80 size-5" />
{m.manage_users()}
</Card.Title>
</Card.Header>

View File

@@ -12,7 +12,7 @@
import appConfigStore from '$lib/stores/application-configuration-store';
import type { UserCreate } from '$lib/types/user.type';
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideChevronLeft } from 'lucide-svelte';
import { LucideChevronLeft } from '@lucide/svelte';
import { toast } from 'svelte-sonner';
import UserForm from '../user-form.svelte';
@@ -82,10 +82,10 @@
<div class="flex items-center justify-between">
<a class="text-muted-foreground flex text-sm" href="/settings/admin/users"
><LucideChevronLeft class="h-5 w-5" /> {m.back()}</a
><LucideChevronLeft class="size-5" /> {m.back()}</a
>
{#if !!user.ldapId}
<Badge variant="default" class="">{m.ldap()}</Badge>
<Badge class="rounded-full" variant="default">{m.ldap()}</Badge>
{/if}
</div>
<Card.Root>
@@ -119,7 +119,7 @@
/>
<div class="mt-5 flex justify-end">
<Button
on:click={() => updateUserGroups(user.userGroupIds)}
onclick={() => updateUserGroups(user.userGroupIds)}
disabled={!!user.ldapId && $appConfigStore.ldapEnabled}
type="submit">{m.save()}</Button
>
@@ -133,6 +133,6 @@
>
<CustomClaimsInput bind:customClaims={user.customClaims} />
<div class="mt-5 flex justify-end">
<Button on:click={updateCustomClaims} type="submit">{m.save()}</Button>
<Button onclick={updateCustomClaims} type="submit">{m.save()}</Button>
</div>
</CollapsibleCard>

View File

@@ -19,8 +19,8 @@
LucideTrash,
LucideUserCheck,
LucideUserX
} from 'lucide-svelte';
import Ellipsis from 'lucide-svelte/icons/ellipsis';
} from '@lucide/svelte';
import Ellipsis from '@lucide/svelte/icons/ellipsis';
import { toast } from 'svelte-sonner';
let {
@@ -116,16 +116,16 @@
<Table.Cell>{item.email}</Table.Cell>
<Table.Cell>{item.username}</Table.Cell>
<Table.Cell>
<Badge variant="outline">{item.isAdmin ? m.admin() : m.user()}</Badge>
<Badge class="rounded-full" variant="outline">{item.isAdmin ? m.admin() : m.user()}</Badge>
</Table.Cell>
<Table.Cell>
<Badge variant={item.disabled ? 'destructive' : 'default'}>
<Badge class="rounded-full" variant={item.disabled ? 'destructive' : 'default'}>
{item.disabled ? m.disabled() : m.enabled()}
</Badge>
</Table.Cell>
{#if $appConfigStore.ldapEnabled}
<Table.Cell>
<Badge variant={item.ldapId ? 'default' : 'outline'}
<Badge class="rounded-full" variant={item.ldapId ? 'default' : 'outline'}
>{item.ldapId ? m.ldap() : m.local()}</Badge
>
</Table.Cell>
@@ -133,24 +133,24 @@
<Table.Cell>
<DropdownMenu.Root>
<DropdownMenu.Trigger class={buttonVariants({ variant: 'ghost', size: 'icon' })}>
<Ellipsis class="h-4 w-4" />
<Ellipsis class="size-4" />
<span class="sr-only">{m.toggle_menu()}</span>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<DropdownMenu.Item onclick={() => (userIdToCreateOneTimeLink = item.id)}
><LucideLink class="mr-2 h-4 w-4" />{m.login_code()}</DropdownMenu.Item
><LucideLink class="mr-2 size-4" />{m.login_code()}</DropdownMenu.Item
>
<DropdownMenu.Item onclick={() => goto(`/settings/admin/users/${item.id}`)}
><LucidePencil class="mr-2 h-4 w-4" /> {m.edit()}</DropdownMenu.Item
><LucidePencil class="mr-2 size-4" /> {m.edit()}</DropdownMenu.Item
>
{#if !item.ldapId || !$appConfigStore.ldapEnabled}
{#if item.disabled}
<DropdownMenu.Item onclick={() => enableUser(item)}
><LucideUserCheck class="mr-2 h-4 w-4" />{m.enable()}</DropdownMenu.Item
><LucideUserCheck class="mr-2 size-4" />{m.enable()}</DropdownMenu.Item
>
{:else}
<DropdownMenu.Item onclick={() => disableUser(item)}
><LucideUserX class="mr-2 h-4 w-4" />{m.disable()}</DropdownMenu.Item
><LucideUserX class="mr-2 size-4" />{m.disable()}</DropdownMenu.Item
>
{/if}
{/if}
@@ -158,7 +158,7 @@
<DropdownMenu.Item
class="text-red-500 focus:!text-red-700"
onclick={() => deleteUser(item)}
><LucideTrash class="mr-2 h-4 w-4" />{m.delete()}</DropdownMenu.Item
><LucideTrash class="mr-2 size-4" />{m.delete()}</DropdownMenu.Item
>
{/if}
</DropdownMenu.Content>

View File

@@ -3,7 +3,7 @@
import * as Card from '$lib/components/ui/card';
import { m } from '$lib/paraglide/messages';
import userStore from '$lib/stores/user-store';
import { LogsIcon } from 'lucide-svelte';
import { LogsIcon } from '@lucide/svelte';
import AuditLogSwitcher from './audit-log-switcher.svelte';
let { data } = $props();
@@ -22,7 +22,7 @@
<Card.Root>
<Card.Header>
<Card.Title>
<LogsIcon class="text-primary/80 h-5 w-5" />
<LogsIcon class="text-primary/80 size-5" />
{m.audit_log()}
</Card.Title>
<Card.Description>{m.see_your_account_activities_from_the_last_3_months()}</Card.Description>

View File

@@ -50,9 +50,9 @@
<div class="mb-6 grid grid-cols-1 gap-4 md:grid-cols-3">
<div>
{#await auditLogService.listUsers()}
<Select.Root>
<Select.Root type="single">
<Select.Trigger class="w-full" disabled>
<Select.Value placeholder={m.all_users()} />
{m.all_users()}
</Select.Trigger>
</Select.Root>
{:then users}
@@ -70,29 +70,27 @@
{/await}
</div>
<div>
<Select.Root
selected={{
value: filters.event,
label: eventTypes[filters.event as keyof typeof eventTypes]
}}
onSelectedChange={(v) => (filters.event = v!.value)}
>
<Select.Trigger class="w-full">
<Select.Value placeholder={m.all_events()} />
</Select.Trigger>
<Select.Content>
<Select.Item value="">{m.all_events()}</Select.Item>
{#each Object.entries(eventTypes) as [value, label]}
<Select.Item {value}>{label}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
<SearchableSelect
class="w-full"
items={[
{ value: '', label: m.all_events() },
...Object.entries(eventTypes).map(([value, label]) => ({
value,
label
}))
]}
bind:value={filters.event}
/>
</div>
<div>
{#await auditLogService.listClientNames()}
<Select.Root>
<Select.Root
type="single"
value={filters.clientName}
onValueChange={(v) => (filters.clientName = v)}
>
<Select.Trigger class="w-full" disabled>
<Select.Value placeholder={m.all_clients()} />
{m.all_clients()}
</Select.Trigger>
</Select.Root>
{:then clientNames}