mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'feat-pink-v2' into 'clean-checks'.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
export const statusCodeOptions = [
|
||||
{
|
||||
label: '301 Moved permanently',
|
||||
value: 301
|
||||
},
|
||||
{
|
||||
label: '302 Found',
|
||||
value: 302
|
||||
},
|
||||
{
|
||||
label: '303 See other',
|
||||
value: 303
|
||||
},
|
||||
{
|
||||
label: '307 Temporary redirect',
|
||||
value: 307
|
||||
},
|
||||
{
|
||||
label: '308 Permanent redirect',
|
||||
value: 308
|
||||
}
|
||||
];
|
||||
@@ -3,41 +3,16 @@
|
||||
import { page } from '$app/stores';
|
||||
import { EmptySearch, PaginationWithLimit } from '$lib/components/index.js';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import Link from '$lib/elements/link.svelte';
|
||||
import Container from '$lib/layout/container.svelte';
|
||||
import { protocol } from '$routes/(console)/store.js';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import {
|
||||
IconDotsHorizontal,
|
||||
IconExternalLink,
|
||||
IconPlus,
|
||||
IconRefresh,
|
||||
IconTrash
|
||||
} from '@appwrite.io/pink-icons-svelte';
|
||||
import {
|
||||
ActionMenu,
|
||||
Card,
|
||||
Empty,
|
||||
Icon,
|
||||
Layout,
|
||||
Popover,
|
||||
Table
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import DeleteDomainModal from './deleteDomainModal.svelte';
|
||||
import RetryDomainModal from './retryDomainModal.svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Card, Empty, Icon, Layout } from '@appwrite.io/pink-svelte';
|
||||
import SearchQuery from '$lib/components/searchQuery.svelte';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { Click, trackEvent } from '$lib/actions/analytics';
|
||||
import CreatePreviewDomainModal from './createPreviewDomainModal.svelte';
|
||||
import type { Domain } from '$lib/sdk/domains.js';
|
||||
import Table from './table.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
let showDelete = false;
|
||||
let showRetry = false;
|
||||
let showPreviewDomainModal = false;
|
||||
let selectedDomain: Domain | Models.ProxyRule = null;
|
||||
|
||||
$: console.log(data.domains);
|
||||
</script>
|
||||
|
||||
@@ -57,80 +32,7 @@
|
||||
</Layout.Stack>
|
||||
|
||||
{#if data.domains.total}
|
||||
<Table.Root columns={4} let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell {root}>Domain</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Redirect to</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Production branch</Table.Header.Cell>
|
||||
<Table.Header.Cell {root} />
|
||||
</svelte:fragment>
|
||||
{#each data.domains.rules as domain}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>
|
||||
<Link external href={`${$protocol}${domain.domain}`} variant="quiet">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="xs">
|
||||
{domain.domain}
|
||||
<Icon icon={IconExternalLink} size="s" />
|
||||
</Layout.Stack>
|
||||
</Link>
|
||||
</Table.Cell>
|
||||
<!-- TODO design redirect status code -->
|
||||
<Table.Cell {root}>
|
||||
{domain?.redirectUrl || 'No redirect'}
|
||||
{domain?.redirectStatusCode ? `(${domain.redirectStatusCode})` : ''}
|
||||
</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
{domain.deploymentVcsProviderBranch || '-'}
|
||||
</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
<Popover let:toggle placement="bottom-start" padding="none">
|
||||
<Button
|
||||
text
|
||||
icon
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
toggle(e);
|
||||
}}>
|
||||
<Icon icon={IconDotsHorizontal} size="s" />
|
||||
</Button>
|
||||
|
||||
<svelte:fragment slot="tooltip" let:toggle>
|
||||
<ActionMenu.Root>
|
||||
{#if domain.status !== 'verified'}
|
||||
<ActionMenu.Item.Button
|
||||
leadingIcon={IconRefresh}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
selectedDomain = domain;
|
||||
showRetry = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Retry
|
||||
</ActionMenu.Item.Button>
|
||||
{/if}
|
||||
<ActionMenu.Item.Button
|
||||
status="danger"
|
||||
leadingIcon={IconTrash}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
selectedDomain = domain;
|
||||
showDelete = true;
|
||||
toggle(e);
|
||||
trackEvent(Click.DomainDeleteClick, {
|
||||
source: 'sites_domain_overview'
|
||||
});
|
||||
}}>
|
||||
Delete
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
<Table domains={data.domains} />
|
||||
|
||||
<PaginationWithLimit
|
||||
name="Domains"
|
||||
@@ -175,15 +77,3 @@
|
||||
</Card.Base>
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
{#if showDelete}
|
||||
<DeleteDomainModal bind:show={showDelete} {selectedDomain} />
|
||||
{/if}
|
||||
|
||||
{#if showRetry}
|
||||
<RetryDomainModal bind:show={showRetry} {selectedDomain} />
|
||||
{/if}
|
||||
|
||||
{#if showPreviewDomainModal}
|
||||
<CreatePreviewDomainModal bind:show={showPreviewDomainModal} />
|
||||
{/if}
|
||||
|
||||
+59
-136
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { Button, Form, InputSelect } from '$lib/elements/forms';
|
||||
import { Button, Form, InputDomain, InputSelect } from '$lib/elements/forms';
|
||||
import { Wizard } from '$lib/layout';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
@@ -19,31 +19,29 @@
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { sortBranches } from '$lib/stores/vcs';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { consoleVariables } from '$routes/(console)/store';
|
||||
import InputDomain from '$lib/elements/forms/inputDomain.svelte';
|
||||
import { consoleVariables, protocol } from '$routes/(console)/store';
|
||||
import { IconGlobeAlt, IconInfo } from '@appwrite.io/pink-icons-svelte';
|
||||
import { LabelCard } from '$lib/components';
|
||||
import { writable } from 'svelte/store';
|
||||
import ConnectRepoModal from '../../../(components)/connectRepoModal.svelte';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { onMount } from 'svelte';
|
||||
import { StatusCode } from '@appwrite.io/console';
|
||||
import VerificationFieldset from './verificationFieldset.svelte';
|
||||
import type { Domain } from '$lib/sdk/domains';
|
||||
import { statusCodeOptions } from '$lib/stores/domains';
|
||||
|
||||
const backPage = `${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains`;
|
||||
|
||||
export let data;
|
||||
|
||||
let formComponent: Form;
|
||||
let isSubmitting = writable(false);
|
||||
|
||||
let showConnectRepo = false;
|
||||
let behaviour: 'REDIRECT' | 'BRANCH' | 'ACTIVE' = 'ACTIVE';
|
||||
let step: 'add' | 'verify' = 'add';
|
||||
let domain = '';
|
||||
let domainName = '';
|
||||
let redirect: string = null;
|
||||
let statusCode: number = null;
|
||||
let branch = null;
|
||||
|
||||
let domainData: Domain;
|
||||
let selectedTab: 'cname' | 'nameserver';
|
||||
|
||||
const redirectOptions = data.domains.rules
|
||||
.filter((d) => !d.domain.endsWith($consoleVariables._APP_DOMAIN_SITES))
|
||||
.map((domain) => ({
|
||||
@@ -51,113 +49,48 @@
|
||||
value: domain.domain
|
||||
}));
|
||||
|
||||
const statusCodeOptions = [
|
||||
{
|
||||
label: '301 Moved permanently',
|
||||
value: 301
|
||||
},
|
||||
{
|
||||
label: '302 Found',
|
||||
value: 302
|
||||
},
|
||||
{
|
||||
label: '303 See other',
|
||||
value: 303
|
||||
},
|
||||
{
|
||||
label: '307 Temporary redirect',
|
||||
value: 307
|
||||
},
|
||||
{
|
||||
label: '308 Permanent redirect',
|
||||
value: 308
|
||||
}
|
||||
];
|
||||
|
||||
onMount(() => {
|
||||
if (
|
||||
$page.url.searchParams.has('connectRepo') &&
|
||||
$page.url.searchParams.get('connectRepo') === 'true'
|
||||
) {
|
||||
showConnectRepo = true;
|
||||
}
|
||||
});
|
||||
|
||||
async function addDomain() {
|
||||
const isPreviewDomain = domain.endsWith($consoleVariables._APP_DOMAIN_SITES);
|
||||
const isNewDomain = data.domains.rules.findIndex((rule) => rule.domain === domain) === -1;
|
||||
const isSubDomain = domain.split('.').length >= 2;
|
||||
const isNewDomain =
|
||||
data.domains.rules.findIndex((rule) => rule.domain === domainName) === -1;
|
||||
try {
|
||||
if (behaviour === 'CREATE') {
|
||||
if (isCloud && !isPreviewDomain) {
|
||||
//Redirect if subdomain so user can choose how to proceed
|
||||
if (isSubDomain) {
|
||||
goto(
|
||||
`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains/add-domain/verify?domain=${domain}`
|
||||
);
|
||||
}
|
||||
//Create domain if it's a new domain
|
||||
else if (isNewDomain) {
|
||||
const domainData = await sdk.forConsole.domains.create(
|
||||
$organization.$id,
|
||||
domain
|
||||
);
|
||||
await sdk.forProject.proxy.createSiteRule(
|
||||
domain,
|
||||
$page.params.site,
|
||||
branch
|
||||
);
|
||||
goto(
|
||||
`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains/add-domain/verify-${domainData.$id}}`
|
||||
);
|
||||
}
|
||||
}
|
||||
//if selfhosted or preview domain create site rule
|
||||
else {
|
||||
await sdk.forProject.proxy.createSiteRule(domain, $page.params.site, branch);
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: 'Domain added successfully'
|
||||
});
|
||||
await goto(backPage);
|
||||
await invalidate(Dependencies.SITES_DOMAINS);
|
||||
}
|
||||
} else if (behaviour === 'REDIRECT') {
|
||||
if (isCloud && !isPreviewDomain) {
|
||||
//Redirect if subdomain so user can choose how to proceed
|
||||
if (isSubDomain) {
|
||||
goto(
|
||||
`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains/add-domain/verify?domain=${domain}?redirect=${redirect}?statusCode=${statusCode}`
|
||||
);
|
||||
}
|
||||
//Create domain if it's a new domain
|
||||
else if (isNewDomain) {
|
||||
const domainData = await sdk.forConsole.domains.create(
|
||||
$organization.$id,
|
||||
domain
|
||||
);
|
||||
const sc = Object.values(StatusCode).find(
|
||||
(code) => parseInt(code) === statusCode
|
||||
);
|
||||
await sdk.forProject.proxy.createRedirectRule(domain, redirect, sc);
|
||||
|
||||
goto(
|
||||
`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains/add-domain/verify-${domainData.$id}}`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (isNewDomain && isCloud) {
|
||||
domainData = await sdk.forConsole.domains.create($organization.$id, domainName);
|
||||
}
|
||||
|
||||
if (behaviour === 'BRANCH') {
|
||||
await sdk.forProject.proxy.createSiteRule(domainName, $page.params.site, branch);
|
||||
} else if (behaviour === 'REDIRECT') {
|
||||
const sc = Object.values(StatusCode).find((code) => parseInt(code) === statusCode);
|
||||
console.log(statusCode, sc);
|
||||
await sdk.forProject.proxy.createRedirectRule(domainName, $protocol + redirect, sc);
|
||||
} else if (behaviour === 'ACTIVE') {
|
||||
await sdk.forProject.proxy.createSiteRule(domainName, $page.params.site);
|
||||
}
|
||||
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: 'Domain added successfully'
|
||||
});
|
||||
await goto(backPage);
|
||||
await invalidate(Dependencies.DOMAINS);
|
||||
await invalidate(Dependencies.SITES_DOMAINS);
|
||||
} catch (error) {
|
||||
await invalidate(Dependencies.DOMAINS);
|
||||
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: isVerified = domainData?.nameservers
|
||||
? domainData?.nameservers.toLocaleLowerCase() === 'appwrite'
|
||||
: undefined;
|
||||
</script>
|
||||
|
||||
<Wizard title="Add custom domain" href={backPage} column columnSize="s" hideFooter={step === 'add'}>
|
||||
<Form bind:this={formComponent} onSubmit={addDomain} bind:isSubmitting>
|
||||
<Form onSubmit={() => (step = 'verify')}>
|
||||
{#if step === 'add'}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Layout.Grid columns={3} columnsXS={1}>
|
||||
@@ -199,7 +132,7 @@
|
||||
<InputDomain
|
||||
label="Domain"
|
||||
id="domain"
|
||||
bind:value={domain}
|
||||
bind:value={domainName}
|
||||
required
|
||||
placeholder="appwrite.example.com" />
|
||||
|
||||
@@ -252,47 +185,37 @@
|
||||
{/if}
|
||||
<Divider />
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
<Button on:click={() => (step = 'verify')}>Add</Button>
|
||||
<Button submit>Add</Button>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
</Layout.Stack>
|
||||
{:else if step === 'verify'}
|
||||
<Card.Base radius="s" padding="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="xs">
|
||||
<Icon icon={IconGlobeAlt} color="--fgcolor-neutral-primary" />
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card.Base radius="s" padding="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="xs">
|
||||
<Icon icon={IconGlobeAlt} color="--fgcolor-neutral-primary" />
|
||||
|
||||
<Typography.Text variation="m-500" color="--fgcolor-neutral-primary">
|
||||
{domain}
|
||||
</Typography.Text>
|
||||
<Typography.Text variation="m-500" color="--fgcolor-neutral-primary">
|
||||
{domainName}
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<Button secondary on:click={() => (step = 'add')}>Change</Button>
|
||||
</Layout.Stack>
|
||||
<Button
|
||||
secondary
|
||||
href={`${base}/project-${$page.params.project}/sites/create-site/repositories`}>
|
||||
Change
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
</Card.Base>
|
||||
|
||||
<VerificationFieldset domain={domainName} verified={isVerified} bind:selectedTab />
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Form>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary href={backPage}>Cancel</Button>
|
||||
<Button on:click={() => formComponent.triggerSubmit()} bind:disabled={$isSubmitting}>
|
||||
Verify
|
||||
</Button>
|
||||
<Button on:click={addDomain}>Verify</Button>
|
||||
</svelte:fragment>
|
||||
</Wizard>
|
||||
|
||||
{#if showConnectRepo}
|
||||
<ConnectRepoModal
|
||||
bind:show={showConnectRepo}
|
||||
site={data.site}
|
||||
onlyExisting
|
||||
callbackState={{ connectRepo: 'true' }} />
|
||||
{/if}
|
||||
|
||||
+3
-1
@@ -1,9 +1,11 @@
|
||||
import { Query } from '@appwrite.io/console';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { RuleTrigger, RuleType } from '$lib/stores/sdk';
|
||||
import { Dependencies } from '$lib/constants.js';
|
||||
|
||||
export const load = async ({ parent }) => {
|
||||
export const load = async ({ parent, depends }) => {
|
||||
const { site } = await parent();
|
||||
depends(Dependencies.DOMAINS);
|
||||
|
||||
const [domains, installations] = await Promise.all([
|
||||
sdk.forProject.proxy.listRules([
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
<script lang="ts">
|
||||
import { Link } from '$lib/elements';
|
||||
import { consoleVariables } from '$routes/(console)/store';
|
||||
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
|
||||
import {
|
||||
Badge,
|
||||
Divider,
|
||||
Fieldset,
|
||||
Icon,
|
||||
InteractiveText,
|
||||
Layout,
|
||||
Table,
|
||||
Tabs,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let domain: string;
|
||||
export let verified: boolean;
|
||||
|
||||
const nameserverList = $consoleVariables?._APP_DOMAINS_NAMESERVERS
|
||||
? $consoleVariables?._APP_DOMAINS_NAMESERVERS.split(',')
|
||||
: ['ns1.appwrite.io', 'ns2.appwrite.io'];
|
||||
|
||||
$: isSubDomain = domain?.split('.')?.length >= 3;
|
||||
export let selectedTab: 'cname' | 'nameserver' = isSubDomain ? 'cname' : 'nameserver';
|
||||
</script>
|
||||
|
||||
<Fieldset legend="Verification">
|
||||
<Layout.Stack gap="xl">
|
||||
<div>
|
||||
<Tabs.Root variant="secondary" let:root>
|
||||
{#if isSubDomain}
|
||||
<Tabs.Item.Button
|
||||
{root}
|
||||
on:click={() => (selectedTab = 'cname')}
|
||||
active={selectedTab === 'cname'}>
|
||||
CNAME
|
||||
</Tabs.Item.Button>
|
||||
{/if}
|
||||
|
||||
<Tabs.Item.Button
|
||||
{root}
|
||||
on:click={() => (selectedTab = 'nameserver')}
|
||||
active={selectedTab === 'nameserver'}>
|
||||
Nameservers
|
||||
</Tabs.Item.Button>
|
||||
</Tabs.Root>
|
||||
<Divider />
|
||||
</div>
|
||||
{#if selectedTab === 'cname' && isSubDomain}
|
||||
<Layout.Stack gap="s">
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Typography.Text variant="l-500" color="--fgcolor-neutral-primary">
|
||||
{domain}
|
||||
</Typography.Text>
|
||||
{#if verified}
|
||||
<Badge variant="secondary" type="success" content="Verified" />
|
||||
{:else if verified === false}
|
||||
<Badge variant="secondary" type="error" content="Verification failed" />
|
||||
{:else}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
type="warning"
|
||||
size="xs"
|
||||
content="Pending verification" />
|
||||
{/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.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<Table.Root columns={3} 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>
|
||||
</svelte:fragment>
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>CNAME</Table.Cell>
|
||||
<Table.Cell {root}>{domain}</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<InteractiveText
|
||||
variant="copy"
|
||||
isVisible
|
||||
text={globalThis?.location?.origin}>
|
||||
{globalThis?.location?.origin}</InteractiveText>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
</Table.Root>
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Icon icon={IconInfo} size="s" color="--fgcolor-neutral-secondary" />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-secondary">
|
||||
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
|
||||
>.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
<Layout.Stack gap="s">
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Typography.Text variant="l-500" color="--fgcolor-neutral-primary"
|
||||
>{domain}</Typography.Text>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
type="warning"
|
||||
size="xs"
|
||||
content="Pending verification" />
|
||||
</Layout.Stack>
|
||||
<Typography.Text variant="m-400">
|
||||
Add the following nameservers on your DNS provider. Note that DNS changes may
|
||||
take time to propagate fully.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<Table.Root columns={2} let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell {root}>Type</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Value</Table.Header.Cell>
|
||||
</svelte:fragment>
|
||||
{#each nameserverList as nameserver}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>NS</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<InteractiveText variant="copy" isVisible text={nameserver}>
|
||||
{nameserver}</InteractiveText>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
-182
@@ -1,182 +0,0 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
Badge,
|
||||
Divider,
|
||||
Fieldset,
|
||||
Icon,
|
||||
InteractiveText,
|
||||
Layout,
|
||||
Table,
|
||||
Tabs,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { Card } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Wizard } from '$lib/layout';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Link } from '$lib/elements';
|
||||
import { consoleVariables } from '$routes/(console)/store';
|
||||
|
||||
const backPage = `${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains`;
|
||||
|
||||
let nameservers = $consoleVariables?._APP_DOMAINS_NAMESERVERS
|
||||
? $consoleVariables?._APP_DOMAINS_NAMESERVERS.split(',')
|
||||
: ['ns1.appwrite.io', 'ns2.appwrite.io'];
|
||||
|
||||
export let data;
|
||||
async function verifyStatus() {
|
||||
try {
|
||||
await sdk.forProject.proxy.updateRuleVerification(data.domain.$id);
|
||||
console.log(data.domain);
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let selectedTab: 'cname' | 'nameserver' = 'cname';
|
||||
|
||||
$: isVerified = data.domain?.nameservers?.toLocaleLowerCase() === 'appwrite';
|
||||
</script>
|
||||
|
||||
<Wizard title="Add custom domain" href={backPage} column columnSize="s" hideFooter>
|
||||
{#if isVerified}
|
||||
<Card radius="s">
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Typography.Text variant="l-500">{data.domain.domain}</Typography.Text>
|
||||
<Badge variant="secondary" type="success" content="Verified" />
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
{:else}
|
||||
<Fieldset legend="Verification">
|
||||
<Layout.Stack gap="xl">
|
||||
<div>
|
||||
<Tabs.Root variant="secondary" let:root>
|
||||
<Tabs.Item.Button
|
||||
{root}
|
||||
on:click={() => (selectedTab = 'cname')}
|
||||
active={selectedTab === 'cname'}>
|
||||
CNAME
|
||||
</Tabs.Item.Button>
|
||||
<Tabs.Item.Button
|
||||
{root}
|
||||
on:click={() => (selectedTab = 'nameserver')}
|
||||
active={selectedTab === 'nameserver'}>
|
||||
Nameservers
|
||||
</Tabs.Item.Button>
|
||||
</Tabs.Root>
|
||||
<Divider />
|
||||
</div>
|
||||
{#if selectedTab === 'cname'}
|
||||
<Layout.Stack gap="s">
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Typography.Text variant="l-500" color="--fgcolor-neutral-primary"
|
||||
>{data.domain?.domain}</Typography.Text>
|
||||
{#if isVerified}
|
||||
<Badge variant="secondary" type="success" content="Verified" />
|
||||
{:else}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
type="warning"
|
||||
size="xs"
|
||||
content="Pending verification" />
|
||||
{/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.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<Table.Root columns={3} 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>
|
||||
</svelte:fragment>
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>CNAME</Table.Cell>
|
||||
<Table.Cell {root}>{data.domain?.domain}</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<InteractiveText
|
||||
variant="copy"
|
||||
isVisible
|
||||
text={globalThis?.location?.origin}>
|
||||
{globalThis?.location?.origin}</InteractiveText>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
</Table.Root>
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Icon icon={IconInfo} size="s" color="--fgcolor-neutral-secondary" />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-secondary">
|
||||
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
|
||||
>.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<Divider />
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
<Button on:click={verifyStatus}>Verify</Button>
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
<Layout.Stack gap="s">
|
||||
<Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Typography.Text variant="l-500" color="--fgcolor-neutral-primary"
|
||||
>{data.domain?.domain}</Typography.Text>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
type="warning"
|
||||
size="xs"
|
||||
content="Pending verification" />
|
||||
</Layout.Stack>
|
||||
<Typography.Text variant="m-400">
|
||||
Add the following nameservers on your DNS provider. Note that DNS
|
||||
changes may take time to propagate fully.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<Table.Root columns={2} let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell {root}>Type</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Value</Table.Header.Cell>
|
||||
</svelte:fragment>
|
||||
{#each nameservers as nameserver}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>NS</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<InteractiveText variant="copy" isVisible text={nameserver}>
|
||||
{nameserver}</InteractiveText>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
<!-- <Layout.Stack gap="s" direction="row" alignItems="center">
|
||||
<Icon icon={IconInfo} size="s" color="--fgcolor-neutral-secondary" />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-secondary">
|
||||
A list of all domain providers and their DNS setting is available <Link
|
||||
variant="muted"
|
||||
href="https://appwrite.io/docs/advanced/platform/custom-domains"
|
||||
>here</Link
|
||||
>.
|
||||
</Typography.Text>
|
||||
</Layout.Stack> -->
|
||||
|
||||
<Divider />
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
<Button on:click={verifyStatus}>Verify</Button>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Wizard>
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
// import { sdk } from '$lib/stores/sdk';
|
||||
import { isCloud } from '$lib/system';
|
||||
|
||||
export const load = async (/*{ params }*/) => {
|
||||
if (isCloud) {
|
||||
// if (params?.id) {
|
||||
// return {
|
||||
// domain: await sdk.forConsole.domains.get(params.id)
|
||||
// };
|
||||
// }
|
||||
} else {
|
||||
return {
|
||||
domain: undefined
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { Column } from '$lib/helpers/types';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const columns = writable<Column[]>([
|
||||
{
|
||||
id: 'domain',
|
||||
title: 'Domain',
|
||||
type: 'string',
|
||||
format: 'string',
|
||||
width: { min: 120, max: 400 }
|
||||
},
|
||||
|
||||
{
|
||||
id: 'redirectUrl',
|
||||
title: 'Redirect to',
|
||||
type: 'string',
|
||||
width: { min: 120, max: 200 }
|
||||
},
|
||||
{
|
||||
id: 'deploymentVcsProviderBranch',
|
||||
title: 'Production branch',
|
||||
type: 'string',
|
||||
width: { min: 70, max: 150 }
|
||||
}
|
||||
]);
|
||||
@@ -0,0 +1,110 @@
|
||||
<script lang="ts">
|
||||
import { Click, trackEvent } from '$lib/actions/analytics';
|
||||
import { Link } from '$lib/elements';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { protocol } from '$routes/(console)/store';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { IconDotsHorizontal, IconRefresh, IconTrash } from '@appwrite.io/pink-icons-svelte';
|
||||
import { ActionMenu, Icon, Layout, Popover, Table, Typography } from '@appwrite.io/pink-svelte';
|
||||
import DeleteDomainModal from './deleteDomainModal.svelte';
|
||||
import RetryDomainModal from './retryDomainModal.svelte';
|
||||
import CreatePreviewDomainModal from './createPreviewDomainModal.svelte';
|
||||
import { columns } from './store';
|
||||
|
||||
export let domains: Models.ProxyRuleList;
|
||||
|
||||
let showDelete = false;
|
||||
let showRetry = false;
|
||||
let selectedDomain: Models.ProxyRule = null;
|
||||
let showPreviewDomainModal = false;
|
||||
</script>
|
||||
|
||||
<Table.Root columns={[...$columns, { id: 'actions', width: 40 }]} let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
{#each $columns as { id, title }}
|
||||
<Table.Header.Cell column={id} {root}>
|
||||
{title}
|
||||
</Table.Header.Cell>
|
||||
{/each}
|
||||
<Table.Header.Cell column="actions" {root} />
|
||||
</svelte:fragment>
|
||||
{#each domains.rules as domain}
|
||||
<Table.Row.Base {root}>
|
||||
{#each $columns as column}
|
||||
<Table.Cell column={column.id} {root}>
|
||||
{#if column.id === 'domain'}
|
||||
<Link external href={`${$protocol}${domain.domain}`} variant="quiet" icon>
|
||||
<Typography.Text truncate>
|
||||
{domain.domain}
|
||||
</Typography.Text>
|
||||
</Link>
|
||||
{:else if column.id === 'redirectUrl'}
|
||||
<!-- TODO design redirect status code -->
|
||||
{domain?.redirectUrl || 'No redirect'}
|
||||
{domain?.redirectStatusCode ? `(${domain.redirectStatusCode})` : ''}
|
||||
{:else if column.id === 'deploymentVcsProviderBranch'}
|
||||
{domain.deploymentVcsProviderBranch || '-'}
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
<Table.Cell column="actions" {root}>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
<Popover let:toggle placement="bottom-start" padding="none">
|
||||
<Button
|
||||
text
|
||||
icon
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
toggle(e);
|
||||
}}>
|
||||
<Icon icon={IconDotsHorizontal} size="s" />
|
||||
</Button>
|
||||
|
||||
<svelte:fragment slot="tooltip" let:toggle>
|
||||
<ActionMenu.Root>
|
||||
{#if domain.status !== 'verified'}
|
||||
<ActionMenu.Item.Button
|
||||
leadingIcon={IconRefresh}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
selectedDomain = domain;
|
||||
showRetry = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Retry
|
||||
</ActionMenu.Item.Button>
|
||||
{/if}
|
||||
<ActionMenu.Item.Button
|
||||
status="danger"
|
||||
leadingIcon={IconTrash}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
selectedDomain = domain;
|
||||
showDelete = true;
|
||||
toggle(e);
|
||||
trackEvent(Click.DomainDeleteClick, {
|
||||
source: 'sites_domain_overview'
|
||||
});
|
||||
}}>
|
||||
Delete
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
|
||||
{#if showDelete}
|
||||
<DeleteDomainModal bind:show={showDelete} {selectedDomain} />
|
||||
{/if}
|
||||
|
||||
{#if showRetry}
|
||||
<RetryDomainModal bind:show={showRetry} {selectedDomain} />
|
||||
{/if}
|
||||
|
||||
{#if showPreviewDomainModal}
|
||||
<CreatePreviewDomainModal bind:show={showPreviewDomainModal} />
|
||||
{/if}
|
||||
@@ -11,13 +11,14 @@
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Card, Trim } from '$lib/components';
|
||||
import { Click, trackEvent } from '$lib/actions/analytics';
|
||||
import { RuleTrigger } from '$lib/stores/sdk';
|
||||
|
||||
export let proxyRuleList: Models.ProxyRuleList;
|
||||
|
||||
let showDomainQR = false;
|
||||
let selectedDomainURL: string;
|
||||
|
||||
$: rules = proxyRuleList?.rules?.filter((rule) => rule.trigger === 'manual') ?? [];
|
||||
$: rules = proxyRuleList?.rules?.filter((rule) => rule.trigger === RuleTrigger.MANUAL) ?? [];
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
|
||||
Reference in New Issue
Block a user