feat: sub-pages for integrity reports

This commit is contained in:
izzy
2025-11-28 11:40:53 +00:00
parent d3abed3414
commit ca358f4dae
23 changed files with 785 additions and 179 deletions
+25 -7
View File
@@ -1,12 +1,11 @@
<script lang="ts">
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
import SettingAccordionState from '$lib/components/shared-components/settings/setting-accordion-state.svelte';
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
import { QueryParameter } from '$lib/constants';
import ServerStatisticsCard from '$lib/components/server-statistics/ServerStatisticsCard.svelte';
import { AppRoute } from '$lib/constants';
import { handleError } from '$lib/utils/handle-error';
import { MaintenanceAction, setMaintenanceMode } from '@immich/sdk';
import { Button, HStack, IconButton, Text } from '@immich/ui';
import { mdiDotsVertical, mdiProgressWrench, mdiRefresh } from '@mdi/js';
import { Button, HStack, Text } from '@immich/ui';
import { mdiProgressWrench } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@@ -46,7 +45,26 @@
<section id="setting-content" class="flex place-content-center sm:mx-4">
<section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
<SettingAccordionState queryParam={QueryParameter.IS_OPEN}>
<p class="text-sm dark:text-immich-dark-fg uppercase">{$t('admin.maintenance_integrity_report')}</p>
<div class="mt-5 hidden justify-between lg:flex gap-4">
{#each ['orphan_file', 'missing_file', 'checksum_mismatch'] as const as reportType (reportType)}
<ServerStatisticsCard
title={$t(`admin.maintenance_integrity_${reportType}`)}
value={data.integrityReport[reportType]}
>
{#snippet footer()}
<Button
href={`${AppRoute.ADMIN_MAINTENANCE_INTEGRITY_REPORT + reportType}`}
size="tiny"
class="self-end mt-1">View Report</Button
>
{/snippet}
</ServerStatisticsCard>
{/each}
</div>
<!-- <SettingAccordionState queryParam={QueryParameter.IS_OPEN}>
<SettingAccordion
title="Integrity Report"
subtitle={`There are ${data.integrityReport.items.length} unresolved issues!`}
@@ -86,7 +104,7 @@
</tbody>
</table>
</SettingAccordion>
</SettingAccordionState>
</SettingAccordionState> -->
</section>
</section>
</AdminPageLayout>
+3 -3
View File
@@ -1,17 +1,17 @@
import { authenticate } from '$lib/utils/auth';
import { getFormatter } from '$lib/utils/i18n';
import { getIntegrityReport } from '@immich/sdk';
import { getIntegrityReportSummary } from '@immich/sdk';
import type { PageLoad } from './$types';
export const load = (async ({ url }) => {
await authenticate(url, { admin: true });
const integrityReport = await getIntegrityReport();
const integrityReport = await getIntegrityReportSummary();
const $t = await getFormatter();
return {
integrityReport,
meta: {
title: $t('admin.system_settings'),
title: $t('admin.maintenance_settings'),
},
};
}) satisfies PageLoad;
@@ -0,0 +1,75 @@
<script lang="ts">
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
import { AppRoute } from '$lib/constants';
import { IconButton } from '@immich/ui';
import { mdiDotsVertical } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
interface Props {
data: PageData;
}
let { data }: Props = $props();
// async function switchToMaintenance() {
// try {
// await setMaintenanceMode({
// setMaintenanceModeDto: {
// action: MaintenanceAction.Start,
// },
// });
// } catch (error) {
// handleError(error, $t('admin.maintenance_start_error'));
// }
// }
</script>
<AdminPageLayout
breadcrumbs={[
{ title: $t('admin.maintenance_settings'), href: AppRoute.ADMIN_MAINTENANCE_SETTINGS },
{ title: $t('admin.maintenance_integrity_report') },
{ title: data.meta.title },
]}
>
<!-- {#snippet buttons()}
<HStack gap={1}>
<Button
leadingIcon={mdiProgressWrench}
size="small"
variant="ghost"
color="secondary"
onclick={switchToMaintenance}
>
<Text class="hidden md:block">{$t('admin.maintenance_start')}</Text>
</Button>
</HStack>
{/snippet} -->
<section id="setting-content" class="flex place-content-center sm:mx-4">
<section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
<table class="mt-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-7/8 text-left px-2 text-sm font-medium">{$t('filename')}</th>
<th class="w-1/8"></th>
</tr>
</thead>
<tbody
class="block max-h-80 w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray dark:text-immich-dark-fg"
>
{#each data.integrityReport.items as { id, path } (id)}
<tr class="flex py-1 w-full place-items-center even:bg-subtle/20 odd:bg-subtle/80">
<td class="w-7/8 text-ellipsis text-left px-2 text-sm select-all">{path}</td>
<td class="w-1/8 text-ellipsis text-right flex justify-end px-2">
<IconButton aria-label="Open" color="secondary" icon={mdiDotsVertical} variant="ghost" /></td
>
</tr>
{/each}
</tbody>
</table>
</section>
</section>
</AdminPageLayout>
@@ -0,0 +1,23 @@
import { authenticate } from '$lib/utils/auth';
import { getFormatter } from '$lib/utils/i18n';
import { getIntegrityReport, IntegrityReportType } from '@immich/sdk';
import type { PageLoad } from './$types';
export const load = (async ({ params, url }) => {
const type = params.type as IntegrityReportType;
await authenticate(url, { admin: true });
const integrityReport = await getIntegrityReport({
maintenanceGetIntegrityReportDto: {
type,
},
});
const $t = await getFormatter();
return {
integrityReport,
meta: {
title: $t(`admin.maintenance_integrity_${type}`),
},
};
}) satisfies PageLoad;