mirror of
https://github.com/immich-app/immich.git
synced 2025-12-26 09:14:58 +03:00
chore: i18n pass, update progress bar
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
IconButton,
|
||||
menuManager,
|
||||
modalManager,
|
||||
ProgressBar,
|
||||
Stack,
|
||||
Text,
|
||||
type ContextMenuBaseProps,
|
||||
@@ -36,15 +37,15 @@
|
||||
function mapBackups(filenames: string[]) {
|
||||
return filenames.map((filename) => {
|
||||
const date = /(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})/.exec(filename);
|
||||
const hoursAgo = date
|
||||
const minutesAgo = date
|
||||
? Math.floor(
|
||||
(+Date.now() - +new Date(`${date[1]}-${date[2]}-${date[3]}T${date[4]}:${date[5]}:${date[6]}`)) / 36e5,
|
||||
(+Date.now() - +new Date(`${date[1]}-${date[2]}-${date[3]}T${date[4]}:${date[5]}:${date[6]}`)) / 60_000,
|
||||
)
|
||||
: null;
|
||||
|
||||
return {
|
||||
filename,
|
||||
hoursAgo,
|
||||
minutesAgo,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -61,9 +62,9 @@
|
||||
|
||||
async function restore(filename: string) {
|
||||
const confirm = await modalManager.showDialog({
|
||||
confirmText: 'Restore',
|
||||
title: 'Restore Backup',
|
||||
prompt: 'Immich will be wiped and restored from the chosen backup. A backup will be created before continuing.',
|
||||
confirmText: $t('restore'),
|
||||
title: $t('admin.maintenance_restore_backup'),
|
||||
prompt: $t('admin.maintenance_restore_backup_description'),
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
@@ -82,9 +83,9 @@
|
||||
|
||||
async function remove(filename: string) {
|
||||
const confirm = await modalManager.showDialog({
|
||||
confirmText: 'Delete',
|
||||
title: 'Delete Backup',
|
||||
prompt: 'This file will be irrevocably deleted.',
|
||||
confirmText: $t('delete'),
|
||||
title: $t('admin.maintenance_delete_backup'),
|
||||
prompt: $t('admin.maintenance_delete_backup_description'),
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
@@ -97,7 +98,7 @@
|
||||
|
||||
backups = backups.filter((backup) => backup.filename !== filename);
|
||||
} catch (error) {
|
||||
handleError(error, 'failed to delete backup i18n');
|
||||
handleError(error, $t('admin.maintenance_delete_error'));
|
||||
} finally {
|
||||
deleting.delete(filename);
|
||||
}
|
||||
@@ -114,14 +115,14 @@
|
||||
target: event.currentTarget as HTMLElement,
|
||||
items: [
|
||||
{
|
||||
title: 'Download',
|
||||
title: $t('download'),
|
||||
icon: mdiDownload,
|
||||
onSelect() {
|
||||
void download(filename);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Delete',
|
||||
title: $t('delete'),
|
||||
icon: mdiTrashCanOutline,
|
||||
color: 'danger',
|
||||
onSelect() {
|
||||
@@ -153,7 +154,7 @@
|
||||
const { backups: newList } = await listBackups();
|
||||
backups = mapBackups(newList);
|
||||
} catch (error) {
|
||||
handleError(error, 'Could not upload backup, is it an .sql/.sql.gz file?');
|
||||
handleError(error, $t('admin.maintenance_upload_backup_error'));
|
||||
} finally {
|
||||
uploadProgress = -1;
|
||||
}
|
||||
@@ -165,15 +166,13 @@
|
||||
<CardBody>
|
||||
{#if uploadProgress === -1}
|
||||
<HStack>
|
||||
<Text class="grow">Upload database backup file</Text>
|
||||
<Button size="small" onclick={upload}>Select file</Button>
|
||||
<Text class="grow">{$t('admin.maintenance_upload_backup')}</Text>
|
||||
<Button size="tiny" onclick={upload}>{$t('select_from_computer')}</Button>
|
||||
</HStack>
|
||||
{:else}
|
||||
<HStack>
|
||||
<Text class="grow">Uploading...</Text>
|
||||
<div class="grow h-2.5 bg-gray-300 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-blue-600 transition-all duration-700" style="width: {uploadProgress * 100}%"></div>
|
||||
</div>
|
||||
<HStack gap={8}>
|
||||
<Text class="grow">{$t('asset_uploading')}</Text>
|
||||
<ProgressBar progress={uploadProgress} size="tiny" />
|
||||
</HStack>
|
||||
{/if}
|
||||
</CardBody>
|
||||
@@ -185,20 +184,48 @@
|
||||
<HStack>
|
||||
<Stack class="grow">
|
||||
<Text>{backup.filename}</Text>
|
||||
{#if typeof backup.hoursAgo === 'number'}
|
||||
{#if backup.hoursAgo <= 24}
|
||||
{#if typeof backup.minutesAgo === 'number'}
|
||||
<Text color="info" size="small">
|
||||
{#if backup.minutesAgo <= 1}
|
||||
{$t('created_minute_ago')}
|
||||
{:else if backup.minutesAgo < 60}
|
||||
{$t('created_minutes_ago', {
|
||||
values: {
|
||||
count: backup.minutesAgo,
|
||||
},
|
||||
})}
|
||||
{:else if backup.minutesAgo < 60 * 2}
|
||||
{$t('created_hour_ago')}
|
||||
{:else if backup.minutesAgo < 60 * 24}
|
||||
{$t('created_hours_ago', {
|
||||
values: {
|
||||
count: Math.floor(backup.minutesAgo / 60),
|
||||
},
|
||||
})}
|
||||
{:else if backup.minutesAgo < 60 * 24 * 2}
|
||||
{$t('created_day_ago')}
|
||||
{:else}
|
||||
{$t('created_days_ago', {
|
||||
values: {
|
||||
count: Math.floor(backup.minutesAgo / (60 * 24)),
|
||||
},
|
||||
})}
|
||||
{/if}
|
||||
</Text>
|
||||
<!-- {#if backup.hoursAgo <= 24}
|
||||
<Text color="info" size="small">Created {backup.hoursAgo} hours ago</Text>
|
||||
{:else if backup.hoursAgo <= 48}
|
||||
<Text color="info" size="small">Created 1 day ago</Text>
|
||||
{:else}
|
||||
<Text color="info" size="small">Created {Math.floor(backup.hoursAgo / 24)} days ago</Text>
|
||||
{/if}
|
||||
{/if} -->
|
||||
{/if}
|
||||
</Stack>
|
||||
|
||||
<Button size="small" disabled={deleting.has(backup.filename)} onclick={() => restore(backup.filename)}
|
||||
>Restore</Button
|
||||
>{$t('restore')}</Button
|
||||
>
|
||||
|
||||
<IconButton
|
||||
shape="round"
|
||||
variant="ghost"
|
||||
@@ -207,7 +234,7 @@
|
||||
class="shrink-0"
|
||||
disabled={deleting.has(backup.filename)}
|
||||
onclick={(event: Event) => handleOpen(event, { position: 'top-right' }, backup.filename)}
|
||||
aria-label="Open menu"
|
||||
aria-label={$t('open')}
|
||||
/>
|
||||
</HStack>
|
||||
</CardBody>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { Button, Card, CardBody, Heading, HStack, Icon, Scrollable, Stack, Text } from '@immich/ui';
|
||||
import { mdiAlert, mdiArrowLeft, mdiArrowRight, mdiCheck, mdiClose, mdiRefresh } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
end?: () => void;
|
||||
@@ -19,22 +20,11 @@
|
||||
}
|
||||
|
||||
onMount(reload);
|
||||
|
||||
const i18nMap = {
|
||||
'encoded-video': 'Encoded Video',
|
||||
library: 'Library',
|
||||
upload: 'Upload',
|
||||
profile: 'Profile',
|
||||
thumbs: 'Thumbs',
|
||||
backups: 'Backups',
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if stage === 0}
|
||||
<Heading size="large" color="primary" tag="h1">Restore Your Library</Heading>
|
||||
<Text
|
||||
>Before restoring a database backup, you must ensure your library has been restored or is otherwise already present.</Text
|
||||
>
|
||||
<Heading size="large" color="primary" tag="h1">{$t('maintenance_restore_library')}</Heading>
|
||||
<Text>{$t('maintenance_restore_library_description')}</Text>
|
||||
<Card>
|
||||
<CardBody>
|
||||
<Stack>
|
||||
@@ -46,12 +36,10 @@
|
||||
color={`rgb(var(--immich-ui-${writable ? 'success' : 'danger'}))`}
|
||||
/>
|
||||
<Text
|
||||
>{i18nMap[folder as keyof typeof i18nMap]} ({writable
|
||||
? 'readable and writable'
|
||||
: readable
|
||||
? 'not writable'
|
||||
: 'not readable'})</Text
|
||||
>
|
||||
>{folder} ({$t(
|
||||
`maintenance_restore_library_folder_${writable ? 'pass' : readable ? 'write_fail' : 'read_fail'}`,
|
||||
)})
|
||||
</Text>
|
||||
</HStack>
|
||||
{/each}
|
||||
{#each integrity.storage as { folder, files } (folder)}
|
||||
@@ -65,47 +53,57 @@
|
||||
<Stack gap={0} class="items-start">
|
||||
<Text>
|
||||
{#if files}
|
||||
{i18nMap[folder as keyof typeof i18nMap]} has {files} folder(s)
|
||||
{$t('maintenance_restore_library_folder_has_files', {
|
||||
values: {
|
||||
folder,
|
||||
count: files,
|
||||
},
|
||||
})}
|
||||
{:else}
|
||||
{i18nMap[folder as keyof typeof i18nMap]} is missing files!
|
||||
{$t('maintenance_restore_library_folder_no_files', {
|
||||
values: {
|
||||
folder,
|
||||
},
|
||||
})}
|
||||
{/if}
|
||||
</Text>
|
||||
{#if !files && (folder === 'profile' || folder === 'upload')}
|
||||
<Text variant="italic">You may be missing files</Text>
|
||||
<Text variant="italic">{$t('maintenance_restore_library_hint_missing_files')}</Text>
|
||||
{/if}
|
||||
{#if !files && (folder === 'encoded-video' || folder === 'thumbs')}
|
||||
<Text variant="italic">You can regenerate these later in settings</Text>
|
||||
<Text variant="italic">{$t('maintenance_restore_library_hint_regenerate_later')}</Text>
|
||||
{/if}
|
||||
{#if !files && folder === 'library'}
|
||||
<Text variant="italic">Using storage template? You may be missing files</Text>
|
||||
<Text variant="italic">{$t('maintenance_restore_library_hint_storage_template_missing_files')}</Text
|
||||
>
|
||||
{/if}
|
||||
</Stack>
|
||||
</HStack>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<Button leadingIcon={mdiRefresh} variant="ghost" onclick={reload}>Refresh</Button>
|
||||
<Button leadingIcon={mdiRefresh} variant="ghost" onclick={reload}>{$t('refresh')}</Button>
|
||||
{:else}
|
||||
<HStack>
|
||||
<Icon icon={mdiRefresh} color="rgb(var(--immich-ui-primary))" />
|
||||
<Text>Loading integrity checks and heuristics...</Text>
|
||||
<Text>{$t('maintenance_restore_library_loading')}</Text>
|
||||
</HStack>
|
||||
{/if}
|
||||
</Stack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<Text>If this looks correct, continue to restoring a backup!</Text>
|
||||
<Text>{$t('maintenance_restore_library_confirm')}</Text>
|
||||
<HStack>
|
||||
<Button onclick={props.end} variant="ghost">Cancel</Button>
|
||||
<Button onclick={() => stage++} trailingIcon={mdiArrowRight}>Next</Button>
|
||||
<Button onclick={props.end} variant="ghost">{$t('cancel')}</Button>
|
||||
<Button onclick={() => stage++} trailingIcon={mdiArrowRight}>{$t('next')}</Button>
|
||||
</HStack>
|
||||
{:else}
|
||||
<Heading size="large" color="primary" tag="h1">Restore From Backup</Heading>
|
||||
<Heading size="large" color="primary" tag="h1">{$t('maintenance_restore_from_backup')}</Heading>
|
||||
<Scrollable class="max-h-80">
|
||||
<MaintenanceBackupsList />
|
||||
</Scrollable>
|
||||
<HStack>
|
||||
<Button onclick={props.end} variant="ghost">Cancel</Button>
|
||||
<Button onclick={() => stage--} variant="ghost" leadingIcon={mdiArrowLeft}>Back</Button>
|
||||
<Button onclick={props.end} variant="ghost">{$t('cancel')}</Button>
|
||||
<Button onclick={() => stage--} variant="ghost" leadingIcon={mdiArrowLeft}>{$t('back')}</Button>
|
||||
</HStack>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user