chore: maintenance page design tweaks (#29087)

This commit is contained in:
Daniel Dietzler 2026-06-16 16:15:54 +02:00 committed by GitHub
parent 9ee412110f
commit 805ca1a2bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 54 additions and 33 deletions

View file

@ -189,18 +189,23 @@
"machine_learning_smart_search_enabled": "Enable smart search",
"machine_learning_smart_search_enabled_description": "If disabled, images will not be encoded for smart search.",
"machine_learning_url_description": "The URL of the machine learning server. If more than one URL is provided, each server will be attempted one-at-a-time until one responds successfully, in order from first to last. Servers that don't respond will be temporarily ignored until they come back online.",
"maintenance_backup_management": "Backup management",
"maintenance_delete_backup": "Delete Backup",
"maintenance_delete_backup_description": "This file will be irrevocably deleted.",
"maintenance_delete_error": "Failed to delete backup.",
"maintenance_integrity_check": "Check",
"maintenance_integrity_check_all": "Check All",
"maintenance_integrity_checksum_mismatch": "Checksum Mismatch",
"maintenance_integrity_checksum_mismatch_description": "Files whose on-disk checksum mismatches the checksum Immich has stored in its database.",
"maintenance_integrity_checksum_mismatch_job": "Check for checksum mismatches",
"maintenance_integrity_checksum_mismatch_refresh_job": "Refresh checksum mismatch reports",
"maintenance_integrity_missing_file": "Missing Files",
"maintenance_integrity_missing_file_description": "Files that Immich has tracked in its database but do not exist on the file system.",
"maintenance_integrity_missing_file_job": "Check for missing files",
"maintenance_integrity_missing_file_refresh_job": "Refresh missing file reports",
"maintenance_integrity_report": "Integrity Report",
"maintenance_integrity_untracked_file": "Untracked Files",
"maintenance_integrity_untracked_file_description": "Files in Immich's directories that Immich does not have any record of.",
"maintenance_integrity_untracked_file_job": "Check for untracked files",
"maintenance_integrity_untracked_file_refresh_job": "Refresh untracked file reports",
"maintenance_restore_backup": "Restore Backup",

View file

@ -12,10 +12,11 @@
icon?: string;
title: string;
valuePromise: MaybePromise<ValueData>;
tooltip?: string;
footer?: Snippet;
}
let { icon, title, valuePromise, footer }: Props = $props();
let { icon, title, valuePromise, tooltip, footer }: Props = $props();
const zeros = (data?: ValueData) => {
let length = 13;
if (data) {
@ -32,7 +33,7 @@
{#if icon}
<Icon {icon} size="40" />
{/if}
<Text size="giant" fontWeight="medium">{title}</Text>
<Text size="giant" fontWeight="medium" title={tooltip}>{title}</Text>
</div>
{#await valuePromise}

View file

@ -21,6 +21,7 @@
import { onMount } from 'svelte';
import { t, type Translations } from 'svelte-i18n';
import type { PageData } from './$types';
import { SvelteSet } from 'svelte/reactivity';
type Props = {
data: PageData;
@ -50,7 +51,7 @@
};
let jobs: QueuesResponseLegacyDto | undefined = $state();
let expectingUpdate: boolean = $state(false);
const activeJobs = new SvelteSet<ManualJobName>();
const getReportTypeTranslation = (report: IntegrityReport): Translations => {
switch (report) {
@ -66,13 +67,27 @@
}
};
const getReportTypeDescriptionKey = (report: IntegrityReport): Translations => {
switch (report) {
case IntegrityReport.UntrackedFile: {
return 'admin.maintenance_integrity_untracked_file_description';
}
case IntegrityReport.MissingFile: {
return 'admin.maintenance_integrity_missing_file_description';
}
case IntegrityReport.ChecksumMismatch: {
return 'admin.maintenance_integrity_checksum_mismatch_description';
}
}
};
const updateReports = async () => {
jobs = await getQueuesLegacy();
if (jobs.integrityCheck.queueStatus.isActive) {
expectingUpdate = true;
} else if (expectingUpdate) {
activeJobs.add(ManualJobName.IntegrityUntrackedFilesRefresh);
} else if (activeJobs.size > 0) {
activeJobs.clear();
integrityReport = await getIntegrityReportSummary();
expectingUpdate = false;
}
};
@ -84,7 +99,7 @@
const onJobCreate = ({ dto }: { dto: JobCreateDto }) => {
if ((Object.values(jobNames).includes(dto.name) || Object.values(refreshJobNames).includes(dto.name)) && jobs) {
expectingUpdate = true;
activeJobs.add(dto.name);
jobs.integrityCheck.queueStatus.isActive = true;
}
};
@ -106,7 +121,7 @@
}
}}
class="mt-1 self-end"
disabled={expectingUpdate}>{$t('admin.maintenance_integrity_check_all')}</Button
disabled={activeJobs.size > 0}>{$t('admin.maintenance_integrity_check_all')}</Button
>
<Button
size="tiny"
@ -117,7 +132,7 @@
}
}}
class="mt-1 self-end"
disabled={expectingUpdate}>{$t('refresh')}</Button
disabled={activeJobs.size > 0}>{$t('refresh')}</Button
></HStack
>
@ -125,36 +140,36 @@
{#each reportTypes as reportType (reportType)}
<ServerStatisticsCard
title={$t(getReportTypeTranslation(reportType))}
tooltip={$t(getReportTypeDescriptionKey(reportType))}
valuePromise={{ value: integrityReport[reportType] }}
>
{#snippet footer()}
<HStack gap={1} class="justify-end">
<Button
onclick={() =>
handleCreateJob({
name: jobNames[reportType],
})}
size="tiny"
variant="ghost"
class="mt-1 self-end"
disabled={expectingUpdate}>{$t('admin.maintenance_integrity_check_all')}</Button
>
<Button
onclick={() =>
handleCreateJob({
name: refreshJobNames[reportType],
})}
size="tiny"
variant="ghost"
class="mt-1 self-end"
disabled={expectingUpdate}>{$t('refresh')}</Button
>
<HStack gap={1} class="justify-between">
<HStack gap={0}>
<Button
onclick={() =>
handleCreateJob({
name: jobNames[reportType],
})}
size="tiny"
variant="ghost"
disabled={activeJobs.has(jobNames[reportType])}>{$t('admin.maintenance_integrity_check')}</Button
>
<Button
onclick={() =>
handleCreateJob({
name: refreshJobNames[reportType],
})}
size="tiny"
variant="ghost"
disabled={activeJobs.has(refreshJobNames[reportType])}>{$t('refresh')}</Button
>
</HStack>
<Button
href={`${Route.systemMaintenanceIntegrityReport({
reportType,
})}`}
size="tiny"
class="mt-1 self-end">{$t('view')}</Button
size="tiny">{$t('view')}</Button
>
</HStack>
{/snippet}
@ -166,7 +181,7 @@
<section id="setting-content" class="flex place-content-center sm:mx-4">
<section class="w-full pb-28 sm:w-5/6 md:w-212.5">
<Text size="small">{$t('admin.maintenance_settings')}</Text>
<Text size="small">{$t('admin.maintenance_backup_management')}</Text>
<SettingAccordion
title={$t('admin.maintenance_restore_database_backup')}