From 8b1d5eb731d14974a58e39c9d25fa7f805fbf2e9 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Mon, 12 Jan 2026 13:38:28 +0530 Subject: [PATCH 01/51] added new filters for sites and functions --- .../components/filters/parsedTagList.svelte | 291 ++++++++++++++++-- .../components/filters/quickFilters.svelte | 9 +- .../layout/responsiveContainerHeader.svelte | 29 +- 3 files changed, 299 insertions(+), 30 deletions(-) diff --git a/src/lib/components/filters/parsedTagList.svelte b/src/lib/components/filters/parsedTagList.svelte index edbd5161e..b451b0a3b 100644 --- a/src/lib/components/filters/parsedTagList.svelte +++ b/src/lib/components/filters/parsedTagList.svelte @@ -1,35 +1,288 @@ -{#if $parsedTags?.length} - + + {#if $parsedTags?.length} {#each $parsedTags as tag (tag.tag)} - { - const t = $tags.filter((t) => t.tag.includes(tag.tag.split(' ')[0])); - t.forEach((t) => (t ? queries.removeFilter(t) : null)); - queries.apply(); - parsedTags.update((tags) => tags.filter((t) => t.tag !== tag.tag)); - }}> - {#key tag.tag} - {tag.tag} - {/key} - - + + {@const parts = parseTagParts(tag.tag)} + {@const property = firstBoldText(tag.tag)} + + {#each parts as part} + + + + {#if part.operator} + {part.text} + {:else} + {capitalize(part.text)} + {/if} + + + {#if property} + {@const filter = getFilterFor(property)} + {#if filter} + {@const isArray = filter?.array} + {@const selectedArray = Array.isArray(tag.value) + ? tag.value + : []} + {#each filter.options as option (filter.title + option.value + option.label)} + + { + if (isArray) { + const exists = + selectedArray.includes( + option.value + ); + const next = exists + ? selectedArray.filter( + (v) => + v !== option.value + ) + : [ + ...selectedArray, + option.value + ]; + addFilterAndApply( + filter.id, + filter.title, + filter.operator, + null, + next, + $columns, + '' + ); + } else { + addFilterAndApply( + filter.id, + filter.title, + filter.operator, + option.value, + [], + $columns, + '' + ); + } + }}> + + {#if isArray} + + {/if} + {capitalize(option.label)} + + + + {/each} + {/if} + {/if} + + + + {/each} + { + const t = $tags.filter((t) => + t.tag.includes(tag.tag.split(' ')[0]) + ); + t.forEach((t) => (t ? queries.removeFilter(t) : null)); + queries.apply(); + parsedTags.update((tags) => tags.filter((t) => t.tag !== tag.tag)); + }}> + + + {tag?.value?.toString()} {/each} + {/if} + + + {#key placeholderVersion} + {#if placeholders?.length} + {#each placeholders as filter (filter.title + filter.id)} + + + + + {capitalize(filter.title)} + + { + e.stopPropagation(); + if (!hiddenPlaceholders.includes(filter.title)) { + hiddenPlaceholders.push(filter.title); + } + placeholderVersion++; + }}> + + + + + {#if filter.options} + {#each filter.options as option (filter.title + option.value + option.label)} + + { + addFilterAndApply( + filter.id, + filter.title, + filter.operator, + filter?.array ? null : option.value, + filter?.array ? [option.value] : [], + $columns, + '' + ); + }}> + {capitalize(option.label)} + + + {/each} + {/if} + + + + {/each} + {/if} + {/key} + + {#if filterCols?.length} + + {/if} + + {#if $parsedTags?.length} - -{/if} + {/if} + diff --git a/src/lib/components/filters/quickFilters.svelte b/src/lib/components/filters/quickFilters.svelte index 76bbf90c5..2e3bb47ef 100644 --- a/src/lib/components/filters/quickFilters.svelte +++ b/src/lib/components/filters/quickFilters.svelte @@ -22,9 +22,12 @@ - {#each filterCols.filter((f) => f?.options) as filter (filter.title + filter.id)} diff --git a/src/lib/layout/responsiveContainerHeader.svelte b/src/lib/layout/responsiveContainerHeader.svelte index 29eed0f56..d1f1621ba 100644 --- a/src/lib/layout/responsiveContainerHeader.svelte +++ b/src/lib/layout/responsiveContainerHeader.svelte @@ -1,7 +1,7 @@ + + + + + + Maximum size: 1,073,741,823 characters + + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte new file mode 100644 index 000000000..b853be3dd --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte @@ -0,0 +1,99 @@ + + + + + + + Maximum size: 4,194,303 characters + + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts index 0a29d12ef..0b94d185d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts @@ -7,6 +7,10 @@ import Float, { submitFloat, updateFloat } from './float.svelte'; import Integer, { submitInteger, updateInteger } from './integer.svelte'; import Ip, { submitIp, updateIp } from './ip.svelte'; import String, { submitString, updateString } from './string.svelte'; +import Varchar, { submitVarchar, updateVarchar } from './varchar.svelte'; +import Text, { submitText, updateText } from './text.svelte'; +import Mediumtext, { submitMediumtext, updateMediumtext } from './mediumtext.svelte'; +import Longtext, { submitLongtext, updateLongtext } from './longtext.svelte'; import Url, { submitUrl, updateUrl } from './url.svelte'; import Datetime, { submitDatetime, updateDatetime } from './datetime.svelte'; import Point, { submitPoint, updatePoint } from './point.svelte'; @@ -32,7 +36,10 @@ import type { ComponentType } from 'svelte'; export type Option = { name: - | 'String' + | 'Text' + | 'Mediumtext' + | 'Longtext' + | 'Varchar' | 'Integer' | 'Float' | 'Boolean' @@ -44,11 +51,16 @@ export type Option = { | 'Relationship' | 'Point' | 'Line' - | 'Polygon'; + | 'Polygon' + | 'String (deprecated)'; sentenceName: string; component: Component; type: | 'string' + | 'text' + | 'mediumtext' + | 'longtext' + | 'varchar' | 'integer' | 'double' | 'boolean' @@ -75,12 +87,39 @@ export type Option = { export const columnOptions: Option[] = [ { - name: 'String', - sentenceName: 'string', - component: String, - type: 'string', - create: submitString, - update: updateString, + name: 'Text', + sentenceName: 'text', + component: Text, + type: 'text', + create: submitText, + update: updateText, + icon: IconText + }, + { + name: 'Mediumtext', + sentenceName: 'mediumtext', + component: Mediumtext, + type: 'mediumtext', + create: submitMediumtext, + update: updateMediumtext, + icon: IconText + }, + { + name: 'Longtext', + sentenceName: 'longtext', + component: Longtext, + type: 'longtext', + create: submitLongtext, + update: updateLongtext, + icon: IconText + }, + { + name: 'Varchar', + sentenceName: 'varchar', + component: Varchar, + type: 'varchar', + create: submitVarchar, + update: updateVarchar, icon: IconText }, { @@ -194,6 +233,15 @@ export const columnOptions: Option[] = [ create: submitRelationship, update: updateRelationship, icon: IconRelationship + }, + { + name: 'String (deprecated)', + sentenceName: 'string', + component: String, + type: 'string', + create: submitString, + update: updateString, + icon: IconText } ]; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte new file mode 100644 index 000000000..6777b4759 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte @@ -0,0 +1,95 @@ + + + + + + + Maximum size: 16,383 characters + + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte new file mode 100644 index 000000000..01c3b8a1d --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte @@ -0,0 +1,103 @@ + + + + + + += 50 ? InputTextarea : InputText} + id="default" + label="Default" + placeholder="Enter string" + maxlength={data.size} + bind:value={data.default} + disabled={data.required || data.array || disabled} + nullable={!data.required && !data.array} /> + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte index 6de8d61ff..bddf43762 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte @@ -23,7 +23,7 @@ columns = $bindable(null), columnId = $bindable(null), columnsOrder = $bindable(null), - selectedOption = $bindable('String'), + selectedOption = $bindable('Text'), createMore = $bindable(false), onColumnsReorder = null }: { @@ -63,8 +63,8 @@ default: null }; - /* default to string */ - selectedOption = 'String'; + /* default to text */ + selectedOption = 'Text'; $option = columnOptions[0]; } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte index a8865d78d..1245063f3 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte @@ -35,6 +35,10 @@ const columnsTypeMap = { string: String, + varchar: String, + text: String, + mediumtext: String, + longtext: String, integer: Integer, double: Integer, boolean: Boolean, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte index 1e7c5f8d0..eecfafe13 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte @@ -32,7 +32,7 @@ const maxlength = $derived( limited ? undefined - : column.type === 'string' + : column.type === 'string' || column.type === 'varchar' ? (column as Models.ColumnString).size : undefined ); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts index a007c01fc..1a65e7873 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts @@ -30,6 +30,12 @@ export function isString(field: Field): field is Models.ColumnString | Models.At return field?.type === 'string'; } +export function isTextType(field: Field): boolean { + if (!field) return false; + const textTypes = ['string', 'varchar', 'text', 'mediumtext', 'longtext']; + return textTypes.includes(field?.type); +} + export function isSpatialType( field: Columns | Attributes | Column ): field is diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/displayName.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/displayName.svelte index 8660d70fa..d8298d9c0 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/displayName.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/displayName.svelte @@ -46,8 +46,9 @@ } function getValidColumns() { + const textTypes = ['string', 'varchar', 'text', 'mediumtext', 'longtext']; return ($columns as Models.ColumnString[]).filter( - (attr) => attr.type === 'string' && !attr?.array + (attr) => textTypes.includes(attr.type) && !attr?.array ); } From 27fb92b466df59a21ca4197b1013c5eb1759e323 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 3 Feb 2026 20:53:55 +1300 Subject: [PATCH 08/51] Fix types --- .../table-[table]/columns/longtext.svelte | 8 ++++---- .../table-[table]/columns/mediumtext.svelte | 8 ++++---- .../database-[database]/table-[table]/columns/text.svelte | 8 ++++---- .../table-[table]/columns/varchar.svelte | 8 ++++---- .../databases/database-[database]/table-[table]/store.ts | 4 ++++ 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/longtext.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/longtext.svelte index dc18391cf..8087541af 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/longtext.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/longtext.svelte @@ -7,7 +7,7 @@ databaseId: string, tableId: string, key: string, - data: Partial + data: Partial ) { await sdk .forProject(page.params.region, page.params.project) @@ -23,7 +23,7 @@ export async function updateLongtext( databaseId: string, tableId: string, - data: Partial, + data: Partial, originalKey?: string ) { await sdk @@ -45,7 +45,7 @@ import { InputTextarea } from '$lib/elements/forms'; import { Layout, Typography } from '@appwrite.io/pink-svelte'; - export let data: Partial = { + export let data: Partial = { required: false, array: false }; @@ -67,7 +67,7 @@ const { stores: { required, array }, listen - } = createConservative>({ + } = createConservative>({ required: false, array: false, ...data diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte index b853be3dd..e87ef840f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte @@ -7,7 +7,7 @@ databaseId: string, tableId: string, key: string, - data: Partial + data: Partial ) { await sdk .forProject(page.params.region, page.params.project) @@ -23,7 +23,7 @@ export async function updateMediumtext( databaseId: string, tableId: string, - data: Partial, + data: Partial, originalKey?: string ) { await sdk @@ -45,7 +45,7 @@ import { InputTextarea } from '$lib/elements/forms'; import { Layout, Typography } from '@appwrite.io/pink-svelte'; - export let data: Partial = { + export let data: Partial = { required: false, array: false }; @@ -67,7 +67,7 @@ const { stores: { required, array }, listen - } = createConservative>({ + } = createConservative>({ required: false, array: false, ...data diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte index 6777b4759..2f2a4443b 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte @@ -7,7 +7,7 @@ databaseId: string, tableId: string, key: string, - data: Partial + data: Partial ) { await sdk.forProject(page.params.region, page.params.project).tablesDB.createTextColumn({ databaseId, @@ -21,7 +21,7 @@ export async function updateText( databaseId: string, tableId: string, - data: Partial, + data: Partial, originalKey?: string ) { await sdk.forProject(page.params.region, page.params.project).tablesDB.updateTextColumn({ @@ -41,7 +41,7 @@ import { InputTextarea } from '$lib/elements/forms'; import { Layout, Typography } from '@appwrite.io/pink-svelte'; - export let data: Partial = { + export let data: Partial = { required: false, array: false }; @@ -63,7 +63,7 @@ const { stores: { required, array }, listen - } = createConservative>({ + } = createConservative>({ required: false, array: false, ...data diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte index 01c3b8a1d..550ec9694 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte @@ -7,7 +7,7 @@ databaseId: string, tableId: string, key: string, - data: Partial + data: Partial ) { await sdk.forProject(page.params.region, page.params.project).tablesDB.createVarcharColumn({ databaseId, @@ -22,7 +22,7 @@ export async function updateVarchar( databaseId: string, tableId: string, - data: Partial, + data: Partial, originalKey?: string ) { await sdk.forProject(page.params.region, page.params.project).tablesDB.updateVarcharColumn({ @@ -42,7 +42,7 @@ import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte'; import { InputNumber, InputText, InputTextarea } from '$lib/elements/forms'; - export let data: Partial = { + export let data: Partial = { required: false, size: 255, array: false @@ -65,7 +65,7 @@ const { stores: { required, array }, listen - } = createConservative>({ + } = createConservative>({ required: false, array: false, ...data diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts index f840a035c..b0cdca091 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts @@ -14,6 +14,10 @@ export type Columns = | Models.ColumnInteger | Models.ColumnIp | Models.ColumnString + | Models.ColumnText + | Models.ColumnMediumtext + | Models.ColumnLongtext + | Models.ColumnVarchar | Models.ColumnUrl | Models.ColumnPoint | Models.ColumnLine From 24fea9e499b996e0b9bd9f50044446be5d1ad0a0 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 3 Feb 2026 22:51:05 +1300 Subject: [PATCH 09/51] Fix types --- .../table-[table]/rows/columns/column.svelte | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte index 1245063f3..9be533a7c 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte @@ -27,6 +27,10 @@ | Models.ColumnInteger | Models.ColumnIp | Models.ColumnString + | Models.ColumnText + | Models.ColumnMediumtext + | Models.ColumnLongtext + | Models.ColumnVarchar | Models.ColumnDatetime | Models.ColumnUrl | Models.ColumnPoint From c8b1dd6dd75e7c5f7c0ed731460cb2825fcfe5c8 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Thu, 5 Feb 2026 12:07:41 +0530 Subject: [PATCH 10/51] fix: tables in mobile view --- src/lib/components/domains/cnameTable.svelte | 1 + src/lib/components/domains/recordTable.svelte | 1 + src/lib/layout/activity.svelte | 2 +- src/routes/(console)/account/sessions/+page.svelte | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/components/domains/cnameTable.svelte b/src/lib/components/domains/cnameTable.svelte index 9569ce89f..eb1dcc693 100644 --- a/src/lib/components/domains/cnameTable.svelte +++ b/src/lib/components/domains/cnameTable.svelte @@ -36,6 +36,7 @@ {#if logs.total} - + User Event diff --git a/src/routes/(console)/account/sessions/+page.svelte b/src/routes/(console)/account/sessions/+page.svelte index bbc261abc..30d1e7829 100644 --- a/src/routes/(console)/account/sessions/+page.svelte +++ b/src/routes/(console)/account/sessions/+page.svelte @@ -97,6 +97,7 @@ Date: Thu, 5 Feb 2026 12:36:15 +0530 Subject: [PATCH 11/51] addressed some coderabiit comments --- .../components/filters/parsedTagList.svelte | 19 +++++------- src/lib/components/filters/setFilters.ts | 31 ++++++++++++------- .../layout/responsiveContainerHeader.svelte | 6 ++-- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/lib/components/filters/parsedTagList.svelte b/src/lib/components/filters/parsedTagList.svelte index 0e9c925cd..98bb4870b 100644 --- a/src/lib/components/filters/parsedTagList.svelte +++ b/src/lib/components/filters/parsedTagList.svelte @@ -12,18 +12,18 @@ import { capitalize } from '$lib/helpers/string'; import { queries, tags } from './store'; import { IconX } from '@appwrite.io/pink-icons-svelte'; - import { parsedTags } from './setFilters'; + import { parsedTags, type ParsedTag } from './setFilters'; import { Button } from '$lib/elements/forms'; import type { Column } from '$lib/helpers/types'; - import type { Writable } from 'svelte/store'; + import { writable, type Writable } from 'svelte/store'; import Menu from '$lib/components/menu/menu.svelte'; import { addFilterAndApply, buildFilterCol, type FilterData } from './quickFilters'; import QuickFilters from '$lib/components/filters/quickFilters.svelte'; let { - columns, + columns = writable([]), analyticsSource = '' - }: { columns: Writable | undefined; analyticsSource?: string } = $props(); + }: { columns?: Writable; analyticsSource?: string } = $props(); function parseTagParts(tagString: string): { text: string; operator: boolean }[] { return tagString @@ -43,11 +43,6 @@ .filter((p) => Boolean(p.text)); } - function firstBoldText(tagString: string): string | null { - const m = /\*\*(.*?)\*\*/.exec(tagString); - return m ? m[1] : null; - } - function getFilterFor(title: string): FilterData | null { if (!columns) return null; const col = ($columns as unknown as Column[]).find((c) => c.title === title); @@ -74,7 +69,7 @@ let placeholderVersion = $state(0); // used to force keyed re-render when needed let activeTitles = $derived( - ($parsedTags || []).map((t) => firstBoldText(t.tag)).filter(Boolean) as string[] + ($parsedTags || []).map((t) => (t as ParsedTag).title).filter(Boolean) as string[] ); // Compute current placeholders (major filters not already active or dismissed) @@ -94,7 +89,7 @@ maxWidth="600px"> {@const parts = parseTagParts(tag.tag)} - {@const property = firstBoldText(tag.tag)} + {@const property = (tag as ParsedTag).title} {#each parts as part} @@ -183,7 +178,7 @@ dismiss on:click={() => { const t = $tags.filter((t) => - t.tag.includes(tag.tag.split(' ')[0]) + t.tag.includes((tag as ParsedTag).title) ); t.forEach((t) => (t ? queries.removeFilter(t) : null)); queries.apply(); diff --git a/src/lib/components/filters/setFilters.ts b/src/lib/components/filters/setFilters.ts index e6f07083c..301a66a0a 100644 --- a/src/lib/components/filters/setFilters.ts +++ b/src/lib/components/filters/setFilters.ts @@ -3,7 +3,11 @@ import { get, writable } from 'svelte/store'; import { type FilterData } from './quickFilters'; import { tags, type TagValue } from './store'; -export const parsedTags = writable([]); +export type ParsedTag = TagValue & { + title: string; +}; + +export const parsedTags = writable([]); export function setFilters(localTags: TagValue[], filterCols: FilterData[], $columns: Column[]) { if (!localTags?.length) { @@ -47,9 +51,10 @@ export function setFilterData(filter: FilterData) { }); } cleanOldTags(filter?.title); - const newTag = { + const newTag: ParsedTag = { tag: tagData.tag.replace(',', ' or '), - value: tagData.value + value: tagData.value, + title: filter.title }; parsedTags.update((tags) => { @@ -69,9 +74,10 @@ export function setTimeFilter(filter: FilterData, columns: Column[]) { const ranges = col.elements as { value: string; label: string }[]; const timeRange = ranges.find((range) => range.value === timeTag.value); if (timeRange) { - const newTag = { + const newTag: ParsedTag = { tag: `**${filter.title}** is **${timeRange.label}**`, - value: timeRange.value + value: timeRange.value, + title: filter.title }; cleanOldTags(filter?.title); @@ -102,9 +108,10 @@ export function setSizeFilter(filter: FilterData, columns: Column[]) { if (sizeRange) { cleanOldTags(filter?.title); - const newTag = { + const newTag: ParsedTag = { tag: `**${filter.title}** is **${sizeRange.label}**`, - value: sizeTag.value + value: sizeTag.value, + title: filter.title }; parsedTags.update((tags) => { tags.push(newTag); @@ -126,9 +133,10 @@ export function setStatusCodeFilter(filter: FilterData, columns: Column[]) { const codeRange = ranges.find((c) => c?.value && c.value === statusCodeTag.value); if (codeRange) { cleanOldTags(filter?.title); - const newTag = { + const newTag: ParsedTag = { tag: `**${filter.title}** is **${codeRange.label}**`, - value: statusCodeTag.value + value: statusCodeTag.value, + title: filter.title }; parsedTags.update((tags) => { tags.push(newTag); @@ -156,9 +164,10 @@ export function setDateFilter(filter: FilterData, columns: Column[]) { }); if (dateRange) { cleanOldTags(filter?.title); - const newTag = { + const newTag: ParsedTag = { tag: `**${filter.title}** is **${dateRange.label}**`, - value: dateTag.value + value: dateTag.value, + title: filter.title }; parsedTags.update((tags) => { tags.push(newTag); diff --git a/src/lib/layout/responsiveContainerHeader.svelte b/src/lib/layout/responsiveContainerHeader.svelte index ebf390cce..79b7f2bcc 100644 --- a/src/lib/layout/responsiveContainerHeader.svelte +++ b/src/lib/layout/responsiveContainerHeader.svelte @@ -109,7 +109,7 @@ direction="row" alignItems="center" gap="m" - style={`min-width: 0; flex: 1 1 auto;`}> + style="min-width: 0; flex: 1 1 auto;"> {#if hasSearch} {/if} @@ -119,7 +119,7 @@ alignItems="center" gap="s" wrap="wrap" - style={`min-width: 0;`}> + style="min-width: 0;"> @@ -127,7 +127,7 @@ direction="row" alignItems="center" justifyContent="flex-end" - style={`align-self: flex-start; white-space: nowrap;`}> + style="align-self: flex-start; white-space: nowrap;"> {#if hasDisplaySettings} {/if} From f3e1cf9e985aa59c2df49ea68d7c34b7f4ebdd21 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Thu, 5 Feb 2026 12:39:11 +0530 Subject: [PATCH 12/51] merge --- src/lib/layout/responsiveContainerHeader.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/layout/responsiveContainerHeader.svelte b/src/lib/layout/responsiveContainerHeader.svelte index 9c34d0cdd..79b7f2bcc 100644 --- a/src/lib/layout/responsiveContainerHeader.svelte +++ b/src/lib/layout/responsiveContainerHeader.svelte @@ -23,7 +23,6 @@ hasSearch = false, searchPlaceholder = 'Search by ID', hasFilters = false, - hasCustomFiltersOnly = false, analyticsSource = '', children }: { @@ -34,7 +33,6 @@ hasSearch?: boolean; searchPlaceholder?: string; hasFilters?: boolean; - hasCustomFiltersOnly?: boolean; analyticsSource?: string; children?: Snippet; } = $props(); From aff587b7796dc82c5025ba688ccfc132be0d3501 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Thu, 5 Feb 2026 12:44:30 +0530 Subject: [PATCH 13/51] svelte check failer --- .../project-[region]-[project]/messaging/providers/+page.svelte | 1 - .../project-[region]-[project]/messaging/topics/+page.svelte | 1 - 2 files changed, 2 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/messaging/providers/+page.svelte b/src/routes/(console)/project-[region]-[project]/messaging/providers/+page.svelte index 5d3929d96..cc80b73af 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/providers/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/messaging/providers/+page.svelte @@ -23,7 +23,6 @@ view={View.Table} hideView hasFilters - hasCustomFiltersOnly hasSearch analyticsSource="messaging_providers" searchPlaceholder="Search by name or ID"> diff --git a/src/routes/(console)/project-[region]-[project]/messaging/topics/+page.svelte b/src/routes/(console)/project-[region]-[project]/messaging/topics/+page.svelte index 30682ca9d..47a305603 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/topics/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/messaging/topics/+page.svelte @@ -70,7 +70,6 @@ view={View.Table} hideView hasFilters - hasCustomFiltersOnly hasSearch analyticsSource="messaging_topics_filter" searchPlaceholder="Search by name or ID"> From 3766948826b15dc247c6b16d5c57ba908c90a6a6 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Thu, 5 Feb 2026 12:58:40 +0530 Subject: [PATCH 14/51] redundant button --- .../components/filters/parsedTagList.svelte | 3 ++- .../layout/responsiveContainerHeader.svelte | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/lib/components/filters/parsedTagList.svelte b/src/lib/components/filters/parsedTagList.svelte index 98bb4870b..0b3116f74 100644 --- a/src/lib/components/filters/parsedTagList.svelte +++ b/src/lib/components/filters/parsedTagList.svelte @@ -19,6 +19,7 @@ import Menu from '$lib/components/menu/menu.svelte'; import { addFilterAndApply, buildFilterCol, type FilterData } from './quickFilters'; import QuickFilters from '$lib/components/filters/quickFilters.svelte'; + import { isSmallViewport } from '$lib/stores/viewport'; let { columns = writable([]), @@ -254,7 +255,7 @@ }}>Clear all {/if} - {#if filterCols?.length} + {#if filterCols?.length && !$isSmallViewport} {/if} diff --git a/src/lib/layout/responsiveContainerHeader.svelte b/src/lib/layout/responsiveContainerHeader.svelte index 79b7f2bcc..7812f34f9 100644 --- a/src/lib/layout/responsiveContainerHeader.svelte +++ b/src/lib/layout/responsiveContainerHeader.svelte @@ -113,15 +113,17 @@ {#if hasSearch} {/if} - - - - + {#if hasFilters} + + + + + {/if} Date: Thu, 5 Feb 2026 13:04:32 +0530 Subject: [PATCH 15/51] update logic --- .../components/filters/parsedTagList.svelte | 98 +++++++++---------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/src/lib/components/filters/parsedTagList.svelte b/src/lib/components/filters/parsedTagList.svelte index 0b3116f74..88ccc66a0 100644 --- a/src/lib/components/filters/parsedTagList.svelte +++ b/src/lib/components/filters/parsedTagList.svelte @@ -67,7 +67,6 @@ // Always-show placeholders are derived from available filters (no hardcoding) // Use reactive array so runes can track changes let hiddenPlaceholders: string[] = $state([]); - let placeholderVersion = $state(0); // used to force keyed re-render when needed let activeTitles = $derived( ($parsedTags || []).map((t) => (t as ParsedTag).title).filter(Boolean) as string[] @@ -142,7 +141,7 @@ null, next, $columns, - '' + analyticsSource ); } else { addFilterAndApply( @@ -152,7 +151,7 @@ option.value, [], $columns, - '' + analyticsSource ); } }}> @@ -195,54 +194,51 @@ {/if} - {#key placeholderVersion} - {#if placeholders?.length} - {#each placeholders as filter (filter.title + filter.id)} - - - - - {capitalize(filter.title)} - - { - e.stopPropagation(); - if (!hiddenPlaceholders.includes(filter.title)) { - hiddenPlaceholders.push(filter.title); - } - placeholderVersion++; - }}> - - - - - {#if filter.options} - {#each filter.options as option (filter.title + option.value + option.label)} - - { - addFilterAndApply( - filter.id, - filter.title, - filter.operator, - filter?.array ? null : option.value, - filter?.array ? [option.value] : [], - $columns, - '' - ); - }}> - {capitalize(option.label)} - - - {/each} - {/if} - - - - {/each} - {/if} - {/key} + {#if placeholders?.length} + {#each placeholders as filter (filter.title + filter.id)} + + + + + {capitalize(filter.title)} + + { + e.stopPropagation(); + if (!hiddenPlaceholders.includes(filter.title)) { + hiddenPlaceholders = [...hiddenPlaceholders, filter.title]; + } + }}> + + + + + {#if filter.options} + {#each filter.options as option (filter.title + option.value + option.label)} + + { + addFilterAndApply( + filter.id, + filter.title, + filter.operator, + filter?.array ? null : option.value, + filter?.array ? [option.value] : [], + $columns, + analyticsSource + ); + }}> + {capitalize(option.label)} + + + {/each} + {/if} + + + + {/each} + {/if} {#if $parsedTags?.length} + {#if buttonVariant === 'secondary'} + + {:else} + + {/if} {#each filterCols.filter((f) => f?.options) as filter (filter.title + filter.id)} {#if filter.options} diff --git a/src/lib/layout/responsiveContainerHeader.svelte b/src/lib/layout/responsiveContainerHeader.svelte index 7812f34f9..571d325c7 100644 --- a/src/lib/layout/responsiveContainerHeader.svelte +++ b/src/lib/layout/responsiveContainerHeader.svelte @@ -1,6 +1,7 @@ diff --git a/src/routes/(console)/project-[region]-[project]/databases/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/+page.svelte index 692098fb3..be153060d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/+page.svelte @@ -58,7 +58,7 @@ {#if $canWriteDatabases} diff --git a/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte b/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte index 2084ce89e..b5c484d28 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte @@ -138,7 +138,7 @@ hasSearch hasFilters filtersStyle="dropdown" - bind:view={data.view} + view={data.view} analyticsSource="messaging_messages" searchPlaceholder="Search by description, type, status, or ID"> {#if $canWriteMessages} diff --git a/src/routes/(console)/project-[region]-[project]/storage/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/+page.svelte index 50463873e..42a1faac2 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/+page.svelte @@ -41,7 +41,7 @@ {#if $canWriteBuckets} From f09baa83b7b64774fb83cc7551d88b61b71003aa Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Sat, 7 Feb 2026 19:34:41 +0530 Subject: [PATCH 35/51] fix for conversion --- src/lib/helpers/unit.ts | 2 +- .../bucket-[bucket]/settings/updateMaxFileSize.svelte | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/helpers/unit.ts b/src/lib/helpers/unit.ts index bc24429bd..9163a8f6e 100644 --- a/src/lib/helpers/unit.ts +++ b/src/lib/helpers/unit.ts @@ -53,7 +53,7 @@ export function createValueUnitPair(initialValue = 0, units: Unit } const unitInBase = v * prevUnit.value; - return unitInBase / newUnit.value; + return Math.round(unitInBase / newUnit.value); }); }); return { diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte index dd7b874fa..5d79d94e9 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte @@ -19,9 +19,7 @@ const options = units.map((v) => ({ label: v.name, value: v.name })); $: selectedUnit = $unit; - const maxValue = function formMaxFileSize() { - return (service * 1000 * 1000) / units.find((unit) => unit.name === selectedUnit).value; - }; + $: maxValue = (service * 1000 * 1000) / units.find((unit) => unit.name === selectedUnit).value; function updateMaxSize() { updateBucket( @@ -80,7 +78,7 @@ disabled={$readOnly && !GRACE_PERIOD_OVERRIDE} placeholder={bucket.maximumFileSize.toString()} min={0} - max={isCloud ? maxValue() : Infinity} + max={isCloud ? maxValue : Infinity} bind:value={$value} /> From 4490c79caf159b723b59874cc56938fe56396ba9 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Sat, 7 Feb 2026 19:48:46 +0530 Subject: [PATCH 36/51] fix: for row security also changing --- .../database-[database]/table-[table]/settings/+page.svelte | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/+page.svelte index bca5e5fde..b024ad585 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/settings/+page.svelte @@ -21,7 +21,10 @@ return { name: table.name, tableId: page.params.table, - databaseId: page.params.database + databaseId: page.params.database, + rowSecurity: table.recordSecurity, + enabled: table.enabled, + permissions: table.$permissions }; }); From c773fd0b8d1a3ed9c1e0047fce27f43cb03d52dc Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Sat, 7 Feb 2026 20:12:09 +0530 Subject: [PATCH 37/51] fix f=gigabytes --- src/lib/helpers/unit.ts | 2 +- .../bucket-[bucket]/settings/updateMaxFileSize.svelte | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/helpers/unit.ts b/src/lib/helpers/unit.ts index 9163a8f6e..bc24429bd 100644 --- a/src/lib/helpers/unit.ts +++ b/src/lib/helpers/unit.ts @@ -53,7 +53,7 @@ export function createValueUnitPair(initialValue = 0, units: Unit } const unitInBase = v * prevUnit.value; - return Math.round(unitInBase / newUnit.value); + return unitInBase / newUnit.value; }); }); return { diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte index 5d79d94e9..dbd2a9033 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte @@ -21,11 +21,13 @@ $: maxValue = (service * 1000 * 1000) / units.find((unit) => unit.name === selectedUnit).value; + $: step = $unit === 'Gigabytes' ? 0.01 : 1; + function updateMaxSize() { updateBucket( bucket, { - maximumFileSize: $baseValue + maximumFileSize: Math.round($baseValue) }, { trackEventName: Submit.BucketUpdateSize, @@ -78,6 +80,7 @@ disabled={$readOnly && !GRACE_PERIOD_OVERRIDE} placeholder={bucket.maximumFileSize.toString()} min={0} + {step} max={isCloud ? maxValue : Infinity} bind:value={$value} /> From 593827fbde6f0da5cb5cb672a8303d00ee25ad86 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Mon, 9 Feb 2026 12:15:41 +0530 Subject: [PATCH 38/51] fix: prevent invalid min/max params for integer attributes --- .../table-[table]/columns/float.svelte | 12 ++++++------ .../table-[table]/columns/integer.svelte | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte index 3badf6d94..e45544e94 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte @@ -14,9 +14,9 @@ tableId, key, required: data.required, - min: data.min, - max: data.max, - xdefault: data.default, + min: data.min !== null ? Number(data.min) : data.min, + max: data.max !== null ? Number(data.max) : data.max, + xdefault: data.default !== null ? Number(data.default) : data.default, array: data.array }); } @@ -32,9 +32,9 @@ tableId, key: originalKey, required: data.required, - xdefault: data.default, - min: data.min, - max: data.max, + xdefault: data.default !== null ? Number(data.default) : data.default, + min: data.min !== null ? Number(data.min) : data.min, + max: data.max !== null ? Number(data.max) : data.max, newKey: data.key !== originalKey ? data.key : undefined }); } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte index 3367a3af9..da32953ca 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte @@ -14,9 +14,9 @@ tableId, key, required: data.required, - min: data.min, - max: data.max, - xdefault: data.default, + min: data.min !== null ? Number(data.min) : data.min, + max: data.max !== null ? Number(data.max) : data.max, + xdefault: data.default !== null ? Number(data.default) : data.default, array: data.array }); } @@ -32,9 +32,9 @@ tableId, key: originalKey, required: data.required, - xdefault: data.default, - min: data.min, - max: data.max, + xdefault: data.default !== null ? Number(data.default) : data.default, + min: data.min !== null ? Number(data.min) : data.min, + max: data.max !== null ? Number(data.max) : data.max, newKey: data.key !== originalKey ? data.key : undefined }); } From a2f630630ac85c88d36b9a5d3b4bcfef5a97829b Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Mon, 9 Feb 2026 12:28:48 +0530 Subject: [PATCH 39/51] use a helper --- src/lib/helpers/numbers.ts | 14 ++++++++++++++ .../table-[table]/columns/float.svelte | 13 +++++++------ .../table-[table]/columns/integer.svelte | 13 +++++++------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/lib/helpers/numbers.ts b/src/lib/helpers/numbers.ts index 0a0657436..fa5cd243a 100644 --- a/src/lib/helpers/numbers.ts +++ b/src/lib/helpers/numbers.ts @@ -95,3 +95,17 @@ export function toExponential(value: number | bigint, fractionDigits: number = 2 export function clampMin(value: number, min: number = 0): number { return Math.max(min, value || 0); } + +export function toNumberOrNull(value: unknown): number | null { + if (value === null || value === undefined) { + return null; + } + + if (typeof value === 'string' && value.trim() === '') { + return null; + } + + const num = Number(value); + + return Number.isNaN(num) ? null : num; +} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte index e45544e94..077023a99 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte @@ -2,6 +2,7 @@ import { page } from '$app/state'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; + import { toNumberOrNull } from '$lib/helpers/numbers'; export async function submitFloat( databaseId: string, @@ -14,9 +15,9 @@ tableId, key, required: data.required, - min: data.min !== null ? Number(data.min) : data.min, - max: data.max !== null ? Number(data.max) : data.max, - xdefault: data.default !== null ? Number(data.default) : data.default, + min: toNumberOrNull(data.min), + max: toNumberOrNull(data.max), + xdefault: toNumberOrNull(data.default), array: data.array }); } @@ -32,9 +33,9 @@ tableId, key: originalKey, required: data.required, - xdefault: data.default !== null ? Number(data.default) : data.default, - min: data.min !== null ? Number(data.min) : data.min, - max: data.max !== null ? Number(data.max) : data.max, + xdefault: toNumberOrNull(data.default), + min: toNumberOrNull(data.min), + max: toNumberOrNull(data.max), newKey: data.key !== originalKey ? data.key : undefined }); } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte index da32953ca..9291a9a94 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte @@ -2,6 +2,7 @@ import { page } from '$app/state'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; + import { toNumberOrNull } from '$lib/helpers/numbers'; export async function submitInteger( databaseId: string, @@ -14,9 +15,9 @@ tableId, key, required: data.required, - min: data.min !== null ? Number(data.min) : data.min, - max: data.max !== null ? Number(data.max) : data.max, - xdefault: data.default !== null ? Number(data.default) : data.default, + min: toNumberOrNull(data.min), + max: toNumberOrNull(data.max), + xdefault: toNumberOrNull(data.default), array: data.array }); } @@ -32,9 +33,9 @@ tableId, key: originalKey, required: data.required, - xdefault: data.default !== null ? Number(data.default) : data.default, - min: data.min !== null ? Number(data.min) : data.min, - max: data.max !== null ? Number(data.max) : data.max, + xdefault: toNumberOrNull(data.default), + min: toNumberOrNull(data.min), + max: toNumberOrNull(data.max), newKey: data.key !== originalKey ? data.key : undefined }); } From ed7db9f8cdae2168c60681541279d57c7ede1ebc Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 9 Feb 2026 13:34:07 +0530 Subject: [PATCH 40/51] fix: hide empty segment. --- .../components/progressbar/ProgressBar.svelte | 20 +++++++++++++++---- src/lib/components/progressbar/index.ts | 1 + .../table-[table]/columns/varchar.svelte | 5 ++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/lib/components/progressbar/ProgressBar.svelte b/src/lib/components/progressbar/ProgressBar.svelte index 4591e706e..1221fefbe 100644 --- a/src/lib/components/progressbar/ProgressBar.svelte +++ b/src/lib/components/progressbar/ProgressBar.svelte @@ -9,19 +9,31 @@ */ export let maxSize: $$Props['maxSize']; + /** + * Hides empty segments where size is < 0; + */ + export let hideEmptySegments: $$Props['hideEmptySegments']; + /** * The data for the progressbar */ export let data: $$Props['data']; + $: segments = hideEmptySegments ? data.filter((item) => item.size > 0) : data; + /** * The remaining value of the progressbar */ - $: remainder = data.reduce((sum: number, item: ProgressbarData) => sum - item.size, maxSize); + $: remainder = segments.reduce( + (sum: number, item: ProgressbarData) => sum - item.size, + maxSize + ); + + $: segmentGap = segments.length > 1 ? '2px' : '0px'; -
- {#each $$props.data as item} +
+ {#each segments as item}
; }; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte index f2f046a75..47bd693de 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte @@ -145,7 +145,10 @@ - + {#if exceedsLimit} This column exceeds the remaining row space. Consider using text, mediumtext, or From a14c0b3c60e12d8fe0c6b0be55e8342d029ff7d9 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 9 Feb 2026 13:37:21 +0530 Subject: [PATCH 41/51] add: default value. --- src/lib/components/progressbar/ProgressBar.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/progressbar/ProgressBar.svelte b/src/lib/components/progressbar/ProgressBar.svelte index 1221fefbe..6ae9b5a8c 100644 --- a/src/lib/components/progressbar/ProgressBar.svelte +++ b/src/lib/components/progressbar/ProgressBar.svelte @@ -12,7 +12,7 @@ /** * Hides empty segments where size is < 0; */ - export let hideEmptySegments: $$Props['hideEmptySegments']; + export let hideEmptySegments: $$Props['hideEmptySegments'] = false; /** * The data for the progressbar From ba95658f3701bd1ed691080cc82b622d5f499301 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 9 Feb 2026 13:38:10 +0530 Subject: [PATCH 42/51] fix: doc. --- src/lib/components/progressbar/ProgressBar.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/progressbar/ProgressBar.svelte b/src/lib/components/progressbar/ProgressBar.svelte index 6ae9b5a8c..4b4b25c5a 100644 --- a/src/lib/components/progressbar/ProgressBar.svelte +++ b/src/lib/components/progressbar/ProgressBar.svelte @@ -10,7 +10,7 @@ export let maxSize: $$Props['maxSize']; /** - * Hides empty segments where size is < 0; + * Hides empty segments where size is <= 0; */ export let hideEmptySegments: $$Props['hideEmptySegments'] = false; From 5c1f03624a3942c3f4a15a06d323c3fee0e35f89 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 9 Feb 2026 16:09:28 +0530 Subject: [PATCH 43/51] fix: reason not mentioned. --- .../change-plan/+page.svelte | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte index 0e06f1016..850f9fb11 100644 --- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte +++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte @@ -151,11 +151,17 @@ } async function trackDowngradeFeedback() { + const selectedReason = feedbackDowngradeOptions.find( + (option) => option.value === feedbackDowngradeReason + )?.label; + + const defaultReason = feedbackDowngradeOptions.find( + (option) => option.value === 'other' + )?.label; + await sdk.forConsole.organizations.createDowngradeFeedback({ organizationId: data.organization.$id, - reason: feedbackDowngradeOptions.find( - (option) => option.value === feedbackDowngradeReason - )?.label, + reason: selectedReason ?? defaultReason, message: feedbackMessage ?? '', fromPlanId: data.organization.billingPlanId, toPlanId: selectedPlan.$id From 14f1c8afd2690828294d9ac4b30bc24f5cea79d3 Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Mon, 9 Feb 2026 12:00:51 +0000 Subject: [PATCH 44/51] fix: Dockerfile to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-ALPINE320-LIBPNG-15062382 - https://snyk.io/vuln/SNYK-ALPINE320-LIBPNG-15062385 - https://snyk.io/vuln/SNYK-ALPINE320-OPENSSL-15121256 - https://snyk.io/vuln/SNYK-ALPINE320-LIBXML2-10165474 - https://snyk.io/vuln/SNYK-ALPINE320-LIBXML2-10165475 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5ccdd958f..788db3b62 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,7 +39,7 @@ ENV NODE_OPTIONS=--max_old_space_size=8192 RUN bun run build -FROM nginx:1.26.3-alpine +FROM nginx:1.29.5-alpine EXPOSE 80 From 979168739e7dbd5a71b6f545c9c3f384f5e06140 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Mon, 9 Feb 2026 22:40:17 +0000 Subject: [PATCH 45/51] use structuredClone to handle BigInt in conservative stores --- src/lib/helpers/stores.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/helpers/stores.ts b/src/lib/helpers/stores.ts index 13a63437d..11c355a8a 100644 --- a/src/lib/helpers/stores.ts +++ b/src/lib/helpers/stores.ts @@ -1,5 +1,5 @@ import { writable, type Writable } from 'svelte/store'; -import { deepClone, objectEntries } from './object'; +import { objectEntries } from './object'; /** * Given an object `obj`, returns an object of writable stores for each key in that object. @@ -16,7 +16,7 @@ export function createConservative>(obj: Obj [K in keyof Obj]: Writable; }; - const history = deepClone(obj); + const history = structuredClone(obj); function listen(input: Obj) { objectEntries(input).forEach(([key, value]) => { From c9f32aaba544c4db99e60ff05587773d6f4066c8 Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 10 Feb 2026 14:33:26 +0530 Subject: [PATCH 46/51] bump: sdk. --- bun.lock | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lock b/bun.lock index b5ebfac76..9f57d4726 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "@appwrite/console", "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@bb72008", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@c6f60aa", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@c1feb89", "@appwrite.io/pink-legacy": "^1.0.3", @@ -107,7 +107,7 @@ "@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="], - "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@bb72008", { "dependencies": { "bignumber.js": "9.0.0", "json-bigint": "1.0.0" } }], + "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@c6f60aa", { "dependencies": { "bignumber.js": "9.0.0", "json-bigint": "1.0.0" } }], "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], diff --git a/package.json b/package.json index fb534d399..2b6618747 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@bb72008", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@c6f60aa", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@c1feb89", "@appwrite.io/pink-legacy": "^1.0.3", From 77aa1203341811594a86f5a20c98cd1277246a09 Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 10 Feb 2026 16:57:51 +0530 Subject: [PATCH 47/51] update: make modal dismissible. --- src/lib/components/billing/updateStateModal.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/components/billing/updateStateModal.svelte b/src/lib/components/billing/updateStateModal.svelte index db6160a7a..fcdf686d7 100644 --- a/src/lib/components/billing/updateStateModal.svelte +++ b/src/lib/components/billing/updateStateModal.svelte @@ -63,9 +63,8 @@ From 9da6614cf13ea1f41dbade9edd431b0a31d0a986 Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 10 Feb 2026 17:01:54 +0530 Subject: [PATCH 48/51] lint. --- src/lib/components/billing/updateStateModal.svelte | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib/components/billing/updateStateModal.svelte b/src/lib/components/billing/updateStateModal.svelte index fcdf686d7..868f9be4c 100644 --- a/src/lib/components/billing/updateStateModal.svelte +++ b/src/lib/components/billing/updateStateModal.svelte @@ -62,11 +62,7 @@ } - + State information is required for US payment methods to apply correct taxes and meet From 7ee9960e1d8b7928f5ff13bcaf630e9d8409f12d Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Tue, 10 Feb 2026 17:42:02 +0530 Subject: [PATCH 49/51] upgrade packages --- bun.lock | 8 ++++---- package.json | 4 ++-- src/lib/helpers/numbers.ts | 14 -------------- .../table-[table]/columns/float.svelte | 13 ++++++------- .../table-[table]/columns/integer.svelte | 13 ++++++------- 5 files changed, 18 insertions(+), 34 deletions(-) diff --git a/bun.lock b/bun.lock index b5ebfac76..47ef09700 100644 --- a/bun.lock +++ b/bun.lock @@ -8,9 +8,9 @@ "@ai-sdk/svelte": "^1.1.24", "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@bb72008", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@c1feb89", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@df765cc", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@dd7e01c", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@df765cc", "@faker-js/faker": "^9.9.0", "@plausible-analytics/tracker": "^0.4.4", "@popperjs/core": "^2.11.8", @@ -111,11 +111,11 @@ "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], - "@appwrite.io/pink-icons-svelte": ["@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@c1feb89", { "peerDependencies": { "svelte": "^4.0.0" } }], + "@appwrite.io/pink-icons-svelte": ["@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@df765cc", { "peerDependencies": { "svelte": "^4.0.0" } }], "@appwrite.io/pink-legacy": ["@appwrite.io/pink-legacy@1.0.3", "", { "dependencies": { "@appwrite.io/pink-icons": "1.0.0", "the-new-css-reset": "^1.11.2" } }, "sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ=="], - "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@dd7e01c", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }], + "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@df765cc", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }], "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], diff --git a/package.json b/package.json index fb534d399..3ef986a9b 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,9 @@ "@ai-sdk/svelte": "^1.1.24", "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@bb72008", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@c1feb89", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@df765cc", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@dd7e01c", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@df765cc", "@faker-js/faker": "^9.9.0", "@plausible-analytics/tracker": "^0.4.4", "@popperjs/core": "^2.11.8", diff --git a/src/lib/helpers/numbers.ts b/src/lib/helpers/numbers.ts index fa5cd243a..0a0657436 100644 --- a/src/lib/helpers/numbers.ts +++ b/src/lib/helpers/numbers.ts @@ -95,17 +95,3 @@ export function toExponential(value: number | bigint, fractionDigits: number = 2 export function clampMin(value: number, min: number = 0): number { return Math.max(min, value || 0); } - -export function toNumberOrNull(value: unknown): number | null { - if (value === null || value === undefined) { - return null; - } - - if (typeof value === 'string' && value.trim() === '') { - return null; - } - - const num = Number(value); - - return Number.isNaN(num) ? null : num; -} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte index 077023a99..bc64c121e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte @@ -2,7 +2,6 @@ import { page } from '$app/state'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; - import { toNumberOrNull } from '$lib/helpers/numbers'; export async function submitFloat( databaseId: string, @@ -15,9 +14,9 @@ tableId, key, required: data.required, - min: toNumberOrNull(data.min), - max: toNumberOrNull(data.max), - xdefault: toNumberOrNull(data.default), + min: data.min, + max: data.max, + xdefault: data.default, array: data.array }); } @@ -33,9 +32,9 @@ tableId, key: originalKey, required: data.required, - xdefault: toNumberOrNull(data.default), - min: toNumberOrNull(data.min), - max: toNumberOrNull(data.max), + min: data.min, + max: data.max, + xdefault: data.default, newKey: data.key !== originalKey ? data.key : undefined }); } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte index 9291a9a94..3367a3af9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte @@ -2,7 +2,6 @@ import { page } from '$app/state'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; - import { toNumberOrNull } from '$lib/helpers/numbers'; export async function submitInteger( databaseId: string, @@ -15,9 +14,9 @@ tableId, key, required: data.required, - min: toNumberOrNull(data.min), - max: toNumberOrNull(data.max), - xdefault: toNumberOrNull(data.default), + min: data.min, + max: data.max, + xdefault: data.default, array: data.array }); } @@ -33,9 +32,9 @@ tableId, key: originalKey, required: data.required, - xdefault: toNumberOrNull(data.default), - min: toNumberOrNull(data.min), - max: toNumberOrNull(data.max), + xdefault: data.default, + min: data.min, + max: data.max, newKey: data.key !== originalKey ? data.key : undefined }); } From 00b390c24d7c27ae7fdff5d94e50ab9061980eaa Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Tue, 10 Feb 2026 17:53:46 +0530 Subject: [PATCH 50/51] svelte check error due to new chnages --- src/lib/components/git/selectRootModal.svelte | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lib/components/git/selectRootModal.svelte b/src/lib/components/git/selectRootModal.svelte index bc817623e..fed59657c 100644 --- a/src/lib/components/git/selectRootModal.svelte +++ b/src/lib/components/git/selectRootModal.svelte @@ -152,7 +152,13 @@ Select the directory where your site code is located using the menu below. - + From 928a31bb11ab22f9df04ce202887d78cc6e1503a Mon Sep 17 00:00:00 2001 From: Harsh Mahajan Date: Wed, 11 Feb 2026 15:00:14 +0530 Subject: [PATCH 51/51] fix: make project limit alert program-aware --- .../(console)/organization-[organization]/+page.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/(console)/organization-[organization]/+page.svelte b/src/routes/(console)/organization-[organization]/+page.svelte index 947cdedca..e10aa76c9 100644 --- a/src/routes/(console)/organization-[organization]/+page.svelte +++ b/src/routes/(console)/organization-[organization]/+page.svelte @@ -219,11 +219,11 @@ {/if} - {#if isCloud && data.currentPlan?.projects !== 0 && projectsToArchive.length === 0 && !freePlanAlertDismissed} + {#if isCloud && !data.program && data.currentPlan?.projects !== 0 && projectsToArchive.length === 0 && !freePlanAlertDismissed} Your Free plan includes up to 2 projects and limited resources. Upgrade to unlock - more capacity and features. + >Your Free plan includes up to {data.currentPlan?.projects} projects and limited resources. + Upgrade to unlock more capacity and features.