@futo-org/backups-orchestrator-ui 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/backends/BackendItem.svelte +28 -24
- package/dist/components/backends/BackendsList.svelte +33 -34
- package/dist/components/backends/BackendsList.svelte.d.ts +1 -0
- package/dist/components/backends/dialogs/SelectBackendModal.svelte +44 -55
- package/dist/components/backups/BackupItem.svelte +33 -26
- package/dist/components/backups/BackupStatus.svelte +200 -0
- package/dist/components/backups/BackupStatus.svelte.d.ts +19 -0
- package/dist/components/backups/BackupsList.svelte +17 -11
- package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +2 -2
- package/dist/components/backups/dialogs/SelectRepositoryModal.svelte +26 -36
- package/dist/components/backups/dialogs/ViewStatusModal.svelte +175 -0
- package/dist/components/backups/dialogs/ViewStatusModal.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte +22 -10
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +2 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +46 -20
- package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte +135 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RunHistoryModal.svelte +2 -2
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +22 -10
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +2 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +23 -21
- package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte +115 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte.d.ts +9 -0
- package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +2 -2
- package/dist/components/dashboard/Dashboard.svelte +14 -7
- package/dist/components/dashboard/Dashboard.svelte.d.ts +1 -1
- package/dist/components/dashboard/DashboardAvgBackupTime.svelte +1 -1
- package/dist/components/dashboard/DashboardBackupHealth.svelte +5 -9
- package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +1 -1
- package/dist/components/dashboard/DashboardCurrentUsage.svelte +1 -1
- package/dist/components/dashboard/DashboardDailyBackupTime.svelte +1 -1
- package/dist/components/dashboard/DashboardInstall.svelte +1 -1
- package/dist/components/dashboard/DashboardRecentBackups.svelte +47 -78
- package/dist/components/dashboard/DashboardTotalStored.svelte +1 -1
- package/dist/components/integrations/immich/ImmichBackupSettings.svelte +12 -0
- package/dist/components/integrations/immich/ImmichBackupSettings.svelte.d.ts +18 -0
- package/dist/components/integrations/immich/ImmichBackupsCard.svelte +73 -0
- package/dist/components/integrations/immich/ImmichBackupsCard.svelte.d.ts +12 -0
- package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte +55 -0
- package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte.d.ts +10 -0
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte +15 -3
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +7 -1
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +66 -0
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte.d.ts +8 -0
- package/dist/components/integrations/immich/ImmichManageBackup.svelte +53 -14
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +45 -71
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +123 -82
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +1 -1
- package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte +313 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte +218 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte +207 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte.d.ts +3 -0
- package/dist/components/onboarding/RecoveryKeyDisplay.svelte +34 -20
- package/dist/components/onboarding/SampleOnboarding.svelte +57 -38
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +10 -24
- package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte +44 -0
- package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte.d.ts +7 -0
- package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte +50 -0
- package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte.d.ts +7 -0
- package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte +45 -0
- package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte.d.ts +8 -0
- package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte +67 -0
- package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte.d.ts +9 -0
- package/dist/components/onboarding/steps/OnboardingStepLayout.svelte +58 -0
- package/dist/components/onboarding/steps/OnboardingStepLayout.svelte.d.ts +19 -0
- package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte +52 -0
- package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte.d.ts +18 -0
- package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte +33 -0
- package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte.d.ts +8 -0
- package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte +27 -0
- package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte.d.ts +10 -0
- package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte +7 -0
- package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte.d.ts +18 -0
- package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte +46 -0
- package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte.d.ts +6 -0
- package/dist/components/onboarding/upsell/UpsellModal.svelte +43 -0
- package/dist/components/onboarding/upsell/UpsellModal.svelte.d.ts +9 -0
- package/dist/components/onboarding/upsell/UpsellPage.svelte +39 -0
- package/dist/components/onboarding/upsell/UpsellPage.svelte.d.ts +13 -0
- package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte +58 -0
- package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte.d.ts +8 -0
- package/dist/components/schedules/RepositoryPicker.svelte +45 -38
- package/dist/components/schedules/ScheduleItem.svelte +32 -26
- package/dist/components/schedules/ScheduleList.svelte +16 -10
- package/dist/components/settings/GlobalSettings.svelte +8 -0
- package/dist/components/settings/GlobalSettings.svelte.d.ts +18 -0
- package/dist/components/settings/SettingsBackends.svelte +16 -0
- package/dist/components/settings/SettingsBackends.svelte.d.ts +18 -0
- package/dist/components/settings/SettingsBilling.svelte +69 -0
- package/dist/components/settings/SettingsBilling.svelte.d.ts +6 -0
- package/dist/components/settings/SettingsNotifications.svelte +47 -0
- package/dist/components/settings/SettingsNotifications.svelte.d.ts +6 -0
- package/dist/components/test/ImmichTestUi.svelte +129 -27
- package/dist/components/test/TestUi.svelte +4 -4
- package/dist/components/test/dashboard/ActiveJobs.svelte +2 -2
- package/dist/components/test/immich/MockImmichPhotos.svelte +36 -0
- package/dist/components/test/immich/MockImmichPhotos.svelte.d.ts +18 -0
- package/dist/components/test/immich/MockImmichPurchaseInfo.svelte +29 -0
- package/dist/components/test/immich/MockImmichPurchaseInfo.svelte.d.ts +18 -0
- package/dist/components/test/immich/MockImmichStorageSpace.svelte +37 -0
- package/dist/components/test/immich/MockImmichStorageSpace.svelte.d.ts +6 -0
- package/dist/components/ui/Accordion.svelte +67 -0
- package/dist/components/ui/Accordion.svelte.d.ts +11 -0
- package/dist/components/ui/ListToolbar.svelte +60 -0
- package/dist/components/ui/ListToolbar.svelte.d.ts +16 -0
- package/dist/components/ui/PageLayout.svelte +21 -9
- package/dist/components/ui/PageLayout.svelte.d.ts +1 -0
- package/dist/components/ui/Pagination.svelte +80 -0
- package/dist/components/ui/Pagination.svelte.d.ts +8 -0
- package/dist/components/ui/PathListField.svelte +17 -14
- package/dist/components/ui/StackList.svelte +18 -18
- package/dist/components/ui/StackList.svelte.d.ts +6 -27
- package/dist/components/ui/StackListItem.svelte +47 -25
- package/dist/components/ui/StackListItem.svelte.d.ts +5 -2
- package/dist/components/ui/StackListOption.svelte +33 -0
- package/dist/components/ui/StackListOption.svelte.d.ts +11 -0
- package/dist/components/ui/StackListPlaceholder.svelte +12 -0
- package/dist/components/ui/StackListPlaceholder.svelte.d.ts +7 -0
- package/dist/components/ui/StepNumber.svelte +20 -0
- package/dist/components/ui/StepNumber.svelte.d.ts +7 -0
- package/dist/components/util/Suspense.svelte +7 -3
- package/dist/components/util/YuccaContext.svelte +1 -1
- package/dist/events.js +1 -1
- package/dist/fetch-client.d.ts +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/services/backend.service.js +3 -0
- package/dist/services/immich.integration.service.d.ts +1 -1
- package/dist/services/immich.integration.service.js +2 -3
- package/dist/services/integrations.service.d.ts +1 -0
- package/dist/services/integrations.service.js +2 -1
- package/dist/services/log.service.svelte.d.ts +12 -0
- package/dist/services/log.service.svelte.js +15 -1
- package/dist/services/repository.service.js +9 -3
- package/dist/services/runHistory.service.js +2 -2
- package/dist/utils/format.d.ts +1 -1
- package/dist/utils/format.js +2 -2
- package/package.json +3 -3
- package/dist/components/backups/dialogs/ViewLogModal.svelte +0 -208
- package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +0 -7
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +0 -403
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +0 -9
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +0 -80
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +0 -8
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +0 -56
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +0 -9
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +0 -50
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +0 -7
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +0 -44
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +0 -8
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +0 -56
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +0 -9
- package/dist/components/util/TimedButton.svelte +0 -37
- package/dist/components/util/TimedButton.svelte.d.ts +0 -7
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Icon, Text } from "@immich/ui";
|
|
3
|
+
import { mdiCloudUpload, mdiCloudUploadOutline } from "@mdi/js";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
configured: boolean;
|
|
7
|
+
active?: boolean;
|
|
8
|
+
href?: string;
|
|
9
|
+
onclick?: () => void;
|
|
10
|
+
class?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
configured,
|
|
15
|
+
active = false,
|
|
16
|
+
href,
|
|
17
|
+
onclick,
|
|
18
|
+
class: className,
|
|
19
|
+
}: Props = $props();
|
|
20
|
+
|
|
21
|
+
const shell = $derived(
|
|
22
|
+
configured
|
|
23
|
+
? `hover:bg-subtle hover:text-primary flex w-full cursor-pointer place-items-center gap-4 rounded-e-full ps-5 py-3 text-start ${active ? "bg-primary/10 text-primary" : ""}`
|
|
24
|
+
: "border-primary/40 from-white via-blue-100 to-purple-100 dark:from-transparent dark:via-blue-500/10 dark:to-purple-500/15 flex w-full cursor-pointer place-items-center gap-4 rounded-xl border bg-gradient-to-r px-4 py-2.5 text-start",
|
|
25
|
+
);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
{#snippet body()}
|
|
29
|
+
<Icon
|
|
30
|
+
icon={configured ? mdiCloudUploadOutline : mdiCloudUpload}
|
|
31
|
+
size="1.375em"
|
|
32
|
+
class="{configured ? '' : 'text-primary'} shrink-0"
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
<Text
|
|
36
|
+
size="small"
|
|
37
|
+
fontWeight="medium"
|
|
38
|
+
color={configured && !active ? undefined : "primary"}
|
|
39
|
+
class="flex-1 truncate"
|
|
40
|
+
>
|
|
41
|
+
{configured ? "Backups" : "Set up Backups"}
|
|
42
|
+
</Text>
|
|
43
|
+
{/snippet}
|
|
44
|
+
|
|
45
|
+
<div class="{configured ? '' : 'mx-4 mb-2'} {className ?? ''}">
|
|
46
|
+
{#if href}
|
|
47
|
+
<a {href} {onclick} class={shell}>
|
|
48
|
+
{@render body()}
|
|
49
|
+
</a>
|
|
50
|
+
{:else}
|
|
51
|
+
<button type="button" {onclick} class={shell}>
|
|
52
|
+
{@render body()}
|
|
53
|
+
</button>
|
|
54
|
+
{/if}
|
|
55
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
configured: boolean;
|
|
3
|
+
active?: boolean;
|
|
4
|
+
href?: string;
|
|
5
|
+
onclick?: () => void;
|
|
6
|
+
class?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const ImmichBackupsNavButton: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type ImmichBackupsNavButton = ReturnType<typeof ImmichBackupsNavButton>;
|
|
10
|
+
export default ImmichBackupsNavButton;
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import UpsellPage from "../../onboarding/upsell/UpsellPage.svelte";
|
|
2
3
|
import ImmichManageBackup from "./ImmichManageBackup.svelte";
|
|
3
4
|
import ImmichOnboardingSetupFlow from "./ImmichOnboardingSetupFlow.svelte";
|
|
4
5
|
|
|
6
|
+
type Question = {
|
|
7
|
+
title: string;
|
|
8
|
+
answer: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
5
11
|
type Props = {
|
|
6
|
-
|
|
12
|
+
price: string;
|
|
13
|
+
includedStorage: string;
|
|
14
|
+
questions: Question[];
|
|
7
15
|
};
|
|
8
16
|
|
|
9
|
-
const {
|
|
17
|
+
const { price, includedStorage, questions }: Props = $props();
|
|
10
18
|
</script>
|
|
11
19
|
|
|
12
|
-
<ImmichOnboardingSetupFlow
|
|
20
|
+
<ImmichOnboardingSetupFlow>
|
|
21
|
+
{#snippet fallback(onStart)}
|
|
22
|
+
<UpsellPage {price} {includedStorage} {questions} onGetStarted={onStart} />
|
|
23
|
+
{/snippet}
|
|
24
|
+
|
|
13
25
|
<ImmichManageBackup />
|
|
14
26
|
</ImmichOnboardingSetupFlow>
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
type Question = {
|
|
2
|
+
title: string;
|
|
3
|
+
answer: string;
|
|
4
|
+
};
|
|
1
5
|
type Props = {
|
|
2
|
-
|
|
6
|
+
price: string;
|
|
7
|
+
includedStorage: string;
|
|
8
|
+
questions: Question[];
|
|
3
9
|
};
|
|
4
10
|
declare const ImmichBackupsPage: import("svelte").Component<Props, {}, "">;
|
|
5
11
|
type ImmichBackupsPage = ReturnType<typeof ImmichBackupsPage>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import OnEvents from "../../util/OnEvents.svelte";
|
|
3
|
+
import {
|
|
4
|
+
useIntegrationEventHandler,
|
|
5
|
+
useIntegrations,
|
|
6
|
+
} from "../../../services/integrations.service";
|
|
7
|
+
import {
|
|
8
|
+
useRepositories,
|
|
9
|
+
useRepositoryEventHandler,
|
|
10
|
+
} from "../../../services/repository.service";
|
|
11
|
+
import ImmichBackupsCard from "./ImmichBackupsCard.svelte";
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
href?: string;
|
|
15
|
+
onclick?: () => void;
|
|
16
|
+
class?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const { href = "/backups", onclick, class: className }: Props = $props();
|
|
20
|
+
|
|
21
|
+
const integrations = useIntegrations();
|
|
22
|
+
const repositories = useRepositories();
|
|
23
|
+
|
|
24
|
+
const { onIntegrationUpdate } = useIntegrationEventHandler();
|
|
25
|
+
const { onRepositoryCreate, onRepositoryUpdate, onRepositoryDelete } =
|
|
26
|
+
useRepositoryEventHandler();
|
|
27
|
+
|
|
28
|
+
const repository = $derived.by(() => {
|
|
29
|
+
const integration = integrations.data?.immichIntegration;
|
|
30
|
+
|
|
31
|
+
return integration
|
|
32
|
+
? repositories.data?.find((entry) => entry.id === integration.id)
|
|
33
|
+
: undefined;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const lastBackup = $derived(repository?.metrics.lastBackup ?? undefined);
|
|
37
|
+
|
|
38
|
+
const failed = $derived(
|
|
39
|
+
Boolean(
|
|
40
|
+
lastBackup && lastBackup !== repository?.metrics.lastSuccessfulBackup,
|
|
41
|
+
),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const sizeBytes = $derived(
|
|
45
|
+
repository?.meter?.sizeBytes ?? repository?.metrics.sizeBytes,
|
|
46
|
+
);
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<OnEvents
|
|
50
|
+
{onIntegrationUpdate}
|
|
51
|
+
{onRepositoryCreate}
|
|
52
|
+
{onRepositoryUpdate}
|
|
53
|
+
{onRepositoryDelete}
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
{#if !integrations.isLoading && !repositories.isLoading}
|
|
57
|
+
<ImmichBackupsCard
|
|
58
|
+
configured={Boolean(repository)}
|
|
59
|
+
{lastBackup}
|
|
60
|
+
{failed}
|
|
61
|
+
{sizeBytes}
|
|
62
|
+
{href}
|
|
63
|
+
{onclick}
|
|
64
|
+
class={className}
|
|
65
|
+
/>
|
|
66
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
href?: string;
|
|
3
|
+
onclick?: () => void;
|
|
4
|
+
class?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const ImmichBackupsSidebarItem: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type ImmichBackupsSidebarItem = ReturnType<typeof ImmichBackupsSidebarItem>;
|
|
8
|
+
export default ImmichBackupsSidebarItem;
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
useScheduleEventHandler,
|
|
18
18
|
useSchedules,
|
|
19
19
|
} from "../../../services/schedule.service";
|
|
20
|
+
import RepositoryRunHistoryPage from "../../backups/run-history/RepositoryRunHistoryPage.svelte";
|
|
21
|
+
import RepositorySnapshotsPage from "../../backups/snapshots-list/RepositorySnapshotsPage.svelte";
|
|
22
|
+
import ImmichBackupSettings from "./ImmichBackupSettings.svelte";
|
|
20
23
|
import { Container, Stack } from "@immich/ui";
|
|
21
24
|
import ImmichManageBackupOverview from "./ImmichManageBackupOverview.svelte";
|
|
22
25
|
|
|
@@ -48,8 +51,12 @@
|
|
|
48
51
|
: undefined,
|
|
49
52
|
);
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
let view = $state<"overview" | "attempts" | "snapshots" | "settings">(
|
|
55
|
+
"overview",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const { ViewRecoveryKey, Configure } = $derived(
|
|
59
|
+
getBackupPageActions(repository?.id, () => (view = "settings")),
|
|
53
60
|
);
|
|
54
61
|
</script>
|
|
55
62
|
|
|
@@ -63,15 +70,47 @@
|
|
|
63
70
|
{onIntegrationUpdate}
|
|
64
71
|
/>
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
<
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
{#if view === "attempts" && repository}
|
|
74
|
+
<PageLayout title="Backup attempts" onBack={() => (view = "overview")}>
|
|
75
|
+
<Container size="medium" center>
|
|
76
|
+
<div class="mt-4">
|
|
77
|
+
<RepositoryRunHistoryPage {repository} />
|
|
78
|
+
</div>
|
|
79
|
+
</Container>
|
|
80
|
+
</PageLayout>
|
|
81
|
+
{:else if view === "settings"}
|
|
82
|
+
<PageLayout title="Backup settings" onBack={() => (view = "overview")}>
|
|
83
|
+
<div class="mt-4">
|
|
84
|
+
<ImmichBackupSettings />
|
|
85
|
+
</div>
|
|
86
|
+
</PageLayout>
|
|
87
|
+
{:else if view === "snapshots" && repository}
|
|
88
|
+
<PageLayout title="Snapshots" onBack={() => (view = "overview")}>
|
|
89
|
+
<Container size="medium" center>
|
|
90
|
+
<div class="mt-4">
|
|
91
|
+
<RepositorySnapshotsPage {repository} immich />
|
|
92
|
+
</div>
|
|
93
|
+
</Container>
|
|
94
|
+
</PageLayout>
|
|
95
|
+
{:else}
|
|
96
|
+
<PageLayout title="Backups" actions={[ViewRecoveryKey, Configure]}>
|
|
97
|
+
<Container size="medium" center>
|
|
98
|
+
{#if repository && schedule}
|
|
99
|
+
<Stack class="mt-4" gap={6}>
|
|
100
|
+
<ImmichManageBackupOverview {repository} {schedule} />
|
|
101
|
+
<BackendsList {repository} />
|
|
102
|
+
<RepositoryRunHistory
|
|
103
|
+
{repository}
|
|
104
|
+
onViewAll={() => (view = "attempts")}
|
|
105
|
+
/>
|
|
106
|
+
<RepositorySnapshotsList
|
|
107
|
+
{repository}
|
|
108
|
+
immich
|
|
109
|
+
limit={5}
|
|
110
|
+
onViewAll={() => (view = "snapshots")}
|
|
111
|
+
/>
|
|
112
|
+
</Stack>
|
|
113
|
+
{/if}
|
|
114
|
+
</Container>
|
|
115
|
+
</PageLayout>
|
|
116
|
+
{/if}
|
|
@@ -3,26 +3,14 @@
|
|
|
3
3
|
import StackListItem from "../../ui/StackListItem.svelte";
|
|
4
4
|
import RelativeTime from "../../util/RelativeTime.svelte";
|
|
5
5
|
import type { LocalRepositoryDto, ScheduleDto } from "../../../fetch-client";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
handleResumeSchedule,
|
|
9
|
-
} from "../../../services/schedule.service";
|
|
10
|
-
import {
|
|
11
|
-
FormatBytes,
|
|
12
|
-
Heading,
|
|
13
|
-
HStack,
|
|
14
|
-
Icon,
|
|
15
|
-
IconButton,
|
|
16
|
-
Stack,
|
|
17
|
-
Text,
|
|
18
|
-
} from "@immich/ui";
|
|
6
|
+
import { handleCreateBackup } from "../../../services/repository.service";
|
|
7
|
+
import { Button, FormatBytes, Icon } from "@immich/ui";
|
|
19
8
|
import {
|
|
20
9
|
mdiAlert,
|
|
21
10
|
mdiArchiveOutline,
|
|
22
11
|
mdiCheck,
|
|
12
|
+
mdiCloudUploadOutline,
|
|
23
13
|
mdiInformation,
|
|
24
|
-
mdiPauseCircleOutline,
|
|
25
|
-
mdiPlayCircleOutline,
|
|
26
14
|
} from "@mdi/js";
|
|
27
15
|
import cronstrue from "cronstrue";
|
|
28
16
|
|
|
@@ -33,72 +21,58 @@
|
|
|
33
21
|
|
|
34
22
|
const { repository, schedule }: Props = $props();
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
} else {
|
|
40
|
-
handlePauseSchedule(schedule!.id, "Immich");
|
|
24
|
+
const status = $derived.by(() => {
|
|
25
|
+
if (!repository.metrics.lastBackup) {
|
|
26
|
+
return { color: "warning", icon: mdiInformation } as const;
|
|
41
27
|
}
|
|
42
|
-
|
|
28
|
+
|
|
29
|
+
return repository.metrics.lastBackup !==
|
|
30
|
+
repository.metrics.lastSuccessfulBackup
|
|
31
|
+
? ({ color: "danger", icon: mdiAlert } as const)
|
|
32
|
+
: ({ color: "success", icon: mdiCheck } as const);
|
|
33
|
+
});
|
|
34
|
+
|
|
43
35
|
</script>
|
|
44
36
|
|
|
45
37
|
<StackList>
|
|
46
|
-
<StackListItem>
|
|
38
|
+
<StackListItem title="Your library" footerColor={status.color}>
|
|
47
39
|
{#snippet icon()}
|
|
48
|
-
<Icon icon={mdiArchiveOutline}
|
|
40
|
+
<Icon icon={mdiArchiveOutline} />
|
|
49
41
|
{/snippet}
|
|
50
42
|
|
|
51
|
-
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
{/if} ·
|
|
60
|
-
<span class="lowercase"
|
|
61
|
-
>{cronstrue.toString(schedule.cron, {
|
|
62
|
-
verbose: true,
|
|
63
|
-
})}</span
|
|
64
|
-
>
|
|
65
|
-
</Text>
|
|
66
|
-
</Stack>
|
|
67
|
-
</HStack>
|
|
43
|
+
{#if repository.meter}
|
|
44
|
+
<FormatBytes bytes={repository.meter.sizeBytes} />
|
|
45
|
+
{:else}
|
|
46
|
+
Estimated <FormatBytes bytes={repository.metrics.sizeBytes} />
|
|
47
|
+
{/if} ·
|
|
48
|
+
<span class="lowercase">
|
|
49
|
+
{cronstrue.toString(schedule.cron, { verbose: true })}
|
|
50
|
+
</span>
|
|
68
51
|
|
|
69
52
|
{#snippet trailing()}
|
|
70
|
-
<
|
|
53
|
+
<Button
|
|
71
54
|
variant="ghost"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
size="small"
|
|
56
|
+
class="whitespace-nowrap"
|
|
57
|
+
leadingIcon={mdiCloudUploadOutline}
|
|
58
|
+
onclick={() => void handleCreateBackup(repository.id)}
|
|
59
|
+
>
|
|
60
|
+
Back up now
|
|
61
|
+
</Button>
|
|
76
62
|
{/snippet}
|
|
77
|
-
</StackListItem>
|
|
78
63
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
/>
|
|
94
|
-
</HStack>
|
|
95
|
-
</StackListItem>
|
|
96
|
-
{/if}
|
|
97
|
-
{:else}
|
|
98
|
-
<StackListItem class="bg-warning-50">
|
|
99
|
-
<HStack>
|
|
100
|
-
<Icon icon={mdiInformation} /> Backup is yet to run.
|
|
101
|
-
</HStack>
|
|
102
|
-
</StackListItem>
|
|
103
|
-
{/if}
|
|
64
|
+
{#snippet footer()}
|
|
65
|
+
<Icon icon={status.icon} />
|
|
66
|
+
|
|
67
|
+
{#if !repository.metrics.lastBackup}
|
|
68
|
+
Backup is yet to run.
|
|
69
|
+
{:else if status.color === "danger"}
|
|
70
|
+
Last backup failed <RelativeTime time={repository.metrics.lastBackup} />
|
|
71
|
+
{:else}
|
|
72
|
+
Last backup successful <RelativeTime
|
|
73
|
+
time={repository.metrics.lastBackup}
|
|
74
|
+
/>
|
|
75
|
+
{/if}
|
|
76
|
+
{/snippet}
|
|
77
|
+
</StackListItem>
|
|
104
78
|
</StackList>
|
|
@@ -1,39 +1,56 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import OnboardingBootstrapError from "../../onboarding/OnboardingBootstrapError.svelte";
|
|
3
|
-
import OnboardingStageBackupServices from "../../onboarding/stages/OnboardingStageBackupServices.svelte";
|
|
4
|
-
import OnboardingStageKeyConfirm from "../../onboarding/stages/OnboardingStageKeyConfirm.svelte";
|
|
5
3
|
import OnboardingStageKeyImport from "../../onboarding/stages/OnboardingStageKeyImport.svelte";
|
|
6
|
-
import OnboardingStageKeyIntro from "../../onboarding/stages/OnboardingStageKeyIntro.svelte";
|
|
7
|
-
import OnboardingStageSaveKey from "../../onboarding/stages/OnboardingStageKeySave.svelte";
|
|
8
4
|
import OnboardingStageTelemetry from "../../onboarding/stages/OnboardingStageTelemetry.svelte";
|
|
9
|
-
import
|
|
5
|
+
import OnboardingStepFinishSetup from "../../onboarding/steps/OnboardingStep1FinishSetup.svelte";
|
|
6
|
+
import OnboardingStepConnectAccount from "../../onboarding/steps/OnboardingStep2ConnectAccount.svelte";
|
|
7
|
+
import OnboardingStepSaveRecoveryKey from "../../onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte";
|
|
8
|
+
import OnboardingStepFirstBackup from "../../onboarding/steps/OnboardingStep4FirstBackup.svelte";
|
|
10
9
|
import type { OnboardingStatusResponseDto } from "../../../fetch-client";
|
|
10
|
+
import {
|
|
11
|
+
handleSetupLocalStorage,
|
|
12
|
+
handleStartYuccaLogin,
|
|
13
|
+
} from "../../../services/backend.service";
|
|
14
|
+
import {
|
|
15
|
+
IMMICH_DEFAULT_CRON,
|
|
16
|
+
useConfigureImmichDefaults,
|
|
17
|
+
} from "../../../services/integrations.service";
|
|
11
18
|
import {
|
|
12
19
|
handleConfirmRecoveryKey,
|
|
13
20
|
handleCurrentRecoveryKey,
|
|
14
21
|
handleOnboardingStatus,
|
|
15
22
|
} from "../../../services/onboarding.service";
|
|
16
|
-
import { LoadingSpinner } from "@immich/ui";
|
|
23
|
+
import { LoadingSpinner, Modal, ModalBody } from "@immich/ui";
|
|
24
|
+
import cronstrue from "cronstrue";
|
|
17
25
|
import { onMount, type Snippet } from "svelte";
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
type Stage =
|
|
28
|
+
| "idle"
|
|
29
|
+
| "intro"
|
|
30
|
+
| "telemetry"
|
|
31
|
+
| "connect"
|
|
32
|
+
| "key-import"
|
|
33
|
+
| "key"
|
|
34
|
+
| "backup"
|
|
35
|
+
| "finished";
|
|
20
36
|
|
|
21
37
|
type Props = {
|
|
22
|
-
|
|
38
|
+
fallback: Snippet<[() => void]>;
|
|
23
39
|
children: Snippet;
|
|
24
40
|
};
|
|
25
41
|
|
|
26
|
-
const {
|
|
42
|
+
const { fallback, children }: Props = $props();
|
|
27
43
|
|
|
28
44
|
let code = $state("");
|
|
29
|
-
let
|
|
45
|
+
let storageLocation = $state("FUTO Backups");
|
|
30
46
|
let status: OnboardingStatusResponseDto | undefined = $state();
|
|
31
|
-
let stage:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
let stage: Stage = $state("idle");
|
|
48
|
+
let resume: Stage = $state("intro");
|
|
49
|
+
let confirming = $state(false);
|
|
50
|
+
|
|
51
|
+
const defaults = useConfigureImmichDefaults();
|
|
52
|
+
|
|
53
|
+
const schedule = cronstrue.toString(IMMICH_DEFAULT_CRON, { verbose: true });
|
|
37
54
|
|
|
38
55
|
onMount(() => {
|
|
39
56
|
handleOnboardingStatus().then(async (data) => {
|
|
@@ -44,12 +61,12 @@
|
|
|
44
61
|
}
|
|
45
62
|
|
|
46
63
|
if (data.hasOnboardedKey) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
if (data.hasBackup) {
|
|
65
|
+
stage = "finished";
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
resume = data.hasTelemetry === "none" ? "telemetry" : "connect";
|
|
53
70
|
} else {
|
|
54
71
|
const { recoveryKey } = await handleCurrentRecoveryKey();
|
|
55
72
|
code = recoveryKey;
|
|
@@ -57,75 +74,99 @@
|
|
|
57
74
|
});
|
|
58
75
|
});
|
|
59
76
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
const onStart = () => (stage = resume);
|
|
78
|
+
const onCancel = () => (stage = "idle");
|
|
79
|
+
|
|
80
|
+
const afterTelemetry = () =>
|
|
81
|
+
(stage = status?.hasOnboardedKey && status.hasBackup
|
|
82
|
+
? "finished"
|
|
83
|
+
: "connect");
|
|
84
|
+
|
|
85
|
+
const onBackendReady = () => (stage = status?.hasOnboardedKey ? "backup" : "key");
|
|
86
|
+
|
|
87
|
+
const onConnect = () => {
|
|
88
|
+
storageLocation = "FUTO Backups";
|
|
89
|
+
handleStartYuccaLogin(onBackendReady);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const onLocalStorage = () => {
|
|
93
|
+
storageLocation = "Local Storage";
|
|
94
|
+
handleSetupLocalStorage(onBackendReady);
|
|
63
95
|
};
|
|
64
96
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
97
|
+
const onConfirmKey = async () => {
|
|
98
|
+
confirming = true;
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
await handleConfirmRecoveryKey();
|
|
102
|
+
stage = "backup";
|
|
103
|
+
} finally {
|
|
104
|
+
confirming = false;
|
|
105
|
+
}
|
|
68
106
|
};
|
|
107
|
+
|
|
108
|
+
const onStartBackup = () =>
|
|
109
|
+
defaults.mutate(undefined, { onSuccess: () => (stage = "finished") });
|
|
69
110
|
</script>
|
|
70
111
|
|
|
71
112
|
{#if status === undefined || status.status === "not-ready"}
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
113
|
+
<div class="flex h-full items-center justify-center p-8">
|
|
114
|
+
<LoadingSpinner />
|
|
115
|
+
</div>
|
|
75
116
|
{:else if stage === "finished"}
|
|
76
117
|
{@render children()}
|
|
77
|
-
{:else
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/>
|
|
118
|
+
{:else}
|
|
119
|
+
{@render fallback(onStart)}
|
|
120
|
+
{/if}
|
|
121
|
+
|
|
122
|
+
{#if status?.status === "error" && stage !== "idle"}
|
|
123
|
+
<OnboardingBootstrapError error={status.error} onQuit={onCancel} />
|
|
124
|
+
{:else if stage === "intro"}
|
|
125
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
126
|
+
<ModalBody>
|
|
127
|
+
<OnboardingStepFinishSetup
|
|
128
|
+
onContinue={() =>
|
|
129
|
+
(stage = status?.hasTelemetry === "none" ? "telemetry" : "connect")}
|
|
130
|
+
onImportKey={() => (stage = "key-import")}
|
|
131
|
+
/>
|
|
132
|
+
</ModalBody>
|
|
133
|
+
</Modal>
|
|
83
134
|
{:else if stage === "telemetry"}
|
|
84
|
-
<OnboardingStageTelemetry
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
onCancel={onExit}
|
|
92
|
-
/>
|
|
135
|
+
<OnboardingStageTelemetry onContinue={afterTelemetry} {onCancel} />
|
|
136
|
+
{:else if stage === "connect"}
|
|
137
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
138
|
+
<ModalBody>
|
|
139
|
+
<OnboardingStepConnectAccount {onConnect} {onLocalStorage} />
|
|
140
|
+
</ModalBody>
|
|
141
|
+
</Modal>
|
|
93
142
|
{:else if stage === "key-import"}
|
|
94
143
|
<OnboardingStageKeyImport
|
|
95
|
-
onStart={() => (stage = "
|
|
96
|
-
onImported={() =>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
onNext={() => (stage = "key-save")}
|
|
102
|
-
onCancel={onExit}
|
|
103
|
-
/>
|
|
104
|
-
{:else if stage === "key-save"}
|
|
105
|
-
<OnboardingStageSaveKey
|
|
106
|
-
{code}
|
|
107
|
-
onNext={() => (stage = "key-confirm")}
|
|
108
|
-
onCancel={onExit}
|
|
109
|
-
/>
|
|
110
|
-
{:else if stage === "key-confirm"}
|
|
111
|
-
<OnboardingStageKeyConfirm
|
|
112
|
-
{code}
|
|
113
|
-
onBack={() => (stage = "key-save")}
|
|
114
|
-
onCancel={onExit}
|
|
115
|
-
{onConfirmKey}
|
|
116
|
-
/>
|
|
117
|
-
{:else if stage === "backup-service"}
|
|
118
|
-
<OnboardingStageBackupServices onNext={onSelectBackend} onCancel={onExit} />
|
|
119
|
-
{:else if stage === "backup-confirm"}
|
|
120
|
-
<ImmichConfirmDefaultBackup
|
|
121
|
-
onCustomize={() => (stage = "backup-create")}
|
|
122
|
-
onConfirm={() => (stage = "finished")}
|
|
123
|
-
onCancel={onExit}
|
|
124
|
-
/>
|
|
125
|
-
{:else if stage === "backup-create"}
|
|
126
|
-
<ImmichConfigureBackup
|
|
127
|
-
onFinish={() => (stage = "finished")}
|
|
128
|
-
onCancel={onExit}
|
|
129
|
-
{backendId}
|
|
144
|
+
onStart={() => (stage = "intro")}
|
|
145
|
+
onImported={(key) => {
|
|
146
|
+
code = key;
|
|
147
|
+
stage = "connect";
|
|
148
|
+
}}
|
|
149
|
+
{onCancel}
|
|
130
150
|
/>
|
|
151
|
+
{:else if stage === "key"}
|
|
152
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
153
|
+
<ModalBody>
|
|
154
|
+
<OnboardingStepSaveRecoveryKey
|
|
155
|
+
{code}
|
|
156
|
+
onContinue={onConfirmKey}
|
|
157
|
+
loading={confirming}
|
|
158
|
+
/>
|
|
159
|
+
</ModalBody>
|
|
160
|
+
</Modal>
|
|
161
|
+
{:else if stage === "backup"}
|
|
162
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
163
|
+
<ModalBody>
|
|
164
|
+
<OnboardingStepFirstBackup
|
|
165
|
+
{schedule}
|
|
166
|
+
{storageLocation}
|
|
167
|
+
{onStartBackup}
|
|
168
|
+
loading={defaults.isPending}
|
|
169
|
+
/>
|
|
170
|
+
</ModalBody>
|
|
171
|
+
</Modal>
|
|
131
172
|
{/if}
|