mirror of
https://github.com/immich-app/immich.git
synced 2026-03-26 20:00:44 +03:00
123 lines
4.7 KiB
Svelte
123 lines
4.7 KiB
Svelte
<script lang="ts">
|
|
import { goto, invalidate } from '$app/navigation';
|
|
import emptyFoldersUrl from '$lib/assets/empty-folders.svg';
|
|
import AdminCard from '$lib/components/AdminCard.svelte';
|
|
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
|
|
import OnEvents from '$lib/components/OnEvents.svelte';
|
|
import ServerStatisticsCard from '$lib/components/server-statistics/ServerStatisticsCard.svelte';
|
|
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
|
import TableButton from '$lib/components/TableButton.svelte';
|
|
import LibraryFolderAddModal from '$lib/modals/LibraryFolderAddModal.svelte';
|
|
import { Route } from '$lib/route';
|
|
import {
|
|
getLibraryActions,
|
|
getLibraryExclusionPatternActions,
|
|
getLibraryFolderActions,
|
|
} from '$lib/services/library.service';
|
|
import { getBytesWithUnit } from '$lib/utils/byte-units';
|
|
|
|
import { Code, CommandPaletteDefaultProvider, Container, Heading, modalManager } from '@immich/ui';
|
|
import { mdiCameraIris, mdiChartPie, mdiFilterMinusOutline, mdiFolderOutline, mdiPlayCircle } from '@mdi/js';
|
|
import type { Snippet } from 'svelte';
|
|
import { t } from 'svelte-i18n';
|
|
import type { LayoutData } from './$types';
|
|
|
|
type Props = {
|
|
children?: Snippet;
|
|
data: LayoutData;
|
|
};
|
|
|
|
let { children, data }: Props = $props();
|
|
|
|
const photosPromise = $derived(data.statisticsPromise.then((stats) => ({ value: stats.photos })));
|
|
|
|
const videosPromise = $derived(data.statisticsPromise.then((stats) => ({ value: stats.videos })));
|
|
|
|
const usagePromise = $derived(
|
|
data.statisticsPromise.then((stats) => {
|
|
const [value, unit] = getBytesWithUnit(stats.usage);
|
|
return { value, unit };
|
|
}),
|
|
);
|
|
|
|
const library = $derived(data.library);
|
|
|
|
const onLibraryUpdate = () => invalidate('app:library');
|
|
|
|
const onLibraryDelete = ({ id }: { id: string }) => {
|
|
if (id === library.id) {
|
|
void goto(Route.libraries());
|
|
}
|
|
};
|
|
|
|
const { Edit, Delete, AddFolder, AddExclusionPattern, Scan } = $derived(getLibraryActions($t, library));
|
|
</script>
|
|
|
|
<OnEvents {onLibraryUpdate} {onLibraryDelete} />
|
|
|
|
<CommandPaletteDefaultProvider name={$t('library')} actions={[Edit, Delete, AddFolder, AddExclusionPattern, Scan]} />
|
|
|
|
<AdminPageLayout
|
|
breadcrumbs={[{ title: $t('external_libraries'), href: Route.libraries() }, { title: library.name }]}
|
|
actions={[Scan, Edit, Delete]}
|
|
>
|
|
<Container size="large" center>
|
|
<div class="grid gap-4 grid-cols-1 lg:grid-cols-2 w-full">
|
|
<Heading tag="h1" size="large" class="col-span-full my-4">{library.name}</Heading>
|
|
<div class="flex flex-col lg:flex-row gap-4 col-span-full">
|
|
<ServerStatisticsCard icon={mdiCameraIris} title={$t('photos')} valuePromise={photosPromise} />
|
|
<ServerStatisticsCard icon={mdiPlayCircle} title={$t('videos')} valuePromise={videosPromise} />
|
|
<ServerStatisticsCard icon={mdiChartPie} title={$t('usage')} valuePromise={usagePromise} />
|
|
</div>
|
|
|
|
<AdminCard icon={mdiFolderOutline} title={$t('folders')} headerAction={AddFolder}>
|
|
{#if library.importPaths.length === 0}
|
|
<EmptyPlaceholder
|
|
src={emptyFoldersUrl}
|
|
text={$t('admin.library_folder_description')}
|
|
fullWidth
|
|
onClick={() => modalManager.show(LibraryFolderAddModal, { library })}
|
|
/>
|
|
{:else}
|
|
<table class="w-full">
|
|
<tbody>
|
|
{#each library.importPaths as folder (folder)}
|
|
{@const { Edit, Delete } = getLibraryFolderActions($t, library, folder)}
|
|
<tr class="h-12">
|
|
<td>
|
|
<Code>{folder}</Code>
|
|
</td>
|
|
<td class="flex gap-2 justify-end">
|
|
<TableButton action={Edit} />
|
|
<TableButton action={Delete} />
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
{/if}
|
|
</AdminCard>
|
|
|
|
<AdminCard icon={mdiFilterMinusOutline} title={$t('exclusion_pattern')} headerAction={AddExclusionPattern}>
|
|
<table class="w-full">
|
|
<tbody>
|
|
{#each library.exclusionPatterns as exclusionPattern (exclusionPattern)}
|
|
{@const { Edit, Delete } = getLibraryExclusionPatternActions($t, library, exclusionPattern)}
|
|
<tr class="h-12">
|
|
<td>
|
|
<Code>{exclusionPattern}</Code>
|
|
</td>
|
|
<td class="flex gap-2 justify-end">
|
|
<TableButton action={Edit} />
|
|
<TableButton action={Delete} />
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
</AdminCard>
|
|
</div>
|
|
{@render children?.()}
|
|
</Container>
|
|
</AdminPageLayout>
|