@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.
- package/dist/components/backends/BackendItem.svelte +28 -24
- package/dist/components/backends/BackendsList.svelte +33 -34
- package/dist/components/backends/BackendsList.svelte.d.ts +1 -0
- package/dist/components/backends/dialogs/SelectBackendModal.svelte +44 -55
- package/dist/components/backups/BackupItem.svelte +33 -26
- package/dist/components/backups/BackupStatus.svelte +200 -0
- package/dist/components/backups/BackupStatus.svelte.d.ts +19 -0
- package/dist/components/backups/BackupsList.svelte +17 -11
- package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +2 -2
- package/dist/components/backups/dialogs/SelectRepositoryModal.svelte +26 -36
- package/dist/components/backups/dialogs/ViewStatusModal.svelte +175 -0
- package/dist/components/backups/dialogs/ViewStatusModal.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte +22 -10
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +2 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +46 -20
- package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte +135 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RunHistoryModal.svelte +2 -2
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +22 -10
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +2 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +23 -21
- package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte +115 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte.d.ts +9 -0
- package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +2 -2
- package/dist/components/dashboard/Dashboard.svelte +14 -7
- package/dist/components/dashboard/Dashboard.svelte.d.ts +1 -1
- package/dist/components/dashboard/DashboardAvgBackupTime.svelte +1 -1
- package/dist/components/dashboard/DashboardBackupHealth.svelte +5 -9
- package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +1 -1
- package/dist/components/dashboard/DashboardCurrentUsage.svelte +1 -1
- package/dist/components/dashboard/DashboardDailyBackupTime.svelte +1 -1
- package/dist/components/dashboard/DashboardInstall.svelte +1 -1
- package/dist/components/dashboard/DashboardRecentBackups.svelte +47 -78
- package/dist/components/dashboard/DashboardTotalStored.svelte +1 -1
- package/dist/components/integrations/immich/ImmichBackupSettings.svelte +12 -0
- package/dist/components/integrations/immich/ImmichBackupSettings.svelte.d.ts +18 -0
- package/dist/components/integrations/immich/ImmichBackupsCard.svelte +73 -0
- package/dist/components/integrations/immich/ImmichBackupsCard.svelte.d.ts +12 -0
- package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte +55 -0
- package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte.d.ts +10 -0
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte +15 -3
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +7 -1
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +66 -0
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte.d.ts +8 -0
- package/dist/components/integrations/immich/ImmichManageBackup.svelte +53 -14
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +45 -71
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +123 -82
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +1 -1
- package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte +313 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte +218 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte +207 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte.d.ts +3 -0
- package/dist/components/onboarding/RecoveryKeyDisplay.svelte +34 -20
- package/dist/components/onboarding/SampleOnboarding.svelte +57 -38
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +10 -24
- package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte +44 -0
- package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte.d.ts +7 -0
- package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte +50 -0
- package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte.d.ts +7 -0
- package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte +45 -0
- package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte.d.ts +8 -0
- package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte +67 -0
- package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte.d.ts +9 -0
- package/dist/components/onboarding/steps/OnboardingStepLayout.svelte +58 -0
- package/dist/components/onboarding/steps/OnboardingStepLayout.svelte.d.ts +19 -0
- package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte +52 -0
- package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte.d.ts +18 -0
- package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte +33 -0
- package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte.d.ts +8 -0
- package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte +27 -0
- package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte.d.ts +10 -0
- package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte +7 -0
- package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte.d.ts +18 -0
- package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte +46 -0
- package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte.d.ts +6 -0
- package/dist/components/onboarding/upsell/UpsellModal.svelte +43 -0
- package/dist/components/onboarding/upsell/UpsellModal.svelte.d.ts +9 -0
- package/dist/components/onboarding/upsell/UpsellPage.svelte +39 -0
- package/dist/components/onboarding/upsell/UpsellPage.svelte.d.ts +13 -0
- package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte +58 -0
- package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte.d.ts +8 -0
- package/dist/components/schedules/RepositoryPicker.svelte +45 -38
- package/dist/components/schedules/ScheduleItem.svelte +32 -26
- package/dist/components/schedules/ScheduleList.svelte +16 -10
- package/dist/components/settings/GlobalSettings.svelte +8 -0
- package/dist/components/settings/GlobalSettings.svelte.d.ts +18 -0
- package/dist/components/settings/SettingsBackends.svelte +16 -0
- package/dist/components/settings/SettingsBackends.svelte.d.ts +18 -0
- package/dist/components/settings/SettingsBilling.svelte +69 -0
- package/dist/components/settings/SettingsBilling.svelte.d.ts +6 -0
- package/dist/components/settings/SettingsNotifications.svelte +47 -0
- package/dist/components/settings/SettingsNotifications.svelte.d.ts +6 -0
- package/dist/components/test/ImmichTestUi.svelte +129 -27
- package/dist/components/test/TestUi.svelte +4 -4
- package/dist/components/test/dashboard/ActiveJobs.svelte +2 -2
- package/dist/components/test/immich/MockImmichPhotos.svelte +36 -0
- package/dist/components/test/immich/MockImmichPhotos.svelte.d.ts +18 -0
- package/dist/components/test/immich/MockImmichPurchaseInfo.svelte +29 -0
- package/dist/components/test/immich/MockImmichPurchaseInfo.svelte.d.ts +18 -0
- package/dist/components/test/immich/MockImmichStorageSpace.svelte +37 -0
- package/dist/components/test/immich/MockImmichStorageSpace.svelte.d.ts +6 -0
- package/dist/components/ui/Accordion.svelte +67 -0
- package/dist/components/ui/Accordion.svelte.d.ts +11 -0
- package/dist/components/ui/ListToolbar.svelte +60 -0
- package/dist/components/ui/ListToolbar.svelte.d.ts +16 -0
- package/dist/components/ui/PageLayout.svelte +21 -9
- package/dist/components/ui/PageLayout.svelte.d.ts +1 -0
- package/dist/components/ui/Pagination.svelte +80 -0
- package/dist/components/ui/Pagination.svelte.d.ts +8 -0
- package/dist/components/ui/PathListField.svelte +17 -14
- package/dist/components/ui/StackList.svelte +18 -18
- package/dist/components/ui/StackList.svelte.d.ts +6 -27
- package/dist/components/ui/StackListItem.svelte +47 -25
- package/dist/components/ui/StackListItem.svelte.d.ts +5 -2
- package/dist/components/ui/StackListOption.svelte +33 -0
- package/dist/components/ui/StackListOption.svelte.d.ts +11 -0
- package/dist/components/ui/StackListPlaceholder.svelte +12 -0
- package/dist/components/ui/StackListPlaceholder.svelte.d.ts +7 -0
- package/dist/components/ui/StepNumber.svelte +20 -0
- package/dist/components/ui/StepNumber.svelte.d.ts +7 -0
- package/dist/components/util/Suspense.svelte +7 -3
- package/dist/components/util/YuccaContext.svelte +1 -1
- package/dist/events.js +1 -1
- package/dist/fetch-client.d.ts +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/services/backend.service.js +3 -0
- package/dist/services/immich.integration.service.d.ts +1 -1
- package/dist/services/immich.integration.service.js +2 -3
- package/dist/services/integrations.service.d.ts +1 -0
- package/dist/services/integrations.service.js +2 -1
- package/dist/services/log.service.svelte.d.ts +12 -0
- package/dist/services/log.service.svelte.js +15 -1
- package/dist/services/repository.service.js +9 -3
- package/dist/services/runHistory.service.js +2 -2
- package/dist/utils/format.d.ts +1 -1
- package/dist/utils/format.js +2 -2
- package/package.json +3 -3
- package/dist/components/backups/dialogs/ViewLogModal.svelte +0 -208
- package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +0 -7
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +0 -403
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +0 -9
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +0 -80
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +0 -8
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +0 -56
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +0 -9
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +0 -50
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +0 -7
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +0 -44
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +0 -8
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +0 -56
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +0 -9
- package/dist/components/util/TimedButton.svelte +0 -37
- package/dist/components/util/TimedButton.svelte.d.ts +0 -7
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import BackendsList from "../../../backends/BackendsList.svelte";
|
|
3
|
+
import Accordion from "../../../ui/Accordion.svelte";
|
|
4
|
+
import OnEvents from "../../../util/OnEvents.svelte";
|
|
5
|
+
import type { RetentionPolicyDto } from "../../../../fetch-client";
|
|
6
|
+
import {
|
|
7
|
+
useConfigureImmichIntegration,
|
|
8
|
+
useIntegrationEventHandler,
|
|
9
|
+
useIntegrations,
|
|
10
|
+
} from "../../../../services/integrations.service";
|
|
11
|
+
import {
|
|
12
|
+
useRepositories,
|
|
13
|
+
useRepositoryEventHandler,
|
|
14
|
+
} from "../../../../services/repository.service";
|
|
15
|
+
import {
|
|
16
|
+
useScheduleEventHandler,
|
|
17
|
+
useSchedules,
|
|
18
|
+
} from "../../../../services/schedule.service";
|
|
19
|
+
import {
|
|
20
|
+
Button,
|
|
21
|
+
Field,
|
|
22
|
+
HStack,
|
|
23
|
+
Input,
|
|
24
|
+
LoadingSpinner,
|
|
25
|
+
Select,
|
|
26
|
+
Stack,
|
|
27
|
+
Switch,
|
|
28
|
+
} from "@immich/ui";
|
|
29
|
+
import { mdiDownloadBox } from "@mdi/js";
|
|
30
|
+
|
|
31
|
+
type RetentionChoice = {
|
|
32
|
+
key: string;
|
|
33
|
+
label: string;
|
|
34
|
+
policy: RetentionPolicyDto | null;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const retentionChoices: RetentionChoice[] = [
|
|
38
|
+
{ key: "15d", label: "After 15 days", policy: { keepWithin: "15d" } },
|
|
39
|
+
{ key: "30d", label: "After 30 days", policy: { keepWithin: "30d" } },
|
|
40
|
+
{ key: "60d", label: "After 60 days", policy: { keepWithin: "60d" } },
|
|
41
|
+
{ key: "90d", label: "After 90 days", policy: { keepWithin: "90d" } },
|
|
42
|
+
{ key: "2", label: "Keep latest two backups", policy: { keepLast: 2 } },
|
|
43
|
+
{ key: "never", label: "Never (keep all backups)", policy: null },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const defaultRetentionKey = "60d";
|
|
47
|
+
|
|
48
|
+
const integrations = useIntegrations();
|
|
49
|
+
const repositories = useRepositories();
|
|
50
|
+
const schedules = useSchedules();
|
|
51
|
+
const mutation = useConfigureImmichIntegration();
|
|
52
|
+
|
|
53
|
+
const { onIntegrationUpdate } = useIntegrationEventHandler();
|
|
54
|
+
const { onRepositoryCreate, onRepositoryUpdate, onRepositoryDelete } =
|
|
55
|
+
useRepositoryEventHandler();
|
|
56
|
+
const { onScheduleCreate, onScheduleUpdate, onScheduleDelete } =
|
|
57
|
+
useScheduleEventHandler();
|
|
58
|
+
|
|
59
|
+
const integration = $derived(integrations.data?.immichIntegration);
|
|
60
|
+
|
|
61
|
+
const repository = $derived(
|
|
62
|
+
integration
|
|
63
|
+
? repositories.data?.find((entry) => entry.id === integration.id)
|
|
64
|
+
: undefined,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const schedule = $derived(
|
|
68
|
+
integration
|
|
69
|
+
? schedules.data?.find((entry) => entry.id === integration.scheduleId)
|
|
70
|
+
: undefined,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const isLoading = $derived(
|
|
74
|
+
integrations.isLoading || repositories.isLoading || schedules.isLoading,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
let name = $state("");
|
|
78
|
+
let worm = $state(false);
|
|
79
|
+
let retentionKey = $state(defaultRetentionKey);
|
|
80
|
+
let loaded = false;
|
|
81
|
+
|
|
82
|
+
const load = () => {
|
|
83
|
+
if (!repository) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
name = repository.name;
|
|
88
|
+
worm = repository.worm;
|
|
89
|
+
|
|
90
|
+
const policy = repository.configuration?.retentionPolicy ?? null;
|
|
91
|
+
retentionKey =
|
|
92
|
+
retentionChoices.find(
|
|
93
|
+
(choice) => JSON.stringify(choice.policy) === JSON.stringify(policy),
|
|
94
|
+
)?.key ?? defaultRetentionKey;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
$effect(() => {
|
|
98
|
+
if (loaded || !repository) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
loaded = true;
|
|
103
|
+
load();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const onSave = () => {
|
|
107
|
+
if (!integration || !repository || !schedule) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
mutation.mutate({
|
|
112
|
+
name,
|
|
113
|
+
cron: schedule.cron,
|
|
114
|
+
dataFolders: integration.configuration.dataFolders,
|
|
115
|
+
backupConfiguration: integration.configuration.backupConfiguration,
|
|
116
|
+
libraries: integration.configuration.libraries,
|
|
117
|
+
worm,
|
|
118
|
+
retentionPolicy: worm
|
|
119
|
+
? null
|
|
120
|
+
: (retentionChoices.find((choice) => choice.key === retentionKey)
|
|
121
|
+
?.policy ?? null),
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<OnEvents
|
|
127
|
+
{onIntegrationUpdate}
|
|
128
|
+
{onRepositoryCreate}
|
|
129
|
+
{onRepositoryUpdate}
|
|
130
|
+
{onRepositoryDelete}
|
|
131
|
+
{onScheduleCreate}
|
|
132
|
+
{onScheduleUpdate}
|
|
133
|
+
{onScheduleDelete}
|
|
134
|
+
/>
|
|
135
|
+
|
|
136
|
+
<Accordion
|
|
137
|
+
title="Storage"
|
|
138
|
+
subtitle="Manage the backup name, where it is stored, and how long backups are kept."
|
|
139
|
+
icon={mdiDownloadBox}
|
|
140
|
+
>
|
|
141
|
+
<Stack gap={4} class="pt-2">
|
|
142
|
+
{#if isLoading}
|
|
143
|
+
<LoadingSpinner />
|
|
144
|
+
{:else}
|
|
145
|
+
<Field
|
|
146
|
+
label="Backup name"
|
|
147
|
+
description="How this backup is labelled across FUTO Backups."
|
|
148
|
+
required="indicator"
|
|
149
|
+
>
|
|
150
|
+
<Input bind:value={name} />
|
|
151
|
+
</Field>
|
|
152
|
+
|
|
153
|
+
<BackendsList {repository} />
|
|
154
|
+
|
|
155
|
+
{#if repository?.worm}
|
|
156
|
+
<Field
|
|
157
|
+
label="Write-only"
|
|
158
|
+
description="Once written, backups can't be removed. This can't be turned off again."
|
|
159
|
+
readOnly // @immich/ui forces enabled={false} when disabled={true}
|
|
160
|
+
>
|
|
161
|
+
<Switch checked class="grayscale brightness-90" />
|
|
162
|
+
</Field>
|
|
163
|
+
{:else}
|
|
164
|
+
<Field
|
|
165
|
+
label="Write-only"
|
|
166
|
+
description="Once written, backups can't be removed. This can't be turned off again."
|
|
167
|
+
>
|
|
168
|
+
<Switch bind:checked={worm} />
|
|
169
|
+
</Field>
|
|
170
|
+
{/if}
|
|
171
|
+
|
|
172
|
+
<Field
|
|
173
|
+
label="Delete old backups"
|
|
174
|
+
description="Older snapshots are pruned automatically."
|
|
175
|
+
disabled={worm}
|
|
176
|
+
>
|
|
177
|
+
<Select
|
|
178
|
+
options={retentionChoices.map(({ key, label }) => ({
|
|
179
|
+
value: key,
|
|
180
|
+
label,
|
|
181
|
+
}))}
|
|
182
|
+
value={worm ? "never" : retentionKey}
|
|
183
|
+
onChange={(value) => (retentionKey = value)}
|
|
184
|
+
/>
|
|
185
|
+
</Field>
|
|
186
|
+
|
|
187
|
+
<HStack gap={2} class="justify-end">
|
|
188
|
+
<Button
|
|
189
|
+
shape="round"
|
|
190
|
+
color="secondary"
|
|
191
|
+
disabled={mutation.isPending}
|
|
192
|
+
onclick={load}
|
|
193
|
+
>
|
|
194
|
+
Reset
|
|
195
|
+
</Button>
|
|
196
|
+
<Button
|
|
197
|
+
shape="round"
|
|
198
|
+
disabled={name.trim().length === 0}
|
|
199
|
+
loading={mutation.isPending}
|
|
200
|
+
onclick={onSave}
|
|
201
|
+
>
|
|
202
|
+
Save
|
|
203
|
+
</Button>
|
|
204
|
+
</HStack>
|
|
205
|
+
{/if}
|
|
206
|
+
</Stack>
|
|
207
|
+
</Accordion>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { Button, Card, CardBody, HStack, Text, VStack } from "@immich/ui";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "@immich/ui";
|
|
9
|
-
import { mdiAsterisk, mdiContentCopy, mdiFile, mdiPrinter } from "@mdi/js";
|
|
4
|
+
mdiAsterisk,
|
|
5
|
+
mdiContentCopy,
|
|
6
|
+
mdiDownloadOutline,
|
|
7
|
+
mdiPrinterOutline,
|
|
8
|
+
} from "@mdi/js";
|
|
10
9
|
|
|
11
10
|
type Props = {
|
|
12
11
|
code: string;
|
|
@@ -69,29 +68,44 @@
|
|
|
69
68
|
};
|
|
70
69
|
</script>
|
|
71
70
|
|
|
72
|
-
<Card
|
|
71
|
+
<Card color="primary" class="shadow-none">
|
|
73
72
|
<CardBody class="flex justify-center">
|
|
74
|
-
<
|
|
73
|
+
<Text size="large" fontWeight="semi-bold"
|
|
74
|
+
><pre><code>{code}</code></pre></Text
|
|
75
|
+
>
|
|
75
76
|
</CardBody>
|
|
76
77
|
</Card>
|
|
77
78
|
|
|
78
79
|
<VStack>
|
|
79
|
-
<HStack>
|
|
80
|
-
<Button leadingIcon={mdiPrinter} variant="outline" onclick={print}>
|
|
81
|
-
Print
|
|
82
|
-
</Button>
|
|
83
|
-
<Button leadingIcon={mdiFile} variant="outline" onclick={saveFile}>
|
|
84
|
-
Save as file
|
|
85
|
-
</Button>
|
|
86
|
-
</HStack>
|
|
87
80
|
<Button
|
|
88
|
-
|
|
81
|
+
shape="round"
|
|
89
82
|
variant="outline"
|
|
83
|
+
leadingIcon={mdiContentCopy}
|
|
90
84
|
onclick={copyToClipboard}
|
|
91
85
|
>
|
|
92
|
-
Copy
|
|
86
|
+
Copy recovery key
|
|
93
87
|
</Button>
|
|
94
|
-
|
|
88
|
+
|
|
89
|
+
<HStack>
|
|
90
|
+
<Button
|
|
91
|
+
leadingIcon={mdiDownloadOutline}
|
|
92
|
+
variant="ghost"
|
|
93
|
+
shape="round"
|
|
94
|
+
onclick={saveFile}
|
|
95
|
+
>
|
|
96
|
+
Download
|
|
97
|
+
</Button>
|
|
98
|
+
<Button
|
|
99
|
+
leadingIcon={mdiPrinterOutline}
|
|
100
|
+
variant="ghost"
|
|
101
|
+
shape="round"
|
|
102
|
+
onclick={print}
|
|
103
|
+
>
|
|
104
|
+
Print
|
|
105
|
+
</Button>
|
|
106
|
+
</HStack>
|
|
107
|
+
|
|
108
|
+
{#if /* intentionally hide this to not overcrowd the modal */ PasswordCredential && false}
|
|
95
109
|
<Button
|
|
96
110
|
leadingIcon={mdiAsterisk}
|
|
97
111
|
variant="outline"
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { OnboardingStatusResponseDto } from "../../fetch-client";
|
|
3
|
+
import {
|
|
4
|
+
handleSetupLocalStorage,
|
|
5
|
+
handleStartYuccaLogin,
|
|
6
|
+
} from "../../services/backend.service";
|
|
3
7
|
import {
|
|
4
8
|
handleConfirmRecoveryKey,
|
|
5
9
|
handleCurrentRecoveryKey,
|
|
6
10
|
handleSkipOnboardingExtraConfig,
|
|
7
11
|
} from "../../services/onboarding.service";
|
|
12
|
+
import { Modal, ModalBody } from "@immich/ui";
|
|
8
13
|
import { onMount } from "svelte";
|
|
9
14
|
import CreateFirstBackup from "./stages/SampleCreateFirstBackup.svelte";
|
|
10
15
|
import CreateFirstSchedule from "./stages/SampleCreateFirstSchedule.svelte";
|
|
11
|
-
import BackupOptions from "./stages/OnboardingStageBackupServices.svelte";
|
|
12
|
-
import ConfirmKey from "./stages/OnboardingStageKeyConfirm.svelte";
|
|
13
16
|
import ImportKey from "./stages/OnboardingStageKeyImport.svelte";
|
|
14
|
-
import KeyIntro from "./stages/OnboardingStageKeyIntro.svelte";
|
|
15
|
-
import SaveKey from "./stages/OnboardingStageKeySave.svelte";
|
|
16
17
|
import Telemetry from "./stages/OnboardingStageTelemetry.svelte";
|
|
17
|
-
import
|
|
18
|
+
import StepFinishSetup from "./steps/OnboardingStep1FinishSetup.svelte";
|
|
19
|
+
import StepConnectAccount from "./steps/OnboardingStep2ConnectAccount.svelte";
|
|
20
|
+
import StepSaveRecoveryKey from "./steps/OnboardingStep3SaveRecoveryKey.svelte";
|
|
18
21
|
|
|
19
22
|
type Props = {
|
|
20
23
|
status: OnboardingStatusResponseDto;
|
|
@@ -25,21 +28,23 @@
|
|
|
25
28
|
const { status, onFinish, onCancel }: Props = $props();
|
|
26
29
|
|
|
27
30
|
let code = $state("");
|
|
31
|
+
let confirming = $state(false);
|
|
28
32
|
|
|
29
33
|
// svelte-ignore state_referenced_locally
|
|
30
34
|
let stage:
|
|
31
|
-
| "
|
|
35
|
+
| "intro"
|
|
32
36
|
| "telemetry"
|
|
33
|
-
|
|
|
34
|
-
| "
|
|
37
|
+
| "key"
|
|
38
|
+
| "key-import"
|
|
39
|
+
| "connect"
|
|
35
40
|
| "backup-create"
|
|
36
41
|
| "schedule-create" = $state(
|
|
37
42
|
!status.hasOnboardedKey
|
|
38
|
-
? "
|
|
43
|
+
? "intro"
|
|
39
44
|
: status.hasTelemetry === "none"
|
|
40
45
|
? "telemetry"
|
|
41
46
|
: !status.hasBackend
|
|
42
|
-
? "
|
|
47
|
+
? "connect"
|
|
43
48
|
: !status.hasBackup
|
|
44
49
|
? "backup-create"
|
|
45
50
|
: "schedule-create",
|
|
@@ -57,56 +62,70 @@
|
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
const onConfirmKey = async () => {
|
|
60
|
-
|
|
65
|
+
confirming = true;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
await handleConfirmRecoveryKey();
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
if (status.hasBackend) {
|
|
71
|
+
onFinish();
|
|
72
|
+
} else {
|
|
73
|
+
stage = "connect";
|
|
74
|
+
}
|
|
75
|
+
} finally {
|
|
76
|
+
confirming = false;
|
|
66
77
|
}
|
|
67
78
|
};
|
|
79
|
+
|
|
80
|
+
const onBackendReady = () => (stage = "backup-create");
|
|
68
81
|
</script>
|
|
69
82
|
|
|
70
|
-
{#if stage === "
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
{#if stage === "intro"}
|
|
84
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
85
|
+
<ModalBody>
|
|
86
|
+
<StepFinishSetup
|
|
87
|
+
onContinue={() =>
|
|
88
|
+
(stage = status.hasTelemetry === "none" ? "telemetry" : "key")}
|
|
89
|
+
onImportKey={() => (stage = "key-import")}
|
|
90
|
+
/>
|
|
91
|
+
</ModalBody>
|
|
92
|
+
</Modal>
|
|
76
93
|
{:else if stage === "telemetry"}
|
|
77
94
|
<Telemetry
|
|
78
95
|
onContinue={() =>
|
|
79
96
|
(stage = !status.hasOnboardedKey
|
|
80
|
-
? "key
|
|
97
|
+
? "key"
|
|
81
98
|
: !status.hasBackend
|
|
82
|
-
? "
|
|
99
|
+
? "connect"
|
|
83
100
|
: !status.hasBackup
|
|
84
101
|
? "backup-create"
|
|
85
102
|
: "schedule-create")}
|
|
86
103
|
{onCancel}
|
|
87
104
|
/>
|
|
88
|
-
{:else if stage === "key
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
{code}
|
|
95
|
-
{onConfirmKey}
|
|
96
|
-
onBack={() => (stage = "key-save")}
|
|
97
|
-
{onCancel}
|
|
98
|
-
/>
|
|
105
|
+
{:else if stage === "key"}
|
|
106
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
107
|
+
<ModalBody>
|
|
108
|
+
<StepSaveRecoveryKey {code} onContinue={onConfirmKey} loading={confirming} />
|
|
109
|
+
</ModalBody>
|
|
110
|
+
</Modal>
|
|
99
111
|
{:else if stage === "key-import"}
|
|
100
112
|
<ImportKey
|
|
101
|
-
onStart={() => (stage = "
|
|
113
|
+
onStart={() => (stage = "intro")}
|
|
102
114
|
onImported={(key) => {
|
|
103
115
|
code = key;
|
|
104
|
-
stage = "key
|
|
116
|
+
stage = "key";
|
|
105
117
|
}}
|
|
106
118
|
{onCancel}
|
|
107
119
|
/>
|
|
108
|
-
{:else if stage === "
|
|
109
|
-
<
|
|
120
|
+
{:else if stage === "connect"}
|
|
121
|
+
<Modal size="small" title="FUTO Backups" onClose={onCancel}>
|
|
122
|
+
<ModalBody>
|
|
123
|
+
<StepConnectAccount
|
|
124
|
+
onConnect={() => handleStartYuccaLogin(onBackendReady)}
|
|
125
|
+
onLocalStorage={() => handleSetupLocalStorage(onBackendReady)}
|
|
126
|
+
/>
|
|
127
|
+
</ModalBody>
|
|
128
|
+
</Modal>
|
|
110
129
|
{:else if stage === "backup-create"}
|
|
111
130
|
<CreateFirstBackup onNext={() => (stage = "schedule-create")} {onSkip} />
|
|
112
131
|
{:else if stage === "schedule-create"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import StackList from "../../ui/StackList.svelte";
|
|
3
|
-
import
|
|
3
|
+
import StackListOption from "../../ui/StackListOption.svelte";
|
|
4
4
|
import {
|
|
5
5
|
handleSetupLocalStorage,
|
|
6
6
|
handleStartYuccaLogin,
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Stack,
|
|
16
16
|
Text,
|
|
17
17
|
} from "@immich/ui";
|
|
18
|
-
import {
|
|
18
|
+
import { mdiHarddisk, mdiShieldCheck } from "@mdi/js";
|
|
19
19
|
|
|
20
20
|
type Props = {
|
|
21
21
|
restore?: boolean;
|
|
@@ -44,34 +44,20 @@
|
|
|
44
44
|
>
|
|
45
45
|
<ModalBody>
|
|
46
46
|
<StackList>
|
|
47
|
-
<
|
|
47
|
+
<StackListOption title="FUTO Backups" onclick={onFutoBackups}>
|
|
48
48
|
{#snippet icon()}
|
|
49
|
-
<Icon icon={mdiShieldCheck}
|
|
49
|
+
<Icon icon={mdiShieldCheck} />
|
|
50
50
|
{/snippet}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
</Stack>
|
|
56
|
-
|
|
57
|
-
{#snippet trailing()}
|
|
58
|
-
<Icon icon={mdiChevronRight} />
|
|
59
|
-
{/snippet}
|
|
60
|
-
</StackListItem>
|
|
61
|
-
<StackListItem onclick={onLocalBackups}>
|
|
52
|
+
Simple, hosted backups.
|
|
53
|
+
</StackListOption>
|
|
54
|
+
<StackListOption title="Local Storage" onclick={onLocalBackups}>
|
|
62
55
|
{#snippet icon()}
|
|
63
|
-
<Icon icon={mdiHarddisk}
|
|
56
|
+
<Icon icon={mdiHarddisk} />
|
|
64
57
|
{/snippet}
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<Text>A folder on this computer.</Text>
|
|
69
|
-
</Stack>
|
|
70
|
-
|
|
71
|
-
{#snippet trailing()}
|
|
72
|
-
<Icon icon={mdiChevronRight} />
|
|
73
|
-
{/snippet}
|
|
74
|
-
</StackListItem>
|
|
59
|
+
A folder on this computer.
|
|
60
|
+
</StackListOption>
|
|
75
61
|
</StackList>
|
|
76
62
|
</ModalBody>
|
|
77
63
|
<ModalFooter>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import StepNumber from "../../ui/StepNumber.svelte";
|
|
3
|
+
import { HStack, Stack, Text } from "@immich/ui";
|
|
4
|
+
import OnboardingStepLayout, {
|
|
5
|
+
type OnboardingStepAction,
|
|
6
|
+
} from "./OnboardingStepLayout.svelte";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
onContinue: () => void;
|
|
10
|
+
onImportKey?: () => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const { onContinue, onImportKey }: Props = $props();
|
|
14
|
+
|
|
15
|
+
const steps = [
|
|
16
|
+
"Connect FUTO account",
|
|
17
|
+
"Save your recovery key",
|
|
18
|
+
"Start your first backup",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const actions: OnboardingStepAction[] = [
|
|
22
|
+
{ label: "Continue", onClick: () => onContinue() },
|
|
23
|
+
{
|
|
24
|
+
label: "Import key",
|
|
25
|
+
onClick: () => onImportKey?.(),
|
|
26
|
+
$if: () => !!onImportKey,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<OnboardingStepLayout
|
|
32
|
+
title="Finish setting up FUTO Backups"
|
|
33
|
+
description="Your subscription is active. Finish setup to create your recovery key and start backing up your Immich library."
|
|
34
|
+
{actions}
|
|
35
|
+
>
|
|
36
|
+
<Stack gap={3}>
|
|
37
|
+
{#each steps as step, index (step)}
|
|
38
|
+
<HStack gap={3} class="items-center">
|
|
39
|
+
<StepNumber step={index + 1} size="small" />
|
|
40
|
+
<Text size="small">{step}</Text>
|
|
41
|
+
</HStack>
|
|
42
|
+
{/each}
|
|
43
|
+
</Stack>
|
|
44
|
+
</OnboardingStepLayout>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
onContinue: () => void;
|
|
3
|
+
onImportKey?: () => void;
|
|
4
|
+
};
|
|
5
|
+
declare const OnboardingStep1FinishSetup: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type OnboardingStep1FinishSetup = ReturnType<typeof OnboardingStep1FinishSetup>;
|
|
7
|
+
export default OnboardingStep1FinishSetup;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { HStack, Icon, Stack, Text } from "@immich/ui";
|
|
3
|
+
import { mdiCheckCircle } from "@mdi/js";
|
|
4
|
+
import OnboardingStepLayout, {
|
|
5
|
+
type OnboardingStepAction,
|
|
6
|
+
} from "./OnboardingStepLayout.svelte";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
onConnect: () => void;
|
|
10
|
+
onLocalStorage?: () => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const { onConnect, onLocalStorage }: Props = $props();
|
|
14
|
+
|
|
15
|
+
const outcomes = [
|
|
16
|
+
"Link this server to your FUTO Backups subscription",
|
|
17
|
+
"Allow Immich to upload encrypted backups",
|
|
18
|
+
"Return you here to finish setup",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const actions: OnboardingStepAction[] = [
|
|
22
|
+
{ label: "Connect account", onClick: () => onConnect() },
|
|
23
|
+
{
|
|
24
|
+
label: "Use local storage",
|
|
25
|
+
onClick: () => onLocalStorage?.(),
|
|
26
|
+
$if: () => !!onLocalStorage,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<OnboardingStepLayout
|
|
32
|
+
title="Connect your FUTO account"
|
|
33
|
+
description="Connect your FUTO account to this Immich server so FUTO Backups can store your encrypted backups."
|
|
34
|
+
{actions}
|
|
35
|
+
>
|
|
36
|
+
<Stack gap={3}>
|
|
37
|
+
<Text fontWeight="semi-bold" size="small">This will:</Text>
|
|
38
|
+
|
|
39
|
+
{#each outcomes as outcome (outcome)}
|
|
40
|
+
<HStack gap={3} class="items-center">
|
|
41
|
+
<Icon
|
|
42
|
+
icon={mdiCheckCircle}
|
|
43
|
+
size="1.25rem"
|
|
44
|
+
class="text-primary shrink-0"
|
|
45
|
+
/>
|
|
46
|
+
<Text size="small">{outcome}</Text>
|
|
47
|
+
</HStack>
|
|
48
|
+
{/each}
|
|
49
|
+
</Stack>
|
|
50
|
+
</OnboardingStepLayout>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
onConnect: () => void;
|
|
3
|
+
onLocalStorage?: () => void;
|
|
4
|
+
};
|
|
5
|
+
declare const OnboardingStep2ConnectAccount: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type OnboardingStep2ConnectAccount = ReturnType<typeof OnboardingStep2ConnectAccount>;
|
|
7
|
+
export default OnboardingStep2ConnectAccount;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import RecoveryKeyDisplay from "../RecoveryKeyDisplay.svelte";
|
|
3
|
+
import { Checkbox, HStack, Stack, Text } from "@immich/ui";
|
|
4
|
+
import OnboardingStepLayout, {
|
|
5
|
+
type OnboardingStepAction,
|
|
6
|
+
} from "./OnboardingStepLayout.svelte";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
code: string;
|
|
10
|
+
onContinue: () => void;
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const { code, onContinue, loading = false }: Props = $props();
|
|
15
|
+
|
|
16
|
+
let saved = $state(false);
|
|
17
|
+
|
|
18
|
+
const actions = $derived<OnboardingStepAction[]>([
|
|
19
|
+
{
|
|
20
|
+
label: "Continue",
|
|
21
|
+
onClick: onContinue,
|
|
22
|
+
disabled: !saved,
|
|
23
|
+
loading,
|
|
24
|
+
},
|
|
25
|
+
]);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<OnboardingStepLayout
|
|
29
|
+
title="Save your recovery key"
|
|
30
|
+
description="You'll need this key to restore your encrypted backups. Save it somewhere safe before continuing. FUTO cannot recover this key if it is lost."
|
|
31
|
+
{actions}
|
|
32
|
+
>
|
|
33
|
+
<Stack gap={4}>
|
|
34
|
+
<RecoveryKeyDisplay {code} />
|
|
35
|
+
|
|
36
|
+
<HStack gap={3} class="items-center">
|
|
37
|
+
<Checkbox bind:checked={saved} id="recovery-key-saved" />
|
|
38
|
+
<Text size="small">
|
|
39
|
+
<label for="recovery-key-saved">
|
|
40
|
+
I saved my recovery key somewhere safe.
|
|
41
|
+
</label>
|
|
42
|
+
</Text>
|
|
43
|
+
</HStack>
|
|
44
|
+
</Stack>
|
|
45
|
+
</OnboardingStepLayout>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
code: string;
|
|
3
|
+
onContinue: () => void;
|
|
4
|
+
loading?: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare const OnboardingStep3SaveRecoveryKey: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type OnboardingStep3SaveRecoveryKey = ReturnType<typeof OnboardingStep3SaveRecoveryKey>;
|
|
8
|
+
export default OnboardingStep3SaveRecoveryKey;
|