Conversation
update: move things around.
update: db page to svelte5.
optimize: imports, singular sources of truth.
fix: height issues on mobile.
add: view selector for custom columns; update; organize the filters for code-mirror; update: disable search/find for now on the editor;
add: display names to view selector. add: new sonners for error and save. add: fuzzy search helper.
add: json5 parser, linter and remove custom one. update: improve code editor's behaviour. add: apply fuzzy suggestions. update: faker for documentsDB.
fix: a bug on autocomplete + backspace adding excess commas. add: duplicate content shortcut.
update: unsaved changes warning.
fix: responsive side spacing for header.
# Conflicts: # src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte
Console (appwrite/console)Project ID: Sites (1)
Tip Every Git commit and branch gets its own deployment URL automatically |
WalkthroughThis pull request introduces comprehensive support for dedicated databases (Prisma, shared, and dedicated types) across the Appwrite console. Changes include a new dedicated databases SDK module exporting 45+ methods and 30+ types, refactoring database terminology from table-centric to entity-centric architecture to support both traditional tables and NoSQL documents, adding dedicated database management pages and settings components (backups, monitoring, HA, cross-region, read replicas, etc.), introducing a CodeMirror 6-based JSON editor with syntax highlighting and validation, new collection and document management pages, and updates to dependencies, stores, and navigation to accommodate multiple database types throughout the application. Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes ✨ Finishing Touches
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 7
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (10)
src/lib/helpers/faker.ts (1)
123-145:⚠️ Potential issue | 🟠 MajorDon't infer the schema-less path from
filteredColumns.length === 0.At Lines 123-145, this folds together "no fields were supplied" and "fields were supplied but none are writable." The latter can happen for tables with only relationships or temporarily unavailable columns, and this path then fabricates
name/💡 If
undefinedis the intended schema-less signalconst filteredColumns = field?.filter( (column) => column.type !== 'relationship' && column.status === 'available' ) ?? []; + const useDefaultRecord = field === undefined; @@ - if (filteredColumns.length === 0) { + if (useDefaultRecord) { record = generateDefaultRecord(id); } else { record = { $id: id }; for (const column of filteredColumns) { record[column.key] = generateValueForField(column); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/helpers/faker.ts` around lines 123 - 145, The code incorrectly treats "no writable columns" the same as "schema-less" by checking filteredColumns.length === 0; change the branch to explicitly detect schema-less input (check if field === undefined) and only call generateDefaultRecord(id) in that case, otherwise build record = { $id: id } and populate with generateValueForField(column) for each column in filteredColumns; update any related type assumptions around record and retain the existing ID.unique() / count loop and filteredColumns computation.src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte (1)
263-288:⚠️ Potential issue | 🟡 MinorAdd
!isDedicatedTypeguard to the bottom sheet button to prevent rendering empty menus for dedicated databases.The button at line 253 that toggles
openBottomSheethas no protection against dedicated database types. SinceloadEntities()returns early for dedicated databases (line 92),sortedEntitieswould be empty, and clicking the button would renderBottomSheet.Menuwith no items. While the button appears only on entity screens (line 242), which shouldn't normally exist for dedicated databases, there's no explicit safeguard. Adding{#if!isDedicatedType}around the button or theon:clickhandler would prevent this edge case.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte around lines 263 - 288, Wrap the BottomSheet trigger and/or the BottomSheet.Menu render with a guard that checks !isDedicatedType to avoid opening/rendering an empty menu for dedicated DBs; specifically, ensure the click that toggles openBottomSheet (and the BottomSheet.Menu usage that consumes sortedEntities) is only reachable when isDedicatedType is false (or skip toggling when isDedicatedType is true), since loadEntities returns early for dedicated DBs and sortedEntities can be empty.src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts (1)
125-128:⚠️ Potential issue | 🟡 MinorAdd missing
SortStateimport from parent store.The
SortStatetype is defined insrc/routes/(console)/project-[region]-[project]/databases/database-[database]/store.tsbut not imported in this file. Without it, line 125 will fail TypeScript type-checking. The collection store at the same database level correctly imports it:import type { SortState } from '$database/store';Add this import statement to the table store.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts around lines 125 - 128, The file defines sortState as writable<SortState> but fails TypeScript checks because SortState is not imported; add a type-only import for the SortState type from the parent database store module (the same module used by the collection store) at the top of this table store file so the sortState declaration compiles and references the correct SortState type.src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/createPolicy.svelte (2)
242-269:⚠️ Potential issue | 🔴 CriticalThe single-plan “Daily backups” switch now points at the wrong preset.
In the non-backups flow, the new filtering leaves
[daily, none], so$presetPolicies[1]resolves tonone. Toggling this switch will submit the no-backup option instead of the daily policy.Proposed fix
- {`@const` dailyPolicy = $presetPolicies[1]} + {`@const` dailyPolicy = $presetPolicies.find((policy) => policy.id === 'daily')} @@ - on:change={(event) => markPolicyChecked(event, dailyPolicy)}> + on:change={(event) => dailyPolicy && markPolicyChecked(event, dailyPolicy)}>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/backups/createPolicy.svelte around lines 242 - 269, The current dailyPolicy constant uses a fixed index ($presetPolicies[1]) which points to the wrong preset after filtering; change the lookup to find the daily preset by identity instead (e.g., locate the policy where id/name/type equals "daily") and use that object when calling markPolicyChecked from the InputSwitch (id="daily_backup"), also add a safe guard if the find returns undefined so the UI doesn't crash; update references to dailyPolicy in this component accordingly.
144-149:⚠️ Potential issue | 🟡 MinorHoist
selectedPolicyGroupabove the reactive reset to fix use-before-declaration.Line 148 assigns to
selectedPolicyGroupbefore its declaration at line 182. Move the declaration above line 144 to resolve this Biome lint error.+ let selectedPolicyGroup: string | null = null; + $: if (isShowing) { resetFormVariables(); showCustomPolicy = false; listOfCustomPolicies = []; selectedPolicyGroup = null;Also, change the type annotation from
stringtostring | nullsince the variable is initialized and reset tonull.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/backups/createPolicy.svelte around lines 144 - 149, Move the declaration of selectedPolicyGroup so it appears before the reactive block that resets state (the $: if (isShowing) { ... } block) to avoid use-before-declaration; update its type annotation from string to string | null since the code initializes and later resets it to null; ensure references to selectedPolicyGroup inside resetFormVariables, showCustomPolicy, listOfCustomPolicies, and the presetPolicies.update reactive code remain valid after the move.src/routes/(console)/project-[region]-[project]/databases/+page.svelte (2)
120-120:⚠️ Potential issue | 🔴 Critical
Createcomponent used but not imported.The
<Create>component at the end of the file is referenced but never imported, andhandleCreatecallback is also undefined. This appears to be leftover code from the previous modal-based flow.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/+page.svelte at line 120, The file references the Create component and a handleCreate callback but neither is defined; remove the leftover modal usage or reintroduce both properly: either import the Create component and implement a handleCreate function (e.g., to update local state or call the existing reload/refresh routine) and pass the project prop, or delete the line "<Create bind:showCreate on:created={handleCreate} project={data.project} />" and any related bind/show state; ensure references to Create and handleCreate are consistently added or removed so there are no unresolved symbols.
59-74:⚠️ Potential issue | 🔴 CriticalMissing
Tooltipimport.The
Tooltipcomponent is used but not imported. This will cause a runtime error.Proposed fix
import { Icon } from '@appwrite.io/pink-svelte'; +import { Tooltip } from '$lib/components';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/+page.svelte around lines 59 - 74, The Tooltip component is used but not imported; add an import for Tooltip at the top of the file (import Tooltip from the same module/package you import Button/Icon from) so the <Tooltip> symbol is defined; ensure the import is colocated with the other UI imports (where Button, Icon, IconPlus are imported) to match existing patterns and avoid runtime errors.src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/edit.svelte (1)
11-16:⚠️ Potential issue | 🔴 CriticalRemove the duplicate
Columnsimport.This module declares
Columnstwice in the same scope (lines 11 and 16), which blocks TypeScript compilation and linting. Keep only the import from$database/store(line 16), as that aligns with the pattern used by other files in the columns directory.Suggested fix
-import { type Columns, columnsOrder, databaseColumnSheetOptions } from '../store'; +import { columnsOrder, databaseColumnSheetOptions } from '../store'; import { columnOptions, STRING_COLUMN_NAME, type Option } from './store'; import { onMount } from 'svelte'; import { Layout } from '@appwrite.io/pink-svelte'; import { preferences } from '$lib/stores/preferences'; import type { Columns } from '$database/store';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/edit.svelte around lines 11 - 16, Remove the duplicate Columns type import by deleting Columns from the first import line (the one importing "columnsOrder" and "databaseColumnSheetOptions" from '../store') and keep only the import that brings Columns from '$database/store'; ensure the remaining imports still include columnsOrder, databaseColumnSheetOptions, columnOptions, STRING_COLUMN_NAME, Option, onMount, Layout and preferences so there are no unresolved symbols.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/create.svelte (1)
102-110:⚠️ Potential issue | 🟠 MajorRun the trailing-dot cleanup after truncation.
slice(0, 36)can turn a previously valid string into one that ends with.. For a long name likeaaaa... .b, this helper will auto-generate an ID that violates the backend rule you document above.Suggested fix
return str .toLowerCase() .replace(/[^a-z0-9\-_. ]+/g, '') .replace(/ /g, '_') .replace(/^-+/, '') - .replace(/\.+$/, '') .replace(/_{2,}/g, '_') - .slice(0, 36); + .slice(0, 36) + .replace(/\.+$/, '');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/create.svelte around lines 102 - 110, The toIdFormat function currently slices the sanitized string with .slice(0, 36) before removing trailing dots, which can create IDs ending with '.' — modify to run the trailing-dot cleanup after truncation: in function toIdFormat, keep all existing normalizations but move the .replace(/\.+$/, '') (the trailing-dot removal) to after the .slice(0, 36) call (and optionally re-run the duplicate-underscore collapse replace(/_{2,}/g, '_') after slicing) so that any trailing dots introduced by truncation are removed before returning the final ID.src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (1)
209-227:⚠️ Potential issue | 🔴 CriticalThis toolbar block has malformed Svelte markup that won't compile.
Lines 209–227 mix two separate controls with broken tag nesting. The
<Icon>component opened at line 218 is never closed before</Button>at line 225, and the</Tooltip>at line 228 has no matching opening tag in this block. Additionally, the preference key is set toentityHeaderExpandedhere, but the same toggle usestableHeaderExpandedelsewhere in the file (line 282), so the persisted state will be inconsistent.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte around lines 209 - 227, The toolbar contains malformed Svelte markup and inconsistent preference keys: fix the Button/Icon nesting so the <Button> wraps only its Icon children correctly and ensure every opened component/tag is properly closed (inspect the Button and Icon usages around the on:click handlers and the tooltip fragment), remove the stray unmatched </Tooltip> or add its matching opening tag if a Tooltip is intended, and make the persisted toggle consistent by using the same preference key used elsewhere (replace preferences.setKey('entityHeaderExpanded', $expandTabs) with preferences.setKey('tableHeaderExpanded', $expandTabs) to match the toggle at tableHeaderExpanded); also ensure the import CSV Icon click handler (showImportCSV) and disabled condition (hasColumns && hasValidColumns && !disableButton) remain attached to the correct Icon/Button after re-nesting.
🟡 Minor comments (26)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/icons/CheckCircleDuotone.svelte-1-1 (1)
1-1:⚠️ Potential issue | 🟡 MinorHide this icon from assistive tech.
This component has no way to expose an accessible name, so screen readers will treat it as an unlabeled graphic. If it is purely decorative, mark the root SVG as hidden.
Suggested change
-<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> +<svg + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 20 20" + fill="none" + aria-hidden="true" + focusable="false">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/icons/CheckCircleDuotone.svelte at line 1, The SVG in the CheckCircleDuotone.svelte component is decorative and must be hidden from assistive tech; update the root <svg> element in CheckCircleDuotone.svelte to include aria-hidden="true" (and add focusable="false" for cross-browser behavior) so screen readers ignore the icon; do this in the file where the <svg xmlns="http://www.w3.org/2000/svg" ...> appears (the CheckCircleDuotone component) rather than attempting to provide an accessible name.src/lib/components/id.svelte-99-116 (1)
99-116:⚠️ Potential issue | 🟡 MinorUnused
truncateprop in type definition.The type definition includes
truncate?: boolean;(line 113), but this prop is not destructured from$props()and is never used in the component. ThetruncateTextaction is always applied unconditionally.Either remove
truncatefrom the type definition if it's not needed, or destructure and use it to conditionally apply truncation.Option 1: Remove unused type (if truncation should always apply)
}: { value: string; event?: string | null; tooltipPortal?: boolean; tooltipDelay?: number; tooltipPlacement?: TooltipPlacement; - truncate?: boolean; copyText?: string; children: Snippet; } = $props();Option 2: Implement conditional truncation (if truncate prop is needed)
const { value, event = null, tooltipPortal = false, tooltipDelay = 0, tooltipPlacement, copyText, + truncate = true, children }: {Then in the template, conditionally apply the action:
<span style:white-space="nowrap" style:overflow="hidden" style:word-break="break-all" use:truncateText={truncate ? {} : undefined}>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/components/id.svelte` around lines 99 - 116, The props type declares truncate?: boolean but truncate is not destructured from $props() nor used; either remove truncate from the type annotation (if truncation should always apply) or destructure truncate from $props() and use it to conditionally apply the truncateText action. To implement the latter, add truncate to the destructured props alongside value/event/tooltipPortal/etc. and change the span's action usage (use:truncateText) to only pass the action when truncate is truthy (e.g., use:truncateText={truncate ? {} : undefined}); if you choose removal, delete the truncate?: boolean entry from the inline type.src/lib/helpers/search.ts-59-59 (1)
59-59:⚠️ Potential issue | 🟡 MinorHandle
limit: 0predictably.The truthy check turns
limit = 0into “no limit”, so callers asking for zero suggestions get the full list back instead.🐛 Suggested fix
- return limit && limit > 0 ? result.slice(0, limit) : result; + return limit === undefined ? result : result.slice(0, Math.max(0, limit));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/helpers/search.ts` at line 59, The current truthy check treats limit = 0 as "no limit" and returns the full result; change the conditional to explicitly detect a numeric limit and clamp it to >= 0 so callers requesting zero suggestions get an empty array. Replace the truthy check around limit with an explicit number check (e.g., typeof limit === 'number') and use Math.max(0, limit) when slicing result (referencing the variables limit and result in this file) so negative or zero values behave predictably.src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte-52-57 (1)
52-57:⚠️ Potential issue | 🟡 MinorExplain why the create action is disabled.
When a collection has no fields, the only CTA is disabled with no guidance, so the user is blocked without a next step. Please add copy or a tooltip that tells them to create a column first.
Based on learnings, "In the Appwrite console databases UI, user-facing labels like "Columns" should remain unchanged even when internal terminology changes to "fields"."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte around lines 52 - 57, The CTA is disabled when there are no fields but gives no guidance; update the EmptySheetCards instance (props on the component used where disabled={!data.collection.fields?.length}) to surface a user hint: when disabled, show a tooltip or change the subtitle to "Create a column first" (or similar) and preserve user-facing terminology "Columns" instead of "fields"; ensure the tooltip/subtitle appears only when data.collection.fields is empty and keep the existing title "Create index" and onClick={toggle} unchanged.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sidesheet.svelte-67-67 (1)
67-67:⚠️ Potential issue | 🟡 MinorScope the no-padding override to the sheet body only.
&.noContentPadding :global(section)will hit every descendant<section>inside the side sheet, including sections rendered bychildren. That makesnoContentPaddingstrip spacing from nested content as well, not just the sheet container. Please target the specific Sheet body element instead of all descendant sections.Also applies to: 192-194
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sidesheet.svelte at line 67, The noContentPadding modifier on the sheet container is currently targeting every descendant <section> via the selector like &.noContentPadding :global(section), which strips padding from nested children; update the CSS to scope the override to the sheet body only by changing those selectors to target the sheet body element (e.g., .sheet-body or the more specific .sheet-container > :global(section.sheet-body)) wherever used (including the occurrences around lines 67 and 192-194), so only the sheet's own body loses padding and nested/children sections remain unaffected.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/spreadsheet.svelte-166-190 (1)
166-190:⚠️ Potential issue | 🟡 MinorDon’t mount the mobile
SideSheetwhen there is no editor content.On small viewports this still renders a
SideSheeteven whennoSqlEditorisundefined. IfshowEditorSideSheetflips totrue, users can get an empty “Edit document” sheet, and the:has(.sheet-container:empty)rule will not reliably hide it because the sheet still renders wrapper/header markup.Possible patch
- <div class="no-sql-editor"> - {`#if` !$isSmallViewport} - <div class="no-sql-editor desktop" style:height={spreadsheetHeight}> - {`@render` noSqlEditor?.()} - </div> - {:else} - <SideSheet - noContentPadding - bind:show={showEditorSideSheet} - submit={sideSheetOptions?.submit} - cancel={{ - onClick: () => { - // fires state callback. - showEditorSideSheet = false; - } - }} - title={sideSheetOptions?.sideSheetTitle ?? 'Edit document'}> - {`@render` noSqlEditor?.()} - - {`#snippet` topEndActions()} - {`@render` sideSheetHeaderAction?.()} - {/snippet} - </SideSheet> - {/if} - </div> + {`#if` noSqlEditor} + <div class="no-sql-editor"> + {`#if` !$isSmallViewport} + <div class="no-sql-editor desktop" style:height={spreadsheetHeight}> + {`@render` noSqlEditor?.()} + </div> + {:else} + <SideSheet + noContentPadding + bind:show={showEditorSideSheet} + submit={sideSheetOptions?.submit} + cancel={{ + onClick: () => { + showEditorSideSheet = false; + } + }} + title={sideSheetOptions?.sideSheetTitle ?? 'Edit document'}> + {`@render` noSqlEditor?.()} + + {`#snippet` topEndActions()} + {`@render` sideSheetHeaderAction?.()} + {/snippet} + </SideSheet> + {/if} + </div> + {/if}Also applies to: 221-223
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/spreadsheet.svelte around lines 166 - 190, The SideSheet is being mounted on small viewports even when noSqlEditor is undefined; update the template to only render/mount SideSheet when noSqlEditor is truthy: wrap the SideSheet block with a Svelte {`#if` noSqlEditor} ... {/if} (or change the existing {:else} to {:else if noSqlEditor}) so that SideSheet, its header/actions (sideSheetHeaderAction) and bindings (bind:show={showEditorSideSheet}, submit={sideSheetOptions?.submit}, cancel handler) are only created when the editor content exists; apply the same fix to the duplicate block referenced (lines 221-223).src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/spreadsheet.svelte-149-156 (1)
149-156:⚠️ Potential issue | 🟡 MinorFire
onOpenfor an initially open editor sheet.If this component mounts with
showEditorSideSheet = true,previousShowEditorSideSheetalready matches and the callback never runs. That skipssideSheetStateCallbacks.onOpen()for deep-linked or restored open states.[suggested fix]
Possible patch
- let previousShowEditorSideSheet = showEditorSideSheet; + let previousShowEditorSideSheet: boolean | undefined; $effect(() => { - if (showEditorSideSheet !== previousShowEditorSideSheet) { + if (previousShowEditorSideSheet === undefined) { + if (showEditorSideSheet) { + manageStateCallbacks(true); + } + } else if (showEditorSideSheet !== previousShowEditorSideSheet) { manageStateCallbacks(showEditorSideSheet); - previousShowEditorSideSheet = showEditorSideSheet; } + previousShowEditorSideSheet = showEditorSideSheet; });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/spreadsheet.svelte around lines 149 - 156, The effect never calls manageStateCallbacks when the component mounts with showEditorSideSheet already true because previousShowEditorSideSheet is initialized to the same value; modify mounting logic so that if showEditorSideSheet is true on mount you explicitly invoke manageStateCallbacks(showEditorSideSheet) (which will trigger sideSheetStateCallbacks.onOpen) before/after setting previousShowEditorSideSheet, keeping the existing $effect for subsequent changes; reference: previousShowEditorSideSheet, showEditorSideSheet, $effect, manageStateCallbacks, and sideSheetStateCallbacks.onOpen.src/routes/(console)/project-[region]-[project]/databases/database-[database]/connectModal.svelte-140-143 (1)
140-143:⚠️ Potential issue | 🟡 MinorDisable the copy action when no connection string is available.
The content section already hides the URI input when
database.connectionStringis missing, but this button stays enabled and silently no-ops. Disable or hide it so the footer matches the available data.Possible fix
- <Button secondary on:click={copyConnectionString}> + <Button + secondary + disabled={!database.connectionString} + on:click={copyConnectionString}>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/connectModal.svelte around lines 140 - 143, The "Copy Connection String" Button remains enabled even when database.connectionString is absent; update the footer to either hide the Button or set it disabled when database.connectionString is falsy. Locate the Button element that triggers copyConnectionString and add a conditional render or a disabled prop tied to a check like "database.connectionString" (and ensure copyConnectionString no-ops safely if called). This keeps the UI consistent with the hidden URI input and prevents a silent no-op action.src/routes/(console)/project-[region]-[project]/databases/(assets)/mongo.svelte-11-13 (1)
11-13:⚠️ Potential issue | 🟡 MinorUse a meaningful alt here, or mark the image decorative.
alt="mongo-db artwork"is not a helpful accessible name. If this logo communicates the database type, usealt="MongoDB"; if it is purely decorative, use an empty alt instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/(assets)/mongo.svelte around lines 11 - 13, The img tag using mongoDbImage currently has alt="mongo-db artwork" which is not meaningful; update the alt attribute on that <img> (referencing the mongoDbImage usage in the component) to either a descriptive label like alt="MongoDB" if the logo conveys the database type, or to an empty string alt="" if the image is purely decorative, and ensure any surrounding markup (the div.custom-tag) does not duplicate necessary accessible text.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts-5-15 (1)
5-15:⚠️ Potential issue | 🟡 MinorAlign the type definition with the actual initialization values.
contextandentityare typed as optional (undefinedallowed), but the store initializes both tonull. This creates a type mismatch where the initialized value does not match the declared type. While TypeScript's strict null checks are currently disabled in this project, fixing this improves type safety and prevents issues if strict mode is enabled in the future.Either allow
nullin theEntityColumnSuggestionstype or initialize these fields toundefined.Suggested fix
export type EntityColumnSuggestions = { force: boolean; enabled: boolean; thinking: boolean; - context?: string | undefined; + context?: string | null; /* for safety when in tables page */ - entity?: { - id: string; - name: string; - }; + entity?: + | { + id: string; + name: string; + } + | null; };Also applies to: 43–49
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts around lines 5 - 15, The EntityColumnSuggestions type declares context?: string and entity?: {id:string;name:string}, but the store initialization sets both to null; update the code so the type aligns with initialization by either (A) allowing null in the type (change to context?: string | null and entity?: { id: string; name: string } | null) or (B) change the store initialization to use undefined instead of null for context and entity; apply the same change for the related fields referenced further down (the other EntityColumnSuggestions instance at lines ~43–49).src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte-87-87 (1)
87-87:⚠️ Potential issue | 🟡 MinorGuard against undefined
columnbefore callingisRelationship.The
columnprop is now optional, butisRelationship(column)at line 119 is called without a null check. Ifcolumnis undefined when rendering a header cell, this could cause unexpected behavior depending on howisRelationshiphandles undefined input.🛡️ Proposed fix
// hide sort options for relationship columns - if (isRelationship(column) && ['sort-asc', 'sort-desc'].includes(item?.action)) { + if (column && isRelationship(column) && ['sort-asc', 'sort-desc'].includes(item?.action)) { return false; }Also applies to: 119-121
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte at line 87, Guard against column being undefined before calling isRelationship: update the header cell rendering logic that calls isRelationship(column) so it first checks column (e.g., if (column && isRelationship(column)) { ... } or const isRel = column ? isRelationship(column) : false) and handle the undefined case (skip relationship-specific logic or use a safe fallback). Apply the same guard to the other occurrences noted (lines around 119–121) to avoid calling isRelationship with undefined and to preserve correct rendering when column is optional.src/routes/(console)/project-[region]-[project]/databases/database-[database]/breadcrumbs.svelte-16-18 (1)
16-18:⚠️ Potential issue | 🟡 MinorInconsistent optional chaining on
organization.Line 16 uses
organization?.$idsuggesting it could be undefined, but line 18 accessesorganization.namewithout optional chaining. This inconsistency could cause a runtime error during page transitions whenorganizationis undefined.Based on learnings: In SvelteKit apps, shared layout components that use
$derived(page.data.*)should use optional chaining when accessing properties that may not be present on all routes.🛡️ Proposed fix
{ href: resolveRoute('/(console)/organization-[organization]', { organization: organization?.$id ?? project.teamId }), - title: organization.name + title: organization?.name ?? '' },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/breadcrumbs.svelte around lines 16 - 18, The code uses optional chaining for organization when building the breadcrumb id (organization?.$id) but accesses organization.name directly for title, which will throw if organization is undefined; update the title assignment in the breadcrumbs (the symbol is title and the organization object referenced in that component) to use optional chaining and a safe fallback (e.g., organization?.name ?? an appropriate default) so title never dereferences undefined during route transitions.src/routes/(console)/project-[region]-[project]/databases/database-[database]/settings/updateNetwork.svelte-46-52 (1)
46-52:⚠️ Potential issue | 🟡 MinorAdd type guard for error handling.
The
errorparameter in catch blocks is typed asunknownin TypeScript strict mode. Accessingerror.messagedirectly may cause type errors or runtime issues if the caught value isn't anErrorinstance.🛡️ Proposed fix
} catch (error) { + const message = error instanceof Error ? error.message : 'An error occurred'; addNotification({ - message: error.message, + message, type: 'error' }); trackError(error, Submit.DatabaseUpdateNetwork); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/settings/updateNetwork.svelte around lines 46 - 52, The catch block is using error.message directly though caught values are unknown; update the catch in the try/catch around the network update so it narrows the type (e.g., use a type guard like "error instanceof Error" or an isError helper) and extract a safe message (fallback to String(error) or a default) before calling addNotification and trackError; ensure you still pass the original error value to trackError (trackError(error, Submit.DatabaseUpdateNetwork)) but use the guarded message when calling addNotification.src/routes/(console)/project-[region]-[project]/databases/store.ts-26-43 (1)
26-43:⚠️ Potential issue | 🟡 MinorAdd case for 'shared' database type in
getDatabaseTypeTitle().The
shareddatabase type is actively used throughout the codebase but lacks a case in this switch statement. Without it, shared databases fall through to the default case and display as "TablesDB" instead of their correct title.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/store.ts around lines 26 - 43, The switch in getDatabaseTypeTitle is missing a case for the 'shared' DatabaseType, causing shared DBs to fall through to the default; add a case 'shared' in getDatabaseTypeTitle (same place as the 'dedicated' case) that reads database.engine (fallback to 'postgres'), maps engine to a human name (postgres -> 'PostgreSQL', mysql -> 'MySQL', otherwise engine), and returns `Shared ${engineName}` so shared databases display the correct title.src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.ts-11-15 (1)
11-15:⚠️ Potential issue | 🟡 MinorUse spread operator pattern to match other usage pages.
The collection usage page uses a different return pattern than all other usage pages in the codebase. For consistency, use the spread operator pattern like the database, functions, storage, and auth usage pages.
♻️ Suggested fix
- return sdk.forProject(params.region, params.project).documentsDB.getCollectionUsage({ + return { + ...(await sdk.forProject(params.region, params.project).documentsDB.getCollectionUsage({ databaseId: params.database, collectionId: params.collection, range: period - }); + })) + };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.ts around lines 11 - 15, The return currently calls sdk.forProject(...).documentsDB.getCollectionUsage(...) directly; change it to await the promise and return a new object using the spread operator to match other usage pages. Specifically, call await sdk.forProject(params.region, params.project).documentsDB.getCollectionUsage({ databaseId: params.database, collectionId: params.collection, range: period }) and return { ...result } (using the spread operator on the awaited result) so the page uses the same spread-pattern as the database/functions/storage/auth usage pages.src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/suggestions.svelte-21-29 (1)
21-29:⚠️ Potential issue | 🟡 MinorUse a platform-neutral shortcut hint.
This banner always tells the user to press
⌘ A, so Windows/Linux users get the wrong instruction. Reuse the same platform check as the command center or renderCtrl/Cmd + A.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/suggestions.svelte around lines 21 - 29, The shortcut hint hardcodes "⌘ A" inside the Layout.Stack/Badge block, which is incorrect on non-Mac platforms; update the rendering logic in this component to detect the platform (reuse the same platform check used by the command center or an existing util) and display either "⌘ / A" for macOS or "Ctrl / A" for Windows/Linux (or render a combined "Ctrl/Cmd + A" label) instead of the fixed "⌘" Badge and "A" Badge; modify the badges inside the Layout.Stack (the Badges rendering the modifier and key) to conditionally show the appropriate modifier symbol string so the UI shows platform-neutral or platform-specific shortcut hints.src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/inputs/displayName.svelte-33-35 (1)
33-35:⚠️ Potential issue | 🟡 MinorConfusing function name -
hasChangedreturns inverse of expected value.The
hasChanged()function returnsisDisabled, which istruewhen there are no changes (or too many names). Callers would expecthasChanged()to returntruewhen data has changed.Proposed fix - rename or invert logic
Option 1: Rename to clarify intent:
- export function hasChanged() { - return isDisabled; + export function canSubmit() { + return !isDisabled; }Option 2: Return the actual "has changed" state:
export function hasChanged() { - return isDisabled; + return symmetricDifference(names, getDisplayNames()).length > 0; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/inputs/displayName.svelte around lines 33 - 35, The exported function hasChanged() currently returns isDisabled (which is true when there are no valid changes), so invert its logic or rename it to match intent: either change hasChanged() to return !isDisabled so callers receive true when the data has actually changed, or keep the existing return and rename hasChanged to something like isDisabledOrInvalid to reflect the current behavior; update any callers of hasChanged() if you rename it to avoid breaking references.src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/error-bar.svelte-37-53 (1)
37-53:⚠️ Potential issue | 🟡 MinorPotential positioning issue on mobile viewport.
The media query sets
left: 50%without a correspondingtransform: translateX(-50%), so the element won't be horizontally centered—it will start at the 50% mark. Additionally, the defaulttransform: translateX(60%)is overridden only partially (left/bottom/position change, but no transform reset).Suggested fix to center on mobile
`@media` (max-width: 768px) { left: 50%; bottom: 5%; position: absolute; + transform: translateX(-50%); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/error-bar.svelte around lines 37 - 53, The .floating-action-bar style uses transform: translateX(60%) globally and the mobile media query sets left: 50% without resetting transform, causing mis-centering on small screens; update the mobile rule for .floating-action-bar to reset or override transform (e.g., transform: translateX(-50%)) so the element is horizontally centered when left: 50% is applied, ensuring the media query fully overrides the desktop translateX(60%).src/routes/(console)/project-[region]-[project]/databases/database-[database]/settings/updateExtensions.svelte-104-109 (1)
104-109:⚠️ Potential issue | 🟡 MinorAdd type guard for error handling.
Same issue applies to the uninstall error handler.
🛡️ Proposed fix
} catch (error) { addNotification({ - message: error.message, + message: error instanceof Error ? error.message : 'Failed to uninstall extension', type: 'error' });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/settings/updateExtensions.svelte around lines 104 - 109, The catch block uses error.message directly; add a type guard to handle non-Error throwables by checking if (error instanceof Error) and using error.message, otherwise derive a safe string (e.g., String(error) or a default like 'Unknown error') before calling addNotification and trackError; update the uninstall error handler similarly and ensure trackError still receives the original error object (or the guarded Error) when calling trackError(error, Submit.DatabaseUninstallExtension).src/routes/(console)/project-[region]-[project]/databases/database-[database]/settings/updateSqlApi.svelte-85-91 (1)
85-91:⚠️ Potential issue | 🟡 MinorAdd type guard for error handling.
The
errorin the catch block is typed asunknown. Accessingerror.messagedirectly may fail at runtime if the caught value is not an Error object.🛡️ Proposed fix
} catch (error) { addNotification({ - message: error.message, + message: error instanceof Error ? error.message : 'Failed to update SQL API settings', type: 'error' }); trackError(error, Submit.DatabaseUpdateSqlApi);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/settings/updateSqlApi.svelte around lines 85 - 91, The catch block treats the caught value as an Error but it's typed unknown; update the handler in the try/catch around addNotification and trackError to first type-guard the caught value (use instanceof Error) and extract a safe message (error.message) only for Error instances, otherwise derive a fallback with String(error) or a default message, then pass either the original Error to trackError or create a new Error from the fallback message; ensure you update the references to addNotification, trackError, and Submit.DatabaseUpdateSqlApi accordingly.src/routes/(console)/project-[region]-[project]/databases/database-[database]/settings/updateExtensions.svelte-67-72 (1)
67-72:⚠️ Potential issue | 🟡 MinorAdd type guard for error handling.
Same pattern as other components - accessing
error.messagewithout checking the error type could fail at runtime.🛡️ Proposed fix
} catch (error) { addNotification({ - message: error.message, + message: error instanceof Error ? error.message : 'Failed to install extension', type: 'error' });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/settings/updateExtensions.svelte around lines 67 - 72, The catch block in updateExtensions.svelte accesses error.message directly; add a type guard to ensure the caught value is an Error (or has a message) before using .message, and provide a safe fallback string otherwise. Update the catch handler around the addNotification(...) and trackError(...) calls: check using "if (error instanceof Error)" or "const msg = typeof error === 'object' && error !== null && 'message' in error ? (error as any).message : String(error)" then pass msg to addNotification and still call trackError(error, Submit.DatabaseInstallExtension). Ensure you reference the existing addNotification call, trackError function, and Submit.DatabaseInstallExtension enum/value when making the change.src/routes/(console)/project-[region]-[project]/databases/database-[database]/settings/upgradeVersion.svelte-57-62 (1)
57-62:⚠️ Potential issue | 🟡 MinorAdd type guard for error handling.
Same pattern as other components - accessing
error.messagewithout checking the error type.🛡️ Proposed fix
} catch (error) { addNotification({ - message: error.message, + message: error instanceof Error ? error.message : 'Failed to upgrade database version', type: 'error' }); trackError(error, Submit.DatabaseUpgradeVersion);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/settings/upgradeVersion.svelte around lines 57 - 62, The catch block in upgradeVersion.svelte reads error.message directly; add a type guard to handle non-Error throwables: check if (error instanceof Error) and use error.message, otherwise coerce to a string (e.g., String(error) or a generic message) before calling addNotification and pass the original error to trackError(…, Submit.DatabaseUpgradeVersion) as before; update the catch surrounding symbols error, addNotification, and trackError so the UI shows a safe message for all thrown values.src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte-46-46 (1)
46-46:⚠️ Potential issue | 🟡 MinorRemove debug console.log statement.
This debug statement should be removed before merging to production.
🧹 Proposed fix
async function onSelect(file: Models.File, localFile = false) { $isCollectionsJsonImportInProgress = true; - console.log(file, localFile); - try {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte at line 46, Remove the debug console.log call that prints file and localFile; locate the statement "console.log(file, localFile);" in the page component (+page.svelte) and delete it (or replace with a proper tidy logger call if persistent logging is required) so no debug output remains in production.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte-26-56 (1)
26-56:⚠️ Potential issue | 🟡 MinorAdd error handling to prevent infinite loading state.
If the SDK call fails,
loadingremainstrueindefinitely, leaving the user stuck on the skeleton loader.🛡️ Proposed fix
async function loadRecordLogs(event?: CustomEvent<number>) { loading = true; if (event) { offset = pageToOffset(event.detail, limit); } const { $databaseId: databaseId, entityId, $id: recordId } = toSupportiveRecord(record); - if (terminology.type === 'documentsdb') { - recordActivityLogs = await sdk - .forProject(page.params.region, page.params.project) - .documentsDB.listDocumentLogs({ - databaseId: databaseId, - collectionId: entityId, - documentId: recordId, - queries: [Query.limit(limit), Query.offset(offset)] - }); - } else { - recordActivityLogs = await sdk - .forProject(page.params.region, page.params.project) - .tablesDB.listRowLogs({ - databaseId: databaseId, - tableId: entityId, - rowId: recordId, - queries: [Query.limit(limit), Query.offset(offset)] - }); - } - - loading = false; + try { + if (terminology.type === 'documentsdb') { + recordActivityLogs = await sdk + .forProject(page.params.region, page.params.project) + .documentsDB.listDocumentLogs({ + databaseId: databaseId, + collectionId: entityId, + documentId: recordId, + queries: [Query.limit(limit), Query.offset(offset)] + }); + } else { + recordActivityLogs = await sdk + .forProject(page.params.region, page.params.project) + .tablesDB.listRowLogs({ + databaseId: databaseId, + tableId: entityId, + rowId: recordId, + queries: [Query.limit(limit), Query.offset(offset)] + }); + } + } catch { + recordActivityLogs = null; + } finally { + loading = false; + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte around lines 26 - 56, The loadRecordLogs function can leave loading=true if the SDK call throws; wrap the SDK calls (the branches calling sdk.forProject(...).documentsDB.listDocumentLogs and sdk.forProject(...).tablesDB.listRowLogs) in a try/catch/finally so that loading is set to false in finally, and in catch set recordActivityLogs to an empty array and log the error (console.error or existing logger) to avoid an infinite skeleton state; keep the existing offset logic (pageToOffset(event.detail, limit)) and ensure the destructuring from toSupportiveRecord(record) remains unchanged.src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte-109-115 (1)
109-115:⚠️ Potential issue | 🟡 MinorUse an accessible name that matches the Documentation action.
This button is visibly labeled “Documentation”, but
ariaLabelsayscreate {entityLower.singular}. Screen readers will announce the wrong action here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/+page.svelte around lines 109 - 115, The ariaLabel on the Button inside the slot "actions" is incorrect (it says create {entityLower.singular}) and should match the visible “Documentation” action; update the Button's ariaLabel prop to "Documentation" (or the localized equivalent) so the accessible name aligns with the visible text for the Button component used in this block.src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte-168-170 (1)
168-170:⚠️ Potential issue | 🟡 MinorKeep this warning in "columns" terminology.
This toast is user-facing, so
"fields"should stay internal here; otherwise the table UI mixes two labels for the same concept.Based on learnings, 'In the Appwrite console databases UI, user-facing labels like "Columns" should remain unchanged even when internal terminology changes to "fields".'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte around lines 168 - 170, The toast message uses internal terminology "fields" but should use the user-facing label "Columns"; update the addNotification call that creates the warning (addNotification({... message: 'Cannot create rows: table has no fields' })) to instead use "Columns" in the message (e.g., 'Cannot create rows: table has no columns') so the UI remains consistent with the Appwrite console terminology.
| deleteEntityDetails: async (orgId: string, entityId: string, databaseType?: string) => { | ||
| const dbType = databaseType ?? 'tables'; | ||
| // remove from account preferences | ||
| const removeCustomTableColumns = updateAndSync((n) => { | ||
| n = ensureObjectProperty(n, 'tables'); | ||
| delete n.tables[tableId]; | ||
| n = ensureObjectProperty(n, dbType); | ||
| delete n.tables[entityId]; | ||
| return n; | ||
| }); |
There was a problem hiding this comment.
Bug: Deletion always targets n.tables instead of using dbType.
The dbType variable is computed but then ignored on line 226 where deletion always uses n.tables[entityId]. This breaks the dual-path storage model for non-"tables" database types.
Proposed fix
deleteEntityDetails: async (orgId: string, entityId: string, databaseType?: string) => {
const dbType = databaseType ?? 'tables';
// remove from account preferences
const removeCustomTableColumns = updateAndSync((n) => {
n = ensureObjectProperty(n, dbType);
- delete n.tables[entityId];
+ delete n[dbType][entityId];
return n;
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| deleteEntityDetails: async (orgId: string, entityId: string, databaseType?: string) => { | |
| const dbType = databaseType ?? 'tables'; | |
| // remove from account preferences | |
| const removeCustomTableColumns = updateAndSync((n) => { | |
| n = ensureObjectProperty(n, 'tables'); | |
| delete n.tables[tableId]; | |
| n = ensureObjectProperty(n, dbType); | |
| delete n.tables[entityId]; | |
| return n; | |
| }); | |
| deleteEntityDetails: async (orgId: string, entityId: string, databaseType?: string) => { | |
| const dbType = databaseType ?? 'tables'; | |
| // remove from account preferences | |
| const removeCustomTableColumns = updateAndSync((n) => { | |
| n = ensureObjectProperty(n, dbType); | |
| delete n[dbType][entityId]; | |
| return n; | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/stores/preferences.ts` around lines 221 - 228, In
deleteEntityDetails, the computed dbType is ignored and the code always deletes
from n.tables; update the deletion to target the dynamic property using dbType
(i.e., delete from n[dbType][entityId]) so the removal respects non-"tables"
storage; keep the call to ensureObjectProperty(n, dbType) and use updateAndSync
as is, referencing the function name deleteEntityDetails and variables dbType,
updateAndSync, ensureObjectProperty and n.tables to locate and change the line.
| documentsDB: new DocumentsDB(clientProject), | ||
| dedicatedDatabases: new DedicatedDatabases(clientProject), |
There was a problem hiding this comment.
DocumentsDB is used but not imported—this will cause a runtime error.
Line 26 shows /*DocumentsDB,*/ is still commented out, but line 140 attempts to instantiate new DocumentsDB(clientProject). This will throw a ReferenceError at runtime.
Proposed fix: Uncomment the DocumentsDB import
- /*DocumentsDB,*/
+ DocumentsDB,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/stores/sdk.ts` around lines 140 - 141, The code instantiates
DocumentsDB (new DocumentsDB(clientProject)) but the DocumentsDB symbol is not
imported; restore/uncomment the DocumentsDB import where the other stores are
imported (remove the commented /*DocumentsDB,*/ and ensure the named import
matches the exported class name), then verify the import list also includes
DedicatedDatabases and that clientProject is the correct argument so the runtime
ReferenceError is resolved.
| </ResponsiveContainerHeader> | ||
|
|
||
| {#if data.databases.total} | ||
| {@render containerHeader()} |
There was a problem hiding this comment.
containerHeader is not defined — runtime error.
The {@render containerHeader()} call references a snippet that doesn't exist. This will cause a runtime error when data.databases.total is truthy.
You likely need to define the snippet or import/pass it from elsewhere.
🧰 Tools
🪛 ESLint
[error] 79-79: 'containerHeader' is not defined.
(no-undef)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/routes/`(console)/project-[region]-[project]/databases/+page.svelte at
line 79, The template calls a non-existent Svelte snippet via {`@render`
containerHeader()}, causing a runtime error when data.databases.total is truthy;
fix by either defining a snippet function named containerHeader
(exported/available in this component) or replace the render call with the
correct snippet/import (or pass containerHeader in from the parent) so that
containerHeader() is a defined function/slot before it is invoked; look for the
{`@render` containerHeader()} usage and ensure the symbol containerHeader is
implemented or correctly imported/passed into this component.
| case 'dedicated': { | ||
| // Dedicated databases are created via the compute/databases endpoint | ||
| // with backend: 'appwrite' | ||
| const dedicatedParams = params as DedicatedDatabaseParams; | ||
| return (await baseSdk.dedicatedDatabases.create({ | ||
| databaseId: dedicatedParams.databaseId, | ||
| name: dedicatedParams.name, | ||
| backend: 'appwrite', | ||
| engine: dedicatedParams.engine, | ||
| region: dedicatedParams.region, | ||
| tier: dedicatedParams.tier, | ||
| highAvailability: dedicatedParams.highAvailability, | ||
| backupEnabled: dedicatedParams.backupEnabled, | ||
| backupSchedule: dedicatedParams.backupSchedule, | ||
| backupRetentionDays: dedicatedParams.backupRetentionDays, | ||
| backupPitr: dedicatedParams.backupPitr, | ||
| pitrRetentionDays: dedicatedParams.pitrRetentionDays | ||
| })) as unknown as Models.Database; |
There was a problem hiding this comment.
Pass the dedicated type into this create call.
DedicatedDatabases.create() defaults a missing type to 'shared', so this branch currently provisions the wrong database class. Dedicated-database creation stays broken until this is explicit.
Suggested fix
case 'dedicated': {
// Dedicated databases are created via the compute/databases endpoint
// with backend: 'appwrite'
const dedicatedParams = params as DedicatedDatabaseParams;
return (await baseSdk.dedicatedDatabases.create({
databaseId: dedicatedParams.databaseId,
name: dedicatedParams.name,
backend: 'appwrite',
+ type: 'dedicated',
engine: dedicatedParams.engine,
region: dedicatedParams.region,
tier: dedicatedParams.tier,
highAvailability: dedicatedParams.highAvailability,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case 'dedicated': { | |
| // Dedicated databases are created via the compute/databases endpoint | |
| // with backend: 'appwrite' | |
| const dedicatedParams = params as DedicatedDatabaseParams; | |
| return (await baseSdk.dedicatedDatabases.create({ | |
| databaseId: dedicatedParams.databaseId, | |
| name: dedicatedParams.name, | |
| backend: 'appwrite', | |
| engine: dedicatedParams.engine, | |
| region: dedicatedParams.region, | |
| tier: dedicatedParams.tier, | |
| highAvailability: dedicatedParams.highAvailability, | |
| backupEnabled: dedicatedParams.backupEnabled, | |
| backupSchedule: dedicatedParams.backupSchedule, | |
| backupRetentionDays: dedicatedParams.backupRetentionDays, | |
| backupPitr: dedicatedParams.backupPitr, | |
| pitrRetentionDays: dedicatedParams.pitrRetentionDays | |
| })) as unknown as Models.Database; | |
| case 'dedicated': { | |
| // Dedicated databases are created via the compute/databases endpoint | |
| // with backend: 'appwrite' | |
| const dedicatedParams = params as DedicatedDatabaseParams; | |
| return (await baseSdk.dedicatedDatabases.create({ | |
| databaseId: dedicatedParams.databaseId, | |
| name: dedicatedParams.name, | |
| backend: 'appwrite', | |
| type: 'dedicated', | |
| engine: dedicatedParams.engine, | |
| region: dedicatedParams.region, | |
| tier: dedicatedParams.tier, | |
| highAvailability: dedicatedParams.highAvailability, | |
| backupEnabled: dedicatedParams.backupEnabled, | |
| backupSchedule: dedicatedParams.backupSchedule, | |
| backupRetentionDays: dedicatedParams.backupRetentionDays, | |
| backupPitr: dedicatedParams.backupPitr, | |
| pitrRetentionDays: dedicatedParams.pitrRetentionDays | |
| })) as unknown as Models.Database; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/sdk.ts
around lines 158 - 175, The dedicated branch of the create flow is not passing
the database "type", causing DedicatedDatabases.create to default to 'shared';
update the dedicated branch (case 'dedicated') to include the explicit type
property (e.g., type: 'dedicated') in the object passed to
baseSdk.dedicatedDatabases.create using the DedicatedDatabaseParams values where
appropriate so the created database is the correct dedicated class.
| // Only register table searcher for non-dedicated databases | ||
| if (!isDedicatedType) { | ||
| $registerSearchers(tablesSearcher); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/routes/\(console\)/project-\[region\]-\[project\]/databases/database-\[database\]/+layout.svelte | head -200Repository: appwrite/console
Length of output: 8800
Move the table searcher registration into a reactive statement to ensure isDedicatedType is defined.
The plain if statement at lines 162-165 executes once during component initialization, before the reactive assignment at line 34 has populated isDedicatedType. At that point, isDedicatedType is undefined, making !isDedicatedType evaluate to true, so tablesSearcher gets registered for all database types including dedicated ones. Wrap this in a reactive statement ($: if (!isDedicatedType) { ... }) to defer execution until isDedicatedType is defined.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte
around lines 162 - 165, The table searcher registration runs too early because
isDedicatedType is populated reactively; change the plain if block to a Svelte
reactive statement so it runs after isDedicatedType is set: replace the existing
if (!isDedicatedType) { $registerSearchers(tablesSearcher); } with a reactive
statement using the `$:` label (i.e., `$: if (!isDedicatedType) {
$registerSearchers(tablesSearcher); }`) so registration only happens once
isDedicatedType is defined.
| const params = page.params; | ||
| const project = page.data.project; | ||
| const database = page.data.database; | ||
| const organization = page.data.organization as Organization; |
There was a problem hiding this comment.
Missing import for Organization type.
The ESLint error confirms that Organization is not defined. Since Models is already imported from @appwrite.io/console, use Models.Organization instead.
🐛 Proposed fix
- const organization = page.data.organization as Organization;
+ const organization = page.data.organization as Models.Organization;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const organization = page.data.organization as Organization; | |
| const organization = page.data.organization as Models.Organization; |
🧰 Tools
🪛 ESLint
[error] 11-11: 'Organization' is not defined.
(no-undef)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/breadcrumbs.svelte
at line 11, The type Organization is not imported; change the annotation to use
Models.Organization (i.e., cast page.data.organization as Models.Organization)
and ensure the existing import from '@appwrite.io/console' exposes Models
(update the import if necessary) so the variable declaration const organization
= page.data.organization as Models.Organization compiles without ESLint errors.
| await dedicatedSdk.updatePoolerConfig(database.$id, { | ||
| mode: poolerEnabled ? poolerMode : undefined, | ||
| defaultPoolSize: poolerEnabled ? poolSize : undefined | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for updatePoolerConfig definition in the SDK to verify expected parameters
ast-grep --pattern 'updatePoolerConfig($$$)'
# Also check the dedicatedDatabases SDK file for the method signature
rg -n 'updatePoolerConfig' --type tsRepository: appwrite/console
Length of output: 127
🏁 Script executed:
sed -n '680,720p' src/lib/sdk/dedicatedDatabases.tsRepository: appwrite/console
Length of output: 1421
🏁 Script executed:
# Find filterUndefined definition
rg -n 'filterUndefined' --type ts -A 5 | head -30
# Check if there's a separate enable/disable method or if the pooler API has an enabled field
rg -n 'pooler|Pooler' src/lib/sdk/dedicatedDatabases.ts | head -20Repository: appwrite/console
Length of output: 2425
🏁 Script executed:
sed -n '246,260p' src/lib/sdk/dedicatedDatabases.tsRepository: appwrite/console
Length of output: 369
🏁 Script executed:
rg -n 'Pooler|pooler' src/lib/sdk/dedicatedDatabases.ts | grep -i 'enable\|disable'Repository: appwrite/console
Length of output: 42
updatePoolerConfig API is missing the enabled parameter to disable the pooler.
The PoolerConfig type includes an enabled: boolean field, but updatePoolerConfig only accepts mode, maxConnections, and defaultPoolSize parameters. When poolerEnabled is false, the component cannot send an explicit enabled: false to the backend—only undefined values are sent for mode and defaultPoolSize, which are then filtered out. The API method signature must include the enabled parameter to allow proper disabling of the pooler.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/settings/updatePooler.svelte
around lines 69 - 72, The updatePoolerConfig call is missing the required
enabled flag so the backend can receive enabled: false; update the API method
signature for updatePoolerConfig (on dedicatedSdk) and the PoolerConfig type to
accept an enabled?: boolean (or required boolean) parameter, then pass enabled:
poolerEnabled from the UI call (replace the current object with { enabled:
poolerEnabled, mode: poolerEnabled ? poolerMode : undefined, defaultPoolSize:
poolerEnabled ? poolSize : undefined }) so the backend can explicitly disable
the pooler when poolerEnabled is false.

What does this PR do?
(Provide a description of what this PR does.)
Test Plan
(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)
Related PRs and Issues
(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)
Have you read the Contributing Guidelines on issues?
(Write your answer here.)
Summary by CodeRabbit
Release Notes
New Features
Improvements