@futo-org/backups-orchestrator-ui 0.12.0 → 0.13.1
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 +2 -4
- package/dist/components/backends/BackendsList.svelte +2 -4
- package/dist/components/backends/dialogs/OAuthDeviceFlowModal.svelte +38 -26
- package/dist/components/backends/dialogs/OAuthDeviceFlowModal.svelte.d.ts +0 -2
- package/dist/components/backends/dialogs/SelectBackendModal.svelte +6 -12
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +5 -12
- package/dist/services/backend.service.d.ts +3 -1
- package/dist/services/backend.service.js +12 -8
- package/dist/services/log.service.svelte.d.ts +2 -0
- package/dist/services/log.service.svelte.js +4 -1
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
} from "../../fetch-client";
|
|
8
8
|
import {
|
|
9
9
|
getBackendActions,
|
|
10
|
-
|
|
10
|
+
handleStartYuccaLogin,
|
|
11
11
|
} from "../../services/backend.service";
|
|
12
12
|
import { Badge, Icon, Text } from "@immich/ui";
|
|
13
13
|
import { mdiCloudOutline, mdiHarddisk, mdiShieldCheckOutline } from "@mdi/js";
|
|
@@ -33,11 +33,9 @@
|
|
|
33
33
|
s3: "S3 Server",
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
const yuccaLogin = useYuccaLogin();
|
|
37
|
-
|
|
38
36
|
const { LoginAgain, Reconfigure } = $derived(
|
|
39
37
|
getBackendActions(repository, backend, repositoryBackend, () =>
|
|
40
|
-
|
|
38
|
+
handleStartYuccaLogin(),
|
|
41
39
|
),
|
|
42
40
|
);
|
|
43
41
|
</script>
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import { options } from "../../options";
|
|
4
4
|
import {
|
|
5
5
|
handleSetupLocalStorage,
|
|
6
|
+
handleStartYuccaLogin,
|
|
6
7
|
useBackendEventHandler,
|
|
7
8
|
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,7 +21,6 @@
|
|
|
21
21
|
|
|
22
22
|
const { advanced } = options;
|
|
23
23
|
const query = useBackends();
|
|
24
|
-
const yuccaLogin = useYuccaLogin();
|
|
25
24
|
const { onBackendCreate } = useBackendEventHandler();
|
|
26
25
|
|
|
27
26
|
const repositoryBackends = $derived(
|
|
@@ -65,8 +64,7 @@
|
|
|
65
64
|
<Button
|
|
66
65
|
size="small"
|
|
67
66
|
variant="outline"
|
|
68
|
-
|
|
69
|
-
onclick={() => yuccaLogin.mutate(undefined)}>Login with FUTO Backups</Button
|
|
67
|
+
onclick={() => handleStartYuccaLogin()}>Login with FUTO Backups</Button
|
|
70
68
|
>
|
|
71
69
|
<Button
|
|
72
70
|
size="small"
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import Suspense from "../../util/Suspense.svelte";
|
|
2
3
|
import type { SocketEvent } from "../../../events";
|
|
3
|
-
import type
|
|
4
|
-
import {
|
|
4
|
+
import { type BackendDto } from "../../../fetch-client";
|
|
5
|
+
import {
|
|
6
|
+
useBackendEventHandler,
|
|
7
|
+
useDeviceFlow,
|
|
8
|
+
} from "../../../services/backend.service";
|
|
5
9
|
import {
|
|
6
10
|
Button,
|
|
7
11
|
Code,
|
|
@@ -20,13 +24,14 @@
|
|
|
20
24
|
import OnEvents from "../../util/OnEvents.svelte";
|
|
21
25
|
|
|
22
26
|
type Props = {
|
|
23
|
-
userCode: string;
|
|
24
|
-
verificationUri: string;
|
|
25
27
|
onCreate?: (backendId: string) => void;
|
|
26
28
|
onClose: () => void;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
|
-
let {
|
|
31
|
+
let { onCreate, onClose }: Props = $props();
|
|
32
|
+
|
|
33
|
+
const uid = $props.id();
|
|
34
|
+
const query = useDeviceFlow(uid);
|
|
30
35
|
|
|
31
36
|
const { onBackendCreate: onBackendCreateHandler } = useBackendEventHandler();
|
|
32
37
|
|
|
@@ -41,12 +46,12 @@
|
|
|
41
46
|
onClose();
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
function
|
|
45
|
-
|
|
49
|
+
function onRetry() {
|
|
50
|
+
query.refetch();
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
function onCopy() {
|
|
49
|
-
navigator.clipboard.writeText(userCode);
|
|
54
|
+
navigator.clipboard.writeText(query.data!.userCode);
|
|
50
55
|
}
|
|
51
56
|
</script>
|
|
52
57
|
|
|
@@ -54,31 +59,38 @@
|
|
|
54
59
|
|
|
55
60
|
<Modal title="Logging into FUTO Backups" icon={false} {onClose}>
|
|
56
61
|
<ModalBody>
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
<Suspense {query}>
|
|
63
|
+
<VStack>
|
|
64
|
+
<Text>You may be asked or shown the following code:</Text>
|
|
65
|
+
<Stack direction="row" align="center">
|
|
66
|
+
<Code class="text-3xl select-all">{query.data!.userCode}</Code>
|
|
67
|
+
<IconButton
|
|
68
|
+
color="secondary"
|
|
69
|
+
variant="outline"
|
|
70
|
+
icon={mdiContentCopy}
|
|
71
|
+
onclick={onCopy}
|
|
72
|
+
aria-label="Copy code"
|
|
73
|
+
/>
|
|
74
|
+
</Stack>
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
<HStack class="mt-4">
|
|
77
|
+
<LoadingSpinner />
|
|
78
|
+
<Text>Waiting for you to confirm login...</Text>
|
|
79
|
+
</HStack>
|
|
80
|
+
</VStack>
|
|
81
|
+
</Suspense>
|
|
75
82
|
</ModalBody>
|
|
76
83
|
<ModalFooter>
|
|
77
84
|
<HStack fullWidth>
|
|
78
85
|
<Button shape="round" color="secondary" fullWidth onclick={onClose}>
|
|
79
86
|
Cancel
|
|
80
87
|
</Button>
|
|
81
|
-
<Button
|
|
88
|
+
<Button
|
|
89
|
+
shape="round"
|
|
90
|
+
fullWidth
|
|
91
|
+
onclick={onRetry}
|
|
92
|
+
disabled={query.isFetching}>Try again</Button
|
|
93
|
+
>
|
|
82
94
|
</HStack>
|
|
83
95
|
</ModalFooter>
|
|
84
96
|
</Modal>
|
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
import Suspense from "../../util/Suspense.svelte";
|
|
5
5
|
import {
|
|
6
6
|
handleSetupLocalStorage,
|
|
7
|
+
handleStartYuccaLogin,
|
|
7
8
|
useBackends,
|
|
8
|
-
useYuccaLogin,
|
|
9
9
|
} from "../../../services/backend.service";
|
|
10
10
|
import {
|
|
11
11
|
Button,
|
|
12
12
|
HStack,
|
|
13
13
|
Icon,
|
|
14
|
-
LoadingSpinner,
|
|
15
14
|
Modal,
|
|
16
15
|
ModalBody,
|
|
17
16
|
ModalFooter,
|
|
@@ -38,7 +37,6 @@
|
|
|
38
37
|
}: Props = $props();
|
|
39
38
|
|
|
40
39
|
const backends = useBackends();
|
|
41
|
-
const yuccaLogin = useYuccaLogin();
|
|
42
40
|
|
|
43
41
|
const onFutoBackups = () => {
|
|
44
42
|
const futoBackend = backends.data!.find(
|
|
@@ -48,7 +46,7 @@
|
|
|
48
46
|
if (futoBackend) {
|
|
49
47
|
onSelect(futoBackend.id);
|
|
50
48
|
} else {
|
|
51
|
-
|
|
49
|
+
handleStartYuccaLogin(onSelect);
|
|
52
50
|
}
|
|
53
51
|
};
|
|
54
52
|
|
|
@@ -65,7 +63,7 @@
|
|
|
65
63
|
|
|
66
64
|
<Suspense query={backends}>
|
|
67
65
|
<StackList>
|
|
68
|
-
<StackListItem
|
|
66
|
+
<StackListItem {disabled} onclick={onFutoBackups}>
|
|
69
67
|
{#snippet icon()}
|
|
70
68
|
<Icon icon={mdiShieldCheck} size="36px" />
|
|
71
69
|
{/snippet}
|
|
@@ -76,14 +74,10 @@
|
|
|
76
74
|
</Stack>
|
|
77
75
|
|
|
78
76
|
{#snippet trailing()}
|
|
79
|
-
{
|
|
80
|
-
<LoadingSpinner />
|
|
81
|
-
{:else}
|
|
82
|
-
<Icon icon={mdiChevronRight} />
|
|
83
|
-
{/if}
|
|
77
|
+
<Icon icon={mdiChevronRight} />
|
|
84
78
|
{/snippet}
|
|
85
79
|
</StackListItem>
|
|
86
|
-
<StackListItem
|
|
80
|
+
<StackListItem {disabled} onclick={onLocalBackups}>
|
|
87
81
|
{#snippet icon()}
|
|
88
82
|
<Icon icon={mdiHarddisk} size="36px" />
|
|
89
83
|
{/snippet}
|
|
@@ -101,7 +95,7 @@
|
|
|
101
95
|
{#each backends.data as backend}
|
|
102
96
|
{#if backend.type === "local"}
|
|
103
97
|
<StackListItem
|
|
104
|
-
|
|
98
|
+
{disabled}
|
|
105
99
|
onclick={() => {
|
|
106
100
|
onSelect(backend.id);
|
|
107
101
|
}}
|
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
import StackListItem from "../../ui/StackListItem.svelte";
|
|
4
4
|
import {
|
|
5
5
|
handleSetupLocalStorage,
|
|
6
|
-
|
|
6
|
+
handleStartYuccaLogin,
|
|
7
7
|
} from "../../../services/backend.service";
|
|
8
8
|
import {
|
|
9
9
|
Button,
|
|
10
10
|
HStack,
|
|
11
11
|
Icon,
|
|
12
|
-
LoadingSpinner,
|
|
13
12
|
Modal,
|
|
14
13
|
ModalBody,
|
|
15
14
|
ModalFooter,
|
|
@@ -26,10 +25,8 @@
|
|
|
26
25
|
|
|
27
26
|
const { restore = false, onNext, onCancel }: Props = $props();
|
|
28
27
|
|
|
29
|
-
const yuccaLogin = useYuccaLogin();
|
|
30
|
-
|
|
31
28
|
function onFutoBackups() {
|
|
32
|
-
|
|
29
|
+
handleStartYuccaLogin(onNext);
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
function onLocalBackups() {
|
|
@@ -47,7 +44,7 @@
|
|
|
47
44
|
>
|
|
48
45
|
<ModalBody>
|
|
49
46
|
<StackList>
|
|
50
|
-
<StackListItem
|
|
47
|
+
<StackListItem onclick={onFutoBackups}>
|
|
51
48
|
{#snippet icon()}
|
|
52
49
|
<Icon icon={mdiShieldCheck} size="36px" />
|
|
53
50
|
{/snippet}
|
|
@@ -58,14 +55,10 @@
|
|
|
58
55
|
</Stack>
|
|
59
56
|
|
|
60
57
|
{#snippet trailing()}
|
|
61
|
-
{
|
|
62
|
-
<LoadingSpinner />
|
|
63
|
-
{:else}
|
|
64
|
-
<Icon icon={mdiChevronRight} />
|
|
65
|
-
{/if}
|
|
58
|
+
<Icon icon={mdiChevronRight} />
|
|
66
59
|
{/snippet}
|
|
67
60
|
</StackListItem>
|
|
68
|
-
<StackListItem
|
|
61
|
+
<StackListItem onclick={onLocalBackups}>
|
|
69
62
|
{#snippet icon()}
|
|
70
63
|
<Icon icon={mdiHarddisk} size="36px" />
|
|
71
64
|
{/snippet}
|
|
@@ -3,14 +3,16 @@ import { type BackendDto, type CreateLocalBackendRequestDto, type LocalRepositor
|
|
|
3
3
|
import { type ActionItem } from '@immich/ui';
|
|
4
4
|
export declare const backendKeys: {
|
|
5
5
|
all: readonly ["backends"];
|
|
6
|
+
deviceFlow: (uid: string) => readonly ["deviceFlow", string];
|
|
6
7
|
};
|
|
7
8
|
export declare const useBackends: () => import("@tanstack/svelte-query").CreateQueryResult<BackendDto[], Error>;
|
|
9
|
+
export declare const useDeviceFlow: (uid: string) => import("@tanstack/svelte-query").CreateQueryResult<import("../fetch-client").DeviceFlowResponseDto, Error>;
|
|
8
10
|
export declare const useBackendEventHandler: () => {
|
|
9
11
|
onBackendCreate(event: SocketEvent<{
|
|
10
12
|
backend: BackendDto;
|
|
11
13
|
}>): void;
|
|
12
14
|
};
|
|
13
|
-
export declare const
|
|
15
|
+
export declare const handleStartYuccaLogin: (onCreate?: (backendId: string) => void) => void;
|
|
14
16
|
export declare const handleSetupLocalStorage: (onCreate?: (backendId: string) => void) => void;
|
|
15
17
|
export declare const useCreateLocalBackend: () => import("@tanstack/svelte-query").CreateMutationResult<import("../fetch-client").BackendResponseDto, Error, CreateLocalBackendRequestDto, unknown>;
|
|
16
18
|
export declare const handleReconfigureRepositoryBackend: (repository: LocalRepositoryDto) => Promise<void>;
|
|
@@ -10,11 +10,22 @@ import { mdiLogin } from '@mdi/js';
|
|
|
10
10
|
import { createMutation, createQuery } from '@tanstack/svelte-query';
|
|
11
11
|
export const backendKeys = {
|
|
12
12
|
all: ['backends'],
|
|
13
|
+
deviceFlow: (uid) => ['deviceFlow', uid],
|
|
13
14
|
};
|
|
14
15
|
export const useBackends = () => createQuery(() => ({
|
|
15
16
|
queryKey: backendKeys.all,
|
|
16
17
|
queryFn: () => getBackends().then(({ backends }) => backends),
|
|
17
18
|
}), () => queryClient);
|
|
19
|
+
export const useDeviceFlow = (uid) => createQuery(() => ({
|
|
20
|
+
queryKey: backendKeys.deviceFlow(uid),
|
|
21
|
+
queryFn: async () => {
|
|
22
|
+
const response = await oidcDeviceFlow();
|
|
23
|
+
window.open(response.verificationUri, '_blank');
|
|
24
|
+
return response;
|
|
25
|
+
},
|
|
26
|
+
refetchOnReconnect: false,
|
|
27
|
+
refetchOnWindowFocus: false,
|
|
28
|
+
}), () => queryClient);
|
|
18
29
|
export const useBackendEventHandler = () => {
|
|
19
30
|
return {
|
|
20
31
|
onBackendCreate(event) {
|
|
@@ -29,18 +40,11 @@ export const useBackendEventHandler = () => {
|
|
|
29
40
|
},
|
|
30
41
|
};
|
|
31
42
|
};
|
|
32
|
-
const
|
|
33
|
-
const response = await oidcDeviceFlow();
|
|
43
|
+
export const handleStartYuccaLogin = (onCreate) => {
|
|
34
44
|
void modalManager.show(OAuthDeviceFlow, {
|
|
35
|
-
...response,
|
|
36
45
|
onCreate,
|
|
37
46
|
});
|
|
38
|
-
window.open(response.verificationUri, '_blank');
|
|
39
47
|
};
|
|
40
|
-
export const useYuccaLogin = () => createMutation(() => ({
|
|
41
|
-
mutationFn: (onCreate) => startYuccaLogin(onCreate),
|
|
42
|
-
onError: (error) => handleError(error, 'Failed to start login'),
|
|
43
|
-
}), () => queryClient);
|
|
44
48
|
export const handleSetupLocalStorage = (onCreate) => {
|
|
45
49
|
void modalManager.show(CreateLocalBackend, { onCreate });
|
|
46
50
|
};
|
|
@@ -34,7 +34,10 @@ export function createLogObserver(logId) {
|
|
|
34
34
|
case 'status': {
|
|
35
35
|
state.status = {
|
|
36
36
|
progress: event.percent_done,
|
|
37
|
-
text: event.seconds_remaining &&
|
|
37
|
+
text: event.seconds_remaining &&
|
|
38
|
+
(event.bytes_done && event.total_bytes
|
|
39
|
+
? event.bytes_done < event.total_bytes
|
|
40
|
+
: event.percent_done < 100)
|
|
38
41
|
? `${formatDuration(event.seconds_remaining * 1000)} remaining`
|
|
39
42
|
: 'Nearly done.',
|
|
40
43
|
currentFiles: event.current_files ?? [],
|
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.13.1",
|
|
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.13.1"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"dev": "vite dev --port 5174",
|