refactor: tables (#25226)

This commit is contained in:
Jason Rasmussen
2026-01-14 07:56:09 -05:00
committed by GitHub
parent c7254a0c30
commit 91d4cd6824
7 changed files with 184 additions and 189 deletions
@@ -8,7 +8,17 @@
import { locale } from '$lib/stores/preferences.store';
import { getBytesWithUnit } from '$lib/utils/byte-units';
import { getLibrary, getLibraryStatistics, type LibraryResponseDto } from '@immich/sdk';
import { Button, CommandPaletteDefaultProvider } from '@immich/ui';
import {
Button,
CommandPaletteDefaultProvider,
Container,
Table,
TableBody,
TableCell,
TableHeader,
TableHeading,
TableRow,
} from '@immich/ui';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
@@ -47,6 +57,15 @@
};
const { Create, ScanAll } = $derived(getLibrariesActions($t, libraries));
const classes = {
column1: 'w-4/12',
column2: 'w-4/12',
column3: 'w-2/12',
column4: 'w-2/12',
column5: 'w-2/12',
column6: 'w-2/12',
};
</script>
<OnEvents {onLibraryCreate} {onLibraryUpdate} {onLibraryDelete} />
@@ -54,51 +73,35 @@
<CommandPaletteDefaultProvider name={$t('library')} actions={[Create, ScanAll]} />
<AdminPageLayout breadcrumbs={[{ title: data.meta.title }]} actions={[ScanAll, Create]}>
<section class="my-4">
<Container size="large" center class="my-4">
<div class="flex flex-col items-center gap-2" in:fade={{ duration: 500 }}>
{#if libraries.length > 0}
<table class="text-start">
<thead
class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray"
>
<tr class="grid grid-cols-6 w-full place-items-center">
<th class="text-center text-sm font-medium">{$t('name')}</th>
<th class="text-center text-sm font-medium">{$t('owner')}</th>
<th class="text-center text-sm font-medium">{$t('photos')}</th>
<th class="text-center text-sm font-medium">{$t('videos')}</th>
<th class="text-center text-sm font-medium">{$t('size')}</th>
<th class="text-center text-sm font-medium"></th>
</tr>
</thead>
<tbody class="block overflow-y-auto rounded-md border dark:border-immich-dark-gray">
<Table striped>
<TableHeader>
<TableHeading class={classes.column1}>{$t('name')}</TableHeading>
<TableHeading class={classes.column2}>{$t('owner')}</TableHeading>
<TableHeading class={classes.column3}>{$t('photos')}</TableHeading>
<TableHeading class={classes.column4}>{$t('videos')}</TableHeading>
<TableHeading class={classes.column5}>{$t('size')}</TableHeading>
<TableHeading class={classes.column6}></TableHeading>
</TableHeader>
<TableBody>
{#each libraries as library (library.id + library.name)}
{@const { photos, usage, videos } = statistics[library.id]}
{@const [diskUsage, diskUsageUnit] = getBytesWithUnit(usage, 0)}
<tr
class="grid grid-cols-6 h-20 w-full place-items-center text-center dark:text-immich-dark-fg even:bg-subtle/20 odd:bg-subtle/80"
>
<td class="text-ellipsis px-4 text-sm">{library.name}</td>
<td class="text-ellipsis px-4 text-sm">
{owners[library.id].name}
</td>
<td class="text-ellipsis px-4 text-sm">
{photos.toLocaleString($locale)}
</td>
<td class="text-ellipsis px-4 text-sm">
{videos.toLocaleString($locale)}
</td>
<td class="text-ellipsis px-4 text-sm">
{diskUsage}
{diskUsageUnit}
</td>
<td class="flex gap-2 text-ellipsis px-4 text-sm">
<TableRow>
<TableCell class={classes.column1}>{library.name}</TableCell>
<TableCell class={classes.column2}>{owners[library.id].name}</TableCell>
<TableCell class={classes.column3}>{photos.toLocaleString($locale)}</TableCell>
<TableCell class={classes.column4}>{videos.toLocaleString($locale)}</TableCell>
<TableCell class={classes.column5}>{diskUsage} {diskUsageUnit}</TableCell>
<TableCell class={classes.column6}>
<Button size="small" onclick={() => handleViewLibrary(library)}>{$t('view')}</Button>
</td>
</tr>
</TableCell>
</TableRow>
{/each}
</tbody>
</table>
</TableBody>
</Table>
{:else}
<EmptyPlaceholder
text={$t('no_libraries_message')}
@@ -109,5 +112,5 @@
{@render children?.()}
</div>
</section>
</Container>
</AdminPageLayout>
@@ -5,7 +5,18 @@
import { locale } from '$lib/stores/preferences.store';
import { getByteUnitString } from '$lib/utils/byte-units';
import { searchUsersAdmin, type UserAdminResponseDto } from '@immich/sdk';
import { Button, CommandPaletteDefaultProvider, Container, Icon } from '@immich/ui';
import {
Button,
CommandPaletteDefaultProvider,
Container,
Icon,
Table,
TableBody,
TableCell,
TableHeader,
TableHeading,
TableRow,
} from '@immich/ui';
import { mdiInfinity } from '@mdi/js';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
@@ -34,6 +45,13 @@
};
const { Create } = $derived(getUserAdminsActions($t));
const classes = {
column1: 'w-8/12 sm:w-5/12 lg:w-6/12 xl:w-4/12 2xl:w-5/12',
column2: 'hidden sm:block w-3/12',
column3: 'hidden xl:block w-3/12 2xl:w-2/12',
column4: 'w-4/12 lg:w-3/12 xl:w-2/12',
};
</script>
<OnEvents
@@ -48,28 +66,19 @@
<AdminPageLayout breadcrumbs={[{ title: data.meta.title }]} actions={[Create]}>
<Container center size="large">
<table class="my-5 w-full text-start">
<thead
class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray"
>
<tr class="flex w-full place-items-center">
<th class="w-8/12 sm:w-5/12 lg:w-6/12 xl:w-4/12 2xl:w-5/12 text-center text-sm font-medium">{$t('email')}</th>
<th class="hidden sm:block w-3/12 text-center text-sm font-medium">{$t('name')}</th>
<th class="hidden xl:block w-3/12 2xl:w-2/12 text-center text-sm font-medium">{$t('has_quota')}</th>
</tr>
</thead>
<tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
<Table class="mt-4" striped spacing="large">
<TableHeader>
<TableHeading class={classes.column1}>{$t('email')}</TableHeading>
<TableHeading class={classes.column2}>{$t('name')}</TableHeading>
<TableHeading class={classes.column3}>{$t('has_quota')}</TableHeading>
</TableHeader>
<TableBody>
{#each users as user (user.id)}
<tr
class="flex h-20 overflow-hidden w-full place-items-center text-center dark:text-immich-dark-fg {user.deletedAt
? 'bg-red-300 dark:bg-red-900'
: 'even:bg-subtle/20 odd:bg-subtle/80'}"
>
<td class="w-8/12 sm:w-5/12 lg:w-6/12 xl:w-4/12 2xl:w-5/12 text-ellipsis break-all px-2 text-sm">
{user.email}
</td>
<td class="hidden sm:block w-3/12 text-ellipsis break-all px-2 text-sm">{user.name}</td>
<td class="hidden xl:block w-3/12 2xl:w-2/12 text-ellipsis break-all px-2 text-sm">
<TableRow color={user.deletedAt ? 'danger' : undefined}>
<TableCell class={classes.column1}>{user.email}</TableCell>
<TableCell class={classes.column2}>{user.name}</TableCell>
<TableCell class={classes.column3}>
<div class="container mx-auto flex flex-wrap justify-center">
{#if user.quotaSizeInBytes !== null && user.quotaSizeInBytes >= 0}
{getByteUnitString(user.quotaSizeInBytes, $locale)}
@@ -77,16 +86,14 @@
<Icon icon={mdiInfinity} size="16" />
{/if}
</div>
</td>
<td
class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-4/12 lg:w-3/12 xl:w-2/12 text-ellipsis break-all text-sm"
>
</TableCell>
<TableCell class={classes.column4}>
<Button onclick={() => handleNavigateUserAdmin(user)}>{$t('view')}</Button>
</td>
</tr>
</TableCell>
</TableRow>
{/each}
</tbody>
</table>
</TableBody>
</Table>
{@render children?.()}
</Container>