@futo-org/backups-orchestrator-ui 0.1.71

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 (192) hide show
  1. package/LICENSE +41 -0
  2. package/dist/components/backends/BackendItem.svelte +64 -0
  3. package/dist/components/backends/BackendItem.svelte.d.ts +10 -0
  4. package/dist/components/backends/BackendsList.svelte +73 -0
  5. package/dist/components/backends/BackendsList.svelte.d.ts +7 -0
  6. package/dist/components/backends/CreateLocalBackend.svelte +46 -0
  7. package/dist/components/backends/CreateLocalBackend.svelte.d.ts +7 -0
  8. package/dist/components/backends/OAuthDeviceFlow.svelte +78 -0
  9. package/dist/components/backends/OAuthDeviceFlow.svelte.d.ts +9 -0
  10. package/dist/components/backups/BackupItem.svelte +59 -0
  11. package/dist/components/backups/BackupItem.svelte.d.ts +7 -0
  12. package/dist/components/backups/BackupsList.svelte +82 -0
  13. package/dist/components/backups/BackupsList.svelte.d.ts +8 -0
  14. package/dist/components/backups/dialogs/ConfigureRepositoryModal.svelte +102 -0
  15. package/dist/components/backups/dialogs/ConfigureRepositoryModal.svelte.d.ts +8 -0
  16. package/dist/components/backups/dialogs/CreateRepositoryModal.svelte +59 -0
  17. package/dist/components/backups/dialogs/CreateRepositoryModal.svelte.d.ts +6 -0
  18. package/dist/components/backups/dialogs/ImportRepositoryModal.svelte +62 -0
  19. package/dist/components/backups/dialogs/ImportRepositoryModal.svelte.d.ts +8 -0
  20. package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +109 -0
  21. package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte.d.ts +8 -0
  22. package/dist/components/backups/dialogs/ViewLogModal.svelte +208 -0
  23. package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +7 -0
  24. package/dist/components/backups/metrics-history/MetricsHistoryModal.svelte +166 -0
  25. package/dist/components/backups/metrics-history/MetricsHistoryModal.svelte.d.ts +8 -0
  26. package/dist/components/backups/run-history/RepositoryRunHistory.svelte +39 -0
  27. package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +7 -0
  28. package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +45 -0
  29. package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte.d.ts +7 -0
  30. package/dist/components/backups/run-history/RunHistoryModal.svelte +18 -0
  31. package/dist/components/backups/run-history/RunHistoryModal.svelte.d.ts +8 -0
  32. package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +53 -0
  33. package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +7 -0
  34. package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +41 -0
  35. package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte.d.ts +8 -0
  36. package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +18 -0
  37. package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte.d.ts +8 -0
  38. package/dist/components/dashboard/Dashboard.svelte +52 -0
  39. package/dist/components/dashboard/Dashboard.svelte.d.ts +9 -0
  40. package/dist/components/dashboard/DashboardAvgBackupTime.svelte +34 -0
  41. package/dist/components/dashboard/DashboardAvgBackupTime.svelte.d.ts +7 -0
  42. package/dist/components/dashboard/DashboardBackupHealth.svelte +91 -0
  43. package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +9 -0
  44. package/dist/components/dashboard/DashboardCurrentUsage.svelte +10 -0
  45. package/dist/components/dashboard/DashboardCurrentUsage.svelte.d.ts +18 -0
  46. package/dist/components/dashboard/DashboardDailyBackupTime.svelte +31 -0
  47. package/dist/components/dashboard/DashboardDailyBackupTime.svelte.d.ts +7 -0
  48. package/dist/components/dashboard/DashboardInstall.svelte +15 -0
  49. package/dist/components/dashboard/DashboardInstall.svelte.d.ts +18 -0
  50. package/dist/components/dashboard/DashboardRecentBackups.svelte +104 -0
  51. package/dist/components/dashboard/DashboardRecentBackups.svelte.d.ts +8 -0
  52. package/dist/components/dashboard/DashboardTotalStored.svelte +27 -0
  53. package/dist/components/dashboard/DashboardTotalStored.svelte.d.ts +7 -0
  54. package/dist/components/integrations/immich/ImmichBackupsPage.svelte +14 -0
  55. package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +6 -0
  56. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +402 -0
  57. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +9 -0
  58. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +80 -0
  59. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +8 -0
  60. package/dist/components/integrations/immich/ImmichManageBackup.svelte +77 -0
  61. package/dist/components/integrations/immich/ImmichManageBackup.svelte.d.ts +3 -0
  62. package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +100 -0
  63. package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte.d.ts +8 -0
  64. package/dist/components/integrations/immich/ImmichOnboardingRestoreFlow.svelte +75 -0
  65. package/dist/components/integrations/immich/ImmichOnboardingRestoreFlow.svelte.d.ts +7 -0
  66. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +113 -0
  67. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +8 -0
  68. package/dist/components/onboarding/OnboardingGate.svelte +48 -0
  69. package/dist/components/onboarding/OnboardingGate.svelte.d.ts +9 -0
  70. package/dist/components/onboarding/RecoveryKeyDisplay.svelte +103 -0
  71. package/dist/components/onboarding/RecoveryKeyDisplay.svelte.d.ts +6 -0
  72. package/dist/components/onboarding/SampleOnboarding.svelte +98 -0
  73. package/dist/components/onboarding/SampleOnboarding.svelte.d.ts +9 -0
  74. package/dist/components/onboarding/dialogs/BackupsRecoveryKeyModal.svelte +43 -0
  75. package/dist/components/onboarding/dialogs/BackupsRecoveryKeyModal.svelte.d.ts +6 -0
  76. package/dist/components/onboarding/restore-point-flow/RestorePointFlow.svelte +96 -0
  77. package/dist/components/onboarding/restore-point-flow/RestorePointFlow.svelte.d.ts +8 -0
  78. package/dist/components/onboarding/restore-point-flow/RestorePointFlow2SelectSnapshot.svelte +83 -0
  79. package/dist/components/onboarding/restore-point-flow/RestorePointFlow2SelectSnapshot.svelte.d.ts +9 -0
  80. package/dist/components/onboarding/restore-point-flow/RestorePointFlow3ConfirmRestore.svelte +118 -0
  81. package/dist/components/onboarding/restore-point-flow/RestorePointFlow3ConfirmRestore.svelte.d.ts +10 -0
  82. package/dist/components/onboarding/restore-point-flow/RestorePointFlow4Restore.svelte +59 -0
  83. package/dist/components/onboarding/restore-point-flow/RestorePointFlow4Restore.svelte.d.ts +8 -0
  84. package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +82 -0
  85. package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte.d.ts +8 -0
  86. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +56 -0
  87. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +9 -0
  88. package/dist/components/onboarding/stages/OnboardingStageKeyImport.svelte +57 -0
  89. package/dist/components/onboarding/stages/OnboardingStageKeyImport.svelte.d.ts +8 -0
  90. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +50 -0
  91. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +7 -0
  92. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +44 -0
  93. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +8 -0
  94. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +56 -0
  95. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +9 -0
  96. package/dist/components/onboarding/stages/SampleCreateFirstBackup.svelte +43 -0
  97. package/dist/components/onboarding/stages/SampleCreateFirstBackup.svelte.d.ts +7 -0
  98. package/dist/components/onboarding/stages/SampleCreateFirstSchedule.svelte +49 -0
  99. package/dist/components/onboarding/stages/SampleCreateFirstSchedule.svelte.d.ts +7 -0
  100. package/dist/components/schedules/RepositoryPicker.svelte +105 -0
  101. package/dist/components/schedules/RepositoryPicker.svelte.d.ts +6 -0
  102. package/dist/components/schedules/ScheduleItem.svelte +47 -0
  103. package/dist/components/schedules/ScheduleItem.svelte.d.ts +8 -0
  104. package/dist/components/schedules/ScheduleList.svelte +51 -0
  105. package/dist/components/schedules/ScheduleList.svelte.d.ts +3 -0
  106. package/dist/components/schedules/dialogs/ConfigureScheduleModal.svelte +48 -0
  107. package/dist/components/schedules/dialogs/ConfigureScheduleModal.svelte.d.ts +8 -0
  108. package/dist/components/schedules/dialogs/CreateScheduleModal.svelte +43 -0
  109. package/dist/components/schedules/dialogs/CreateScheduleModal.svelte.d.ts +6 -0
  110. package/dist/components/test/ImmichTestUi.svelte +183 -0
  111. package/dist/components/test/ImmichTestUi.svelte.d.ts +6 -0
  112. package/dist/components/test/TestUi.svelte +134 -0
  113. package/dist/components/test/TestUi.svelte.d.ts +6 -0
  114. package/dist/components/test/dashboard/ActiveJobs.svelte +380 -0
  115. package/dist/components/test/dashboard/ActiveJobs.svelte.d.ts +3 -0
  116. package/dist/components/test/dashboard/BackupHealth.svelte +95 -0
  117. package/dist/components/test/dashboard/BackupHealth.svelte.d.ts +7 -0
  118. package/dist/components/test/dashboard/BackupStats.svelte +117 -0
  119. package/dist/components/test/dashboard/BackupStats.svelte.d.ts +8 -0
  120. package/dist/components/test/dashboard/Dashboard.svelte +76 -0
  121. package/dist/components/test/dashboard/Dashboard.svelte.d.ts +6 -0
  122. package/dist/components/test/dashboard/RecentBackups.svelte +96 -0
  123. package/dist/components/test/dashboard/RecentBackups.svelte.d.ts +8 -0
  124. package/dist/components/ui/PageLayout.svelte +67 -0
  125. package/dist/components/ui/PageLayout.svelte.d.ts +10 -0
  126. package/dist/components/ui/PathListField.svelte +83 -0
  127. package/dist/components/ui/PathListField.svelte.d.ts +17 -0
  128. package/dist/components/ui/PathPickerField.svelte +74 -0
  129. package/dist/components/ui/PathPickerField.svelte.d.ts +15 -0
  130. package/dist/components/ui/PathPickerModal.svelte +219 -0
  131. package/dist/components/ui/PathPickerModal.svelte.d.ts +14 -0
  132. package/dist/components/ui/StackList.svelte +30 -0
  133. package/dist/components/ui/StackList.svelte.d.ts +30 -0
  134. package/dist/components/ui/StackListItem.svelte +64 -0
  135. package/dist/components/ui/StackListItem.svelte.d.ts +13 -0
  136. package/dist/components/ui/VisualisationGauge.svelte +25 -0
  137. package/dist/components/ui/VisualisationGauge.svelte.d.ts +10 -0
  138. package/dist/components/ui/VisualisationSegmentedBar.svelte +48 -0
  139. package/dist/components/ui/VisualisationSegmentedBar.svelte.d.ts +14 -0
  140. package/dist/components/util/OnEvents.svelte +31 -0
  141. package/dist/components/util/OnEvents.svelte.d.ts +7 -0
  142. package/dist/components/util/RelativeTime.svelte +21 -0
  143. package/dist/components/util/RelativeTime.svelte.d.ts +6 -0
  144. package/dist/components/util/Suspense.svelte +21 -0
  145. package/dist/components/util/Suspense.svelte.d.ts +29 -0
  146. package/dist/components/util/TimedButton.svelte +37 -0
  147. package/dist/components/util/TimedButton.svelte.d.ts +7 -0
  148. package/dist/components/util/YuccaContext.svelte +26 -0
  149. package/dist/components/util/YuccaContext.svelte.d.ts +8 -0
  150. package/dist/events.d.ts +6 -0
  151. package/dist/events.js +47 -0
  152. package/dist/fetch-client.d.ts +289 -0
  153. package/dist/fetch-client.js +233 -0
  154. package/dist/index.d.ts +28 -0
  155. package/dist/index.js +28 -0
  156. package/dist/options.d.ts +5 -0
  157. package/dist/options.js +6 -0
  158. package/dist/providers.d.ts +11 -0
  159. package/dist/providers.js +35 -0
  160. package/dist/query-client.d.ts +2 -0
  161. package/dist/query-client.js +2 -0
  162. package/dist/services/backend.service.d.ts +18 -0
  163. package/dist/services/backend.service.js +61 -0
  164. package/dist/services/filesystem.service.d.ts +2 -0
  165. package/dist/services/filesystem.service.js +11 -0
  166. package/dist/services/immich.integration.service.d.ts +6 -0
  167. package/dist/services/immich.integration.service.js +24 -0
  168. package/dist/services/integrations.service.d.ts +13 -0
  169. package/dist/services/integrations.service.js +42 -0
  170. package/dist/services/log.service.svelte.d.ts +53 -0
  171. package/dist/services/log.service.svelte.js +93 -0
  172. package/dist/services/metricsHistory.service.d.ts +4 -0
  173. package/dist/services/metricsHistory.service.js +12 -0
  174. package/dist/services/onboarding.service.d.ts +11 -0
  175. package/dist/services/onboarding.service.js +56 -0
  176. package/dist/services/repository.service.d.ts +45 -0
  177. package/dist/services/repository.service.js +157 -0
  178. package/dist/services/runHistory.service.d.ts +26 -0
  179. package/dist/services/runHistory.service.js +54 -0
  180. package/dist/services/schedule.service.d.ts +35 -0
  181. package/dist/services/schedule.service.js +126 -0
  182. package/dist/services/snapshot.service.d.ts +29 -0
  183. package/dist/services/snapshot.service.js +108 -0
  184. package/dist/services/task.service.d.ts +3 -0
  185. package/dist/services/task.service.js +20 -0
  186. package/dist/utils/actions.d.ts +2 -0
  187. package/dist/utils/actions.js +3 -0
  188. package/dist/utils/format.d.ts +2 -0
  189. package/dist/utils/format.js +24 -0
  190. package/dist/utils/handle-error.d.ts +9 -0
  191. package/dist/utils/handle-error.js +42 -0
  192. package/package.json +79 -0
package/LICENSE ADDED
@@ -0,0 +1,41 @@
1
+ Source First License 1.1
2
+
3
+ Acceptance
4
+ By using the software, you agree to all of the terms and conditions below.
5
+
6
+ Copyright License
7
+ FUTO Holdings, Inc. (the “Licensor”) grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
8
+
9
+ Limitations
10
+ You may use or modify the software only for non-commercial purposes such as personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, all without any anticipated commercial application.
11
+ You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes.
12
+ Notwithstanding the above, you may not remove or obscure any functionality in the software related to payment to the Licensor in any copy you distribute to others.
13
+ You may not alter, remove, or obscure any licensing, copyright, or other notices of the Licensor in the software. Any use of the Licensor’s trademarks is subject to applicable law.
14
+
15
+ Patents
16
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your license for the software granted under these terms ends immediately. If your company makes such a claim, your license ends immediately for work on behalf of your company.
17
+
18
+ Notices
19
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software, such as but not limited to, a statement in a readme file or an in-application about section.
20
+
21
+ Fair Use
22
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
23
+
24
+ No Other Rights
25
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the Licensor from granting licenses to anyone else. These terms do not imply any other licenses.
26
+
27
+ Termination
28
+ If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
29
+
30
+ No Liability
31
+ As far as the law allows, the software comes as is, without any warranty or condition, and the Licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
32
+
33
+ Definitions
34
+
35
+ The “Licensor” is the entity offering these terms, FUTO Holdings, Inc.
36
+ The “software” is the software the licensor makes available under these terms, including any portion of it.
37
+ “You” refers to the individual or entity agreeing to these terms.
38
+ “Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
39
+ “Your license” is the license granted to you for the software under these terms.
40
+ “Use” means anything you do with the software requiring your license.
41
+ “Trademark” means trademarks, service marks, and similar rights.
@@ -0,0 +1,64 @@
1
+ <script lang="ts">
2
+ import type {
3
+ BackendDto,
4
+ BackendType,
5
+ RepositoryBackendDto,
6
+ } from "../../fetch-client";
7
+ import { getBackendActions } from "../../services/backend.service";
8
+ import { Badge, Icon, Text } from "@immich/ui";
9
+ import { mdiCloudOutline, mdiHarddisk, mdiShieldCheckOutline } from "@mdi/js";
10
+ import StackListItem from "../ui/StackListItem.svelte";
11
+
12
+ type Props = {
13
+ backend: BackendDto;
14
+ repositoryBackend?: RepositoryBackendDto & { primary?: boolean };
15
+ };
16
+
17
+ const { backend, repositoryBackend }: Props = $props();
18
+
19
+ const BackendIcons: Record<BackendType, string> = {
20
+ yucca: mdiShieldCheckOutline,
21
+ local: mdiHarddisk,
22
+ s3: mdiCloudOutline,
23
+ };
24
+
25
+ const BackendNames: Record<BackendType, string> = {
26
+ yucca: "FUTO Backups",
27
+ local: "Local Storage",
28
+ s3: "S3 Server",
29
+ };
30
+
31
+ const { LoginAgain } = $derived(getBackendActions(backend));
32
+ </script>
33
+
34
+ <StackListItem actions={[LoginAgain]}>
35
+ {#snippet icon()}
36
+ <Icon icon={BackendIcons[backend.type]} />
37
+ {/snippet}
38
+
39
+ <Text>{BackendNames[backend.type]}</Text>
40
+
41
+ {#if repositoryBackend?.primary}
42
+ <Text size="small">(primary)</Text>
43
+ {/if}
44
+
45
+ {#snippet trailing()}
46
+ {#if repositoryBackend}
47
+ <Badge
48
+ color={backend.isOnline && repositoryBackend.online
49
+ ? "success"
50
+ : "danger"}
51
+ size="small"
52
+ >{backend.isOnline
53
+ ? repositoryBackend.online
54
+ ? "Active"
55
+ : "Missing on service"
56
+ : "Offline"}</Badge
57
+ >
58
+ {:else}
59
+ <Badge color={backend.isOnline ? "success" : "danger"} size="small"
60
+ >{backend.isOnline ? "Online" : "Offline"}</Badge
61
+ >
62
+ {/if}
63
+ {/snippet}
64
+ </StackListItem>
@@ -0,0 +1,10 @@
1
+ import type { BackendDto, RepositoryBackendDto } from "../../fetch-client";
2
+ type Props = {
3
+ backend: BackendDto;
4
+ repositoryBackend?: RepositoryBackendDto & {
5
+ primary?: boolean;
6
+ };
7
+ };
8
+ declare const BackendItem: import("svelte").Component<Props, {}, "">;
9
+ type BackendItem = ReturnType<typeof BackendItem>;
10
+ export default BackendItem;
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ import type { LocalRepositoryDto } from "../../fetch-client";
3
+ import { options } from "../../options";
4
+ import {
5
+ handleSetupLocalStorage,
6
+ handleYuccaLogin,
7
+ useBackendEventHandler,
8
+ useBackends,
9
+ } from "../../services/backend.service";
10
+ import { Button, HStack } from "@immich/ui";
11
+ import StackList from "../ui/StackList.svelte";
12
+ import OnEvents from "../util/OnEvents.svelte";
13
+ import Suspense from "../util/Suspense.svelte";
14
+ import BackendItem from "./BackendItem.svelte";
15
+
16
+ type Props = {
17
+ repository?: LocalRepositoryDto;
18
+ };
19
+
20
+ const { repository }: Props = $props();
21
+
22
+ const { advanced } = options;
23
+ const query = useBackends();
24
+ const { onBackendCreate } = useBackendEventHandler();
25
+
26
+ const repositoryBackends = $derived(
27
+ repository?.backends
28
+ ? [
29
+ {
30
+ ...repository.backends.primary,
31
+ primary: true,
32
+ },
33
+ ...repository.backends.secondary,
34
+ ]
35
+ : [],
36
+ );
37
+ </script>
38
+
39
+ <OnEvents {onBackendCreate} />
40
+
41
+ <Suspense {query}>
42
+ <StackList>
43
+ {#snippet title()}
44
+ {#if repository}
45
+ Where your backup is stored
46
+ {:else}
47
+ Configured backends
48
+ {/if}
49
+ {/snippet}
50
+
51
+ {#each query.data as backend (backend.id)}
52
+ <BackendItem
53
+ {backend}
54
+ repositoryBackend={repositoryBackends.find(
55
+ ({ id }) => backend.id === id,
56
+ )}
57
+ />
58
+ {/each}
59
+ </StackList>
60
+
61
+ {#if $advanced}
62
+ <HStack>
63
+ <Button size="small" variant="outline" onclick={() => handleYuccaLogin()}
64
+ >Login with FUTO Backups</Button
65
+ >
66
+ <Button
67
+ size="small"
68
+ variant="outline"
69
+ onclick={() => handleSetupLocalStorage()}>New local storage</Button
70
+ >
71
+ </HStack>
72
+ {/if}
73
+ </Suspense>
@@ -0,0 +1,7 @@
1
+ import type { LocalRepositoryDto } from "../../fetch-client";
2
+ type Props = {
3
+ repository?: LocalRepositoryDto;
4
+ };
5
+ declare const BackendsList: import("svelte").Component<Props, {}, "">;
6
+ type BackendsList = ReturnType<typeof BackendsList>;
7
+ export default BackendsList;
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ import PathPickerField from "../ui/PathPickerField.svelte";
3
+ import { useCreateLocalBackend } from "../../services/backend.service";
4
+ import { FormModal, Stack } from "@immich/ui";
5
+
6
+ type Props = {
7
+ onClose: () => void;
8
+ onCreate?: (backendId: string) => void;
9
+ };
10
+
11
+ let { onClose, onCreate }: Props = $props();
12
+
13
+ let path = $state("");
14
+
15
+ const mutation = useCreateLocalBackend();
16
+
17
+ const onSubmit = () =>
18
+ mutation.mutate(
19
+ { path },
20
+ {
21
+ onSuccess: ({ backend }) => {
22
+ onCreate?.(backend.id);
23
+ onClose();
24
+ },
25
+ },
26
+ );
27
+ </script>
28
+
29
+ <FormModal
30
+ size="small"
31
+ title="Create local backend"
32
+ disabled={path.length === 0 || mutation.isPending}
33
+ {onSubmit}
34
+ {onClose}
35
+ >
36
+ <Stack gap={4}>
37
+ <PathPickerField
38
+ bind:value={path}
39
+ pickerTitle="Choose backend folder"
40
+ pickerDescription="Pick the local directory where backups will be stored."
41
+ >
42
+ {#snippet title()}Path{/snippet}
43
+ {#snippet description()}Local directory to store backups.{/snippet}
44
+ </PathPickerField>
45
+ </Stack>
46
+ </FormModal>
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ onClose: () => void;
3
+ onCreate?: (backendId: string) => void;
4
+ };
5
+ declare const CreateLocalBackend: import("svelte").Component<Props, {}, "">;
6
+ type CreateLocalBackend = ReturnType<typeof CreateLocalBackend>;
7
+ export default CreateLocalBackend;
@@ -0,0 +1,78 @@
1
+ <script lang="ts">
2
+ import type { SocketEvent } from "../../events";
3
+ import type { BackendDto } from "../../fetch-client";
4
+ import { useBackendEventHandler } from "../../services/backend.service";
5
+ import {
6
+ Button,
7
+ Code,
8
+ HStack,
9
+ IconButton,
10
+ LoadingSpinner,
11
+ Modal,
12
+ ModalBody,
13
+ ModalFooter,
14
+ Stack,
15
+ Text,
16
+ VStack,
17
+ } from "@immich/ui";
18
+ import { mdiContentCopy } from "@mdi/js";
19
+ import OnEvents from "../util/OnEvents.svelte";
20
+
21
+ type Props = {
22
+ userCode: string;
23
+ verificationUri: string;
24
+ onCreate?: (backendId: string) => void;
25
+ onClose: () => void;
26
+ };
27
+
28
+ let { userCode, verificationUri, onCreate, onClose }: Props = $props();
29
+
30
+ const { onBackendCreate: onBackendCreateHandler } = useBackendEventHandler();
31
+
32
+ function onBackendCreate(event: SocketEvent<{ backend: BackendDto }>) {
33
+ onBackendCreateHandler(event);
34
+ onCreate?.(event.data.backend.id);
35
+ onClose();
36
+ }
37
+
38
+ function onOpen() {
39
+ window.open(verificationUri, "_blank");
40
+ }
41
+
42
+ function onCopy() {
43
+ navigator.clipboard.writeText(userCode);
44
+ }
45
+ </script>
46
+
47
+ <OnEvents {onBackendCreate} />
48
+
49
+ <Modal title="Logging into FUTO Backups" icon={false} {onClose}>
50
+ <ModalBody>
51
+ <VStack>
52
+ <Text>You may be asked or shown the following code:</Text>
53
+ <Stack direction="row" align="center">
54
+ <Code class="text-3xl select-all">{userCode}</Code>
55
+ <IconButton
56
+ color="secondary"
57
+ variant="outline"
58
+ icon={mdiContentCopy}
59
+ onclick={onCopy}
60
+ aria-label="Copy code"
61
+ />
62
+ </Stack>
63
+
64
+ <HStack class="mt-4">
65
+ <LoadingSpinner />
66
+ <Text>Waiting for you to confirm login...</Text>
67
+ </HStack>
68
+ </VStack>
69
+ </ModalBody>
70
+ <ModalFooter>
71
+ <HStack fullWidth>
72
+ <Button shape="round" color="secondary" fullWidth onclick={onClose}>
73
+ Cancel
74
+ </Button>
75
+ <Button shape="round" fullWidth onclick={onOpen}>Open login again</Button>
76
+ </HStack>
77
+ </ModalFooter>
78
+ </Modal>
@@ -0,0 +1,9 @@
1
+ type Props = {
2
+ userCode: string;
3
+ verificationUri: string;
4
+ onCreate?: (backendId: string) => void;
5
+ onClose: () => void;
6
+ };
7
+ declare const OAuthDeviceFlow: import("svelte").Component<Props, {}, "">;
8
+ type OAuthDeviceFlow = ReturnType<typeof OAuthDeviceFlow>;
9
+ export default OAuthDeviceFlow;
@@ -0,0 +1,59 @@
1
+ <script lang="ts">
2
+ import type { LocalRepositoryDto } from "../../fetch-client";
3
+ import { getRepositoryActions } from "../../services/repository.service";
4
+ import { Badge, FormatBytes, Text } from "@immich/ui";
5
+ import RelativeTime from "../util/RelativeTime.svelte";
6
+ import StackListItem from "../ui/StackListItem.svelte";
7
+
8
+ type Props = {
9
+ repository: LocalRepositoryDto;
10
+ };
11
+
12
+ const { repository }: Props = $props();
13
+
14
+ const { BackupNow, Snapshots, History, Configure, Import, MetricsHistory } =
15
+ $derived(getRepositoryActions(repository));
16
+ </script>
17
+
18
+ <StackListItem
19
+ actions={[BackupNow, Snapshots, History, Configure, Import, MetricsHistory]}
20
+ >
21
+ <Text>{repository.name}</Text>
22
+
23
+ {#if repository.backends}
24
+ <Badge size="tiny" color="info">
25
+ {#if repository.backends.primary.type === "yucca"}
26
+ FUTO Backups
27
+ {:else if repository.backends.primary.type === "local"}
28
+ Local Storage
29
+ {:else}
30
+ S3 Server
31
+ {/if}
32
+ </Badge>
33
+ {#if !repository.backends.primary.online}
34
+ <Badge size="tiny" color="danger">Offline</Badge>
35
+ {/if}
36
+ {/if}
37
+
38
+ {#if repository.worm}
39
+ <Badge size="tiny" color="info">WORM</Badge>
40
+ {/if}
41
+
42
+ <Badge size="tiny" color="secondary">
43
+ <FormatBytes bytes={repository.metrics.sizeBytes} />
44
+ </Badge>
45
+
46
+ {#snippet trailing()}
47
+ {#if repository.metrics.lastBackup && (!repository.metrics.lastSuccessfulBackup || +new Date(repository.metrics.lastBackup) > +new Date(repository.metrics.lastSuccessfulBackup))}
48
+ <Badge size="tiny" color="danger">
49
+ Failed <RelativeTime time={repository.metrics.lastBackup} />
50
+ </Badge>
51
+ {:else if repository.metrics.lastSuccessfulBackup}
52
+ <Badge size="tiny" color="success">
53
+ Successful <RelativeTime time={repository.metrics.lastSuccessfulBackup} />
54
+ </Badge>
55
+ {:else}
56
+ <Badge size="tiny" color="warning">Never backed up</Badge>
57
+ {/if}
58
+ {/snippet}
59
+ </StackListItem>
@@ -0,0 +1,7 @@
1
+ import type { LocalRepositoryDto } from "../../fetch-client";
2
+ type Props = {
3
+ repository: LocalRepositoryDto;
4
+ };
5
+ declare const BackupItem: import("svelte").Component<Props, {}, "">;
6
+ type BackupItem = ReturnType<typeof BackupItem>;
7
+ export default BackupItem;
@@ -0,0 +1,82 @@
1
+ <script lang="ts">
2
+ import type { RepositoryListResponseDto } from "../../fetch-client";
3
+ import {
4
+ useRepositories,
5
+ useRepositoryEventHandler,
6
+ } from "../../services/repository.service";
7
+ import { Button, HStack, modalManager, Stack, Text } from "@immich/ui";
8
+ import StackList from "../ui/StackList.svelte";
9
+ import OnEvents from "../util/OnEvents.svelte";
10
+ import BackupItem from "./BackupItem.svelte";
11
+ import CreateRepositoryModal from "./dialogs/CreateRepositoryModal.svelte";
12
+
13
+ type Props = {
14
+ local?: boolean;
15
+ initialData?: RepositoryListResponseDto;
16
+ };
17
+
18
+ const { local, initialData }: Props = $props();
19
+
20
+ // svelte-ignore state_referenced_locally
21
+ const query = useRepositories(initialData?.repositories);
22
+
23
+ const { onRepositoryCreate, onRepositoryUpdate, onRepositoryDelete } =
24
+ useRepositoryEventHandler();
25
+
26
+ const localRepositories = $derived(
27
+ query.data?.filter((repository) => repository.configuration) ?? [],
28
+ );
29
+
30
+ const remoteRepositories = $derived(
31
+ query.data?.filter((repository) => !repository.configuration) ?? [],
32
+ );
33
+
34
+ const createNewBackup = () => modalManager.show(CreateRepositoryModal);
35
+ </script>
36
+
37
+ <OnEvents {onRepositoryCreate} {onRepositoryUpdate} {onRepositoryDelete} />
38
+
39
+ <Stack gap={6}>
40
+ {#if local}
41
+ <Stack gap={2}>
42
+ <StackList {query}>
43
+ {#snippet title()}Backups on this machine{/snippet}
44
+ {#snippet children()}
45
+ {#each localRepositories as repository (repository.id)}
46
+ <BackupItem {repository} />
47
+ {/each}
48
+ {#if localRepositories.length === 0}
49
+ <Text class="text-center py-6" color="muted">
50
+ No backups on this machine yet.
51
+ </Text>
52
+ {/if}
53
+ {/snippet}
54
+ </StackList>
55
+
56
+ <HStack>
57
+ <Button
58
+ shape="round"
59
+ size="tiny"
60
+ variant="outline"
61
+ onclick={createNewBackup}>Create new backup</Button
62
+ >
63
+ </HStack>
64
+ </Stack>
65
+ {/if}
66
+
67
+ <StackList {query}>
68
+ {#snippet title()}
69
+ {local ? "Backups found elsewhere" : "Your Backups"}
70
+ {/snippet}
71
+ {#snippet children()}
72
+ {#each remoteRepositories as repository (repository.id)}
73
+ <BackupItem {repository} />
74
+ {/each}
75
+ {#if remoteRepositories.length === 0}
76
+ <Text class="text-center py-6" color="muted">
77
+ {local ? "No other backups found." : "No backups yet."}
78
+ </Text>
79
+ {/if}
80
+ {/snippet}
81
+ </StackList>
82
+ </Stack>
@@ -0,0 +1,8 @@
1
+ import type { RepositoryListResponseDto } from "../../fetch-client";
2
+ type Props = {
3
+ local?: boolean;
4
+ initialData?: RepositoryListResponseDto;
5
+ };
6
+ declare const BackupsList: import("svelte").Component<Props, {}, "">;
7
+ type BackupsList = ReturnType<typeof BackupsList>;
8
+ export default BackupsList;
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import BackendsList from "../../backends/BackendsList.svelte";
3
+ import { type LocalRepositoryDto } from "../../../fetch-client";
4
+ import { options } from "../../../options";
5
+ import {
6
+ useRemoveRepository,
7
+ useUpdateRepository,
8
+ } from "../../../services/repository.service";
9
+ import PathListField from "../../ui/PathListField.svelte";
10
+ import {
11
+ Button,
12
+ Field,
13
+ FormModal,
14
+ Input,
15
+ modalManager,
16
+ Stack,
17
+ } from "@immich/ui";
18
+ import { SvelteSet } from "svelte/reactivity";
19
+
20
+ type Props = {
21
+ repository: LocalRepositoryDto;
22
+ onClose: () => void;
23
+ };
24
+
25
+ let { repository, onClose }: Props = $props();
26
+
27
+ // svelte-ignore state_referenced_locally
28
+ let name = $state(repository.name);
29
+ // svelte-ignore state_referenced_locally
30
+ let paths = new SvelteSet(repository.configuration?.paths ?? []);
31
+
32
+ const local = $derived(typeof repository.configuration === "object");
33
+
34
+ const updateMutation = useUpdateRepository();
35
+ const removeMutation = useRemoveRepository();
36
+
37
+ const onSubmit = () =>
38
+ updateMutation.mutate(
39
+ { id: repository.id, dto: { name, paths: [...paths] }, local },
40
+ { onSuccess: () => onClose() },
41
+ );
42
+
43
+ const onRemove = async () => {
44
+ const confirm = await modalManager.showDialog({
45
+ confirmText: local ? "Remove" : "Delete",
46
+ title: local ? "Remove Repository" : "Delete Repository",
47
+ prompt: local
48
+ ? "Repository will be removed locally."
49
+ : "This repository will be removed.",
50
+ });
51
+
52
+ if (!confirm) return;
53
+
54
+ removeMutation.mutate(
55
+ { id: repository.id, local },
56
+ { onSuccess: () => onClose() },
57
+ );
58
+ };
59
+
60
+ const { advanced } = options;
61
+ </script>
62
+
63
+ <FormModal
64
+ disabled={name.length === 0 ||
65
+ updateMutation.isPending ||
66
+ removeMutation.isPending}
67
+ title={`Configure ${name}`}
68
+ size="large"
69
+ {onSubmit}
70
+ {onClose}
71
+ >
72
+ <Stack gap={4}>
73
+ <Stack gap={2}>
74
+ <Field label="Name">
75
+ <Input bind:value={name} />
76
+ </Field>
77
+ </Stack>
78
+
79
+ {#if repository.configuration}
80
+ <PathListField
81
+ {paths}
82
+ addLabel="Add path"
83
+ manageLabel="Add first path"
84
+ pickerTitle="Backup Paths"
85
+ pickerDescription="Select files and folders to include in this backup."
86
+ >
87
+ {#snippet label()}Backup Paths{/snippet}
88
+ {#snippet empty()}No paths configured yet.{/snippet}
89
+ </PathListField>
90
+ {/if}
91
+
92
+ <Button
93
+ color="danger"
94
+ loading={removeMutation.isPending}
95
+ onclick={onRemove}>Remove Repository</Button
96
+ >
97
+
98
+ {#if advanced}
99
+ <BackendsList {repository} />
100
+ {/if}
101
+ </Stack>
102
+ </FormModal>
@@ -0,0 +1,8 @@
1
+ import { type LocalRepositoryDto } from "../../../fetch-client";
2
+ type Props = {
3
+ repository: LocalRepositoryDto;
4
+ onClose: () => void;
5
+ };
6
+ declare const ConfigureRepositoryModal: import("svelte").Component<Props, {}, "">;
7
+ type ConfigureRepositoryModal = ReturnType<typeof ConfigureRepositoryModal>;
8
+ export default ConfigureRepositoryModal;
@@ -0,0 +1,59 @@
1
+ <script lang="ts">
2
+ import { useCreateRepository } from "../../../services/repository.service";
3
+ import {
4
+ Checkbox,
5
+ Field,
6
+ FormModal,
7
+ Input,
8
+ modalManager,
9
+ Stack,
10
+ } from "@immich/ui";
11
+ import ConfigureRepositoryModal from "./ConfigureRepositoryModal.svelte";
12
+
13
+ type Props = {
14
+ onClose: () => void;
15
+ };
16
+
17
+ let { onClose }: Props = $props();
18
+
19
+ let name = $state("");
20
+ let worm = $state(false);
21
+
22
+ const mutation = useCreateRepository();
23
+
24
+ const onSubmit = () =>
25
+ mutation.mutate(
26
+ { name, worm },
27
+ {
28
+ onSuccess: ({ repository }) => {
29
+ onClose();
30
+
31
+ modalManager.open(ConfigureRepositoryModal, {
32
+ repository: {
33
+ ...repository,
34
+ configuration: repository.configuration!,
35
+ },
36
+ });
37
+ },
38
+ },
39
+ );
40
+ </script>
41
+
42
+ <FormModal
43
+ title="Create A New Backup"
44
+ disabled={name.length === 0 || mutation.isPending}
45
+ {onSubmit}
46
+ {onClose}
47
+ >
48
+ <Stack gap={4}>
49
+ <Field label="Name" description="A memorable name for this backup">
50
+ <Input bind:value={name} />
51
+ </Field>
52
+ <Field
53
+ label="Write once (WORM)"
54
+ description="Prevent anything being deleted"
55
+ >
56
+ <Checkbox bind:checked={worm} />
57
+ </Field>
58
+ </Stack>
59
+ </FormModal>
@@ -0,0 +1,6 @@
1
+ type Props = {
2
+ onClose: () => void;
3
+ };
4
+ declare const CreateRepositoryModal: import("svelte").Component<Props, {}, "">;
5
+ type CreateRepositoryModal = ReturnType<typeof CreateRepositoryModal>;
6
+ export default CreateRepositoryModal;