@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
@@ -0,0 +1,219 @@
1
+ <script lang="ts">
2
+ import StackList from "./StackList.svelte";
3
+ import type { FilesystemListingResponseDto } from "../../fetch-client";
4
+ import { handleGetFileListing } from "../../services/filesystem.service";
5
+ import {
6
+ Button,
7
+ FormModal,
8
+ Heading,
9
+ HStack,
10
+ Icon,
11
+ IconButton,
12
+ ListButton,
13
+ LoadingSpinner,
14
+ Stack,
15
+ Text,
16
+ } from "@immich/ui";
17
+ import {
18
+ mdiArrowUp,
19
+ mdiClose,
20
+ mdiFileOutline,
21
+ mdiFolderOutline,
22
+ mdiPlus,
23
+ } from "@mdi/js";
24
+ import { onMount } from "svelte";
25
+ import { SvelteSet } from "svelte/reactivity";
26
+
27
+ type Props = {
28
+ title: string;
29
+ description?: string;
30
+ initial?: string[];
31
+ foldersOnly?: boolean;
32
+ single?: boolean;
33
+ handleGetListing?: (path?: string) => Promise<FilesystemListingResponseDto>;
34
+ onSubmit: (paths: string[]) => void | Promise<void>;
35
+ onClose: () => void;
36
+ };
37
+
38
+ let {
39
+ title,
40
+ description,
41
+ initial = [],
42
+ foldersOnly = false,
43
+ single = false,
44
+ handleGetListing,
45
+ onSubmit,
46
+ onClose,
47
+ }: Props = $props();
48
+
49
+ // svelte-ignore state_referenced_locally
50
+ const selected = new SvelteSet(initial);
51
+ let listing: FilesystemListingResponseDto | undefined = $state();
52
+
53
+ const browse = async (path?: string) => {
54
+ listing = undefined;
55
+ listing = await (handleGetListing ?? handleGetFileListing)(path);
56
+ };
57
+
58
+ onMount(() => void browse());
59
+
60
+ const sortedItems = $derived(
61
+ listing
62
+ ? [...listing.items].sort(
63
+ (a, b) =>
64
+ Number(b.isDirectory) - Number(a.isDirectory) ||
65
+ a.path.localeCompare(b.path),
66
+ )
67
+ : [],
68
+ );
69
+
70
+ let submitting = $state(false);
71
+
72
+ const handleSubmit = async () => {
73
+ if (submitting) return;
74
+ submitting = true;
75
+ try {
76
+ await onSubmit([...selected]);
77
+ onClose();
78
+ } finally {
79
+ submitting = false;
80
+ }
81
+ };
82
+
83
+ const add = async (path: string) => {
84
+ if (single) {
85
+ if (submitting) return;
86
+ submitting = true;
87
+ try {
88
+ await onSubmit([path]);
89
+ onClose();
90
+ } finally {
91
+ submitting = false;
92
+ }
93
+ } else {
94
+ selected.add(path);
95
+ }
96
+ };
97
+ </script>
98
+
99
+ <FormModal
100
+ {title}
101
+ size="large"
102
+ submitText="Save"
103
+ disabled={submitting}
104
+ onSubmit={handleSubmit}
105
+ {onClose}
106
+ >
107
+ <Stack gap={5}>
108
+ {#if description}
109
+ <Text color="secondary">{description}</Text>
110
+ {/if}
111
+
112
+ {#if !single}
113
+ {#if selected.size > 0}
114
+ <StackList>
115
+ {#snippet title()}
116
+ Selected paths
117
+ {/snippet}
118
+ {#each [...selected] as path (path)}
119
+ <HStack gap={2} class="items-center px-4 py-3">
120
+ <Text class="grow truncate" title={path}>{path}</Text>
121
+ <IconButton
122
+ icon={mdiClose}
123
+ aria-label="Remove"
124
+ size="tiny"
125
+ variant="ghost"
126
+ onclick={() => selected.delete(path)}
127
+ />
128
+ </HStack>
129
+ {/each}
130
+ </StackList>
131
+ {:else}
132
+ <Stack gap={2}>
133
+ <Heading class="px-1" size="tiny">Selected paths</Heading>
134
+ <Text color="muted" class="text-center py-6">No paths selected</Text>
135
+ </Stack>
136
+ {/if}
137
+ {/if}
138
+
139
+ {#if !listing}
140
+ <Stack gap={2}>
141
+ <Heading class="px-1" size="tiny">Browse</Heading>
142
+ <div class="py-6 flex justify-center">
143
+ <LoadingSpinner />
144
+ </div>
145
+ </Stack>
146
+ {:else}
147
+ <StackList>
148
+ {#snippet title()}
149
+ Browse
150
+ {/snippet}
151
+
152
+ <HStack gap={2} class="items-center px-4 py-3 bg-subtle">
153
+ <Icon icon={mdiFolderOutline} color="primary" />
154
+ <Text class="grow truncate" title={listing.path}>
155
+ {listing.path}
156
+ </Text>
157
+ {#if listing.parent && listing.parent !== listing.path}
158
+ <IconButton
159
+ icon={mdiArrowUp}
160
+ aria-label="Go up"
161
+ size="tiny"
162
+ variant="ghost"
163
+ onclick={() => browse(listing!.parent)}
164
+ />
165
+ {/if}
166
+ </HStack>
167
+
168
+ {#each sortedItems as item (item.path)}
169
+ {#if item.isDirectory || !foldersOnly}
170
+ <HStack gap={2} class="items-center px-2 py-1">
171
+ {#if item.isDirectory}
172
+ <ListButton
173
+ leadingIcon={mdiFolderOutline}
174
+ onclick={() => browse(item.path)}
175
+ class="flex-1 justify-start"
176
+ >
177
+ {item.path.split(/[\\/]/).pop()}
178
+ </ListButton>
179
+ {:else}
180
+ <HStack gap={2} class="items-center grow px-2 py-2">
181
+ <Icon icon={mdiFileOutline} color="secondary" />
182
+ <Text
183
+ class="grow truncate"
184
+ color="secondary"
185
+ title={item.path}
186
+ >
187
+ {item.path.split(/[\\/]/).pop()}
188
+ </Text>
189
+ </HStack>
190
+ {/if}
191
+ <IconButton
192
+ icon={mdiPlus}
193
+ aria-label={single ? "Select" : "Add"}
194
+ size="tiny"
195
+ variant="ghost"
196
+ disabled={!single && selected.has(item.path)}
197
+ onclick={() => add(item.path)}
198
+ />
199
+ </HStack>
200
+ {/if}
201
+ {/each}
202
+
203
+ {#if sortedItems.filter((item) => item.isDirectory || !foldersOnly).length === 0}
204
+ {#if foldersOnly}
205
+ <Stack class="items-center px-4 py-6">
206
+ <Button variant="outline" onclick={() => add(listing!.path)}>
207
+ Use this folder
208
+ </Button>
209
+ </Stack>
210
+ {:else}
211
+ <Text color="muted" class="text-center py-6">
212
+ This folder is empty
213
+ </Text>
214
+ {/if}
215
+ {/if}
216
+ </StackList>
217
+ {/if}
218
+ </Stack>
219
+ </FormModal>
@@ -0,0 +1,14 @@
1
+ import type { FilesystemListingResponseDto } from "../../fetch-client";
2
+ type Props = {
3
+ title: string;
4
+ description?: string;
5
+ initial?: string[];
6
+ foldersOnly?: boolean;
7
+ single?: boolean;
8
+ handleGetListing?: (path?: string) => Promise<FilesystemListingResponseDto>;
9
+ onSubmit: (paths: string[]) => void | Promise<void>;
10
+ onClose: () => void;
11
+ };
12
+ declare const PathPickerModal: import("svelte").Component<Props, {}, "">;
13
+ type PathPickerModal = ReturnType<typeof PathPickerModal>;
14
+ export default PathPickerModal;
@@ -0,0 +1,30 @@
1
+ <script lang="ts" generics="T">
2
+ import { getReadableErrorMessage } from "../../utils/handle-error";
3
+ import { Alert, Heading, LoadingSpinner, Stack } from "@immich/ui";
4
+ import type { CreateQueryResult } from "@tanstack/svelte-query";
5
+ import type { Snippet } from "svelte";
6
+
7
+ type Props = {
8
+ title?: Snippet;
9
+ query?: CreateQueryResult<T>;
10
+ children: Snippet<[T]>;
11
+ };
12
+
13
+ const { title, query, children }: Props = $props();
14
+ </script>
15
+
16
+ <Stack gap={2}>
17
+ {#if title}
18
+ <Heading class="px-1" size="tiny">{@render title()}</Heading>
19
+ {/if}
20
+
21
+ {#if query?.isLoading}
22
+ <LoadingSpinner />
23
+ {:else if query?.isError}
24
+ <Alert color="danger">{getReadableErrorMessage(query.error)}</Alert>
25
+ {:else}
26
+ <Stack gap={0} class="divide-y rounded-2xl border overflow-hidden">
27
+ {@render children(query?.data as T)}
28
+ </Stack>
29
+ {/if}
30
+ </Stack>
@@ -0,0 +1,30 @@
1
+ import type { CreateQueryResult } from "@tanstack/svelte-query";
2
+ import type { Snippet } from "svelte";
3
+ declare function $$render<T>(): {
4
+ props: {
5
+ title?: Snippet;
6
+ query?: CreateQueryResult<T>;
7
+ children: Snippet<[T]>;
8
+ };
9
+ exports: {};
10
+ bindings: "";
11
+ slots: {};
12
+ events: {};
13
+ };
14
+ declare class __sveltets_Render<T> {
15
+ props(): ReturnType<typeof $$render<T>>['props'];
16
+ events(): ReturnType<typeof $$render<T>>['events'];
17
+ slots(): ReturnType<typeof $$render<T>>['slots'];
18
+ bindings(): "";
19
+ exports(): {};
20
+ }
21
+ interface $$IsomorphicComponent {
22
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
23
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
24
+ } & ReturnType<__sveltets_Render<T>['exports']>;
25
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
26
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
27
+ }
28
+ declare const StackList: $$IsomorphicComponent;
29
+ type StackList<T> = InstanceType<typeof StackList<T>>;
30
+ export default StackList;
@@ -0,0 +1,64 @@
1
+ <script lang="ts">
2
+ import { hasActions } from "../../utils/actions";
3
+ import { ContextMenuButton, HStack, type ActionItem } from "@immich/ui";
4
+ import { mdiDotsVertical } from "@mdi/js";
5
+ import type { Snippet } from "svelte";
6
+
7
+ type Props = {
8
+ class?: string;
9
+ icon?: Snippet;
10
+ children: Snippet;
11
+ trailing?: Snippet;
12
+ actions?: ActionItem[];
13
+ onclick?: () => void;
14
+ };
15
+
16
+ const {
17
+ class: className,
18
+ icon,
19
+ children,
20
+ trailing,
21
+ actions = [],
22
+ onclick,
23
+ }: Props = $props();
24
+ </script>
25
+
26
+ {#snippet body()}
27
+ <HStack gap={4} class={`${className} items-center px-4 py-3`}>
28
+ {#if icon}
29
+ <div
30
+ class="flex p-2 items-center justify-center rounded-lg bg-subtle text-lg"
31
+ >
32
+ {@render icon?.()}
33
+ </div>
34
+ {/if}
35
+
36
+ <HStack gap={1} class="flex-1 items-baseline">
37
+ {@render children()}
38
+ </HStack>
39
+
40
+ {@render trailing?.()}
41
+
42
+ {#if hasActions(actions)}
43
+ <ContextMenuButton
44
+ icon={mdiDotsVertical}
45
+ aria-label="Options"
46
+ items={actions}
47
+ variant="ghost"
48
+ color="secondary"
49
+ />
50
+ {/if}
51
+ </HStack>
52
+ {/snippet}
53
+
54
+ {#if onclick}
55
+ <button
56
+ {onclick}
57
+ type="button"
58
+ class="block w-full text-left rounded-lg hover:bg-subtle focus-visible:outline-2 focus-visible:outline-primary-500 cursor-pointer"
59
+ >
60
+ {@render body()}
61
+ </button>
62
+ {:else}
63
+ {@render body()}
64
+ {/if}
@@ -0,0 +1,13 @@
1
+ import { type ActionItem } from "@immich/ui";
2
+ import type { Snippet } from "svelte";
3
+ type Props = {
4
+ class?: string;
5
+ icon?: Snippet;
6
+ children: Snippet;
7
+ trailing?: Snippet;
8
+ actions?: ActionItem[];
9
+ onclick?: () => void;
10
+ };
11
+ declare const StackListItem: import("svelte").Component<Props, {}, "">;
12
+ type StackListItem = ReturnType<typeof StackListItem>;
13
+ export default StackListItem;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import { Text } from "@immich/ui";
3
+ import type { Snippet } from "svelte";
4
+
5
+ type Props = {
6
+ title: string;
7
+ content: string;
8
+ compact?: boolean;
9
+ subtitle?: Snippet;
10
+ };
11
+
12
+ const { title, content, compact = false, subtitle }: Props = $props();
13
+ </script>
14
+
15
+ <div>
16
+ <Text color="secondary" class={compact ? "text-xs" : ""}>{title}</Text>
17
+ <Text class={`tabular-nums ${compact ? "text-xl" : "text-2xl"}`}>
18
+ {content}
19
+ </Text>
20
+ {#if subtitle}
21
+ <Text color="secondary" class="text-xs">
22
+ {@render subtitle()}
23
+ </Text>
24
+ {/if}
25
+ </div>
@@ -0,0 +1,10 @@
1
+ import type { Snippet } from "svelte";
2
+ type Props = {
3
+ title: string;
4
+ content: string;
5
+ compact?: boolean;
6
+ subtitle?: Snippet;
7
+ };
8
+ declare const VisualisationGauge: import("svelte").Component<Props, {}, "">;
9
+ type VisualisationGauge = ReturnType<typeof VisualisationGauge>;
10
+ export default VisualisationGauge;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import { Badge, HStack, Stack, Text } from "@immich/ui";
3
+
4
+ type Segment = {
5
+ value: number;
6
+ label: string;
7
+ color: string;
8
+ badge: "success" | "warning" | "danger" | "secondary";
9
+ };
10
+
11
+ type Props = {
12
+ title: string;
13
+ summary: string;
14
+ segments: Segment[];
15
+ };
16
+
17
+ const { title, summary, segments }: Props = $props();
18
+ </script>
19
+
20
+ <Stack>
21
+ <HStack class="justify-between">
22
+ <Text size="large">{title}</Text>
23
+ <Text color="secondary">{summary}</Text>
24
+ </HStack>
25
+
26
+ <div
27
+ style="display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 2px;"
28
+ >
29
+ {#each segments as segment (segment.label)}
30
+ {#if segment.value > 0}
31
+ <div
32
+ style="flex: {segment.value}; background: {segment.color}; border-radius: 3px;"
33
+ ></div>
34
+ {/if}
35
+ {/each}
36
+ </div>
37
+
38
+ <HStack wrap>
39
+ {#each segments as segment (segment.label)}
40
+ {#if segment.value > 0}
41
+ <Badge size="tiny" color={segment.badge}>
42
+ {segment.value}
43
+ {segment.label}
44
+ </Badge>
45
+ {/if}
46
+ {/each}
47
+ </HStack>
48
+ </Stack>
@@ -0,0 +1,14 @@
1
+ type Segment = {
2
+ value: number;
3
+ label: string;
4
+ color: string;
5
+ badge: "success" | "warning" | "danger" | "secondary";
6
+ };
7
+ type Props = {
8
+ title: string;
9
+ summary: string;
10
+ segments: Segment[];
11
+ };
12
+ declare const VisualisationSegmentedBar: import("svelte").Component<Props, {}, "">;
13
+ type VisualisationSegmentedBar = ReturnType<typeof VisualisationSegmentedBar>;
14
+ export default VisualisationSegmentedBar;
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import { events, SocketEvent, useSocket } from "../../events";
3
+ import { onDestroy, onMount } from "svelte";
4
+
5
+ type Props = {
6
+ [key: `on${string}`]: (event: SocketEvent<any>) => void;
7
+ };
8
+
9
+ const props: Props = $props();
10
+ const disconnect = useSocket();
11
+
12
+ onMount(() => {
13
+ for (const key of Object.keys(props)) {
14
+ events.addEventListener(
15
+ key.slice(2),
16
+ props[key as `on${string}`] as (event: Event) => void,
17
+ );
18
+ }
19
+ });
20
+
21
+ onDestroy(() => {
22
+ disconnect();
23
+
24
+ for (const key of Object.keys(props)) {
25
+ events.removeEventListener(
26
+ key.slice(2),
27
+ props[key as `on${string}`] as (event: Event) => void,
28
+ );
29
+ }
30
+ });
31
+ </script>
@@ -0,0 +1,7 @@
1
+ import { SocketEvent } from "../../events";
2
+ type Props = {
3
+ [key: `on${string}`]: (event: SocketEvent<any>) => void;
4
+ };
5
+ declare const OnEvents: import("svelte").Component<Props, {}, "">;
6
+ type OnEvents = ReturnType<typeof OnEvents>;
7
+ export default OnEvents;
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import { DateTime } from "luxon";
3
+ import { onDestroy, onMount } from "svelte";
4
+
5
+ type Props = {
6
+ time: string;
7
+ };
8
+
9
+ const props: Props = $props();
10
+
11
+ const format = () => DateTime.fromISO(props.time).toRelative();
12
+
13
+ let text = $state(format());
14
+
15
+ let interval: ReturnType<typeof setInterval>;
16
+
17
+ onMount(() => (interval = setInterval(() => (text = format()), 1000)));
18
+ onDestroy(() => clearInterval(interval));
19
+ </script>
20
+
21
+ {text}
@@ -0,0 +1,6 @@
1
+ type Props = {
2
+ time: string;
3
+ };
4
+ declare const RelativeTime: import("svelte").Component<Props, {}, "">;
5
+ type RelativeTime = ReturnType<typeof RelativeTime>;
6
+ export default RelativeTime;
@@ -0,0 +1,21 @@
1
+ <script lang="ts" generics="T extends object">
2
+ import { getReadableErrorMessage } from "../../utils/handle-error";
3
+ import { Alert, LoadingSpinner } from "@immich/ui";
4
+ import type { CreateQueryResult } from "@tanstack/svelte-query";
5
+ import type { Snippet } from "svelte";
6
+
7
+ type Props = {
8
+ query: CreateQueryResult<T>;
9
+ children: Snippet<[T]>;
10
+ };
11
+
12
+ const { query, children }: Props = $props();
13
+ </script>
14
+
15
+ {#if query.isLoading}
16
+ <LoadingSpinner />
17
+ {:else if query.isError}
18
+ <Alert color="danger">{getReadableErrorMessage(query.error)}</Alert>
19
+ {:else if query.isSuccess}
20
+ {@render children(query.data)}
21
+ {/if}
@@ -0,0 +1,29 @@
1
+ import type { CreateQueryResult } from "@tanstack/svelte-query";
2
+ import type { Snippet } from "svelte";
3
+ declare function $$render<T extends object>(): {
4
+ props: {
5
+ query: CreateQueryResult<T>;
6
+ children: Snippet<[T]>;
7
+ };
8
+ exports: {};
9
+ bindings: "";
10
+ slots: {};
11
+ events: {};
12
+ };
13
+ declare class __sveltets_Render<T extends object> {
14
+ props(): ReturnType<typeof $$render<T>>['props'];
15
+ events(): ReturnType<typeof $$render<T>>['events'];
16
+ slots(): ReturnType<typeof $$render<T>>['slots'];
17
+ bindings(): "";
18
+ exports(): {};
19
+ }
20
+ interface $$IsomorphicComponent {
21
+ new <T extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
22
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
23
+ } & ReturnType<__sveltets_Render<T>['exports']>;
24
+ <T extends object>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
25
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
26
+ }
27
+ declare const Suspense: $$IsomorphicComponent;
28
+ type Suspense<T extends object> = InstanceType<typeof Suspense<T>>;
29
+ export default Suspense;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from "svelte";
3
+ import { Button } from "@immich/ui";
4
+
5
+ type Props = {
6
+ text: string;
7
+ onclick: () => void;
8
+ };
9
+
10
+ let { text, onclick }: Props = $props();
11
+
12
+ let time = $state(5);
13
+ let interval: number | undefined;
14
+
15
+ onMount(() => {
16
+ interval = setInterval(
17
+ () => {
18
+ if (time === 0) {
19
+ clearInterval(interval);
20
+ return;
21
+ }
22
+
23
+ time--;
24
+ },
25
+ import.meta.env.DEV ? 100 : 1000,
26
+ ) as never;
27
+ });
28
+
29
+ onDestroy(() => clearInterval(interval));
30
+ </script>
31
+
32
+ <Button {onclick} disabled={time !== 0}
33
+ >{text}
34
+ {#if time !== 0}
35
+ ({time})
36
+ {/if}</Button
37
+ >
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ text: string;
3
+ onclick: () => void;
4
+ };
5
+ declare const TimedButton: import("svelte").Component<Props, {}, "">;
6
+ type TimedButton = ReturnType<typeof TimedButton>;
7
+ export default TimedButton;
@@ -0,0 +1,26 @@
1
+ <script lang="ts">
2
+ import { TooltipProvider } from "@immich/ui";
3
+ import { QueryClientProvider } from "@tanstack/svelte-query";
4
+ import { defaults as orchestrationDefaults } from "../../fetch-client";
5
+ import type { Snippet } from "svelte";
6
+
7
+ type Props = {
8
+ children: Snippet;
9
+ baseUrl?: string;
10
+ };
11
+
12
+ const { baseUrl, children }: Props = $props();
13
+
14
+ // svelte-ignore state_referenced_locally
15
+ if (baseUrl) {
16
+ orchestrationDefaults.baseUrl = baseUrl;
17
+ }
18
+
19
+ import { queryClient } from "../../query-client";
20
+ </script>
21
+
22
+ <QueryClientProvider client={queryClient}>
23
+ <TooltipProvider>
24
+ {@render children()}
25
+ </TooltipProvider>
26
+ </QueryClientProvider>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from "svelte";
2
+ type Props = {
3
+ children: Snippet;
4
+ baseUrl?: string;
5
+ };
6
+ declare const YuccaContext: import("svelte").Component<Props, {}, "">;
7
+ type YuccaContext = ReturnType<typeof YuccaContext>;
8
+ export default YuccaContext;