@futo-org/backups-orchestrator-ui 0.40.2 → 0.42.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/backups/BackupItem.svelte +4 -2
- package/dist/components/backups/BackupItem.svelte.d.ts +0 -1
- package/dist/components/backups/BackupsList.svelte +5 -3
- package/dist/components/backups/BackupsList.svelte.d.ts +0 -1
- package/dist/components/dashboard/Dashboard.svelte +6 -8
- package/dist/components/dashboard/Dashboard.svelte.d.ts +0 -1
- package/dist/components/dashboard/DashboardBackupHealth.svelte +4 -2
- package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +0 -1
- package/dist/components/dashboard/DashboardInstall.svelte +1 -1
- package/dist/components/dashboard/DashboardRecentBackups.svelte +4 -2
- package/dist/components/dashboard/DashboardRecentBackups.svelte.d.ts +0 -1
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +88 -140
- package/dist/components/integrations/immich/ImmichManageBackup.svelte +8 -48
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +31 -22
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte.d.ts +2 -0
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +8 -3
- package/dist/components/onboarding/RecoveryKeyDisplay.svelte +3 -3
- package/dist/components/test/ImmichTestUi.svelte +5 -5
- package/dist/components/test/TestUi.svelte +9 -32
- package/dist/components/test/TestUi.svelte.d.ts +1 -4
- package/dist/components/test/dashboard/Dashboard.svelte +0 -3
- package/dist/components/test/immich/MockImmichPhotos.svelte +1 -1
- package/dist/components/util/OnEvents.svelte +3 -1
- package/dist/components/util/RelativeTime.svelte +4 -1
- package/dist/components/util/YuccaContext.svelte +1 -8
- package/dist/components/util/YuccaContext.svelte.d.ts +0 -1
- package/dist/events.js +2 -2
- package/dist/fetch-client.d.ts +69 -60
- package/dist/fetch-client.js +8 -5
- package/dist/providers.d.ts +14 -10
- package/dist/providers.js +16 -26
- package/dist/services/immich.integration.service.d.ts +22 -0
- package/dist/services/immich.integration.service.js +58 -0
- package/dist/services/integrations.service.d.ts +4 -2
- package/dist/services/integrations.service.js +3 -2
- package/dist/services/log.service.svelte.js +2 -2
- package/dist/services/session.service.js +3 -2
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { LocalRepositoryDto } from "../../fetch-client";
|
|
3
|
+
import { getProvider } from "../../providers";
|
|
3
4
|
import { getRepositoryActions } from "../../services/repository.service";
|
|
4
5
|
import { getBackupOutcome } from "../../utils/backup-status";
|
|
5
6
|
import { Badge, FormatBytes, Icon } from "@immich/ui";
|
|
@@ -9,10 +10,11 @@
|
|
|
9
10
|
|
|
10
11
|
type Props = {
|
|
11
12
|
repository: LocalRepositoryDto;
|
|
12
|
-
local?: boolean
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
const { repository
|
|
15
|
+
const { repository }: Props = $props();
|
|
16
|
+
|
|
17
|
+
const local = getProvider().api === "orchestrator";
|
|
16
18
|
|
|
17
19
|
const BackendNames = {
|
|
18
20
|
yucca: "FUTO Backups",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
useRepositories,
|
|
5
5
|
useRepositoryEventHandler,
|
|
6
6
|
} from "../../services/repository.service";
|
|
7
|
+
import { getProvider } from "../../providers";
|
|
7
8
|
import { Button, HStack, modalManager, Stack } from "@immich/ui";
|
|
8
9
|
import StackList from "../ui/StackList.svelte";
|
|
9
10
|
import StackListPlaceholder from "../ui/StackListPlaceholder.svelte";
|
|
@@ -13,11 +14,12 @@
|
|
|
13
14
|
import CreateRepositoryModal from "./dialogs/CreateRepositoryModal.svelte";
|
|
14
15
|
|
|
15
16
|
type Props = {
|
|
16
|
-
local?: boolean;
|
|
17
17
|
initialData?: RepositoryListResponseDto;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
const {
|
|
20
|
+
const { initialData }: Props = $props();
|
|
21
|
+
|
|
22
|
+
const local = getProvider().api === "orchestrator";
|
|
21
23
|
|
|
22
24
|
// svelte-ignore state_referenced_locally
|
|
23
25
|
const query = useRepositories(initialData?.repositories);
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
|
|
47
49
|
<Suspense {query}>
|
|
48
50
|
{#each localRepositories as repository (repository.id)}
|
|
49
|
-
<BackupItem {repository}
|
|
51
|
+
<BackupItem {repository} />
|
|
50
52
|
{/each}
|
|
51
53
|
|
|
52
54
|
{#if localRepositories.length === 0}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
useRepositories,
|
|
5
5
|
useRepositoryEventHandler,
|
|
6
6
|
} from "../../services/repository.service";
|
|
7
|
+
import { getProvider } from "../../providers";
|
|
7
8
|
import { getReadableErrorMessage } from "../../utils/handle-error";
|
|
8
9
|
import { Alert, LoadingSpinner, Stack } from "@immich/ui";
|
|
9
10
|
import OnEvents from "../util/OnEvents.svelte";
|
|
@@ -16,12 +17,13 @@
|
|
|
16
17
|
import DashboardTotalStored from "./DashboardTotalStored.svelte";
|
|
17
18
|
|
|
18
19
|
type Props = {
|
|
19
|
-
local?: boolean;
|
|
20
20
|
initialData?: RepositoryListResponseDto;
|
|
21
21
|
onViewBackups?: () => void;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const {
|
|
24
|
+
const { initialData, onViewBackups }: Props = $props();
|
|
25
|
+
|
|
26
|
+
const local = getProvider().api === "orchestrator";
|
|
25
27
|
|
|
26
28
|
// svelte-ignore state_referenced_locally
|
|
27
29
|
const query = useRepositories(initialData?.repositories);
|
|
@@ -38,11 +40,7 @@
|
|
|
38
40
|
{:else if query.isSuccess}
|
|
39
41
|
<Stack gap={6}>
|
|
40
42
|
<Stack direction="row" gap={4}>
|
|
41
|
-
<DashboardBackupHealth
|
|
42
|
-
repositories={query.data}
|
|
43
|
-
{local}
|
|
44
|
-
{onViewBackups}
|
|
45
|
-
/>
|
|
43
|
+
<DashboardBackupHealth repositories={query.data} {onViewBackups} />
|
|
46
44
|
|
|
47
45
|
{#if !local}
|
|
48
46
|
<DashboardInstall />
|
|
@@ -54,6 +52,6 @@
|
|
|
54
52
|
<DashboardTotalStored repositories={query.data} />
|
|
55
53
|
<DashboardCurrentUsage />
|
|
56
54
|
</Stack>
|
|
57
|
-
<DashboardRecentBackups repositories={query.data}
|
|
55
|
+
<DashboardRecentBackups repositories={query.data} />
|
|
58
56
|
</Stack>
|
|
59
57
|
{/if}
|
|
@@ -8,16 +8,18 @@
|
|
|
8
8
|
CardTitle,
|
|
9
9
|
HStack,
|
|
10
10
|
} from "@immich/ui";
|
|
11
|
+
import { getProvider } from "../../providers";
|
|
11
12
|
import { getBackupOutcome } from "../../utils/backup-status";
|
|
12
13
|
import VisualisationSegmentedBar from "../ui/VisualisationSegmentedBar.svelte";
|
|
13
14
|
|
|
14
15
|
type Props = {
|
|
15
16
|
repositories: LocalRepositoryDto[];
|
|
16
|
-
local?: boolean;
|
|
17
17
|
onViewBackups?: () => void;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
const { repositories,
|
|
20
|
+
const { repositories, onViewBackups }: Props = $props();
|
|
21
|
+
|
|
22
|
+
const local = getProvider().api === "orchestrator";
|
|
21
23
|
|
|
22
24
|
const total = $derived(repositories.length);
|
|
23
25
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<CardTitle>Install FUTO Backups</CardTitle>
|
|
8
8
|
</CardHeader>
|
|
9
9
|
<CardBody>
|
|
10
|
-
<Button variant="outline" size="small">
|
|
10
|
+
<Button href="https://my.immich.app/link?target=backups" variant="outline" size="small">
|
|
11
11
|
<Logo variant="icon" size="tiny" />
|
|
12
12
|
Setup on Immich
|
|
13
13
|
</Button>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
mdiCloudOffOutline,
|
|
7
7
|
mdiHistory,
|
|
8
8
|
} from "@mdi/js";
|
|
9
|
+
import { getProvider } from "../../providers";
|
|
9
10
|
import { getBackupOutcome } from "../../utils/backup-status";
|
|
10
11
|
import MetricsHistoryModal from "../backups/metrics-history/MetricsHistoryModal.svelte";
|
|
11
12
|
import StackList from "../ui/StackList.svelte";
|
|
@@ -15,10 +16,11 @@
|
|
|
15
16
|
|
|
16
17
|
type Props = {
|
|
17
18
|
repositories: LocalRepositoryDto[];
|
|
18
|
-
local?: boolean;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
const { repositories
|
|
21
|
+
const { repositories }: Props = $props();
|
|
22
|
+
|
|
23
|
+
const local = getProvider().api === "orchestrator";
|
|
22
24
|
|
|
23
25
|
const recentAttempts = $derived(
|
|
24
26
|
repositories
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { LocalRepositoryDto } from "../../fetch-client";
|
|
2
2
|
type Props = {
|
|
3
3
|
repositories: LocalRepositoryDto[];
|
|
4
|
-
local?: boolean;
|
|
5
4
|
};
|
|
6
5
|
declare const DashboardRecentBackups: import("svelte").Component<Props, {}, "">;
|
|
7
6
|
type DashboardRecentBackups = ReturnType<typeof DashboardRecentBackups>;
|
|
@@ -2,23 +2,10 @@
|
|
|
2
2
|
import OnEvents from "../../util/OnEvents.svelte";
|
|
3
3
|
import RelativeTime from "../../util/RelativeTime.svelte";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "../../../services/
|
|
8
|
-
import {
|
|
9
|
-
useRepositories,
|
|
10
|
-
useRepositoryEventHandler,
|
|
11
|
-
} from "../../../services/repository.service";
|
|
12
|
-
import {
|
|
13
|
-
useRunEventHandler,
|
|
14
|
-
useRunHistory,
|
|
15
|
-
} from "../../../services/runHistory.service";
|
|
16
|
-
import {
|
|
17
|
-
useScheduleEventHandler,
|
|
18
|
-
useSchedules,
|
|
19
|
-
} from "../../../services/schedule.service";
|
|
20
|
-
import { getBackupOutcome } from "../../../utils/backup-status";
|
|
21
|
-
import { HStack, Icon, Text } from "@immich/ui";
|
|
5
|
+
useImmichBackupStatus,
|
|
6
|
+
useImmichBackupStatusEventHandler,
|
|
7
|
+
} from "../../../services/immich.integration.service";
|
|
8
|
+
import { HStack, Icon, LoadingSpinner, Text } from "@immich/ui";
|
|
22
9
|
import {
|
|
23
10
|
mdiChevronRight,
|
|
24
11
|
mdiCloudAlertOutline,
|
|
@@ -27,7 +14,7 @@
|
|
|
27
14
|
mdiCloudUploadOutline,
|
|
28
15
|
} from "@mdi/js";
|
|
29
16
|
|
|
30
|
-
type Color = "primary" | "success" | "warning" | "danger";
|
|
17
|
+
type Color = "primary" | "secondary" | "success" | "warning" | "danger";
|
|
31
18
|
|
|
32
19
|
type Props = {
|
|
33
20
|
href: string;
|
|
@@ -35,136 +22,97 @@
|
|
|
35
22
|
|
|
36
23
|
const { href }: Props = $props();
|
|
37
24
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
schedules.data?.find((entry) => entry.id === integration.scheduleId)
|
|
71
|
-
?.paused,
|
|
72
|
-
),
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const lastBackup = $derived(repository?.metrics.lastBackup ?? undefined);
|
|
76
|
-
|
|
77
|
-
const outcome = $derived(getBackupOutcome(repository?.metrics));
|
|
78
|
-
|
|
79
|
-
const loading = $derived(
|
|
80
|
-
integrations.isLoading || repositories.isLoading || schedules.isLoading,
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
const configured = $derived(Boolean(repository));
|
|
84
|
-
const running = $derived(latestBackupRun?.status === "incomplete");
|
|
85
|
-
|
|
86
|
-
const status = $derived.by(() => {
|
|
87
|
-
if (running) {
|
|
88
|
-
return { color: "primary", icon: mdiCloudUploadOutline } as const;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (outcome === "failed") {
|
|
92
|
-
return { color: "danger", icon: mdiCloudOffOutline } as const;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (outcome === "warn") {
|
|
96
|
-
return { color: "warning", icon: mdiCloudCheckVariantOutline } as const;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (paused) {
|
|
100
|
-
return { color: "warning", icon: mdiCloudAlertOutline } as const;
|
|
25
|
+
const backup = useImmichBackupStatus();
|
|
26
|
+
|
|
27
|
+
const { status } = $derived(backup);
|
|
28
|
+
|
|
29
|
+
const configured = $derived(status.kind !== "unconfigured");
|
|
30
|
+
|
|
31
|
+
const appearance = $derived.by(() => {
|
|
32
|
+
switch (status.kind) {
|
|
33
|
+
case "loading": {
|
|
34
|
+
return { color: "secondary", icon: undefined } as const;
|
|
35
|
+
}
|
|
36
|
+
case "running": {
|
|
37
|
+
return { color: "primary", icon: mdiCloudUploadOutline } as const;
|
|
38
|
+
}
|
|
39
|
+
case "offline":
|
|
40
|
+
case "missing":
|
|
41
|
+
case "failed": {
|
|
42
|
+
return { color: "danger", icon: mdiCloudOffOutline } as const;
|
|
43
|
+
}
|
|
44
|
+
case "warn": {
|
|
45
|
+
return { color: "warning", icon: mdiCloudCheckVariantOutline } as const;
|
|
46
|
+
}
|
|
47
|
+
case "paused": {
|
|
48
|
+
return { color: "warning", icon: mdiCloudAlertOutline } as const;
|
|
49
|
+
}
|
|
50
|
+
case "unconfigured":
|
|
51
|
+
case "never": {
|
|
52
|
+
return { color: "warning", icon: mdiCloudOffOutline } as const;
|
|
53
|
+
}
|
|
54
|
+
case "complete": {
|
|
55
|
+
return { color: "success", icon: mdiCloudCheckVariantOutline } as const;
|
|
56
|
+
}
|
|
101
57
|
}
|
|
102
|
-
|
|
103
|
-
if (!configured || !lastBackup) {
|
|
104
|
-
return { color: "warning", icon: mdiCloudOffOutline } as const;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return { color: "success", icon: mdiCloudCheckVariantOutline } as const;
|
|
108
58
|
});
|
|
109
59
|
|
|
110
60
|
const tints: Record<Color, string> = {
|
|
111
61
|
primary: "bg-primary-50 text-primary",
|
|
62
|
+
secondary: "bg-subtle text-muted",
|
|
112
63
|
success: "bg-success-50 text-success-700",
|
|
113
64
|
warning: "bg-warning-50 text-warning-800",
|
|
114
65
|
danger: "bg-danger-50 text-danger-700",
|
|
115
66
|
};
|
|
116
67
|
</script>
|
|
117
68
|
|
|
118
|
-
<OnEvents
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{
|
|
122
|
-
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
status
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
</HStack>
|
|
169
|
-
</a>
|
|
170
|
-
{/if}
|
|
69
|
+
<OnEvents {...useImmichBackupStatusEventHandler()} />
|
|
70
|
+
|
|
71
|
+
<a
|
|
72
|
+
{href}
|
|
73
|
+
class="flex w-full cursor-pointer items-center gap-2 px-3 py-3 text-start text-sm {tints[
|
|
74
|
+
appearance.color
|
|
75
|
+
]}"
|
|
76
|
+
>
|
|
77
|
+
{#if appearance.icon}
|
|
78
|
+
<Icon icon={appearance.icon} size="1.25em" class="shrink-0" />
|
|
79
|
+
{:else}
|
|
80
|
+
<LoadingSpinner size="tiny" class="shrink-0" />
|
|
81
|
+
{/if}
|
|
82
|
+
|
|
83
|
+
<Text size="tiny" class="flex-1 leading-tight">
|
|
84
|
+
{#if status.kind === "loading"}
|
|
85
|
+
Checking backup status
|
|
86
|
+
{:else if status.kind === "offline"}
|
|
87
|
+
Backup service is offline
|
|
88
|
+
{:else if status.kind === "missing"}
|
|
89
|
+
Backup missing on service
|
|
90
|
+
{:else if status.kind === "running"}
|
|
91
|
+
Backing up now
|
|
92
|
+
{:else if status.kind === "failed"}
|
|
93
|
+
Backup failed
|
|
94
|
+
{:else if status.kind === "warn"}
|
|
95
|
+
Backed up with warnings <RelativeTime time={status.lastBackup} />
|
|
96
|
+
{:else if status.kind === "paused"}
|
|
97
|
+
Backups paused
|
|
98
|
+
{:else if status.kind === "unconfigured"}
|
|
99
|
+
Not backed up
|
|
100
|
+
{:else if status.kind === "complete"}
|
|
101
|
+
Last backup <RelativeTime time={status.lastBackup} />
|
|
102
|
+
{:else}
|
|
103
|
+
Finish setting up backups
|
|
104
|
+
{/if}
|
|
105
|
+
</Text>
|
|
106
|
+
|
|
107
|
+
<HStack gap={0}>
|
|
108
|
+
{#if !configured}
|
|
109
|
+
<Text size="tiny" color="primary" class="shrink-0">Set up</Text>
|
|
110
|
+
{/if}
|
|
111
|
+
|
|
112
|
+
<Icon
|
|
113
|
+
icon={mdiChevronRight}
|
|
114
|
+
size="1.25em"
|
|
115
|
+
class={configured ? "shrink-0" : "shrink-0 text-primary"}
|
|
116
|
+
/>
|
|
117
|
+
</HStack>
|
|
118
|
+
</a>
|
|
@@ -4,52 +4,20 @@
|
|
|
4
4
|
import RepositorySnapshotsList from "../../backups/snapshots-list/RepositorySnapshotsList.svelte";
|
|
5
5
|
import PageLayout from "../../ui/PageLayout.svelte";
|
|
6
6
|
import OnEvents from "../../util/OnEvents.svelte";
|
|
7
|
-
import { getBackupPageActions } from "../../../services/immich.integration.service";
|
|
8
7
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
useRepositories,
|
|
14
|
-
useRepositoryEventHandler,
|
|
15
|
-
} from "../../../services/repository.service";
|
|
16
|
-
import {
|
|
17
|
-
useScheduleEventHandler,
|
|
18
|
-
useSchedules,
|
|
19
|
-
} from "../../../services/schedule.service";
|
|
8
|
+
getBackupPageActions,
|
|
9
|
+
useImmichBackupStatus,
|
|
10
|
+
useImmichBackupStatusEventHandler,
|
|
11
|
+
} from "../../../services/immich.integration.service";
|
|
20
12
|
import RepositoryRunHistoryPage from "../../backups/run-history/RepositoryRunHistoryPage.svelte";
|
|
21
13
|
import RepositorySnapshotsPage from "../../backups/snapshots-list/RepositorySnapshotsPage.svelte";
|
|
22
14
|
import ImmichBackupSettings from "./ImmichBackupSettings.svelte";
|
|
23
15
|
import { Container, Stack } from "@immich/ui";
|
|
24
16
|
import ImmichManageBackupOverview from "./ImmichManageBackupOverview.svelte";
|
|
25
17
|
|
|
26
|
-
const
|
|
27
|
-
const repositories = useRepositories();
|
|
28
|
-
const integrations = useIntegrations();
|
|
29
|
-
|
|
30
|
-
const { onScheduleCreate, onScheduleUpdate, onScheduleDelete } =
|
|
31
|
-
useScheduleEventHandler();
|
|
32
|
-
const { onRepositoryCreate, onRepositoryUpdate, onRepositoryDelete } =
|
|
33
|
-
useRepositoryEventHandler();
|
|
34
|
-
const { onIntegrationUpdate } = useIntegrationEventHandler();
|
|
18
|
+
const backup = useImmichBackupStatus();
|
|
35
19
|
|
|
36
|
-
const schedule = $derived(
|
|
37
|
-
integrations.data?.immichIntegration
|
|
38
|
-
? schedules.data?.find(
|
|
39
|
-
(schedule) =>
|
|
40
|
-
schedule.id === integrations.data.immichIntegration!.scheduleId,
|
|
41
|
-
)
|
|
42
|
-
: undefined,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const repository = $derived(
|
|
46
|
-
integrations.data?.immichIntegration
|
|
47
|
-
? repositories.data?.find(
|
|
48
|
-
(repository) =>
|
|
49
|
-
repository.id === integrations.data.immichIntegration!.id,
|
|
50
|
-
)
|
|
51
|
-
: undefined,
|
|
52
|
-
);
|
|
20
|
+
const { repository, schedule } = $derived(backup);
|
|
53
21
|
|
|
54
22
|
let view = $state<"overview" | "attempts" | "snapshots" | "settings">(
|
|
55
23
|
"overview",
|
|
@@ -60,15 +28,7 @@
|
|
|
60
28
|
);
|
|
61
29
|
</script>
|
|
62
30
|
|
|
63
|
-
<OnEvents
|
|
64
|
-
{onScheduleCreate}
|
|
65
|
-
{onScheduleUpdate}
|
|
66
|
-
{onScheduleDelete}
|
|
67
|
-
{onRepositoryCreate}
|
|
68
|
-
{onRepositoryUpdate}
|
|
69
|
-
{onRepositoryDelete}
|
|
70
|
-
{onIntegrationUpdate}
|
|
71
|
-
/>
|
|
31
|
+
<OnEvents {...useImmichBackupStatusEventHandler()} />
|
|
72
32
|
|
|
73
33
|
{#if view === "attempts" && repository}
|
|
74
34
|
<PageLayout title="Backup attempts" onBack={() => (view = "overview")}>
|
|
@@ -97,7 +57,7 @@
|
|
|
97
57
|
<Container size="medium" center>
|
|
98
58
|
{#if repository && schedule}
|
|
99
59
|
<Stack class="mt-4" gap={6}>
|
|
100
|
-
<ImmichManageBackupOverview {repository} {schedule} />
|
|
60
|
+
<ImmichManageBackupOverview {repository} {schedule} status={backup.status} />
|
|
101
61
|
<BackendsList {repository} />
|
|
102
62
|
<RepositoryRunHistory
|
|
103
63
|
{repository}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import StackListItem from "../../ui/StackListItem.svelte";
|
|
4
4
|
import RelativeTime from "../../util/RelativeTime.svelte";
|
|
5
5
|
import type { LocalRepositoryDto, ScheduleDto } from "../../../fetch-client";
|
|
6
|
+
import type { ImmichBackupStatus } from "../../../services/immich.integration.service";
|
|
6
7
|
import { handleCreateBackup } from "../../../services/repository.service";
|
|
7
|
-
import { getBackupOutcome } from "../../../utils/backup-status";
|
|
8
8
|
import { Button, FormatBytes, Icon } from "@immich/ui";
|
|
9
9
|
import {
|
|
10
10
|
mdiAlert,
|
|
@@ -12,39 +12,44 @@
|
|
|
12
12
|
mdiCheck,
|
|
13
13
|
mdiCloudUploadOutline,
|
|
14
14
|
mdiInformation,
|
|
15
|
+
mdiProgressUpload,
|
|
15
16
|
} from "@mdi/js";
|
|
16
17
|
import cronstrue from "cronstrue";
|
|
17
18
|
|
|
18
19
|
type Props = {
|
|
19
20
|
repository: LocalRepositoryDto;
|
|
20
21
|
schedule: ScheduleDto;
|
|
22
|
+
status: ImmichBackupStatus;
|
|
21
23
|
};
|
|
22
24
|
|
|
23
|
-
const { repository, schedule }: Props = $props();
|
|
25
|
+
const { repository, schedule, status }: Props = $props();
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
case "never": {
|
|
30
|
-
return { color: "warning", icon: mdiInformation } as const;
|
|
27
|
+
const appearance = $derived.by(() => {
|
|
28
|
+
switch (status.kind) {
|
|
29
|
+
case "running": {
|
|
30
|
+
return { color: "primary", icon: mdiProgressUpload } as const;
|
|
31
31
|
}
|
|
32
|
+
case "offline":
|
|
33
|
+
case "missing":
|
|
32
34
|
case "failed": {
|
|
33
35
|
return { color: "danger", icon: mdiAlert } as const;
|
|
34
36
|
}
|
|
35
37
|
case "warn": {
|
|
36
38
|
return { color: "warning", icon: mdiAlert } as const;
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
case "complete": {
|
|
39
41
|
return { color: "success", icon: mdiCheck } as const;
|
|
40
42
|
}
|
|
43
|
+
default: {
|
|
44
|
+
return { color: "warning", icon: mdiInformation } as const;
|
|
45
|
+
}
|
|
41
46
|
}
|
|
42
47
|
});
|
|
43
48
|
|
|
44
49
|
</script>
|
|
45
50
|
|
|
46
51
|
<StackList>
|
|
47
|
-
<StackListItem title="Your library" footerColor={
|
|
52
|
+
<StackListItem title="Your library" footerColor={appearance.color}>
|
|
48
53
|
{#snippet icon()}
|
|
49
54
|
<Icon icon={mdiArchiveOutline} />
|
|
50
55
|
{/snippet}
|
|
@@ -71,20 +76,24 @@
|
|
|
71
76
|
{/snippet}
|
|
72
77
|
|
|
73
78
|
{#snippet footer()}
|
|
74
|
-
<Icon icon={
|
|
79
|
+
<Icon icon={appearance.icon} />
|
|
75
80
|
|
|
76
|
-
{#if
|
|
77
|
-
Backup is
|
|
78
|
-
{:else if
|
|
79
|
-
|
|
80
|
-
{:else if
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
/>
|
|
81
|
+
{#if status.kind === "offline"}
|
|
82
|
+
Backup storage is offline.
|
|
83
|
+
{:else if status.kind === "missing"}
|
|
84
|
+
Backup is missing on the service.
|
|
85
|
+
{:else if status.kind === "running"}
|
|
86
|
+
Backup in progress
|
|
87
|
+
{:else if status.kind === "failed"}
|
|
88
|
+
Last backup failed <RelativeTime time={status.lastBackup} />
|
|
89
|
+
{:else if status.kind === "warn"}
|
|
90
|
+
Last backup finished with warnings <RelativeTime time={status.lastBackup} />
|
|
91
|
+
{:else if status.kind === "complete"}
|
|
92
|
+
Last backup successful <RelativeTime time={status.lastBackup} />
|
|
93
|
+
{:else if status.kind === "paused"}
|
|
94
|
+
Backups paused
|
|
84
95
|
{:else}
|
|
85
|
-
|
|
86
|
-
time={repository.metrics.lastBackup!}
|
|
87
|
-
/>
|
|
96
|
+
Backup is yet to run.
|
|
88
97
|
{/if}
|
|
89
98
|
{/snippet}
|
|
90
99
|
</StackListItem>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { LocalRepositoryDto, ScheduleDto } from "../../../fetch-client";
|
|
2
|
+
import type { ImmichBackupStatus } from "../../../services/immich.integration.service";
|
|
2
3
|
type Props = {
|
|
3
4
|
repository: LocalRepositoryDto;
|
|
4
5
|
schedule: ScheduleDto;
|
|
6
|
+
status: ImmichBackupStatus;
|
|
5
7
|
};
|
|
6
8
|
declare const ImmichManageBackupOverview: import("svelte").Component<Props, {}, "">;
|
|
7
9
|
type ImmichManageBackupOverview = ReturnType<typeof ImmichManageBackupOverview>;
|