@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.
- 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
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
} from "../../../services/backend.service";
|
|
14
14
|
import {
|
|
15
15
|
IMMICH_DEFAULT_CRON,
|
|
16
|
-
|
|
16
|
+
useConfigureAndStartImmichIntegration,
|
|
17
17
|
} from "../../../services/integrations.service";
|
|
18
18
|
import {
|
|
19
19
|
handleConfirmRecoveryKey,
|
|
20
20
|
handleCurrentRecoveryKey,
|
|
21
21
|
handleOnboardingStatus,
|
|
22
22
|
} from "../../../services/onboarding.service";
|
|
23
|
+
import { handleCreateBackup } from "../../../services/repository.service";
|
|
23
24
|
import { LoadingSpinner, Modal, ModalBody } from "@immich/ui";
|
|
24
25
|
import cronstrue from "cronstrue";
|
|
25
26
|
import { onMount, type Snippet } from "svelte";
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
let resume: Stage = $state("intro");
|
|
49
50
|
let confirming = $state(false);
|
|
50
51
|
|
|
51
|
-
const defaults =
|
|
52
|
+
const defaults = useConfigureAndStartImmichIntegration();
|
|
52
53
|
|
|
53
54
|
const schedule = cronstrue.toString(IMMICH_DEFAULT_CRON, { verbose: true });
|
|
54
55
|
|
|
@@ -116,7 +117,11 @@
|
|
|
116
117
|
};
|
|
117
118
|
|
|
118
119
|
const onStartBackup = () =>
|
|
119
|
-
defaults.mutate(undefined, { onSuccess: () =>
|
|
120
|
+
defaults.mutate(undefined, { onSuccess: ({ repositoryId }) => {
|
|
121
|
+
stage = "finished";
|
|
122
|
+
handleCreateBackup(repositoryId).catch(() => void 0);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
120
125
|
</script>
|
|
121
126
|
|
|
122
127
|
{#if status === undefined || status.status === "not-ready"}
|
|
@@ -104,11 +104,11 @@
|
|
|
104
104
|
Print
|
|
105
105
|
</Button>
|
|
106
106
|
</HStack>
|
|
107
|
-
|
|
108
|
-
{#if /* intentionally hide this to not overcrowd the modal */ PasswordCredential && false}
|
|
107
|
+
{#if PasswordCredential}
|
|
109
108
|
<Button
|
|
110
109
|
leadingIcon={mdiAsterisk}
|
|
111
|
-
variant="
|
|
110
|
+
variant="ghost"
|
|
111
|
+
shape="round"
|
|
112
112
|
onclick={storeCredentials}
|
|
113
113
|
>
|
|
114
114
|
Save to password manager
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { orchestrationApiProvider, setProvider } from "../../providers";
|
|
3
2
|
import {
|
|
4
3
|
AppShell,
|
|
5
4
|
AppShellHeader,
|
|
@@ -72,9 +71,6 @@
|
|
|
72
71
|
|
|
73
72
|
demoPadding.set(true);
|
|
74
73
|
onDestroy(() => demoPadding.set(false));
|
|
75
|
-
|
|
76
|
-
// svelte-ignore state_referenced_locally
|
|
77
|
-
setProvider(orchestrationApiProvider);
|
|
78
74
|
</script>
|
|
79
75
|
|
|
80
76
|
{#snippet hideReminder()}
|
|
@@ -237,7 +233,11 @@
|
|
|
237
233
|
icon={{ icon: mdiImageAlbum, flipped: true }}
|
|
238
234
|
/>
|
|
239
235
|
<NavbarItem href="#" title="Utilities" icon={mdiToolboxOutline} />
|
|
240
|
-
<NavbarItem
|
|
236
|
+
<NavbarItem
|
|
237
|
+
href="#"
|
|
238
|
+
title="Archive"
|
|
239
|
+
icon={mdiArchiveArrowDownOutline}
|
|
240
|
+
/>
|
|
241
241
|
<NavbarItem href="#" title="Locked folder" icon={mdiLockOutline} />
|
|
242
242
|
<NavbarItem href="#" title="Trash" icon={mdiTrashCanOutline} />
|
|
243
243
|
{/if}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
MockProvider,
|
|
4
|
-
orchestrationApiProvider,
|
|
5
|
-
setProvider,
|
|
6
|
-
} from "../../providers";
|
|
7
2
|
import {
|
|
8
3
|
AppShell,
|
|
9
4
|
AppShellHeader,
|
|
10
5
|
AppShellSidebar,
|
|
11
6
|
Heading,
|
|
12
7
|
NavbarItem,
|
|
13
|
-
Text,
|
|
14
8
|
ThemeSwitcher,
|
|
15
9
|
} from "@immich/ui";
|
|
16
10
|
import {
|
|
@@ -24,15 +18,6 @@
|
|
|
24
18
|
import Dashboard from "../dashboard/Dashboard.svelte";
|
|
25
19
|
import ScheduleList from "../schedules/ScheduleList.svelte";
|
|
26
20
|
|
|
27
|
-
const { mock }: { mock: boolean } = $props();
|
|
28
|
-
|
|
29
|
-
// svelte-ignore state_referenced_locally
|
|
30
|
-
if (mock) {
|
|
31
|
-
setProvider(new MockProvider());
|
|
32
|
-
} else {
|
|
33
|
-
setProvider(orchestrationApiProvider);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
21
|
let open = $state(true);
|
|
37
22
|
let route = $state("dashboard");
|
|
38
23
|
</script>
|
|
@@ -41,15 +26,11 @@
|
|
|
41
26
|
<AppShellHeader>
|
|
42
27
|
<div class="flex items-center justify-between w-full px-4 py-2">
|
|
43
28
|
<Heading>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
src="/app-name-here.png"
|
|
50
|
-
class="inline h-12"
|
|
51
|
-
/>
|
|
52
|
-
{/if}
|
|
29
|
+
<img
|
|
30
|
+
alt="App Name Here"
|
|
31
|
+
src="/app-name-here.png"
|
|
32
|
+
class="inline h-12"
|
|
33
|
+
/>
|
|
53
34
|
</Heading>
|
|
54
35
|
<ThemeSwitcher size="medium" color="secondary" />
|
|
55
36
|
</div>
|
|
@@ -118,17 +99,13 @@
|
|
|
118
99
|
|
|
119
100
|
<div class="p-4 flex flex-col gap-2 max-w-6xl m-auto">
|
|
120
101
|
{#if route === "dashboard"}
|
|
121
|
-
<Dashboard
|
|
102
|
+
<Dashboard onViewBackups={() => (route = "backups")} />
|
|
122
103
|
{:else if route === "backups"}
|
|
123
|
-
<BackupsList
|
|
104
|
+
<BackupsList />
|
|
124
105
|
{:else if route === "config"}
|
|
125
|
-
|
|
126
|
-
<GlobalSettings />
|
|
127
|
-
{/if}
|
|
106
|
+
<GlobalSettings />
|
|
128
107
|
{:else if route === "schedules"}
|
|
129
|
-
|
|
130
|
-
<ScheduleList />
|
|
131
|
-
{/if}
|
|
108
|
+
<ScheduleList />
|
|
132
109
|
{/if}
|
|
133
110
|
</div>
|
|
134
111
|
</AppShell>
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
mock: boolean;
|
|
3
|
-
};
|
|
4
|
-
declare const TestUi: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
1
|
+
declare const TestUi: import("svelte").Component<Record<string, never>, {}, "">;
|
|
5
2
|
type TestUi = ReturnType<typeof TestUi>;
|
|
6
3
|
export default TestUi;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { options } from "../../../options";
|
|
3
2
|
import { getReadableErrorMessage } from "../../../utils/handle-error";
|
|
4
3
|
import {
|
|
5
4
|
Alert,
|
|
@@ -27,8 +26,6 @@
|
|
|
27
26
|
onNavigate?: (route: string) => void;
|
|
28
27
|
};
|
|
29
28
|
|
|
30
|
-
const { advanced } = options;
|
|
31
|
-
|
|
32
29
|
const { onNavigate }: Props = $props();
|
|
33
30
|
|
|
34
31
|
const query = useRepositories();
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
{@const seed = seedOf(groupIndex, index)}
|
|
26
26
|
<div
|
|
27
27
|
class="h-36 grow rounded-sm"
|
|
28
|
-
style="background-color:
|
|
28
|
+
style="background-color: color-mix(in oklch, var(--immich-ui-light) {grey(seed)}%, var(--immich-ui-dark)); flex-basis: {aspect(
|
|
29
29
|
seed,
|
|
30
30
|
) * 9}rem"
|
|
31
31
|
></div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { events, SocketEvent, useSocket } from "../../events";
|
|
3
|
+
import { getProvider } from "../../providers";
|
|
3
4
|
import { onDestroy, onMount } from "svelte";
|
|
4
5
|
|
|
5
6
|
type Props = {
|
|
@@ -7,7 +8,8 @@
|
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
const props: Props = $props();
|
|
10
|
-
const disconnect =
|
|
11
|
+
const disconnect =
|
|
12
|
+
getProvider().api === "orchestrator" ? useSocket() : () => {};
|
|
11
13
|
|
|
12
14
|
onMount(() => {
|
|
13
15
|
for (const key of Object.keys(props)) {
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
const props: Props = $props();
|
|
10
10
|
|
|
11
|
-
const format = () =>
|
|
11
|
+
const format = () => {
|
|
12
|
+
const time = DateTime.fromISO(props.time);
|
|
13
|
+
return DateTime.now().diff(time).as('minute') < 1 ? "a moment ago" : time.toRelative();
|
|
14
|
+
};
|
|
12
15
|
|
|
13
16
|
let text = $state(format());
|
|
14
17
|
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { TooltipProvider } from "@immich/ui";
|
|
3
3
|
import { QueryClientProvider } from "@tanstack/svelte-query";
|
|
4
|
-
import { defaults as orchestrationDefaults } from "../../fetch-client";
|
|
5
4
|
import type { Snippet } from "svelte";
|
|
6
5
|
|
|
7
6
|
type Props = {
|
|
8
7
|
children: Snippet;
|
|
9
|
-
baseUrl?: string;
|
|
10
8
|
};
|
|
11
9
|
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
// svelte-ignore state_referenced_locally
|
|
15
|
-
if (typeof baseUrl === "string") {
|
|
16
|
-
orchestrationDefaults.baseUrl = baseUrl;
|
|
17
|
-
}
|
|
10
|
+
const { children }: Props = $props();
|
|
18
11
|
|
|
19
12
|
import { queryClient } from "../../query-client";
|
|
20
13
|
</script>
|
package/dist/events.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { io, Socket } from 'socket.io-client';
|
|
2
|
-
import {
|
|
2
|
+
import { getProvider } from './providers';
|
|
3
3
|
let socket;
|
|
4
4
|
export const events = new EventTarget();
|
|
5
5
|
export class SocketEvent extends Event {
|
|
@@ -10,7 +10,7 @@ export class SocketEvent extends Event {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
function createSocket() {
|
|
13
|
-
socket = io(
|
|
13
|
+
socket = io(getProvider().baseUrl || undefined, {
|
|
14
14
|
path: '/api/yucca/socket.io',
|
|
15
15
|
transports: ['websocket'],
|
|
16
16
|
autoConnect: false,
|
package/dist/fetch-client.d.ts
CHANGED
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as Oazapfts from "@oazapfts/runtime";
|
|
8
8
|
export declare const defaults: Oazapfts.Defaults<Oazapfts.CustomHeaders>;
|
|
9
|
-
export declare const servers: {
|
|
10
|
-
server1: string;
|
|
11
|
-
};
|
|
9
|
+
export declare const servers: {};
|
|
12
10
|
export type DeviceFlowEventType = "START" | "SUCCESS" | "FAILURE";
|
|
13
11
|
export type DeviceFlowFailureReason = "NOT_CONNECTED" | "DEVICE_FLOW_FAILED" | "WRONG_ACCOUNT" | "UNKNOWN";
|
|
14
12
|
export type DeviceFlowEventDto = {
|
|
@@ -83,6 +81,27 @@ export type IntegrationsResponseDto = {
|
|
|
83
81
|
immichState?: ImmichStateDto;
|
|
84
82
|
immichIntegration?: ImmichIntegrationDto;
|
|
85
83
|
};
|
|
84
|
+
export type TaskStatus = "incomplete" | "complete" | "warn" | "failed";
|
|
85
|
+
export type RepositoryMetricsDto = {
|
|
86
|
+
lastBackup?: string | null;
|
|
87
|
+
lastBackupStatus?: TaskStatus;
|
|
88
|
+
lastBackupDuration?: number;
|
|
89
|
+
sizeBytes: number;
|
|
90
|
+
};
|
|
91
|
+
export type RepositoryMeterDto = {
|
|
92
|
+
sizeBytes: number;
|
|
93
|
+
objectCount: number;
|
|
94
|
+
lastUpdated?: string | null;
|
|
95
|
+
};
|
|
96
|
+
export type RepositoryBackendDto = {
|
|
97
|
+
id: string;
|
|
98
|
+
"type": BackendType;
|
|
99
|
+
online: boolean;
|
|
100
|
+
};
|
|
101
|
+
export type RepositoryBackendsDto = {
|
|
102
|
+
primary: RepositoryBackendDto;
|
|
103
|
+
secondary: RepositoryBackendDto[];
|
|
104
|
+
};
|
|
86
105
|
export type RetentionPolicyDto = {
|
|
87
106
|
keepLast?: number;
|
|
88
107
|
keepWithin?: string;
|
|
@@ -92,6 +111,48 @@ export type RetentionPolicyDto = {
|
|
|
92
111
|
keepWithinMonthly?: string;
|
|
93
112
|
keepWithinYearly?: string;
|
|
94
113
|
};
|
|
114
|
+
export type RepositoryConfigurationDto = {
|
|
115
|
+
paths: string[];
|
|
116
|
+
retentionPolicy?: (RetentionPolicyDto) | null;
|
|
117
|
+
};
|
|
118
|
+
export type LocalRepositoryDto = {
|
|
119
|
+
id: string;
|
|
120
|
+
worm: boolean;
|
|
121
|
+
name: string;
|
|
122
|
+
siteCode: string | null;
|
|
123
|
+
storageClusterCode: string | null;
|
|
124
|
+
metrics: RepositoryMetricsDto;
|
|
125
|
+
meter?: RepositoryMeterDto;
|
|
126
|
+
backends?: RepositoryBackendsDto;
|
|
127
|
+
configuration?: RepositoryConfigurationDto;
|
|
128
|
+
};
|
|
129
|
+
export type ScheduleDto = {
|
|
130
|
+
id: string;
|
|
131
|
+
name: string;
|
|
132
|
+
paused: boolean;
|
|
133
|
+
cron: string;
|
|
134
|
+
repositories: string[];
|
|
135
|
+
lastRun?: string;
|
|
136
|
+
lastFinished?: string;
|
|
137
|
+
};
|
|
138
|
+
export type RunStatus = "incomplete" | "complete" | "warn" | "failed";
|
|
139
|
+
export type RunType = "schedule" | "restore" | "backup" | "forget";
|
|
140
|
+
export type RunDto = {
|
|
141
|
+
id: string;
|
|
142
|
+
repositoryId: string;
|
|
143
|
+
start: string;
|
|
144
|
+
end?: string;
|
|
145
|
+
logFilePath: string;
|
|
146
|
+
status: RunStatus;
|
|
147
|
+
"type": RunType;
|
|
148
|
+
};
|
|
149
|
+
export type ImmichBackupStatusDto = {
|
|
150
|
+
integration?: ImmichIntegrationDto;
|
|
151
|
+
repository?: LocalRepositoryDto;
|
|
152
|
+
backend?: BackendDto;
|
|
153
|
+
schedule?: ScheduleDto;
|
|
154
|
+
latestBackupRun?: RunDto;
|
|
155
|
+
};
|
|
95
156
|
export type ConfigureImmichIntegrationRequestDto = {
|
|
96
157
|
name: string;
|
|
97
158
|
worm: boolean;
|
|
@@ -102,6 +163,9 @@ export type ConfigureImmichIntegrationRequestDto = {
|
|
|
102
163
|
retentionPolicy?: (RetentionPolicyDto) | null;
|
|
103
164
|
paused?: boolean;
|
|
104
165
|
};
|
|
166
|
+
export type ConfigureImmichIntegrationResponseDto = {
|
|
167
|
+
repositoryId: string;
|
|
168
|
+
};
|
|
105
169
|
export type ImmichRollbackRequestDto = {
|
|
106
170
|
repositoryId: string;
|
|
107
171
|
snapshotId: string;
|
|
@@ -134,42 +198,6 @@ export type RepositoryCreateRequestDto = {
|
|
|
134
198
|
site?: string;
|
|
135
199
|
paths?: string[];
|
|
136
200
|
};
|
|
137
|
-
export type TaskStatus = "incomplete" | "complete" | "warn" | "failed";
|
|
138
|
-
export type RepositoryMetricsDto = {
|
|
139
|
-
lastBackup?: string | null;
|
|
140
|
-
lastBackupStatus?: TaskStatus;
|
|
141
|
-
lastBackupDuration?: number;
|
|
142
|
-
sizeBytes: number;
|
|
143
|
-
};
|
|
144
|
-
export type RepositoryMeterDto = {
|
|
145
|
-
sizeBytes: number;
|
|
146
|
-
objectCount: number;
|
|
147
|
-
lastUpdated?: string | null;
|
|
148
|
-
};
|
|
149
|
-
export type RepositoryBackendDto = {
|
|
150
|
-
id: string;
|
|
151
|
-
"type": BackendType;
|
|
152
|
-
online: boolean;
|
|
153
|
-
};
|
|
154
|
-
export type RepositoryBackendsDto = {
|
|
155
|
-
primary: RepositoryBackendDto;
|
|
156
|
-
secondary: RepositoryBackendDto[];
|
|
157
|
-
};
|
|
158
|
-
export type RepositoryConfigurationDto = {
|
|
159
|
-
paths: string[];
|
|
160
|
-
retentionPolicy?: (RetentionPolicyDto) | null;
|
|
161
|
-
};
|
|
162
|
-
export type LocalRepositoryDto = {
|
|
163
|
-
id: string;
|
|
164
|
-
worm: boolean;
|
|
165
|
-
name: string;
|
|
166
|
-
siteCode: string | null;
|
|
167
|
-
storageClusterCode: string | null;
|
|
168
|
-
metrics: RepositoryMetricsDto;
|
|
169
|
-
meter?: RepositoryMeterDto;
|
|
170
|
-
backends?: RepositoryBackendsDto;
|
|
171
|
-
configuration?: RepositoryConfigurationDto;
|
|
172
|
-
};
|
|
173
201
|
export type RepositoryCreateResponseDto = {
|
|
174
202
|
repository: LocalRepositoryDto;
|
|
175
203
|
};
|
|
@@ -224,17 +252,6 @@ export type RepositoryCheckImportResponseDto = {
|
|
|
224
252
|
export type RepositoryPrimaryBackendReconfigureRequestDto = {
|
|
225
253
|
backendId: string;
|
|
226
254
|
};
|
|
227
|
-
export type RunStatus = "incomplete" | "complete" | "warn" | "failed";
|
|
228
|
-
export type RunType = "schedule" | "restore" | "backup" | "forget";
|
|
229
|
-
export type RunDto = {
|
|
230
|
-
id: string;
|
|
231
|
-
repositoryId: string;
|
|
232
|
-
start: string;
|
|
233
|
-
end?: string;
|
|
234
|
-
logFilePath: string;
|
|
235
|
-
status: RunStatus;
|
|
236
|
-
"type": RunType;
|
|
237
|
-
};
|
|
238
255
|
export type RunHistoryResponseDto = {
|
|
239
256
|
runs: RunDto[];
|
|
240
257
|
};
|
|
@@ -271,15 +288,6 @@ export type ScheduleCreateRequestDto = {
|
|
|
271
288
|
cron: string;
|
|
272
289
|
repositories: string[];
|
|
273
290
|
};
|
|
274
|
-
export type ScheduleDto = {
|
|
275
|
-
id: string;
|
|
276
|
-
name: string;
|
|
277
|
-
paused: boolean;
|
|
278
|
-
cron: string;
|
|
279
|
-
repositories: string[];
|
|
280
|
-
lastRun?: string;
|
|
281
|
-
lastFinished?: string;
|
|
282
|
-
};
|
|
283
291
|
export type ScheduleCreateResponseDto = {
|
|
284
292
|
schedule: ScheduleDto;
|
|
285
293
|
};
|
|
@@ -306,7 +314,8 @@ export declare function getFileListing({ path }?: {
|
|
|
306
314
|
path?: string;
|
|
307
315
|
}, opts?: Oazapfts.RequestOpts): Promise<FilesystemListingResponseDto>;
|
|
308
316
|
export declare function getIntegrations(opts?: Oazapfts.RequestOpts): Promise<IntegrationsResponseDto>;
|
|
309
|
-
export declare function
|
|
317
|
+
export declare function getImmichBackupStatus(opts?: Oazapfts.RequestOpts): Promise<ImmichBackupStatusDto>;
|
|
318
|
+
export declare function configureImmichIntegration(configureImmichIntegrationRequestDto: ConfigureImmichIntegrationRequestDto, opts?: Oazapfts.RequestOpts): Promise<ConfigureImmichIntegrationResponseDto>;
|
|
310
319
|
export declare function startImmichRollback(immichRollbackRequestDto: ImmichRollbackRequestDto, opts?: Oazapfts.RequestOpts): Promise<never>;
|
|
311
320
|
export declare function onboardingStatus(opts?: Oazapfts.RequestOpts): Promise<OnboardingStatusResponseDto>;
|
|
312
321
|
export declare function currentRecoveryKey(opts?: Oazapfts.RequestOpts): Promise<CurrentRecoveryKeyResponse>;
|
package/dist/fetch-client.js
CHANGED
|
@@ -8,12 +8,10 @@ import * as Oazapfts from "@oazapfts/runtime";
|
|
|
8
8
|
import * as QS from "@oazapfts/runtime/query";
|
|
9
9
|
export const defaults = {
|
|
10
10
|
headers: {},
|
|
11
|
-
baseUrl: "
|
|
11
|
+
baseUrl: "/"
|
|
12
12
|
};
|
|
13
13
|
const oazapfts = Oazapfts.runtime(defaults);
|
|
14
|
-
export const servers = {
|
|
15
|
-
server1: "http://localhost:22676"
|
|
16
|
-
};
|
|
14
|
+
export const servers = {};
|
|
17
15
|
export function connectDeviceFlow(opts) {
|
|
18
16
|
return oazapfts.ok(oazapfts.fetchJson("/api/yucca/auth/oidc/device", {
|
|
19
17
|
...opts
|
|
@@ -68,8 +66,13 @@ export function getIntegrations(opts) {
|
|
|
68
66
|
...opts
|
|
69
67
|
}));
|
|
70
68
|
}
|
|
69
|
+
export function getImmichBackupStatus(opts) {
|
|
70
|
+
return oazapfts.ok(oazapfts.fetchJson("/api/yucca/integrations/immich/status", {
|
|
71
|
+
...opts
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
71
74
|
export function configureImmichIntegration(configureImmichIntegrationRequestDto, opts) {
|
|
72
|
-
return oazapfts.ok(oazapfts.
|
|
75
|
+
return oazapfts.ok(oazapfts.fetchJson("/api/yucca/integrations/immich", oazapfts.json({
|
|
73
76
|
...opts,
|
|
74
77
|
method: "POST",
|
|
75
78
|
body: configureImmichIntegrationRequestDto
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import * as orchestrationApiClient from './fetch-client';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
export type YuccaApi = 'orchestrator' | 'customer';
|
|
3
|
+
type GetRepositories = () => Promise<orchestrationApiClient.RepositoryListResponseDto>;
|
|
4
|
+
export type YuccaProvider = {
|
|
5
|
+
api: YuccaApi;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
getRepositories: GetRepositories;
|
|
8
|
+
};
|
|
9
|
+
export type YuccaOptions = {
|
|
10
|
+
api: YuccaApi;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const configureYucca: ({ api, baseUrl, }: YuccaOptions) => YuccaProvider;
|
|
14
|
+
export declare const getProvider: () => YuccaProvider;
|
|
15
|
+
export {};
|
package/dist/providers.js
CHANGED
|
@@ -1,37 +1,27 @@
|
|
|
1
1
|
import * as yuccaApiClient from '@futo-org/backups-api-client';
|
|
2
2
|
import * as orchestrationApiClient from './fetch-client';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export const orchestrationApiProvider = orchestrationApiClient;
|
|
8
|
-
export class MockProvider extends BaseProvider {
|
|
9
|
-
async getRepositories() {
|
|
10
|
-
return {
|
|
11
|
-
repositories: [
|
|
12
|
-
{
|
|
13
|
-
id: 'repo1',
|
|
14
|
-
name: 'My Repository',
|
|
15
|
-
worm: false,
|
|
16
|
-
siteCode: 'local',
|
|
17
|
-
storageClusterCode: 'local-dev',
|
|
18
|
-
metrics: {
|
|
19
|
-
sizeBytes: 1337,
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
/* eslint-enable @typescript-eslint/require-await */
|
|
3
|
+
const clients = {
|
|
4
|
+
orchestrator: orchestrationApiClient,
|
|
5
|
+
customer: yuccaApiClient,
|
|
6
|
+
};
|
|
27
7
|
const KEY = '__yucca_provider__';
|
|
28
|
-
export const
|
|
8
|
+
export const configureYucca = ({ api, baseUrl, }) => {
|
|
9
|
+
const client = clients[api];
|
|
10
|
+
if (baseUrl !== undefined) {
|
|
11
|
+
client.defaults.baseUrl = baseUrl;
|
|
12
|
+
}
|
|
13
|
+
const provider = {
|
|
14
|
+
api,
|
|
15
|
+
baseUrl: client.defaults.baseUrl.replace(/\/$/, ''),
|
|
16
|
+
getRepositories: client.getRepositories,
|
|
17
|
+
};
|
|
29
18
|
globalThis[KEY] = provider;
|
|
19
|
+
return provider;
|
|
30
20
|
};
|
|
31
21
|
export const getProvider = () => {
|
|
32
22
|
const provider = globalThis[KEY];
|
|
33
23
|
if (!provider) {
|
|
34
|
-
throw new Error('
|
|
24
|
+
throw new Error('Yucca is not configured: call configureYucca() before rendering any component');
|
|
35
25
|
}
|
|
36
26
|
return provider;
|
|
37
27
|
};
|
|
@@ -4,3 +4,25 @@ export declare const getBackupPageActions: (repositoryId: string | undefined, on
|
|
|
4
4
|
ViewRecoveryKey: ActionItem;
|
|
5
5
|
BackUpNow: ActionItem;
|
|
6
6
|
};
|
|
7
|
+
export declare const immichBackupStatusKeys: {
|
|
8
|
+
all: readonly ["immichBackupStatus"];
|
|
9
|
+
};
|
|
10
|
+
export declare const useImmichBackupStatusEventHandler: () => {
|
|
11
|
+
onIntegrationUpdate: () => undefined;
|
|
12
|
+
onRepositoryUpdate: () => undefined;
|
|
13
|
+
onRepositoryDelete: () => undefined;
|
|
14
|
+
onScheduleUpdate: () => undefined;
|
|
15
|
+
onRunCreate: () => undefined;
|
|
16
|
+
onRunUpdate: () => undefined;
|
|
17
|
+
};
|
|
18
|
+
export type ImmichBackupStatus = {
|
|
19
|
+
kind: 'loading' | 'offline' | 'missing' | 'running' | 'paused' | 'unconfigured' | 'never';
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'complete' | 'warn' | 'failed';
|
|
22
|
+
lastBackup: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const useImmichBackupStatus: () => {
|
|
25
|
+
readonly repository: import("../fetch-client").LocalRepositoryDto | undefined;
|
|
26
|
+
readonly schedule: import("../fetch-client").ScheduleDto | undefined;
|
|
27
|
+
readonly status: ImmichBackupStatus;
|
|
28
|
+
};
|
|
@@ -1,6 +1,10 @@
|
|
|
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';
|
|
5
|
+
import { queryClient } from '../query-client';
|
|
6
|
+
import { getBackupOutcome } from '../utils/backup-status';
|
|
7
|
+
import { createQuery } from '@tanstack/svelte-query';
|
|
4
8
|
import { handleCreateBackup } from './repository.service';
|
|
5
9
|
export const getBackupPageActions = (repositoryId, onConfigure) => {
|
|
6
10
|
const Configure = {
|
|
@@ -21,3 +25,57 @@ export const getBackupPageActions = (repositoryId, onConfigure) => {
|
|
|
21
25
|
};
|
|
22
26
|
return { Configure, ViewRecoveryKey, BackUpNow };
|
|
23
27
|
};
|
|
28
|
+
export const immichBackupStatusKeys = {
|
|
29
|
+
all: ['immichBackupStatus'],
|
|
30
|
+
};
|
|
31
|
+
const invalidateImmichBackupStatus = () => void queryClient.invalidateQueries({
|
|
32
|
+
queryKey: immichBackupStatusKeys.all,
|
|
33
|
+
});
|
|
34
|
+
export const useImmichBackupStatusEventHandler = () => ({
|
|
35
|
+
onIntegrationUpdate: invalidateImmichBackupStatus,
|
|
36
|
+
onRepositoryUpdate: invalidateImmichBackupStatus,
|
|
37
|
+
onRepositoryDelete: invalidateImmichBackupStatus,
|
|
38
|
+
onScheduleUpdate: invalidateImmichBackupStatus,
|
|
39
|
+
onRunCreate: invalidateImmichBackupStatus,
|
|
40
|
+
onRunUpdate: invalidateImmichBackupStatus,
|
|
41
|
+
});
|
|
42
|
+
const toImmichBackupStatus = (data, loading) => {
|
|
43
|
+
if (loading || !data) {
|
|
44
|
+
return { kind: 'loading' };
|
|
45
|
+
}
|
|
46
|
+
if (data.backend?.isOnline === false) {
|
|
47
|
+
return { kind: 'offline' };
|
|
48
|
+
}
|
|
49
|
+
if (data.repository?.backends?.primary.online === false) {
|
|
50
|
+
return { kind: 'missing' };
|
|
51
|
+
}
|
|
52
|
+
if (data.latestBackupRun?.status === 'incomplete') {
|
|
53
|
+
return { kind: 'running' };
|
|
54
|
+
}
|
|
55
|
+
const outcome = getBackupOutcome(data.repository?.metrics);
|
|
56
|
+
const lastBackup = data.repository?.metrics.lastBackup;
|
|
57
|
+
if (lastBackup && outcome !== 'never') {
|
|
58
|
+
return { kind: outcome, lastBackup };
|
|
59
|
+
}
|
|
60
|
+
if (data.schedule?.paused) {
|
|
61
|
+
return { kind: 'paused' };
|
|
62
|
+
}
|
|
63
|
+
return { kind: data.repository ? 'never' : 'unconfigured' };
|
|
64
|
+
};
|
|
65
|
+
export const useImmichBackupStatus = () => {
|
|
66
|
+
const query = createQuery(() => ({
|
|
67
|
+
queryKey: immichBackupStatusKeys.all,
|
|
68
|
+
queryFn: () => getImmichBackupStatus(),
|
|
69
|
+
}), () => queryClient);
|
|
70
|
+
return {
|
|
71
|
+
get repository() {
|
|
72
|
+
return query.data?.repository;
|
|
73
|
+
},
|
|
74
|
+
get schedule() {
|
|
75
|
+
return query.data?.schedule;
|
|
76
|
+
},
|
|
77
|
+
get status() {
|
|
78
|
+
return toImmichBackupStatus(query.data, query.isLoading);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -10,5 +10,7 @@ export declare const useIntegrationEventHandler: () => {
|
|
|
10
10
|
integrations: IntegrationsResponseDto;
|
|
11
11
|
}>): void;
|
|
12
12
|
};
|
|
13
|
-
export declare const useConfigureImmichIntegration: () => import("@tanstack/svelte-query").CreateMutationResult<
|
|
14
|
-
export declare const
|
|
13
|
+
export declare const useConfigureImmichIntegration: () => import("@tanstack/svelte-query").CreateMutationResult<import("../fetch-client").ConfigureImmichIntegrationResponseDto, Error, ConfigureImmichIntegrationRequestDto, unknown>;
|
|
14
|
+
export declare const useConfigureAndStartImmichIntegration: () => import("@tanstack/svelte-query").CreateMutationResult<{
|
|
15
|
+
repositoryId: string;
|
|
16
|
+
}, Error, void, unknown>;
|