mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' into supposed-improvements
This commit is contained in:
+1
-1
@@ -26,7 +26,7 @@
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@appwrite.io/pink-icons-svelte": "^2.0.0-RC.1",
|
||||
"@appwrite.io/pink-legacy": "^1.0.3",
|
||||
"@appwrite.io/pink-svelte": "https://try-module.cloud/-/@appwrite/@appwrite.io/pink-svelte@d74b893",
|
||||
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@d7e3b86",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/sveltekit": "^8.38.0",
|
||||
"@stripe/stripe-js": "^3.5.0",
|
||||
|
||||
Generated
+5
-5
@@ -24,8 +24,8 @@ importers:
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3
|
||||
'@appwrite.io/pink-svelte':
|
||||
specifier: https://try-module.cloud/-/@appwrite/@appwrite.io/pink-svelte@d74b893
|
||||
version: https://try-module.cloud/-/@appwrite/%40appwrite.io%2Fpink-svelte@d74b893(svelte@5.25.3)
|
||||
specifier: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@d7e3b86
|
||||
version: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@d7e3b86(svelte@5.25.3)
|
||||
'@popperjs/core':
|
||||
specifier: ^2.11.8
|
||||
version: 2.11.8
|
||||
@@ -281,8 +281,8 @@ packages:
|
||||
'@appwrite.io/pink-legacy@1.0.3':
|
||||
resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==}
|
||||
|
||||
'@appwrite.io/pink-svelte@https://try-module.cloud/-/@appwrite/%40appwrite.io%2Fpink-svelte@d74b893':
|
||||
resolution: {tarball: https://try-module.cloud/-/@appwrite/%40appwrite.io%2Fpink-svelte@d74b893}
|
||||
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@d7e3b86':
|
||||
resolution: {tarball: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@d7e3b86}
|
||||
version: 2.0.0-RC.2
|
||||
peerDependencies:
|
||||
svelte: ^4.0.0
|
||||
@@ -3654,7 +3654,7 @@ snapshots:
|
||||
'@appwrite.io/pink-icons': 1.0.0
|
||||
the-new-css-reset: 1.11.3
|
||||
|
||||
'@appwrite.io/pink-svelte@https://try-module.cloud/-/@appwrite/%40appwrite.io%2Fpink-svelte@d74b893(svelte@5.25.3)':
|
||||
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@d7e3b86(svelte@5.25.3)':
|
||||
dependencies:
|
||||
'@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3)
|
||||
'@floating-ui/dom': 1.6.13
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import type { Coupon } from '$lib/sdk/billing';
|
||||
import { formatCurrency } from '$lib/helpers/numbers';
|
||||
import { IconTag } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Badge, Icon, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let label: string;
|
||||
export let value: number;
|
||||
export let couponData: Partial<Coupon> = {
|
||||
code: null,
|
||||
status: null,
|
||||
credits: null
|
||||
};
|
||||
|
||||
let adjustedValue = value;
|
||||
|
||||
$: if (label?.toLowerCase() === 'credits' && couponData?.status === 'active') {
|
||||
adjustedValue = value - (couponData?.credits || 0);
|
||||
} else {
|
||||
adjustedValue = value;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if adjustedValue > 0}
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack inline direction="row" gap="xxs" alignItems="center" alignContent="center">
|
||||
<Icon icon={IconTag} color="--fgcolor-success" size="s" />
|
||||
<Typography.Text color="--fgcolor-neutral-primary">{label}</Typography.Text>
|
||||
</Layout.Stack>
|
||||
{#if value >= 100}
|
||||
<Badge variant="secondary" content="Credits applied" />
|
||||
{:else}
|
||||
<Typography.Text color="--fgcolor-success"
|
||||
>-{formatCurrency(adjustedValue)}</Typography.Text>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
@@ -7,6 +7,7 @@
|
||||
import { CreditsApplied } from '.';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { AppwriteException } from '@appwrite.io/console';
|
||||
import DiscountsApplied from './discountsApplied.svelte';
|
||||
|
||||
export let billingPlan: Tier;
|
||||
export let collaborators: string[];
|
||||
@@ -35,7 +36,8 @@
|
||||
if (
|
||||
e.type === 'billing_coupon_not_found' ||
|
||||
e.type === 'billing_coupon_already_used' ||
|
||||
e.type === 'billing_credit_unsupported'
|
||||
e.type === 'billing_credit_unsupported' ||
|
||||
e.type === 'billing_coupon_not_eligible'
|
||||
) {
|
||||
couponData = {
|
||||
code: null,
|
||||
@@ -65,7 +67,8 @@
|
||||
if (
|
||||
e.type === 'billing_coupon_not_found' ||
|
||||
e.type === 'billing_coupon_already_used' ||
|
||||
e.type === 'billing_credit_unsupported'
|
||||
e.type === 'billing_credit_unsupported' ||
|
||||
e.type === 'billing_coupon_not_eligible'
|
||||
) {
|
||||
couponData = {
|
||||
code: null,
|
||||
@@ -80,13 +83,6 @@
|
||||
$: organizationId
|
||||
? getUpdatePlanEstimate(organizationId, billingPlan, collaborators, couponData?.code)
|
||||
: getEstimate(billingPlan, collaborators, couponData?.code);
|
||||
|
||||
$: estimatedTotal =
|
||||
couponData?.status === 'active'
|
||||
? estimation?.grossAmount - couponData.credits >= 0
|
||||
? estimation?.grossAmount - couponData.credits
|
||||
: 0
|
||||
: estimation?.grossAmount;
|
||||
</script>
|
||||
|
||||
{#if estimation}
|
||||
@@ -102,6 +98,9 @@
|
||||
>{formatCurrency(item.value)}</Typography.Text>
|
||||
</Layout.Stack>
|
||||
{/each}
|
||||
{#each estimation.discounts ?? [] as item}
|
||||
<DiscountsApplied {couponData} {...item} />
|
||||
{/each}
|
||||
|
||||
{#if couponData?.status === 'active'}
|
||||
<CreditsApplied bind:couponData {fixedCoupon} />
|
||||
@@ -110,15 +109,15 @@
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Typography.Text>Total due</Typography.Text>
|
||||
<Typography.Text>
|
||||
{formatCurrency(estimatedTotal)}
|
||||
{formatCurrency(estimation.grossAmount)}
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<Typography.Text>
|
||||
You'll pay <b>{formatCurrency(estimatedTotal)}</b>
|
||||
You'll pay <b>{formatCurrency(estimation.grossAmount)}</b>
|
||||
now.
|
||||
{#if couponData?.code}Once your credits run out,{:else}Then{/if} you'll be charged
|
||||
<b>{formatCurrency(estimation.grossAmount)}</b> every 30 days.
|
||||
<b>{formatCurrency(estimation.amount)}</b> every 30 days.
|
||||
</Typography.Text>
|
||||
|
||||
<InputChoice
|
||||
|
||||
@@ -97,7 +97,11 @@
|
||||
<Layout.Stack gap="s" alignContent="flex-start">
|
||||
<!-- `Raw time` as per design -->
|
||||
<Typography.Caption color="--fgcolor-neutral-tertiary" variant="400">
|
||||
{timeToString}
|
||||
{#if $$slots.title}
|
||||
<slot name="title" />
|
||||
{:else}
|
||||
{timeToString}
|
||||
{/if}
|
||||
</Typography.Caption>
|
||||
|
||||
<!-- `Absolute time` as per design -->
|
||||
|
||||
@@ -129,5 +129,10 @@
|
||||
bind:value={expirationSelect} />
|
||||
|
||||
{#if expirationSelect === 'custom'}
|
||||
<InputDateTime required id="expire" label={dateSelectorLabel} bind:value={expirationCustom} />
|
||||
<InputDateTime
|
||||
required
|
||||
type="date"
|
||||
id="expire"
|
||||
label={dateSelectorLabel}
|
||||
bind:value={expirationCustom} />
|
||||
{/if}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { repositories } from '$routes/(console)/project-[region]-[project]/functions/function-[function]/store';
|
||||
import { installation, installations, repository } from '$lib/stores/vcs';
|
||||
import { isSmallViewport } from '$lib/stores/viewport';
|
||||
import {
|
||||
Layout,
|
||||
Table,
|
||||
@@ -49,7 +50,9 @@
|
||||
async function loadInstallations() {
|
||||
if (installationList) {
|
||||
if (installationList.installations.length) {
|
||||
untrack(() => (selectedInstallation = installationList.installations[0].$id));
|
||||
if (!selectedInstallation) {
|
||||
untrack(() => (selectedInstallation = installationList.installations[0].$id));
|
||||
}
|
||||
installation.set(
|
||||
installationList.installations.find(
|
||||
(entry) => entry.$id === selectedInstallation
|
||||
@@ -62,7 +65,9 @@
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.vcs.listInstallations();
|
||||
if (installations.length) {
|
||||
untrack(() => (selectedInstallation = installations[0].$id));
|
||||
if (!selectedInstallation) {
|
||||
untrack(() => (selectedInstallation = installationList.installations[0].$id));
|
||||
}
|
||||
installation.set(installations.find((entry) => entry.$id === selectedInstallation));
|
||||
}
|
||||
return installations;
|
||||
@@ -133,7 +138,7 @@
|
||||
<InputSearch placeholder="Search repositories" disabled />
|
||||
</Layout.Stack>
|
||||
{:then installations}
|
||||
<Layout.Stack direction="row">
|
||||
<Layout.Stack direction={$isSmallViewport ? 'column' : 'row'}>
|
||||
<InputSelect
|
||||
id="installation"
|
||||
options={[
|
||||
@@ -233,39 +238,43 @@
|
||||
<Layout.Stack
|
||||
gap="s"
|
||||
direction="row"
|
||||
alignItems="center">
|
||||
<Typography.Text
|
||||
truncate
|
||||
color="--fgcolor-neutral-secondary">
|
||||
{repo.name}
|
||||
</Typography.Text>
|
||||
{#if repo.private}
|
||||
<Icon
|
||||
size="s"
|
||||
icon={IconLockClosed}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
{/if}
|
||||
<time datetime={repo.pushedAt}>
|
||||
<Typography.Caption
|
||||
variant="400"
|
||||
truncate
|
||||
color="--fgcolor-neutral-tertiary">
|
||||
{timeFromNow(repo.pushedAt)}
|
||||
</Typography.Caption>
|
||||
</time>
|
||||
</Layout.Stack>
|
||||
{#if action === 'button'}
|
||||
alignItems="center"
|
||||
justifyContent="space-between">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="flex-end">
|
||||
gap="s"
|
||||
alignItems="center">
|
||||
<Typography.Text
|
||||
truncate
|
||||
color="--fgcolor-neutral-secondary">
|
||||
{repo.name}
|
||||
</Typography.Text>
|
||||
{#if repo.private}
|
||||
<Icon
|
||||
size="s"
|
||||
icon={IconLockClosed}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
{/if}
|
||||
{#if !$isSmallViewport}
|
||||
<time datetime={repo.pushedAt}>
|
||||
<Typography.Caption
|
||||
variant="400"
|
||||
truncate
|
||||
color="--fgcolor-neutral-tertiary">
|
||||
{timeFromNow(repo.pushedAt)}
|
||||
</Typography.Caption>
|
||||
</time>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{#if action === 'button'}
|
||||
<PinkButton.Button
|
||||
size="xs"
|
||||
variant="secondary"
|
||||
on:click={() => connect(repo)}>
|
||||
Connect
|
||||
</PinkButton.Button>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
const none = undefined as never;
|
||||
|
||||
// function pagination(page: number, total: number) {
|
||||
// const pagesShown = 5;
|
||||
// const start = Math.max(
|
||||
@@ -56,11 +58,11 @@
|
||||
{#if !hidePages}
|
||||
<Pagination
|
||||
{limit}
|
||||
page={currentPage}
|
||||
{total}
|
||||
type="button"
|
||||
on:page={handleOptionClick}
|
||||
createLink={undefined as never} />
|
||||
createLink={none}
|
||||
page={currentPage}
|
||||
on:page={handleOptionClick} />
|
||||
{:else}
|
||||
<Layout.Stack direction="row" inline>
|
||||
<Button.Button
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
Layout,
|
||||
Link,
|
||||
Selector,
|
||||
Spinner,
|
||||
Table,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
@@ -24,9 +25,10 @@
|
||||
|
||||
let search = '';
|
||||
let offset = 0;
|
||||
let results: Models.TeamList<Record<string, unknown>>;
|
||||
let selected: Set<string> = new Set();
|
||||
let isLoading = false;
|
||||
let hasSelection = false;
|
||||
let selected: Set<string> = new Set();
|
||||
let results: Models.TeamList<Record<string, unknown>>;
|
||||
|
||||
function reset() {
|
||||
offset = 0;
|
||||
@@ -41,9 +43,11 @@
|
||||
|
||||
async function request() {
|
||||
if (!show) return;
|
||||
isLoading = true;
|
||||
results = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.teams.list([Query.limit(5), Query.offset(offset)], search || undefined);
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
function onSelection(role: string) {
|
||||
@@ -71,23 +75,24 @@
|
||||
</script>
|
||||
|
||||
<Modal title="Select teams" bind:show onSubmit={create} on:close={reset}>
|
||||
<Typography.Text
|
||||
<Typography.Text slot="description"
|
||||
>Grant access to any member of a specific team. To grant access to team members with
|
||||
specific roles, you will need to set a <Link.Button on:click={() => dispatch('custom')}
|
||||
>custom permission</Link.Button
|
||||
>.</Typography.Text>
|
||||
<InputSearch autofocus placeholder="Search by name or ID" bind:value={search} />
|
||||
{#if results?.teams?.length}
|
||||
<Table.Root columns={[{ id: 'checkbox', width: 40 }, { id: 'team' }]} let:root>
|
||||
<Table.Root columns={[{ id: 'checkbox', width: 20 }, { id: 'team' }]} let:root>
|
||||
{#each results.teams as team (team.$id)}
|
||||
{@const role = `team:${team.$id}`}
|
||||
{@const exists = $groups.has(role)}
|
||||
<Table.Row.Button {root} on:click={() => onSelection(role)} disabled={exists}>
|
||||
<Table.Cell column="checkbox" {root}>
|
||||
<Selector.Checkbox
|
||||
size="s"
|
||||
id={team.$id}
|
||||
checked={exists || selected.has(role)}
|
||||
disabled={exists} />
|
||||
disabled={exists}
|
||||
checked={exists || selected.has(role)} />
|
||||
</Table.Cell>
|
||||
<Table.Cell column="team" {root}>
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
@@ -105,10 +110,16 @@
|
||||
</Table.Row.Button>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
|
||||
<Layout.Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<p class="text">Total results: {results?.total}</p>
|
||||
<PaginationInline limit={5} bind:offset total={results?.total} hidePages />
|
||||
</div>
|
||||
<PaginationInline
|
||||
limit={5}
|
||||
bind:offset
|
||||
total={results?.total}
|
||||
hidePages
|
||||
on:change={request} />
|
||||
</Layout.Stack>
|
||||
{:else if search}
|
||||
<EmptySearch bind:search target="teams" hidePages>
|
||||
<Button
|
||||
@@ -119,6 +130,11 @@
|
||||
size="s">Documentation</Button>
|
||||
<Button secondary on:click={() => (search = '')}>Clear search</Button>
|
||||
</EmptySearch>
|
||||
{:else if isLoading}
|
||||
<!-- 275px nearly matches the height of at-least 5 items in the table above -->
|
||||
<div style:margin-inline="auto" style:min-height="275px" style:align-content="center">
|
||||
<Spinner size="m" />
|
||||
</div>
|
||||
{:else}
|
||||
<Card.Base padding="none">
|
||||
<Empty title="You have no teams. Create a team to see them here." type="secondary">
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
Layout,
|
||||
Link,
|
||||
Selector,
|
||||
Spinner,
|
||||
Table,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
@@ -27,9 +28,10 @@
|
||||
|
||||
let search = '';
|
||||
let offset = 0;
|
||||
let results: Models.UserList<Record<string, unknown>>;
|
||||
let selected: Set<string> = new Set();
|
||||
let isLoading = false;
|
||||
let hasSelection = false;
|
||||
let selected: Set<string> = new Set();
|
||||
let results: Models.UserList<Record<string, unknown>>;
|
||||
|
||||
function reset() {
|
||||
offset = 0;
|
||||
@@ -44,9 +46,11 @@
|
||||
|
||||
async function request() {
|
||||
if (!show) return;
|
||||
isLoading = true;
|
||||
results = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.users.list([Query.limit(5), Query.offset(offset)], search || undefined);
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
function onSelection(role: string) {
|
||||
@@ -74,8 +78,11 @@
|
||||
</script>
|
||||
|
||||
<Modal title="Select users" bind:show onSubmit={create} on:close={reset}>
|
||||
<Typography.Text>Grant access to any authenticated or anonymous user.</Typography.Text>
|
||||
<Typography.Text slot="description"
|
||||
>Grant access to any authenticated or anonymous user.</Typography.Text>
|
||||
|
||||
<InputSearch autofocus placeholder="Search by name, email, phone or ID" bind:value={search} />
|
||||
|
||||
{#if results?.users?.length}
|
||||
<Table.Root columns={[{ id: 'checkbox', width: 40 }, { id: 'user' }]} let:root>
|
||||
{#each results.users as user (user.$id)}
|
||||
@@ -86,8 +93,8 @@
|
||||
<Selector.Checkbox
|
||||
size="s"
|
||||
id={user.$id}
|
||||
checked={exists || selected.has(role)}
|
||||
disabled={exists} />
|
||||
disabled={exists}
|
||||
checked={exists || selected.has(role)} />
|
||||
</Table.Cell>
|
||||
<Table.Cell column="user" {root}>
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
@@ -141,7 +148,12 @@
|
||||
|
||||
<Layout.Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<p class="text">Total results: {results?.total}</p>
|
||||
<PaginationInline limit={5} bind:offset total={results?.total} hidePages />
|
||||
<PaginationInline
|
||||
limit={5}
|
||||
bind:offset
|
||||
total={results?.total}
|
||||
hidePages
|
||||
on:change={request} />
|
||||
</Layout.Stack>
|
||||
{:else if search}
|
||||
<EmptySearch bind:search target="users" hidePages>
|
||||
@@ -153,6 +165,11 @@
|
||||
size="s">Documentation</Button>
|
||||
<Button secondary on:click={() => (search = '')}>Clear search</Button>
|
||||
</EmptySearch>
|
||||
{:else if isLoading}
|
||||
<!-- 275px nearly matches the height of at-least 5 items in the table above -->
|
||||
<div style:margin-inline="auto" style:min-height="275px" style:align-content="center">
|
||||
<Spinner size="m" />
|
||||
</div>
|
||||
{:else}
|
||||
<Card.Base padding="none">
|
||||
<Empty title="You have no users. Create a user to see them here." type="secondary">
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
export let autofocus = false;
|
||||
export let autocomplete = false;
|
||||
export let step: number | 'any' = 0.001;
|
||||
export let type: 'date' | 'time' | 'datetime-local' = 'date';
|
||||
|
||||
let error: string;
|
||||
let element: HTMLInputElement;
|
||||
@@ -36,6 +37,10 @@
|
||||
$: if (value) {
|
||||
error = null;
|
||||
}
|
||||
|
||||
function onChange(event: CustomEvent) {
|
||||
value = (event.target as HTMLInputElement).value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Layout.Stack gap="s" direction="row">
|
||||
@@ -47,8 +52,9 @@
|
||||
{required}
|
||||
{value}
|
||||
{step}
|
||||
{type}
|
||||
helper={error}
|
||||
on:change={(event) => (value = (event.target as HTMLInputElement).value)}
|
||||
on:change={onChange}
|
||||
autocomplete={autocomplete ? 'on' : 'off'}>
|
||||
{#if nullable}
|
||||
<Selector.Checkbox
|
||||
|
||||
@@ -90,6 +90,105 @@ export async function createRecord(record: Partial<Models.DnsRecord>, domainId:
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateRecord(record: Partial<Models.DnsRecord>, domainId: string) {
|
||||
switch (record.type) {
|
||||
case 'A':
|
||||
return await sdk.forConsole.domains.updateRecordA(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'AAAA':
|
||||
return await sdk.forConsole.domains.updateRecordAAAA(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'CNAME':
|
||||
return await sdk.forConsole.domains.updateRecordCNAME(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'MX':
|
||||
return await sdk.forConsole.domains.updateRecordMX(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.priority,
|
||||
record.comment
|
||||
);
|
||||
case 'TXT':
|
||||
return await sdk.forConsole.domains.updateRecordTXT(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'NS':
|
||||
return await sdk.forConsole.domains.updateRecordNS(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'SRV':
|
||||
return await sdk.forConsole.domains.updateRecordSRV(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.priority,
|
||||
record.weight,
|
||||
record.port,
|
||||
record?.comment || undefined
|
||||
);
|
||||
case 'CAA':
|
||||
return await sdk.forConsole.domains.updateRecordCAA(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'HTTPS':
|
||||
return await sdk.forConsole.domains.updateRecordHTTPS(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
case 'ALIAS':
|
||||
return await sdk.forConsole.domains.updateRecordAlias(
|
||||
domainId,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export type ParsedRecords = {
|
||||
A: Partial<Models.DnsRecord>[];
|
||||
AAAA: Partial<Models.DnsRecord>[];
|
||||
|
||||
@@ -15,7 +15,6 @@ export function isASubdomain(domain: string | null): boolean {
|
||||
|
||||
const { domain: apex, subdomain } = parse(domain);
|
||||
if (!apex) return false;
|
||||
if (subdomain === 'www') return false;
|
||||
|
||||
return !!subdomain;
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { get } from 'svelte/store';
|
||||
import { user } from '$lib/stores/user';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
const userPreferences = () => get(user)?.prefs;
|
||||
|
||||
export const joinWaitlistSites = () => {
|
||||
const prefs = userPreferences();
|
||||
const newPrefs = {
|
||||
...prefs,
|
||||
joinWaitlistSites: true
|
||||
};
|
||||
|
||||
sdk.forConsole.account.updatePrefs(newPrefs);
|
||||
|
||||
if (sessionStorage) {
|
||||
sessionStorage.setItem('joinWaitlistSites', 'true');
|
||||
}
|
||||
};
|
||||
|
||||
export const isOnWaitlistSites = (): boolean => {
|
||||
const prefs = userPreferences();
|
||||
const joinedInPrefs = 'joinWaitlistSites' in prefs;
|
||||
|
||||
let joinedInSession = false;
|
||||
if (sessionStorage) {
|
||||
joinedInSession = sessionStorage.getItem('joinWaitlistSites') === 'true';
|
||||
}
|
||||
|
||||
return joinedInSession || joinedInPrefs;
|
||||
};
|
||||
@@ -111,6 +111,9 @@
|
||||
let state: undefined | 'open' | 'closed' | 'icons' = 'closed';
|
||||
$: state = $isSidebarOpen ? 'open' : 'closed';
|
||||
|
||||
let isProjectPage;
|
||||
$: isProjectPage = $page.route?.id?.includes('project-');
|
||||
|
||||
function handleResize() {
|
||||
$isSidebarOpen = false;
|
||||
showAccountMenu = false;
|
||||
@@ -155,7 +158,7 @@
|
||||
<div
|
||||
class="content"
|
||||
class:has-transition={showContentTransition}
|
||||
class:icons-content={state === 'icons'}
|
||||
class:icons-content={state === 'icons' && isProjectPage}
|
||||
class:no-sidebar={!showSideNavigation}>
|
||||
<section class="main-content" data-test={showSideNavigation}>
|
||||
{#if $page.data?.header}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
|
||||
import { Modal } from '$lib/components';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
@@ -28,10 +27,8 @@
|
||||
let error: string = null;
|
||||
|
||||
onMount(async () => {
|
||||
const countryList = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.locale.listCountries();
|
||||
const locale = await sdk.forProject(page.params.region, page.params.project).locale.get();
|
||||
const countryList = await sdk.forConsole.locale.listCountries();
|
||||
const locale = await sdk.forConsole.locale.get();
|
||||
if (locale.countryCode) {
|
||||
country = locale.countryCode;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
Tag,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { page } from '$app/state';
|
||||
|
||||
let show = false;
|
||||
let showEdit = false;
|
||||
@@ -38,9 +37,7 @@
|
||||
let countryList: Models.CountryList;
|
||||
|
||||
onMount(async () => {
|
||||
countryList = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.locale.listCountries();
|
||||
countryList = await sdk.forConsole.locale.listCountries();
|
||||
});
|
||||
|
||||
$: orgList = $organizationList.teams as unknown as Organization[];
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
];
|
||||
|
||||
onMount(async () => {
|
||||
const countryList = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.locale.listCountries();
|
||||
const countryList = await sdk.forConsole.locale.listCountries();
|
||||
options = countryList.countries.map((country) => {
|
||||
return {
|
||||
value: country.code,
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
$: selectedOrgId = tempOrgId;
|
||||
|
||||
function isUpgrade() {
|
||||
const newPlan = page.data.plansInfo.get(billingPlan);
|
||||
const newPlan = $plansInfo.get(billingPlan);
|
||||
return currentPlan && newPlan && currentPlan.order < newPlan.order;
|
||||
}
|
||||
|
||||
@@ -227,34 +227,42 @@
|
||||
function getBillingPlan(): Tier | undefined {
|
||||
const campaignPlan =
|
||||
campaign?.plan && $plansInfo.get(campaign.plan) ? $plansInfo.get(campaign.plan) : null;
|
||||
const orgPlan =
|
||||
selectedOrg?.billingPlan && $plansInfo.get(selectedOrg.billingPlan)
|
||||
? $plansInfo.get(selectedOrg.billingPlan)
|
||||
: null;
|
||||
const newPlan = $plansInfo.get(billingPlan);
|
||||
|
||||
if (!campaignPlan && !orgPlan) {
|
||||
return;
|
||||
// if campaign has a plan and it's higher than the selected new plan
|
||||
if (campaignPlan?.order > newPlan?.order) {
|
||||
return campaignPlan.$id as Tier;
|
||||
}
|
||||
if (!campaignPlan) {
|
||||
return selectedOrg?.billingPlan;
|
||||
|
||||
// if current plan's order is higher than the selected new plan
|
||||
if (currentPlan?.order > newPlan?.order) {
|
||||
return currentPlan.$id as Tier;
|
||||
}
|
||||
if (!orgPlan) {
|
||||
return campaign.plan;
|
||||
}
|
||||
return campaignPlan.order > orgPlan.order ? campaign.plan : selectedOrg?.billingPlan;
|
||||
|
||||
return billingPlan;
|
||||
}
|
||||
|
||||
$: if (selectedOrg) {
|
||||
$: if (currentPlan) {
|
||||
billingPlan = getBillingPlan();
|
||||
}
|
||||
|
||||
$: isNewOrg = selectedOrgId && selectedOrgId !== newOrgId;
|
||||
|
||||
$: {
|
||||
if (selectedOrgId) {
|
||||
if (isNewOrg) {
|
||||
(async () => {
|
||||
currentPlan = await sdk.forConsole.billing.getOrganizationPlan(selectedOrgId);
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
// after adding a payment method, fetch the payment methods again so the input can be updated
|
||||
$: if (
|
||||
paymentMethodId &&
|
||||
!methods?.paymentMethods?.find((method) => method.$id === paymentMethodId)
|
||||
) {
|
||||
loadPaymentMethods();
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -363,7 +371,7 @@
|
||||
{collaborators}
|
||||
bind:couponData
|
||||
bind:billingBudget
|
||||
organizationId={selectedOrgId}>
|
||||
organizationId={isNewOrg ? selectedOrgId : null}>
|
||||
{#if campaign?.template === 'review' && (campaign?.cta || campaign?.claimed || campaign?.unclaimed)}
|
||||
<div class="u-margin-block-end-24">
|
||||
<p class="body-text-1 u-bold">{campaign?.cta}</p>
|
||||
@@ -396,6 +404,8 @@
|
||||
{/if}
|
||||
{#if selectedOrgId === newOrgId}
|
||||
Create organization
|
||||
{:else if isUpgrade()}
|
||||
Upgrade
|
||||
{:else}
|
||||
Apply
|
||||
{/if}
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { loading } from '$routes/store';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { ID, Region } from '@appwrite.io/console';
|
||||
import { ID, Region, type Models } from '@appwrite.io/console';
|
||||
import { openImportWizard } from '../project-[region]-[project]/settings/migrations/(import)';
|
||||
import { readOnly } from '$lib/stores/billing';
|
||||
import { onMount, type ComponentType } from 'svelte';
|
||||
@@ -163,23 +162,28 @@
|
||||
<svelte:fragment slot="title">
|
||||
{project.name}
|
||||
</svelte:fragment>
|
||||
{#each platforms as platform, i}
|
||||
{#if i < 3}
|
||||
{@const icon = getIconForPlatform(platform.icon)}
|
||||
<Badge variant="secondary" content={platform.name}>
|
||||
<Icon {icon} size="s" slot="start" />
|
||||
</Badge>
|
||||
{/if}
|
||||
|
||||
{#each platforms.slice(0, 2) as platform}
|
||||
{@const icon = getIconForPlatform(platform.icon)}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
content={platform.name}
|
||||
style="width: max-content;">
|
||||
<Icon {icon} size="s" slot="start" />
|
||||
</Badge>
|
||||
{/each}
|
||||
{#if platforms?.length > 3}
|
||||
<Badge variant="secondary" content={`+${project.platforms.length - 3}`} />
|
||||
|
||||
{#if platforms.length > 3}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
content={`+${platforms.length - 2}`}
|
||||
style="width: max-content;" />
|
||||
{/if}
|
||||
|
||||
<svelte:fragment slot="icons">
|
||||
{#if isCloud && $regionsStore?.regions}
|
||||
{@const region = findRegion(project)}
|
||||
<span class="u-color-text-gray u-medium u-line-height-2">
|
||||
{region?.name}
|
||||
</span>
|
||||
<Typography.Text>{region.name}</Typography.Text>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</GridItem1>
|
||||
|
||||
@@ -302,8 +302,7 @@
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
|
||||
<!-- Show email input if upgrading from free plan -->
|
||||
{#if selectedPlan !== BillingPlan.FREE && data.organization.billingPlan === BillingPlan.FREE}
|
||||
{#if isUpgrade}
|
||||
<Fieldset legend="Payment">
|
||||
<SelectPaymentMethod
|
||||
methods={data.paymentMethods}
|
||||
|
||||
+17
-2
@@ -17,6 +17,7 @@
|
||||
import { invalidate } from '$app/navigation';
|
||||
import type { RecordType } from '$lib/stores/domains';
|
||||
import { createRecord } from '$lib/helpers/domains';
|
||||
import { showPriority } from './table.svelte';
|
||||
|
||||
export let show = false;
|
||||
|
||||
@@ -30,6 +31,20 @@
|
||||
let weight: number;
|
||||
let port: number;
|
||||
|
||||
const placeholders: Record<RecordType, string> = {
|
||||
A: '76.75.21.21',
|
||||
AAAA: '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
|
||||
CNAME: 'stage.example.com',
|
||||
MX: 'mail.example.com',
|
||||
TXT: 'v=spf1 include:_spf.example.com ~all',
|
||||
NS: 'ns1.example.com',
|
||||
SRV: '10 5 8080 example.com',
|
||||
CAA: '0 issue "letsencrypt.org"',
|
||||
HTTPS: 'https://example.com',
|
||||
ALIAS: 'www.example.com'
|
||||
};
|
||||
$: placeholder = placeholders[type] ?? 'Enter value';
|
||||
|
||||
async function handleSubmit() {
|
||||
const record = {
|
||||
name,
|
||||
@@ -77,7 +92,7 @@
|
||||
</Input.Helper>
|
||||
</Layout.Stack>
|
||||
|
||||
<InputText id="value" label="Value" placeholder="76.75.21.21" bind:value>
|
||||
<InputText id="value" label="Value" {placeholder} bind:value>
|
||||
<Tooltip slot="info">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<span slot="tooltip">
|
||||
@@ -96,7 +111,7 @@
|
||||
</span>
|
||||
</Tooltip>
|
||||
</InputNumber>
|
||||
{#if type === 'MX'}
|
||||
{#if showPriority(type)}
|
||||
<InputNumber
|
||||
id="priority"
|
||||
label="Priority"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { derived, writable } from 'svelte/store';
|
||||
|
||||
export const domain = derived(page, ($page) => $page.data.domain as Models.Domain);
|
||||
export const columns = writable<Column[]>([
|
||||
{ id: 'name', title: 'Name', type: 'string', width: { min: 150 } },
|
||||
{ id: 'name', title: 'Name', type: 'string', width: { min: 200 } },
|
||||
{ id: 'type', title: 'Type', type: 'string', width: 125 },
|
||||
{ id: 'value', title: 'Value', type: 'string', width: 250 },
|
||||
{ id: 'ttl', title: 'TTL', type: 'integer', width: 100 },
|
||||
|
||||
+29
-4
@@ -1,3 +1,12 @@
|
||||
<script lang="ts" context="module">
|
||||
import type { RecordType } from '$lib/stores/domains';
|
||||
|
||||
export function showPriority(record: Models.DnsRecord | RecordType): boolean {
|
||||
const type = typeof record === 'string' ? record : record.type;
|
||||
return type.toLowerCase() === 'mx' || type.toLowerCase() === 'srv';
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { PaginationWithLimit } from '$lib/components';
|
||||
import {
|
||||
@@ -29,6 +38,15 @@
|
||||
let showEdit = false;
|
||||
let showDelete = false;
|
||||
let selectedRecord: Models.DnsRecord = null;
|
||||
|
||||
function formatRecordName(name: string) {
|
||||
const limit = 30;
|
||||
return {
|
||||
value: name.length > limit ? `${name.slice(0, limit)}...` : name,
|
||||
truncated: name.length > limit,
|
||||
whole: name
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
@@ -47,9 +65,16 @@
|
||||
{#each $columns as column}
|
||||
<Table.Cell column={column.id} {root}>
|
||||
{#if column.id === 'name'}
|
||||
<Typography.Code>
|
||||
{record.name}
|
||||
</Typography.Code>
|
||||
{@const formatted = formatRecordName(record.name)}
|
||||
<Tooltip placement="bottom" disabled={!formatted.truncated}>
|
||||
<Typography.Text truncate>{formatted.value}</Typography.Text>
|
||||
<span
|
||||
slot="tooltip"
|
||||
style:white-space="pre-wrap"
|
||||
style:word-break="break-all">
|
||||
{formatted.whole}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{:else if column.id === 'type'}
|
||||
<Typography.Text>
|
||||
{record.type}
|
||||
@@ -70,7 +95,7 @@
|
||||
</Typography.Text>
|
||||
{:else if column.id === 'priority'}
|
||||
<Typography.Text>
|
||||
{record?.priority ?? '-'}
|
||||
{showPriority(record) ? (record?.priority ?? '0') : '-'}
|
||||
</Typography.Text>
|
||||
{:else if column.id === 'comment'}
|
||||
<Typography.Text truncate>
|
||||
|
||||
+34
-121
@@ -13,12 +13,14 @@
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { symmetricDifference } from '$lib/helpers/array';
|
||||
import { deepClone } from '$lib/helpers/object';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { page } from '$app/state';
|
||||
import { recordTypes } from './store';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import type { RecordType } from '$lib/stores/domains';
|
||||
import { updateRecord } from '$lib/helpers/domains';
|
||||
import { showPriority } from './table.svelte';
|
||||
|
||||
export let show = false;
|
||||
export let selectedRecord: Models.DnsRecord;
|
||||
@@ -26,114 +28,23 @@
|
||||
let record = deepClone(selectedRecord);
|
||||
let error = '';
|
||||
|
||||
const placeholders: Record<RecordType, string> = {
|
||||
A: '76.75.21.21',
|
||||
AAAA: '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
|
||||
CNAME: 'stage.example.com',
|
||||
MX: 'mail.example.com',
|
||||
TXT: 'v=spf1 include:_spf.example.com ~all',
|
||||
NS: 'ns1.example.com',
|
||||
SRV: '10 5 8080 example.com',
|
||||
CAA: '0 issue "letsencrypt.org"',
|
||||
HTTPS: 'https://example.com',
|
||||
ALIAS: 'www.example.com'
|
||||
};
|
||||
$: placeholder = placeholders[record.type] ?? 'Enter value';
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
switch (record.type) {
|
||||
case 'A':
|
||||
await sdk.forConsole.domains.updateRecordA(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'AAAA':
|
||||
await sdk.forConsole.domains.updateRecordAAAA(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'CNAME':
|
||||
await sdk.forConsole.domains.updateRecordCNAME(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'MX':
|
||||
await sdk.forConsole.domains.updateRecordMX(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.priority,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'TXT':
|
||||
await sdk.forConsole.domains.updateRecordTXT(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'NS':
|
||||
await sdk.forConsole.domains.updateRecordNS(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'CAA':
|
||||
await sdk.forConsole.domains.updateRecordCAA(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'HTTPS':
|
||||
await sdk.forConsole.domains.updateRecordHTTPS(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
case 'ALIAS':
|
||||
await sdk.forConsole.domains.updateRecordAlias(
|
||||
page.params.domain,
|
||||
record.$id,
|
||||
record.name,
|
||||
record.value,
|
||||
record.ttl,
|
||||
record.comment
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
await updateRecord(record, page.params.domain);
|
||||
show = false;
|
||||
invalidate(Dependencies.DOMAINS);
|
||||
addNotification({
|
||||
@@ -173,7 +84,7 @@
|
||||
</Input.Helper>
|
||||
</Layout.Stack>
|
||||
|
||||
<InputText id="value" label="Value" placeholder="76.75.21.21" bind:value={record.value}>
|
||||
<InputText id="value" label="Value" {placeholder} bind:value={record.value}>
|
||||
<Tooltip slot="info">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<span slot="tooltip">
|
||||
@@ -191,19 +102,21 @@
|
||||
</span>
|
||||
</Tooltip>
|
||||
</InputNumber>
|
||||
<InputNumber
|
||||
id="priority"
|
||||
label="Priority"
|
||||
placeholder="Enter number"
|
||||
bind:value={record.priority}>
|
||||
<Tooltip slot="info">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<span slot="tooltip">
|
||||
Sets the priority for this DNS record. Lower numbers indicate higher
|
||||
priority (e.g., 10 is higher than 20).
|
||||
</span>
|
||||
</Tooltip>
|
||||
</InputNumber>
|
||||
{#if showPriority(record)}
|
||||
<InputNumber
|
||||
id="priority"
|
||||
label="Priority"
|
||||
placeholder="Enter number"
|
||||
bind:value={record.priority}>
|
||||
<Tooltip slot="info">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<span slot="tooltip">
|
||||
Sets the priority for this DNS record. Lower numbers indicate higher
|
||||
priority (e.g., 10 is higher than 20).
|
||||
</span>
|
||||
</Tooltip>
|
||||
</InputNumber>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
<InputTextarea
|
||||
|
||||
+4
-2
@@ -6,11 +6,13 @@
|
||||
export let label: string;
|
||||
export let value: string;
|
||||
export let attribute: Models.AttributeDatetime;
|
||||
export let type: 'date' | 'time' | 'datetime-local' = 'datetime-local';
|
||||
</script>
|
||||
|
||||
<InputDateTime
|
||||
{id}
|
||||
{label}
|
||||
{type}
|
||||
bind:value
|
||||
required={attribute.required}
|
||||
nullable={!attribute.required}
|
||||
bind:value />
|
||||
nullable={!attribute.required} />
|
||||
|
||||
+18
-11
@@ -25,6 +25,7 @@
|
||||
FloatingActionBar,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import DualTimeView from '$lib/components/dualTimeView.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
@@ -244,17 +245,23 @@
|
||||
{/if}
|
||||
{:else}
|
||||
{@const formatted = formatColumn(document[id])}
|
||||
<Tooltip disabled={!formatted.truncated} placement="bottom">
|
||||
<Typography.Text truncate>
|
||||
{formatted.value}
|
||||
</Typography.Text>
|
||||
<span
|
||||
style:white-space="pre-wrap"
|
||||
style:word-break="break-all"
|
||||
slot="tooltip">
|
||||
{formatted.whole}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{@const isDatetimeAttribute = attr.type === 'datetime'}
|
||||
{#if isDatetimeAttribute}
|
||||
<DualTimeView time={formatted.whole}>
|
||||
<span slot="title">Timestamp</span>
|
||||
{toLocaleDateTime(formatted.whole, true, 'UTC')}
|
||||
</DualTimeView>
|
||||
{:else}
|
||||
<Tooltip placement="bottom" disabled={!formatted.truncated}>
|
||||
<Typography.Text truncate>{formatted.value}</Typography.Text>
|
||||
<span
|
||||
slot="tooltip"
|
||||
style:white-space="pre-wrap"
|
||||
style:word-break="break-all">
|
||||
{formatted.whole}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@
|
||||
import { ConnectRepoModal } from '$lib/components/git/index.js';
|
||||
import { isValueOfStringEnum } from '$lib/helpers/types.js';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { project, regionalProtocol } from '$routes/(console)/project-[region]-[project]/store';
|
||||
import { project } from '$routes/(console)/project-[region]-[project]/store';
|
||||
import { getApexDomain } from '$lib/helpers/tlds';
|
||||
|
||||
const routeBase = `${base}/project-${page.params.region}-${page.params.project}/functions/function-${page.params.function}/domains`;
|
||||
@@ -72,7 +72,7 @@
|
||||
} else if (behaviour === 'REDIRECT') {
|
||||
rule = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.proxy.createRedirectRule(domainName, $regionalProtocol + redirect, statusCode);
|
||||
.proxy.createRedirectRule(domainName, redirect, statusCode);
|
||||
} else if (behaviour === 'ACTIVE') {
|
||||
rule = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
|
||||
+2
-4
@@ -57,10 +57,8 @@ const val APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.
|
||||
trackEvent(Submit.PlatformCreate, {
|
||||
type: 'android'
|
||||
});
|
||||
await Promise.all([
|
||||
invalidate(Dependencies.PROJECT),
|
||||
invalidate(Dependencies.PLATFORMS)
|
||||
]);
|
||||
invalidate(Dependencies.PROJECT);
|
||||
invalidate(Dependencies.PLATFORMS);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.PlatformCreate);
|
||||
addNotification({
|
||||
|
||||
+13
-17
@@ -4,6 +4,7 @@
|
||||
import { createPlatform } from './wizard/store';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import {
|
||||
Card as Pink2Card,
|
||||
Code,
|
||||
Layout,
|
||||
Icon,
|
||||
@@ -26,7 +27,6 @@
|
||||
import { PlatformType } from '@appwrite.io/console';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { LabelCard } from '$lib/components';
|
||||
|
||||
let showExitModal = false;
|
||||
let isPlatformCreated = false;
|
||||
@@ -68,10 +68,8 @@ APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.proj
|
||||
trackEvent(Submit.PlatformCreate, {
|
||||
type: platform
|
||||
});
|
||||
await Promise.all([
|
||||
invalidate(Dependencies.PROJECT),
|
||||
invalidate(Dependencies.PLATFORMS)
|
||||
]);
|
||||
invalidate(Dependencies.PROJECT);
|
||||
invalidate(Dependencies.PLATFORMS);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.PlatformCreate);
|
||||
addNotification({
|
||||
@@ -108,20 +106,18 @@ APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.proj
|
||||
<Form onSubmit={createApplePlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Stack gap="l" direction="row">
|
||||
<Layout.Grid gap="l" rowGap="l" columns={4} columnsXS={2}>
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<div class="u-width-full-line">
|
||||
<!-- TODO: https://github.com/appwrite/pink/pull/248 for correct spacing -->
|
||||
<LabelCard
|
||||
name={key}
|
||||
bind:group={platform}
|
||||
variant="primary"
|
||||
{value}
|
||||
title={key}
|
||||
disabled={isPlatformCreated} />
|
||||
</div>
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Stack>
|
||||
</Layout.Grid>
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
|
||||
+13
-16
@@ -4,6 +4,7 @@
|
||||
import { createPlatform } from './wizard/store';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import {
|
||||
Card as Pink2Card,
|
||||
Code,
|
||||
Layout,
|
||||
Icon,
|
||||
@@ -25,7 +26,6 @@
|
||||
import OnboardingPlatformCard from './components/OnboardingPlatformCard.svelte';
|
||||
import { PlatformType } from '@appwrite.io/console';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { LabelCard } from '$lib/components';
|
||||
|
||||
let showExitModal = false;
|
||||
let isPlatformCreated = false;
|
||||
@@ -125,10 +125,8 @@ static const String APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.reg
|
||||
type: platform
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
invalidate(Dependencies.PROJECT),
|
||||
invalidate(Dependencies.PLATFORMS)
|
||||
]);
|
||||
invalidate(Dependencies.PROJECT);
|
||||
invalidate(Dependencies.PLATFORMS);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.PlatformCreate);
|
||||
addNotification({
|
||||
@@ -165,19 +163,18 @@ static const String APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.reg
|
||||
<Form onSubmit={createFlutterPlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Stack gap="l" direction="row">
|
||||
<Layout.Grid gap="l" rowGap="l" columns={3} columnsXS={2} columnsXXS={1}>
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<div class="u-width-full-line">
|
||||
<!-- TODO: https://github.com/appwrite/pink/pull/248 for correct spacing -->
|
||||
<LabelCard
|
||||
name={key}
|
||||
bind:group={platform}
|
||||
variant="primary"
|
||||
{value}
|
||||
title={key} />
|
||||
</div>
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Stack>
|
||||
</Layout.Grid>
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
|
||||
+13
-16
@@ -4,6 +4,7 @@
|
||||
import { createPlatform } from './wizard/store';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import {
|
||||
Card as Pink2Card,
|
||||
Code,
|
||||
Layout,
|
||||
Icon,
|
||||
@@ -25,10 +26,9 @@
|
||||
import OnboardingPlatformCard from './components/OnboardingPlatformCard.svelte';
|
||||
import { PlatformType } from '@appwrite.io/console';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { LabelCard } from '$lib/components';
|
||||
|
||||
let showExitModal = false;
|
||||
export let isPlatformCreated = false;
|
||||
let isPlatformCreated = false;
|
||||
let isCreatingPlatform = false;
|
||||
let connectionSuccessful = false;
|
||||
const projectId = page.params.project;
|
||||
@@ -94,10 +94,9 @@ const APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.para
|
||||
trackEvent(Submit.PlatformCreate, {
|
||||
type: platform
|
||||
});
|
||||
await Promise.all([
|
||||
invalidate(Dependencies.PROJECT),
|
||||
invalidate(Dependencies.PLATFORMS)
|
||||
]);
|
||||
|
||||
invalidate(Dependencies.PROJECT);
|
||||
invalidate(Dependencies.PLATFORMS);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.PlatformCreate);
|
||||
addNotification({
|
||||
@@ -136,16 +135,14 @@ const APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.para
|
||||
<!-- Step One -->
|
||||
<Layout.Stack gap="l" direction="row">
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<div class="u-width-full-line">
|
||||
<!-- TODO: https://github.com/appwrite/pink/pull/248 for correct spacing -->
|
||||
<LabelCard
|
||||
name={key}
|
||||
bind:group={platform}
|
||||
variant="primary"
|
||||
{value}
|
||||
title={key}
|
||||
disabled={isPlatformCreated} />
|
||||
</div>
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Stack>
|
||||
|
||||
|
||||
+18
-20
@@ -11,10 +11,9 @@
|
||||
Fieldset,
|
||||
InlineCode,
|
||||
Card,
|
||||
Button,
|
||||
Tooltip
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { Form, InputText } from '$lib/elements/forms';
|
||||
import { Button, Form, InputText } from '$lib/elements/forms';
|
||||
import {
|
||||
IconVue,
|
||||
IconAppwrite,
|
||||
@@ -166,10 +165,8 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
type: platform
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
invalidate(Dependencies.PROJECT),
|
||||
invalidate(Dependencies.PLATFORMS)
|
||||
]);
|
||||
invalidate(Dependencies.PROJECT);
|
||||
invalidate(Dependencies.PLATFORMS);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.PlatformCreate);
|
||||
addNotification({
|
||||
@@ -223,10 +220,10 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
</div>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
{#if isChangingFramework}
|
||||
<Button.Button
|
||||
<Button
|
||||
disabled={!selectedFramework}
|
||||
on:click={() => (isChangingFramework = false)}>
|
||||
Save</Button.Button>
|
||||
Save</Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
@@ -249,8 +246,7 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
</Tooltip>
|
||||
</InputText></Fieldset>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end"
|
||||
><Button.Button type="submit" disabled={!selectedFramework}
|
||||
>Create platform</Button.Button
|
||||
><Button submit disabled={!selectedFramework}>Create platform</Button
|
||||
></Layout.Stack>
|
||||
{/if}
|
||||
{:else}
|
||||
@@ -264,12 +260,12 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
<Typography.Text variant="m-500"
|
||||
>{selectedFramework.label}</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<Button.Button
|
||||
variant="secondary"
|
||||
<Button
|
||||
size="s"
|
||||
secondary
|
||||
on:click={() => {
|
||||
isChangingFramework = true;
|
||||
}}>Change</Button.Button>
|
||||
}}>Change</Button>
|
||||
</Layout.Stack></Card.Base>
|
||||
{/if}
|
||||
|
||||
@@ -338,15 +334,15 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
color="--fgcolor-neutral-primary">
|
||||
Demo app runs on http://localhost:{selectedFramework.portNumber}</Typography.Text
|
||||
></Layout.Stack>
|
||||
<Button.Anchor
|
||||
variant="secondary"
|
||||
<Button
|
||||
external
|
||||
secondary
|
||||
href={`http://localhost:${selectedFramework.portNumber}`}
|
||||
target="_blank"
|
||||
><Layout.Stack direction="row" gap="xs"
|
||||
>Open <Icon
|
||||
icon={IconExternalLink}
|
||||
color="--fgcolor-neutral-tertiary" /></Layout.Stack
|
||||
></Button.Anchor
|
||||
></Button
|
||||
></Layout.Stack
|
||||
></Card.Base>
|
||||
{/if}
|
||||
@@ -394,10 +390,12 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
{#if isPlatformCreated}
|
||||
<Button.Anchor
|
||||
<Button
|
||||
size="s"
|
||||
secondary
|
||||
fullWidthMobile
|
||||
href={location.pathname}
|
||||
variant="secondary"
|
||||
disabled={isCreatingPlatform}>Go to dashboard</Button.Anchor>
|
||||
disabled={isCreatingPlatform}>Go to dashboard</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Wizard>
|
||||
|
||||
@@ -11,14 +11,12 @@
|
||||
import { isServiceLimited } from '$lib/stores/billing';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { canWriteSites } from '$lib/stores/roles.js';
|
||||
import { Card, Icon, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import { Icon, Layout } from '@appwrite.io/pink-svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { app } from '$lib/stores/app';
|
||||
import CreateSiteModal from './createSiteModal.svelte';
|
||||
import EmptyLight from './(images)/empty-sites-light.svg';
|
||||
import EmptyDark from './(images)/empty-sites-dark.svg';
|
||||
import EmptyLightMobile from './(images)/empty-sites-light-mobile.svg';
|
||||
import EmptyDarkMobile from './(images)/empty-sites-dark-mobile.svg';
|
||||
import Grid from './grid.svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
import { columns } from './store';
|
||||
@@ -28,15 +26,10 @@
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { APPWRITE_OFFICIALS_ORG, isCloud } from '$lib/system';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { isOnWaitlistSites, joinWaitlistSites } from '$lib/helpers/waitlist';
|
||||
import { isSmallViewport } from '$lib/stores/viewport';
|
||||
|
||||
export let data;
|
||||
|
||||
let show = false;
|
||||
let isOnWaitlist = isOnWaitlistSites();
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
@@ -46,7 +39,6 @@
|
||||
},
|
||||
keys: ['c'],
|
||||
disabled:
|
||||
!showSites ||
|
||||
isServiceLimited('sites', $organization?.billingPlan, data.siteList?.total) ||
|
||||
!$canWriteSites,
|
||||
icon: IconPlus,
|
||||
@@ -63,123 +55,46 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Controls visibility of Sites feature:
|
||||
* - Shown if running on self-hosted
|
||||
* - Shown on cloud only if the organization is Appwrite's.
|
||||
* - Hidden on cloud for any non-Appwrite organization.
|
||||
*/
|
||||
$: showSites = !isCloud || $organization.$id === APPWRITE_OFFICIALS_ORG;
|
||||
|
||||
$: isDark = $app.themeInUse === 'dark';
|
||||
|
||||
$: imgSrc = isDark
|
||||
? $isSmallViewport
|
||||
? EmptyDarkMobile
|
||||
: EmptyDark
|
||||
: $isSmallViewport
|
||||
? EmptyLightMobile
|
||||
: EmptyLight;
|
||||
|
||||
$: imgClass = $isSmallViewport ? 'mobile' : 'desktop';
|
||||
|
||||
function addToWaitlist() {
|
||||
joinWaitlistSites();
|
||||
addNotification({
|
||||
type: 'success',
|
||||
title: 'Waitlist joined',
|
||||
message: "We'll let you know as soon as Appwrite Sites is ready for you."
|
||||
});
|
||||
|
||||
isOnWaitlist = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
{#if showSites}
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search by name" />
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<ViewSelector
|
||||
{columns}
|
||||
view={data.view}
|
||||
hideColumns
|
||||
hideView={!data.siteList.total} />
|
||||
{#if $canWriteSites}
|
||||
<Button on:mousedown={() => (show = true)} event="create_site" size="s">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create site
|
||||
</Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search by name" />
|
||||
</Layout.Stack>
|
||||
{#if data.siteList.total}
|
||||
{#if data.view === View.Grid}
|
||||
<Grid siteList={data.siteList} />
|
||||
{:else}
|
||||
<Table siteList={data.siteList} />
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<ViewSelector {columns} view={data.view} hideColumns hideView={!data.siteList.total} />
|
||||
{#if $canWriteSites}
|
||||
<Button on:mousedown={() => (show = true)} event="create_site" size="s">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create site
|
||||
</Button>
|
||||
{/if}
|
||||
<PaginationWithLimit
|
||||
name="Sites"
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
total={data.siteList.total} />
|
||||
{:else if data.search}
|
||||
<EmptySearch target="sites" />
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
{#if data.siteList.total}
|
||||
{#if data.view === View.Grid}
|
||||
<Grid siteList={data.siteList} />
|
||||
{:else}
|
||||
<Empty
|
||||
single
|
||||
allowCreate={$canWriteSites}
|
||||
href="https://appwrite.io/docs/products/sites"
|
||||
description="Deploy and manage your web your web applications with Sites. "
|
||||
target="site"
|
||||
src={$app.themeInUse === 'dark' ? EmptyDark : EmptyLight}
|
||||
on:click={() => (show = true)}>
|
||||
</Empty>
|
||||
<Table siteList={data.siteList} />
|
||||
{/if}
|
||||
<PaginationWithLimit
|
||||
name="Sites"
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
total={data.siteList.total} />
|
||||
{:else if data.search}
|
||||
<EmptySearch target="sites" />
|
||||
{:else}
|
||||
<Card.Base padding="m">
|
||||
<Layout.Stack gap="xxl">
|
||||
<img src={imgSrc} alt="create" aria-hidden="true" height="242" class={imgClass} />
|
||||
|
||||
<Layout.Stack>
|
||||
{#if isOnWaitlist}
|
||||
<Typography.Title size="s" align="center" color="--fgcolor-neutral-primary">
|
||||
You've successfully joined the Sites waitlist
|
||||
</Typography.Title>
|
||||
|
||||
<Typography.Text align="center" color="--fgcolor-neutral-secondary">
|
||||
We can't wait for you to try out Sites on Cloud. You will get access
|
||||
soon.
|
||||
</Typography.Text>
|
||||
{:else}
|
||||
<Layout.Stack gap="m" alignItems="center">
|
||||
<Typography.Title
|
||||
size="s"
|
||||
align="center"
|
||||
color="--fgcolor-neutral-primary">
|
||||
Appwrite Sites is in high demand
|
||||
</Typography.Title>
|
||||
|
||||
<div style:max-width="600px">
|
||||
<Typography.Text align="center" color="--fgcolor-neutral-secondary">
|
||||
To ensure a smooth experience for everyone, we’re rolling out
|
||||
access gradually. Join the waitlist and be one of the first to
|
||||
deploy with Sites.
|
||||
</Typography.Text>
|
||||
</div>
|
||||
|
||||
<div style:margin-block-start="1rem">
|
||||
<Button on:click={addToWaitlist}>Join waitlist</Button>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
<Empty
|
||||
single
|
||||
allowCreate={$canWriteSites}
|
||||
href="https://appwrite.io/docs/products/sites"
|
||||
description="Deploy and manage your web your web applications with Sites. "
|
||||
target="site"
|
||||
src={$app.themeInUse === 'dark' ? EmptyDark : EmptyLight}
|
||||
on:click={() => (show = true)}>
|
||||
</Empty>
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
|
||||
@@ -2,15 +2,8 @@ import { Query } from '@appwrite.io/console';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { getLimit, getPage, getSearch, getView, pageToOffset, View } from '$lib/helpers/load';
|
||||
import { CARD_LIMIT, Dependencies } from '$lib/constants';
|
||||
import { APPWRITE_OFFICIALS_ORG, isCloud } from '$lib/system';
|
||||
|
||||
export const load = async ({ url, depends, route, params, parent }) => {
|
||||
// don't load anything on cloud unless org is appwrite atm!
|
||||
const { organization } = await parent();
|
||||
if (isCloud && organization?.$id !== APPWRITE_OFFICIALS_ORG) {
|
||||
return;
|
||||
}
|
||||
|
||||
export const load = async ({ url, depends, route, params }) => {
|
||||
depends(Dependencies.SITES);
|
||||
|
||||
const page = getPage(url);
|
||||
|
||||
@@ -2,17 +2,9 @@ import Breadcrumbs from './breadcrumbs.svelte';
|
||||
import Header from './header.svelte';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { error, redirect } from '@sveltejs/kit';
|
||||
import { APPWRITE_OFFICIALS_ORG, isCloud } from '$lib/system';
|
||||
import { base } from '$app/paths';
|
||||
|
||||
export const load = async ({ depends, params, parent }) => {
|
||||
// don't load anything on cloud unless org is appwrite atm!
|
||||
const { organization } = await parent();
|
||||
if (isCloud && organization?.$id !== APPWRITE_OFFICIALS_ORG) {
|
||||
redirect(307, `${base}/project-${params.region}-${params.project}/sites`);
|
||||
}
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export const load = async ({ depends, params }) => {
|
||||
depends(Dependencies.SITE);
|
||||
try {
|
||||
const [site] = await Promise.all([
|
||||
|
||||
@@ -27,12 +27,17 @@ export const load = async ({ params, depends, url, route }) => {
|
||||
.proxy.listRules(
|
||||
[
|
||||
Query.or([
|
||||
Query.equal('type', RuleType.DEPLOYMENT),
|
||||
Query.equal('type', RuleType.REDIRECT)
|
||||
Query.and([
|
||||
Query.equal('type', RuleType.REDIRECT),
|
||||
Query.equal('trigger', RuleTrigger.MANUAL)
|
||||
]),
|
||||
Query.and([
|
||||
Query.equal('type', RuleType.DEPLOYMENT),
|
||||
Query.equal('trigger', RuleTrigger.MANUAL),
|
||||
Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
|
||||
Query.equal('deploymentResourceId', params.site)
|
||||
])
|
||||
]),
|
||||
Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
|
||||
Query.equal('deploymentResourceId', params.site),
|
||||
Query.equal('trigger', RuleTrigger.MANUAL),
|
||||
Query.limit(limit),
|
||||
Query.offset(offset),
|
||||
Query.orderDesc(''),
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { onMount } from 'svelte';
|
||||
import { ConnectRepoModal } from '$lib/components/git/index.js';
|
||||
import { project, regionalProtocol } from '$routes/(console)/project-[region]-[project]/store';
|
||||
import { project } from '$routes/(console)/project-[region]-[project]/store';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { getApexDomain } from '$lib/helpers/tlds';
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
} else if (behaviour === 'REDIRECT') {
|
||||
rule = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.proxy.createRedirectRule(domainName, $regionalProtocol + redirect, statusCode);
|
||||
.proxy.createRedirectRule(domainName, redirect, statusCode);
|
||||
} else if (behaviour === 'ACTIVE') {
|
||||
rule = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
|
||||
Reference in New Issue
Block a user