@futo-org/backups-orchestrator-ui 0.4.0 → 0.5.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/backends/BackendItem.svelte +9 -2
- package/dist/components/backends/BackendsList.svelte +7 -3
- package/dist/components/backends/dialogs/OAuthDeviceFlowModal.svelte +7 -1
- package/dist/components/backends/dialogs/SelectBackendModal.svelte +12 -6
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +2 -2
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +12 -5
- package/dist/services/backend.service.d.ts +2 -2
- package/dist/services/backend.service.js +13 -15
- package/package.json +2 -2
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
LocalRepositoryDto,
|
|
6
6
|
RepositoryBackendDto,
|
|
7
7
|
} from "../../fetch-client";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
getBackendActions,
|
|
10
|
+
useYuccaLogin,
|
|
11
|
+
} from "../../services/backend.service";
|
|
9
12
|
import { Badge, Icon, Text } from "@immich/ui";
|
|
10
13
|
import { mdiCloudOutline, mdiHarddisk, mdiShieldCheckOutline } from "@mdi/js";
|
|
11
14
|
import StackListItem from "../ui/StackListItem.svelte";
|
|
@@ -30,8 +33,12 @@
|
|
|
30
33
|
s3: "S3 Server",
|
|
31
34
|
};
|
|
32
35
|
|
|
36
|
+
const yuccaLogin = useYuccaLogin();
|
|
37
|
+
|
|
33
38
|
const { LoginAgain, Reconfigure } = $derived(
|
|
34
|
-
getBackendActions(repository, backend, repositoryBackend)
|
|
39
|
+
getBackendActions(repository, backend, repositoryBackend, () =>
|
|
40
|
+
yuccaLogin.mutate(undefined),
|
|
41
|
+
),
|
|
35
42
|
);
|
|
36
43
|
</script>
|
|
37
44
|
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import { options } from "../../options";
|
|
4
4
|
import {
|
|
5
5
|
handleSetupLocalStorage,
|
|
6
|
-
handleYuccaLogin,
|
|
7
6
|
useBackendEventHandler,
|
|
8
7
|
useBackends,
|
|
8
|
+
useYuccaLogin,
|
|
9
9
|
} from "../../services/backend.service";
|
|
10
10
|
import { Button, HStack } from "@immich/ui";
|
|
11
11
|
import StackList from "../ui/StackList.svelte";
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
const { advanced } = options;
|
|
23
23
|
const query = useBackends();
|
|
24
|
+
const yuccaLogin = useYuccaLogin();
|
|
24
25
|
const { onBackendCreate } = useBackendEventHandler();
|
|
25
26
|
|
|
26
27
|
const repositoryBackends = $derived(
|
|
@@ -61,8 +62,11 @@
|
|
|
61
62
|
|
|
62
63
|
{#if $advanced}
|
|
63
64
|
<HStack>
|
|
64
|
-
<Button
|
|
65
|
-
|
|
65
|
+
<Button
|
|
66
|
+
size="small"
|
|
67
|
+
variant="outline"
|
|
68
|
+
loading={yuccaLogin.isPending}
|
|
69
|
+
onclick={() => yuccaLogin.mutate(undefined)}>Login with FUTO Backups</Button
|
|
66
70
|
>
|
|
67
71
|
<Button
|
|
68
72
|
size="small"
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
ModalFooter,
|
|
14
14
|
Stack,
|
|
15
15
|
Text,
|
|
16
|
+
toastManager,
|
|
16
17
|
VStack,
|
|
17
18
|
} from "@immich/ui";
|
|
18
19
|
import { mdiContentCopy } from "@mdi/js";
|
|
@@ -35,6 +36,11 @@
|
|
|
35
36
|
onClose();
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
function onDeviceFlowFailure() {
|
|
40
|
+
toastManager.danger("Failed to log into FUTO Backups");
|
|
41
|
+
onClose();
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
function onOpen() {
|
|
39
45
|
window.open(verificationUri, "_blank");
|
|
40
46
|
}
|
|
@@ -44,7 +50,7 @@
|
|
|
44
50
|
}
|
|
45
51
|
</script>
|
|
46
52
|
|
|
47
|
-
<OnEvents {onBackendCreate} />
|
|
53
|
+
<OnEvents {onBackendCreate} {onDeviceFlowFailure} />
|
|
48
54
|
|
|
49
55
|
<Modal title="Logging into FUTO Backups" icon={false} {onClose}>
|
|
50
56
|
<ModalBody>
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
import Suspense from "../../util/Suspense.svelte";
|
|
5
5
|
import {
|
|
6
6
|
handleSetupLocalStorage,
|
|
7
|
-
handleYuccaLogin,
|
|
8
7
|
useBackends,
|
|
8
|
+
useYuccaLogin,
|
|
9
9
|
} from "../../../services/backend.service";
|
|
10
10
|
import {
|
|
11
11
|
Button,
|
|
12
12
|
HStack,
|
|
13
13
|
Icon,
|
|
14
|
+
LoadingSpinner,
|
|
14
15
|
Modal,
|
|
15
16
|
ModalBody,
|
|
16
17
|
ModalFooter,
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
}: Props = $props();
|
|
38
39
|
|
|
39
40
|
const backends = useBackends();
|
|
41
|
+
const yuccaLogin = useYuccaLogin();
|
|
40
42
|
|
|
41
43
|
const onFutoBackups = () => {
|
|
42
44
|
const futoBackend = backends.data!.find(
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
if (futoBackend) {
|
|
47
49
|
onSelect(futoBackend.id);
|
|
48
50
|
} else {
|
|
49
|
-
|
|
51
|
+
yuccaLogin.mutate(onSelect);
|
|
50
52
|
}
|
|
51
53
|
};
|
|
52
54
|
|
|
@@ -63,7 +65,7 @@
|
|
|
63
65
|
|
|
64
66
|
<Suspense query={backends}>
|
|
65
67
|
<StackList>
|
|
66
|
-
<StackListItem {disabled} onclick={onFutoBackups}>
|
|
68
|
+
<StackListItem disabled={disabled || yuccaLogin.isPending} onclick={onFutoBackups}>
|
|
67
69
|
{#snippet icon()}
|
|
68
70
|
<Icon icon={mdiShieldCheck} size="36px" />
|
|
69
71
|
{/snippet}
|
|
@@ -74,10 +76,14 @@
|
|
|
74
76
|
</Stack>
|
|
75
77
|
|
|
76
78
|
{#snippet trailing()}
|
|
77
|
-
|
|
79
|
+
{#if yuccaLogin.isPending}
|
|
80
|
+
<LoadingSpinner />
|
|
81
|
+
{:else}
|
|
82
|
+
<Icon icon={mdiChevronRight} />
|
|
83
|
+
{/if}
|
|
78
84
|
{/snippet}
|
|
79
85
|
</StackListItem>
|
|
80
|
-
<StackListItem {disabled} onclick={onLocalBackups}>
|
|
86
|
+
<StackListItem disabled={disabled || yuccaLogin.isPending} onclick={onLocalBackups}>
|
|
81
87
|
{#snippet icon()}
|
|
82
88
|
<Icon icon={mdiHarddisk} size="36px" />
|
|
83
89
|
{/snippet}
|
|
@@ -95,7 +101,7 @@
|
|
|
95
101
|
{#each backends.data as backend}
|
|
96
102
|
{#if backend.type === "local"}
|
|
97
103
|
<StackListItem
|
|
98
|
-
{disabled}
|
|
104
|
+
disabled={disabled || yuccaLogin.isPending}
|
|
99
105
|
onclick={() => {
|
|
100
106
|
onSelect(backend.id);
|
|
101
107
|
}}
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
<Heading size="tiny">Your library</Heading>
|
|
54
54
|
<Text>
|
|
55
55
|
{#if repository.meter}
|
|
56
|
-
|
|
56
|
+
<FormatBytes bytes={repository.meter.sizeBytes} />
|
|
57
57
|
{:else}
|
|
58
|
-
<FormatBytes bytes={repository.metrics.sizeBytes} />
|
|
58
|
+
Estimated <FormatBytes bytes={repository.metrics.sizeBytes} />
|
|
59
59
|
{/if} ·
|
|
60
60
|
<span class="lowercase"
|
|
61
61
|
>{cronstrue.toString(schedule.cron, {
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
import StackListItem from "../../ui/StackListItem.svelte";
|
|
4
4
|
import {
|
|
5
5
|
handleSetupLocalStorage,
|
|
6
|
-
|
|
6
|
+
useYuccaLogin,
|
|
7
7
|
} from "../../../services/backend.service";
|
|
8
8
|
import {
|
|
9
9
|
Button,
|
|
10
10
|
HStack,
|
|
11
11
|
Icon,
|
|
12
|
+
LoadingSpinner,
|
|
12
13
|
Modal,
|
|
13
14
|
ModalBody,
|
|
14
15
|
ModalFooter,
|
|
@@ -25,8 +26,10 @@
|
|
|
25
26
|
|
|
26
27
|
const { restore = false, onNext, onCancel }: Props = $props();
|
|
27
28
|
|
|
29
|
+
const yuccaLogin = useYuccaLogin();
|
|
30
|
+
|
|
28
31
|
function onFutoBackups() {
|
|
29
|
-
|
|
32
|
+
yuccaLogin.mutate(onNext);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
function onLocalBackups() {
|
|
@@ -44,7 +47,7 @@
|
|
|
44
47
|
>
|
|
45
48
|
<ModalBody>
|
|
46
49
|
<StackList>
|
|
47
|
-
<StackListItem onclick={onFutoBackups}>
|
|
50
|
+
<StackListItem disabled={yuccaLogin.isPending} onclick={onFutoBackups}>
|
|
48
51
|
{#snippet icon()}
|
|
49
52
|
<Icon icon={mdiShieldCheck} size="36px" />
|
|
50
53
|
{/snippet}
|
|
@@ -55,10 +58,14 @@
|
|
|
55
58
|
</Stack>
|
|
56
59
|
|
|
57
60
|
{#snippet trailing()}
|
|
58
|
-
|
|
61
|
+
{#if yuccaLogin.isPending}
|
|
62
|
+
<LoadingSpinner />
|
|
63
|
+
{:else}
|
|
64
|
+
<Icon icon={mdiChevronRight} />
|
|
65
|
+
{/if}
|
|
59
66
|
{/snippet}
|
|
60
67
|
</StackListItem>
|
|
61
|
-
<StackListItem onclick={onLocalBackups}>
|
|
68
|
+
<StackListItem disabled={yuccaLogin.isPending} onclick={onLocalBackups}>
|
|
62
69
|
{#snippet icon()}
|
|
63
70
|
<Icon icon={mdiHarddisk} size="36px" />
|
|
64
71
|
{/snippet}
|
|
@@ -10,14 +10,14 @@ export declare const useBackendEventHandler: () => {
|
|
|
10
10
|
backend: BackendDto;
|
|
11
11
|
}>): void;
|
|
12
12
|
};
|
|
13
|
-
export declare const
|
|
13
|
+
export declare const useYuccaLogin: () => import("@tanstack/svelte-query").CreateMutationResult<void, Error, ((backendId: string) => void) | undefined, unknown>;
|
|
14
14
|
export declare const handleSetupLocalStorage: (onCreate?: (backendId: string) => void) => void;
|
|
15
15
|
export declare const useCreateLocalBackend: () => import("@tanstack/svelte-query").CreateMutationResult<import("../fetch-client").BackendResponseDto, Error, CreateLocalBackendRequestDto, unknown>;
|
|
16
16
|
export declare const handleReconfigureRepositoryBackend: (repository: LocalRepositoryDto) => Promise<void>;
|
|
17
17
|
export declare const handleRemoveRepositoryBackend: (_backend: BackendDto, _repositoryBackend: RepositoryBackendDto) => void;
|
|
18
18
|
export declare const getBackendActions: (repository: LocalRepositoryDto | undefined, backend: BackendDto, repositoryBackend?: RepositoryBackendDto & {
|
|
19
19
|
primary?: boolean;
|
|
20
|
-
}) => {
|
|
20
|
+
}, onLogin?: () => void) => {
|
|
21
21
|
LoginAgain: ActionItem;
|
|
22
22
|
Reconfigure: ActionItem;
|
|
23
23
|
Remove: ActionItem;
|
|
@@ -29,20 +29,18 @@ export const useBackendEventHandler = () => {
|
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
window.open(response.verificationUri, '_blank');
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
handleError(error, 'Failed to start login');
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
32
|
+
const startYuccaLogin = async (onCreate) => {
|
|
33
|
+
const response = await oidcDeviceFlow();
|
|
34
|
+
void modalManager.show(OAuthDeviceFlow, {
|
|
35
|
+
...response,
|
|
36
|
+
onCreate,
|
|
37
|
+
});
|
|
38
|
+
window.open(response.verificationUri, '_blank');
|
|
45
39
|
};
|
|
40
|
+
export const useYuccaLogin = () => createMutation(() => ({
|
|
41
|
+
mutationFn: (onCreate) => startYuccaLogin(onCreate),
|
|
42
|
+
onError: (error) => handleError(error, 'Failed to start login'),
|
|
43
|
+
}), () => queryClient);
|
|
46
44
|
export const handleSetupLocalStorage = (onCreate) => {
|
|
47
45
|
void modalManager.show(CreateLocalBackend, { onCreate });
|
|
48
46
|
};
|
|
@@ -58,11 +56,11 @@ export const handleReconfigureRepositoryBackend = async (repository) => {
|
|
|
58
56
|
export const handleRemoveRepositoryBackend = (_backend, _repositoryBackend) => {
|
|
59
57
|
alert('TODO: implement me when multi-repository-backend support is added');
|
|
60
58
|
};
|
|
61
|
-
export const getBackendActions = (repository, backend, repositoryBackend) => {
|
|
59
|
+
export const getBackendActions = (repository, backend, repositoryBackend, onLogin) => {
|
|
62
60
|
const LoginAgain = {
|
|
63
61
|
icon: mdiLogin,
|
|
64
62
|
title: 'Login again',
|
|
65
|
-
onAction: () =>
|
|
63
|
+
onAction: () => onLogin?.(),
|
|
66
64
|
$if: () => backend.type === 'yucca' && !backend.isOnline,
|
|
67
65
|
};
|
|
68
66
|
const Reconfigure = {
|
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.5.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.5.0"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"dev": "vite dev --port 5174",
|