Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lib/components/domains/nameserverTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
{#if verified === true}
<Badge variant="secondary" type="success" size="xs" content="Verified" />
{:else if verified === false}
<Badge variant="secondary" type="warning" size="xs" content="Verification failed" />
<Badge variant="secondary" type="error" size="xs" content="Verification failed" />
{/if}
</Layout.Stack>
<Typography.Text variant="m-400">
Expand Down
144 changes: 114 additions & 30 deletions src/lib/components/domains/recordTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,56 @@
Alert
} from '@appwrite.io/pink-svelte';
import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store';
import { getSubdomain } from '$lib/helpers/tlds';
import { isCloud } from '$lib/system';

export let domain: string;
export let verified = undefined;
export let variant: 'cname' | 'a' | 'aaaa';
export let service: 'sites' | 'general' = 'general';
let {
domain,
verified = undefined,
variant,
service = 'general',
ruleStatus = undefined,
onNavigateToNameservers = () => {},
onNavigateToA = () => {},
onNavigateToAAAA = () => {}
}: {
domain: string;
verified?: boolean;
variant: 'cname' | 'a' | 'aaaa';
service?: 'sites' | 'functions' | 'general';
ruleStatus?: 'created' | 'verifying' | 'unverified' | 'verified';
onNavigateToNameservers?: () => void;
onNavigateToA?: () => void;
onNavigateToAAAA?: () => void;
} = $props();

let subdomain = domain?.split('.')?.slice(0, -2)?.join('.');
const subdomain = $derived(getSubdomain(domain));
const caaText = $derived(
$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA?.includes(' ')
? $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
: `0 issue "${$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}"`
);
const aTabVisible = $derived(
!isCloud &&
Boolean($regionalConsoleVariables._APP_DOMAIN_TARGET_A) &&
$regionalConsoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'
);
const aaaaTabVisible = $derived(
!isCloud &&
Boolean($regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA) &&
$regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'
);

function setTarget() {
switch (variant) {
case 'cname':
return service === 'general'
? $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME
: $regionalConsoleVariables._APP_DOMAIN_SITES;
if (service === 'sites') {
return $regionalConsoleVariables._APP_DOMAIN_SITES;
} else if (service === 'functions') {
return $regionalConsoleVariables._APP_DOMAIN_FUNCTIONS;
} else {
return $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME;
}
case 'a':
return $regionalConsoleVariables._APP_DOMAIN_TARGET_A;
case 'aaaa':
Expand All @@ -37,42 +73,90 @@
<Typography.Text variant="l-500" color="--fgcolor-neutral-primary">
{domain}
</Typography.Text>
{#if verified === true}
<Badge variant="secondary" type="success" size="xs" content="Verified" />
{:else if verified === false}
<Badge variant="secondary" type="warning" size="xs" content="Verification failed" />
{#if verified !== undefined}
{#if ruleStatus === 'created'}
<Badge
variant="secondary"
type="error"
size="xs"
content="Verification failed" />
{:else if ruleStatus === 'verifying'}
<Badge variant="secondary" size="xs" content="Generating certificate" />
{:else if ruleStatus === 'unverified'}
<Badge
variant="secondary"
type="error"
size="xs"
content="Certificate generation failed" />
{:else if verified === true}
<Badge variant="secondary" type="success" size="xs" content="Verified" />
{/if}
{/if}
</Layout.Stack>
<Typography.Text variant="m-400">
Add the following record on your DNS provider. Note that DNS changes may take time to
propagate fully.
Add the following {$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
? 'records'
: 'record'} on your DNS provider. Note that DNS changes may take up to 48 hours to propagate
fully.
</Typography.Text>
</Layout.Stack>

<Table.Root columns={3} let:root>
<Table.Root
columns={[
{ id: 'type', width: { min: 150 } },
{ id: 'name', width: { min: 80 } },
{ id: 'value', width: { min: 100 } }
]}
let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Type</Table.Header.Cell>
<Table.Header.Cell {root}>Name</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
<Table.Header.Cell column="type" {root}>Type</Table.Header.Cell>
<Table.Header.Cell column="name" {root}>Name</Table.Header.Cell>
<Table.Header.Cell column="value" {root}>Value</Table.Header.Cell>
</svelte:fragment>
<Table.Row.Base {root}>
<Table.Cell {root}>{variant.toUpperCase()}</Table.Cell>
<Table.Cell {root}>{subdomain || '@'}</Table.Cell>
<Table.Cell {root}>
<Table.Cell column="type" {root}>{variant.toUpperCase()}</Table.Cell>
<Table.Cell column="name" {root}>{subdomain || '@'}</Table.Cell>
<Table.Cell column="value" {root}>
<InteractiveText variant="copy" isVisible text={setTarget()} />
</Table.Cell>
</Table.Row.Base>
{#if $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}
<Table.Row.Base {root}>
<Table.Cell column="type" {root}>
<Layout.Stack gap="s" direction="row" alignItems="center">
<span>CAA</span>
<Badge variant="secondary" size="xs" content="Recommended" />
</Layout.Stack>
</Table.Cell>
<Table.Cell column="name" {root}>@</Table.Cell>
<Table.Cell column="value" {root}>
<InteractiveText variant="copy" isVisible text={caaText} />
</Table.Cell>
</Table.Row.Base>
{/if}
</Table.Root>
<Layout.Stack gap="s" direction="row" alignItems="center">
{#if variant === 'cname'}
<Alert.Inline>
If your domain uses CAA records, ensure certainly.com is authorized — otherwise, SSL
setup may fail. A list of all domain providers and their DNS setting is available <Link
variant="muted"
external
href="https://appwrite.io/docs/advanced/platform/custom-domains">here</Link
>.
</Alert.Inline>
{#if variant === 'cname' && !subdomain}
{#if isCloud}
<Alert.Inline>
Since <Badge variant="secondary" size="s" content={domain} /> is an apex domain, CNAME
record is only supported by certain providers. If yours doesn't, please verify using
<Link variant="muted" on:click={onNavigateToNameservers}>nameservers</Link> instead.
</Alert.Inline>
{:else if aTabVisible || aaaaTabVisible}
<Alert.Inline>
Since <Badge variant="secondary" size="s" content={domain} /> is an apex domain, CNAME
record is only supported by certain providers. If yours doesn't, please verify using
{#if aTabVisible}
<Link variant="muted" on:click={onNavigateToA}>A record</Link>
{#if aaaaTabVisible}
or <Link variant="muted" on:click={onNavigateToAAAA}>AAAA record</Link
>{/if}
{:else if aaaaTabVisible}
<Link variant="muted" on:click={onNavigateToAAAA}>AAAA record</Link>
{/if} instead.
</Alert.Inline>
{/if}
{:else}
<Typography.Text variant="m-400" color="--fgcolor-neutral-secondary">
A list of all domain providers and their DNS setting is available <Link
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/navbar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@
]} />

{#if dailyCredits !== null}
<Typography.Caption>
<Typography.Caption variant="400">
{dailyCredits} daily and {monthlyCredits} monthly
credits
</Typography.Caption>
Expand Down
9 changes: 9 additions & 0 deletions src/lib/helpers/tlds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,12 @@ export function isASubdomain(domain: string | null): boolean {

return !!subdomain;
}

/**
* Returns the subdomain part from a full domain string.
*/
export function getSubdomain(domain: string): string {
if (!domain) return '';

return parse(domain, { allowPrivateDomains: true }).subdomain || '';
}
14 changes: 10 additions & 4 deletions src/lib/studio/domains/add/view.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}: {
show: boolean;
siteId: string;
onDomainAdded: (rule: string, domain: Models.Domain, verified: boolean) => void;
onDomainAdded: (rule: Models.ProxyRule, domain: Models.Domain, verified: boolean) => void;
} = $props();

let domainName = $state('');
Expand Down Expand Up @@ -84,9 +84,15 @@
siteId
});

const verified = rule?.status === 'verified';
onDomainAdded(rule.$id, domain, verified);
if (verified) await invalidate(Dependencies.SITES_DOMAINS);
const verified = rule?.status !== 'created';
if (verified) {
await invalidate(Dependencies.SITES_DOMAINS);
addNotification({
type: 'success',
message: 'Domain verified successfully'
});
}
onDomainAdded(rule, domain, verified);

show = false;
} catch (error) {
Expand Down
43 changes: 31 additions & 12 deletions src/lib/studio/domains/manage/table.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,46 @@
</Table.Row.Base>
{/each}
{:else if proxyRules && proxyRules.total > 0}
{#each proxyRules.rules as rule}
{#each proxyRules.rules as proxyRule}
{@const isRetryable =
proxyRule.status === 'created' || proxyRule.status === 'unverified'}
<Table.Row.Base {root}>
<Table.Cell column="domain" {root}>
<Layout.Stack direction="row" gap="xs" alignItems="center">
<Link external variant="quiet" href={`${$regionalProtocol}${rule.domain}`}>
<Link
external
variant="quiet"
href={`${$regionalProtocol}${proxyRule.domain}`}>
<Layout.Stack direction="row" gap="xxs" alignItems="center">
<Typography.Text truncate>
{rule.domain}
{proxyRule.domain}
</Typography.Text>
<Icon size="xs" icon={IconExternalLink} />
</Layout.Stack>
</Link>

{#if rule.status === 'verifying'}
<Badge variant="secondary" content="Verifying" size="s" />
{:else if rule.status !== 'verified'}
{#if proxyRule.status !== 'verified'}
<Badge
size="s"
type="warning"
variant="secondary"
content="Verification failed" />
type={proxyRule.status === 'verifying' ? undefined : 'error'}
content={proxyRule.status === 'created'
? 'Verification failed'
: proxyRule.status === 'verifying'
? 'Generating certificate'
: 'Certificate generation failed'}
size="xs" />
{/if}
{#if isRetryable}
<Link
size="s"
variant="muted"
on:click={(e) => {
e.preventDefault();
selectedProxyRule = proxyRule;
showRetry = true;
}}>
Retry
</Link>
{/if}
</Layout.Stack>
</Table.Cell>
Expand All @@ -145,7 +164,7 @@
</Button>

<svelte:fragment slot="tooltip" let:toggle>
{@render domainActions(rule, toggle)}
{@render domainActions(proxyRule, toggle, isRetryable)}
</svelte:fragment>
</Popover>
</Table.Cell>
Expand All @@ -169,12 +188,12 @@
<RetryDomainModal bind:show={showRetry} {selectedProxyRule} />
{/if}

{#snippet domainActions(rule, toggle)}
{#snippet domainActions(rule, toggle, isRetryable)}
<ActionMenu.Root>
<ActionMenu.Item.Anchor href={`${$regionalProtocol}${rule.domain}`} external>
Open domain
</ActionMenu.Item.Anchor>
{#if rule.status !== 'verified' && rule.status !== 'verifying'}
{#if isRetryable}
<ActionMenu.Item.Button
leadingIcon={IconRefresh}
on:click={() => {
Expand Down
Loading
Loading