diff --git a/package.json b/package.json index cd1ba9713..e7a9ca3e9 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,11 @@ "e2e:ui": "playwright test tests/e2e --ui" }, "dependencies": { - "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464", + "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@08b7400", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@9738320", + "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@11e0653", "@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 1ffa100e3..72535bb8b 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@74f9464 - version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464 + specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@08b7400 + version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@08b7400 '@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@9738320 - version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@9738320(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19) + specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@11e0653 + version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@11e0653(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19) '@popperjs/core': specifier: ^2.11.8 version: 2.11.8 @@ -211,18 +211,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@74f9464': - resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464} + '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@08b7400': + resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@08b7400} version: 1.2.1 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@11e065399ceac01b462887282f593271ec8b29a4': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@11e065399ceac01b462887282f593271ec8b29a4} 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@9738320c3694272255ba4cc7639586ed8bbcc094': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320c3694272255ba4cc7639586ed8bbcc094} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@64948b6': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@64948b6} version: 1.0.0-next.7 peerDependencies: svelte: ^4.0.0 @@ -236,8 +236,9 @@ 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@9738320': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@9738320} + + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@11e0653': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@11e0653} version: 1.0.0-next.85 peerDependencies: react-dom: ^18.0.0 @@ -4241,13 +4242,13 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@74f9464': {} + '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@08b7400': {} - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320(svelte@4.2.19)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@11e065399ceac01b462887282f593271ec8b29a4(svelte@4.2.19)': dependencies: svelte: 4.2.19 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320c3694272255ba4cc7639586ed8bbcc094(svelte@4.2.19)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@64948b6(svelte@4.2.19)': dependencies: svelte: 4.2.19 @@ -4260,9 +4261,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@9738320(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)': + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@11e0653(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)': dependencies: - '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@9738320c3694272255ba4cc7639586ed8bbcc094(svelte@4.2.19) + '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@11e065399ceac01b462887282f593271ec8b29a4(svelte@4.2.19) '@floating-ui/dom': 1.6.13 '@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.3(svelte@4.2.19))(svelte@4.2.19) '@melt-ui/svelte': 0.86.3(svelte@4.2.19) diff --git a/src/lib/components/billing/selectPaymentMethod.svelte b/src/lib/components/billing/selectPaymentMethod.svelte index 6bc15f69f..cd0e7d0e4 100644 --- a/src/lib/components/billing/selectPaymentMethod.svelte +++ b/src/lib/components/billing/selectPaymentMethod.svelte @@ -5,8 +5,16 @@ import { onMount } from 'svelte'; import PaymentModal from './paymentModal.svelte'; import { capitalize } from '$lib/helpers/string'; - import { Alert, Fieldset, Icon, Layout, Selector } from '@appwrite.io/pink-svelte'; - import { IconPlus } from '@appwrite.io/pink-icons-svelte'; + import { + Alert, + Fieldset, + Icon, + Layout, + Selector, + Card, + Typography + } from '@appwrite.io/pink-svelte'; + import { IconExclamationCircle, IconPlus } from '@appwrite.io/pink-icons-svelte'; import InputSelect from '$lib/elements/forms/inputSelect.svelte'; import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; @@ -33,48 +41,55 @@ $: selectedPaymentMethod = methods?.paymentMethods?.find((method) => method.$id === value); -
- - {#if filteredMethods?.length} - {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'} - - Indian credit or debit card-holders - To comply with RBI regulations in India, Appwrite will ask for verification to charge - up to $150 USD on your payment method. We will never charge more than the cost of - your plan and the resources you use, or your budget cap limit. For higher usage limits, - please contact us. - - {/if} - { - return { - value: method.$id, - label: `${capitalize(method.brand)} ending in ${method.last4}`, - data: [method.brand] - }; - })} /> -
+ + {#if filteredMethods?.length} + {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'} + + Indian credit or debit card-holders + To comply with RBI regulations in India, Appwrite will ask for verification to charge + up to $150 USD on your payment method. We will never charge more than the cost of your + plan and the resources you use, or your budget cap limit. For higher usage limits, please + contact us. + + {/if} + { + return { + value: method.$id, + label: `${capitalize(method.brand)} ending in ${method.last4}`, + data: [method.brand] + }; + })} /> +
+ +
+ {:else} + + + + + No saved payment methods + -
- {:else} - - - - {/if} -
-
+ + + {/if} + {#if showPaymentModal && isCloud && hasStripePublicKey} diff --git a/src/lib/components/git/productionBranchFieldset.svelte b/src/lib/components/git/productionBranchFieldset.svelte index f6de639ab..3f4d6d09c 100644 --- a/src/lib/components/git/productionBranchFieldset.svelte +++ b/src/lib/components/git/productionBranchFieldset.svelte @@ -5,7 +5,7 @@ import { sdk } from '$lib/stores/sdk'; import { sortBranches } from '$lib/stores/vcs'; - export let branch: string; + export let branch = 'main'; export let rootDir: string; export let silentMode: boolean; export let installationId: string; diff --git a/src/lib/components/sidebar.svelte b/src/lib/components/sidebar.svelte index a6e63d968..8c8482e58 100644 --- a/src/lib/components/sidebar.svelte +++ b/src/lib/components/sidebar.svelte @@ -1,6 +1,7 @@ -
+
{#each $columns as column} - (column.hide = !column.hide)} - checked={!column.hide} - disabled={allowNoColumns - ? false - : selectedColumnsNumber <= 1 && column.hide !== true} /> + {#if !column?.exclude} + (column.hide = !column.hide)} + checked={!column.hide} + disabled={allowNoColumns + ? false + : selectedColumnsNumber <= 1 && column.hide !== true} /> + {/if} {/each} diff --git a/src/lib/constants.ts b/src/lib/constants.ts index b363b1dce..a038fd15f 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -380,13 +380,13 @@ export const scopes: { }, { scope: 'log.read', - description: "Access to read your sites's logs", + description: "Access to read your sites's logs", category: 'Sites', icon: 'globe' }, { scope: 'log.write', - description: "Access to execute your project's sites", + description: "Access to delete your site's logs", category: 'Sites', icon: 'globe' } diff --git a/src/lib/elements/forms/inputTags.svelte b/src/lib/elements/forms/inputTags.svelte index bca3b7489..fa2b445fa 100644 --- a/src/lib/elements/forms/inputTags.svelte +++ b/src/lib/elements/forms/inputTags.svelte @@ -7,6 +7,7 @@ export let placeholder = ''; export let disabled = false; export let helper: string | undefined = undefined; + export let pattern: string | undefined = undefined; let value = ''; let error: string; @@ -33,7 +34,8 @@ {id} {placeholder} {disabled} + {pattern} bind:value={tags} helper={error || helper} on:invalid={handleInvalid} - state={error ? 'error' : 'default'} /> + state={error ? 'error' : 'default'}> diff --git a/src/lib/elements/forms/inputText.svelte b/src/lib/elements/forms/inputText.svelte index 658c0475a..e2bc35941 100644 --- a/src/lib/elements/forms/inputText.svelte +++ b/src/lib/elements/forms/inputText.svelte @@ -15,7 +15,7 @@ export let autocomplete = false; export let maxlength: number = null; - let error: string; + export let error: string = null; const handleInvalid = (event: Event) => { event.preventDefault(); diff --git a/src/lib/helpers/string.ts b/src/lib/helpers/string.ts index 2ef6ac191..4ef014dd5 100644 --- a/src/lib/helpers/string.ts +++ b/src/lib/helpers/string.ts @@ -48,3 +48,8 @@ const formatter = Intl.NumberFormat('en', { export function formatNum(number: number): string { return formatter.format(number); } + +/** + * Returns a regex to check hostname validity. Supports wildcards too! + */ +export const hostnameRegex = String.raw`(\*)|(\*\.)?(?!-)[A-Za-z0-9\-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,18}|localhost`; diff --git a/src/lib/helpers/timeConversion.ts b/src/lib/helpers/timeConversion.ts index 330a38c2f..a0cdf725e 100644 --- a/src/lib/helpers/timeConversion.ts +++ b/src/lib/helpers/timeConversion.ts @@ -114,3 +114,29 @@ export function formatTimeDetailed(time: number): string { return parts.join(' '); } + +/** + * Calculates the time difference between a starting date/time and the current time. + * Returns the difference formatted in seconds, minutes, or hours depending on the magnitude. + * + * @export + * @param {Date | number | string} startTime - The starting date/time, timestamp in milliseconds, or ISO date string (e.g., '2025-03-20T15:50:43.495+00:00') + * @returns {string} The formatted time difference + */ +export function timer(startTime: Date | number | string): string { + let start: number; + + if (startTime instanceof Date) { + start = startTime.getTime(); + } else if (typeof startTime === 'number') { + start = startTime; + } else { + // Handle ISO date string format + start = new Date(startTime).getTime(); + } + + const now = new Date().getTime(); + const diffInSeconds = (now - start) / 1000; + + return calculateTime(diffInSeconds); +} diff --git a/src/lib/helpers/types.ts b/src/lib/helpers/types.ts index 664871d71..99fd0cb4d 100644 --- a/src/lib/helpers/types.ts +++ b/src/lib/helpers/types.ts @@ -31,6 +31,7 @@ export type Column = PinkColumn & { array?: boolean; format?: string; show?: boolean; + exclude?: boolean; elements?: string[] | { value: string | number; label: string }[]; }; diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index 5497d4991..1a55d1181 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -1,6 +1,6 @@ @@ -79,7 +92,7 @@ {fullHeight} {height} showScrollButton={!hideScrollButtons} - logs={buildLogs || 'No logs available'} + logs={buildLogs || setCopy()} bind:theme={$app.themeInUse} /> {/key} diff --git a/src/routes/(console)/project-[project]/sites/+page.svelte b/src/routes/(console)/project-[project]/sites/+page.svelte index 58864b1c0..4025cc497 100644 --- a/src/routes/(console)/project-[project]/sites/+page.svelte +++ b/src/routes/(console)/project-[project]/sites/+page.svelte @@ -22,6 +22,10 @@ import { columns } from './store'; import { View } from '$lib/helpers/load'; import Table from './table.svelte'; + import { onMount } from 'svelte'; + import { invalidate } from '$app/navigation'; + import { Dependencies } from '$lib/constants'; + import { sdk } from '$lib/stores/sdk'; export let data; let show = false; @@ -41,6 +45,14 @@ ]); $updateCommandGroupRanks({ sites: 1000 }); + + onMount(() => { + return sdk.forConsole.client.subscribe('console', (response) => { + if (response.events.includes(`sites.*`)) { + invalidate(Dependencies.SITES); + } + }); + }); @@ -60,7 +72,7 @@ {#if data.siteList.total} {#if data.view === View.Grid} - + {:else} {/if} diff --git a/src/routes/(console)/project-[project]/sites/+page.ts b/src/routes/(console)/project-[project]/sites/+page.ts index 1525d8c9e..73c610a59 100644 --- a/src/routes/(console)/project-[project]/sites/+page.ts +++ b/src/routes/(console)/project-[project]/sites/+page.ts @@ -17,35 +17,11 @@ export const load = async ({ url, depends, route }) => { search || undefined ); - // TODO: @Meldiron Discuss better solution for getting screnshot IDs - const deployments: Models.Deployment[] = []; - await Promise.all( - siteList.sites.map(async (site) => { - if (!site.deploymentId) { - return; - } - - // TODO: @Meldiron Tripple-check if this can ever happened - // It happened to me but on QA that might have corrupted data - try { - const deployment = await sdk.forProject.sites.getDeployment( - site.$id, - site.deploymentId - ); - deployments.push(deployment); - } catch (err) { - // Active deployment no longer available (deleted?) - console.warn(err); - } - }) - ); - return { offset, limit, search, siteList, - deployments, view }; }; diff --git a/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte b/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte index eaf9ca1bb..548b66be2 100644 --- a/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte +++ b/src/routes/(console)/project-[project]/sites/create-site/configuration.svelte @@ -37,6 +37,7 @@ export let frameworks: Models.Framework[]; export let selectedFramework: Models.Framework; $: frameworkData = frameworks.find((framework) => framework.key === selectedFramework?.key); + $: ssr = frameworkData?.adapters.find((adapter) => adapter.key === 'ssr'); export let variables: Partial[] = []; export let installCommand = ''; @@ -54,9 +55,9 @@ let frameworkId = selectedFramework.key; $: if (!installCommand || !buildCommand || !outputDirectory) { - installCommand ||= frameworkData?.adapters?.ssr?.installCommand; - buildCommand ||= frameworkData?.adapters?.ssr?.buildCommand; - outputDirectory ||= frameworkData?.adapters?.ssr?.outputDirectory; + installCommand ||= ssr?.installCommand; + buildCommand ||= ssr?.buildCommand; + outputDirectory ||= ssr?.outputDirectory; } @@ -86,15 +87,12 @@ id="installCommand" label="Install command" bind:value={installCommand} - placeholder={frameworkData?.adapters?.ssr?.installCommand} /> + placeholder={ssr?.installCommand} /> @@ -103,14 +101,12 @@ id="buildCommand" label="Build command" bind:value={buildCommand} - placeholder={frameworkData?.adapters?.ssr?.buildCommand} /> + placeholder={ssr?.buildCommand} /> @@ -119,15 +115,12 @@ id="outputDirectory" label="Output directory" bind:value={outputDirectory} - placeholder={frameworkData?.adapters?.ssr?.outputDirectory} /> + placeholder={ssr?.outputDirectory} /> diff --git a/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte index 8bc9dca99..a02633697 100644 --- a/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte +++ b/src/routes/(console)/project-[project]/sites/create-site/deploying/+page.svelte @@ -39,7 +39,8 @@ bind:deployment={data.deployment} bind:site={data.site} hideScrollButtons - height="calc(100dvh - 430px)" /> + height="calc(100dvh - 430px)" + emptyCopy="No logs available yet..." /> diff --git a/src/routes/(console)/project-[project]/sites/create-site/details.svelte b/src/routes/(console)/project-[project]/sites/create-site/details.svelte index 7bf4928e1..52c2ed3ba 100644 --- a/src/routes/(console)/project-[project]/sites/create-site/details.svelte +++ b/src/routes/(console)/project-[project]/sites/create-site/details.svelte @@ -17,8 +17,6 @@ }[] = []; let showCustomId = false; - - $: console.log(options);
@@ -32,7 +30,7 @@ required placeholder="Enter name" /> {#if showCustomId} - + {:else}
(showCustomId = !showCustomId)}> diff --git a/src/routes/(console)/project-[project]/sites/create-site/domain.svelte b/src/routes/(console)/project-[project]/sites/create-site/domain.svelte index d77495956..397fdeeb1 100644 --- a/src/routes/(console)/project-[project]/sites/create-site/domain.svelte +++ b/src/routes/(console)/project-[project]/sites/create-site/domain.svelte @@ -1,83 +1,74 @@ -{#if showConfig} -
- - - - - - .{$consoleVariables._APP_DOMAIN_SITES} - - - - - - - - - - - - - -
-{:else} - - - - - - {domain}.{$consoleVariables._APP_DOMAIN_SITES} - - +
+ + + + + + .{$consoleVariables._APP_DOMAIN_SITES} + + + + disabled={originalDomain === newDomain} + on:click={() => (newDomain = originalDomain)}>Reset - -{/if} + + +
diff --git a/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte b/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte index 658353802..3578b0598 100644 --- a/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte +++ b/src/routes/(console)/project-[project]/sites/create-site/manual/+page.svelte @@ -42,7 +42,7 @@ async function create() { try { - domain = await buildVerboseDomain(name, $project.name, $organization.name, id); + domain = await buildVerboseDomain(name, $organization.name, $project.name, id); const fr = Object.values(Framework).find((f) => f === framework.key); const buildRuntime = Object.values(BuildRuntime).find( @@ -125,13 +125,10 @@ Create site - Appwrite -
@@ -184,7 +181,7 @@ -