@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.
- package/LICENSE +41 -0
- package/dist/components/backends/BackendItem.svelte +64 -0
- package/dist/components/backends/BackendItem.svelte.d.ts +10 -0
- package/dist/components/backends/BackendsList.svelte +73 -0
- package/dist/components/backends/BackendsList.svelte.d.ts +7 -0
- package/dist/components/backends/CreateLocalBackend.svelte +46 -0
- package/dist/components/backends/CreateLocalBackend.svelte.d.ts +7 -0
- package/dist/components/backends/OAuthDeviceFlow.svelte +78 -0
- package/dist/components/backends/OAuthDeviceFlow.svelte.d.ts +9 -0
- package/dist/components/backups/BackupItem.svelte +59 -0
- package/dist/components/backups/BackupItem.svelte.d.ts +7 -0
- package/dist/components/backups/BackupsList.svelte +82 -0
- package/dist/components/backups/BackupsList.svelte.d.ts +8 -0
- package/dist/components/backups/dialogs/ConfigureRepositoryModal.svelte +102 -0
- package/dist/components/backups/dialogs/ConfigureRepositoryModal.svelte.d.ts +8 -0
- package/dist/components/backups/dialogs/CreateRepositoryModal.svelte +59 -0
- package/dist/components/backups/dialogs/CreateRepositoryModal.svelte.d.ts +6 -0
- package/dist/components/backups/dialogs/ImportRepositoryModal.svelte +62 -0
- package/dist/components/backups/dialogs/ImportRepositoryModal.svelte.d.ts +8 -0
- package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +109 -0
- package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte.d.ts +8 -0
- package/dist/components/backups/dialogs/ViewLogModal.svelte +208 -0
- package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +7 -0
- package/dist/components/backups/metrics-history/MetricsHistoryModal.svelte +166 -0
- package/dist/components/backups/metrics-history/MetricsHistoryModal.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte +39 -0
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +7 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +45 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte.d.ts +7 -0
- package/dist/components/backups/run-history/RunHistoryModal.svelte +18 -0
- package/dist/components/backups/run-history/RunHistoryModal.svelte.d.ts +8 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +53 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +7 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +41 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte.d.ts +8 -0
- package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +18 -0
- package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte.d.ts +8 -0
- package/dist/components/dashboard/Dashboard.svelte +52 -0
- package/dist/components/dashboard/Dashboard.svelte.d.ts +9 -0
- package/dist/components/dashboard/DashboardAvgBackupTime.svelte +34 -0
- package/dist/components/dashboard/DashboardAvgBackupTime.svelte.d.ts +7 -0
- package/dist/components/dashboard/DashboardBackupHealth.svelte +91 -0
- package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +9 -0
- package/dist/components/dashboard/DashboardCurrentUsage.svelte +10 -0
- package/dist/components/dashboard/DashboardCurrentUsage.svelte.d.ts +18 -0
- package/dist/components/dashboard/DashboardDailyBackupTime.svelte +31 -0
- package/dist/components/dashboard/DashboardDailyBackupTime.svelte.d.ts +7 -0
- package/dist/components/dashboard/DashboardInstall.svelte +15 -0
- package/dist/components/dashboard/DashboardInstall.svelte.d.ts +18 -0
- package/dist/components/dashboard/DashboardRecentBackups.svelte +104 -0
- package/dist/components/dashboard/DashboardRecentBackups.svelte.d.ts +8 -0
- package/dist/components/dashboard/DashboardTotalStored.svelte +27 -0
- package/dist/components/dashboard/DashboardTotalStored.svelte.d.ts +7 -0
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte +14 -0
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +6 -0
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +402 -0
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +9 -0
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +80 -0
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +8 -0
- package/dist/components/integrations/immich/ImmichManageBackup.svelte +77 -0
- package/dist/components/integrations/immich/ImmichManageBackup.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +100 -0
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte.d.ts +8 -0
- package/dist/components/integrations/immich/ImmichOnboardingRestoreFlow.svelte +75 -0
- package/dist/components/integrations/immich/ImmichOnboardingRestoreFlow.svelte.d.ts +7 -0
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +113 -0
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +8 -0
- package/dist/components/onboarding/OnboardingGate.svelte +48 -0
- package/dist/components/onboarding/OnboardingGate.svelte.d.ts +9 -0
- package/dist/components/onboarding/RecoveryKeyDisplay.svelte +103 -0
- package/dist/components/onboarding/RecoveryKeyDisplay.svelte.d.ts +6 -0
- package/dist/components/onboarding/SampleOnboarding.svelte +98 -0
- package/dist/components/onboarding/SampleOnboarding.svelte.d.ts +9 -0
- package/dist/components/onboarding/dialogs/BackupsRecoveryKeyModal.svelte +43 -0
- package/dist/components/onboarding/dialogs/BackupsRecoveryKeyModal.svelte.d.ts +6 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow.svelte +96 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow.svelte.d.ts +8 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow2SelectSnapshot.svelte +83 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow2SelectSnapshot.svelte.d.ts +9 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow3ConfirmRestore.svelte +118 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow3ConfirmRestore.svelte.d.ts +10 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow4Restore.svelte +59 -0
- package/dist/components/onboarding/restore-point-flow/RestorePointFlow4Restore.svelte.d.ts +8 -0
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +82 -0
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte.d.ts +8 -0
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +56 -0
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +9 -0
- package/dist/components/onboarding/stages/OnboardingStageKeyImport.svelte +57 -0
- package/dist/components/onboarding/stages/OnboardingStageKeyImport.svelte.d.ts +8 -0
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +50 -0
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +7 -0
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +44 -0
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +8 -0
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +56 -0
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +9 -0
- package/dist/components/onboarding/stages/SampleCreateFirstBackup.svelte +43 -0
- package/dist/components/onboarding/stages/SampleCreateFirstBackup.svelte.d.ts +7 -0
- package/dist/components/onboarding/stages/SampleCreateFirstSchedule.svelte +49 -0
- package/dist/components/onboarding/stages/SampleCreateFirstSchedule.svelte.d.ts +7 -0
- package/dist/components/schedules/RepositoryPicker.svelte +105 -0
- package/dist/components/schedules/RepositoryPicker.svelte.d.ts +6 -0
- package/dist/components/schedules/ScheduleItem.svelte +47 -0
- package/dist/components/schedules/ScheduleItem.svelte.d.ts +8 -0
- package/dist/components/schedules/ScheduleList.svelte +51 -0
- package/dist/components/schedules/ScheduleList.svelte.d.ts +3 -0
- package/dist/components/schedules/dialogs/ConfigureScheduleModal.svelte +48 -0
- package/dist/components/schedules/dialogs/ConfigureScheduleModal.svelte.d.ts +8 -0
- package/dist/components/schedules/dialogs/CreateScheduleModal.svelte +43 -0
- package/dist/components/schedules/dialogs/CreateScheduleModal.svelte.d.ts +6 -0
- package/dist/components/test/ImmichTestUi.svelte +183 -0
- package/dist/components/test/ImmichTestUi.svelte.d.ts +6 -0
- package/dist/components/test/TestUi.svelte +134 -0
- package/dist/components/test/TestUi.svelte.d.ts +6 -0
- package/dist/components/test/dashboard/ActiveJobs.svelte +380 -0
- package/dist/components/test/dashboard/ActiveJobs.svelte.d.ts +3 -0
- package/dist/components/test/dashboard/BackupHealth.svelte +95 -0
- package/dist/components/test/dashboard/BackupHealth.svelte.d.ts +7 -0
- package/dist/components/test/dashboard/BackupStats.svelte +117 -0
- package/dist/components/test/dashboard/BackupStats.svelte.d.ts +8 -0
- package/dist/components/test/dashboard/Dashboard.svelte +76 -0
- package/dist/components/test/dashboard/Dashboard.svelte.d.ts +6 -0
- package/dist/components/test/dashboard/RecentBackups.svelte +96 -0
- package/dist/components/test/dashboard/RecentBackups.svelte.d.ts +8 -0
- package/dist/components/ui/PageLayout.svelte +67 -0
- package/dist/components/ui/PageLayout.svelte.d.ts +10 -0
- package/dist/components/ui/PathListField.svelte +83 -0
- package/dist/components/ui/PathListField.svelte.d.ts +17 -0
- package/dist/components/ui/PathPickerField.svelte +74 -0
- package/dist/components/ui/PathPickerField.svelte.d.ts +15 -0
- package/dist/components/ui/PathPickerModal.svelte +219 -0
- package/dist/components/ui/PathPickerModal.svelte.d.ts +14 -0
- package/dist/components/ui/StackList.svelte +30 -0
- package/dist/components/ui/StackList.svelte.d.ts +30 -0
- package/dist/components/ui/StackListItem.svelte +64 -0
- package/dist/components/ui/StackListItem.svelte.d.ts +13 -0
- package/dist/components/ui/VisualisationGauge.svelte +25 -0
- package/dist/components/ui/VisualisationGauge.svelte.d.ts +10 -0
- package/dist/components/ui/VisualisationSegmentedBar.svelte +48 -0
- package/dist/components/ui/VisualisationSegmentedBar.svelte.d.ts +14 -0
- package/dist/components/util/OnEvents.svelte +31 -0
- package/dist/components/util/OnEvents.svelte.d.ts +7 -0
- package/dist/components/util/RelativeTime.svelte +21 -0
- package/dist/components/util/RelativeTime.svelte.d.ts +6 -0
- package/dist/components/util/Suspense.svelte +21 -0
- package/dist/components/util/Suspense.svelte.d.ts +29 -0
- package/dist/components/util/TimedButton.svelte +37 -0
- package/dist/components/util/TimedButton.svelte.d.ts +7 -0
- package/dist/components/util/YuccaContext.svelte +26 -0
- package/dist/components/util/YuccaContext.svelte.d.ts +8 -0
- package/dist/events.d.ts +6 -0
- package/dist/events.js +47 -0
- package/dist/fetch-client.d.ts +289 -0
- package/dist/fetch-client.js +233 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +28 -0
- package/dist/options.d.ts +5 -0
- package/dist/options.js +6 -0
- package/dist/providers.d.ts +11 -0
- package/dist/providers.js +35 -0
- package/dist/query-client.d.ts +2 -0
- package/dist/query-client.js +2 -0
- package/dist/services/backend.service.d.ts +18 -0
- package/dist/services/backend.service.js +61 -0
- package/dist/services/filesystem.service.d.ts +2 -0
- package/dist/services/filesystem.service.js +11 -0
- package/dist/services/immich.integration.service.d.ts +6 -0
- package/dist/services/immich.integration.service.js +24 -0
- package/dist/services/integrations.service.d.ts +13 -0
- package/dist/services/integrations.service.js +42 -0
- package/dist/services/log.service.svelte.d.ts +53 -0
- package/dist/services/log.service.svelte.js +93 -0
- package/dist/services/metricsHistory.service.d.ts +4 -0
- package/dist/services/metricsHistory.service.js +12 -0
- package/dist/services/onboarding.service.d.ts +11 -0
- package/dist/services/onboarding.service.js +56 -0
- package/dist/services/repository.service.d.ts +45 -0
- package/dist/services/repository.service.js +157 -0
- package/dist/services/runHistory.service.d.ts +26 -0
- package/dist/services/runHistory.service.js +54 -0
- package/dist/services/schedule.service.d.ts +35 -0
- package/dist/services/schedule.service.js +126 -0
- package/dist/services/snapshot.service.d.ts +29 -0
- package/dist/services/snapshot.service.js +108 -0
- package/dist/services/task.service.d.ts +3 -0
- package/dist/services/task.service.js +20 -0
- package/dist/utils/actions.d.ts +2 -0
- package/dist/utils/actions.js +3 -0
- package/dist/utils/format.d.ts +2 -0
- package/dist/utils/format.js +24 -0
- package/dist/utils/handle-error.d.ts +9 -0
- package/dist/utils/handle-error.js +42 -0
- package/package.json +79 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
onNext: () => void;
|
|
3
|
+
onImportKey: () => void;
|
|
4
|
+
onCancel: () => void;
|
|
5
|
+
icon?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const OnboardingStageWelcome: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type OnboardingStageWelcome = ReturnType<typeof OnboardingStageWelcome>;
|
|
9
|
+
export default OnboardingStageWelcome;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Checkbox, Field, FormModal, Input, Stack } from "@immich/ui";
|
|
3
|
+
import { useCreateRepository } from "../../../services/repository.service";
|
|
4
|
+
import { SvelteSet } from "svelte/reactivity";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
onNext: () => void;
|
|
8
|
+
onSkip: () => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
let { onNext, onSkip }: Props = $props();
|
|
12
|
+
|
|
13
|
+
let name = $state("");
|
|
14
|
+
let worm = $state(false);
|
|
15
|
+
let paths = new SvelteSet([]);
|
|
16
|
+
|
|
17
|
+
const mutation = useCreateRepository();
|
|
18
|
+
|
|
19
|
+
const onSubmit = () =>
|
|
20
|
+
mutation.mutate(
|
|
21
|
+
{ name, worm, paths: [...paths] },
|
|
22
|
+
{ onSuccess: () => onSkip() },
|
|
23
|
+
);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<FormModal
|
|
27
|
+
title="Create Your First Backup"
|
|
28
|
+
disabled={name.length === 0 || mutation.isPending}
|
|
29
|
+
onClose={onSkip}
|
|
30
|
+
{onSubmit}
|
|
31
|
+
>
|
|
32
|
+
<Stack gap={4}>
|
|
33
|
+
<Field label="Name" description="A memorable name for this backup">
|
|
34
|
+
<Input bind:value={name} />
|
|
35
|
+
</Field>
|
|
36
|
+
<Field
|
|
37
|
+
label="Write once (WORM)"
|
|
38
|
+
description="Prevent anything being deleted"
|
|
39
|
+
>
|
|
40
|
+
<Checkbox bind:checked={worm} />
|
|
41
|
+
</Field>
|
|
42
|
+
</Stack>
|
|
43
|
+
</FormModal>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Field, FormModal, Input, Stack } from "@immich/ui";
|
|
3
|
+
import validate from "cron-validate";
|
|
4
|
+
import { useCreateSchedule } from "../../../services/schedule.service";
|
|
5
|
+
import { useRepositories } from "../../../services/repository.service";
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
onFinish: () => void;
|
|
9
|
+
onSkip: () => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const { onFinish, onSkip }: Props = $props();
|
|
13
|
+
|
|
14
|
+
const query = useRepositories();
|
|
15
|
+
const repositories = $derived(
|
|
16
|
+
(query.data ?? []).filter((repository) => repository.configuration),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
let name = $state("");
|
|
20
|
+
let cron = $state("*/15 * * * *");
|
|
21
|
+
|
|
22
|
+
const mutation = useCreateSchedule();
|
|
23
|
+
|
|
24
|
+
const onSubmit = () =>
|
|
25
|
+
mutation.mutate(
|
|
26
|
+
{
|
|
27
|
+
name,
|
|
28
|
+
cron,
|
|
29
|
+
repositories: repositories.map((repository) => repository.id),
|
|
30
|
+
},
|
|
31
|
+
{ onSuccess: () => onFinish() },
|
|
32
|
+
);
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<FormModal
|
|
36
|
+
title="Create First Schedule"
|
|
37
|
+
disabled={name.length === 0 || validate(cron).isError() || mutation.isPending}
|
|
38
|
+
onClose={onSkip}
|
|
39
|
+
{onSubmit}
|
|
40
|
+
>
|
|
41
|
+
<Stack gap={4}>
|
|
42
|
+
<Field label="Name" description="Give this schedule a name">
|
|
43
|
+
<Input bind:value={name} />
|
|
44
|
+
</Field>
|
|
45
|
+
<Field label="Schedule" description="Uses cron syntax">
|
|
46
|
+
<Input bind:value={cron} />
|
|
47
|
+
</Field>
|
|
48
|
+
</Stack>
|
|
49
|
+
</FormModal>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
onFinish: () => void;
|
|
3
|
+
onSkip: () => void;
|
|
4
|
+
};
|
|
5
|
+
declare const SampleCreateFirstSchedule: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type SampleCreateFirstSchedule = ReturnType<typeof SampleCreateFirstSchedule>;
|
|
7
|
+
export default SampleCreateFirstSchedule;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useRepositories } from "../../services/repository.service";
|
|
3
|
+
import { HStack, IconButton, Stack, Text } from "@immich/ui";
|
|
4
|
+
import { mdiArrowDown, mdiArrowUp, mdiClose, mdiPlus } from "@mdi/js";
|
|
5
|
+
import StackList from "../ui/StackList.svelte";
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
repositories: string[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
let { repositories = $bindable() }: Props = $props();
|
|
12
|
+
|
|
13
|
+
const repositoryQuery = useRepositories();
|
|
14
|
+
|
|
15
|
+
const nameById = $derived(
|
|
16
|
+
Object.fromEntries(
|
|
17
|
+
(repositoryQuery.data ?? []).map((repo) => [repo.id, repo.name]),
|
|
18
|
+
),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const available = $derived(
|
|
22
|
+
(repositoryQuery.data ?? []).filter(
|
|
23
|
+
(repo) => !repositories.includes(repo.id),
|
|
24
|
+
),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const move = (index: number, delta: number) => {
|
|
28
|
+
const target = index + delta;
|
|
29
|
+
if (target < 0 || target >= repositories.length) return;
|
|
30
|
+
const next = [...repositories];
|
|
31
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
32
|
+
repositories = next;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const remove = (id: string) => {
|
|
36
|
+
repositories = repositories.filter((entry) => entry !== id);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const add = (id: string) => {
|
|
40
|
+
repositories = [...repositories, id];
|
|
41
|
+
};
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<Stack gap={4}>
|
|
45
|
+
<StackList>
|
|
46
|
+
{#snippet title()}Repositories{/snippet}
|
|
47
|
+
|
|
48
|
+
{#each repositories as id, index (id)}
|
|
49
|
+
<HStack gap={2} class="px-4 py-3">
|
|
50
|
+
<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>
|
|
76
|
+
{/each}
|
|
77
|
+
|
|
78
|
+
{#if repositories.length === 0}
|
|
79
|
+
<HStack class="px-4 py-3">
|
|
80
|
+
<Text color="secondary" size="small">
|
|
81
|
+
No repositories in this schedule yet.
|
|
82
|
+
</Text>
|
|
83
|
+
</HStack>
|
|
84
|
+
{/if}
|
|
85
|
+
</StackList>
|
|
86
|
+
|
|
87
|
+
{#if available.length > 0}
|
|
88
|
+
<StackList>
|
|
89
|
+
{#snippet title()}Available{/snippet}
|
|
90
|
+
|
|
91
|
+
{#each available as repo (repo.id)}
|
|
92
|
+
<HStack gap={2} class="px-4 py-3">
|
|
93
|
+
<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>
|
|
102
|
+
{/each}
|
|
103
|
+
</StackList>
|
|
104
|
+
{/if}
|
|
105
|
+
</Stack>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import StackListItem from "../ui/StackListItem.svelte";
|
|
3
|
+
import RelativeTime from "../util/RelativeTime.svelte";
|
|
4
|
+
import type { ScheduleDto } from "../../fetch-client";
|
|
5
|
+
import { getScheduleActions } from "../../services/schedule.service";
|
|
6
|
+
import { Badge, HStack, Stack, Text } from "@immich/ui";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
schedule: ScheduleDto;
|
|
10
|
+
repositoryNames: Record<string, string>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const { schedule, repositoryNames }: Props = $props();
|
|
14
|
+
|
|
15
|
+
const { Resume, Pause, Configure, Delete } = $derived(
|
|
16
|
+
getScheduleActions(schedule),
|
|
17
|
+
);
|
|
18
|
+
</script>
|
|
19
|
+
|
|
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>
|
|
43
|
+
{:else}
|
|
44
|
+
<Text size="small" color="secondary">No backups in this schedule.</Text>
|
|
45
|
+
{/if}
|
|
46
|
+
</Stack>
|
|
47
|
+
</StackListItem>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ScheduleDto } from "../../fetch-client";
|
|
2
|
+
type Props = {
|
|
3
|
+
schedule: ScheduleDto;
|
|
4
|
+
repositoryNames: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
declare const ScheduleItem: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type ScheduleItem = ReturnType<typeof ScheduleItem>;
|
|
8
|
+
export default ScheduleItem;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useRepositories } from "../../services/repository.service";
|
|
3
|
+
import {
|
|
4
|
+
useScheduleEventHandler,
|
|
5
|
+
useSchedules,
|
|
6
|
+
} from "../../services/schedule.service";
|
|
7
|
+
import { Button, HStack, modalManager, Stack, Text } from "@immich/ui";
|
|
8
|
+
import StackList from "../ui/StackList.svelte";
|
|
9
|
+
import OnEvents from "../util/OnEvents.svelte";
|
|
10
|
+
import CreateScheduleModal from "./dialogs/CreateScheduleModal.svelte";
|
|
11
|
+
import ScheduleItem from "./ScheduleItem.svelte";
|
|
12
|
+
|
|
13
|
+
const schedulesQuery = useSchedules();
|
|
14
|
+
const repositoriesQuery = useRepositories();
|
|
15
|
+
|
|
16
|
+
const { onScheduleCreate, onScheduleUpdate, onScheduleDelete } =
|
|
17
|
+
useScheduleEventHandler();
|
|
18
|
+
|
|
19
|
+
const repositoryNames = $derived(
|
|
20
|
+
Object.fromEntries(
|
|
21
|
+
repositoriesQuery.data?.map((repository) => [
|
|
22
|
+
repository.id,
|
|
23
|
+
repository.name,
|
|
24
|
+
]) ?? [],
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const onCreate = () => modalManager.open(CreateScheduleModal, {});
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<OnEvents {onScheduleCreate} {onScheduleUpdate} {onScheduleDelete} />
|
|
32
|
+
|
|
33
|
+
<Stack gap={2}>
|
|
34
|
+
<StackList query={schedulesQuery}>
|
|
35
|
+
{#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}
|
|
44
|
+
</StackList>
|
|
45
|
+
|
|
46
|
+
<HStack>
|
|
47
|
+
<Button shape="round" size="tiny" variant="outline" onclick={onCreate}
|
|
48
|
+
>Create new schedule</Button
|
|
49
|
+
>
|
|
50
|
+
</HStack>
|
|
51
|
+
</Stack>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ScheduleDto } from "../../../fetch-client";
|
|
3
|
+
import { Field, FormModal, Input, Stack } from "@immich/ui";
|
|
4
|
+
import validate from "cron-validate";
|
|
5
|
+
import { useUpdateSchedule } from "../../../services/schedule.service";
|
|
6
|
+
import RepositoryPicker from "../RepositoryPicker.svelte";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
schedule: ScheduleDto;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const { onClose, schedule }: Props = $props();
|
|
14
|
+
|
|
15
|
+
// svelte-ignore state_referenced_locally
|
|
16
|
+
let name = $state(schedule.name);
|
|
17
|
+
// svelte-ignore state_referenced_locally
|
|
18
|
+
let cron = $state(schedule.cron);
|
|
19
|
+
// svelte-ignore state_referenced_locally
|
|
20
|
+
let repositories = $state([...schedule.repositories]);
|
|
21
|
+
|
|
22
|
+
const mutation = useUpdateSchedule();
|
|
23
|
+
|
|
24
|
+
const onSubmit = () =>
|
|
25
|
+
mutation.mutate(
|
|
26
|
+
{ id: schedule.id, dto: { name, cron, repositories } },
|
|
27
|
+
{ onSuccess: () => onClose() },
|
|
28
|
+
);
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<FormModal
|
|
32
|
+
title={`Edit ${schedule.name}`}
|
|
33
|
+
size="large"
|
|
34
|
+
disabled={name.length === 0 || validate(cron).isError() || mutation.isPending}
|
|
35
|
+
{onSubmit}
|
|
36
|
+
{onClose}
|
|
37
|
+
>
|
|
38
|
+
<Stack gap={4}>
|
|
39
|
+
<Field label="Name">
|
|
40
|
+
<Input bind:value={name} />
|
|
41
|
+
</Field>
|
|
42
|
+
<Field label="Schedule" description="Uses cron syntax">
|
|
43
|
+
<Input bind:value={cron} />
|
|
44
|
+
</Field>
|
|
45
|
+
|
|
46
|
+
<RepositoryPicker bind:repositories />
|
|
47
|
+
</Stack>
|
|
48
|
+
</FormModal>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ScheduleDto } from "../../../fetch-client";
|
|
2
|
+
type Props = {
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
schedule: ScheduleDto;
|
|
5
|
+
};
|
|
6
|
+
declare const ConfigureScheduleModal: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type ConfigureScheduleModal = ReturnType<typeof ConfigureScheduleModal>;
|
|
8
|
+
export default ConfigureScheduleModal;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Field, FormModal, Input, Stack } from "@immich/ui";
|
|
3
|
+
import validate from "cron-validate";
|
|
4
|
+
import { useCreateSchedule } from "../../../services/schedule.service";
|
|
5
|
+
import RepositoryPicker from "../RepositoryPicker.svelte";
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const { onClose }: Props = $props();
|
|
12
|
+
|
|
13
|
+
let name = $state("");
|
|
14
|
+
let cron = $state("*/15 * * * *");
|
|
15
|
+
let repositories = $state<string[]>([]);
|
|
16
|
+
|
|
17
|
+
const mutation = useCreateSchedule();
|
|
18
|
+
|
|
19
|
+
const onSubmit = () =>
|
|
20
|
+
mutation.mutate(
|
|
21
|
+
{ name, cron, repositories },
|
|
22
|
+
{ onSuccess: () => onClose() },
|
|
23
|
+
);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<FormModal
|
|
27
|
+
title="Create A New Schedule"
|
|
28
|
+
size="large"
|
|
29
|
+
disabled={name.length === 0 || validate(cron).isError() || mutation.isPending}
|
|
30
|
+
{onSubmit}
|
|
31
|
+
{onClose}
|
|
32
|
+
>
|
|
33
|
+
<Stack gap={4}>
|
|
34
|
+
<Field label="Name" description="Give this schedule a name">
|
|
35
|
+
<Input bind:value={name} />
|
|
36
|
+
</Field>
|
|
37
|
+
<Field label="Schedule" description="Uses cron syntax">
|
|
38
|
+
<Input bind:value={cron} />
|
|
39
|
+
</Field>
|
|
40
|
+
|
|
41
|
+
<RepositoryPicker bind:repositories />
|
|
42
|
+
</Stack>
|
|
43
|
+
</FormModal>
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { orchestrationApiProvider, setProvider } from "../../providers";
|
|
3
|
+
import {
|
|
4
|
+
AppShell,
|
|
5
|
+
AppShellHeader,
|
|
6
|
+
AppShellSidebar,
|
|
7
|
+
Avatar,
|
|
8
|
+
Button,
|
|
9
|
+
IconButton,
|
|
10
|
+
Input,
|
|
11
|
+
Logo,
|
|
12
|
+
NavbarGroup,
|
|
13
|
+
NavbarItem,
|
|
14
|
+
ThemeSwitcher,
|
|
15
|
+
} from "@immich/ui";
|
|
16
|
+
import {
|
|
17
|
+
mdiAccountMultipleOutline,
|
|
18
|
+
mdiArchiveArrowDownOutline,
|
|
19
|
+
mdiBackupRestore,
|
|
20
|
+
mdiBellOutline,
|
|
21
|
+
mdiCastVariant,
|
|
22
|
+
mdiHeartOutline,
|
|
23
|
+
mdiImageAlbum,
|
|
24
|
+
mdiImageMultipleOutline,
|
|
25
|
+
mdiLockOutline,
|
|
26
|
+
mdiMagnify,
|
|
27
|
+
mdiMapOutline,
|
|
28
|
+
mdiMenu,
|
|
29
|
+
mdiToolboxOutline,
|
|
30
|
+
mdiTrashCanOutline,
|
|
31
|
+
mdiTrayArrowUp,
|
|
32
|
+
mdiTune,
|
|
33
|
+
} from "@mdi/js";
|
|
34
|
+
import { options } from "../../options";
|
|
35
|
+
import { onDestroy } from "svelte";
|
|
36
|
+
import ImmichManageBackup from "../integrations/immich/ImmichManageBackup.svelte";
|
|
37
|
+
import ImmichOnboardingRestoreFlow from "../integrations/immich/ImmichOnboardingRestoreFlow.svelte";
|
|
38
|
+
import ImmichOnboardingSetupFlow from "../integrations/immich/ImmichOnboardingSetupFlow.svelte";
|
|
39
|
+
|
|
40
|
+
type Props = {
|
|
41
|
+
onExit: () => void;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const { onExit }: Props = $props();
|
|
45
|
+
const { testUiRestore, demoPadding } = options;
|
|
46
|
+
|
|
47
|
+
demoPadding.set(true);
|
|
48
|
+
onDestroy(() => demoPadding.set(false));
|
|
49
|
+
|
|
50
|
+
// svelte-ignore state_referenced_locally
|
|
51
|
+
setProvider(orchestrationApiProvider);
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<AppShell>
|
|
55
|
+
<AppShellHeader>
|
|
56
|
+
<div class="grid grid-cols-[--spacing(64)_auto] items-center w-full py-2">
|
|
57
|
+
<div class="flex flex-row gap-1 mx-4 items-center">
|
|
58
|
+
<IconButton
|
|
59
|
+
shape="round"
|
|
60
|
+
color="secondary"
|
|
61
|
+
variant="ghost"
|
|
62
|
+
size="medium"
|
|
63
|
+
aria-label="Main menu"
|
|
64
|
+
icon={mdiMenu}
|
|
65
|
+
onclick={() => {}}
|
|
66
|
+
class="sidebar:hidden"
|
|
67
|
+
/>
|
|
68
|
+
<Logo variant="inline" class="h-12" />
|
|
69
|
+
</div>
|
|
70
|
+
<div class="flex justify-between gap-4 lg:gap-8 pe-6">
|
|
71
|
+
<div class="hidden w-full max-w-5xl flex-1 sm:block">
|
|
72
|
+
<Input
|
|
73
|
+
placeholder="Search your photos"
|
|
74
|
+
leadingIcon={mdiMagnify}
|
|
75
|
+
trailingIcon={mdiTune}
|
|
76
|
+
shape="round"
|
|
77
|
+
size="medium"
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<section
|
|
82
|
+
class="flex place-items-center justify-end gap-1 md:gap-2 w-full sm:w-auto"
|
|
83
|
+
>
|
|
84
|
+
<IconButton
|
|
85
|
+
color="secondary"
|
|
86
|
+
shape="round"
|
|
87
|
+
variant="ghost"
|
|
88
|
+
size="medium"
|
|
89
|
+
icon={mdiMagnify}
|
|
90
|
+
href="#"
|
|
91
|
+
aria-label="Search"
|
|
92
|
+
class="sm:hidden"
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<Button
|
|
96
|
+
leadingIcon={mdiTrayArrowUp}
|
|
97
|
+
onclick={() => {}}
|
|
98
|
+
class="hidden lg:flex"
|
|
99
|
+
variant="ghost"
|
|
100
|
+
size="medium"
|
|
101
|
+
color="secondary">Upload</Button
|
|
102
|
+
>
|
|
103
|
+
<IconButton
|
|
104
|
+
color="secondary"
|
|
105
|
+
shape="round"
|
|
106
|
+
variant="ghost"
|
|
107
|
+
size="medium"
|
|
108
|
+
onclick={() => {}}
|
|
109
|
+
title="Upload"
|
|
110
|
+
aria-label="Upload"
|
|
111
|
+
icon={mdiTrayArrowUp}
|
|
112
|
+
class="lg:hidden"
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
<ThemeSwitcher size="medium" color="secondary" />
|
|
116
|
+
|
|
117
|
+
<IconButton
|
|
118
|
+
shape="round"
|
|
119
|
+
color="secondary"
|
|
120
|
+
variant="ghost"
|
|
121
|
+
size="medium"
|
|
122
|
+
icon={mdiBellOutline}
|
|
123
|
+
onclick={() => {}}
|
|
124
|
+
aria-label="Notifications"
|
|
125
|
+
/>
|
|
126
|
+
|
|
127
|
+
<IconButton
|
|
128
|
+
shape="round"
|
|
129
|
+
color="secondary"
|
|
130
|
+
variant="ghost"
|
|
131
|
+
size="medium"
|
|
132
|
+
icon={mdiCastVariant}
|
|
133
|
+
onclick={() => {}}
|
|
134
|
+
aria-label="Cast"
|
|
135
|
+
/>
|
|
136
|
+
|
|
137
|
+
<button
|
|
138
|
+
type="button"
|
|
139
|
+
class="flex ps-2"
|
|
140
|
+
onclick={() => {}}
|
|
141
|
+
title="User"
|
|
142
|
+
>
|
|
143
|
+
<Avatar name="FUTO Backups" size="medium" color="primary" />
|
|
144
|
+
</button>
|
|
145
|
+
</section>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</AppShellHeader>
|
|
149
|
+
|
|
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} />
|
|
170
|
+
</div>
|
|
171
|
+
</AppShellSidebar>
|
|
172
|
+
|
|
173
|
+
{#if $testUiRestore}
|
|
174
|
+
<ImmichOnboardingRestoreFlow
|
|
175
|
+
{onExit}
|
|
176
|
+
onFinish={() => testUiRestore.set(false)}
|
|
177
|
+
/>
|
|
178
|
+
{:else}
|
|
179
|
+
<ImmichOnboardingSetupFlow {onExit}>
|
|
180
|
+
<ImmichManageBackup />
|
|
181
|
+
</ImmichOnboardingSetupFlow>
|
|
182
|
+
{/if}
|
|
183
|
+
</AppShell>
|