From cdff501429ec96f2b2007cc0d1e5689675f1756f Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:39:40 +0530 Subject: [PATCH 01/27] treat filter datetime inputs as local; convert to UTC on apply --- src/lib/components/filters/content.svelte | 9 +++++++-- src/lib/components/filters/filtersModal.svelte | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/lib/components/filters/content.svelte b/src/lib/components/filters/content.svelte index a42161f43..c4a83c821 100644 --- a/src/lib/components/filters/content.svelte +++ b/src/lib/components/filters/content.svelte @@ -14,6 +14,7 @@ import type { Column } from '$lib/helpers/types'; import type { Writable } from 'svelte/store'; import { TagList } from '.'; + import { toLocalDateTimeISO } from '$lib/helpers/date'; import { Icon, Layout } from '@appwrite.io/pink-svelte'; import { IconPlus } from '@appwrite.io/pink-icons-svelte'; @@ -79,7 +80,7 @@ value = column?.array ? [] : null; if (column?.type === 'datetime') { const now = new Date(); - value = now.toISOString().slice(0, 16); + value = toLocalDateTimeISO(now.toISOString()).slice(0, 16); } // Initialize spatial data with default values if (column?.type === 'point') { @@ -108,7 +109,11 @@ if (isDistanceOperator && distanceValue !== null && value !== null) { addFilter(columnsArray, columnId, operatorKey, value, arrayValues, distanceValue); } else { - addFilter(columnsArray, columnId, operatorKey, value, arrayValues); + const preparedValue = + column?.type === 'datetime' && typeof value === 'string' && value + ? new Date(value).toISOString() + : value; + addFilter(columnsArray, columnId, operatorKey, preparedValue, arrayValues); } columnId = null; diff --git a/src/lib/components/filters/filtersModal.svelte b/src/lib/components/filters/filtersModal.svelte index e69f2af1a..0281b43c6 100644 --- a/src/lib/components/filters/filtersModal.svelte +++ b/src/lib/components/filters/filtersModal.svelte @@ -57,7 +57,11 @@ } function addCondition() { - const newTag = generateTag(selectedColumn, operatorKey, value || arrayValues); + const preparedValue = + column?.type === 'datetime' && typeof value === 'string' && value + ? new Date(value).toISOString() + : value; + const newTag = generateTag(selectedColumn, operatorKey, preparedValue || arrayValues); if (localTags.some((t) => t.tag === newTag.tag && t.value === newTag.value)) { return; } else { @@ -66,7 +70,7 @@ { id: selectedColumn, operator: operatorKey, - value: value, + value: preparedValue, arrayValues: arrayValues } ]; From e2c8613e272dfa2b3afbb397a374ebe558496dd4 Mon Sep 17 00:00:00 2001 From: AbhiVarde Date: Tue, 25 Nov 2025 10:38:03 +0530 Subject: [PATCH 02/27] fix: responsive layout for input fields and tables on mobile devices --- .../messaging/providers/table.svelte | 111 ++++++++++-------- .../overview/platforms/+page.svelte | 88 ++++++++------ .../bucket-[bucket]/settings/+page.svelte | 17 +-- 3 files changed, 127 insertions(+), 89 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte b/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte index a54178b3d..4706ee00d 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte @@ -39,51 +39,68 @@ } - - {#snippet header(root)} - {#each $columns as { id, title }} - {title} - {/each} - {/snippet} +
+ + {#snippet header(root)} + {#each $columns as { id, title }} + {title} + {/each} + {/snippet} - {#snippet children(root)} - {@const TableRowComponent = $canWriteProviders ? Table.Row.Link : Table.Row.Base} - {#each data.providers.providers as provider (provider.$id)} - {@const href = $canWriteProviders - ? `${base}/project-${page.params.region}-${page.params.project}/messaging/providers/provider-${provider.$id}` - : undefined} - - {#each $columns as column} - - {#if column.id === '$id'} - {#key $columns} - {provider.$id} - {/key} - {:else if column.id === 'provider'} - - {:else if column.id === 'type'} - - {:else if column.id === 'enabled'} - - - {#if provider.enabled} - - {/if} - - - {:else} - {provider[column.id]} - {/if} - - {/each} - - {/each} - {/snippet} - + {#snippet children(root)} + {@const TableRowComponent = $canWriteProviders ? Table.Row.Link : Table.Row.Base} + {#each data.providers.providers as provider (provider.$id)} + {@const href = $canWriteProviders + ? `${base}/project-${page.params.region}-${page.params.project}/messaging/providers/provider-${provider.$id}` + : undefined} + + {#each $columns as column} + + {#if column.id === '$id'} + {#key $columns} + {provider.$id} + {/key} + {:else if column.id === 'provider'} + + {:else if column.id === 'type'} + + {:else if column.id === 'enabled'} + + + {#if provider.enabled} + + {/if} + + + {:else} + {provider[column.id]} + {/if} + + {/each} + + {/each} + {/snippet} + +
+ + diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte index 49376776f..bc06d5b50 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte @@ -121,41 +121,43 @@ {#if data.platforms.platforms.length} - - - Name - Platform type - Identifier - Last updated - - {#each data.platforms.platforms as platform} - - - {platform.name} - - - - - {PlatformTypes[platform.type]} - - - - {#if platform.type.includes('web') || platform.type === 'web'} - {platform.hostname || '—'} - {:else} - {platform.key || platform.hostname || '—'} - {/if} - - - {#if platform.$updatedAt} - - {:else} - never - {/if} - - - {/each} - +
+ + + Name + Platform type + Identifier + Last updated + + {#each data.platforms.platforms as platform} + + + {platform.name} + + + + + {PlatformTypes[platform.type]} + + + + {#if platform.type.includes('web') || platform.type === 'web'} + {platform.hostname || '—'} + {:else} + {platform.key || platform.hostname || '—'} + {/if} + + + {#if platform.$updatedAt} + + {:else} + never + {/if} + + + {/each} + +
{:else} {/if} + + diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte index 6c7ca6d64..933ac0a6a 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte @@ -411,13 +411,15 @@ {#key extensions.length} - +
+ +
{/key} - + {#each suggestedExtensions as ext} { showDelete = true; trackEvent(Click.StorageBucketDeleteClick); - }}>Delete + }} + >Delete
From 5ccfd08450a79eea8a111cec9c4671c6277eb604 Mon Sep 17 00:00:00 2001 From: AbhiVarde Date: Tue, 25 Nov 2025 20:28:52 +0530 Subject: [PATCH 03/27] fix: apply review feedback --- .../messaging/providers/store.ts | 10 +- .../messaging/providers/table.svelte | 111 ++++++++---------- .../overview/platforms/+page.svelte | 88 ++++++-------- .../overview/platforms/store.ts | 9 ++ .../bucket-[bucket]/settings/+page.svelte | 17 ++- 5 files changed, 104 insertions(+), 131 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/messaging/providers/store.ts b/src/routes/(console)/project-[region]-[project]/messaging/providers/store.ts index da9c51351..4e186ece4 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/providers/store.ts +++ b/src/routes/(console)/project-[region]-[project]/messaging/providers/store.ts @@ -19,11 +19,11 @@ import { } from './components'; export const columns = writable([ - { id: '$id', title: 'Provider ID', type: 'string' }, - { id: 'name', title: 'Name', type: 'string' }, - { id: 'provider', title: 'Provider', type: 'string' }, - { id: 'type', title: 'Type', type: 'string' }, - { id: 'enabled', title: 'Status', type: 'boolean' } + { id: '$id', title: 'Provider ID', type: 'string', width: 200 }, + { id: 'name', title: 'Name', type: 'string', width: { min: 120 } }, + { id: 'provider', title: 'Provider', type: 'string', width: { min: 120 } }, + { id: 'type', title: 'Type', type: 'string', width: { min: 120 } }, + { id: 'enabled', title: 'Status', type: 'boolean', width: { min: 120 } } ]); export type ProviderInput = { diff --git a/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte b/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte index 4706ee00d..a54178b3d 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/messaging/providers/table.svelte @@ -39,68 +39,51 @@ } -
- - {#snippet header(root)} - {#each $columns as { id, title }} - {title} - {/each} - {/snippet} + + {#snippet header(root)} + {#each $columns as { id, title }} + {title} + {/each} + {/snippet} - {#snippet children(root)} - {@const TableRowComponent = $canWriteProviders ? Table.Row.Link : Table.Row.Base} - {#each data.providers.providers as provider (provider.$id)} - {@const href = $canWriteProviders - ? `${base}/project-${page.params.region}-${page.params.project}/messaging/providers/provider-${provider.$id}` - : undefined} - - {#each $columns as column} - - {#if column.id === '$id'} - {#key $columns} - {provider.$id} - {/key} - {:else if column.id === 'provider'} - - {:else if column.id === 'type'} - - {:else if column.id === 'enabled'} - - - {#if provider.enabled} - - {/if} - - - {:else} - {provider[column.id]} - {/if} - - {/each} - - {/each} - {/snippet} - -
- - + {#snippet children(root)} + {@const TableRowComponent = $canWriteProviders ? Table.Row.Link : Table.Row.Base} + {#each data.providers.providers as provider (provider.$id)} + {@const href = $canWriteProviders + ? `${base}/project-${page.params.region}-${page.params.project}/messaging/providers/provider-${provider.$id}` + : undefined} + + {#each $columns as column} + + {#if column.id === '$id'} + {#key $columns} + {provider.$id} + {/key} + {:else if column.id === 'provider'} + + {:else if column.id === 'type'} + + {:else if column.id === 'enabled'} + + + {#if provider.enabled} + + {/if} + + + {:else} + {provider[column.id]} + {/if} + + {/each} + + {/each} + {/snippet} +
diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte index bc06d5b50..1e3095139 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte @@ -1,4 +1,5 @@ {#if data.platforms.platforms.length} -
- - - Name - Platform type - Identifier - Last updated - - {#each data.platforms.platforms as platform} - - - {platform.name} - - - - - {PlatformTypes[platform.type]} - - - - {#if platform.type.includes('web') || platform.type === 'web'} - {platform.hostname || '—'} - {:else} - {platform.key || platform.hostname || '—'} - {/if} - - - {#if platform.$updatedAt} - - {:else} - never - {/if} - - + + + {#each $columns as column} + + {column.title} + {/each} - -
+ + {#each data.platforms.platforms as platform} + + + {platform.name} + + + + + {PlatformTypes[platform.type]} + + + + {#if platform.type.includes('web') || platform.type === 'web'} + {platform.hostname || '—'} + {:else} + {platform.key || platform.hostname || '—'} + {/if} + + + {#if platform.$updatedAt} + + {:else} + never + {/if} + + + {/each} + {:else} {/if} - - diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts b/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts index f5241c806..bc031f73d 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts @@ -1,5 +1,14 @@ import type { ComponentType } from 'svelte'; import { PlatformType } from '@appwrite.io/console'; +import { writable } from 'svelte/store'; +import type { Column } from '$lib/helpers/types'; + +export const columns = writable([ + { id: 'name', title: 'Name', type: 'string', width: { min: 120 } }, + { id: 'type', title: 'Platform type', type: 'string', width: { min: 120 } }, + { id: 'identifier', title: 'Identifier', type: 'string', width: { min: 120 } }, + { id: '$updatedAt', title: 'Last updated', type: 'string', width: { min: 120 } } +]); export type PlatformProps = { key?: string; diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte index 933ac0a6a..1ea7cc4d7 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte @@ -411,15 +411,13 @@ {#key extensions.length} -
- -
+ {/key} - + {#each suggestedExtensions as ext} { showDelete = true; trackEvent(Click.StorageBucketDeleteClick); - }} - >Delete + }}>Delete
From ff4ff0c16d821476b9693978c72ed051da39fdc8 Mon Sep 17 00:00:00 2001 From: Hemachandar Date: Fri, 28 Nov 2025 12:23:39 +0530 Subject: [PATCH 04/27] Pagination for list repositories --- package.json | 2 +- pnpm-lock.yaml | 10 +- src/lib/components/git/repositories.svelte | 235 ++++++++++-------- .../components/git/skeletonRepoList.svelte | 4 +- .../functions/function-[function]/store.ts | 4 +- 5 files changed, 141 insertions(+), 114 deletions(-) diff --git a/package.json b/package.json index 1c916e181..b4a375839 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@acef319", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@eb6be9d", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6916470", "@appwrite.io/pink-legacy": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1724be838..1bfe1f451 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.1.24 version: 1.1.24(svelte@5.25.3)(zod@3.24.3) '@appwrite.io/console': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@acef319 - version: https://pkg.vc/-/@appwrite/@appwrite.io/console@acef319 + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@eb6be9d + version: https://pkg.vc/-/@appwrite/@appwrite.io/console@eb6be9d '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 @@ -260,8 +260,8 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@acef319': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@acef319} + '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@eb6be9d': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@eb6be9d} version: 1.10.0 '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': @@ -3703,7 +3703,7 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@acef319': {} + '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@eb6be9d': {} '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)': dependencies: diff --git a/src/lib/components/git/repositories.svelte b/src/lib/components/git/repositories.svelte index 260576f32..2d8374518 100644 --- a/src/lib/components/git/repositories.svelte +++ b/src/lib/components/git/repositories.svelte @@ -1,5 +1,5 @@ - {#each Array(4) as _} + {#each Array(count) as _} diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts index 2ee963047..c6630be5d 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/store.ts @@ -17,10 +17,12 @@ export const proxyRuleList = derived( export const repositories: Writable<{ search: string; installationId: string; - repositories: Models.ProviderRepository[]; + total: number; + repositories: Models.ProviderRepository[] | Models.ProviderRepositoryFramework[] | Models.ProviderRepositoryRuntime[]; }> = writable({ search: '', installationId: '', + total: 0, repositories: [] }); From fe7fdeb5fd39f680a76c88defd727ff681b4ade6 Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 2 Dec 2025 14:20:51 +0530 Subject: [PATCH 05/27] fix: disable free plan in selection if one already exists. --- .../components/billing/planSelection.svelte | 53 +++++++++++-------- .../create-organization/+page.svelte | 39 +++++++------- .../change-plan/+page.svelte | 5 +- 3 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/lib/components/billing/planSelection.svelte b/src/lib/components/billing/planSelection.svelte index 0e194f9b6..6499a47c0 100644 --- a/src/lib/components/billing/planSelection.svelte +++ b/src/lib/components/billing/planSelection.svelte @@ -2,7 +2,7 @@ import { BillingPlan } from '$lib/constants'; import { formatCurrency } from '$lib/helpers/numbers'; import { currentPlan, organization } from '$lib/stores/organization'; - import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte'; + import { Badge, Layout, Tooltip, Typography } from '@appwrite.io/pink-svelte'; import { LabelCard } from '..'; import type { Plan } from '$lib/sdk/billing'; import { page } from '$app/state'; @@ -17,31 +17,42 @@ // experiment to remove scale plan temporarily $: plansWithoutScale = plans.filter((plan) => plan.$id != BillingPlan.SCALE); + + function shouldShowTooltip(plan: Plan) { + if (plan.$id !== BillingPlan.FREE) return true; + else return !anyOrgFree; + } {#each plansWithoutScale as plan} - - - {#if $organization?.billingPlan === plan.$id && !isNewOrg} - - {/if} + + + + {#if $organization?.billingPlan === plan.$id && !isNewOrg} + + {/if} + + + {plan.desc} + + + {@const isZeroPrice = (plan.price ?? 0) <= 0} + {@const price = formatCurrency(plan.price ?? 0)} + {isZeroPrice ? price : `${price} per month + usage`} + + + + + Only 1 free organization is allowed per account. - - {plan.desc} - - - {@const isZeroPrice = (plan.price ?? 0) <= 0} - {@const price = formatCurrency(plan.price ?? 0)} - {isZeroPrice ? price : `${price} per month + usage`} - - + {/each} {#if $currentPlan && !currentPlanInList} import { afterNavigate, goto, invalidate, preloadData } from '$app/navigation'; - import { base } from '$app/paths'; + import { base, resolve } from '$app/paths'; import { page } from '$app/state'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { PlanComparisonBox, PlanSelection, SelectPaymentMethod } from '$lib/components/billing'; @@ -20,25 +20,26 @@ import { writable } from 'svelte/store'; import EstimatedTotalBox from '$lib/components/billing/estimatedTotalBox.svelte'; import { onMount } from 'svelte'; + import type { PageProps } from './$types'; - export let data; + const { data }: PageProps = $props(); - let selectedPlan: BillingPlan = data.plan as BillingPlan; - let selectedCoupon: Partial | null = data.coupon; - let previousPage: string = base; - let showExitModal = false; + let showExitModal = $state(false); + let previousPage: string = $state(resolve('/(console)')); + let selectedPlan: BillingPlan = $state(data.plan as BillingPlan); + let selectedCoupon: Partial | null = $state(data.coupon); - let formComponent: Form; - let isSubmitting = writable(false); + let isSubmitting = $state(writable(false)); + let formComponent: Form | null = $state(null); - let name: string; - let billingPlan: BillingPlan = BillingPlan.FREE; - let paymentMethodId: string; - let collaborators: string[] = []; - let taxId: string; + let name: string | null = $state(null); + let taxId: string | null = $state(null); + let collaborators: string[] = $state([]); + let paymentMethodId: string | null = $state(null); + let billingPlan: BillingPlan = $state(BillingPlan.FREE); - let billingBudget: number; - let showCreditModal = false; + let showCreditModal = $state(false); + let billingBudget: number | undefined = $state(undefined); afterNavigate(({ from }) => { previousPage = from?.url?.pathname || previousPage; @@ -48,8 +49,7 @@ if (page.url.searchParams.has('coupon')) { const coupon = page.url.searchParams.get('coupon'); try { - const response = await sdk.forConsole.billing.getCouponAccount(coupon); - selectedCoupon = response; + selectedCoupon = await sdk.forConsole.billing.getCouponAccount(coupon); } catch (e) { selectedCoupon = { code: null, @@ -200,7 +200,10 @@ >. - + {#if selectedPlan !== BillingPlan.FREE} diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte index ac5d47b75..8d4e7110a 100644 --- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte +++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte @@ -324,7 +324,10 @@ {/if} - + {#if isDowngrade && selectedPlan === BillingPlan.FREE && data.hasFreeOrgs} Date: Tue, 2 Dec 2025 17:47:04 +0530 Subject: [PATCH 06/27] add: column waiting logic on ai suggestions as well. --- .../(observer)/columnObserver.ts | 65 +++++++++++++++++++ .../(suggestions)/empty.svelte | 27 +++++++- .../table-[table]/+layout.svelte | 64 ++++-------------- 3 files changed, 101 insertions(+), 55 deletions(-) create mode 100644 src/routes/(console)/project-[region]-[project]/databases/database-[database]/(observer)/columnObserver.ts diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(observer)/columnObserver.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(observer)/columnObserver.ts new file mode 100644 index 000000000..28ced29eb --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(observer)/columnObserver.ts @@ -0,0 +1,65 @@ +import type { Columns } from '../table-[table]/store'; +import type { RealtimeResponse } from '$lib/stores/sdk'; + +export function setupColumnObserver() { + let expectedCount = 0; + let resolvePromise: () => void; + let timeout: ReturnType; + let isActive = true; + + const availableColumns = new Set(); + const waitPromise = new Promise((resolve) => (resolvePromise = resolve)); + + const columnCreationHandler = (response: RealtimeResponse) => { + if (!isActive) return; + + const { events, payload } = response; + + if ( + events.includes('databases.*.tables.*.columns.*.create') || + events.includes('databases.*.tables.*.columns.*.update') + ) { + const asColumn = payload as Columns; + const columnId = asColumn.key; + const status = asColumn.status; + + if (status === 'available') { + availableColumns.add(columnId); + + if (expectedCount > 0 && availableColumns.size >= expectedCount) { + clearTimeout(timeout); + cleanup(); + resolvePromise(); + } + } + } + }; + + const cleanup = () => { + isActive = false; + if (timeout) clearTimeout(timeout); + }; + + // return function to start waiting! + const startWaiting = (count: number) => { + expectedCount = count; + + timeout = setTimeout(() => { + cleanup(); + resolvePromise(); + }, 10000); + + if (availableColumns.size >= expectedCount) { + clearTimeout(timeout); + cleanup(); + resolvePromise(); + } + }; + + return { + cleanup, + waitPromise, + startWaiting, + columnCreationHandler + }; +} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 22839e48a..00347261f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -19,8 +19,9 @@ import { preferences } from '$lib/stores/preferences'; import SpreadsheetContainer from '../table-[table]/layout/spreadsheet.svelte'; import { onDestroy, onMount, tick } from 'svelte'; - import { sdk } from '$lib/stores/sdk'; + import { sdk, realtime, type RealtimeResponse } from '$lib/stores/sdk'; import { page } from '$app/state'; + import { setupColumnObserver } from '../(observer)/columnObserver'; import { type ColumnInput, mapSuggestedColumns, @@ -125,6 +126,7 @@ // let tooltipTopPosition = $state(50); let triggerColumnId = $state(null); let hoveredColumnId = $state(null); + let columnCreationHandler: ((response: RealtimeResponse) => void) | null = null; // for deleting a column + undo let undoTimer: ReturnType | null = $state(null); @@ -585,7 +587,7 @@ ($isSmallViewport ? 14 : 17) + (!$expandTabs ? 2 : 0) - userDataRows.length ); - onMount(async () => { + onMount(() => { columnsOrder.set(preferences.getColumnOrder(tableId)); columnsWidth.set(preferences.getColumnWidths(tableId)); @@ -595,7 +597,13 @@ } requestAnimationFrame(recalcAll); - await suggestColumns(); + suggestColumns(); + + return realtime.forProject(page.params.region, ['project', 'console'], (response) => { + if (response.events.includes('databases.*.tables.*.columns.*')) { + columnCreationHandler?.(response); + } + }); }); function resetSuggestionsStore(fullReset: boolean = true) { @@ -968,6 +976,14 @@ } try { + const { + startWaiting, + waitPromise, + columnCreationHandler: handler + } = setupColumnObserver(); + + columnCreationHandler = handler; + const results = []; for (const column of customColumns) { @@ -1066,6 +1082,9 @@ results.push(columnResult); } + startWaiting(customColumns.length); + await waitPromise; + await invalidate(Dependencies.TABLE); addNotification({ @@ -1087,6 +1106,8 @@ message: error.message }); creatingColumns = false; + } finally { + columnCreationHandler = null; } } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte index bc4f7f186..63d3c23f4 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte @@ -73,9 +73,10 @@ import { Submit, trackEvent } from '$lib/actions/analytics'; import { isTabletViewport } from '$lib/stores/viewport'; + import { showColumnsSuggestionsModal } from '../(suggestions)'; import IndexesSuggestions from '../(suggestions)/indexes.svelte'; import ColumnsSuggestions from '../(suggestions)/columns.svelte'; - import { showColumnsSuggestionsModal } from '../(suggestions)'; + import { setupColumnObserver } from '../(observer)/columnObserver'; let editRow: EditRow; let editRelatedRow: EditRelatedRow; @@ -276,56 +277,6 @@ indexes: 700 }); - function setupColumnObserver() { - let expectedCount = 0; - let resolvePromise: () => void; - let timeout: ReturnType; - - const availableColumns = new Set(); - const waitPromise = new Promise((resolve) => (resolvePromise = resolve)); - - columnCreationHandler = (response: RealtimeResponse) => { - const { events, payload } = response; - - if ( - events.includes('databases.*.tables.*.columns.*.create') || - events.includes('databases.*.tables.*.columns.*.update') - ) { - const asColumn = payload as Columns; - const columnId = asColumn.key; - const status = asColumn.status; - - if (status === 'available') { - availableColumns.add(columnId); - - if (expectedCount > 0 && availableColumns.size >= expectedCount) { - clearTimeout(timeout); - columnCreationHandler = null; - resolvePromise(); - } - } - } - }; - - // return function to start waiting! - const startWaiting = (count: number) => { - expectedCount = count; - - timeout = setTimeout(() => { - columnCreationHandler = null; - resolvePromise(); - }, 10000); - - if (availableColumns.size >= expectedCount) { - clearTimeout(timeout); - columnCreationHandler = null; - resolvePromise(); - } - }; - - return { startWaiting, waitPromise }; - } - async function createFakeData() { isWaterfallFromFaker.set(true); @@ -338,7 +289,14 @@ if (!filteredColumns.length) { try { - const { startWaiting, waitPromise } = setupColumnObserver(); + const { + startWaiting, + waitPromise, + columnCreationHandler: handler + } = setupColumnObserver(); + + columnCreationHandler = handler; + columns = await generateColumns($project, page.params.database, page.params.table); startWaiting(columns.length); await waitPromise; @@ -354,6 +312,8 @@ }); $spreadsheetLoading = false; return; + } finally { + columnCreationHandler = null; } } From fa9c9d41c728da72347a4c3fda347b5b77d8cc6d Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:11:07 +0530 Subject: [PATCH 07/27] feat: add quick create-organization button in org header --- .../organization-[organization]/header.svelte | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/routes/(console)/organization-[organization]/header.svelte b/src/routes/(console)/organization-[organization]/header.svelte index 38ec2a743..0d56e7f04 100644 --- a/src/routes/(console)/organization-[organization]/header.svelte +++ b/src/routes/(console)/organization-[organization]/header.svelte @@ -1,4 +1,5 @@ {#if loading}