Skip to content

Commit 0d4822d

Browse files
feat: progress hosting (#1197)
* feat: progress hosting * feat: hosting service * feat: use hosting service * fix: set config step as done
1 parent 5503b8f commit 0d4822d

File tree

8 files changed

+183
-35
lines changed

8 files changed

+183
-35
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<script lang="ts">
2+
import { isNullish, nonNullish } from '@dfinity/utils';
3+
import { untrack } from 'svelte';
4+
import WizardProgressSteps from '$lib/components/ui/WizardProgressSteps.svelte';
5+
import { i18n } from '$lib/stores/i18n.store';
6+
import { type HostingProgress, HostingProgressStep } from '$lib/types/progress-hosting';
7+
import type { ProgressStep } from '$lib/types/progress-step';
8+
import { mapProgressState } from '$lib/utils/progress.utils';
9+
10+
interface Props {
11+
progress: HostingProgress | undefined;
12+
withConfig: boolean;
13+
}
14+
15+
let { progress, withConfig }: Props = $props();
16+
17+
interface Steps {
18+
preparing: ProgressStep;
19+
customDomain: ProgressStep;
20+
authConfig?: ProgressStep;
21+
}
22+
23+
let steps: Steps = $state({
24+
preparing: {
25+
state: 'in_progress',
26+
step: 'preparing',
27+
text: $i18n.core.preparing
28+
},
29+
customDomain: {
30+
state: 'next',
31+
step: 'custom-domain',
32+
text: $i18n.hosting.config_custom_domain_in_progress
33+
},
34+
...(withConfig && {
35+
authConfig: {
36+
state: 'next',
37+
step: 'auth-config',
38+
text: $i18n.hosting.config_auth_config_in_progress
39+
}
40+
})
41+
});
42+
43+
let displaySteps = $derived(Object.values(steps) as [ProgressStep, ...ProgressStep[]]);
44+
45+
$effect(() => {
46+
progress;
47+
48+
untrack(() => {
49+
const { preparing, customDomain, authConfig } = steps;
50+
51+
steps = {
52+
preparing: {
53+
...preparing,
54+
state: isNullish(progress) ? 'in_progress' : 'completed'
55+
},
56+
customDomain: {
57+
...customDomain,
58+
state:
59+
progress?.step === HostingProgressStep.CustomDomain
60+
? mapProgressState(progress?.state)
61+
: customDomain.state
62+
},
63+
...(nonNullish(authConfig) && {
64+
authConfig: {
65+
...authConfig,
66+
state:
67+
progress?.step === HostingProgressStep.AuthConfig
68+
? mapProgressState(progress?.state)
69+
: authConfig.state
70+
}
71+
})
72+
};
73+
});
74+
});
75+
</script>
76+
77+
<WizardProgressSteps steps={displaySteps}>
78+
{$i18n.core.hold_tight}
79+
</WizardProgressSteps>

src/frontend/src/lib/components/modals/CustomDomainModal.svelte

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
<script lang="ts">
22
import { isEmptyString, isNullish, nonNullish, fromNullishNullable } from '@dfinity/utils';
3-
import { createEventDispatcher, onMount } from 'svelte';
3+
import { onMount } from 'svelte';
44
import type { AuthenticationConfig } from '$declarations/satellite/satellite.did';
5-
import { setAuthConfig } from '$lib/api/satellites.api';
5+
import ProgressHosting from '$lib/components/canister/ProgressHosting.svelte';
66
import AddCustomDomainAuth from '$lib/components/hosting/AddCustomDomainAuth.svelte';
77
import AddCustomDomainDns from '$lib/components/hosting/AddCustomDomainDns.svelte';
88
import AddCustomDomainForm from '$lib/components/hosting/AddCustomDomainForm.svelte';
99
import IconVerified from '$lib/components/icons/IconVerified.svelte';
1010
import Modal from '$lib/components/ui/Modal.svelte';
11-
import SpinnerModal from '$lib/components/ui/SpinnerModal.svelte';
12-
import { setCustomDomain } from '$lib/services/custom-domain.services';
11+
import { configHosting } from '$lib/services/hosting.services';
1312
import { authStore } from '$lib/stores/auth.store';
1413
import { wizardBusy } from '$lib/stores/busy.store';
1514
import { i18n } from '$lib/stores/i18n.store';
1615
import { toasts } from '$lib/stores/toasts.store';
1716
import type { CustomDomainDns } from '$lib/types/custom-domain';
1817
import type { JunoModalCustomDomainDetail, JunoModalDetail } from '$lib/types/modal';
18+
import type { HostingProgress } from '$lib/types/progress-hosting';
19+
import type { Option } from '$lib/types/utils';
1920
import { toCustomDomainDns } from '$lib/utils/custom-domain.utils';
2021
import { emit } from '$lib/utils/events.utils';
2122
2223
interface Props {
2324
detail: JunoModalDetail;
25+
onclose: () => void;
2426
}
2527
26-
let { detail }: Props = $props();
28+
let { detail, onclose }: Props = $props();
2729
2830
let { satellite, config } = $derived(detail as JunoModalCustomDomainDetail);
2931
@@ -45,13 +47,16 @@
4547
edit = true;
4648
});
4749
48-
let editConfig: AuthenticationConfig | null;
50+
let editConfig = $state<Option<AuthenticationConfig>>();
4951
const onAuth = (detail: AuthenticationConfig | null) => {
5052
editConfig = detail;
5153
5254
step = 'dns';
5355
};
5456
57+
let progress: HostingProgress | undefined = $state(undefined);
58+
const onProgress = (hostingProgress: HostingProgress | undefined) => (progress = hostingProgress);
59+
5560
const setupCustomDomain = async () => {
5661
if (isNullish(dns)) {
5762
toasts.error({
@@ -63,37 +68,27 @@
6368
wizardBusy.start();
6469
step = 'in_progress';
6570
66-
try {
67-
await setCustomDomain({
68-
satelliteId: satellite.satellite_id,
69-
domainName: dns.hostname
70-
});
71-
72-
if (nonNullish(editConfig)) {
73-
await setAuthConfig({
74-
satelliteId: satellite.satellite_id,
75-
config: editConfig,
76-
identity: $authStore.identity
77-
});
78-
}
71+
const { success } = await configHosting({
72+
satelliteId: satellite.satellite_id,
73+
domainName: dns.hostname,
74+
editConfig,
75+
identity: $authStore.identity,
76+
onProgress
77+
});
7978
80-
step = 'ready';
81-
} catch (err: unknown) {
82-
toasts.error({
83-
text: $i18n.errors.hosting_configuration_issues,
84-
detail: err
85-
});
79+
wizardBusy.stop();
8680
81+
if (success !== 'ok') {
8782
step = edit ? 'dns' : 'init';
83+
return;
8884
}
8985
90-
wizardBusy.stop();
86+
step = 'ready';
9187
};
9288
93-
const dispatch = createEventDispatcher();
9489
const close = () => {
9590
emit({ message: 'junoSyncCustomDomains' });
96-
dispatch('junoClose');
91+
onclose();
9792
};
9893
9994
const onFormNext = () => {
@@ -124,9 +119,7 @@
124119
on:junoClose
125120
/>
126121
{:else if step === 'in_progress'}
127-
<SpinnerModal>
128-
<p>{$i18n.hosting.config_in_progress}</p>
129-
</SpinnerModal>
122+
<ProgressHosting {progress} withConfig={nonNullish(editConfig)} />
130123
{:else if step === 'auth'}
131124
<AddCustomDomainAuth {domainNameInput} {config} next={onAuth} />
132125
{:else}

src/frontend/src/lib/components/modals/Modals.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
{/if}
5656

5757
{#if modal?.type === 'add_custom_domain' && nonNullish(modal.detail)}
58-
<CustomDomainModal on:junoClose={close} detail={modal.detail} />
58+
<CustomDomainModal onclose={close} detail={modal.detail} />
5959
{/if}
6060

6161
{#if modal?.type === 'create_controller' && nonNullish(modal.detail)}

src/frontend/src/lib/i18n/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@
389389
"type": "Type",
390390
"host": "Host",
391391
"value": "Value",
392-
"config_in_progress": "Configuration in progress...",
392+
"config_custom_domain_in_progress": "Setting up custom domain...",
393+
"config_auth_config_in_progress": "Configuring main domain for authentication...",
393394
"add_custom_domain": "Add custom domain",
394395
"description": "Enter the exact domain name you want people to see when they visit your satellite. It can be a domain (yourdomain.com) or a subdomain (app.yourdomain.com).",
395396
"custom_domain": "Custom domain",

src/frontend/src/lib/i18n/zh-cn.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@
389389
"type": "类型",
390390
"host": "主机",
391391
"value": "",
392-
"config_in_progress": "处理配置...",
392+
"config_custom_domain_in_progress": "Setting up custom domain...",
393+
"config_auth_config_in_progress": "Configuring main domain for authentication...",
393394
"add_custom_domain": "增加域名",
394395
"description": "输入准确的域名用于用户访问你的 satellite. 它可以是二级级域名(yourdomain.com)或者是子域名 (app.yourdomain.com).",
395396
"custom_domain": "定制域名",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { AuthenticationConfig } from '$declarations/satellite/satellite.did';
2+
import { setAuthConfig } from '$lib/api/satellites.api';
3+
import { setCustomDomain } from '$lib/services/custom-domain.services';
4+
import { execute } from '$lib/services/progress.services';
5+
import { i18n } from '$lib/stores/i18n.store';
6+
import { toasts } from '$lib/stores/toasts.store';
7+
import type { OptionIdentity } from '$lib/types/itentity';
8+
import { type HostingProgress, HostingProgressStep } from '$lib/types/progress-hosting';
9+
import type { Option } from '$lib/types/utils';
10+
import { Principal } from '@dfinity/principal';
11+
import { assertNonNullish, nonNullish } from '@dfinity/utils';
12+
import { get } from 'svelte/store';
13+
14+
export const configHosting = async ({
15+
satelliteId,
16+
editConfig,
17+
domainName,
18+
identity,
19+
onProgress
20+
}: {
21+
domainName: string;
22+
editConfig: Option<AuthenticationConfig>;
23+
satelliteId: Principal;
24+
identity: OptionIdentity;
25+
onProgress: (progress: HostingProgress | undefined) => void;
26+
}): Promise<{ success: 'ok' | 'error'; err?: unknown }> => {
27+
try {
28+
assertNonNullish(identity, get(i18n).core.not_logged_in);
29+
30+
const configCustomDomain = async () =>
31+
await setCustomDomain({
32+
satelliteId,
33+
domainName
34+
});
35+
36+
await execute({ fn: configCustomDomain, onProgress, step: HostingProgressStep.CustomDomain });
37+
38+
if (nonNullish(editConfig)) {
39+
const configAuth = async () =>
40+
await setAuthConfig({
41+
satelliteId,
42+
config: editConfig,
43+
identity
44+
});
45+
46+
await execute({ fn: configAuth, onProgress, step: HostingProgressStep.AuthConfig });
47+
}
48+
} catch (err: unknown) {
49+
const labels = get(i18n);
50+
51+
toasts.error({
52+
text: labels.errors.hosting_configuration_issues,
53+
detail: err
54+
});
55+
56+
return { success: 'error', err };
57+
}
58+
59+
return { success: 'ok' };
60+
};

src/frontend/src/lib/types/i18n.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ interface I18nHosting {
402402
type: string;
403403
host: string;
404404
value: string;
405-
config_in_progress: string;
405+
config_custom_domain_in_progress: string;
406+
config_auth_config_in_progress: string;
406407
add_custom_domain: string;
407408
description: string;
408409
custom_domain: string;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { UpgradeCodeProgressState } from '@junobuild/admin';
2+
3+
export enum HostingProgressStep {
4+
CustomDomain = 0,
5+
AuthConfig = 1
6+
}
7+
8+
export type HostingProgressState = UpgradeCodeProgressState;
9+
10+
export interface HostingProgress {
11+
step: HostingProgressStep;
12+
state: HostingProgressState;
13+
}

0 commit comments

Comments
 (0)