@futo-org/backups-orchestrator-ui 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) 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 +22 -10
  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 +135 -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 +73 -0
  38. package/dist/components/integrations/immich/ImmichBackupsCard.svelte.d.ts +12 -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 +15 -3
  42. package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +7 -1
  43. package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +66 -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 +27 -0
  73. package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte.d.ts +10 -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 +39 -0
  81. package/dist/components/onboarding/upsell/UpsellPage.svelte.d.ts +13 -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 +129 -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/MockImmichPhotos.svelte +36 -0
  99. package/dist/components/test/immich/MockImmichPhotos.svelte.d.ts +18 -0
  100. package/dist/components/test/immich/MockImmichPurchaseInfo.svelte +29 -0
  101. package/dist/components/test/immich/MockImmichPurchaseInfo.svelte.d.ts +18 -0
  102. package/dist/components/test/immich/MockImmichStorageSpace.svelte +37 -0
  103. package/dist/components/test/immich/MockImmichStorageSpace.svelte.d.ts +6 -0
  104. package/dist/components/ui/Accordion.svelte +67 -0
  105. package/dist/components/ui/Accordion.svelte.d.ts +11 -0
  106. package/dist/components/ui/ListToolbar.svelte +60 -0
  107. package/dist/components/ui/ListToolbar.svelte.d.ts +16 -0
  108. package/dist/components/ui/PageLayout.svelte +21 -9
  109. package/dist/components/ui/PageLayout.svelte.d.ts +1 -0
  110. package/dist/components/ui/Pagination.svelte +80 -0
  111. package/dist/components/ui/Pagination.svelte.d.ts +8 -0
  112. package/dist/components/ui/PathListField.svelte +17 -14
  113. package/dist/components/ui/StackList.svelte +18 -18
  114. package/dist/components/ui/StackList.svelte.d.ts +6 -27
  115. package/dist/components/ui/StackListItem.svelte +47 -25
  116. package/dist/components/ui/StackListItem.svelte.d.ts +5 -2
  117. package/dist/components/ui/StackListOption.svelte +33 -0
  118. package/dist/components/ui/StackListOption.svelte.d.ts +11 -0
  119. package/dist/components/ui/StackListPlaceholder.svelte +12 -0
  120. package/dist/components/ui/StackListPlaceholder.svelte.d.ts +7 -0
  121. package/dist/components/ui/StepNumber.svelte +20 -0
  122. package/dist/components/ui/StepNumber.svelte.d.ts +7 -0
  123. package/dist/components/util/Suspense.svelte +7 -3
  124. package/dist/components/util/YuccaContext.svelte +1 -1
  125. package/dist/events.js +1 -1
  126. package/dist/fetch-client.d.ts +2 -0
  127. package/dist/index.d.ts +6 -1
  128. package/dist/index.js +6 -1
  129. package/dist/services/backend.service.js +3 -0
  130. package/dist/services/immich.integration.service.d.ts +1 -1
  131. package/dist/services/immich.integration.service.js +2 -3
  132. package/dist/services/integrations.service.d.ts +1 -0
  133. package/dist/services/integrations.service.js +2 -1
  134. package/dist/services/log.service.svelte.d.ts +12 -0
  135. package/dist/services/log.service.svelte.js +15 -1
  136. package/dist/services/repository.service.js +9 -3
  137. package/dist/services/runHistory.service.js +2 -2
  138. package/dist/utils/format.d.ts +1 -1
  139. package/dist/utils/format.js +2 -2
  140. package/package.json +3 -3
  141. package/dist/components/backups/dialogs/ViewLogModal.svelte +0 -208
  142. package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +0 -7
  143. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +0 -403
  144. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +0 -9
  145. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +0 -80
  146. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +0 -8
  147. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +0 -56
  148. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +0 -9
  149. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +0 -50
  150. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +0 -7
  151. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +0 -44
  152. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +0 -8
  153. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +0 -56
  154. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +0 -9
  155. package/dist/components/util/TimedButton.svelte +0 -37
  156. package/dist/components/util/TimedButton.svelte.d.ts +0 -7
@@ -1,8 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { useRepositories } from "../../services/repository.service";
3
- import { HStack, IconButton, Stack, Text } from "@immich/ui";
3
+ import { IconButton, Stack, Text } from "@immich/ui";
4
4
  import { mdiArrowDown, mdiArrowUp, mdiClose, mdiPlus } from "@mdi/js";
5
5
  import StackList from "../ui/StackList.svelte";
6
+ import StackListItem from "../ui/StackListItem.svelte";
6
7
 
7
8
  type Props = {
8
9
  repositories: string[];
@@ -46,41 +47,44 @@
46
47
  {#snippet title()}Repositories{/snippet}
47
48
 
48
49
  {#each repositories as id, index (id)}
49
- <HStack gap={2} class="px-4 py-3">
50
+ <StackListItem>
50
51
  <Text class="grow truncate" size="small">{nameById[id] ?? id}</Text>
51
- <IconButton
52
- icon={mdiArrowUp}
53
- size="tiny"
54
- variant="ghost"
55
- aria-label="Move up"
56
- disabled={index === 0}
57
- onclick={() => move(index, -1)}
58
- />
59
- <IconButton
60
- icon={mdiArrowDown}
61
- size="tiny"
62
- variant="ghost"
63
- aria-label="Move down"
64
- disabled={index === repositories.length - 1}
65
- onclick={() => move(index, 1)}
66
- />
67
- <IconButton
68
- icon={mdiClose}
69
- size="tiny"
70
- color="danger"
71
- variant="ghost"
72
- aria-label="Remove"
73
- onclick={() => remove(id)}
74
- />
75
- </HStack>
52
+
53
+ {#snippet trailing()}
54
+ <IconButton
55
+ icon={mdiArrowUp}
56
+ size="tiny"
57
+ variant="ghost"
58
+ aria-label="Move up"
59
+ disabled={index === 0}
60
+ onclick={() => move(index, -1)}
61
+ />
62
+ <IconButton
63
+ icon={mdiArrowDown}
64
+ size="tiny"
65
+ variant="ghost"
66
+ aria-label="Move down"
67
+ disabled={index === repositories.length - 1}
68
+ onclick={() => move(index, 1)}
69
+ />
70
+ <IconButton
71
+ icon={mdiClose}
72
+ size="tiny"
73
+ color="danger"
74
+ variant="ghost"
75
+ aria-label="Remove"
76
+ onclick={() => remove(id)}
77
+ />
78
+ {/snippet}
79
+ </StackListItem>
76
80
  {/each}
77
81
 
78
82
  {#if repositories.length === 0}
79
- <HStack class="px-4 py-3">
83
+ <StackListItem>
80
84
  <Text color="secondary" size="small">
81
85
  No repositories in this schedule yet.
82
86
  </Text>
83
- </HStack>
87
+ </StackListItem>
84
88
  {/if}
85
89
  </StackList>
86
90
 
@@ -89,16 +93,19 @@
89
93
  {#snippet title()}Available{/snippet}
90
94
 
91
95
  {#each available as repo (repo.id)}
92
- <HStack gap={2} class="px-4 py-3">
96
+ <StackListItem>
93
97
  <Text class="grow truncate" size="small">{repo.name}</Text>
94
- <IconButton
95
- icon={mdiPlus}
96
- size="tiny"
97
- variant="ghost"
98
- aria-label="Add"
99
- onclick={() => add(repo.id)}
100
- />
101
- </HStack>
98
+
99
+ {#snippet trailing()}
100
+ <IconButton
101
+ icon={mdiPlus}
102
+ size="tiny"
103
+ variant="ghost"
104
+ aria-label="Add"
105
+ onclick={() => add(repo.id)}
106
+ />
107
+ {/snippet}
108
+ </StackListItem>
102
109
  {/each}
103
110
  </StackList>
104
111
  {/if}
@@ -3,7 +3,8 @@
3
3
  import RelativeTime from "../util/RelativeTime.svelte";
4
4
  import type { ScheduleDto } from "../../fetch-client";
5
5
  import { getScheduleActions } from "../../services/schedule.service";
6
- import { Badge, HStack, Stack, Text } from "@immich/ui";
6
+ import { Badge, Icon } from "@immich/ui";
7
+ import { mdiClockOutline } from "@mdi/js";
7
8
 
8
9
  type Props = {
9
10
  schedule: ScheduleDto;
@@ -17,31 +18,36 @@
17
18
  );
18
19
  </script>
19
20
 
20
- <StackListItem actions={[Resume, Pause, Configure, Delete]}>
21
- <Stack gap={0} class="min-w-0">
22
- <HStack gap={1} class="items-baseline">
23
- <Text>{schedule.name}</Text>
24
- <Badge size="tiny" color="info">{schedule.cron}</Badge>
25
- {#if schedule.paused}
26
- <Badge size="tiny" color="warning">Paused</Badge>
27
- {/if}
28
- {#if schedule.lastRun}
29
- <Badge size="tiny" color="success">
30
- Ran <RelativeTime time={schedule.lastRun} />
31
- </Badge>
32
- {:else}
33
- <Badge size="tiny" color="secondary">Never run</Badge>
34
- {/if}
35
- </HStack>
36
-
37
- {#if schedule.repositories.length > 0}
38
- <Text size="small" color="secondary">
39
- {schedule.repositories
40
- .map((repositoryId) => repositoryNames[repositoryId] ?? repositoryId)
41
- .join(", ")}
42
- </Text>
21
+ <StackListItem
22
+ title={schedule.name}
23
+ color={schedule.paused ? "warning" : "primary"}
24
+ actions={[Resume, Pause, Configure, Delete]}
25
+ >
26
+ {#snippet icon()}
27
+ <Icon icon={mdiClockOutline} />
28
+ {/snippet}
29
+
30
+ {#if schedule.repositories.length > 0}
31
+ {schedule.repositories
32
+ .map((repositoryId) => repositoryNames[repositoryId] ?? repositoryId)
33
+ .join(", ")}
34
+ {:else}
35
+ No backups in this schedule.
36
+ {/if}
37
+
38
+ {#snippet trailing()}
39
+ <Badge size="tiny" color="info">{schedule.cron}</Badge>
40
+
41
+ {#if schedule.paused}
42
+ <Badge size="tiny" color="warning">Paused</Badge>
43
+ {/if}
44
+
45
+ {#if schedule.lastRun}
46
+ <Badge size="tiny" color="success">
47
+ Ran <RelativeTime time={schedule.lastRun} />
48
+ </Badge>
43
49
  {:else}
44
- <Text size="small" color="secondary">No backups in this schedule.</Text>
50
+ <Badge size="tiny" color="secondary">Never run</Badge>
45
51
  {/if}
46
- </Stack>
52
+ {/snippet}
47
53
  </StackListItem>
@@ -4,9 +4,11 @@
4
4
  useScheduleEventHandler,
5
5
  useSchedules,
6
6
  } from "../../services/schedule.service";
7
- import { Button, HStack, modalManager, Stack, Text } from "@immich/ui";
7
+ import { Button, HStack, modalManager, Stack } from "@immich/ui";
8
8
  import StackList from "../ui/StackList.svelte";
9
+ import StackListPlaceholder from "../ui/StackListPlaceholder.svelte";
9
10
  import OnEvents from "../util/OnEvents.svelte";
11
+ import Suspense from "../util/Suspense.svelte";
10
12
  import CreateScheduleModal from "./dialogs/CreateScheduleModal.svelte";
11
13
  import ScheduleItem from "./ScheduleItem.svelte";
12
14
 
@@ -31,16 +33,20 @@
31
33
  <OnEvents {onScheduleCreate} {onScheduleUpdate} {onScheduleDelete} />
32
34
 
33
35
  <Stack gap={2}>
34
- <StackList query={schedulesQuery}>
36
+ <StackList>
35
37
  {#snippet title()}Schedules{/snippet}
36
- {#snippet children(schedules)}
37
- {#each schedules as schedule (schedule.id)}
38
- <ScheduleItem {schedule} {repositoryNames} />
39
- {/each}
40
- {#if schedules.length === 0}
41
- <Text class="text-center py-6" color="muted">No schedules yet.</Text>
42
- {/if}
43
- {/snippet}
38
+
39
+ <Suspense query={schedulesQuery}>
40
+ {#snippet children(schedules)}
41
+ {#each schedules as schedule (schedule.id)}
42
+ <ScheduleItem {schedule} {repositoryNames} />
43
+ {/each}
44
+
45
+ {#if schedules.length === 0}
46
+ <StackListPlaceholder>No schedules yet.</StackListPlaceholder>
47
+ {/if}
48
+ {/snippet}
49
+ </Suspense>
44
50
  </StackList>
45
51
 
46
52
  <HStack>
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ import { Container } from "@immich/ui";
3
+ import SettingsBackends from "./SettingsBackends.svelte";
4
+ </script>
5
+
6
+ <Container size="large" center>
7
+ <SettingsBackends />
8
+ </Container>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const GlobalSettings: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type GlobalSettings = InstanceType<typeof GlobalSettings>;
18
+ export default GlobalSettings;
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import BackendsList from "../backends/BackendsList.svelte";
3
+ import Accordion from "../ui/Accordion.svelte";
4
+ import { Stack } from "@immich/ui";
5
+ import { mdiCloudOutline } from "@mdi/js";
6
+ </script>
7
+
8
+ <Accordion
9
+ title="Storage backends"
10
+ subtitle="Manage the storage services your backups can be sent to."
11
+ icon={mdiCloudOutline}
12
+ >
13
+ <Stack gap={4} class="pt-2">
14
+ <BackendsList actions />
15
+ </Stack>
16
+ </Accordion>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const SettingsBackends: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type SettingsBackends = InstanceType<typeof SettingsBackends>;
18
+ export default SettingsBackends;
@@ -0,0 +1,69 @@
1
+ <script lang="ts">
2
+ import Accordion from "../ui/Accordion.svelte";
3
+ import {
4
+ Badge,
5
+ Button,
6
+ Field,
7
+ HStack,
8
+ Input,
9
+ Label,
10
+ Stack,
11
+ Text,
12
+ } from "@immich/ui";
13
+ import { mdiCreditCardOutline } from "@mdi/js";
14
+
15
+ type Props = {
16
+ onManageBilling: () => void;
17
+ };
18
+
19
+ const { onManageBilling }: Props = $props();
20
+ </script>
21
+
22
+ <Accordion
23
+ title="Billing"
24
+ subtitle="Manage your FUTO Backups subscription and billing."
25
+ icon={mdiCreditCardOutline}
26
+ >
27
+ <Stack gap={4} class="pt-2">
28
+ <Accordion
29
+ title="FUTO Backups"
30
+ subtitle="Hosted cloud backup storage for your Immich library."
31
+ isOpen
32
+ >
33
+ <Stack gap={4} class="pt-2">
34
+ <HStack gap={4} class="items-start justify-between">
35
+ <Stack gap={0}>
36
+ <Label label="Status" color="primary" />
37
+ <Text size="small" color="muted">
38
+ Connection state for your backup storage.
39
+ </Text>
40
+ </Stack>
41
+
42
+ <Badge color="primary">Active</Badge>
43
+ </HStack>
44
+
45
+ <Field
46
+ label="Storage Used"
47
+ description="How much storage your backups are using."
48
+ color="primary"
49
+ readOnly
50
+ >
51
+ <Input value="100 GiB" />
52
+ </Field>
53
+
54
+ <Field
55
+ label="Next Billing Date"
56
+ description="When your next FUTO Backups charge will occur."
57
+ color="primary"
58
+ readOnly
59
+ >
60
+ <Input value="August 20, 2026" />
61
+ </Field>
62
+ </Stack>
63
+ </Accordion>
64
+
65
+ <HStack class="justify-end">
66
+ <Button shape="round" onclick={onManageBilling}>Manage billing</Button>
67
+ </HStack>
68
+ </Stack>
69
+ </Accordion>
@@ -0,0 +1,6 @@
1
+ type Props = {
2
+ onManageBilling: () => void;
3
+ };
4
+ declare const SettingsBilling: import("svelte").Component<Props, {}, "">;
5
+ type SettingsBilling = ReturnType<typeof SettingsBilling>;
6
+ export default SettingsBilling;
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import Accordion from "../ui/Accordion.svelte";
3
+ import { Button, Field, HStack, Stack, Switch } from "@immich/ui";
4
+ import { mdiBellOutline } from "@mdi/js";
5
+
6
+ const alerts = $state([
7
+ {
8
+ label: "Backup failures",
9
+ description: "Notify me when a backup fails.",
10
+ checked: true,
11
+ },
12
+ {
13
+ label: "Storage issues",
14
+ description: "Notify me when backup storage is unavailable or running low.",
15
+ checked: true,
16
+ },
17
+ {
18
+ label: "Billing issues",
19
+ description: "Notify me when FUTO Backups billing needs attention.",
20
+ checked: true,
21
+ },
22
+ ]);
23
+
24
+ type Props = {
25
+ onSave: () => void;
26
+ };
27
+
28
+ const { onSave }: Props = $props();
29
+ </script>
30
+
31
+ <Accordion
32
+ title="Notifications"
33
+ subtitle="Manage backup alerts."
34
+ icon={mdiBellOutline}
35
+ >
36
+ <Stack gap={4} class="pt-2">
37
+ {#each alerts as alert (alert.label)}
38
+ <Field label={alert.label} description={alert.description}>
39
+ <Switch bind:checked={alert.checked} />
40
+ </Field>
41
+ {/each}
42
+
43
+ <HStack class="justify-end">
44
+ <Button shape="round" onclick={onSave}>Save</Button>
45
+ </HStack>
46
+ </Stack>
47
+ </Accordion>
@@ -0,0 +1,6 @@
1
+ type Props = {
2
+ onSave: () => void;
3
+ };
4
+ declare const SettingsNotifications: import("svelte").Component<Props, {}, "">;
5
+ type SettingsNotifications = ReturnType<typeof SettingsNotifications>;
6
+ export default SettingsNotifications;
@@ -6,19 +6,24 @@
6
6
  AppShellSidebar,
7
7
  Avatar,
8
8
  Button,
9
+ HStack,
9
10
  IconButton,
10
11
  Input,
11
12
  Logo,
12
13
  NavbarGroup,
13
14
  NavbarItem,
15
+ Stack,
16
+ Text,
14
17
  ThemeSwitcher,
15
18
  } from "@immich/ui";
16
19
  import {
17
20
  mdiAccountMultipleOutline,
18
21
  mdiArchiveArrowDownOutline,
19
- mdiBackupRestore,
20
22
  mdiBellOutline,
21
23
  mdiCastVariant,
24
+ mdiChartBoxOutline,
25
+ mdiCogOutline,
26
+ mdiFormatListBulletedType,
22
27
  mdiHeartOutline,
23
28
  mdiImageAlbum,
24
29
  mdiImageMultipleOutline,
@@ -33,9 +38,17 @@
33
38
  } from "@mdi/js";
34
39
  import { options } from "../../options";
35
40
  import { onDestroy } from "svelte";
36
- import ImmichManageBackup from "../integrations/immich/ImmichManageBackup.svelte";
41
+ import ImmichBackupsNavButton from "../integrations/immich/ImmichBackupsNavButton.svelte";
42
+ import MockImmichPhotos from "./immich/MockImmichPhotos.svelte";
43
+ import MockImmichPurchaseInfo from "./immich/MockImmichPurchaseInfo.svelte";
44
+ import MockImmichStorageSpace from "./immich/MockImmichStorageSpace.svelte";
45
+ import ImmichBackupsPage from "../integrations/immich/ImmichBackupsPage.svelte";
37
46
  import ImmichOnboardingRestoreFlow from "../integrations/immich/ImmichOnboardingRestoreFlow.svelte";
38
- import ImmichOnboardingSetupFlow from "../integrations/immich/ImmichOnboardingSetupFlow.svelte";
47
+ import OnEvents from "../util/OnEvents.svelte";
48
+ import {
49
+ useIntegrationEventHandler,
50
+ useIntegrations,
51
+ } from "../../services/integrations.service";
39
52
 
40
53
  type Props = {
41
54
  onExit: () => void;
@@ -44,6 +57,27 @@
44
57
  const { onExit }: Props = $props();
45
58
  const { testUiRestore, demoPadding } = options;
46
59
 
60
+ let route = $state<"photos" | "settings">("photos");
61
+
62
+ const integrations = useIntegrations();
63
+ const { onIntegrationUpdate } = useIntegrationEventHandler();
64
+ const configured = $derived(Boolean(integrations.data?.immichIntegration));
65
+
66
+ const sampleQuestions = [
67
+ {
68
+ title: "Is FUTO Backups the same as an Immich product key?",
69
+ answer: "Sample answer copy for the FAQ preview.",
70
+ },
71
+ {
72
+ title: "How is FUTO Backups priced?",
73
+ answer: "Sample answer copy for the FAQ preview.",
74
+ },
75
+ {
76
+ title: "Can I use local storage instead?",
77
+ answer: "Sample answer copy for the FAQ preview.",
78
+ },
79
+ ];
80
+
47
81
  demoPadding.set(true);
48
82
  onDestroy(() => demoPadding.set(false));
49
83
 
@@ -51,7 +85,9 @@
51
85
  setProvider(orchestrationApiProvider);
52
86
  </script>
53
87
 
54
- <AppShell>
88
+ <OnEvents {onIntegrationUpdate} />
89
+
90
+ <AppShell class="h-full">
55
91
  <AppShellHeader>
56
92
  <div class="grid grid-cols-[--spacing(64)_auto] items-center w-full py-2">
57
93
  <div class="flex flex-row gap-1 mx-4 items-center">
@@ -134,6 +170,17 @@
134
170
  aria-label="Cast"
135
171
  />
136
172
 
173
+ <IconButton
174
+ shape="round"
175
+ color="secondary"
176
+ variant={route === "settings" ? "filled" : "ghost"}
177
+ size="medium"
178
+ icon={mdiCogOutline}
179
+ onclick={() =>
180
+ (route = route === "settings" ? "photos" : "settings")}
181
+ aria-label="Settings"
182
+ />
183
+
137
184
  <button
138
185
  type="button"
139
186
  class="flex ps-2"
@@ -147,26 +194,77 @@
147
194
  </div>
148
195
  </AppShellHeader>
149
196
 
150
- <AppShellSidebar>
151
- <div class="pt-4 pr-2">
152
- <NavbarItem href="#" title="Photos" icon={mdiImageMultipleOutline} />
153
- <NavbarItem href="#" title="Explore" icon={mdiMagnify} />
154
- <NavbarItem href="#" title="Map" icon={mdiMapOutline} />
155
- <NavbarItem href="#" title="Sharing" icon={mdiAccountMultipleOutline} />
156
-
157
- <NavbarGroup title="Library" size="tiny" />
158
-
159
- <NavbarItem href="#" title="Favorites" icon={mdiHeartOutline} />
160
- <NavbarItem
161
- href="#"
162
- title="Albums"
163
- icon={{ icon: mdiImageAlbum, flipped: true }}
164
- />
165
- <NavbarItem href="#" title="Backups" icon={mdiBackupRestore} active />
166
- <NavbarItem href="#" title="Utilities" icon={mdiToolboxOutline} />
167
- <NavbarItem href="#" title="Archive" icon={mdiArchiveArrowDownOutline} />
168
- <NavbarItem href="#" title="Locked folder" icon={mdiLockOutline} />
169
- <NavbarItem href="#" title="Trash" icon={mdiTrashCanOutline} />
197
+ <AppShellSidebar class="relative">
198
+ <div class="flex h-full flex-col pt-4 pr-2">
199
+ {#if route === "settings"}
200
+ <ImmichBackupsNavButton
201
+ {configured}
202
+ active
203
+ onclick={() => {}}
204
+ />
205
+
206
+ <NavbarItem
207
+ href="#"
208
+ title="Users"
209
+ icon={mdiAccountMultipleOutline}
210
+ isActive={() => false}
211
+ />
212
+ <NavbarItem
213
+ href="#"
214
+ title="Job Queues"
215
+ icon={mdiFormatListBulletedType}
216
+ isActive={() => false}
217
+ />
218
+ <NavbarItem
219
+ href="#"
220
+ title="Server Stats"
221
+ icon={mdiChartBoxOutline}
222
+ isActive={() => false}
223
+ />
224
+ <NavbarItem
225
+ href="#"
226
+ title="Settings"
227
+ icon={mdiCogOutline}
228
+ isActive={() => false}
229
+ />
230
+ {:else}
231
+ <NavbarItem
232
+ href="#"
233
+ title="Photos"
234
+ icon={mdiImageMultipleOutline}
235
+ active
236
+ />
237
+ <NavbarItem href="#" title="Explore" icon={mdiMagnify} />
238
+ <NavbarItem href="#" title="Map" icon={mdiMapOutline} />
239
+ <NavbarItem href="#" title="Sharing" icon={mdiAccountMultipleOutline} />
240
+
241
+ <NavbarGroup title="Library" size="tiny" />
242
+
243
+ <NavbarItem href="#" title="Favorites" icon={mdiHeartOutline} />
244
+ <NavbarItem
245
+ href="#"
246
+ title="Albums"
247
+ icon={{ icon: mdiImageAlbum, flipped: true }}
248
+ />
249
+ <NavbarItem href="#" title="Utilities" icon={mdiToolboxOutline} />
250
+ <NavbarItem href="#" title="Archive" icon={mdiArchiveArrowDownOutline} />
251
+ <NavbarItem href="#" title="Locked folder" icon={mdiLockOutline} />
252
+ <NavbarItem href="#" title="Trash" icon={mdiTrashCanOutline} />
253
+ {/if}
254
+
255
+ <Stack gap={4} class="mt-auto p-4">
256
+ <MockImmichStorageSpace onBackups={() => (route = "settings")} />
257
+
258
+ {#if route !== "settings"}
259
+ <MockImmichPurchaseInfo />
260
+ {/if}
261
+
262
+ <HStack gap={2}>
263
+ <span class="bg-success size-2 rounded-full"></span>
264
+ <Text size="small" class="flex-1">Server Online</Text>
265
+ <Text size="small" color="muted">v3.0.3</Text>
266
+ </HStack>
267
+ </Stack>
170
268
  </div>
171
269
  </AppShellSidebar>
172
270
 
@@ -175,9 +273,13 @@
175
273
  {onExit}
176
274
  onFinish={() => testUiRestore.set(false)}
177
275
  />
276
+ {:else if route === "settings"}
277
+ <ImmichBackupsPage
278
+ price="$1"
279
+ includedStorage="50 GB"
280
+ questions={sampleQuestions}
281
+ />
178
282
  {:else}
179
- <ImmichOnboardingSetupFlow {onExit}>
180
- <ImmichManageBackup />
181
- </ImmichOnboardingSetupFlow>
283
+ <MockImmichPhotos />
182
284
  {/if}
183
285
  </AppShell>