@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
@@ -1,403 +0,0 @@
1
- <script lang="ts">
2
- import Suspense from "../../util/Suspense.svelte";
3
- import * as sdk from "../../../fetch-client";
4
- import {
5
- useConfigureImmichIntegration,
6
- useIntegrations,
7
- } from "../../../services/integrations.service";
8
- import { useRepositories } from "../../../services/repository.service";
9
- import { useSchedules } from "../../../services/schedule.service";
10
- import {
11
- Button,
12
- Checkbox,
13
- Field,
14
- FormModal,
15
- Heading,
16
- HStack,
17
- Input,
18
- Select,
19
- Stack,
20
- Switch,
21
- Text,
22
- } from "@immich/ui";
23
- import validateCron from "cron-validate";
24
- import cronstrue from "cronstrue";
25
- import { SvelteSet } from "svelte/reactivity";
26
-
27
- type Props = {
28
- onFinish?: () => void;
29
- onCancel?: () => void;
30
- onClose?: () => void;
31
- backendId?: string;
32
- };
33
-
34
- let { onFinish, onCancel, onClose }: Props = $props();
35
-
36
- const query = useIntegrations();
37
- const schedulesQuery = useSchedules();
38
- const repositoriesQuery = useRepositories();
39
-
40
- type RetentionChoice = {
41
- key: string;
42
- label: string;
43
- policy: sdk.RetentionPolicyDto | null;
44
- };
45
-
46
- const retentionChoices: RetentionChoice[] = [
47
- { key: "15d", label: "After 15 days", policy: { keepWithin: "15d" } },
48
- { key: "30d", label: "After 30 days", policy: { keepWithin: "30d" } },
49
- { key: "60d", label: "After 60 days", policy: { keepWithin: "60d" } },
50
- { key: "90d", label: "After 90 days", policy: { keepWithin: "90d" } },
51
- { key: "2", label: "Keep latest two backups", policy: { keepLast: 2 } },
52
- { key: "never", label: "Never (keep all backups)", policy: null },
53
- ];
54
- const defaultRetentionKey = "60d";
55
-
56
- let name = $state("Immich");
57
- let worm = $state(false);
58
- let backupConfiguration = $state(true);
59
- let librariesMode = $state<"all" | "none" | "some">("all");
60
- let retentionKey = $state<string>(defaultRetentionKey);
61
-
62
- let cron = $state("0 3 * * *");
63
- let scheduleMode = $state<"daily" | "custom">("daily");
64
- let scheduleHour = $state(3);
65
- let scheduleMinute = $state(0);
66
-
67
- const selectedFolders = new SvelteSet<string>();
68
- const selectedLibraries = new SvelteSet<string>();
69
-
70
- type FolderItem = { label: string; description?: string; folders: string[] };
71
-
72
- let populated = false;
73
-
74
- $effect(() => {
75
- if (populated || !query.data?.immichState) {
76
- return;
77
- }
78
- populated = true;
79
-
80
- const integration = query.data.immichIntegration;
81
- if (integration) {
82
- const config = integration.configuration;
83
- backupConfiguration = config.backupConfiguration;
84
-
85
- const repository = repositoriesQuery.data?.find(
86
- (entry) => entry.id === integration.id,
87
- );
88
-
89
- const policy = repository?.configuration?.retentionPolicy ?? null;
90
- const matched = retentionChoices.find(
91
- (choice) => JSON.stringify(choice.policy) === JSON.stringify(policy),
92
- );
93
- retentionKey = matched?.key ?? defaultRetentionKey;
94
-
95
- if (config.libraries === "all") {
96
- librariesMode = "all";
97
- } else if (config.libraries.length === 0) {
98
- librariesMode = "none";
99
- } else {
100
- librariesMode = "some";
101
-
102
- for (const id of config.libraries) {
103
- selectedLibraries.add(id);
104
- }
105
- }
106
-
107
- for (const folder of config.dataFolders) {
108
- selectedFolders.add(folder);
109
- }
110
-
111
- const schedule = schedulesQuery.data?.find(
112
- (schedule) => schedule.id === integration.scheduleId,
113
- );
114
-
115
- if (schedule) {
116
- cron = schedule.cron;
117
-
118
- const match = /(\d+) (\d+) \* \* \*/.exec(cron);
119
- if (match) {
120
- scheduleMode = "daily";
121
- scheduleHour = parseInt(match[2]);
122
- scheduleMinute = parseInt(match[1]);
123
- } else {
124
- scheduleMode = "custom";
125
- }
126
- }
127
- } else {
128
- for (const folder of query.data.immichState.dataFolders) {
129
- selectedFolders.add(folder);
130
- }
131
- }
132
- });
133
-
134
- const effectiveCron = $derived(
135
- scheduleMode === "daily" ? `${scheduleMinute} ${scheduleHour} * * *` : cron,
136
- );
137
-
138
- const mutation = useConfigureImmichIntegration();
139
-
140
- const onSubmit = () => {
141
- selectedFolders.add("backups");
142
-
143
- mutation.mutate(
144
- {
145
- name,
146
- worm,
147
- cron: effectiveCron,
148
- dataFolders: [...selectedFolders],
149
- backupConfiguration,
150
- libraries:
151
- librariesMode === "all"
152
- ? "all"
153
- : librariesMode === "none"
154
- ? []
155
- : [...selectedLibraries],
156
- retentionPolicy: worm
157
- ? null
158
- : (retentionChoices.find((choice) => choice.key === retentionKey)
159
- ?.policy ?? null),
160
- },
161
- {
162
- onSuccess: () => {
163
- onFinish?.();
164
- onClose?.();
165
- },
166
- },
167
- );
168
- };
169
-
170
- function applicableFolders(item: FolderItem, available: string[]): string[] {
171
- return item.folders.filter((folder) => available.includes(folder));
172
- }
173
-
174
- function isItemChecked(item: FolderItem, available: string[]): boolean {
175
- const folders = applicableFolders(item, available);
176
- return (
177
- folders.length > 0 &&
178
- folders.every((folder) => selectedFolders.has(folder))
179
- );
180
- }
181
-
182
- function toggleItem(item: FolderItem, available: string[]) {
183
- const folders = applicableFolders(item, available);
184
- const allOn = folders.every((folder) => selectedFolders.has(folder));
185
- for (const folder of folders) {
186
- if (allOn) {
187
- selectedFolders.delete(folder);
188
- } else {
189
- selectedFolders.add(folder);
190
- }
191
- }
192
- }
193
-
194
- function toggleLibrary(id: string) {
195
- if (selectedLibraries.has(id)) {
196
- selectedLibraries.delete(id);
197
- } else {
198
- selectedLibraries.add(id);
199
- }
200
- }
201
- </script>
202
-
203
- <FormModal
204
- title="Backup settings"
205
- size="large"
206
- disabled={(scheduleMode === "custom" &&
207
- !validateCron(effectiveCron).isError()) ||
208
- name.length === 0 ||
209
- mutation.isPending}
210
- onClose={() => {
211
- onCancel?.();
212
- onClose?.();
213
- }}
214
- {onSubmit}
215
- >
216
- <Stack gap={6}>
217
- <Field label="Name">
218
- <Input bind:value={name} />
219
- </Field>
220
-
221
- <Suspense {query}>
222
- {#snippet children({ immichState: immich })}
223
- <Stack gap={2}>
224
- <Heading size="tiny">What to back up</Heading>
225
-
226
- {#each [{ label: "Photos and videos", description: "Your media uploaded directly to Immich.", folders: ["upload", "profile", "library"], recommended: true }, { label: "Database backups", description: "Albums, faces, and metadata. You'll need this to restore.", folders: ["backups"], required: true }, { label: "Thumbnails and previews", description: "Generated photo previews, can be recreated later.", folders: ["thumbs"], regenerate: true }, { label: "Encoded videos", description: "Generated video previews, can be recreated later.", folders: ["encoded-video"], regenerate: true }] as item (item.label)}
227
- <label class="select-none">
228
- <Stack direction="row">
229
- <Checkbox
230
- checked={item.required ||
231
- isItemChecked(item, immich!.dataFolders)}
232
- onCheckedChange={() => toggleItem(item, immich!.dataFolders)}
233
- disabled={item.required}
234
- />
235
- <Stack gap={0}>
236
- <Text>{item.label}</Text>
237
- {#if item.description}
238
- <Text size="small" color="secondary"
239
- >{item.description}</Text
240
- >
241
- {/if}
242
- {#if item.recommended && !isItemChecked(item, immich!.dataFolders)}
243
- <Text size="small" color="danger"
244
- >It is highly recommended you back this up!</Text
245
- >
246
- {/if}
247
- {#if item.regenerate && !isItemChecked(item, immich!.dataFolders)}
248
- <Text size="small" color="warning"
249
- >When restoring, you will see broken previews, use the
250
- admin panel to regenerate them.</Text
251
- >
252
- {/if}
253
- </Stack>
254
- </Stack>
255
- </label>
256
- {/each}
257
-
258
- <label class="select-none">
259
- <Stack direction="row">
260
- <Checkbox bind:checked={backupConfiguration} />
261
- <Stack gap={0}>
262
- <Text>Backup configuration</Text>
263
- <Text size="small" color="secondary"
264
- >Saves these settings too.</Text
265
- >
266
- {#if !backupConfiguration}
267
- <Text size="small" color="warning"
268
- >You will need to reconfigure backups from scratch after
269
- restoring.</Text
270
- >
271
- {/if}
272
- </Stack>
273
- </Stack>
274
- </label>
275
- </Stack>
276
-
277
- <Stack gap={2}>
278
- <Stack gap={0}>
279
- <Heading size="tiny">External Libraries</Heading>
280
- <Text size="small" color="secondary">
281
- External libraries stored outside of Immich can also be included
282
- in your backup. <br /> By default, all existing and future external
283
- libraries will be included in your backup.
284
- </Text>
285
- </Stack>
286
-
287
- <HStack fullWidth>
288
- {#each [{ id: "all" as const, label: "All" }, { id: "none" as const, label: "None" }, { id: "some" as const, label: "Pick" }] as option (option.id)}
289
- <Button
290
- fullWidth
291
- size="small"
292
- variant={librariesMode === option.id ? "filled" : "outline"}
293
- color={librariesMode === option.id ? "primary" : "secondary"}
294
- onclick={() => (librariesMode = option.id)}
295
- >
296
- {option.label}
297
- </Button>
298
- {/each}
299
- </HStack>
300
-
301
- {#if librariesMode === "all"}
302
- {#if immich!.libraries.length !== 0}
303
- <Text size="small" color="secondary"
304
- >Libraries included: {immich!.libraries
305
- .map((item) => item.name)
306
- .join(", ")}</Text
307
- >
308
- {/if}
309
- {:else if librariesMode === "some"}
310
- {#if immich!.libraries.length === 0}
311
- <Text size="small" color="secondary"
312
- >No external libraries found.</Text
313
- >
314
- {:else}
315
- <Stack gap={1}>
316
- {#each immich!.libraries as library (library.id)}
317
- <label class="flex select-none items-center gap-2">
318
- <Checkbox
319
- checked={selectedLibraries.has(library.id)}
320
- onCheckedChange={() => toggleLibrary(library.id)}
321
- />
322
- <Text>{library.name}</Text>
323
- </label>
324
- {/each}
325
- </Stack>
326
- {/if}
327
- {/if}
328
- </Stack>
329
-
330
- <Stack gap={2}>
331
- <Heading size="tiny">Schedule</Heading>
332
-
333
- <HStack fullWidth>
334
- {#each [{ id: "daily" as const, label: "Every day" }, { id: "custom" as const, label: "Custom cron expression" }] as option (option.id)}
335
- <Button
336
- fullWidth
337
- size="small"
338
- variant={scheduleMode === option.id ? "filled" : "outline"}
339
- color={scheduleMode === option.id ? "primary" : "secondary"}
340
- onclick={() => (scheduleMode = option.id)}
341
- >
342
- {option.label}
343
- </Button>
344
- {/each}
345
- </HStack>
346
-
347
- {#if scheduleMode === "daily"}
348
- <Field label="Time">
349
- <Input
350
- type="time"
351
- value={`${String(scheduleHour).padStart(2, "0")}:${String(scheduleMinute).padStart(2, "0")}`}
352
- oninput={(event) => {
353
- const [hours, minutes] = (
354
- event.currentTarget as HTMLInputElement
355
- ).value.split(":");
356
- scheduleHour = Number(hours);
357
- scheduleMinute = Number(minutes);
358
- }}
359
- />
360
- </Field>
361
- {:else}
362
- <Field label="Cron expression">
363
- <Input bind:value={cron} placeholder="0 3 * * *" />
364
- </Field>
365
-
366
- <Text size="small" color="secondary"
367
- >Your backups will run <span class="lowercase"
368
- >{cronstrue.toString(cron, {
369
- verbose: true,
370
- })}</span
371
- ></Text
372
- >
373
- {/if}
374
- </Stack>
375
- {/snippet}
376
- </Suspense>
377
-
378
- <Stack gap={2}>
379
- <Heading size="tiny">Advanced</Heading>
380
- <Field
381
- label="Write-only"
382
- description="Once written, files can't be removed."
383
- >
384
- <Switch bind:checked={worm} />
385
- </Field>
386
-
387
- <Field
388
- label="Delete old backups"
389
- description="Older snapshots will be pruned automatically."
390
- disabled={worm}
391
- >
392
- <Select
393
- options={retentionChoices.map(({ key, label }) => ({
394
- value: key,
395
- label,
396
- }))}
397
- value={worm ? "never" : retentionKey}
398
- onChange={(value) => (retentionKey = value)}
399
- />
400
- </Field>
401
- </Stack>
402
- </Stack>
403
- </FormModal>
@@ -1,9 +0,0 @@
1
- type Props = {
2
- onFinish?: () => void;
3
- onCancel?: () => void;
4
- onClose?: () => void;
5
- backendId?: string;
6
- };
7
- declare const ImmichConfigureBackup: import("svelte").Component<Props, {}, "">;
8
- type ImmichConfigureBackup = ReturnType<typeof ImmichConfigureBackup>;
9
- export default ImmichConfigureBackup;
@@ -1,80 +0,0 @@
1
- <script lang="ts">
2
- import { useConfigureImmichDefaults } from "../../../services/integrations.service";
3
- import {
4
- Button,
5
- HStack,
6
- Icon,
7
- Modal,
8
- ModalBody,
9
- ModalFooter,
10
- Stack,
11
- Text,
12
- } from "@immich/ui";
13
- import {
14
- mdiClockOutline,
15
- mdiFolderMultipleOutline,
16
- mdiImageMultipleOutline,
17
- } from "@mdi/js";
18
-
19
- type Props = {
20
- onCustomize: () => void;
21
- onConfirm: () => void;
22
- onCancel: () => void;
23
- };
24
-
25
- const { onCustomize, onConfirm, onCancel }: Props = $props();
26
-
27
- const mutation = useConfigureImmichDefaults();
28
-
29
- const onCreate = () =>
30
- mutation.mutate(undefined, { onSuccess: () => onConfirm() });
31
- </script>
32
-
33
- <Modal title="Ready to back up Immich" size="small" onClose={onCancel}>
34
- <ModalBody>
35
- <Stack gap={3}>
36
- <Text>
37
- We'll create a backup with sensible defaults. You can change anything
38
- later from the Immich backups page.
39
- </Text>
40
-
41
- <Stack>
42
- <HStack>
43
- <Icon
44
- icon={mdiImageMultipleOutline}
45
- class="shrink-0 place-self-start mt-1"
46
- />
47
- <Text>Photos, videos, database, and configuration</Text>
48
- </HStack>
49
- <HStack>
50
- <Icon
51
- icon={mdiFolderMultipleOutline}
52
- class="shrink-0 place-self-start mt-1"
53
- />
54
- <Text>All external libraries</Text>
55
- </HStack>
56
- <HStack>
57
- <Icon
58
- icon={mdiClockOutline}
59
- class="shrink-0 place-self-start mt-1"
60
- />
61
- <Text>Runs every day at 3:00 AM</Text>
62
- </HStack>
63
- </Stack>
64
- </Stack>
65
- </ModalBody>
66
- <ModalFooter>
67
- <HStack gap={2}>
68
- <Button
69
- variant="ghost"
70
- onclick={onCustomize}
71
- disabled={mutation.isPending}
72
- >
73
- Customize
74
- </Button>
75
- <Button onclick={onCreate} loading={mutation.isPending}>
76
- Create backup
77
- </Button>
78
- </HStack>
79
- </ModalFooter>
80
- </Modal>
@@ -1,8 +0,0 @@
1
- type Props = {
2
- onCustomize: () => void;
3
- onConfirm: () => void;
4
- onCancel: () => void;
5
- };
6
- declare const ImmichConfirmDefaultBackup: import("svelte").Component<Props, {}, "">;
7
- type ImmichConfirmDefaultBackup = ReturnType<typeof ImmichConfirmDefaultBackup>;
8
- export default ImmichConfirmDefaultBackup;
@@ -1,56 +0,0 @@
1
- <script lang="ts">
2
- import {
3
- Button,
4
- Field,
5
- HStack,
6
- Input,
7
- Modal,
8
- ModalBody,
9
- ModalFooter,
10
- Stack,
11
- Text,
12
- } from "@immich/ui";
13
-
14
- type Props = {
15
- code: string;
16
-
17
- onConfirmKey: () => Promise<void>;
18
- onBack: () => void;
19
- onCancel: () => void;
20
- };
21
-
22
- const { code, onConfirmKey, onBack, onCancel }: Props = $props();
23
-
24
- let value = $state("");
25
-
26
- const strip = (key: string) => {
27
- return key.replace(/\s/g, "").toLowerCase().trim();
28
- };
29
- </script>
30
-
31
- <Modal
32
- size="small"
33
- title="Confirm recovery key"
34
- onClose={onCancel}
35
- icon={false}
36
- >
37
- <ModalBody>
38
- <Stack>
39
- <Text size="small" class="text-muted text-left"
40
- >Ensure you've saved the key properly.</Text
41
- >
42
-
43
- <Field label="Recovery Key">
44
- <Input bind:value />
45
- </Field>
46
- </Stack>
47
- </ModalBody>
48
- <ModalFooter>
49
- <HStack>
50
- <Button disabled={strip(code) !== strip(value)} onclick={onConfirmKey}
51
- >Confirm</Button
52
- >
53
- <Button variant="ghost" onclick={onBack}>See the key again</Button>
54
- </HStack>
55
- </ModalFooter>
56
- </Modal>
@@ -1,9 +0,0 @@
1
- type Props = {
2
- code: string;
3
- onConfirmKey: () => Promise<void>;
4
- onBack: () => void;
5
- onCancel: () => void;
6
- };
7
- declare const OnboardingStageKeyConfirm: import("svelte").Component<Props, {}, "">;
8
- type OnboardingStageKeyConfirm = ReturnType<typeof OnboardingStageKeyConfirm>;
9
- export default OnboardingStageKeyConfirm;
@@ -1,50 +0,0 @@
1
- <script lang="ts">
2
- import TimedButton from "../../util/TimedButton.svelte";
3
- import {
4
- Button,
5
- HStack,
6
- Icon,
7
- Modal,
8
- ModalBody,
9
- ModalFooter,
10
- Stack,
11
- Text,
12
- } from "@immich/ui";
13
- import { mdiKey, mdiSecurity } from "@mdi/js";
14
-
15
- type Props = {
16
- onNext: () => void;
17
- onCancel: () => void;
18
- };
19
-
20
- const { onNext, onCancel }: Props = $props();
21
- </script>
22
-
23
- <Modal
24
- size="small"
25
- title="Keeping your photos private"
26
- onClose={onCancel}
27
- icon={false}
28
- >
29
- <ModalBody>
30
- <Stack>
31
- <HStack>
32
- <Icon icon={mdiKey} class="shrink-0 place-self-start mt-1" />
33
- <Text
34
- >You are about to be given a code which you need to put in a safe
35
- place.</Text
36
- >
37
- </HStack>
38
- <HStack>
39
- <Icon icon={mdiSecurity} class="shrink-0 place-self-start mt-1" />
40
- <Text>If you lose the key, your backup is gone.</Text>
41
- </HStack>
42
- </Stack>
43
- </ModalBody>
44
- <ModalFooter>
45
- <HStack>
46
- <TimedButton text="Next" onclick={onNext} />
47
- <Button variant="ghost" onclick={onCancel}>Cancel</Button>
48
- </HStack>
49
- </ModalFooter>
50
- </Modal>
@@ -1,7 +0,0 @@
1
- type Props = {
2
- onNext: () => void;
3
- onCancel: () => void;
4
- };
5
- declare const OnboardingStageKeyIntro: import("svelte").Component<Props, {}, "">;
6
- type OnboardingStageKeyIntro = ReturnType<typeof OnboardingStageKeyIntro>;
7
- export default OnboardingStageKeyIntro;
@@ -1,44 +0,0 @@
1
- <script lang="ts">
2
- import {
3
- Button,
4
- HStack,
5
- LoadingSpinner,
6
- Modal,
7
- ModalBody,
8
- ModalFooter,
9
- Stack,
10
- Text,
11
- } from "@immich/ui";
12
- import RecoveryKeyDisplay from "../RecoveryKeyDisplay.svelte";
13
-
14
- type Props = {
15
- code: string;
16
-
17
- onNext: () => void;
18
- onCancel: () => void;
19
- };
20
-
21
- const { code, onNext, onCancel }: Props = $props();
22
- </script>
23
-
24
- <Modal size="small" title="Your recovery key" onClose={onCancel} icon={false}>
25
- <ModalBody>
26
- <Stack gap={4}>
27
- <Text size="small" class="text-muted text-left">
28
- Save this key somewhere safe, it will be used to restore your backups.
29
- </Text>
30
-
31
- {#if code}
32
- <RecoveryKeyDisplay {code} />
33
- {:else}
34
- <LoadingSpinner />
35
- {/if}
36
- </Stack>
37
- </ModalBody>
38
- <ModalFooter>
39
- <HStack>
40
- <Button onclick={onNext}>Next</Button>
41
- <Button variant="ghost" onclick={onCancel}>Cancel</Button>
42
- </HStack>
43
- </ModalFooter>
44
- </Modal>
@@ -1,8 +0,0 @@
1
- type Props = {
2
- code: string;
3
- onNext: () => void;
4
- onCancel: () => void;
5
- };
6
- declare const OnboardingStageKeySave: import("svelte").Component<Props, {}, "">;
7
- type OnboardingStageKeySave = ReturnType<typeof OnboardingStageKeySave>;
8
- export default OnboardingStageKeySave;