diff --git a/package.json b/package.json index db12591b0..280c3841f 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,11 @@ "e2e:ui": "playwright test --ui" }, "dependencies": { - "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9c6551f", + "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@207628e", + "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", "@stripe/stripe-js": "^3.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 063480f9f..4fb650293 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@appwrite.io/console': - specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9c6551f - version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9c6551f + specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e + version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 @@ -21,8 +21,8 @@ importers: specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@207628e - version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@207628e(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3) + specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7 + version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3) '@popperjs/core': specifier: ^2.11.8 version: 2.11.8 @@ -238,18 +238,18 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9c6551f': - resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9c6551f} + '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e': + resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e} version: 1.2.1 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@16d19d7471dc8cb55ee3893b3e88470f383d60b1': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@16d19d7471dc8cb55ee3893b3e88470f383d60b1} version: 1.0.0-next.7 peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e41f5ce1df4b7880030c2865452408d8ed': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e41f5ce1df4b7880030c2865452408d8ed} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e} version: 1.0.0-next.7 peerDependencies: svelte: ^4.0.0 @@ -263,8 +263,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@207628e': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@207628e} + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7} version: 1.0.0-next.85 peerDependencies: react-dom: ^18.0.0 @@ -3733,13 +3733,13 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9c6551f': {} + '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e': {} - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@16d19d7471dc8cb55ee3893b3e88470f383d60b1(svelte@5.25.3)': dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e41f5ce1df4b7880030c2865452408d8ed(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3752,9 +3752,9 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@207628e(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3)': dependencies: - '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e41f5ce1df4b7880030c2865452408d8ed(svelte@5.25.3) + '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@16d19d7471dc8cb55ee3893b3e88470f383d60b1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 '@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.5(svelte@5.25.3))(svelte@5.25.3) '@melt-ui/svelte': 0.86.5(svelte@5.25.3) diff --git a/src/lib/components/billing/paymentModal.svelte b/src/lib/components/billing/paymentModal.svelte index 1185db3e3..4f1afcdf6 100644 --- a/src/lib/components/billing/paymentModal.svelte +++ b/src/lib/components/billing/paymentModal.svelte @@ -19,9 +19,9 @@ async function handleSubmit() { try { const card = await submitStripeCard(name, page?.params?.organization ?? null); + show = false; invalidate(Dependencies.PAYMENT_METHODS); dispatch('submit', card); - show = false; addNotification({ type: 'success', message: 'A new payment method has been added to your account' diff --git a/src/lib/components/cardContainer.svelte b/src/lib/components/cardContainer.svelte index 7a8410ddb..ac5223a6d 100644 --- a/src/lib/components/cardContainer.svelte +++ b/src/lib/components/cardContainer.svelte @@ -7,7 +7,7 @@ import { isCloud } from '$lib/system'; import CardPlanLimit from './cardPlanLimit.svelte'; - export let showEmpty = true; + export let disableEmpty = true; export let offset = 0; export let total = 0; export let event: string = null; @@ -25,8 +25,8 @@ {#if total > 3 ? total < limit + offset : total % 2 !== 0} {#if isCloud && serviceId && total >= planLimit} - {:else if showEmpty} - + {:else} + {/if} diff --git a/src/lib/components/copy.svelte b/src/lib/components/copy.svelte index 1f21d2e3e..970d04074 100644 --- a/src/lib/components/copy.svelte +++ b/src/lib/components/copy.svelte @@ -40,7 +40,7 @@ role="button" tabindex="0" style:cursor="pointer" - on:click|preventDefault={handleClick} + on:click|preventDefault|stopPropagation={handleClick} on:keyup={clickOnEnter} on:mouseenter={() => setTimeout(() => (content = 'Click to copy'))}> diff --git a/src/lib/components/domains/cnameTable.svelte b/src/lib/components/domains/cnameTable.svelte index c4b031320..ca985afc6 100644 --- a/src/lib/components/domains/cnameTable.svelte +++ b/src/lib/components/domains/cnameTable.svelte @@ -54,8 +54,8 @@ - {$consoleVariables._APP_DOMAIN_TARGET} + text={$consoleVariables._APP_DOMAIN_TARGET_CNAME}> + {$consoleVariables._APP_DOMAIN_TARGET_CNAME} diff --git a/src/lib/components/domains/nameserverTable.svelte b/src/lib/components/domains/nameserverTable.svelte index 2dcd252c0..be059890f 100644 --- a/src/lib/components/domains/nameserverTable.svelte +++ b/src/lib/components/domains/nameserverTable.svelte @@ -7,7 +7,7 @@ export let verified = false; const nameserverList = $consoleVariables?._APP_DOMAINS_NAMESERVERS - ? $consoleVariables?._APP_DOMAINS_NAMESERVERS.split(',') + ? $consoleVariables?._APP_DOMAINS_NAMESERVERS?.split(',') : ['ns1.appwrite.io', 'ns2.appwrite.io']; diff --git a/src/lib/components/domains/recordTable.svelte b/src/lib/components/domains/recordTable.svelte new file mode 100644 index 000000000..dba63ac6d --- /dev/null +++ b/src/lib/components/domains/recordTable.svelte @@ -0,0 +1,81 @@ + + + + + + + {domain} + + {#if verified} + + {:else if verified === false} + + {:else} + + {/if} + + + Add the following record on your DNS provider. Note that DNS changes may take time to + propagate fully. + + + + + + Type + Name + Value + + + {variant.toUpperCase()} + {subdomain || '@'} + + + {setTarget()} + + + + + + + A list of all domain providers and their DNS setting is available here. + + + diff --git a/src/lib/components/dualTimeView.svelte b/src/lib/components/dualTimeView.svelte index f7abea807..e6ee84fb0 100644 --- a/src/lib/components/dualTimeView.svelte +++ b/src/lib/components/dualTimeView.svelte @@ -1,8 +1,14 @@ - setTimeout(show, 150)} on:mouseleave={() => hidePopover(hide)}> + { + if (!$menuOpen) { + setTimeout(show, 150); + } + }} + on:mouseleave={() => hidePopover(hide)}> {capitalize(timeFromNow(time))} @@ -99,7 +111,7 @@ isVisible variant="copy" text={toLocaleDateTime(time, 'UTC')} - value={new Date(time).toISOString()} /> + value={toISOString(time)} /> diff --git a/src/lib/components/empty.svelte b/src/lib/components/empty.svelte index 4f850c186..aebffa965 100644 --- a/src/lib/components/empty.svelte +++ b/src/lib/components/empty.svelte @@ -9,6 +9,7 @@ export let href: string = null; export let allowCreate = true; export let description = 'Need a hand? Learn more in our documentation.'; + export let disabled = false; export let src: string = null; function track() { @@ -47,7 +48,7 @@ {:else} - + diff --git a/src/lib/components/fakeModal.svelte b/src/lib/components/fakeModal.svelte index a37281253..0db0ad65d 100644 --- a/src/lib/components/fakeModal.svelte +++ b/src/lib/components/fakeModal.svelte @@ -45,7 +45,7 @@ } } - $: if (backdrop) { + $: if (backdrop && show && !document.body.contains(backdrop)) { document.body.appendChild(backdrop); } diff --git a/src/lib/components/filters/filters.svelte b/src/lib/components/filters/filters.svelte index 6d9e7067f..f8c9a3e6e 100644 --- a/src/lib/components/filters/filters.svelte +++ b/src/lib/components/filters/filters.svelte @@ -138,45 +138,48 @@ {/if} - - {#if displayQuickFilters} - - {:else} - Apply filter rules to refine the table view - (applied = 0)} /> - {/if} - - {#if quickFilters} - (displayQuickFilters = !displayQuickFilters)} - class="u-margin-block-end-auto"> - {displayQuickFilters ? 'Advanced filters' : 'Quick filters'} - + + + {#if displayQuickFilters} + + {:else} + Apply filter rules to refine the table view + (applied = 0)} /> {/if} - - {#if singleCondition} - Cancel - {:else} - - Clear all + + {#if quickFilters} + (displayQuickFilters = !displayQuickFilters)} + class="u-margin-block-end-auto"> + {displayQuickFilters ? 'Advanced filters' : 'Quick filters'} {/if} - Apply + + {#if singleCondition} + Cancel + {:else} + + Clear all + + {/if} + Apply + - - + + diff --git a/src/lib/components/filters/quickfiltersSubMenu.svelte b/src/lib/components/filters/quickfiltersSubMenu.svelte index 35477d3ac..a3aee392d 100644 --- a/src/lib/components/filters/quickfiltersSubMenu.svelte +++ b/src/lib/components/filters/quickfiltersSubMenu.svelte @@ -41,7 +41,7 @@ - + {#each filter.options as option (option.value + option.checked)} {#if variant === 'radio'} diff --git a/src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte b/src/lib/components/git/connectRepoModal.svelte similarity index 62% rename from src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte rename to src/lib/components/git/connectRepoModal.svelte index fc15eccc3..17397c8f6 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/connectRepoModal.svelte +++ b/src/lib/components/git/connectRepoModal.svelte @@ -4,33 +4,38 @@ import { Icon, Layout } from '@appwrite.io/pink-svelte'; import { installation, repository } from '$lib/stores/vcs'; import { sdk } from '$lib/stores/sdk'; - import { createEventDispatcher, onMount } from 'svelte'; + import { onMount } from 'svelte'; import { IconArrowSmRight } from '@appwrite.io/pink-icons-svelte'; import { Link } from '$lib/elements'; import { NewRepository, Repositories } from '$lib/components/git'; import ConnectGit from '$lib/components/git/connectGit.svelte'; - import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console'; import { addNotification } from '$lib/stores/notifications'; import { Click, trackEvent } from '$lib/actions/analytics'; - import { invalidate } from '$app/navigation'; - import { Dependencies } from '$lib/constants'; import RepositoryBehaviour from '$lib/components/git/repositoryBehaviour.svelte'; - const dispatch = createEventDispatcher(); + let { + show = $bindable(false), + product, + callbackState = null, + onlyExisting = false, + connect = async () => {} + }: { + show?: boolean; + product: 'functions' | 'sites'; + callbackState?: Record; + onlyExisting?: boolean; + connect?: (installationId: string, repositoryId: string) => Promise; + } = $props(); - export let show = false; - export let site: Models.Site; - export let callbackState: Record = null; - export let onlyExisting = false; - - let repositoryBehaviour: 'new' | 'existing' | undefined = onlyExisting ? 'existing' : undefined; - let repositoryName = ''; - let repositoryPrivate = true; - let selectedInstallationId = ''; - let selectedRepository = ''; - let installations = { installations: [], total: 0 }; - let hasInstallations = !!installations?.total; - let error = ''; + let repositoryBehaviour: 'new' | 'existing' | undefined = $state( + onlyExisting ? 'existing' : undefined + ); + let repositoryName = $state(''); + let repositoryPrivate = $state(true); + let selectedInstallationId = $state(''); + let selectedRepository = $state(''); + let installations = $state({ installations: [], total: 0 }); + let error = $state(''); onMount(async () => { installations = await sdk.forProject.vcs.listInstallations(); @@ -38,11 +43,9 @@ $installation = installations.installations[0]; } selectedInstallationId = installations.total ? installations.installations[0]?.$id : ''; - hasInstallations = !!installations?.total; - if (hasInstallations) { + if (!!installations?.total) { repositoryBehaviour = 'existing'; } - console.log(selectedInstallationId); }); async function connectRepo() { @@ -57,29 +60,8 @@ selectedRepository = repo.id; } - const s = await sdk.forProject.sites.update( - site.$id, - site.name, - site.framework as Framework, - site.enabled, - site.logging || undefined, - site.timeout, - site.installCommand, - site.buildCommand, - site.outputDirectory, - site.buildRuntime as BuildRuntime, - site.adapter as Adapter, - site.fallbackFile, - selectedInstallationId, - selectedRepository, - 'main', - undefined, - undefined, - undefined - ); - invalidate(Dependencies.SITE); + await connect(selectedInstallationId, selectedRepository); show = false; - dispatch('connect', s); addNotification({ type: 'success', message: 'Repository connected successfully' @@ -97,9 +79,10 @@ onSubmit={connectRepo} bind:error> - Connect your site to an existing repository or create a new one. + Connect your {product === 'functions' ? 'function' : 'site'} to an existing repository or create + a new one. - {#if hasInstallations} + {#if !!installations?.total} {#if !onlyExisting} @@ -112,18 +95,17 @@ {installations} /> {:else} { + connect={(e) => { trackEvent(Click.ConnectRepositoryClick, { - from: 'sites' + from: product }); - repository.set(e.detail); - repositoryName = e.detail.name; - selectedRepository = e.detail.id; + repository.set(e); + repositoryName = e.name; + selectedRepository = e.id; connectRepo(); }} /> {/if} diff --git a/src/lib/components/git/deploymentDomains.svelte b/src/lib/components/git/deploymentDomains.svelte index 425612558..bb6ed3942 100644 --- a/src/lib/components/git/deploymentDomains.svelte +++ b/src/lib/components/git/deploymentDomains.svelte @@ -6,34 +6,49 @@ import type { Models } from '@appwrite.io/console'; import { IconExternalLink, IconQrcode } from '@appwrite.io/pink-icons-svelte'; import { ActionMenu, Icon, Layout, Popover, Tag, Typography } from '@appwrite.io/pink-svelte'; - import { createEventDispatcher } from 'svelte'; - export let domains: Models.ProxyRuleList; - export let hideQRCode = true; + let { + domains, + hideQRCode = true, + showQR = () => {} + }: { + domains: Models.ProxyRuleList; + hideQRCode?: boolean; + showQR?: (show: boolean) => void; + } = $props(); - const dispatch = createEventDispatcher(); + let sortedDomains = $derived( + domains?.rules?.sort((a, b) => { + if (a?.trigger === 'manual' && b?.trigger !== 'manual') { + return -1; + } else if (a?.trigger !== 'manual' && b?.trigger === 'manual') { + return 1; + } + return 0; + }) + ); {#if domains?.total} - + - {domains.rules[0]?.domain} + {sortedDomains[0]?.domain} - {#if domains.rules.length > 1} + {#if sortedDomains.length > 1} - +{domains.rules.length - 1} + +{sortedDomains.length - 1} - {#each domains.rules as rule, i} + {#each sortedDomains as rule, i} {#if i !== 0} {/if} {#if !hideQRCode} - dispatch('showQR')}> + showQR(true)}> {/if} diff --git a/src/lib/components/git/deploymentSource.svelte b/src/lib/components/git/deploymentSource.svelte index 071b7c5e6..99d7aebfc 100644 --- a/src/lib/components/git/deploymentSource.svelte +++ b/src/lib/components/git/deploymentSource.svelte @@ -11,7 +11,11 @@ } from '@appwrite.io/pink-icons-svelte'; import { ActionMenu, Layout, Popover, Icon } from '@appwrite.io/pink-svelte'; - export let deployment: Models.Deployment; + let { + deployment + }: { + deployment: Models.Deployment; + } = $props(); {#if deployment.type === 'vcs'} diff --git a/src/lib/components/git/index.ts b/src/lib/components/git/index.ts index 50028158f..a5cab5eed 100644 --- a/src/lib/components/git/index.ts +++ b/src/lib/components/git/index.ts @@ -8,3 +8,4 @@ export { default as DeploymentDomains } from './deploymentDomains.svelte'; export { default as ConnectBehaviour } from './connectBehaviour.svelte'; export { default as ProductionBranchFieldset } from './productionBranchFieldset.svelte'; export { default as RepositoryCard } from './repositoryCard.svelte'; +export { default as ConnectRepoModal } from './connectRepoModal.svelte'; diff --git a/src/lib/components/git/productionBranchFieldset.svelte b/src/lib/components/git/productionBranchFieldset.svelte index 3f4d6d09c..e97bcacf5 100644 --- a/src/lib/components/git/productionBranchFieldset.svelte +++ b/src/lib/components/git/productionBranchFieldset.svelte @@ -1,6 +1,6 @@ {#if hasInstallations} @@ -117,13 +125,23 @@ { - return { - label: entry.organization, - value: entry.$id - }; - })} + options={[ + ...installations.map((entry) => { + return { + label: entry.organization, + value: entry.$id + }; + }), + { + label: 'Add installation', + leadingIcon: IconPlus, + value: 'new' + } + ]} on:change={() => { + if (selectedInstallation === 'new') { + window.location.href = connectGitHub(callbackState).toString(); + } search = ''; installation.set( installations.find((entry) => entry.$id === selectedInstallation) @@ -154,84 +172,90 @@ {:then response} {#if response?.length} - - - {#each paginatedItems as repo} - - - - {#if action === 'select'} - repository.set(repo)} - value={repo.id} /> - {/if} - {#if product === 'sites'} - {#if repo?.framework && repo.framework !== 'other'} - - - - {:else} - - {/if} - {:else} - {@const iconName = repo?.runtime - ? repo.runtime.split('-')[0] - : undefined} - - - - {/if} + + {#snippet children(paginatedItems)} + + {#each paginatedItems as repo} + + - - {repo.name} - - {#if repo.private} - + alignItems="center" + gap="s"> + {#if action === 'select'} + repository.set(repo)} + value={repo.id} /> {/if} - - - {timeFromNow(repo.pushedAt)} - - - - {#if action === 'button'} - - + + + {:else} + + {/if} + {:else} + {@const iconName = repo?.runtime + ? repo.runtime.split('-')[0] + : undefined} + dispatch('connect', repo)}> - Connect - + alt={repo.name} + empty={!iconName}> + + + {/if} + + + {repo.name} + + {#if repo.private} + + {/if} + + + {timeFromNow(repo.pushedAt)} + + - {/if} - - - - {/each} - + {#if action === 'button'} + + connect(repo)}> + Connect + + + {/if} + + + + {/each} + + {/snippet} {:else} diff --git a/src/lib/components/menu/menu.svelte b/src/lib/components/menu/menu.svelte index ca115bb76..6e7e3a030 100644 --- a/src/lib/components/menu/menu.svelte +++ b/src/lib/components/menu/menu.svelte @@ -1,6 +1,7 @@ + {#if $open} + + {/if} - + {#if $$slots.start} diff --git a/src/lib/components/menu/store.ts b/src/lib/components/menu/store.ts new file mode 100644 index 000000000..571b30b82 --- /dev/null +++ b/src/lib/components/menu/store.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const menuOpen = writable(false); diff --git a/src/lib/components/menu/subMenu.svelte b/src/lib/components/menu/subMenu.svelte index 29a0487f5..4fa080832 100644 --- a/src/lib/components/menu/subMenu.svelte +++ b/src/lib/components/menu/subMenu.svelte @@ -21,7 +21,7 @@ - + {#if $$slots.start} diff --git a/src/lib/components/navbar.svelte b/src/lib/components/navbar.svelte index 855201b10..b5672af48 100644 --- a/src/lib/components/navbar.svelte +++ b/src/lib/components/navbar.svelte @@ -243,8 +243,11 @@ class:keepTransformTransition={shouldAnimateThemeToggle}> - (shouldAnimateThemeToggle = true)} + on:change={() => { + setTimeout(() => { + shouldAnimateThemeToggle = true; + }, 150); + }} buttons={[ { id: 'light', diff --git a/src/lib/components/paginationInline.svelte b/src/lib/components/paginationInline.svelte index 3e718cf0a..924a3f6ef 100644 --- a/src/lib/components/paginationInline.svelte +++ b/src/lib/components/paginationInline.svelte @@ -54,14 +54,7 @@ {#if !hidePages} - + {:else} - + {@render children(paginatedItems, limit)} {#if !hideFooter} diff --git a/src/lib/components/permissions/permissions.svelte b/src/lib/components/permissions/permissions.svelte index 1118e4173..cfd2a2f5c 100644 --- a/src/lib/components/permissions/permissions.svelte +++ b/src/lib/components/permissions/permissions.svelte @@ -215,7 +215,7 @@ {groups} on:create={create} let:toggle> - + diff --git a/src/lib/components/searchQuery.svelte b/src/lib/components/searchQuery.svelte index 73bae1230..3c26004a8 100644 --- a/src/lib/components/searchQuery.svelte +++ b/src/lib/components/searchQuery.svelte @@ -1,61 +1,50 @@ @@ -63,14 +52,15 @@ {placeholder} {disabled} {required} - bind:value={search} + {autofocus} + bind:value={inputValue} --bgcolor-neutral-default="var(--bgcolor-neutral-primary)"> - {#if search} - (search = '')} /> + {#if inputValue} + {/if} diff --git a/src/lib/components/sidebar.svelte b/src/lib/components/sidebar.svelte index cd72a5ece..e1a592675 100644 --- a/src/lib/components/sidebar.svelte +++ b/src/lib/components/sidebar.svelte @@ -70,8 +70,7 @@ } $: state = $isTabletViewport ? 'closed' : getSidebarState(); - $: pathname = page.url.pathname; - $: isOnProjectSettings = /^\/console\/project-[a-zA-Z0-9-]+\/settings$/.test(pathname); + $: isOnProjectSettings = /^\/console\/project-[a-zA-Z0-9-]+\/settings$/.test(page.url.pathname); const projectOptions = [ { name: 'Auth', icon: IconUserGroup, slug: 'auth', category: 'build' }, @@ -145,7 +144,7 @@ { trackEvent(Click.MenuOverviewClick); sideBarIsOpen = false; @@ -175,7 +174,7 @@ { trackEvent(`click_menu_${projectOption.slug}`); sideBarIsOpen = false; @@ -206,7 +205,7 @@ { trackEvent(`click_menu_${projectOption.slug}`); sideBarIsOpen = false; diff --git a/src/lib/elements/forms/inputFilePicker.svelte b/src/lib/elements/forms/inputFilePicker.svelte index 6c62e4629..38c90d163 100644 --- a/src/lib/elements/forms/inputFilePicker.svelte +++ b/src/lib/elements/forms/inputFilePicker.svelte @@ -3,7 +3,7 @@ import FilePicker from '$lib/components/filePicker.svelte'; import { humanFileSize } from '$lib/helpers/sizeConvertion'; import type { Models } from '@appwrite.io/console'; - import { Label } from '.'; + import { Button, Label } from '.'; export let label: string = null; export let value: Models.File = null; @@ -62,13 +62,7 @@ Max file size: 1MB - (show = true)}> - Browse - + (show = true)}>Browse {#if value} diff --git a/src/lib/helpers/date.ts b/src/lib/helpers/date.ts index 420d1ab45..293062e6d 100644 --- a/src/lib/helpers/date.ts +++ b/src/lib/helpers/date.ts @@ -190,6 +190,13 @@ export const diffDays = (date1: Date, date2: Date) => { }; export function timeFromNow(datetime: string): string { + if (!datetime) { + return 'unknown time'; + } + if (!isValidDate(datetime)) { + return 'invalid date'; + } + return dayjs().to(dayjs(datetime)); } @@ -216,3 +223,12 @@ export function getUTCOffset(): string { return `${hours >= 0 ? '+' : ''}${hours}${minutes ? `:${minutes.toString().padStart(2, '0')}` : ''}`; } + +export function toISOString(date: string): string { + const d = new Date(date); + + if (isNaN(d.getTime())) { + return 'n/a'; + } + return d.toISOString(); +} diff --git a/src/lib/helpers/domains.test.ts b/src/lib/helpers/domains.test.ts new file mode 100644 index 000000000..8d6c487bf --- /dev/null +++ b/src/lib/helpers/domains.test.ts @@ -0,0 +1,382 @@ +import { describe, expect, it } from 'vitest'; +import { parseDnsRecords } from './domains'; + +describe('parseDnsRecords', () => { + it('should parse standard zone file with origin', () => { + const content = `$ORIGIN example.com. ; designates the start of this zone file in the namespace +$TTL 3600 ; default expiration time (in seconds) of all RRs without their own TTL value +example.com. IN SOA ns.example.com. username.example.com. ( 2020091025 7200 3600 1209600 3600 ) +example.com. IN NS ns ; ns.example.com is a nameserver for example.com +example.com. IN NS ns.somewhere.example. ; ns.somewhere.example is a backup nameserver for example.com +example.com. IN MX 10 mail.example.com. ; mail.example.com is the mailserver for example.com +@ IN MX 20 mail2.example.com. ; equivalent to above line, "@" represents zone origin +@ IN MX 50 mail3 ; equivalent to above line, but using a relative host name +example.com. IN A 192.0.2.1 ; IPv4 address for example.com + IN AAAA 2001:db8:10::1 ; IPv6 address for example.com +ns IN A 192.0.2.2 ; IPv4 address for ns.example.com + IN AAAA 2001:db8:10::2 ; IPv6 address for ns.example.com +www IN CNAME example.com. ; www.example.com is an alias for example.com +wwwtest IN CNAME www ; wwwtest.example.com is another alias for www.example.com +mail IN A 192.0.2.3 ; IPv4 address for mail.example.com +mail2 IN A 192.0.2.4 ; IPv4 address for mail2.example.com +mail3 IN A 192.0.2.5 ; IPv4 address for mail3.example.com`; + + const result = parseDnsRecords(content); + + expect(result.NS).toHaveLength(2); + expect(result.NS[0].name).toBe('example.com'); + expect(result.NS[0].value).toBe('ns'); + expect(result.NS[1].name).toBe('example.com'); + expect(result.NS[1].value).toBe('ns.somewhere.example'); + + expect(result.MX).toHaveLength(3); + expect(result.MX[0].name).toBe('example.com'); + expect(result.MX[0].priority).toBe(10); + expect(result.MX[0].value).toBe('mail.example.com'); + expect(result.MX[1].name).toBe(''); + expect(result.MX[1].priority).toBe(20); + expect(result.MX[1].value).toBe('mail2.example.com'); + expect(result.MX[2].name).toBe(''); + expect(result.MX[2].priority).toBe(50); + expect(result.MX[2].value).toBe('mail3'); + + expect(result.A).toHaveLength(5); + expect(result.A[0].name).toBe('example.com'); + expect(result.A[0].value).toBe('192.0.2.1'); + expect(result.A[1].name).toBe('ns'); + expect(result.A[1].value).toBe('192.0.2.2'); + expect(result.A[2].name).toBe('mail'); + expect(result.A[2].value).toBe('192.0.2.3'); + expect(result.A[3].name).toBe('mail2'); + expect(result.A[3].value).toBe('192.0.2.4'); + expect(result.A[4].name).toBe('mail3'); + expect(result.A[4].value).toBe('192.0.2.5'); + + expect(result.AAAA).toHaveLength(2); + expect(result.AAAA[0].name).toBe('example.com'); + expect(result.AAAA[0].value).toBe('2001:db8:10::1'); + expect(result.AAAA[1].name).toBe('ns'); + expect(result.AAAA[1].value).toBe('2001:db8:10::2'); + + expect(result.CNAME).toHaveLength(2); + expect(result.CNAME[0].name).toBe('www'); + expect(result.CNAME[0].value).toBe('example.com'); + expect(result.CNAME[1].name).toBe('wwwtest'); + expect(result.CNAME[1].value).toBe('www'); + }); + + it('should parse localhost zone file', () => { + const content = `$ORIGIN localhost. +@ 86400 IN SOA @ root ( + 1999010100 ; serial + 10800 ; refresh (3 hours) + 900 ; retry (15 minutes) + 604800 ; expire (1 week) + 86400 ; minimum (1 day) + ) +@ 86400 IN NS @ +@ 86400 IN A 127.0.0.1 +@ 86400 IN AAAA ::1`; + + const result = parseDnsRecords(content); + + expect(result.NS).toHaveLength(1); + expect(result.NS[0].name).toBe(''); + expect(result.NS[0].value).toBe('@'); + expect(result.NS[0].ttl).toBe(86400); + + expect(result.A).toHaveLength(1); + expect(result.A[0].name).toBe(''); + expect(result.A[0].value).toBe('127.0.0.1'); + expect(result.A[0].ttl).toBe(86400); + + expect(result.AAAA).toHaveLength(1); + expect(result.AAAA[0].name).toBe(''); + expect(result.AAAA[0].value).toBe('::1'); + expect(result.AAAA[0].ttl).toBe(86400); + }); + + it('should parse complex zone file with multiple record types and comments', () => { + const content = `; Exported (y-m-d hh:mm:ss): 2019-01-10 13:05:04 +; +; This file is intended for use for informational and archival +; purposes ONLY and MUST be edited before use on a production +; DNS server. +; +; In particular, you must update the SOA record with the correct +; authoritative name server and contact e-mail address information, +; and add the correct NS records for the name servers which will +; be authoritative for this domain. +; +; For further information, please consult the BIND documentation +; located on the following website: +; +; http://www.isc.org/ +; +; And RFC 1035: +; +; http://www.ietf.org/rfc/rfc1035.txt +; +; Please note that we do NOT offer technical support for any use +; of this zone data, the BIND name server, or any other third- +; party DNS software. +; +; Use at your own risk. +; SOA Record +example.com. 3600 IN SOA ns41.domaincontrol.com. dns.net. ( + 2018122702 + 28800 + 7200 + 604800 + 3600 + ) +; A Records +@ 600 IN A 192.0.2.249 +blog 10800 IN A 192.0.2.255 +dev 1800 IN A 192.0.2.254 +dev01 1800 IN A 192.0.2.253 +dev02 1800 IN A 192.0.2.252 +dev03 1800 IN A 192.0.2.251 +dev04 1800 IN A 192.0.2.250 +; CNAME Records +abc123b432dc7785b7ef31f04f25c3e71 1800 IN CNAME verify.bing.com. +akamai 600 IN CNAME www.example.com.edgekey.net. +email 3600 IN CNAME email.secureserver.net. +; MX Records +@ 604800 IN MX 10 amlxe.l.google.com. +@ 604800 IN MX 10 aplxe.l.google.com. +; TXT Records +@ 3600 IN TXT "google-site-verification=3J82-80dbMyCo5Q5C1G11JszeOnZPGCSYlHcPcXg" +@ 3600 IN TXT "google-site-verification=eS_QPYLE_W4nduSrlN-cddxG7ZqOnB743xsbX918"`; + + const result = parseDnsRecords(content); + + expect(result.A).toHaveLength(7); + expect(result.A[0].name).toBe(''); + expect(result.A[0].value).toBe('192.0.2.249'); + expect(result.A[0].ttl).toBe(600); + expect(result.A[1].name).toBe('blog'); + expect(result.A[1].value).toBe('192.0.2.255'); + expect(result.A[1].ttl).toBe(10800); + + expect(result.CNAME).toHaveLength(3); + expect(result.CNAME[0].name).toBe('abc123b432dc7785b7ef31f04f25c3e71'); + expect(result.CNAME[0].value).toBe('verify.bing.com'); + expect(result.CNAME[0].ttl).toBe(1800); + expect(result.CNAME[1].name).toBe('akamai'); + expect(result.CNAME[1].value).toBe('www.example.com.edgekey.net'); + expect(result.CNAME[1].ttl).toBe(600); + + expect(result.MX).toHaveLength(2); + expect(result.MX[0].name).toBe(''); + expect(result.MX[0].value).toBe('amlxe.l.google.com'); + expect(result.MX[0].priority).toBe(10); + expect(result.MX[0].ttl).toBe(604800); + expect(result.MX[1].name).toBe(''); + expect(result.MX[1].value).toBe('aplxe.l.google.com'); + expect(result.MX[1].priority).toBe(10); + expect(result.MX[1].ttl).toBe(604800); + + expect(result.TXT).toHaveLength(2); + expect(result.TXT[0].name).toBe(''); + expect(result.TXT[0].value).toBe( + 'google-site-verification=3J82-80dbMyCo5Q5C1G11JszeOnZPGCSYlHcPcXg' + ); + expect(result.TXT[0].ttl).toBe(3600); + expect(result.TXT[1].name).toBe(''); + expect(result.TXT[1].value).toBe( + 'google-site-verification=eS_QPYLE_W4nduSrlN-cddxG7ZqOnB743xsbX918' + ); + expect(result.TXT[1].ttl).toBe(3600); + }); + + it('should parse zone file with origin prefix', () => { + const content = `$ORIGIN example.com. +example.com. 3600 IN SOA ns41.domaincontrol.com. dns.net. ( + 2018122702 + 28800 + 7200 + 604800 + 3600 + ) + +; A Records +@ 600 IN A 192.0.2.249 +blog 10800 IN A 192.0.2.255 +dev 1800 IN A 192.0.2.254 +dev01 1800 IN A 192.0.2.253 +dev02 1800 IN A 192.0.2.252 +dev03 1800 IN A 192.0.2.251 +dev04 1800 IN A 192.0.2.250 +abc123b432dc7785b7ef31f04f25c3e71 1800 IN CNAME verify.bing.com. +; CNAME Records +akamai 600 IN CNAME www.example.edgekey.net. +email 3600 IN CNAME email.secureserver.net. +; MX Records +@ 604800 IN MX 10 amlxe.l.google.com. +@ 604800 IN MX 10 aplxe.l.google.com. +; TXT Records +@ 3600 IN TXT "google-site-verification=3J82-80dbMyCo5Q5C1GM8os1VYVEOnZPGCSYlHcPcXg" +@ 3600 IN TXT "google-site-verification=eS_QPYLE_W4nduSrlN-cddxG7ZqOnB7k7uIG7qrsyu8"`; + + const result = parseDnsRecords(content); + + expect(result.A).toHaveLength(7); + expect(result.A[0].name).toBe(''); + expect(result.A[0].value).toBe('192.0.2.249'); + expect(result.A[0].ttl).toBe(600); + + expect(result.CNAME).toHaveLength(3); + expect(result.CNAME[0].name).toBe('abc123b432dc7785b7ef31f04f25c3e71'); + expect(result.CNAME[0].value).toBe('verify.bing.com'); + expect(result.CNAME[1].name).toBe('akamai'); + expect(result.CNAME[1].value).toBe('www.example.edgekey.net'); + + expect(result.MX).toHaveLength(2); + expect(result.MX[0].name).toBe(''); + expect(result.MX[0].priority).toBe(10); + expect(result.MX[0].value).toBe('amlxe.l.google.com'); + + expect(result.TXT).toHaveLength(2); + expect(result.TXT[0].name).toBe(''); + expect(result.TXT[0].value).toBe( + 'google-site-verification=3J82-80dbMyCo5Q5C1GM8os1VYVEOnZPGCSYlHcPcXg' + ); + }); + + it('should parse complex zone file with multiple servers', () => { + const content = `$ORIGIN example.com. +$TTL 86400 +@ IN SOA dns1.example.com. hostmaster.example.com. ( + 2001062501 ; serial + 21600 ; refresh after 6 hours + 3600 ; retry after 1 hour + 604800 ; expire after 1 week + 86400 ) ; minimum TTL of 1 day + + + IN NS dns1.example.com. + IN NS dns2.example.com. + + + IN MX 10 mail.example.com. + IN MX 20 mail2.example.com. + + +dns1 IN A 10.0.1.1 +dns2 IN A 10.0.1.2 + + +server1 IN A 10.0.1.5 +server2 IN A 10.0.1.6 + + +ftp IN A 10.0.1.3 + IN A 10.0.1.4 + +mail IN CNAME server1 +mail2 IN CNAME server2 + + +www IN CNAME server1`; + + const result = parseDnsRecords(content); + + expect(result.NS).toHaveLength(2); + expect(result.NS[0].name).toBe(''); + expect(result.NS[0].value).toBe('dns1.example.com'); + expect(result.NS[1].name).toBe(''); + expect(result.NS[1].value).toBe('dns2.example.com'); + + expect(result.MX).toHaveLength(2); + expect(result.MX[0].name).toBe(''); + expect(result.MX[0].priority).toBe(10); + expect(result.MX[0].value).toBe('mail.example.com'); + expect(result.MX[1].name).toBe(''); + expect(result.MX[1].priority).toBe(20); + expect(result.MX[1].value).toBe('mail2.example.com'); + + expect(result.A).toHaveLength(6); + expect(result.A[0].name).toBe('dns1'); + expect(result.A[0].value).toBe('10.0.1.1'); + expect(result.A[1].name).toBe('dns2'); + expect(result.A[1].value).toBe('10.0.1.2'); + expect(result.A[2].name).toBe('server1'); + expect(result.A[2].value).toBe('10.0.1.5'); + expect(result.A[3].name).toBe('server2'); + expect(result.A[3].value).toBe('10.0.1.6'); + expect(result.A[4].name).toBe('ftp'); + expect(result.A[4].value).toBe('10.0.1.3'); + expect(result.A[5].name).toBe('ftp'); + expect(result.A[5].value).toBe('10.0.1.4'); + + expect(result.CNAME).toHaveLength(3); + expect(result.CNAME[0].name).toBe('mail'); + expect(result.CNAME[0].value).toBe('server1'); + expect(result.CNAME[1].name).toBe('mail2'); + expect(result.CNAME[1].value).toBe('server2'); + expect(result.CNAME[2].name).toBe('www'); + expect(result.CNAME[2].value).toBe('server1'); + }); + + it('should parse reverse zone file with PTR records', () => { + const content = `;; reverse zone file for 127.0.0.1 and ::1 +$TTL 1814400 ; 3 weeks +@ 1814400 IN SOA localhost. root.localhost. ( + 1999010100 ; serial + 10800 ; refresh (3 hours) + 900 ; retry (15 minutes) + 604800 ; expire (1 week) + 86400 ; minimum (1 day) + ) +@ 1814400 IN NS localhost. +1 1814400 IN PTR localhost.`; + + const result = parseDnsRecords(content); + + expect(result.NS).toHaveLength(1); + expect(result.NS[0].name).toBe(''); + expect(result.NS[0].value).toBe('localhost'); + expect(result.NS[0].ttl).toBe(1814400); + + expect(result.PTR).toHaveLength(1); + expect(result.PTR[0].name).toBe('1'); + expect(result.PTR[0].value).toBe('localhost'); + expect(result.PTR[0].ttl).toBe(1814400); + }); + + it('should handle empty content', () => { + const result = parseDnsRecords(''); + expect(result.A).toHaveLength(0); + expect(result.AAAA).toHaveLength(0); + expect(result.CNAME).toHaveLength(0); + expect(result.MX).toHaveLength(0); + expect(result.NS).toHaveLength(0); + expect(result.TXT).toHaveLength(0); + expect(result.PTR).toHaveLength(0); + }); + + it('should handle invalid content', () => { + const result = parseDnsRecords('This is not a valid zone file'); + expect(result.A).toHaveLength(0); + expect(result.AAAA).toHaveLength(0); + expect(result.CNAME).toHaveLength(0); + expect(result.MX).toHaveLength(0); + expect(result.NS).toHaveLength(0); + expect(result.TXT).toHaveLength(0); + expect(result.PTR).toHaveLength(0); + }); + + it('should handle content with only comments', () => { + const result = parseDnsRecords(`; This is a comment +; This is another comment +; And one more comment`); + expect(result.A).toHaveLength(0); + expect(result.AAAA).toHaveLength(0); + expect(result.CNAME).toHaveLength(0); + expect(result.MX).toHaveLength(0); + expect(result.NS).toHaveLength(0); + expect(result.TXT).toHaveLength(0); + expect(result.PTR).toHaveLength(0); + }); +}); diff --git a/src/lib/helpers/domains.ts b/src/lib/helpers/domains.ts new file mode 100644 index 000000000..18e47e5f4 --- /dev/null +++ b/src/lib/helpers/domains.ts @@ -0,0 +1,106 @@ +import type { DnsRecord } from '$lib/sdk/domains'; +import { sdk } from '$lib/stores/sdk'; + +export async function createRecord(record: Partial, domainId: string) { + switch (record.type) { + case 'A': + return await sdk.forConsole.domains.createRecordA( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'AAAA': + return await sdk.forConsole.domains.createRecordAAAA( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'CNAME': + return await sdk.forConsole.domains.createRecordCNAME( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'MX': + return await sdk.forConsole.domains.createRecordMX( + domainId, + record.name, + record.value, + record.priority || 10, + record.ttl, + record?.comment || undefined + ); + case 'TXT': + return await sdk.forConsole.domains.createRecordTXT( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'NS': + return await sdk.forConsole.domains.createRecordNS( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'SRV': + return await sdk.forConsole.domains.createRecordSRV( + domainId, + record.name, + record.value, + record.ttl, + record.priority, + record.weight, + record.port, + record?.comment || undefined + ); + case 'CAA': + return await sdk.forConsole.domains.createRecordCAA( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'HTTPS': + return await sdk.forConsole.domains.createRecordHTTPS( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + case 'ALIAS': + return await sdk.forConsole.domains.createRecordAlias( + domainId, + record.name, + record.value, + record.ttl, + record?.comment || undefined + ); + } +} + +export type ParsedRecords = { + A: Partial[]; + AAAA: Partial[]; + CNAME: Partial[]; + MX: Partial[]; + TXT: Partial[]; + NS: Partial[]; + SRV: Partial[]; + CAA: Partial[]; + PTR: Partial[]; + HTTPS: Partial[]; + ALIAS: Partial[]; + [key: string]: Partial[]; +}; diff --git a/src/lib/layout/createProject.svelte b/src/lib/layout/createProject.svelte index dbbf41f5e..4758dbbb0 100644 --- a/src/lib/layout/createProject.svelte +++ b/src/lib/layout/createProject.svelte @@ -58,7 +58,7 @@ size="s" on:click={() => { showCustomId = true; - }}> Project ID + }}> Project ID {/if} diff --git a/src/lib/stores/domains.ts b/src/lib/stores/domains.ts index 82f716700..ea339f83d 100644 --- a/src/lib/stores/domains.ts +++ b/src/lib/stores/domains.ts @@ -20,3 +20,15 @@ export const statusCodeOptions = [ value: 308 } ]; + +export type RecordType = + | 'A' + | 'AAAA' + | 'CNAME' + | 'MX' + | 'TXT' + | 'NS' + | 'SRV' + | 'CAA' + | 'HTTPS' + | 'ALIAS'; diff --git a/src/lib/stores/stripe.ts b/src/lib/stores/stripe.ts index b461af01e..86651a3e8 100644 --- a/src/lib/stores/stripe.ts +++ b/src/lib/stores/stripe.ts @@ -62,7 +62,7 @@ export async function submitStripeCard(name: string, organizationId?: string) { } // Element needs to be submitted before confirming the setup intent - elements.submit(); + await elements.submit(); const baseUrl = 'https://cloud.appwrite.io/console'; const accountUrl = `${baseUrl}/account/payments?clientSecret=${clientSecret}`; diff --git a/src/routes/(console)/onboarding/create-project/+page.svelte b/src/routes/(console)/onboarding/create-project/+page.svelte index e43906c5a..d6676a320 100644 --- a/src/routes/(console)/onboarding/create-project/+page.svelte +++ b/src/routes/(console)/onboarding/create-project/+page.svelte @@ -115,7 +115,7 @@ on:submit={createProject}> - + Create diff --git a/src/routes/(console)/onboarding/create-project/loading.svelte b/src/routes/(console)/onboarding/create-project/loading.svelte index f623646c5..484c0cfce 100644 --- a/src/routes/(console)/onboarding/create-project/loading.svelte +++ b/src/routes/(console)/onboarding/create-project/loading.svelte @@ -269,6 +269,7 @@ transition: opacity 0.5s var(--animation-type); @media (min-width: 768px) { + margin-top: 50px; margin-bottom: 50px; } } diff --git a/src/routes/(console)/organization-[organization]/+page.svelte b/src/routes/(console)/organization-[organization]/+page.svelte index 1d21dac63..c5f2bc244 100644 --- a/src/routes/(console)/organization-[organization]/+page.svelte +++ b/src/routes/(console)/organization-[organization]/+page.svelte @@ -47,16 +47,21 @@ let showCreate = false; let showCreateProjectCloud = false; - function allServiceDisabled(project: Models.Project): boolean { - return false; + async function allServiceDisabled(project: Models.Project) { let disabled = true; - services.load(project); - $services.list.forEach((service) => { - if (service.value) { - disabled = false; - } - }); - return disabled; + try { + if (!project.$id) return false; + if (!project.platforms.length) return false; + services.load(project); + $services.list.forEach((service) => { + if (service.value) { + disabled = false; + } + }); + return disabled; + } catch (e) { + return true; + } } function filterPlatforms(platforms: { name: string; icon: string }[]) { @@ -209,12 +214,14 @@ {project.name} - {#if allServiceDisabled(project)} - - All services are - disabled. - - {/if} + {#await allServiceDisabled(project) then isDisabled} + {#if isDisabled} + + All services are + disabled. + + {/if} + {/await} {#each platforms as platform, i} {#if i < 3} diff --git a/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte b/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte index ecae47486..6cb9717e2 100644 --- a/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte +++ b/src/routes/(console)/organization-[organization]/billing/paymentMethods.svelte @@ -230,7 +230,7 @@ - + {#if $paymentMethods.total} {#each filteredPaymentMethods as paymentMethod} (showPayment = true)}> + on:click={(e) => { + toggle(e); + showPayment = true; + }}> Add new payment method @@ -262,7 +265,7 @@ - + {#if $paymentMethods.total} {#each filteredPaymentMethods as paymentMethod} (showPayment = true)}> + on:click={(e) => { + toggle(e); + showPayment = true; + }}> Add new payment method diff --git a/src/routes/(console)/organization-[organization]/domains/+page.svelte b/src/routes/(console)/organization-[organization]/domains/+page.svelte index c32b99235..a847238d5 100644 --- a/src/routes/(console)/organization-[organization]/domains/+page.svelte +++ b/src/routes/(console)/organization-[organization]/domains/+page.svelte @@ -1,7 +1,7 @@ @@ -45,7 +73,7 @@ Import zone file - + Export as .txt diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/addPresetModal.svelte b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/addPresetModal.svelte index e5db0d394..5305ee2b7 100644 --- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/addPresetModal.svelte +++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/addPresetModal.svelte @@ -11,6 +11,7 @@ import { presets } from './store'; import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; + import { createRecord } from '$lib/helpers/domains'; export let show = false; export let selectedPreset: (typeof presets)[number]; @@ -35,16 +36,9 @@ async function handleSubmit() { try { - //TODO: create DNS records if (records.total) { - const promises = records.dnsRecords.map((record) => - sdk.forConsole.domains.createRecordMX( - page.params.domain, - record.name, - record.value, - record.ttl, - record.priority - ) + const promises = records.dnsRecords.map( + async (record) => await createRecord(record, page.params.domain) ); await Promise.all(promises); } @@ -62,8 +56,6 @@ trackError(e, Submit.RecordCreate); } } - - $: console.log(selectedPreset); []; - AAAA: Partial[]; - CNAME: Partial[]; - MX: Partial[]; - TXT: Partial[]; - NS: Partial[]; - SRV: Partial[]; - CAA: Partial[]; - PTR: Partial[]; - HTTPS: Partial[]; - ALIAS: Partial[]; - [key: string]: Partial[]; - }; - - function parseZoneFile(content: string): ParsedRecords { - const records: ParsedRecords = { - A: [], - AAAA: [], - CNAME: [], - MX: [], - TXT: [], - NS: [], - SRV: [], - CAA: [], - PTR: [], - HTTPS: [], - ALIAS: [] - }; - - // Split the content into lines and process each line - const lines = content.split('\n'); - - for (let line of lines) { - // Remove comments, but save them for record comment field - let comment = ''; - const commentIndex = line.indexOf(';'); - if (commentIndex !== -1) { - comment = line.substring(commentIndex + 1).trim(); - line = line.substring(0, commentIndex).trim(); - } - - // Skip empty lines or pure comment lines - if (!line.trim()) continue; - - // Split line into parts (whitespace separated) - const parts = line.trim().split(/\s+/); - - // Need at least a name, TTL/class/type, and value - if (parts.length < 3) continue; - - let recordType = ''; - let name = ''; - let value = ''; - let ttl = 3600; - let priority: number | undefined; - let weight: number | undefined; - let port: number | undefined; - - // Try to determine the record type from the parts - for (let i = 0; i < parts.length; i++) { - const part = parts[i].toUpperCase(); - if (['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SRV', 'CAA'].includes(part)) { - recordType = part; - name = parts[0] === '@' ? '' : parts[0]; // @ represents the domain itself - - // Handle TTL if it appears to be a number - const possibleTtl = parseInt(parts[i - 1]); - if (!isNaN(possibleTtl) && i > 0) { - ttl = possibleTtl; - } - - if (recordType === 'MX' && i + 2 < parts.length) { - priority = parseInt(parts[i + 1]); - value = parts[i + 2]; - } else if (recordType === 'SRV' && i + 4 < parts.length) { - priority = parseInt(parts[i + 1]); - weight = parseInt(parts[i + 2]); - port = parseInt(parts[i + 3]); - value = parts[i + 4]; - } else if (i + 1 < parts.length) { - value = parts.slice(i + 1).join(' '); - } - - break; - } - } - - if (recordType && value) { - if (recordType === 'TXT' && value.startsWith('"') && value.endsWith('"')) { - value = value.slice(1, -1); - } - - const record: Partial = { - name, - value, - ttl, - comment: comment || undefined - }; - - if (priority !== undefined) { - record.priority = priority; - } - - if (!records[recordType]) { - records[recordType] = []; - } - - records[recordType].push(record); - } - } - - return records; - } - async function handleSubmit() { try { if (!files?.length) return; const file = files[0]; const content = await file.text(); - const parsedRecords = parseZoneFile(content); - - let recordCount = 0; - - for (const [type, records] of Object.entries(parsedRecords)) { - recordCount += records.length; - - for (const record of records) { - switch (type) { - case 'A': - await sdk.forConsole.domains.createRecordA( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'AAAA': - await sdk.forConsole.domains.createRecordAAAA( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'CNAME': - await sdk.forConsole.domains.createRecordCNAME( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'MX': - await sdk.forConsole.domains.createRecordMX( - page.params.domain, - record.name, - record.value, - record.priority || 10, - record.ttl, - record.comment - ); - break; - case 'TXT': - await sdk.forConsole.domains.createRecordTXT( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'NS': - await sdk.forConsole.domains.createRecordNS( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'SRV': - await sdk.forConsole.domains.createRecordSRV( - page.params.domain, - record.name, - record.value, - record.ttl, - record.priority, - record.weight, - record.port, - record.comment - ); - break; - case 'CAA': - await sdk.forConsole.domains.createRecordCAA( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'PTR': - await sdk.forConsole.domains.createRecordHTTPS( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - case 'ALIAS': - await sdk.forConsole.domains.createRecordAlias( - page.params.domain, - record.name, - record.value, - record.ttl, - record.comment - ); - break; - } - } - } + await sdk.forConsole.domains.updateZone(page.params.domain, content); + invalidate(Dependencies.DOMAIN); show = false; addNotification({ type: 'success', - message: `${recordCount} DNS records have been imported successfully` + message: `DNS records have been imported successfully` }); trackEvent(Submit.RecordCreate); } catch (e) { diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/updateRecordModal.svelte b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/updateRecordModal.svelte index 7f573ff7c..a559d79be 100644 --- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/updateRecordModal.svelte +++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/updateRecordModal.svelte @@ -20,8 +20,6 @@ import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; - // type RecordType = 'A' | 'AAAA' | 'CNAME' | 'MX' | 'TXT' | 'NS' | 'SRV' | 'CAA' | 'PTR'; - export let show = false; export let selectedRecord: DnsRecord; @@ -30,7 +28,6 @@ async function handleSubmit() { try { - //TODO: update DNS record switch (record.type) { case 'A': await sdk.forConsole.domains.updateRecordA( diff --git a/src/routes/(console)/organization-[organization]/domains/store.ts b/src/routes/(console)/organization-[organization]/domains/store.ts new file mode 100644 index 000000000..b8a22477d --- /dev/null +++ b/src/routes/(console)/organization-[organization]/domains/store.ts @@ -0,0 +1,11 @@ +import type { Column } from '$lib/helpers/types'; +import { writable } from 'svelte/store'; + +export const columns = writable([ + { id: 'domain', title: 'Domain', type: 'string', width: { min: 300 } }, + { id: 'registrar', title: 'Registrar', type: 'string' }, + { id: 'nameservers', title: 'Nameservers', type: 'string' }, + { id: 'expiry_date', title: 'Expiry Date', type: 'datetime' }, + { id: 'renewal', title: 'Renewal', type: 'boolean' }, + { id: 'auto_renewal', title: 'Auto Renewal', type: 'boolean' } +]); diff --git a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/totalMembers.svelte b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/totalMembers.svelte index e74b0c2ac..0d688edc7 100644 --- a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/totalMembers.svelte +++ b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/totalMembers.svelte @@ -52,37 +52,38 @@ - - - - Members - Joined - - {#each paginatedItems as member} - - - - - - - {member.userName ? member.userName : member.userEmail} - + + {#snippet children(paginatedItems: typeof members.memberships)} + + + Members + Joined + + {#each paginatedItems as member} + + + + + + + {member.userName + ? member.userName + : member.userEmail} + + - - - - - - - {/each} - + + + + + + {/each} + + {/snippet} {:else} diff --git a/src/routes/(console)/project-[project]/auth/+page.svelte b/src/routes/(console)/project-[project]/auth/+page.svelte index ec04ac85a..41ec7caac 100644 --- a/src/routes/(console)/project-[project]/auth/+page.svelte +++ b/src/routes/(console)/project-[project]/auth/+page.svelte @@ -59,7 +59,7 @@ - + ($showCreateUser = true)} event="create_user" size="s"> Create user diff --git a/src/routes/(console)/project-[project]/auth/user-[user]/identities/+page.svelte b/src/routes/(console)/project-[project]/auth/user-[user]/identities/+page.svelte index 4076b3698..901991a1d 100644 --- a/src/routes/(console)/project-[project]/auth/user-[user]/identities/+page.svelte +++ b/src/routes/(console)/project-[project]/auth/user-[user]/identities/+page.svelte @@ -48,13 +48,13 @@ - + - + diff --git a/src/routes/(console)/project-[project]/auth/user-[user]/targets/+page.svelte b/src/routes/(console)/project-[project]/auth/user-[user]/targets/+page.svelte index 08494ee20..087596e67 100644 --- a/src/routes/(console)/project-[project]/auth/user-[user]/targets/+page.svelte +++ b/src/routes/(console)/project-[project]/auth/user-[user]/targets/+page.svelte @@ -34,7 +34,7 @@ - + diff --git a/src/routes/(console)/project-[project]/auth/user-[user]/updateLabels.svelte b/src/routes/(console)/project-[project]/auth/user-[user]/updateLabels.svelte index d31063062..dc50f44b5 100644 --- a/src/routes/(console)/project-[project]/auth/user-[user]/updateLabels.svelte +++ b/src/routes/(console)/project-[project]/auth/user-[user]/updateLabels.svelte @@ -9,7 +9,8 @@ import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; import { user } from './store'; - import { Tag, Input, Layout } from '@appwrite.io/pink-svelte'; + import { Tag, Input, Layout, Icon } from '@appwrite.io/pink-svelte'; + import { IconPlus } from '@appwrite.io/pink-icons-svelte'; const alphaNumericRegExp = /^[a-zA-Z0-9]+$/; let suggestedLabels = ['admin', 'premium', 'mvp']; @@ -39,7 +40,6 @@ trackError(error, Submit.UserUpdateLabels); } } - $: console.log(labels); // TODO: Remove type cast when console SDK is updated $: isDisabled = !!error || @@ -68,11 +68,13 @@ New label-based roles will be assigned. - + {#key labels.length} + + {/key} {#each suggestedLabels as suggestedLabel} e !== suggestedLabel); } }}> - + {suggestedLabel} {/each} diff --git a/src/routes/(console)/project-[project]/databases/+page.svelte b/src/routes/(console)/project-[project]/databases/+page.svelte index f6bb4ca6a..051f49979 100644 --- a/src/routes/(console)/project-[project]/databases/+page.svelte +++ b/src/routes/(console)/project-[project]/databases/+page.svelte @@ -47,7 +47,7 @@ - + - + - + - + diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/email.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/email.svelte index 540cc370d..cf93d4b5f 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/email.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/email.svelte @@ -6,6 +6,14 @@ export let label: string; export let value: string | null; export let attribute: Models.AttributeUrl; + + $: nullable = attribute.required ? false : !value; - + diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/integer.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/integer.svelte index 2647c00e9..00ee6a2af 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/integer.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributes/integer.svelte @@ -6,12 +6,14 @@ export let label: string; export let value: number; export let attribute: Models.AttributeInteger; + + $: nullable = attribute.required ? false : !value; {#if attribute.size >= 50} diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/delete.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/delete.svelte index 0b3096fee..9c5e89302 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/delete.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/delete.svelte @@ -3,7 +3,7 @@ import { base } from '$app/paths'; import { page } from '$app/state'; import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; - import { Modal, Trim } from '$lib/components'; + import { Confirm, Trim } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; @@ -52,7 +52,7 @@ ) as Models.AttributeRelationship[]; - + Are you sure you want to delete the document from {$collection.name} (showDelete = false)}>Cancel Delete - + diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/indexes/createIndex.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/indexes/createIndex.svelte index 13e4b2fd0..99d742c3d 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/indexes/createIndex.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/indexes/createIndex.svelte @@ -158,7 +158,7 @@ {/each} - + Add attribute diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/relationshipsModal.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/relationshipsModal.svelte index 49bf2b4ac..c09462ccb 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/relationshipsModal.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/relationshipsModal.svelte @@ -27,34 +27,36 @@ {#if data?.length} - - ({ id }))]}> - - Document ID - {#if args?.length} - {#each args as arg} - {arg} - {/each} - {/if} - - {#each paginatedItems as doc} - (show = false)}> - - {doc.$id} - + + {#snippet children(paginatedItems: typeof data)} + ({ id }))]}> + + Document ID {#if args?.length} {#each args as arg} - {doc[arg]} + {arg} {/each} {/if} - - {/each} - + + {#each paginatedItems as doc} + (show = false)}> + + {doc.$id} + + {#if args?.length} + {#each args as arg} + {doc[arg]} + {/each} + {/if} + + {/each} + + {/snippet} {/if} diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/displayName.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/displayName.svelte index 64a98ae26..a60fc2489 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/displayName.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/displayName.svelte @@ -57,9 +57,8 @@ Display name - Select string attributes as display names for your documents. The selected names will be used - as short forms to identify documents in the Appwrite console, like when creating database relationships. - You can specify up to 5 names. + Select up to 5 string attributes to display as document names in the Appwrite console. These + help identify documents in places like relationships. @@ -94,7 +93,7 @@ {/if} { names[names.length] = null; diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/updatePermissions.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/updatePermissions.svelte index ee3028291..16d39d490 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/updatePermissions.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/settings/updatePermissions.svelte @@ -48,22 +48,19 @@ } } - $: if ( + $: arePermsDisabled = !( collectionPermissions && symmetricDifference(collectionPermissions, $collection.$permissions).length - ) { - arePermsDisabled = false; - } else arePermsDisabled = true; + ); Permissions - Choose who can access your collection and documents. For more about - - Permissions + Learn more . {#if collectionPermissions} diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte index a5af8aac6..60fb843ac 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/subNavigation.svelte @@ -14,17 +14,17 @@ import { isTabletViewport } from '$lib/stores/viewport'; import { BottomSheet } from '$lib/components'; - $: data = page.data as PageData; - $: project = page.params.project; - $: databaseId = page.params.database; - $: collectionId = page.params.collection; + let data = $derived(page.data) as PageData; + let project = $derived(page.params.project); + let databaseId = $derived(page.params.database); + let collectionId = $derived(page.params.collection); - $: sortedCollections = data?.allCollections?.collections?.sort((a, b) => - a.name.localeCompare(b.name) + const sortedCollections = $derived.by(() => + data?.allCollections?.collections?.slice().sort((a, b) => a.name.localeCompare(b.name)) ); - $: selectedCollection = sortedCollections?.find( - (collection) => collection.$id === collectionId + const selectedCollection = $derived.by(() => + sortedCollections()?.find((collection) => collection.$id === collectionId) ); let openBottomSheet = false; diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte index 99551e59b..90a75a65f 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/collection-[collection]/table.svelte @@ -157,7 +157,7 @@ let:root allowSelection bind:selectedRows - columns={[{ id: '$id', width: 150 }, ...$columns, { id: '$created' }, { id: '$updated' }]}> + columns={[{ id: '$id', width: 200 }, ...$columns, { id: '$created' }, { id: '$updated' }]}> Document ID {#each $columns as column} diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/delete.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/delete.svelte index 93acb9b68..21c1e9316 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/delete.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/delete.svelte @@ -10,7 +10,7 @@ import { database } from './store'; import { toLocaleDate } from '$lib/helpers/date'; import { type Models, Query } from '@appwrite.io/console'; - import { Table } from '@appwrite.io/pink-svelte'; + import { Spinner, Table } from '@appwrite.io/pink-svelte'; const databaseId = page.params.database; @@ -86,6 +86,8 @@ $: if (!showDelete) { collections = null; collectionItems = []; + } else { + listCollections(); } @@ -98,53 +100,52 @@ Are you sure you want to delete {$database.name}? {/if} - {#await listCollections()} + + {#if isLoadingDocumentsCount} - + - {:then} - {#if error} - - Are you sure you want to delete {$database.name}? - - {:else if collectionItems.length > 0} - - - - Collection - Last Updated - - {#each collectionItems as collection} - - {collection.name} - {toLocaleDate(collection.updatedAt)} - - {/each} - + {:else if error} + + Are you sure you want to delete {$database.name}? + + {:else if collectionItems.length > 0} + + + + Collection + Last Updated + + {#each collectionItems as collection} + + {collection.name} + {toLocaleDate(collection.updatedAt)} + + {/each} + - {#if collectionItems.length < collections.total} - - - Show more - - - {#if isLoadingDocumentsCount} - - {/if} - - {:else if collectionItems.length > 25} - { - collectionItems = collectionItems.slice(0, 3); - }} - type="button"> - Show less + {#if collectionItems.length < collections.total} + + + Show more - {/if} - - {/if} - {/await} + + {#if isLoadingDocumentsCount} + + {/if} + + {:else if collectionItems.length > 25} + { + collectionItems = collectionItems.slice(0, 3); + }} + type="button"> + Show less + + {/if} + + {/if} {#if !isLoadingDocumentsCount} diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte index 6457b1354..a3ea156e8 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte @@ -12,7 +12,7 @@ (showCreate = true)} event="collection"> diff --git a/src/routes/(console)/project-[project]/databases/grid.svelte b/src/routes/(console)/project-[project]/databases/grid.svelte index 17a1b5435..2045fcde8 100644 --- a/src/routes/(console)/project-[project]/databases/grid.svelte +++ b/src/routes/(console)/project-[project]/databases/grid.svelte @@ -10,7 +10,7 @@ (showCreate = true)} event="database" diff --git a/src/routes/(console)/project-[project]/functions/+page.svelte b/src/routes/(console)/project-[project]/functions/+page.svelte index fd916a02c..db6eb692d 100644 --- a/src/routes/(console)/project-[project]/functions/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/+page.svelte @@ -77,7 +77,7 @@ - + @@ -88,12 +88,12 @@ {#if data.functions.total} goto(`${base}/project-${project}/functions/create-function`)}> - {#each data.functions.functions as func} + {#each data.functions.functions as func (func.$id)} diff --git a/src/routes/(console)/project-[project]/functions/create-function/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/+page.svelte index f4faa7d03..829fcdb15 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/+page.svelte @@ -33,7 +33,6 @@ previousPage = from?.url?.pathname || previousPage; }); - let hasInstallations: boolean; let selectedRepository: string; const featuredTemplatesList = data.templatesList.templates @@ -57,12 +56,10 @@ baseRuntimesList.some((base) => base.$id === r.name) ); - function connect(e: CustomEvent) { + function connect(e: Models.ProviderRepository) { trackEvent(Click.ConnectRepositoryClick, { from: 'cover' }); - repository.set(e.detail); - goto( - `${wizardBase}/create-function/repository-${e.detail.id}?installation=${$installation.$id}` - ); + repository.set(e); + goto(`${wizardBase}/create-function/repository-${e.id}?installation=${$installation.$id}`); } @@ -103,16 +100,15 @@ Connect Git repository + {connect} /> - {#if hasInstallations} + {#if data.installations.total} diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte index d925ef4e8..05e70a1d8 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte @@ -48,28 +48,26 @@ let runtime: Runtime; let entrypoint = ''; let buildCommand = ''; - let scopes: string[] = []; + let roles: string[] = []; let variables: Partial[] = []; let files: FileList; let specification = specificationOptions[0].value; async function create() { try { - console.log(runtime); - const func = await sdk.forProject.functions.create( id || ID.unique(), name, runtime, - undefined, + roles?.length ? roles : undefined, undefined, undefined, undefined, true, undefined, entrypoint, + buildCommand, undefined, - scopes, undefined, undefined, undefined, @@ -99,8 +97,8 @@ func.$id, files[0], true, - entrypoint, - buildCommand + undefined, + undefined ); trackEvent(Submit.FunctionCreate, { @@ -188,7 +186,7 @@ options={runtimeOptions} showEntrypoint /> - + diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte b/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte index 8487e6759..8f3091f39 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte @@ -5,7 +5,7 @@ import { Accordion, Fieldset, Layout } from '@appwrite.io/pink-svelte'; export let buildCommand = ''; - export let scopes: string[] = []; + export let roles: string[] = []; @@ -28,7 +28,7 @@ >Learn more - + diff --git a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte index 65d24064c..4612fe685 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte @@ -17,9 +17,7 @@ {repository?.organization}/{repository?.name} - + Change diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte index 4da0fc2f8..62f0c459b 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte @@ -44,7 +44,6 @@ let showExitModal = false; let isCreatingRepository = false; - let hasInstallations = !!data?.installations?.total; let formComponent: Form; let isSubmitting = writable(false); @@ -69,9 +68,6 @@ let specification = specificationOptions[0].value; onMount(async () => { - if (page.url.searchParams.has('runtime')) { - runtime = page.url.searchParams.get('runtime') as Runtime; - } if (!$installation?.$id) { $installation = data.installations.installations[0]; } @@ -87,7 +83,11 @@ const versionB = b.split('-')[1]; return versionB.localeCompare(versionA, undefined, { numeric: true }); }); - runtime = matchingRuntimes[0]; + if (page.url.searchParams.has('runtime')) { + runtime = page.url.searchParams.get('runtime') as Runtime; + } else { + runtime = matchingRuntimes[0]; + } } }); @@ -133,8 +133,8 @@ data.template.timeout ? data.template.timeout : undefined, undefined, undefined, - entrypoint || rt.entrypoint, - undefined, + entrypoint || rt?.entrypoint || undefined, + rt?.commands || undefined, selectedScopes?.length ? selectedScopes : undefined, connectBehaviour === 'later' ? undefined : $installation?.$id || undefined, connectBehaviour === 'later' ? undefined : $repository?.id || undefined, @@ -150,8 +150,6 @@ func.$id ); - console.log(variables); - // Add variables const promises = variables.map((variable) => sdk.forProject.functions.createVariable( @@ -249,7 +247,6 @@ bind:specification {specificationOptions} {options} /> - {#if connectBehaviour === 'now'} - {#if hasInstallations} + {#if !!data?.installations?.total} @@ -285,16 +282,15 @@ {:else} { + connect={(e) => { trackEvent(Click.ConnectRepositoryClick, { from: 'template-wizard' }); - repository.set(e.detail); - repositoryName = e.detail.name; - selectedRepository = e.detail.id; + repository.set(e); + repositoryName = e.name; + selectedRepository = e.id; showConfig = true; }} /> {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte index d889f7c52..b131983ca 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte @@ -13,20 +13,70 @@ Typography } from '@appwrite.io/pink-svelte'; import { DeploymentSource, DeploymentCreatedBy, DeploymentDomains } from '$lib/components/git'; - import { func } from '../store'; import { capitalize } from '$lib/helpers/string'; import { isCloud } from '$lib/system'; import { IconInfo } from '@appwrite.io/pink-icons-svelte'; + import Link from '$lib/elements/link.svelte'; + import { base } from '$app/paths'; + import { page } from '$app/state'; + import type { Snippet } from 'svelte'; - export let deployment: Models.Deployment; - export let proxyRuleList: Models.ProxyRuleList; - export let variant: 'primary' | 'secondary' = 'primary'; - export let activeDeployment = false; + let { + deployment, + proxyRuleList, + variant = 'primary', + activeDeployment = false, + footer + }: { + deployment: Models.Deployment; + proxyRuleList: Models.ProxyRuleList; + variant?: 'primary' | 'secondary'; + activeDeployment?: boolean; + footer?: Snippet; + } = $props(); - $: totalSize = humanFileSize(deployment?.totalSize ?? 0); + let totalSize = $derived(humanFileSize(deployment?.totalSize ?? 0)); +{#snippet titleSnippet(title: string)} + + {title} + +{/snippet} + +{#snippet textGroup(title: string, text: string)} + + {@render titleSnippet(title)} + + {text} + + +{/snippet} + +{#snippet protection(text: string, tooltip: string)} + + + + {text} + + + + {tooltip} + + + + + + + + +{/snippet} + @@ -57,20 +107,24 @@ - - Domains - + {@render titleSnippet('Domains')} - + {#if $func.deploymentId === deployment.$id} + + {:else} + + Only the active deployment has a domain. + + {/if} {#if deployment.status === 'failed'} - - Status - + {@render titleSnippet('Status')} @@ -90,27 +144,15 @@ {#if deployment?.buildDuration} - - - Build duration - - - {formatTimeDetailed(deployment.buildDuration)} - - + {@render textGroup( + 'Build duration', + formatTimeDetailed(deployment.buildDuration) + )} {/if} + {@render textGroup('Total size', `${totalSize.value} ${totalSize.unit}`)} + - - Total size - - - {totalSize.value}{totalSize.unit} - - - - - Runtime - + {@render titleSnippet('Runtime')} - - - - - Global CDN - - - Optimized speed by caching content on servers closer to - users. - - - - - - - - - - - - DDoS protection - - - Safeguards your site by detecting and blocking malicious - traffic. - - - - - - - - - + + {@render protection( + 'Global CDN', + 'Optimized speed by caching content on servers closer to users.' + )} + {@render protection( + 'DDoS protection', + 'Safeguards your site by detecting and blocking malicious traffic.' + )} - - Source - + {@render titleSnippet('Source')} @@ -178,13 +185,13 @@ - {#if $$slots.footer} + {#if footer} - + {@render footer()} {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte deleted file mode 100644 index 2df35af1f..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Connect your function to an existing repository or create a new one. - - {#if hasInstallations} - - - {#if repositoryBehaviour === 'new'} - - {:else} - { - trackEvent(Click.ConnectRepositoryClick, { - from: 'functions' - }); - repository.set(e.detail); - repositoryName = e.detail.name; - selectedRepository = e.detail.id; - connectRepo(); - }} /> - {/if} - - {:else} - - {/if} - - {#if repositoryBehaviour === 'existing'} - - - - Missing a repository? check your permissions - - - - {:else if repositoryBehaviour === 'new'} - (show = false)}>Cancel - - Create - - {/if} - - diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte index 897eca73e..19d81e0ca 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte @@ -209,8 +209,8 @@ callbackState={{ createDeployment: 'true' }} - on:connect={(e) => { - repository.set(e.detail); + connect={(e) => { + repository.set(e); hasRepository = true; }} /> {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte index 55d9c2445..ea04fbb5b 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte @@ -21,7 +21,7 @@ await sdk.forProject.functions.createDeployment( $func.$id, files[0], - undefined, + true, undefined, undefined ); diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte index a4254aedd..ff3336871 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte @@ -74,7 +74,7 @@ deployment={activeDeployment} proxyRuleList={data.proxyRuleList} activeDeployment> - + {#snippet footer()} @@ -112,7 +112,7 @@ Execute - + {/snippet} {:else if data.activeDeployment?.status === 'building'} @@ -171,9 +171,7 @@ - {#if data.deploymentList.total} - - {/if} + {#if data.deploymentList.total} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte index 16ea96458..1416f679f 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte @@ -72,7 +72,7 @@ - + {#snippet footer()} {#if data.deployment.status === 'processing' || data.deployment.status === 'building' || data.deployment.status === 'waiting'} Activate {/if} - + {/snippet} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte index fc9cbe02f..467edc314 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte @@ -3,148 +3,40 @@ import { page } from '$app/state'; 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 { IconPlus } from '@appwrite.io/pink-icons-svelte'; + import { Card, Empty, Icon, Layout } from '@appwrite.io/pink-svelte'; import DeleteDomainModal from './deleteDomainModal.svelte'; import RetryDomainModal from './retryDomainModal.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 Table from './table.svelte'; - export let data; + let { data } = $props(); - let showDelete = false; - let showRetry = false; + let showDelete = $state(false); + let showRetry = $state(false); let selectedDomain: Models.ProxyRule = null; - let showPreviewDomainModal = false; - - - { - toggle(event); - trackEvent(Click.DomainCreateClick, { - source: 'functions_domain_overview' - }); - }}> - - Add domain - - - - - Custom domain - - (showPreviewDomainModal = true)}> - Preview domain - - - - + + { + trackEvent(Click.DomainCreateClick, { + source: 'functions_domain_overview' + }); + }}> + + Add domain + - {#if data.domains.total} - - - Domain - Redirect to - Production branch - - - {#each data.domains.rules as domain} - - - - - {domain.domain} - - - - - - {domain?.redirectUrl || 'No redirect'} - {domain?.redirectStatusCode ? `(${domain.redirectStatusCode})` : ''} - - - {domain.deploymentVcsProviderBranch || '-'} - - - - { - e.preventDefault(); - toggle(e); - }}> - - - - - - {#if domain.status !== 'verified'} - { - e.preventDefault(); - selectedDomain = domain; - showRetry = true; - toggle(e); - }}> - Retry - - {/if} - { - e.preventDefault(); - selectedDomain = domain; - showDelete = true; - toggle(e); - trackEvent(Click.DomainDeleteClick, { - source: 'functions_domain_overview' - }); - }}> - Delete - - - - - - - {/each} - + {/if} - -{#if showPreviewDomainModal} - -{/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte index 962006783..e6fdb78f9 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte @@ -1,68 +1,36 @@ - + - + {:else if behaviour === 'REDIRECT'} - + - - - Redirect this domain. Domains added to your project will be - listed here. - + Redirect your domain to this URL. - + + - Cancel + Cancel formComponent.triggerSubmit()} bind:disabled={$isSubmitting}> Add @@ -291,6 +236,8 @@ {#if showConnectRepo} {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts index b233e47dc..e89c914b0 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts @@ -1,9 +1,11 @@ import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; import { RuleTrigger, RuleType } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants'; -export const load = async ({ parent }) => { +export const load = async ({ parent, depends }) => { const { function: func } = await parent(); + depends(Dependencies.DOMAINS, Dependencies.FUNCTION_DOMAINS); const [domains, installations] = await Promise.all([ sdk.forProject.proxy.listRules([ diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte new file mode 100644 index 000000000..16902325e --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte @@ -0,0 +1,160 @@ + + + + + + + + + + + + {page.params.domain} + + + Change + + + + + + + + {#if isSubDomain && !!$consoleVariables._APP_DOMAIN_TARGET_CNAME && $consoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'} + (selectedTab = 'cname')} + active={selectedTab === 'cname'}> + CNAME + + {/if} + {#if isCloud} + (selectedTab = 'nameserver')} + active={selectedTab === 'nameserver'}> + Nameservers + + {/if} + {#if !!$consoleVariables._APP_DOMAIN_TARGET_A && $consoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'} + (selectedTab = 'a')} + active={selectedTab === 'a'}> + A + + {/if} + {#if !!$consoleVariables._APP_DOMAIN_TARGET_AAAA && $consoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'} + (selectedTab = 'aaaa')} + active={selectedTab === 'aaaa'}> + AAAA + + {/if} + + + + {#if selectedTab === 'nameserver'} + + {:else} + + {/if} + + + + Verify + + + + + + + diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts new file mode 100644 index 000000000..dfaaa1a60 --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts @@ -0,0 +1,22 @@ +import { sdk } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants.js'; +import { isCloud } from '$lib/system'; +import type { Domain, DomainsList } from '$lib/sdk/domains.js'; + +export const load = async ({ parent, depends, params }) => { + depends(Dependencies.DOMAINS); + + let domain: Domain; + let domainsList: DomainsList; + if (isCloud) { + [domain, domainsList] = await Promise.all([ + sdk.forConsole.domains.get(params.domain), + sdk.forConsole.domains.list() + ]); + } + + return { + domain, + domainsList + }; +}; diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte deleted file mode 100644 index 6034860c4..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - - {#if isVerified} - - - {data.domain.domain} - - - - {:else} - - - - - (selectedTab = 'cname')} - active={selectedTab === 'cname'}> - CNAME - - (selectedTab = 'nameserver')} - active={selectedTab === 'nameserver'}> - Nameservers - - - - - {#if selectedTab === 'cname'} - - - {data.domain?.domain} - {#if isVerified} - - {:else} - - {/if} - - - Add the following record on your DNS provider. Note that DNS changes may - take time to propagate fully. - - - - - - Type - Name - Value - - - CNAME - {data.domain?.domain} - - - {globalThis?.location?.origin} - - - - - - - A list of all domain providers and their DNS setting is available here. - - - - - - Verify - - {:else} - - - {data.domain?.domain} - - - - Add the following nameservers on your DNS provider. Note that DNS - changes may take time to propagate fully. - - - - - - Type - Value - - {#each nameservers as nameserver} - - NS - - - {nameserver} - - - {/each} - - - - - - Verify - - {/if} - - - {/if} - diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts deleted file mode 100644 index 13d1680f5..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts +++ /dev/null @@ -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 - }; - } -}; diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte deleted file mode 100644 index af7c37ee9..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte +++ /dev/null @@ -1,104 +0,0 @@ - - - - - Get an auto-generated domain to quickly access your project. You can customize its prefix. - - - - - - - - .{$consoleVariables._APP_DOMAIN_FUNCTIONS} - - - - - - - - - (show = false)}>Cancel - Add - - diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/store.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/store.ts new file mode 100644 index 000000000..902fb3e3e --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/store.ts @@ -0,0 +1,19 @@ +import type { Column } from '$lib/helpers/types'; +import { writable } from 'svelte/store'; + +export const columns = writable([ + { + id: 'domain', + title: 'Domain', + type: 'string', + format: 'string', + width: { min: 200 } + }, + + { + id: 'target', + title: 'Target', + type: 'string', + width: { min: 120, max: 400 } + } +]); diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/table.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/table.svelte new file mode 100644 index 000000000..4fe75d81a --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/table.svelte @@ -0,0 +1,121 @@ + + + + + {#each $columns as { id, title }} + + {title} + + {/each} + + + {#each domains.rules as domain} + + {#each $columns as column} + + {#if column.id === 'domain'} + + + {domain.domain} + {#if domain.status !== 'verified'} + + {/if} + + + {:else if column.id === 'target'} + {domain?.redirectUrl + ? 'Redirect to ' + domain.redirectUrl + : domain?.deploymentVcsProviderBranch + ? 'Deployed from' + domain.deploymentVcsProviderBranch + : '-'} + {/if} + + {/each} + + + + { + e.preventDefault(); + toggle(e); + }}> + + + + + + {#if domain.status !== 'verified'} + { + selectedDomain = domain; + showRetry = true; + toggle(e); + }}> + Retry + + {/if} + { + selectedDomain = domain; + showDelete = true; + toggle(e); + trackEvent(Click.DomainDeleteClick, { + source: 'sites_domain_overview' + }); + }}> + Delete + + + + + + + + {/each} + + +{#if showDelete} + +{/if} + +{#if showRetry} + +{/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte index 42248ac4a..ee525786a 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte @@ -21,10 +21,10 @@ import { logStatusConverter } from './store'; import { LogsRequest, LogsResponse } from '$lib/components/logs'; - export let open = false; export let selectedLogId: string; export let logs: Models.Execution[]; export let logging: boolean; + export let open = false; function nextLog() { const currentIndex = logs.findIndex((log) => log.$id === selectedLogId); @@ -38,6 +38,7 @@ selectedLogId = logs[currentIndex - 1].$id; } } + $: if (!open) { selectedLogId = null; } @@ -47,7 +48,9 @@ $: isLastLog = logs.findIndex((log) => log.$id === selectedLogId) === logs.length - 1; - + (open = false)} /> + + @@ -107,7 +110,6 @@ - {capitalize(selectedLog.status)} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte index 3d82af0c9..fb0d8bf4c 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte @@ -14,8 +14,8 @@ export let columns: Column[]; export let logs: Models.ExecutionList; - let openSheet = false; let selectedLogId: string = null; + let open = false; @@ -27,8 +27,9 @@ {#each logs.executions as log} { - openSheet = true; + on:click={(e) => { + e.stopPropagation(); + open = true; selectedLogId = log.$id; }}> {#each columns as column} @@ -67,7 +68,6 @@ - {status} @@ -83,4 +83,4 @@ {/each} - + diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte index cbedc4de8..20f3bc670 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte @@ -26,12 +26,7 @@ Updated - - {capitalize(timeFromNow($func.$updatedAt))} - - {toLocaleDateTime($func.$updatedAt)} - - + {toLocaleDateTime($func.$updatedAt)} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte index e851f0a73..5e3240fa0 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte @@ -22,9 +22,8 @@ } from '@appwrite.io/pink-svelte'; import Card from '$lib/components/card.svelte'; import { IconGithub } from '@appwrite.io/pink-icons-svelte'; - import { ConnectGit, RepositoryCard } from '$lib/components/git'; + import { ConnectGit, ConnectRepoModal, RepositoryCard } from '$lib/components/git'; import { isValueOfStringEnum } from '$lib/helpers/types'; - import ConnectRepoModal from '../(modals)/connectRepoModal.svelte'; export let func: Models.Function; export let installations: Models.InstallationList; @@ -114,6 +113,37 @@ selectedBranch !== func?.providerBranch || silentMode !== func?.providerSilentMode || selectedDir !== func?.providerRootDirectory; + + async function connect(selectedInstallationId: string, selectedRepository: string) { + try { + if (!isValueOfStringEnum(Runtime, func.runtime)) { + throw new Error(`Invalid runtime: ${func.runtime}`); + } + await sdk.forProject.functions.update( + func.$id, + func.name, + func.runtime as Runtime, + func.execute || undefined, + func.events || undefined, + func.schedule || undefined, + func.timeout || undefined, + func.enabled || undefined, + func.logging || undefined, + func.entrypoint, + func.commands || undefined, + func.scopes || undefined, + selectedInstallationId, + selectedRepository, + 'main', + undefined, + undefined, + undefined + ); + await invalidate(Dependencies.FUNCTION); + } catch (error) { + console.log(error); + } + } @@ -224,7 +254,7 @@ {#if showConnectRepo} - + {/if} {#if showDisconnect} diff --git a/src/routes/(console)/project-[project]/functions/templates/+page.svelte b/src/routes/(console)/project-[project]/functions/templates/+page.svelte index 007ae8d56..4d7a3053c 100644 --- a/src/routes/(console)/project-[project]/functions/templates/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/templates/+page.svelte @@ -82,7 +82,7 @@ - + @@ -140,86 +140,88 @@ {#if data.templates?.length > 0} - - - {#each paginatedItems as template} - {@const baseRuntimes = getBaseRuntimes(template.runtimes)} - {@const displayed = baseRuntimes.slice(0, 2)} - {@const hidden = baseRuntimes.slice(1, -1)} - - - - - {template.name} - - - - {template.tagline} - - - + + {#snippet children(paginatedItems: typeof data.templates)} + + {#each paginatedItems as template} + {@const baseRuntimes = getBaseRuntimes(template.runtimes)} + {@const displayed = baseRuntimes.slice(0, 2)} + {@const hidden = baseRuntimes.slice(1, -1)} + - - {#each displayed as runtime} - {@const icon = getIconFromRuntime(runtime.name)} - {#if icon} - - - - {/if} - {/each} - {#if hidden.length} - - - - +{hidden.length} - - - - {hidden.map((n) => n.name).join(', ')} - - - {/if} - + gap="xl"> + + + {template.name} + + + + {template.tagline} + + + - - Details - - {#if $canWriteFunctions} - - {/if} + justifyContent="space-between" + alignItems="center"> + + {#each displayed as runtime} + {@const icon = getIconFromRuntime(runtime.name)} + {#if icon} + + + + {/if} + {/each} + {#if hidden.length} + + + + +{hidden.length} + + + + {hidden.map((n) => n.name).join(', ')} + + + {/if} + + + + Details + + {#if $canWriteFunctions} + + {/if} + - - - {/each} - + + {/each} + + {/snippet} {:else if data?.search} diff --git a/src/routes/(console)/project-[project]/messaging/+page.svelte b/src/routes/(console)/project-[project]/messaging/+page.svelte index 34445fdd2..a55584536 100644 --- a/src/routes/(console)/project-[project]/messaging/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/+page.svelte @@ -90,11 +90,11 @@ + placeholder="Search by description, type, status, or ID" /> - + {#if $canWriteMessages} {/if} diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte index 78fb352f9..8d621c4e8 100644 --- a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte +++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte @@ -89,6 +89,7 @@ = writable([]); + let data: Writable<[string, string][]> = writable([['', '']]); let title: string; let body: string; let topics: string[]; @@ -135,51 +135,53 @@ - + A key/value payload of additional metadata that's hidden from users. Use this to include information to support logic such as redirection and routing. - {#each $data as [key, value], index} - - - + + {#each $data as [key, value], index} + - { - if (index === 0 && $data?.length === 1) { - $data = [['', '']]; - } else { - $data.splice(index, 1); - $data = $data; - } - }}> - - + id={`key-${index}`} + bind:value={key} + placeholder="Enter key" + label={index === 0 ? 'Key' : undefined} /> + + + { + if (index === 0 && $data?.length === 1) { + $data = [['', '']]; + } else { + $data.splice(index, 1); + $data = $data; + } + }}> + + + - - {/each} - - 0 && $data[$data.length - 1][0] === ''} - on:click={() => ($data = [...$data, ['', '']])}> - - Add data - - + {/each} + + 0 && $data[$data.length - 1][0] === ''} + on:click={() => ($data = [...$data, ['', '']])}> + + Add data + + + diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte index 844c9f4c2..63c10d664 100644 --- a/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte +++ b/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte @@ -114,7 +114,7 @@ bind:value={file} label="Media" optionalText="(Optional)" /> - + {#each customData || [] as [key, value], index} 0 && customData[customData.length - 1][0] === ''} on:click={() => (customData = [...customData, ['', '']])}> diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte index a6ccd2205..f9f0677a1 100644 --- a/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte +++ b/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte @@ -98,6 +98,7 @@ }); show = false; } catch (error) { + show = false; addNotification({ message: error.message, type: 'error' diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte index a32ff96d6..256a95270 100644 --- a/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte +++ b/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte @@ -7,6 +7,7 @@ import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; import { MessagingProviderType, type Models } from '@appwrite.io/console'; import { Dependencies } from '$lib/constants'; + import { Dialog, Layout } from '@appwrite.io/pink-svelte'; export let show = false; export let message: Models.Message & { data: Record }; @@ -75,6 +76,7 @@ }); show = false; } catch (error) { + show = false; addNotification({ message: error.message, type: 'error' @@ -84,7 +86,7 @@ }; - + You are about to send a message to an estimated This action is irreversible. - (show = false)}>Cancel - Send + + (show = false)}>Cancel + Send + - + diff --git a/src/routes/(console)/project-[project]/messaging/providers/+page.svelte b/src/routes/(console)/project-[project]/messaging/providers/+page.svelte index 0ab4c0099..1521b23b7 100644 --- a/src/routes/(console)/project-[project]/messaging/providers/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/providers/+page.svelte @@ -30,7 +30,7 @@ - + {#if $canWriteProviders} diff --git a/src/routes/(console)/project-[project]/messaging/topics/+page.svelte b/src/routes/(console)/project-[project]/messaging/topics/+page.svelte index 6c3cdddc6..1318a583e 100644 --- a/src/routes/(console)/project-[project]/messaging/topics/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/topics/+page.svelte @@ -75,7 +75,7 @@ - + {#if $canWriteTopics} { diff --git a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte index a03180e6c..86044d589 100644 --- a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte @@ -34,11 +34,11 @@ let subscribersByTargetId: Record = {}; const columns = writable([ { id: '$id', title: 'Subscriber ID', type: 'string', width: 200 }, - { id: 'userName', title: 'Name', type: 'string', filter: false, width: 100 }, - { id: 'targetId', title: 'Target ID', type: 'string', width: 140 }, - { id: 'target', title: 'Target', type: 'string', filter: false, width: 140 }, - { id: 'type', title: 'Type', type: 'string', width: 80 }, - { id: '$createdAt', title: 'Created', type: 'datetime', width: 100 } + { id: 'userName', title: 'Name', type: 'string', filter: false, width: { min: 80 } }, + { id: 'targetId', title: 'Target ID', type: 'string', width: { min: 200 } }, + { id: 'target', title: 'Target', type: 'string', filter: false, width: { min: 140 } }, + { id: 'type', title: 'Type', type: 'string', width: { min: 80 } }, + { id: '$createdAt', title: 'Created', type: 'datetime', width: { min: 100 } } ]); onMount(() => { @@ -89,7 +89,6 @@ - Subscribers { @@ -103,12 +102,10 @@ - + - + (showAdd = true)} event="create_subscriber"> Add subscriber @@ -118,7 +115,7 @@ - + diff --git a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte index a1db8cea0..a6309dff8 100644 --- a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte +++ b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte @@ -102,7 +102,7 @@ {target.identifier} {/if} {:else if column.id === 'type'} - + {:else if column.id === '$createdAt'} {toLocaleDateTime(subscriber[column.id])} {:else} diff --git a/src/routes/(console)/project-[project]/sites/(components)/logs.svelte b/src/routes/(console)/project-[project]/sites/(components)/logs.svelte index 6cafa59c5..d5aaed10d 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/logs.svelte +++ b/src/routes/(console)/project-[project]/sites/(components)/logs.svelte @@ -22,12 +22,21 @@ import { Badge, Card, Layout, Logs, Spinner, Typography } from '@appwrite.io/pink-svelte'; import LogsTimer from './logsTimer.svelte'; - export let deployment: Models.Deployment; - export let hideTitle = false; - export let hideScrollButtons = false; - export let height = 'auto'; - export let fullHeight = false; - export let emptyCopy = 'No logs available'; + let { + deployment = $bindable(), + hideTitle = false, + hideScrollButtons = false, + height = 'auto', + fullHeight = false, + emptyCopy = 'No logs available' + }: { + deployment: Models.Deployment; + hideTitle?: boolean; + hideScrollButtons?: boolean; + height?: string; + fullHeight?: boolean; + emptyCopy?: string; + } = $props(); function setCopy() { if (deployment.status === 'failed') { @@ -62,7 +71,7 @@ {/if} - {#if ['waiting', 'processing'].includes(deployment.status)} + {#if ['waiting', 'processing'].includes(deployment.status) || (deployment.status === 'building' && !deployment?.buildLogs?.length)} Waiting for build to start... diff --git a/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte b/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte index 7eb75448c..70af02974 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte +++ b/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte @@ -1,37 +1,70 @@ Open the preview of your site on any mobile or tablet device. + + + + + + + { + copy(url); + tooltipMessage = 'Copied'; + setTimeout(() => { + tooltipMessage = 'Copy'; + }, 1000); + }}> + + + + {tooltipMessage} + + - + - - - copy(url)} /> - - diff --git a/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte b/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte index 98d5d07ab..a298df23c 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte +++ b/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte @@ -72,7 +72,7 @@ (show = !show)} /> + showQR={() => (show = !show)} /> @@ -186,8 +186,8 @@ -{#if show && siteUrl} - +{#if show && proxyRuleList.total} + {/if}
Apply filter rules to refine the table view
- All services are - disabled. -
+ All services are + disabled. +
Are you sure you want to delete the document from {$collection.name} (showDelete = false)}>Cancel
- Are you sure you want to delete {$database.name}? -
+ Are you sure you want to delete {$database.name}? +
diff --git a/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte b/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte index 6457b1354..a3ea156e8 100644 --- a/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte +++ b/src/routes/(console)/project-[project]/databases/database-[database]/grid.svelte @@ -12,7 +12,7 @@ (showCreate = true)} event="collection"> diff --git a/src/routes/(console)/project-[project]/databases/grid.svelte b/src/routes/(console)/project-[project]/databases/grid.svelte index 17a1b5435..2045fcde8 100644 --- a/src/routes/(console)/project-[project]/databases/grid.svelte +++ b/src/routes/(console)/project-[project]/databases/grid.svelte @@ -10,7 +10,7 @@ (showCreate = true)} event="database" diff --git a/src/routes/(console)/project-[project]/functions/+page.svelte b/src/routes/(console)/project-[project]/functions/+page.svelte index fd916a02c..db6eb692d 100644 --- a/src/routes/(console)/project-[project]/functions/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/+page.svelte @@ -77,7 +77,7 @@ - + @@ -88,12 +88,12 @@ {#if data.functions.total} goto(`${base}/project-${project}/functions/create-function`)}> - {#each data.functions.functions as func} + {#each data.functions.functions as func (func.$id)} diff --git a/src/routes/(console)/project-[project]/functions/create-function/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/+page.svelte index f4faa7d03..829fcdb15 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/+page.svelte @@ -33,7 +33,6 @@ previousPage = from?.url?.pathname || previousPage; }); - let hasInstallations: boolean; let selectedRepository: string; const featuredTemplatesList = data.templatesList.templates @@ -57,12 +56,10 @@ baseRuntimesList.some((base) => base.$id === r.name) ); - function connect(e: CustomEvent) { + function connect(e: Models.ProviderRepository) { trackEvent(Click.ConnectRepositoryClick, { from: 'cover' }); - repository.set(e.detail); - goto( - `${wizardBase}/create-function/repository-${e.detail.id}?installation=${$installation.$id}` - ); + repository.set(e); + goto(`${wizardBase}/create-function/repository-${e.id}?installation=${$installation.$id}`); } @@ -103,16 +100,15 @@ Connect Git repository + {connect} /> - {#if hasInstallations} + {#if data.installations.total} diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte index d925ef4e8..05e70a1d8 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/manual/+page.svelte @@ -48,28 +48,26 @@ let runtime: Runtime; let entrypoint = ''; let buildCommand = ''; - let scopes: string[] = []; + let roles: string[] = []; let variables: Partial[] = []; let files: FileList; let specification = specificationOptions[0].value; async function create() { try { - console.log(runtime); - const func = await sdk.forProject.functions.create( id || ID.unique(), name, runtime, - undefined, + roles?.length ? roles : undefined, undefined, undefined, undefined, true, undefined, entrypoint, + buildCommand, undefined, - scopes, undefined, undefined, undefined, @@ -99,8 +97,8 @@ func.$id, files[0], true, - entrypoint, - buildCommand + undefined, + undefined ); trackEvent(Submit.FunctionCreate, { @@ -188,7 +186,7 @@ options={runtimeOptions} showEntrypoint /> - + diff --git a/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte b/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte index 8487e6759..8f3091f39 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/manual/configuration.svelte @@ -5,7 +5,7 @@ import { Accordion, Fieldset, Layout } from '@appwrite.io/pink-svelte'; export let buildCommand = ''; - export let scopes: string[] = []; + export let roles: string[] = []; @@ -28,7 +28,7 @@ >Learn more - + diff --git a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte index 65d24064c..4612fe685 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/repository-[repository]/repoCard.svelte @@ -17,9 +17,7 @@ {repository?.organization}/{repository?.name} - + Change diff --git a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte index 4da0fc2f8..62f0c459b 100644 --- a/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/create-function/template-[template]/+page.svelte @@ -44,7 +44,6 @@ let showExitModal = false; let isCreatingRepository = false; - let hasInstallations = !!data?.installations?.total; let formComponent: Form; let isSubmitting = writable(false); @@ -69,9 +68,6 @@ let specification = specificationOptions[0].value; onMount(async () => { - if (page.url.searchParams.has('runtime')) { - runtime = page.url.searchParams.get('runtime') as Runtime; - } if (!$installation?.$id) { $installation = data.installations.installations[0]; } @@ -87,7 +83,11 @@ const versionB = b.split('-')[1]; return versionB.localeCompare(versionA, undefined, { numeric: true }); }); - runtime = matchingRuntimes[0]; + if (page.url.searchParams.has('runtime')) { + runtime = page.url.searchParams.get('runtime') as Runtime; + } else { + runtime = matchingRuntimes[0]; + } } }); @@ -133,8 +133,8 @@ data.template.timeout ? data.template.timeout : undefined, undefined, undefined, - entrypoint || rt.entrypoint, - undefined, + entrypoint || rt?.entrypoint || undefined, + rt?.commands || undefined, selectedScopes?.length ? selectedScopes : undefined, connectBehaviour === 'later' ? undefined : $installation?.$id || undefined, connectBehaviour === 'later' ? undefined : $repository?.id || undefined, @@ -150,8 +150,6 @@ func.$id ); - console.log(variables); - // Add variables const promises = variables.map((variable) => sdk.forProject.functions.createVariable( @@ -249,7 +247,6 @@ bind:specification {specificationOptions} {options} /> - {#if connectBehaviour === 'now'} - {#if hasInstallations} + {#if !!data?.installations?.total} @@ -285,16 +282,15 @@ {:else} { + connect={(e) => { trackEvent(Click.ConnectRepositoryClick, { from: 'template-wizard' }); - repository.set(e.detail); - repositoryName = e.detail.name; - selectedRepository = e.detail.id; + repository.set(e); + repositoryName = e.name; + selectedRepository = e.id; showConfig = true; }} /> {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte index d889f7c52..b131983ca 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/(components)/deploymentCard.svelte @@ -13,20 +13,70 @@ Typography } from '@appwrite.io/pink-svelte'; import { DeploymentSource, DeploymentCreatedBy, DeploymentDomains } from '$lib/components/git'; - import { func } from '../store'; import { capitalize } from '$lib/helpers/string'; import { isCloud } from '$lib/system'; import { IconInfo } from '@appwrite.io/pink-icons-svelte'; + import Link from '$lib/elements/link.svelte'; + import { base } from '$app/paths'; + import { page } from '$app/state'; + import type { Snippet } from 'svelte'; - export let deployment: Models.Deployment; - export let proxyRuleList: Models.ProxyRuleList; - export let variant: 'primary' | 'secondary' = 'primary'; - export let activeDeployment = false; + let { + deployment, + proxyRuleList, + variant = 'primary', + activeDeployment = false, + footer + }: { + deployment: Models.Deployment; + proxyRuleList: Models.ProxyRuleList; + variant?: 'primary' | 'secondary'; + activeDeployment?: boolean; + footer?: Snippet; + } = $props(); - $: totalSize = humanFileSize(deployment?.totalSize ?? 0); + let totalSize = $derived(humanFileSize(deployment?.totalSize ?? 0)); +{#snippet titleSnippet(title: string)} + + {title} + +{/snippet} + +{#snippet textGroup(title: string, text: string)} + + {@render titleSnippet(title)} + + {text} + + +{/snippet} + +{#snippet protection(text: string, tooltip: string)} + + + + {text} + + + + {tooltip} + + + + + + + + +{/snippet} + @@ -57,20 +107,24 @@ - - Domains - + {@render titleSnippet('Domains')} - + {#if $func.deploymentId === deployment.$id} + + {:else} + + Only the active deployment has a domain. + + {/if} {#if deployment.status === 'failed'} - - Status - + {@render titleSnippet('Status')} @@ -90,27 +144,15 @@ {#if deployment?.buildDuration} - - - Build duration - - - {formatTimeDetailed(deployment.buildDuration)} - - + {@render textGroup( + 'Build duration', + formatTimeDetailed(deployment.buildDuration) + )} {/if} + {@render textGroup('Total size', `${totalSize.value} ${totalSize.unit}`)} + - - Total size - - - {totalSize.value}{totalSize.unit} - - - - - Runtime - + {@render titleSnippet('Runtime')} - - - - - Global CDN - - - Optimized speed by caching content on servers closer to - users. - - - - - - - - - - - - DDoS protection - - - Safeguards your site by detecting and blocking malicious - traffic. - - - - - - - - - + + {@render protection( + 'Global CDN', + 'Optimized speed by caching content on servers closer to users.' + )} + {@render protection( + 'DDoS protection', + 'Safeguards your site by detecting and blocking malicious traffic.' + )} - - Source - + {@render titleSnippet('Source')} @@ -178,13 +185,13 @@ - {#if $$slots.footer} + {#if footer} - + {@render footer()} {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte deleted file mode 100644 index 2df35af1f..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/connectRepoModal.svelte +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Connect your function to an existing repository or create a new one. - - {#if hasInstallations} - - - {#if repositoryBehaviour === 'new'} - - {:else} - { - trackEvent(Click.ConnectRepositoryClick, { - from: 'functions' - }); - repository.set(e.detail); - repositoryName = e.detail.name; - selectedRepository = e.detail.id; - connectRepo(); - }} /> - {/if} - - {:else} - - {/if} - - {#if repositoryBehaviour === 'existing'} - - - - Missing a repository? check your permissions - - - - {:else if repositoryBehaviour === 'new'} - (show = false)}>Cancel - - Create - - {/if} - - diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte index 897eca73e..19d81e0ca 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createGit.svelte @@ -209,8 +209,8 @@ callbackState={{ createDeployment: 'true' }} - on:connect={(e) => { - repository.set(e.detail); + connect={(e) => { + repository.set(e); hasRepository = true; }} /> {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte index 55d9c2445..ea04fbb5b 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/(modals)/createManual.svelte @@ -21,7 +21,7 @@ await sdk.forProject.functions.createDeployment( $func.$id, files[0], - undefined, + true, undefined, undefined ); diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte index a4254aedd..ff3336871 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/+page.svelte @@ -74,7 +74,7 @@ deployment={activeDeployment} proxyRuleList={data.proxyRuleList} activeDeployment> - + {#snippet footer()} @@ -112,7 +112,7 @@ Execute - + {/snippet} {:else if data.activeDeployment?.status === 'building'} @@ -171,9 +171,7 @@ - {#if data.deploymentList.total} - - {/if} + {#if data.deploymentList.total} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte index 16ea96458..1416f679f 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte @@ -72,7 +72,7 @@ - + {#snippet footer()} {#if data.deployment.status === 'processing' || data.deployment.status === 'building' || data.deployment.status === 'waiting'} Activate {/if} - + {/snippet} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte index fc9cbe02f..467edc314 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/+page.svelte @@ -3,148 +3,40 @@ import { page } from '$app/state'; 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 { IconPlus } from '@appwrite.io/pink-icons-svelte'; + import { Card, Empty, Icon, Layout } from '@appwrite.io/pink-svelte'; import DeleteDomainModal from './deleteDomainModal.svelte'; import RetryDomainModal from './retryDomainModal.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 Table from './table.svelte'; - export let data; + let { data } = $props(); - let showDelete = false; - let showRetry = false; + let showDelete = $state(false); + let showRetry = $state(false); let selectedDomain: Models.ProxyRule = null; - let showPreviewDomainModal = false; - - - { - toggle(event); - trackEvent(Click.DomainCreateClick, { - source: 'functions_domain_overview' - }); - }}> - - Add domain - - - - - Custom domain - - (showPreviewDomainModal = true)}> - Preview domain - - - - + + { + trackEvent(Click.DomainCreateClick, { + source: 'functions_domain_overview' + }); + }}> + + Add domain + - {#if data.domains.total} - - - Domain - Redirect to - Production branch - - - {#each data.domains.rules as domain} - - - - - {domain.domain} - - - - - - {domain?.redirectUrl || 'No redirect'} - {domain?.redirectStatusCode ? `(${domain.redirectStatusCode})` : ''} - - - {domain.deploymentVcsProviderBranch || '-'} - - - - { - e.preventDefault(); - toggle(e); - }}> - - - - - - {#if domain.status !== 'verified'} - { - e.preventDefault(); - selectedDomain = domain; - showRetry = true; - toggle(e); - }}> - Retry - - {/if} - { - e.preventDefault(); - selectedDomain = domain; - showDelete = true; - toggle(e); - trackEvent(Click.DomainDeleteClick, { - source: 'functions_domain_overview' - }); - }}> - Delete - - - - - - - {/each} - + {/if} - -{#if showPreviewDomainModal} - -{/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte index 962006783..e6fdb78f9 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.svelte @@ -1,68 +1,36 @@ - + - + {:else if behaviour === 'REDIRECT'} - + - - - Redirect this domain. Domains added to your project will be - listed here. - + Redirect your domain to this URL. - + + - Cancel + Cancel formComponent.triggerSubmit()} bind:disabled={$isSubmitting}> Add @@ -291,6 +236,8 @@ {#if showConnectRepo} {/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts index b233e47dc..e89c914b0 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/+page.ts @@ -1,9 +1,11 @@ import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; import { RuleTrigger, RuleType } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants'; -export const load = async ({ parent }) => { +export const load = async ({ parent, depends }) => { const { function: func } = await parent(); + depends(Dependencies.DOMAINS, Dependencies.FUNCTION_DOMAINS); const [domains, installations] = await Promise.all([ sdk.forProject.proxy.listRules([ diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte new file mode 100644 index 000000000..16902325e --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte @@ -0,0 +1,160 @@ + + + + + + + + + + + + {page.params.domain} + + + Change + + + + + + + + {#if isSubDomain && !!$consoleVariables._APP_DOMAIN_TARGET_CNAME && $consoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'} + (selectedTab = 'cname')} + active={selectedTab === 'cname'}> + CNAME + + {/if} + {#if isCloud} + (selectedTab = 'nameserver')} + active={selectedTab === 'nameserver'}> + Nameservers + + {/if} + {#if !!$consoleVariables._APP_DOMAIN_TARGET_A && $consoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'} + (selectedTab = 'a')} + active={selectedTab === 'a'}> + A + + {/if} + {#if !!$consoleVariables._APP_DOMAIN_TARGET_AAAA && $consoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'} + (selectedTab = 'aaaa')} + active={selectedTab === 'aaaa'}> + AAAA + + {/if} + + + + {#if selectedTab === 'nameserver'} + + {:else} + + {/if} + + + + Verify + + + + + + + diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts new file mode 100644 index 000000000..dfaaa1a60 --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts @@ -0,0 +1,22 @@ +import { sdk } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants.js'; +import { isCloud } from '$lib/system'; +import type { Domain, DomainsList } from '$lib/sdk/domains.js'; + +export const load = async ({ parent, depends, params }) => { + depends(Dependencies.DOMAINS); + + let domain: Domain; + let domainsList: DomainsList; + if (isCloud) { + [domain, domainsList] = await Promise.all([ + sdk.forConsole.domains.get(params.domain), + sdk.forConsole.domains.list() + ]); + } + + return { + domain, + domainsList + }; +}; diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte deleted file mode 100644 index 6034860c4..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - - {#if isVerified} - - - {data.domain.domain} - - - - {:else} - - - - - (selectedTab = 'cname')} - active={selectedTab === 'cname'}> - CNAME - - (selectedTab = 'nameserver')} - active={selectedTab === 'nameserver'}> - Nameservers - - - - - {#if selectedTab === 'cname'} - - - {data.domain?.domain} - {#if isVerified} - - {:else} - - {/if} - - - Add the following record on your DNS provider. Note that DNS changes may - take time to propagate fully. - - - - - - Type - Name - Value - - - CNAME - {data.domain?.domain} - - - {globalThis?.location?.origin} - - - - - - - A list of all domain providers and their DNS setting is available here. - - - - - - Verify - - {:else} - - - {data.domain?.domain} - - - - Add the following nameservers on your DNS provider. Note that DNS - changes may take time to propagate fully. - - - - - - Type - Value - - {#each nameservers as nameserver} - - NS - - - {nameserver} - - - {/each} - - - - - - Verify - - {/if} - - - {/if} - diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts deleted file mode 100644 index 13d1680f5..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/add-domain/verify/+page.ts +++ /dev/null @@ -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 - }; - } -}; diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte deleted file mode 100644 index af7c37ee9..000000000 --- a/src/routes/(console)/project-[project]/functions/function-[function]/domains/createPreviewDomainModal.svelte +++ /dev/null @@ -1,104 +0,0 @@ - - - - - Get an auto-generated domain to quickly access your project. You can customize its prefix. - - - - - - - - .{$consoleVariables._APP_DOMAIN_FUNCTIONS} - - - - - - - - - (show = false)}>Cancel - Add - - diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/store.ts b/src/routes/(console)/project-[project]/functions/function-[function]/domains/store.ts new file mode 100644 index 000000000..902fb3e3e --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/store.ts @@ -0,0 +1,19 @@ +import type { Column } from '$lib/helpers/types'; +import { writable } from 'svelte/store'; + +export const columns = writable([ + { + id: 'domain', + title: 'Domain', + type: 'string', + format: 'string', + width: { min: 200 } + }, + + { + id: 'target', + title: 'Target', + type: 'string', + width: { min: 120, max: 400 } + } +]); diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/domains/table.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/domains/table.svelte new file mode 100644 index 000000000..4fe75d81a --- /dev/null +++ b/src/routes/(console)/project-[project]/functions/function-[function]/domains/table.svelte @@ -0,0 +1,121 @@ + + + + + {#each $columns as { id, title }} + + {title} + + {/each} + + + {#each domains.rules as domain} + + {#each $columns as column} + + {#if column.id === 'domain'} + + + {domain.domain} + {#if domain.status !== 'verified'} + + {/if} + + + {:else if column.id === 'target'} + {domain?.redirectUrl + ? 'Redirect to ' + domain.redirectUrl + : domain?.deploymentVcsProviderBranch + ? 'Deployed from' + domain.deploymentVcsProviderBranch + : '-'} + {/if} + + {/each} + + + + { + e.preventDefault(); + toggle(e); + }}> + + + + + + {#if domain.status !== 'verified'} + { + selectedDomain = domain; + showRetry = true; + toggle(e); + }}> + Retry + + {/if} + { + selectedDomain = domain; + showDelete = true; + toggle(e); + trackEvent(Click.DomainDeleteClick, { + source: 'sites_domain_overview' + }); + }}> + Delete + + + + + + + + {/each} + + +{#if showDelete} + +{/if} + +{#if showRetry} + +{/if} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte index 42248ac4a..ee525786a 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/sheet.svelte @@ -21,10 +21,10 @@ import { logStatusConverter } from './store'; import { LogsRequest, LogsResponse } from '$lib/components/logs'; - export let open = false; export let selectedLogId: string; export let logs: Models.Execution[]; export let logging: boolean; + export let open = false; function nextLog() { const currentIndex = logs.findIndex((log) => log.$id === selectedLogId); @@ -38,6 +38,7 @@ selectedLogId = logs[currentIndex - 1].$id; } } + $: if (!open) { selectedLogId = null; } @@ -47,7 +48,9 @@ $: isLastLog = logs.findIndex((log) => log.$id === selectedLogId) === logs.length - 1; - + (open = false)} /> + + @@ -107,7 +110,6 @@ - {capitalize(selectedLog.status)} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte index 3d82af0c9..fb0d8bf4c 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/executions/table.svelte @@ -14,8 +14,8 @@ export let columns: Column[]; export let logs: Models.ExecutionList; - let openSheet = false; let selectedLogId: string = null; + let open = false; @@ -27,8 +27,9 @@ {#each logs.executions as log} { - openSheet = true; + on:click={(e) => { + e.stopPropagation(); + open = true; selectedLogId = log.$id; }}> {#each columns as column} @@ -67,7 +68,6 @@ - {status} @@ -83,4 +83,4 @@ {/each} - + diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte index cbedc4de8..20f3bc670 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/executeFunction.svelte @@ -26,12 +26,7 @@ Updated - - {capitalize(timeFromNow($func.$updatedAt))} - - {toLocaleDateTime($func.$updatedAt)} - - + {toLocaleDateTime($func.$updatedAt)} diff --git a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte index e851f0a73..5e3240fa0 100644 --- a/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte +++ b/src/routes/(console)/project-[project]/functions/function-[function]/settings/updateRepository.svelte @@ -22,9 +22,8 @@ } from '@appwrite.io/pink-svelte'; import Card from '$lib/components/card.svelte'; import { IconGithub } from '@appwrite.io/pink-icons-svelte'; - import { ConnectGit, RepositoryCard } from '$lib/components/git'; + import { ConnectGit, ConnectRepoModal, RepositoryCard } from '$lib/components/git'; import { isValueOfStringEnum } from '$lib/helpers/types'; - import ConnectRepoModal from '../(modals)/connectRepoModal.svelte'; export let func: Models.Function; export let installations: Models.InstallationList; @@ -114,6 +113,37 @@ selectedBranch !== func?.providerBranch || silentMode !== func?.providerSilentMode || selectedDir !== func?.providerRootDirectory; + + async function connect(selectedInstallationId: string, selectedRepository: string) { + try { + if (!isValueOfStringEnum(Runtime, func.runtime)) { + throw new Error(`Invalid runtime: ${func.runtime}`); + } + await sdk.forProject.functions.update( + func.$id, + func.name, + func.runtime as Runtime, + func.execute || undefined, + func.events || undefined, + func.schedule || undefined, + func.timeout || undefined, + func.enabled || undefined, + func.logging || undefined, + func.entrypoint, + func.commands || undefined, + func.scopes || undefined, + selectedInstallationId, + selectedRepository, + 'main', + undefined, + undefined, + undefined + ); + await invalidate(Dependencies.FUNCTION); + } catch (error) { + console.log(error); + } + } @@ -224,7 +254,7 @@ {#if showConnectRepo} - + {/if} {#if showDisconnect} diff --git a/src/routes/(console)/project-[project]/functions/templates/+page.svelte b/src/routes/(console)/project-[project]/functions/templates/+page.svelte index 007ae8d56..4d7a3053c 100644 --- a/src/routes/(console)/project-[project]/functions/templates/+page.svelte +++ b/src/routes/(console)/project-[project]/functions/templates/+page.svelte @@ -82,7 +82,7 @@ - + @@ -140,86 +140,88 @@ {#if data.templates?.length > 0} - - - {#each paginatedItems as template} - {@const baseRuntimes = getBaseRuntimes(template.runtimes)} - {@const displayed = baseRuntimes.slice(0, 2)} - {@const hidden = baseRuntimes.slice(1, -1)} - - - - - {template.name} - - - - {template.tagline} - - - + + {#snippet children(paginatedItems: typeof data.templates)} + + {#each paginatedItems as template} + {@const baseRuntimes = getBaseRuntimes(template.runtimes)} + {@const displayed = baseRuntimes.slice(0, 2)} + {@const hidden = baseRuntimes.slice(1, -1)} + - - {#each displayed as runtime} - {@const icon = getIconFromRuntime(runtime.name)} - {#if icon} - - - - {/if} - {/each} - {#if hidden.length} - - - - +{hidden.length} - - - - {hidden.map((n) => n.name).join(', ')} - - - {/if} - + gap="xl"> + + + {template.name} + + + + {template.tagline} + + + - - Details - - {#if $canWriteFunctions} - - {/if} + justifyContent="space-between" + alignItems="center"> + + {#each displayed as runtime} + {@const icon = getIconFromRuntime(runtime.name)} + {#if icon} + + + + {/if} + {/each} + {#if hidden.length} + + + + +{hidden.length} + + + + {hidden.map((n) => n.name).join(', ')} + + + {/if} + + + + Details + + {#if $canWriteFunctions} + + {/if} + - - - {/each} - + + {/each} + + {/snippet} {:else if data?.search} diff --git a/src/routes/(console)/project-[project]/messaging/+page.svelte b/src/routes/(console)/project-[project]/messaging/+page.svelte index 34445fdd2..a55584536 100644 --- a/src/routes/(console)/project-[project]/messaging/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/+page.svelte @@ -90,11 +90,11 @@ + placeholder="Search by description, type, status, or ID" /> - + {#if $canWriteMessages} {/if} diff --git a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte index 78fb352f9..8d621c4e8 100644 --- a/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte +++ b/src/routes/(console)/project-[project]/messaging/create-[type]/(type)/email.svelte @@ -89,6 +89,7 @@ = writable([]); + let data: Writable<[string, string][]> = writable([['', '']]); let title: string; let body: string; let topics: string[]; @@ -135,51 +135,53 @@ - + A key/value payload of additional metadata that's hidden from users. Use this to include information to support logic such as redirection and routing. - {#each $data as [key, value], index} - - - + + {#each $data as [key, value], index} + - { - if (index === 0 && $data?.length === 1) { - $data = [['', '']]; - } else { - $data.splice(index, 1); - $data = $data; - } - }}> - - + id={`key-${index}`} + bind:value={key} + placeholder="Enter key" + label={index === 0 ? 'Key' : undefined} /> + + + { + if (index === 0 && $data?.length === 1) { + $data = [['', '']]; + } else { + $data.splice(index, 1); + $data = $data; + } + }}> + + + - - {/each} - - 0 && $data[$data.length - 1][0] === ''} - on:click={() => ($data = [...$data, ['', '']])}> - - Add data - - + {/each} + + 0 && $data[$data.length - 1][0] === ''} + on:click={() => ($data = [...$data, ['', '']])}> + + Add data + + + diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte index 844c9f4c2..63c10d664 100644 --- a/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte +++ b/src/routes/(console)/project-[project]/messaging/message-[message]/pushMessage.svelte @@ -114,7 +114,7 @@ bind:value={file} label="Media" optionalText="(Optional)" /> - + {#each customData || [] as [key, value], index} 0 && customData[customData.length - 1][0] === ''} on:click={() => (customData = [...customData, ['', '']])}> diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte index a6ccd2205..f9f0677a1 100644 --- a/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte +++ b/src/routes/(console)/project-[project]/messaging/message-[message]/scheduleModal.svelte @@ -98,6 +98,7 @@ }); show = false; } catch (error) { + show = false; addNotification({ message: error.message, type: 'error' diff --git a/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte b/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte index a32ff96d6..256a95270 100644 --- a/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte +++ b/src/routes/(console)/project-[project]/messaging/message-[message]/sendModal.svelte @@ -7,6 +7,7 @@ import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; import { MessagingProviderType, type Models } from '@appwrite.io/console'; import { Dependencies } from '$lib/constants'; + import { Dialog, Layout } from '@appwrite.io/pink-svelte'; export let show = false; export let message: Models.Message & { data: Record }; @@ -75,6 +76,7 @@ }); show = false; } catch (error) { + show = false; addNotification({ message: error.message, type: 'error' @@ -84,7 +86,7 @@ }; - + You are about to send a message to an estimated This action is irreversible. - (show = false)}>Cancel - Send + + (show = false)}>Cancel + Send + - + diff --git a/src/routes/(console)/project-[project]/messaging/providers/+page.svelte b/src/routes/(console)/project-[project]/messaging/providers/+page.svelte index 0ab4c0099..1521b23b7 100644 --- a/src/routes/(console)/project-[project]/messaging/providers/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/providers/+page.svelte @@ -30,7 +30,7 @@ - + {#if $canWriteProviders} diff --git a/src/routes/(console)/project-[project]/messaging/topics/+page.svelte b/src/routes/(console)/project-[project]/messaging/topics/+page.svelte index 6c3cdddc6..1318a583e 100644 --- a/src/routes/(console)/project-[project]/messaging/topics/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/topics/+page.svelte @@ -75,7 +75,7 @@ - + {#if $canWriteTopics} { diff --git a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte index a03180e6c..86044d589 100644 --- a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte +++ b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/+page.svelte @@ -34,11 +34,11 @@ let subscribersByTargetId: Record = {}; const columns = writable([ { id: '$id', title: 'Subscriber ID', type: 'string', width: 200 }, - { id: 'userName', title: 'Name', type: 'string', filter: false, width: 100 }, - { id: 'targetId', title: 'Target ID', type: 'string', width: 140 }, - { id: 'target', title: 'Target', type: 'string', filter: false, width: 140 }, - { id: 'type', title: 'Type', type: 'string', width: 80 }, - { id: '$createdAt', title: 'Created', type: 'datetime', width: 100 } + { id: 'userName', title: 'Name', type: 'string', filter: false, width: { min: 80 } }, + { id: 'targetId', title: 'Target ID', type: 'string', width: { min: 200 } }, + { id: 'target', title: 'Target', type: 'string', filter: false, width: { min: 140 } }, + { id: 'type', title: 'Type', type: 'string', width: { min: 80 } }, + { id: '$createdAt', title: 'Created', type: 'datetime', width: { min: 100 } } ]); onMount(() => { @@ -89,7 +89,6 @@ - Subscribers { @@ -103,12 +102,10 @@ - + - + (showAdd = true)} event="create_subscriber"> Add subscriber @@ -118,7 +115,7 @@ - + diff --git a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte index a1db8cea0..a6309dff8 100644 --- a/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte +++ b/src/routes/(console)/project-[project]/messaging/topics/topic-[topic]/table.svelte @@ -102,7 +102,7 @@ {target.identifier} {/if} {:else if column.id === 'type'} - + {:else if column.id === '$createdAt'} {toLocaleDateTime(subscriber[column.id])} {:else} diff --git a/src/routes/(console)/project-[project]/sites/(components)/logs.svelte b/src/routes/(console)/project-[project]/sites/(components)/logs.svelte index 6cafa59c5..d5aaed10d 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/logs.svelte +++ b/src/routes/(console)/project-[project]/sites/(components)/logs.svelte @@ -22,12 +22,21 @@ import { Badge, Card, Layout, Logs, Spinner, Typography } from '@appwrite.io/pink-svelte'; import LogsTimer from './logsTimer.svelte'; - export let deployment: Models.Deployment; - export let hideTitle = false; - export let hideScrollButtons = false; - export let height = 'auto'; - export let fullHeight = false; - export let emptyCopy = 'No logs available'; + let { + deployment = $bindable(), + hideTitle = false, + hideScrollButtons = false, + height = 'auto', + fullHeight = false, + emptyCopy = 'No logs available' + }: { + deployment: Models.Deployment; + hideTitle?: boolean; + hideScrollButtons?: boolean; + height?: string; + fullHeight?: boolean; + emptyCopy?: string; + } = $props(); function setCopy() { if (deployment.status === 'failed') { @@ -62,7 +71,7 @@ {/if} - {#if ['waiting', 'processing'].includes(deployment.status)} + {#if ['waiting', 'processing'].includes(deployment.status) || (deployment.status === 'building' && !deployment?.buildLogs?.length)} Waiting for build to start... diff --git a/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte b/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte index 7eb75448c..70af02974 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte +++ b/src/routes/(console)/project-[project]/sites/(components)/openOnMobileModal.svelte @@ -1,37 +1,70 @@ Open the preview of your site on any mobile or tablet device. + + + + + + + { + copy(url); + tooltipMessage = 'Copied'; + setTimeout(() => { + tooltipMessage = 'Copy'; + }, 1000); + }}> + + + + {tooltipMessage} + + - + - - - copy(url)} /> - - diff --git a/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte b/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte index 98d5d07ab..a298df23c 100644 --- a/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte +++ b/src/routes/(console)/project-[project]/sites/(components)/siteCard.svelte @@ -72,7 +72,7 @@ (show = !show)} /> + showQR={() => (show = !show)} /> @@ -186,8 +186,8 @@ -{#if show && siteUrl} - +{#if show && proxyRuleList.total} + {/if}
You are about to send a message to an estimated This action is irreversible.