@futo-org/backups-orchestrator-ui 0.27.0 → 0.30.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.
Files changed (163) hide show
  1. package/dist/components/backends/BackendItem.svelte +28 -24
  2. package/dist/components/backends/BackendsList.svelte +33 -34
  3. package/dist/components/backends/BackendsList.svelte.d.ts +1 -0
  4. package/dist/components/backends/dialogs/SelectBackendModal.svelte +44 -55
  5. package/dist/components/backups/BackupItem.svelte +33 -26
  6. package/dist/components/backups/BackupStatus.svelte +200 -0
  7. package/dist/components/backups/BackupStatus.svelte.d.ts +19 -0
  8. package/dist/components/backups/BackupsList.svelte +17 -11
  9. package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +2 -2
  10. package/dist/components/backups/dialogs/SelectRepositoryModal.svelte +26 -36
  11. package/dist/components/backups/dialogs/ViewStatusModal.svelte +175 -0
  12. package/dist/components/backups/dialogs/ViewStatusModal.svelte.d.ts +8 -0
  13. package/dist/components/backups/run-history/RepositoryRunHistory.svelte +23 -12
  14. package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +2 -0
  15. package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +46 -20
  16. package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte +136 -0
  17. package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte.d.ts +8 -0
  18. package/dist/components/backups/run-history/RunHistoryModal.svelte +2 -2
  19. package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +22 -10
  20. package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +2 -0
  21. package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +23 -21
  22. package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte +115 -0
  23. package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte.d.ts +9 -0
  24. package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +2 -2
  25. package/dist/components/dashboard/Dashboard.svelte +14 -7
  26. package/dist/components/dashboard/Dashboard.svelte.d.ts +1 -1
  27. package/dist/components/dashboard/DashboardAvgBackupTime.svelte +1 -1
  28. package/dist/components/dashboard/DashboardBackupHealth.svelte +5 -9
  29. package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +1 -1
  30. package/dist/components/dashboard/DashboardCurrentUsage.svelte +1 -1
  31. package/dist/components/dashboard/DashboardDailyBackupTime.svelte +1 -1
  32. package/dist/components/dashboard/DashboardInstall.svelte +1 -1
  33. package/dist/components/dashboard/DashboardRecentBackups.svelte +47 -78
  34. package/dist/components/dashboard/DashboardTotalStored.svelte +1 -1
  35. package/dist/components/integrations/immich/ImmichBackupSettings.svelte +12 -0
  36. package/dist/components/integrations/immich/ImmichBackupSettings.svelte.d.ts +18 -0
  37. package/dist/components/integrations/immich/ImmichBackupsCard.svelte +109 -0
  38. package/dist/components/integrations/immich/ImmichBackupsCard.svelte.d.ts +13 -0
  39. package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte +55 -0
  40. package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte.d.ts +10 -0
  41. package/dist/components/integrations/immich/ImmichBackupsPage.svelte +16 -3
  42. package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +8 -1
  43. package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +102 -0
  44. package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte.d.ts +8 -0
  45. package/dist/components/integrations/immich/ImmichManageBackup.svelte +53 -14
  46. package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +45 -71
  47. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +123 -82
  48. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +1 -1
  49. package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte +313 -0
  50. package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte.d.ts +3 -0
  51. package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte +218 -0
  52. package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte.d.ts +3 -0
  53. package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte +207 -0
  54. package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte.d.ts +3 -0
  55. package/dist/components/onboarding/RecoveryKeyDisplay.svelte +34 -20
  56. package/dist/components/onboarding/SampleOnboarding.svelte +57 -38
  57. package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +10 -24
  58. package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte +44 -0
  59. package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte.d.ts +7 -0
  60. package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte +50 -0
  61. package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte.d.ts +7 -0
  62. package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte +45 -0
  63. package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte.d.ts +8 -0
  64. package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte +67 -0
  65. package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte.d.ts +9 -0
  66. package/dist/components/onboarding/steps/OnboardingStepLayout.svelte +58 -0
  67. package/dist/components/onboarding/steps/OnboardingStepLayout.svelte.d.ts +19 -0
  68. package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte +52 -0
  69. package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte.d.ts +18 -0
  70. package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte +33 -0
  71. package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte.d.ts +8 -0
  72. package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte +32 -0
  73. package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte.d.ts +11 -0
  74. package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte +7 -0
  75. package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte.d.ts +18 -0
  76. package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte +46 -0
  77. package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte.d.ts +6 -0
  78. package/dist/components/onboarding/upsell/UpsellModal.svelte +43 -0
  79. package/dist/components/onboarding/upsell/UpsellModal.svelte.d.ts +9 -0
  80. package/dist/components/onboarding/upsell/UpsellPage.svelte +40 -0
  81. package/dist/components/onboarding/upsell/UpsellPage.svelte.d.ts +14 -0
  82. package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte +58 -0
  83. package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte.d.ts +8 -0
  84. package/dist/components/schedules/RepositoryPicker.svelte +45 -38
  85. package/dist/components/schedules/ScheduleItem.svelte +32 -26
  86. package/dist/components/schedules/ScheduleList.svelte +16 -10
  87. package/dist/components/settings/GlobalSettings.svelte +8 -0
  88. package/dist/components/settings/GlobalSettings.svelte.d.ts +18 -0
  89. package/dist/components/settings/SettingsBackends.svelte +16 -0
  90. package/dist/components/settings/SettingsBackends.svelte.d.ts +18 -0
  91. package/dist/components/settings/SettingsBilling.svelte +69 -0
  92. package/dist/components/settings/SettingsBilling.svelte.d.ts +6 -0
  93. package/dist/components/settings/SettingsNotifications.svelte +47 -0
  94. package/dist/components/settings/SettingsNotifications.svelte.d.ts +6 -0
  95. package/dist/components/test/ImmichTestUi.svelte +143 -27
  96. package/dist/components/test/TestUi.svelte +4 -4
  97. package/dist/components/test/dashboard/ActiveJobs.svelte +2 -2
  98. package/dist/components/test/immich/MockImmichHideBackupsReminder.svelte +12 -0
  99. package/dist/components/test/immich/MockImmichHideBackupsReminder.svelte.d.ts +3 -0
  100. package/dist/components/test/immich/MockImmichPhotos.svelte +36 -0
  101. package/dist/components/test/immich/MockImmichPhotos.svelte.d.ts +18 -0
  102. package/dist/components/test/immich/MockImmichPurchaseInfo.svelte +29 -0
  103. package/dist/components/test/immich/MockImmichPurchaseInfo.svelte.d.ts +18 -0
  104. package/dist/components/test/immich/MockImmichServerStatus.svelte +9 -0
  105. package/dist/components/test/immich/MockImmichServerStatus.svelte.d.ts +18 -0
  106. package/dist/components/test/immich/MockImmichSidebar.svelte +20 -0
  107. package/dist/components/test/immich/MockImmichSidebar.svelte.d.ts +7 -0
  108. package/dist/components/test/immich/MockImmichStorageSpace.svelte +25 -0
  109. package/dist/components/test/immich/MockImmichStorageSpace.svelte.d.ts +7 -0
  110. package/dist/components/ui/Accordion.svelte +67 -0
  111. package/dist/components/ui/Accordion.svelte.d.ts +11 -0
  112. package/dist/components/ui/ListToolbar.svelte +60 -0
  113. package/dist/components/ui/ListToolbar.svelte.d.ts +16 -0
  114. package/dist/components/ui/PageLayout.svelte +21 -9
  115. package/dist/components/ui/PageLayout.svelte.d.ts +1 -0
  116. package/dist/components/ui/Pagination.svelte +80 -0
  117. package/dist/components/ui/Pagination.svelte.d.ts +8 -0
  118. package/dist/components/ui/PathListField.svelte +17 -14
  119. package/dist/components/ui/StackList.svelte +18 -18
  120. package/dist/components/ui/StackList.svelte.d.ts +6 -27
  121. package/dist/components/ui/StackListItem.svelte +47 -25
  122. package/dist/components/ui/StackListItem.svelte.d.ts +5 -2
  123. package/dist/components/ui/StackListOption.svelte +33 -0
  124. package/dist/components/ui/StackListOption.svelte.d.ts +11 -0
  125. package/dist/components/ui/StackListPlaceholder.svelte +12 -0
  126. package/dist/components/ui/StackListPlaceholder.svelte.d.ts +7 -0
  127. package/dist/components/ui/StepNumber.svelte +20 -0
  128. package/dist/components/ui/StepNumber.svelte.d.ts +7 -0
  129. package/dist/components/util/Suspense.svelte +7 -3
  130. package/dist/components/util/YuccaContext.svelte +1 -1
  131. package/dist/events.js +1 -1
  132. package/dist/fetch-client.d.ts +2 -0
  133. package/dist/index.d.ts +6 -1
  134. package/dist/index.js +6 -1
  135. package/dist/services/backend.service.js +3 -0
  136. package/dist/services/immich.integration.service.d.ts +1 -1
  137. package/dist/services/immich.integration.service.js +2 -3
  138. package/dist/services/integrations.service.d.ts +1 -0
  139. package/dist/services/integrations.service.js +2 -1
  140. package/dist/services/log.service.svelte.d.ts +12 -0
  141. package/dist/services/log.service.svelte.js +15 -1
  142. package/dist/services/repository.service.js +9 -3
  143. package/dist/services/runHistory.service.d.ts +1 -1
  144. package/dist/services/runHistory.service.js +5 -4
  145. package/dist/utils/format.d.ts +1 -1
  146. package/dist/utils/format.js +2 -2
  147. package/package.json +3 -3
  148. package/dist/components/backups/dialogs/ViewLogModal.svelte +0 -208
  149. package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +0 -7
  150. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +0 -403
  151. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +0 -9
  152. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +0 -80
  153. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +0 -8
  154. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +0 -56
  155. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +0 -9
  156. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +0 -50
  157. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +0 -7
  158. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +0 -44
  159. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +0 -8
  160. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +0 -56
  161. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +0 -9
  162. package/dist/components/util/TimedButton.svelte +0 -37
  163. 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,27 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import UpsellPage from "../../onboarding/upsell/UpsellPage.svelte";
2
4
  import ImmichManageBackup from "./ImmichManageBackup.svelte";
3
5
  import ImmichOnboardingSetupFlow from "./ImmichOnboardingSetupFlow.svelte";
4
6
 
7
+ type Question = {
8
+ title: string;
9
+ answer: string | Snippet;
10
+ };
11
+
5
12
  type Props = {
6
- onExit: () => void;
13
+ price: string;
14
+ includedStorage: string;
15
+ questions: Question[];
7
16
  };
8
17
 
9
- const { onExit }: Props = $props();
18
+ const { price, includedStorage, questions }: Props = $props();
10
19
  </script>
11
20
 
12
- <ImmichOnboardingSetupFlow {onExit}>
21
+ <ImmichOnboardingSetupFlow>
22
+ {#snippet fallback(onStart)}
23
+ <UpsellPage {price} {includedStorage} {questions} onGetStarted={onStart} />
24
+ {/snippet}
25
+
13
26
  <ImmichManageBackup />
14
27
  </ImmichOnboardingSetupFlow>
@@ -1,5 +1,12 @@
1
+ import type { Snippet } from "svelte";
2
+ type Question = {
3
+ title: string;
4
+ answer: string | Snippet;
5
+ };
1
6
  type Props = {
2
- onExit: () => void;
7
+ price: string;
8
+ includedStorage: string;
9
+ questions: Question[];
3
10
  };
4
11
  declare const ImmichBackupsPage: import("svelte").Component<Props, {}, "">;
5
12
  type ImmichBackupsPage = ReturnType<typeof ImmichBackupsPage>;
@@ -0,0 +1,102 @@
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 {
12
+ useRunEventHandler,
13
+ useRunHistory,
14
+ } from "../../../services/runHistory.service";
15
+ import {
16
+ useScheduleEventHandler,
17
+ useSchedules,
18
+ } from "../../../services/schedule.service";
19
+ import ImmichBackupsCard from "./ImmichBackupsCard.svelte";
20
+
21
+ type Props = {
22
+ href?: string;
23
+ onclick?: () => void;
24
+ class?: string;
25
+ };
26
+
27
+ const { href = "/backups", onclick, class: className }: Props = $props();
28
+
29
+ // TODO: this should probably be condensed into one big request - since this loads on every initial Immich page load (in the future)
30
+
31
+ const integrations = useIntegrations();
32
+ const repositories = useRepositories();
33
+ const schedules = useSchedules();
34
+
35
+ const { onIntegrationUpdate } = useIntegrationEventHandler();
36
+ const { onRepositoryCreate, onRepositoryUpdate, onRepositoryDelete } =
37
+ useRepositoryEventHandler();
38
+ const { onScheduleCreate, onScheduleUpdate, onScheduleDelete } =
39
+ useScheduleEventHandler();
40
+ const { onRunCreate, onRunUpdate } = useRunEventHandler();
41
+
42
+ const integration = $derived(integrations.data?.immichIntegration);
43
+
44
+ const repository = $derived(
45
+ integration
46
+ ? repositories.data?.find((entry) => entry.id === integration.id)
47
+ : undefined,
48
+ );
49
+
50
+ const runHistory = useRunHistory(() => repository?.id);
51
+
52
+ const latestBackupRun = $derived(
53
+ runHistory.data?.find(
54
+ (run) => run.type === "backup" || run.type === "schedule",
55
+ ),
56
+ );
57
+
58
+ const paused = $derived(
59
+ Boolean(
60
+ integration &&
61
+ schedules.data?.find((entry) => entry.id === integration.scheduleId)
62
+ ?.paused,
63
+ ),
64
+ );
65
+
66
+ const lastBackup = $derived(repository?.metrics.lastBackup ?? undefined);
67
+
68
+ const failed = $derived(
69
+ Boolean(
70
+ lastBackup && lastBackup !== repository?.metrics.lastSuccessfulBackup,
71
+ ),
72
+ );
73
+
74
+ const loading = $derived(
75
+ integrations.isLoading || repositories.isLoading || schedules.isLoading,
76
+ );
77
+ </script>
78
+
79
+ <OnEvents
80
+ {onIntegrationUpdate}
81
+ {onRepositoryCreate}
82
+ {onRepositoryUpdate}
83
+ {onRepositoryDelete}
84
+ {onScheduleCreate}
85
+ {onScheduleUpdate}
86
+ {onScheduleDelete}
87
+ {onRunCreate}
88
+ {onRunUpdate}
89
+ />
90
+
91
+ {#if !loading}
92
+ <ImmichBackupsCard
93
+ {href}
94
+ {failed}
95
+ {paused}
96
+ {onclick}
97
+ {lastBackup}
98
+ class={className}
99
+ configured={Boolean(repository)}
100
+ running={latestBackupRun?.status === "incomplete"}
101
+ />
102
+ {/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
- const { ViewRecoveryKey, Configure, BackUpNow } = $derived(
52
- getBackupPageActions(repository?.id),
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
- <PageLayout title="Backups" actions={[ViewRecoveryKey, Configure, BackUpNow]}>
67
- <Container size="large" center>
68
- {#if repository && schedule}
69
- <Stack class="mt-4" gap={8}>
70
- <ImmichManageBackupOverview {repository} {schedule} />
71
- <BackendsList {repository} />
72
- <RepositoryRunHistory {repository} />
73
- <RepositorySnapshotsList {repository} immich />
74
- </Stack>
75
- {/if}
76
- </Container>
77
- </PageLayout>
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
- handlePauseSchedule,
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
- function togglePause() {
37
- if (schedule!.paused) {
38
- handleResumeSchedule(schedule!.id, "Immich");
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} size="32px" />
40
+ <Icon icon={mdiArchiveOutline} />
49
41
  {/snippet}
50
42
 
51
- <HStack gap={4}>
52
- <Stack gap={0}>
53
- <Heading size="tiny">Your library</Heading>
54
- <Text>
55
- {#if repository.meter}
56
- <FormatBytes bytes={repository.meter.sizeBytes} />
57
- {:else}
58
- Estimated <FormatBytes bytes={repository.metrics.sizeBytes} />
59
- {/if} &middot;
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} &middot;
48
+ <span class="lowercase">
49
+ {cronstrue.toString(schedule.cron, { verbose: true })}
50
+ </span>
68
51
 
69
52
  {#snippet trailing()}
70
- <IconButton
53
+ <Button
71
54
  variant="ghost"
72
- onclick={togglePause}
73
- aria-label={schedule.paused ? "Resume backups" : "Pause backups"}
74
- icon={schedule.paused ? mdiPlayCircleOutline : mdiPauseCircleOutline}
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
- {#if repository.metrics.lastBackup}
80
- {#if repository.metrics.lastBackup !== repository.metrics.lastSuccessfulBackup}
81
- <StackListItem class="bg-danger-100">
82
- <HStack>
83
- <Icon icon={mdiAlert} /> Last backup failed <RelativeTime
84
- time={repository.metrics.lastBackup}
85
- />
86
- </HStack>
87
- </StackListItem>
88
- {:else}
89
- <StackListItem class="bg-success-50">
90
- <HStack>
91
- <Icon icon={mdiCheck} /> Last backup successful <RelativeTime
92
- time={repository.metrics.lastBackup}
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>