@futo-org/backups-orchestrator-ui 0.45.0 → 0.46.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/integrations/immich/ImmichBackupSettingsPage.svelte +2 -0
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +8 -1
- package/dist/components/integrations/immich/ImmichDatabaseDumpAlert.svelte +42 -0
- package/dist/components/integrations/immich/ImmichDatabaseDumpAlert.svelte.d.ts +18 -0
- package/dist/components/integrations/immich/ImmichManageBackupPage.svelte +2 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsBandwidth.svelte +150 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsBandwidth.svelte.d.ts +3 -0
- package/dist/fetch-client.d.ts +24 -0
- package/dist/fetch-client.js +25 -0
- package/dist/services/config.service.d.ts +6 -0
- package/dist/services/config.service.js +16 -0
- package/dist/services/immich.integration.service.d.ts +4 -0
- package/dist/services/immich.integration.service.js +27 -2
- package/package.json +2 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Container } from "@immich/ui";
|
|
3
3
|
import ImmichConfiguredGate from "./ImmichConfiguredGate.svelte";
|
|
4
4
|
import ImmichSettingsBackupContents from "./settings/ImmichSettingsBackupContents.svelte";
|
|
5
|
+
import ImmichSettingsBandwidth from "./settings/ImmichSettingsBandwidth.svelte";
|
|
5
6
|
import ImmichSettingsSchedule from "./settings/ImmichSettingsSchedule.svelte";
|
|
6
7
|
import ImmichSettingsStorage from "./settings/ImmichSettingsStorage.svelte";
|
|
7
8
|
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
<Container size="large" center>
|
|
18
19
|
<ImmichSettingsBackupContents />
|
|
19
20
|
<ImmichSettingsSchedule />
|
|
21
|
+
<ImmichSettingsBandwidth />
|
|
20
22
|
<ImmichSettingsStorage />
|
|
21
23
|
</Container>
|
|
22
24
|
{/snippet}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
} from "../../../services/immich.integration.service";
|
|
8
8
|
import { HStack, Icon, LoadingSpinner, Text } from "@immich/ui";
|
|
9
9
|
import {
|
|
10
|
+
mdiAlertCircleOutline,
|
|
10
11
|
mdiChevronRight,
|
|
11
12
|
mdiCloudAlertOutline,
|
|
12
13
|
mdiCloudCheckVariantOutline,
|
|
@@ -29,6 +30,10 @@
|
|
|
29
30
|
const configured = $derived(status.kind !== "unconfigured");
|
|
30
31
|
|
|
31
32
|
const appearance = $derived.by(() => {
|
|
33
|
+
if (backup.needsAttention) {
|
|
34
|
+
return { color: "warning", icon: mdiAlertCircleOutline } as const;
|
|
35
|
+
}
|
|
36
|
+
|
|
32
37
|
switch (status.kind) {
|
|
33
38
|
case "loading": {
|
|
34
39
|
return { color: "secondary", icon: undefined } as const;
|
|
@@ -85,7 +90,9 @@
|
|
|
85
90
|
{/if}
|
|
86
91
|
|
|
87
92
|
<Text size="tiny" class="flex-1 leading-tight">
|
|
88
|
-
{#if
|
|
93
|
+
{#if backup.needsAttention}
|
|
94
|
+
Needs attention
|
|
95
|
+
{:else if status.kind === "loading"}
|
|
89
96
|
Checking backup status
|
|
90
97
|
{:else if status.kind === "offline"}
|
|
91
98
|
Backup service is offline
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
useConfigureImmichDatabaseDump,
|
|
4
|
+
useIgnoreImmichDatabaseDumpWarning,
|
|
5
|
+
useImmichBackupStatus,
|
|
6
|
+
} from "../../../services/immich.integration.service";
|
|
7
|
+
import { Alert, Button, HStack, Stack, Text } from "@immich/ui";
|
|
8
|
+
|
|
9
|
+
const backup = useImmichBackupStatus();
|
|
10
|
+
const configure = useConfigureImmichDatabaseDump();
|
|
11
|
+
const ignore = useIgnoreImmichDatabaseDumpWarning();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
{#if backup.needsAttention}
|
|
15
|
+
<Alert color="warning" title="Immich database backups are still enabled">
|
|
16
|
+
<Stack gap={3}>
|
|
17
|
+
<Text size="small">
|
|
18
|
+
FUTO Backups already creates the same database backups as Immich.
|
|
19
|
+
<br />
|
|
20
|
+
Most users should select "use FUTO Backups only".
|
|
21
|
+
</Text>
|
|
22
|
+
<HStack gap={2}>
|
|
23
|
+
<Button
|
|
24
|
+
size="small"
|
|
25
|
+
color="primary"
|
|
26
|
+
loading={configure.isPending}
|
|
27
|
+
onclick={() => configure.mutate({ enabled: false })}
|
|
28
|
+
>
|
|
29
|
+
Use FUTO Backups only
|
|
30
|
+
</Button>
|
|
31
|
+
<Button
|
|
32
|
+
size="small"
|
|
33
|
+
variant="ghost"
|
|
34
|
+
loading={ignore.isPending}
|
|
35
|
+
onclick={() => ignore.mutate()}
|
|
36
|
+
>
|
|
37
|
+
Ignore
|
|
38
|
+
</Button>
|
|
39
|
+
</HStack>
|
|
40
|
+
</Stack>
|
|
41
|
+
</Alert>
|
|
42
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const ImmichDatabaseDumpAlert: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type ImmichDatabaseDumpAlert = InstanceType<typeof ImmichDatabaseDumpAlert>;
|
|
18
|
+
export default ImmichDatabaseDumpAlert;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
useImmichBackupStatusEventHandler,
|
|
11
11
|
} from "../../../services/immich.integration.service";
|
|
12
12
|
import { Container, Stack } from "@immich/ui";
|
|
13
|
+
import ImmichDatabaseDumpAlert from "./ImmichDatabaseDumpAlert.svelte";
|
|
13
14
|
import ImmichManageBackupOverview from "./ImmichManageBackupOverview.svelte";
|
|
14
15
|
|
|
15
16
|
type Props = {
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
<Container size="medium" center>
|
|
36
37
|
{#if repository && schedule}
|
|
37
38
|
<Stack class="mt-4" gap={6}>
|
|
39
|
+
<ImmichDatabaseDumpAlert />
|
|
38
40
|
<ImmichManageBackupOverview {repository} {schedule} status={backup.status} />
|
|
39
41
|
<BackendsList {repository} />
|
|
40
42
|
<RepositoryRunHistory {repository} onViewAll={onViewAttempts} />
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Accordion from "../../../ui/Accordion.svelte";
|
|
3
|
+
import { useConfig, useUpdateConfig } from "../../../../services/config.service";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Field,
|
|
7
|
+
HStack,
|
|
8
|
+
LoadingSpinner,
|
|
9
|
+
Select,
|
|
10
|
+
Stack,
|
|
11
|
+
Switch,
|
|
12
|
+
Text,
|
|
13
|
+
} from "@immich/ui";
|
|
14
|
+
import { mdiSpeedometerSlow } from "@mdi/js";
|
|
15
|
+
|
|
16
|
+
const bytesPerMegabyte = 1_000_000;
|
|
17
|
+
const unlimited = "0";
|
|
18
|
+
|
|
19
|
+
const speeds = [
|
|
20
|
+
{ value: unlimited, label: "No limit" },
|
|
21
|
+
...[0.5, 1, 2, 5, 10, 20, 50, 100].map((megabytes) => ({
|
|
22
|
+
value: String(megabytes * bytesPerMegabyte),
|
|
23
|
+
label: `${megabytes} MB/s`,
|
|
24
|
+
})),
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const hours = Array.from({ length: 24 }, (_, hour) => ({
|
|
28
|
+
value: `${String(hour).padStart(2, "0")}:00`,
|
|
29
|
+
label: `${String(hour).padStart(2, "0")}:00`,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const defaultQuietHoursStart = "22:00";
|
|
33
|
+
const defaultQuietHoursEnd = "06:00";
|
|
34
|
+
|
|
35
|
+
const config = useConfig();
|
|
36
|
+
const mutation = useUpdateConfig();
|
|
37
|
+
|
|
38
|
+
let speed = $state(unlimited);
|
|
39
|
+
let quiet = $state(false);
|
|
40
|
+
let quietStart = $state(defaultQuietHoursStart);
|
|
41
|
+
let quietEnd = $state(defaultQuietHoursEnd);
|
|
42
|
+
let loaded = false;
|
|
43
|
+
|
|
44
|
+
const load = () => {
|
|
45
|
+
if (!config.data) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { bytesPerSec, quietHours } = config.data.bandwidth;
|
|
50
|
+
const [start = defaultQuietHoursStart, end = defaultQuietHoursEnd] =
|
|
51
|
+
quietHours?.split("-") ?? [];
|
|
52
|
+
|
|
53
|
+
speed = String(bytesPerSec);
|
|
54
|
+
quiet = Boolean(quietHours);
|
|
55
|
+
quietStart = start;
|
|
56
|
+
quietEnd = end;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
$effect(() => {
|
|
60
|
+
if (loaded || !config.data) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
loaded = true;
|
|
65
|
+
load();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const limited = $derived(speed !== unlimited);
|
|
69
|
+
|
|
70
|
+
const onSave = () => {
|
|
71
|
+
mutation.mutate({
|
|
72
|
+
bandwidth: {
|
|
73
|
+
bytesPerSec: Number(speed),
|
|
74
|
+
quietHours: limited && quiet ? `${quietStart}-${quietEnd}` : undefined,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<Accordion
|
|
81
|
+
title="Bandwidth"
|
|
82
|
+
subtitle="Manage how fast backups upload."
|
|
83
|
+
icon={mdiSpeedometerSlow}
|
|
84
|
+
>
|
|
85
|
+
<Stack gap={4} class="pt-2">
|
|
86
|
+
{#if config.isLoading}
|
|
87
|
+
<LoadingSpinner />
|
|
88
|
+
{:else}
|
|
89
|
+
<Field
|
|
90
|
+
label="Upload speed"
|
|
91
|
+
description="Slow down backup uploads without affecting restores."
|
|
92
|
+
color="primary"
|
|
93
|
+
>
|
|
94
|
+
<Select
|
|
95
|
+
options={speeds}
|
|
96
|
+
value={speed}
|
|
97
|
+
onChange={(value) => (speed = value)}
|
|
98
|
+
/>
|
|
99
|
+
</Field>
|
|
100
|
+
|
|
101
|
+
<Field
|
|
102
|
+
label="Full speed during quiet hours"
|
|
103
|
+
description="Lift the limit while you are asleep."
|
|
104
|
+
color="primary"
|
|
105
|
+
disabled={!limited}
|
|
106
|
+
>
|
|
107
|
+
<Switch bind:checked={quiet} />
|
|
108
|
+
</Field>
|
|
109
|
+
|
|
110
|
+
{#if limited && quiet}
|
|
111
|
+
<HStack gap={4}>
|
|
112
|
+
<Field label="From" color="primary">
|
|
113
|
+
<Select
|
|
114
|
+
options={hours}
|
|
115
|
+
value={quietStart}
|
|
116
|
+
onChange={(value) => (quietStart = value)}
|
|
117
|
+
/>
|
|
118
|
+
</Field>
|
|
119
|
+
<Field label="Until" color="primary">
|
|
120
|
+
<Select
|
|
121
|
+
options={hours}
|
|
122
|
+
value={quietEnd}
|
|
123
|
+
onChange={(value) => (quietEnd = value)}
|
|
124
|
+
/>
|
|
125
|
+
</Field>
|
|
126
|
+
</HStack>
|
|
127
|
+
|
|
128
|
+
{#if quietStart === quietEnd}
|
|
129
|
+
<Text size="small" color="muted">
|
|
130
|
+
With the same start and end time, the limit never applies.
|
|
131
|
+
</Text>
|
|
132
|
+
{/if}
|
|
133
|
+
{/if}
|
|
134
|
+
|
|
135
|
+
<HStack gap={2} class="justify-end">
|
|
136
|
+
<Button
|
|
137
|
+
shape="round"
|
|
138
|
+
color="secondary"
|
|
139
|
+
disabled={mutation.isPending}
|
|
140
|
+
onclick={load}
|
|
141
|
+
>
|
|
142
|
+
Reset
|
|
143
|
+
</Button>
|
|
144
|
+
<Button shape="round" loading={mutation.isPending} onclick={onSave}>
|
|
145
|
+
Save
|
|
146
|
+
</Button>
|
|
147
|
+
</HStack>
|
|
148
|
+
{/if}
|
|
149
|
+
</Stack>
|
|
150
|
+
</Accordion>
|
package/dist/fetch-client.d.ts
CHANGED
|
@@ -47,6 +47,16 @@ export type CreateLocalBackendRequestDto = {
|
|
|
47
47
|
export type BackendResponseDto = {
|
|
48
48
|
backend: BackendDto;
|
|
49
49
|
};
|
|
50
|
+
export type BandwidthDto = {
|
|
51
|
+
bytesPerSec: number;
|
|
52
|
+
quietHours?: string;
|
|
53
|
+
};
|
|
54
|
+
export type ConfigResponseDto = {
|
|
55
|
+
bandwidth: BandwidthDto;
|
|
56
|
+
};
|
|
57
|
+
export type ConfigUpdateRequestDto = {
|
|
58
|
+
bandwidth: BandwidthDto;
|
|
59
|
+
};
|
|
50
60
|
export type FilesystemListingItemDto = {
|
|
51
61
|
path: string;
|
|
52
62
|
isDirectory: boolean;
|
|
@@ -146,12 +156,18 @@ export type RunDto = {
|
|
|
146
156
|
status: RunStatus;
|
|
147
157
|
"type": RunType;
|
|
148
158
|
};
|
|
159
|
+
export type ImmichDatabaseDumpConfigDto = {
|
|
160
|
+
enabled: boolean;
|
|
161
|
+
keepLastAmount: number;
|
|
162
|
+
};
|
|
149
163
|
export type ImmichBackupStatusDto = {
|
|
150
164
|
integration?: ImmichIntegrationDto;
|
|
151
165
|
repository?: LocalRepositoryDto;
|
|
152
166
|
backend?: BackendDto;
|
|
153
167
|
schedule?: ScheduleDto;
|
|
154
168
|
latestBackupRun?: RunDto;
|
|
169
|
+
databaseDump?: ImmichDatabaseDumpConfigDto;
|
|
170
|
+
databaseDumpWarningIgnored?: boolean;
|
|
155
171
|
};
|
|
156
172
|
export type ConfigureImmichIntegrationRequestDto = {
|
|
157
173
|
name: string;
|
|
@@ -167,6 +183,10 @@ export type ConfigureImmichIntegrationRequestDto = {
|
|
|
167
183
|
export type ConfigureImmichIntegrationResponseDto = {
|
|
168
184
|
repositoryId: string;
|
|
169
185
|
};
|
|
186
|
+
export type ConfigureImmichDatabaseDumpRequestDto = {
|
|
187
|
+
enabled?: boolean;
|
|
188
|
+
keepLastAmount?: number;
|
|
189
|
+
};
|
|
170
190
|
export type ImmichRollbackRequestDto = {
|
|
171
191
|
repositoryId: string;
|
|
172
192
|
snapshotId: string;
|
|
@@ -313,6 +333,8 @@ export declare function createSession(createSessionRequestDto: CreateSessionRequ
|
|
|
313
333
|
export declare function createTicket(ticketCreateRequestDto: TicketCreateRequestDto, opts?: Oazapfts.RequestOpts): Promise<TicketCreateResponseDto>;
|
|
314
334
|
export declare function getBackends(opts?: Oazapfts.RequestOpts): Promise<BackendsResponseDto>;
|
|
315
335
|
export declare function createLocalBackend(createLocalBackendRequestDto: CreateLocalBackendRequestDto, opts?: Oazapfts.RequestOpts): Promise<BackendResponseDto>;
|
|
336
|
+
export declare function getConfig(opts?: Oazapfts.RequestOpts): Promise<ConfigResponseDto>;
|
|
337
|
+
export declare function updateConfig(configUpdateRequestDto: ConfigUpdateRequestDto, opts?: Oazapfts.RequestOpts): Promise<ConfigResponseDto>;
|
|
316
338
|
export declare function resetOrchestrator(opts?: Oazapfts.RequestOpts): Promise<never>;
|
|
317
339
|
export declare function getFileListing({ path }?: {
|
|
318
340
|
path?: string;
|
|
@@ -320,6 +342,8 @@ export declare function getFileListing({ path }?: {
|
|
|
320
342
|
export declare function getIntegrations(opts?: Oazapfts.RequestOpts): Promise<IntegrationsResponseDto>;
|
|
321
343
|
export declare function getImmichBackupStatus(opts?: Oazapfts.RequestOpts): Promise<ImmichBackupStatusDto>;
|
|
322
344
|
export declare function configureImmichIntegration(configureImmichIntegrationRequestDto: ConfigureImmichIntegrationRequestDto, opts?: Oazapfts.RequestOpts): Promise<ConfigureImmichIntegrationResponseDto>;
|
|
345
|
+
export declare function ignoreImmichDatabaseDumpWarning(opts?: Oazapfts.RequestOpts): Promise<never>;
|
|
346
|
+
export declare function configureImmichDatabaseDump(configureImmichDatabaseDumpRequestDto: ConfigureImmichDatabaseDumpRequestDto, opts?: Oazapfts.RequestOpts): Promise<never>;
|
|
323
347
|
export declare function startImmichRollback(immichRollbackRequestDto: ImmichRollbackRequestDto, opts?: Oazapfts.RequestOpts): Promise<never>;
|
|
324
348
|
export declare function onboardingStatus(opts?: Oazapfts.RequestOpts): Promise<OnboardingStatusResponseDto>;
|
|
325
349
|
export declare function currentRecoveryKey(opts?: Oazapfts.RequestOpts): Promise<CurrentRecoveryKeyResponse>;
|
package/dist/fetch-client.js
CHANGED
|
@@ -48,6 +48,18 @@ export function createLocalBackend(createLocalBackendRequestDto, opts) {
|
|
|
48
48
|
body: createLocalBackendRequestDto
|
|
49
49
|
})));
|
|
50
50
|
}
|
|
51
|
+
export function getConfig(opts) {
|
|
52
|
+
return oazapfts.ok(oazapfts.fetchJson("/api/yucca/config", {
|
|
53
|
+
...opts
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
export function updateConfig(configUpdateRequestDto, opts) {
|
|
57
|
+
return oazapfts.ok(oazapfts.fetchJson("/api/yucca/config", oazapfts.json({
|
|
58
|
+
...opts,
|
|
59
|
+
method: "PUT",
|
|
60
|
+
body: configUpdateRequestDto
|
|
61
|
+
})));
|
|
62
|
+
}
|
|
51
63
|
export function resetOrchestrator(opts) {
|
|
52
64
|
return oazapfts.ok(oazapfts.fetchText("/api/yucca/debug/reset", {
|
|
53
65
|
...opts,
|
|
@@ -78,6 +90,19 @@ export function configureImmichIntegration(configureImmichIntegrationRequestDto,
|
|
|
78
90
|
body: configureImmichIntegrationRequestDto
|
|
79
91
|
})));
|
|
80
92
|
}
|
|
93
|
+
export function ignoreImmichDatabaseDumpWarning(opts) {
|
|
94
|
+
return oazapfts.ok(oazapfts.fetchText("/api/yucca/integrations/immich/database-dump/ignore-warning", {
|
|
95
|
+
...opts,
|
|
96
|
+
method: "POST"
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
export function configureImmichDatabaseDump(configureImmichDatabaseDumpRequestDto, opts) {
|
|
100
|
+
return oazapfts.ok(oazapfts.fetchText("/api/yucca/integrations/immich/database-dump", oazapfts.json({
|
|
101
|
+
...opts,
|
|
102
|
+
method: "POST",
|
|
103
|
+
body: configureImmichDatabaseDumpRequestDto
|
|
104
|
+
})));
|
|
105
|
+
}
|
|
81
106
|
export function startImmichRollback(immichRollbackRequestDto, opts) {
|
|
82
107
|
return oazapfts.ok(oazapfts.fetchText("/api/yucca/integrations/immich/rollback", oazapfts.json({
|
|
83
108
|
...opts,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ConfigUpdateRequestDto } from '../fetch-client';
|
|
2
|
+
export declare const configKeys: {
|
|
3
|
+
all: readonly ["config"];
|
|
4
|
+
};
|
|
5
|
+
export declare const useConfig: () => import("@tanstack/svelte-query").CreateQueryResult<import("../fetch-client").ConfigResponseDto, Error>;
|
|
6
|
+
export declare const useUpdateConfig: () => import("@tanstack/svelte-query").CreateMutationResult<import("../fetch-client").ConfigResponseDto, Error, ConfigUpdateRequestDto, unknown>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getConfig, updateConfig, } from '../fetch-client';
|
|
2
|
+
import { queryClient } from '../query-client';
|
|
3
|
+
import { handleError } from '../utils/handle-error';
|
|
4
|
+
import { createMutation, createQuery } from '@tanstack/svelte-query';
|
|
5
|
+
export const configKeys = {
|
|
6
|
+
all: ['config'],
|
|
7
|
+
};
|
|
8
|
+
export const useConfig = () => createQuery(() => ({
|
|
9
|
+
queryKey: configKeys.all,
|
|
10
|
+
queryFn: () => getConfig(),
|
|
11
|
+
}), () => queryClient);
|
|
12
|
+
export const useUpdateConfig = () => createMutation(() => ({
|
|
13
|
+
mutationFn: (dto) => updateConfig(dto),
|
|
14
|
+
onSuccess: (config) => queryClient.setQueryData(configKeys.all, config),
|
|
15
|
+
onError: (error) => handleError(error, 'Failed to save settings'),
|
|
16
|
+
}), () => queryClient);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ActionItem } from '@immich/ui';
|
|
2
|
+
import { type ConfigureImmichDatabaseDumpRequestDto } from '../fetch-client';
|
|
2
3
|
export declare const getBackupPageActions: (repositoryId: string | undefined, onConfigure: () => void) => {
|
|
3
4
|
Configure: ActionItem;
|
|
4
5
|
ViewRecoveryKey: ActionItem;
|
|
@@ -25,4 +26,7 @@ export declare const useImmichBackupStatus: () => {
|
|
|
25
26
|
readonly repository: import("../fetch-client").LocalRepositoryDto | undefined;
|
|
26
27
|
readonly schedule: import("../fetch-client").ScheduleDto | undefined;
|
|
27
28
|
readonly status: ImmichBackupStatus;
|
|
29
|
+
readonly needsAttention: boolean;
|
|
28
30
|
};
|
|
31
|
+
export declare const useConfigureImmichDatabaseDump: () => import("@tanstack/svelte-query").CreateMutationResult<never, Error, ConfigureImmichDatabaseDumpRequestDto, unknown>;
|
|
32
|
+
export declare const useIgnoreImmichDatabaseDumpWarning: () => import("@tanstack/svelte-query").CreateMutationResult<never, Error, void, unknown>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import BackupsRecoveryKeyModal from '../components/onboarding/dialogs/BackupsRecoveryKeyModal.svelte';
|
|
2
2
|
import { modalManager } from '@immich/ui';
|
|
3
3
|
import { mdiCloudUploadOutline, mdiCogOutline, mdiKeyOutline } from '@mdi/js';
|
|
4
|
-
import { getImmichBackupStatus, } from '../fetch-client';
|
|
4
|
+
import { configureImmichDatabaseDump, getImmichBackupStatus, ignoreImmichDatabaseDumpWarning, } from '../fetch-client';
|
|
5
5
|
import { queryClient } from '../query-client';
|
|
6
|
+
import { handleError } from '../utils/handle-error';
|
|
6
7
|
import { getBackupOutcome } from '../utils/backup-status';
|
|
7
|
-
import { createQuery } from '@tanstack/svelte-query';
|
|
8
|
+
import { createMutation, createQuery } from '@tanstack/svelte-query';
|
|
8
9
|
import { handleCreateBackup } from './repository.service';
|
|
9
10
|
export const getBackupPageActions = (repositoryId, onConfigure) => {
|
|
10
11
|
const Configure = {
|
|
@@ -31,6 +32,7 @@ export const immichBackupStatusKeys = {
|
|
|
31
32
|
const invalidateImmichBackupStatus = () => void queryClient.invalidateQueries({
|
|
32
33
|
queryKey: immichBackupStatusKeys.all,
|
|
33
34
|
});
|
|
35
|
+
const updateImmichBackupStatus = (update) => queryClient.setQueryData(immichBackupStatusKeys.all, (data) => data && update(data));
|
|
34
36
|
export const useImmichBackupStatusEventHandler = () => ({
|
|
35
37
|
onIntegrationUpdate: invalidateImmichBackupStatus,
|
|
36
38
|
onRepositoryUpdate: invalidateImmichBackupStatus,
|
|
@@ -77,5 +79,28 @@ export const useImmichBackupStatus = () => {
|
|
|
77
79
|
get status() {
|
|
78
80
|
return toImmichBackupStatus(query.data, query.isLoading);
|
|
79
81
|
},
|
|
82
|
+
get needsAttention() {
|
|
83
|
+
const usingImmichDbDump = query.data?.databaseDump?.enabled === true &&
|
|
84
|
+
query.data.schedule !== undefined &&
|
|
85
|
+
!query.data.schedule.paused &&
|
|
86
|
+
query.data.databaseDumpWarningIgnored !== true;
|
|
87
|
+
return usingImmichDbDump;
|
|
88
|
+
},
|
|
80
89
|
};
|
|
81
90
|
};
|
|
91
|
+
export const useConfigureImmichDatabaseDump = () => createMutation(() => ({
|
|
92
|
+
mutationFn: (dto) => configureImmichDatabaseDump(dto),
|
|
93
|
+
onSuccess: (_, dto) => updateImmichBackupStatus((data) => ({
|
|
94
|
+
...data,
|
|
95
|
+
databaseDump: data.databaseDump && { ...data.databaseDump, ...dto },
|
|
96
|
+
})),
|
|
97
|
+
onError: (error) => handleError(error, 'Failed to update Immich database dump settings'),
|
|
98
|
+
}), () => queryClient);
|
|
99
|
+
export const useIgnoreImmichDatabaseDumpWarning = () => createMutation(() => ({
|
|
100
|
+
mutationFn: () => ignoreImmichDatabaseDumpWarning(),
|
|
101
|
+
onSuccess: () => updateImmichBackupStatus((data) => ({
|
|
102
|
+
...data,
|
|
103
|
+
databaseDumpWarningIgnored: true,
|
|
104
|
+
})),
|
|
105
|
+
onError: (error) => handleError(error, 'Failed to ignore Immich database dump warning'),
|
|
106
|
+
}), () => queryClient);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@futo-org/backups-orchestrator-ui",
|
|
3
3
|
"repository": "https://github.com/immich-app/yucca",
|
|
4
4
|
"description": "Backups orchestrator (UI library)",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.46.0",
|
|
6
6
|
"license": "Source First License 1.1",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"lodash.debounce": "^4.0.8",
|
|
65
65
|
"luxon": "^3.7.2",
|
|
66
66
|
"socket.io-client": "^4.8.3",
|
|
67
|
-
"@futo-org/backups-api-client": "^0.
|
|
67
|
+
"@futo-org/backups-api-client": "^0.46.0"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"dev": "vite dev --port 5174",
|