feat: plugins

This commit is contained in:
Jason Rasmussen
2025-10-21 13:29:32 -04:00
parent 9dffbaea98
commit a6b0f0c76a
23 changed files with 877 additions and 2 deletions

View File

@@ -25,6 +25,7 @@ export enum AppRoute {
ADMIN_STATS = '/admin/server-status',
ADMIN_JOBS = '/admin/jobs-status',
ADMIN_REPAIR = '/admin/repair',
ADMIN_PLUGINS = '/admin/plugins',
ALBUMS = '/albums',
LIBRARIES = '/libraries',

View File

@@ -2,7 +2,7 @@
import BottomInfo from '$lib/components/shared-components/side-bar/bottom-info.svelte';
import { AppRoute } from '$lib/constants';
import { NavbarItem } from '@immich/ui';
import { mdiAccountMultipleOutline, mdiBookshelf, mdiCog, mdiServer, mdiSync } from '@mdi/js';
import { mdiAccountMultipleOutline, mdiBookshelf, mdiCog, mdiConnection, mdiServer, mdiSync } from '@mdi/js';
import { t } from 'svelte-i18n';
</script>
@@ -10,6 +10,7 @@
<div class="flex flex-col pt-8 pe-4 gap-1">
<NavbarItem title={$t('users')} href={AppRoute.ADMIN_USERS} icon={mdiAccountMultipleOutline} />
<NavbarItem title={$t('jobs')} href={AppRoute.ADMIN_JOBS} icon={mdiSync} />
<NavbarItem title={$t('plugins')} href={AppRoute.ADMIN_PLUGINS} icon={mdiConnection} />
<NavbarItem title={$t('settings')} href={AppRoute.ADMIN_SETTINGS} icon={mdiCog} />
<NavbarItem title={$t('external_libraries')} href={AppRoute.ADMIN_LIBRARY_MANAGEMENT} icon={mdiBookshelf} />
<NavbarItem title={$t('server_stats')} href={AppRoute.ADMIN_STATS} icon={mdiServer} />

View File

@@ -0,0 +1,54 @@
<script lang="ts">
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
import { Button, Icon, Switch } from '@immich/ui';
import { mdiCheckDecagram, mdiWrench } from '@mdi/js';
import { range } from 'lodash-es';
import type { PageData } from './$types';
type Props = {
data: PageData;
};
const { data }: Props = $props();
const plugins = range(0, 8).map((index) => ({
name: `Plugin-${index}`,
description: `Plugin ${index} is awesome because it can do x and even y!`,
isEnabled: Math.random() < 0.5,
isInstalled: Math.random() < 0.5,
isOfficial: Math.random() < 0.5,
version: 1,
}));
</script>
<AdminPageLayout title={data.meta.title}>
{#snippet buttons()}
<div class="flex gap-2 items-center justify-center">
<Button leadingIcon={mdiWrench} onclick={() => console.log('clicked')}>Test</Button>
</div>
{/snippet}
<section id="setting-content" class="flex place-content-center sm:mx-4">
<div class="grid grid-cols-1 xl:grid-cols-2 gap-4">
{#each plugins as plugin, i (i)}
<section
class="flex flex-col gap-4 justify-between dark:bg-immich-dark-gray bg-immich-gray dark:border-0 border-gray-200 border border-solid rounded-2xl p-4"
>
<div class="flex flex-col gap-2">
<h1 class="m-0 items-start flex gap-2">
{plugin.name}
{#if plugin.isOfficial}
<Icon icon={mdiCheckDecagram} size="18" class="text-success" />
{/if}
<div class="place-self-end justify-self-end justify-end self-end">Version {plugin.version}</div>
</h1>
<p class="m-0 text-sm text-gray-600 dark:text-gray-300">{plugin.description}</p>
</div>
<div class="flex">Is {plugin.isInstalled ? '' : 'not '}installed</div>
<Switch checked={plugin.isEnabled} id={plugin.name} title="Enabled" />
</section>
{/each}
</div>
</section>
</AdminPageLayout>

View File

@@ -0,0 +1,16 @@
import { authenticate } from '$lib/utils/auth';
import { getFormatter } from '$lib/utils/i18n';
import type { PageLoad } from './$types';
export const load = (async ({ url }) => {
await authenticate(url, { admin: true });
const plugins = [];
const $t = await getFormatter();
return {
plugins,
meta: {
title: $t('plugins'),
},
};
}) satisfies PageLoad;