@futo-org/backups-orchestrator-ui 0.40.2 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/components/backups/BackupItem.svelte +4 -2
  2. package/dist/components/backups/BackupItem.svelte.d.ts +0 -1
  3. package/dist/components/backups/BackupsList.svelte +5 -3
  4. package/dist/components/backups/BackupsList.svelte.d.ts +0 -1
  5. package/dist/components/dashboard/Dashboard.svelte +6 -8
  6. package/dist/components/dashboard/Dashboard.svelte.d.ts +0 -1
  7. package/dist/components/dashboard/DashboardBackupHealth.svelte +4 -2
  8. package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +0 -1
  9. package/dist/components/dashboard/DashboardInstall.svelte +1 -1
  10. package/dist/components/dashboard/DashboardRecentBackups.svelte +4 -2
  11. package/dist/components/dashboard/DashboardRecentBackups.svelte.d.ts +0 -1
  12. package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +88 -140
  13. package/dist/components/integrations/immich/ImmichManageBackup.svelte +8 -48
  14. package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +31 -22
  15. package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte.d.ts +2 -0
  16. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +8 -3
  17. package/dist/components/onboarding/RecoveryKeyDisplay.svelte +3 -3
  18. package/dist/components/test/ImmichTestUi.svelte +5 -5
  19. package/dist/components/test/TestUi.svelte +9 -32
  20. package/dist/components/test/TestUi.svelte.d.ts +1 -4
  21. package/dist/components/test/dashboard/Dashboard.svelte +0 -3
  22. package/dist/components/test/immich/MockImmichPhotos.svelte +1 -1
  23. package/dist/components/util/OnEvents.svelte +3 -1
  24. package/dist/components/util/RelativeTime.svelte +4 -1
  25. package/dist/components/util/YuccaContext.svelte +1 -8
  26. package/dist/components/util/YuccaContext.svelte.d.ts +0 -1
  27. package/dist/events.js +2 -2
  28. package/dist/fetch-client.d.ts +69 -60
  29. package/dist/fetch-client.js +8 -5
  30. package/dist/providers.d.ts +14 -10
  31. package/dist/providers.js +16 -26
  32. package/dist/services/immich.integration.service.d.ts +22 -0
  33. package/dist/services/immich.integration.service.js +58 -0
  34. package/dist/services/integrations.service.d.ts +4 -2
  35. package/dist/services/integrations.service.js +3 -2
  36. package/dist/services/log.service.svelte.js +2 -2
  37. package/dist/services/session.service.js +3 -2
  38. 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, local }: Props = $props();
15
+ const { repository }: Props = $props();
16
+
17
+ const local = getProvider().api === "orchestrator";
16
18
 
17
19
  const BackendNames = {
18
20
  yucca: "FUTO Backups",
@@ -1,7 +1,6 @@
1
1
  import type { LocalRepositoryDto } from "../../fetch-client";
2
2
  type Props = {
3
3
  repository: LocalRepositoryDto;
4
- local?: boolean;
5
4
  };
6
5
  declare const BackupItem: import("svelte").Component<Props, {}, "">;
7
6
  type BackupItem = ReturnType<typeof BackupItem>;
@@ -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 { local, initialData }: Props = $props();
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} {local} />
51
+ <BackupItem {repository} />
50
52
  {/each}
51
53
 
52
54
  {#if localRepositories.length === 0}
@@ -1,6 +1,5 @@
1
1
  import type { RepositoryListResponseDto } from "../../fetch-client";
2
2
  type Props = {
3
- local?: boolean;
4
3
  initialData?: RepositoryListResponseDto;
5
4
  };
6
5
  declare const BackupsList: import("svelte").Component<Props, {}, "">;
@@ -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 { local, initialData, onViewBackups }: Props = $props();
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} {local} />
55
+ <DashboardRecentBackups repositories={query.data} />
58
56
  </Stack>
59
57
  {/if}
@@ -1,6 +1,5 @@
1
1
  import type { RepositoryListResponseDto } from "../../fetch-client";
2
2
  type Props = {
3
- local?: boolean;
4
3
  initialData?: RepositoryListResponseDto;
5
4
  onViewBackups?: () => void;
6
5
  };
@@ -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, local, onViewBackups }: Props = $props();
20
+ const { repositories, onViewBackups }: Props = $props();
21
+
22
+ const local = getProvider().api === "orchestrator";
21
23
 
22
24
  const total = $derived(repositories.length);
23
25
 
@@ -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
  onViewBackups?: () => void;
6
5
  };
7
6
  declare const DashboardBackupHealth: import("svelte").Component<Props, {}, "">;
@@ -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, local }: Props = $props();
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
- useIntegrationEventHandler,
6
- useIntegrations,
7
- } from "../../../services/integrations.service";
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
- // TODO: this should probably be condensed into one big request - since this loads on every initial Immich page load (in the future)
39
-
40
- const integrations = useIntegrations();
41
- const repositories = useRepositories();
42
- const schedules = useSchedules();
43
-
44
- const { onIntegrationUpdate } = useIntegrationEventHandler();
45
- const { onRepositoryCreate, onRepositoryUpdate, onRepositoryDelete } =
46
- useRepositoryEventHandler();
47
- const { onScheduleCreate, onScheduleUpdate, onScheduleDelete } =
48
- useScheduleEventHandler();
49
- const { onRunCreate, onRunUpdate } = useRunEventHandler();
50
-
51
- const integration = $derived(integrations.data?.immichIntegration);
52
-
53
- const repository = $derived(
54
- integration
55
- ? repositories.data?.find((entry) => entry.id === integration.id)
56
- : undefined,
57
- );
58
-
59
- const runHistory = useRunHistory(() => repository?.id);
60
-
61
- const latestBackupRun = $derived(
62
- runHistory.data?.find(
63
- (run) => run.type === "backup" || run.type === "schedule",
64
- ),
65
- );
66
-
67
- const paused = $derived(
68
- Boolean(
69
- integration &&
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
- {onIntegrationUpdate}
120
- {onRepositoryCreate}
121
- {onRepositoryUpdate}
122
- {onRepositoryDelete}
123
- {onScheduleCreate}
124
- {onScheduleUpdate}
125
- {onScheduleDelete}
126
- {onRunCreate}
127
- {onRunUpdate}
128
- />
129
-
130
- {#if !loading}
131
- <a
132
- {href}
133
- class="flex w-full cursor-pointer items-center gap-2 px-3 py-3 text-start text-sm {tints[
134
- status.color
135
- ]}"
136
- >
137
- <Icon color={status.color} icon={status.icon} size="1.25em" class="shrink-0" />
138
-
139
- <Text size="tiny" color={status.color} class="flex-1 truncate">
140
- {#if running}
141
- Backing up now
142
- {:else if outcome === "failed"}
143
- Backup failed
144
- {:else if outcome === "warn" && lastBackup}
145
- Backed up with warnings <RelativeTime time={lastBackup} />
146
- {:else if paused}
147
- Backups paused
148
- {:else if !configured}
149
- Not backed up
150
- {:else if lastBackup}
151
- Last backup <RelativeTime time={lastBackup} />
152
- {:else}
153
- Finish setting up backups
154
- {/if}
155
- </Text>
156
-
157
- <HStack gap={0}>
158
- {#if !configured}
159
- <Text size="tiny" color="primary" class="shrink-0">Set up</Text>
160
- {/if}
161
-
162
- <Icon
163
- color={configured ? status.color : "primary5"}
164
- icon={mdiChevronRight}
165
- size="1.25em"
166
- class="shrink-0"
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
- useIntegrationEventHandler,
10
- useIntegrations,
11
- } from "../../../services/integrations.service";
12
- import {
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 schedules = useSchedules();
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 outcome = $derived(getBackupOutcome(repository.metrics));
26
-
27
- const status = $derived.by(() => {
28
- switch (outcome) {
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
- default: {
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={status.color}>
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={status.icon} />
79
+ <Icon icon={appearance.icon} />
75
80
 
76
- {#if outcome === "never"}
77
- Backup is yet to run.
78
- {:else if outcome === "failed"}
79
- Last backup failed <RelativeTime time={repository.metrics.lastBackup!} />
80
- {:else if outcome === "warn"}
81
- Last backup finished with warnings <RelativeTime
82
- time={repository.metrics.lastBackup!}
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
- Last backup successful <RelativeTime
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>;