Skip to content

Deploy: VectorsDB + DocumentsDB preview#2931

Open
premtsd-code wants to merge 158 commits intomainfrom
feat-vectorsdb-diff-main
Open

Deploy: VectorsDB + DocumentsDB preview#2931
premtsd-code wants to merge 158 commits intomainfrom
feat-vectorsdb-diff-main

Conversation

@premtsd-code
Copy link
Copy Markdown
Contributor

@premtsd-code premtsd-code commented Mar 25, 2026

Preview deployment branch for VectorsDB and DocumentsDB features.

Do not merge — this branch is for deployment and testing only.

Summary by CodeRabbit

  • New Features

    • Added multi-database support with DocumentsDB and VectorsDB collections alongside traditional tables
    • Introduced JSON5 editor for document management with syntax highlighting, linting, and error detection
    • Added collection management including creation, deletion, settings, and permissions
    • Implemented vector embedding modal for text-to-vector conversion
    • Added collection activity logs, usage tracking, and index management
    • Enabled custom column display names for collections
    • Enhanced database creation wizard with type selection UI
    • Added fuzzy search for record attribute discovery
  • Improvements

    • Refactored architecture from table-centric to entity-centric design
    • Consolidated shared state management at database level
    • Enhanced backup policy configuration UI

Resolve conflicts keeping documentsdb renames (entityColumnSuggestions,
DatabasesIndexType, $database path aliases) while incorporating main's
feature flag filters (supportForSpatials, supportForIntegerIds) and
getSupportedColumns helper.
@appwrite
Copy link
Copy Markdown

appwrite bot commented Mar 25, 2026

Console (appwrite/console)

Project ID: 688b7bf400350cbd60e9

Sites (1)
Site Status Logs Preview QR
 console-stage
688b7cf6003b1842c9dc
Ready Ready View Logs Preview URL QR Code

Tip

Environment variable changes require redeployment to take effect

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

Walkthrough

This pull request introduces comprehensive support for multiple database types (TablesDB, DocumentsDB, and VectorsDB) into the console application. The changes include a new JSON5 editor component for NoSQL document management with CodeMirror integration, refactored database abstraction layers to handle multiple entity types uniformly, new collection-scoped routes and layouts, updated type system to support schema-based and non-schema-based databases, and migration of table-specific state to shared entity-level stores. The implementation adds database creation wizards, collection management interfaces, document editing capabilities, and index management alongside existing table functionality.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-vectorsdb-diff-main

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical, Major 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 (4)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/createPolicy.svelte (2)

237-267: ⚠️ Potential issue | 🔴 Critical

Fix the daily preset lookup typo.

getPolicyById('dank') always returns undefined, so toggling this switch will throw when markPolicyChecked reads policy.label.

🩹 Minimal fix
-        {`@const` dailyPolicy = getPolicyById('dank')}
+        {`@const` dailyPolicy = getPolicyById('daily')}
🤖 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 237 - 267, The daily preset lookup uses the wrong id string in
getPolicyById('dank') causing dailyPolicy to be undefined; change the id to the
correct preset id (e.g., getPolicyById('daily') or the actual "daily" preset key
used by your policy definitions) so dailyPolicy is a valid object before calling
markPolicyChecked(event, dailyPolicy) and update any tests or usages that relied
on the old typo; the symbols to change are getPolicyById and the dailyPolicy
variable in createPolicy.svelte where the switch calls markPolicyChecked.

145-165: ⚠️ Potential issue | 🟠 Major

Keep preset ids stable in the reset path.

presetPolicies is a shared store, and the new flow now relies on fixed ids (getPolicyById('daily' | 'none'), filteredPresetPolicies). Replacing every policy.id with ID.unique() here means one visit through the single-policy backups-tab flow can break subsequent renders in the other flows.

🩹 Minimal fix
         if ($currentPlan?.backupPolicies === 1 && isFromBackupsTab) {
             presetPolicies.update((all) =>
                 all.map((policy) => {
-                    policy.id = ID.unique();
-                    policy.checked = policy.label === 'Daily';
+                    policy.checked = policy.id === 'daily';
                     return policy;
                 })
             );
         }
🤖 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 145 - 165, The reactive block that runs when isShowing resets
presetPolicies and currently reassigns policy.id = ID.unique(), which breaks
consumers that expect stable ids (e.g., getPolicyById('daily' | 'none') and
filteredPresetPolicies); update the presetPolicies map inside the isShowing
branch to only modify policy.checked (and any other non-id fields) without
changing policy.id so existing stable ids remain intact, and remove the
ID.unique() assignment from that update path; locate the reactive block around
isShowing, the resetFormVariables() call, and the presetPolicies.update(...)
where policy.id is set and delete or stop changing the id there.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/indexes.svelte (1)

239-247: ⚠️ Potential issue | 🟡 Minor

Improve type safety of SuggestedIndexSchema.type to prevent unsafe cast.

The type property in SuggestedIndexSchema is defined as string (line 37 in store.ts), but it's populated exclusively with DatabasesIndexType enum values. The cast to TablesDBIndexType at line 243 masks this mismatch. While the cast appears safe in the current data flow (suggestions API returns DatabasesIndexType values), this creates a maintenance risk if enum definitions diverge.

Change SuggestedIndexSchema.type from string to DatabasesIndexType to enforce type correctness at the source. This eliminates the unsafe cast and clarifies that indexes come from the suggestions engine which uses the older DatabasesIndexType.

🤖 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)/indexes.svelte
around lines 239 - 247, Update the SuggestedIndexSchema.type declaration from
string to DatabasesIndexType in store.ts so the schema accurately reflects the
enum values produced by the suggestions engine; then remove the unsafe cast at
the createIndex call (where index.type is cast to TablesDBIndexType) and pass
the typed value directly or map explicitly if needed, ensuring any code using
SuggestedIndexSchema (e.g., the createIndex invocation in indexes.svelte)
compiles without a string-to-enum cast and preserves type safety between
DatabasesIndexType and TablesDBIndexType.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/create.svelte (1)

1-9: ⚠️ Potential issue | 🟠 Major

Change type field in CreateIndexesCallbackType from string to DatabasesIndexType.

The exported callback type currently declares type: string, but the component passes a DatabasesIndexType enum value. This type mismatch forces consumers to cast the value (e.g., as TablesDBIndexType). Instead, use the enum type directly to maintain type safety and eliminate casting:

export type CreateIndexesCallbackType = {
    key: string;
    type: DatabasesIndexType;
    fields: string[];
    lengths: (number | null)[];
    orders: OrderBy[];
};
🤖 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/indexes/create.svelte
around lines 1 - 9, Update the CreateIndexesCallbackType so its `type` property
uses the DatabasesIndexType enum instead of a plain string: locate the exported
type alias CreateIndexesCallbackType in the file and change the `type: string`
declaration to `type: DatabasesIndexType` (ensure DatabasesIndexType is imported
at the top as it already is); this preserves type-safety and removes the need
for downstream casts when passing enum values.
🟡 Minor comments (14)
src/routes/(console)/(migration-wizard)/wizard.svelte-84-84 (1)

84-84: ⚠️ Potential issue | 🟡 Minor

Align fallback project name capitalization with the rest of this PR.

Line 84 uses "New project", while other updated defaults in this PR use "New Project", causing minor UI copy inconsistency.

💡 Suggested fix
-        return isExisting ? currentSelectedProject.name : newProjName || 'New project';
+        return isExisting ? currentSelectedProject.name : newProjName || 'New Project';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(console)/(migration-wizard)/wizard.svelte at line 84, The
fallback default string in the return expression "return isExisting ?
currentSelectedProject.name : newProjName || 'New project';" is capitalized
inconsistently; change the literal 'New project' to 'New Project' so the
ternary/OR expression uses the same capitalization as other defaults in this PR
(update the string in the expression inside wizard.svelte).
src/routes/(console)/project-[region]-[project]/databases/database-[database]/breadcrumbs.svelte-11-18 (1)

11-18: ⚠️ Potential issue | 🟡 Minor

Inconsistent optional chaining may cause runtime error during navigation.

Line 16 uses organization?.$id (defensive), but line 18 accesses organization.name directly. During page transitions, page.data.organization can briefly be undefined, causing a runtime error.

🛡️ Proposed fix
             {
                 href: resolveRoute('/(console)/organization-[organization]', {
                     organization: organization?.$id ?? project.teamId
                 }),
-                title: organization.name
+                title: organization?.name ?? ''
             },

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. During page transitions, reactive statements can briefly evaluate with different page.data structures."

🤖 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 11 - 18, The breadcrumb component accesses page.data.organization
inconsistently: it uses organization?.$id defensively but reads
organization.name directly, which can throw if organization is undefined during
transitions; update the title (and any other direct property reads) to use
optional chaining and a safe fallback (e.g., organization?.name ?? '') so
resolveRoute and the breadcrumb array always handle a missing organization;
locate the variable organization and the object literal returned in the
breadcrumbs array to apply the change.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts-43-49 (1)

43-49: ⚠️ Potential issue | 🟡 Minor

Type inconsistency: context initialized as null but typed as string | undefined.

Line 9 declares context?: string | undefined but line 45 initializes it as null. Similarly, line 47 initializes entity as null but the type (line 12-15) uses optional field syntax without null.

🔧 Suggested fix
 export const entityColumnSuggestions = writable<EntityColumnSuggestions>({
     enabled: false,
-    context: null,
+    context: undefined,
     thinking: false,
-    entity: null,
+    entity: undefined,
     force: 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]/(suggestions)/store.ts
around lines 43 - 49, The EntityColumnSuggestions initial state uses null for
context and entity but the type definition for EntityColumnSuggestions declares
context?: string | undefined and entity as optional (no null); update either the
type or the initial value to match: change the initial store value in
entityColumnSuggestions to use undefined (omit context/entity or set them to
undefined) or modify the EntityColumnSuggestions type to allow null (e.g.,
context: string | undefined | null and entity: <type> | null) so the declared
types and the initial values are consistent.
src/lib/elements/forms/inputTags.svelte-31-47 (1)

31-47: ⚠️ Potential issue | 🟡 Minor

Potential error state conflict between reactive blocks.

The reactive block at lines 43-47 unconditionally sets error = null when tags.length <= max, which will clear errors set by handleInvalid (e.g., "This field is required"). This could hide validation errors when the user hasn't exceeded the max limit.

Consider preserving the existing error state when max validation passes:

🐛 Proposed fix
 $: if (max !== undefined && tags.length > max) {
     error = `Maximum ${max} fields allowed`;
-} else if (max === undefined || tags.length <= max) {
-    error = null;
+} else if (error === `Maximum ${max} fields allowed`) {
+    // Only clear the max-related error, preserve other validation errors
+    error = null;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/elements/forms/inputTags.svelte` around lines 31 - 47, The
max-validation reactive block currently unconditionally clears error when
tags.length <= max, wiping out other validation messages from handleInvalid;
change that block to only clear the max-related error (e.g., compare error to
the max message `Maximum ${max} fields allowed` or use a dedicated constant like
MAX_ERROR_MSG) and leave any other existing error untouched, so modify the
reactive block that references max, tags and error to only set error = null when
the current error equals the max error message (or clear/set a separate maxError
flag) and otherwise preserve error set by handleInvalid.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte-27-60 (1)

27-60: ⚠️ Potential issue | 🟡 Minor

Add error handling to prevent indefinite loading state.

If listDocumentLogs or listRowLogs throws an error, loading remains true and the user sees a perpetual skeleton. Wrap the API calls in try/catch and ensure loading is set to false in a finally block.

🛡️ 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);

+        try {
             if (terminology.type === 'documentsdb' || terminology.type === 'vectorsdb') {
                 const collectionService = getCollectionService(
                     page.params.region,
                     page.params.project,
                     terminology.type
                 );
                 recordActivityLogs = await collectionService.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 (error) {
+            recordActivityLogs = null;
+        } finally {
+            loading = false;
+        }
-
-        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 27 - 60, The loadRecordLogs function can leave loading true if
listDocumentLogs or listRowLogs throws; wrap the API invocation block in
try/catch/finally (around the calls that assign recordActivityLogs) so any
thrown error is caught (log or surface it via console/processLogger) and ensure
loading = false in the finally block; in the catch set recordActivityLogs to an
empty array or a safe fallback and preserve existing offset behavior — locate
the logic inside loadRecordLogs where listDocumentLogs and tablesDB.listRowLogs
are called and add the try/catch/finally around those calls.
src/routes/(console)/project-[region]-[project]/databases/create/+page.svelte-39-40 (1)

39-40: ⚠️ Potential issue | 🟡 Minor

Validate type query parameter against allowed values.

The type query param is cast to DatabaseType without validation. If a user navigates with an invalid ?type=invalid, the UI may behave unexpectedly or show an invalid database type card selected.

🛡️ Proposed fix
+    const validTypes: DatabaseType[] = ['tablesdb', 'documentsdb', 'vectorsdb'];
     const typeFromParams = page.url.searchParams.get('type') ?? (null as DatabaseType);
-    let type = $state(typeFromParams ?? 'tablesdb') as DatabaseType;
+    let type = $state<DatabaseType>(
+        validTypes.includes(typeFromParams as DatabaseType) 
+            ? (typeFromParams as DatabaseType) 
+            : 'tablesdb'
+    );
🤖 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/create/+page.svelte
around lines 39 - 40, The code currently casts page.url.searchParams.get('type')
to DatabaseType without validation; update the logic around typeFromParams and
type to validate the query value against the allowed DatabaseType values (e.g.,
the set of enum/string variants used elsewhere) and only use it if it matches;
otherwise fall back to the safe default ('tablesdb'). Locate the symbols
typeFromParams and type (and any DatabaseType enum/union) and implement a check
(e.g., allowedValues.includes(typeFromParams)) before assigning/casting,
ensuring invalid values do not become the selected type.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/inputs/displayName.svelte-15-15 (1)

15-15: ⚠️ Potential issue | 🟡 Minor

Unused prop declaration.

The inModal prop is declared in the type definition but not destructured in the props binding, making it inaccessible.

Proposed fix

Either remove from type if unused:

     }: {
         collectionId: string;
         databaseType: string;
-        inModal?: boolean;
         onSuccess?: () => Promise<void> | void;

Or add to destructuring if needed:

     let {
         collectionId,
         databaseType,
+        inModal = false,
         onSuccess = null,
🤖 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
at line 15, The type declares an optional prop named inModal but it’s never
destructured so the component cannot access it; either remove inModal from the
props type if it’s unused, or add it to the component’s props binding
(destructure/export it where other props are defined) so the displayName.svelte
component can read inModal (e.g., include inModal alongside the existing
destructured props or add export let inModal:boolean|undefined).
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/editPermissions.svelte-51-51 (1)

51-51: ⚠️ Potential issue | 🟡 Minor

Typo: "make suer" → "make sure".

-            // TODO: `@itznotabug`, make suer this doesn't trigger or lose spreadsheet scroll state!
+            // TODO: `@itznotabug`, make sure this doesn't trigger or lose spreadsheet scroll state!
🤖 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/editPermissions.svelte
at line 51, Fix the typo in the TODO comment in editPermissions.svelte: change
"make suer" to "make sure" in the existing comment "// TODO: `@itznotabug`, make
suer this doesn't trigger or lose spreadsheet scroll state!" so the comment
reads "// TODO: `@itznotabug`, make sure this doesn't trigger or lose spreadsheet
scroll state!" to improve readability and correctness.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/editPermissions.svelte-60-65 (1)

60-65: ⚠️ Potential issue | 🟡 Minor

Type-check the caught error before accessing .message.

The error in the catch block is of type unknown. Accessing .message directly may fail if the error is not an Error instance.

🛡️ Proposed fix
         } catch (error) {
+            const message = error instanceof Error ? error.message : String(error);
             addNotification({
-                message: error.message,
+                message,
                 type: 'error'
             });
             trackError(error, analytics.submit.record('UpdatePermissions'));
🤖 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/editPermissions.svelte
around lines 60 - 65, The catch block assumes `error` has a `.message` property;
since `error` is `unknown` you should type-check it before accessing `.message`
— update the `catch (error)` handling in the `editPermissions.svelte` code to
first check `if (error instanceof Error)` and use `error.message` for
`addNotification` and pass the `Error` to `trackError`; otherwise convert the
unknown to a string (e.g., `String(error)` or a fallback message) for
`addNotification` and call `trackError` with a safe wrapper or metadata so code
using `analytics.submit.record('UpdatePermissions')` and `trackError(error,
...)` always receives a valid value.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/editPermissions.svelte-25-25 (1)

25-25: ⚠️ Potential issue | 🟡 Minor

Permissions state won't update if record prop changes.

The permissions state is initialized once from record.$permissions but won't react if the record prop changes. If this component is reused with different records without remounting, stale permissions will be displayed.

🔧 Proposed fix using $derived or $effect

If the component should react to record changes:

-    let permissions = $state(record.$permissions);
+    let permissions = $state<string[]>([]);
+
+    $effect(() => {
+        permissions = [...record.$permissions];
+    });

Alternatively, if the component is always remounted when record changes, this can be left as-is but should be documented.

🤖 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/editPermissions.svelte
at line 25, The permissions variable is initialized once from
record.$permissions (let permissions = $state(record.$permissions)) and will not
update when the record prop changes; change this to a reactive binding so
permissions tracks record updates — e.g. replace the one-time init with a
reactive statement or derived/effect that reassigns permissions when record or
record.$permissions changes (reference variables: permissions, record,
record.$permissions, $state) so the component shows fresh permissions whenever
record changes.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte-48-48 (1)

48-48: ⚠️ Potential issue | 🟡 Minor

Type annotation mismatch.

columnsError is typed as string but initialized to null. Use string | null for correctness.

✏️ Proposed fix
-    let columnsError: string = $state(null);
+    let columnsError: string | null = $state(null);
🤖 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 48, columnsError is declared as string but initialized with null; update
its type to allow null by changing the annotation on columnsError to string |
null so the initialization with $state(null) is type-correct (i.e., modify the
declaration of columnsError to use string | null while keeping the $state(null)
initializer).
src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/spreadsheet.svelte-71-73 (1)

71-73: ⚠️ Potential issue | 🟡 Minor

Remove debug console.log statement.

This console.log appears to be a debug artifact that should be removed before merging.

🧹 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]/spreadsheet.svelte
around lines 71 - 73, Remove the stray debug console.log statement from this
Svelte route component (search for any console.log in the file, e.g., near the
export let data: PageData declaration or inside onMount/ lifecycle code) —
delete the console.log line(s) entirely (do not leave commented-out logs) and
run the build/linter to confirm no unused variables or warnings remain.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/store.ts-9-9 (1)

9-9: ⚠️ Potential issue | 🟡 Minor

Potential runtime error if collection.indexes is undefined.

The derived store directly accesses $page.data.collection.indexes without defensive checks. If collection or indexes is undefined during navigation, this could throw.

🛡️ Add defensive access
-export const indexes = derived(page, ($page) => $page.data.collection.indexes as Models.Index[]);
+export const indexes = derived(page, ($page) => ($page.data.collection?.indexes ?? []) as Models.Index[]);
🤖 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]/store.ts
at line 9, The derived store exported as indexes currently dereferences
$page.data.collection.indexes directly which can throw if collection or indexes
is undefined; change the derived callback in the indexes export to defensively
access the path (use optional chaining on $page.data.collection?.indexes and
default to an empty array) and still cast to Models.Index[] so the store always
yields a safe array even during navigation or loading.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/view.svelte-1536-1543 (1)

1536-1543: ⚠️ Potential issue | 🟡 Minor

Mutating a prop directly may cause unexpected behavior.

Line 1541 assigns showSuggestions = false, but showSuggestions is a prop. In Svelte 5, props are not bindable by default, so this mutation won't propagate to the parent. If this is intentional local state, consider using a separate state variable.

🔧 Use local state instead of mutating prop
+    let localShowSuggestions = $state(showSuggestions);
+
+    // Sync with prop changes
+    $effect(() => {
+        localShowSuggestions = showSuggestions;
+    });

// Then in the template:
-    {`#if` ($isSmallViewport && showSuggestions) || (showSuggestions && hasStartedEditing)}
+    {`#if` ($isSmallViewport && localShowSuggestions) || (localShowSuggestions && hasStartedEditing)}
         <Suggestions
-            show={showSuggestions}
+            show={localShowSuggestions}
             showMock={showMockSuggestions}
             onMobileClick={() => {
-                showSuggestions = false;
+                localShowSuggestions = false;
                 applySuggestedAttributes();
             }} />
🤖 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)/editor/view.svelte
around lines 1536 - 1543, The code currently mutates the prop showSuggestions
inside the Suggestions onMobileClick handler (showSuggestions = false), which
won't propagate in Svelte 5; instead create local state or emit an event: either
introduce a local boolean (e.g., isSuggestionsVisible) initialized from the prop
showSuggestions and use that in the {`#if` ...} and set isSuggestionsVisible =
false in the onMobileClick before calling applySuggestedAttributes(), or use
createEventDispatcher in this component to dispatch a "closeSuggestions" (or
similar) event from the Suggestions onMobileClick handler so the parent can
update its showSuggestions prop; update references to showSuggestions in this
file (the {`#if` ...} and the Suggestions show= prop) to use the chosen local
variable or to rely on the dispatched event accordingly and keep
applySuggestedAttributes() call intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07a98a7d-f426-4cb6-9729-5219f9cbc9a9

📥 Commits

Reviewing files that changed from the base of the PR and between 5251384 and fecbdaf.

⛔ Files ignored due to path filters (14)
  • bun.lock is excluded by !**/*.lock
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/dark/documents-db.svg is excluded by !**/*.svg
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/dark/mongo-db.svg is excluded by !**/*.svg
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/dark/tables-db.svg is excluded by !**/*.svg
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/dark/vectors-db.svg is excluded by !**/*.svg
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/documents-db.svg is excluded by !**/*.svg
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/tables-db.svg is excluded by !**/*.svg
  • src/routes/(console)/project-[region]-[project]/databases/(assets)/vectors-db.svg is excluded by !**/*.svg
  • static/images/databases/empty-documentsdb-dark.svg is excluded by !**/*.svg
  • static/images/databases/empty-documentsdb-light.svg is excluded by !**/*.svg
  • static/images/databases/empty-tablesdb-dark.svg is excluded by !**/*.svg
  • static/images/databases/empty-tablesdb-light.svg is excluded by !**/*.svg
  • static/images/databases/empty-vectorsdb-dark.svg is excluded by !**/*.svg
  • static/images/databases/empty-vectorsdb-light.svg is excluded by !**/*.svg
📒 Files selected for processing (148)
  • bugs.md
  • eslint.config.js
  • package.json
  • src/lib/actions/analytics.ts
  • src/lib/commandCenter/commands.ts
  • src/lib/components/columnSelector.svelte
  • src/lib/components/csvImportBox.svelte
  • src/lib/components/customId.svelte
  • src/lib/components/filters/content.svelte
  • src/lib/components/filters/filters.svelte
  • src/lib/components/id.svelte
  • src/lib/components/modal.svelte
  • src/lib/components/sortButton.svelte
  • src/lib/components/viewSelector.svelte
  • src/lib/constants.ts
  • src/lib/elements/forms/Seekbar.svelte
  • src/lib/elements/forms/inputId.svelte
  • src/lib/elements/forms/inputProjectId.svelte
  • src/lib/elements/forms/inputTags.svelte
  • src/lib/helpers/faker.ts
  • src/lib/helpers/object.ts
  • src/lib/helpers/search.ts
  • src/lib/helpers/types.ts
  • src/lib/helpers/unsavedChanges.ts
  • src/lib/layout/footer.svelte
  • src/lib/layout/progress.svelte
  • src/lib/stores/migration.ts
  • src/lib/stores/navigation.ts
  • src/lib/stores/preferences.ts
  • src/lib/stores/sdk.ts
  • src/lib/stores/viewport.ts
  • src/routes/(console)/(migration-wizard)/resource-form.svelte
  • src/routes/(console)/(migration-wizard)/wizard.svelte
  • src/routes/(console)/onboarding/create-project/+page.svelte
  • src/routes/(console)/organization-[organization]/change-plan/+page.svelte
  • src/routes/(console)/project-[region]-[project]/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/auth/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/auth/user-[user]/deleteUser.svelte
  • src/routes/(console)/project-[region]-[project]/databases/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/databases/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/create.svelte
  • src/routes/(console)/project-[region]-[project]/databases/create/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/create/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/index.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/init.svelte.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/navigation.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/sdk.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/types.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/create.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/editPermissions.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/index.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/header.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/create.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/view.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/index.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sidesheet.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/spreadsheet.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/settings/danger.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(observer)/columnObserver.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/indexes.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/[...rest]/+page.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/createPolicy.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/breadcrumbs.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/embeddingModal.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/extensions/duplicates.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/extensions/highlighting.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/extensions/hover.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/extensions/index.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/extensions/readonly.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/helpers/constants.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/helpers/errorMessages.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/helpers/keymaps.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/helpers/theme.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/index.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/view.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/inputs/displayName.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/error.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/icons/CheckCircleDuotone.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/index.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/save.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/suggestions.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/header.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/settings/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/settings/displayName.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/spreadsheet.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/settings/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/createColumnDropdown.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/deleteColumn.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/edit.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/cell/edit.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/columnForm.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/columnItem.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/create.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table.svelte
  • src/routes/(console)/project-[region]-[project]/databases/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/grid.svelte
  • src/routes/(console)/project-[region]-[project]/databases/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/table.svelte
  • src/routes/(console)/project-[region]-[project]/functions/+page.svelte
  • src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.svelte
  • src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/executeFunction.svelte
  • src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte
  • src/routes/(console)/project-[region]-[project]/settings/+page.svelte
  • src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/wizard.svelte
  • src/routes/(console)/project-[region]-[project]/settings/updateLabels.svelte
  • src/routes/(console)/project-[region]-[project]/updateVariables.svelte
  • src/routes/(console)/verify-email/+page.svelte
  • src/themes/dark-cloud.json
  • src/themes/dark.json
  • src/themes/light-cloud.json
  • src/themes/light.json
💤 Files with no reviewable changes (1)
  • src/routes/(console)/project-[region]-[project]/databases/create.svelte

Comment on lines +220 to 231
// `databaseType` fallback for legacy cases.
deleteEntityDetails: async (
orgId: string,
entityId: string,
databaseType: string = 'tables'
) => {
// remove from account preferences
const removeCustomTableColumns = updateAndSync((n) => {
n = ensureObjectProperty(n, 'tables');
delete n.tables[tableId];
n = ensureObjectProperty(n, databaseType);
delete n.tables[entityId];
return n;
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bug: databaseType parameter ignored when deleting from tables.

The deleteEntityDetails function accepts a databaseType parameter but hardcodes 'tables' on line 229 when deleting custom table columns. This means collections/vectors entities won't be properly cleaned up.

🐛 Proposed fix
             // remove from account preferences
             const removeCustomTableColumns = updateAndSync((n) => {
                 n = ensureObjectProperty(n, databaseType);
-                delete n.tables[entityId];
+                delete n[databaseType][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.

Suggested change
// `databaseType` fallback for legacy cases.
deleteEntityDetails: async (
orgId: string,
entityId: string,
databaseType: string = 'tables'
) => {
// remove from account preferences
const removeCustomTableColumns = updateAndSync((n) => {
n = ensureObjectProperty(n, 'tables');
delete n.tables[tableId];
n = ensureObjectProperty(n, databaseType);
delete n.tables[entityId];
return n;
});
// `databaseType` fallback for legacy cases.
deleteEntityDetails: async (
orgId: string,
entityId: string,
databaseType: string = 'tables'
) => {
// remove from account preferences
const removeCustomTableColumns = updateAndSync((n) => {
n = ensureObjectProperty(n, databaseType);
delete n[databaseType][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 220 - 231, In
deleteEntityDetails, the databaseType parameter is ignored because the code
deletes from the hardcoded n.tables; change the logic to use the databaseType
variable throughout: call ensureObjectProperty(n, databaseType) and delete the
entity via delete n[databaseType][entityId] (instead of delete
n.tables[entityId]) so collections/vectors are cleaned up; update any related
closure (removeCustomTableColumns) name or comments if needed to reflect the
generic databaseType usage.

Comment on lines +77 to +89
<EmptyDatabaseCloud
disabled={$canWriteDatabases}
onDatabaseTypeSelected={async (type) => {
await goto(
withPath(
resolveRoute(
'/(console)/project-[region]-[project]/databases/create',
page.params
),
`?type=${type}`
)
);
}} />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inverted disabled prop logic.

The disabled prop is set to $canWriteDatabases, which is true when the user can write. This would disable the component when the user has permissions, which is the opposite of intended behavior.

Proposed fix
         <EmptyDatabaseCloud
-            disabled={$canWriteDatabases}
+            disabled={!$canWriteDatabases}
             onDatabaseTypeSelected={async (type) => {
🤖 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 77 - 89, The EmptyDatabaseCloud component is being disabled
incorrectly because the disabled prop is bound to $canWriteDatabases (true when
the user can write); invert this logic so the component is disabled only when
the user cannot write. Update the disabled prop on EmptyDatabaseCloud to use the
negation of $canWriteDatabases (i.e., disabled={!$canWriteDatabases}) while
leaving the onDatabaseTypeSelected handler (the async function calling goto with
withPath(resolveRoute(...), `?type=${type}`)) unchanged.

Comment on lines +183 to +206
let selectedPolicyGroup: null | string = null;
$: if (selectedPolicyGroup) {
if (selectedPolicyGroup === 'custom') {
if (listOfCustomPolicies.length === 0) {
showCustomPolicy = true;
}

presetPolicies.update((policies) => {
return policies.map((policy) => ({
...policy,
checked: false
}));
});
} else if (selectedPolicyGroup !== 'custom') {
listOfCustomPolicies = [];
showCustomPolicy = false;

presetPolicies.update((policies) => {
return policies.map((policy) => ({
...policy,
checked: selectedPolicyGroup !== 'none' && policy.id === selectedPolicyGroup
}));
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Leaving custom should also clear the edit session.

If a user starts editing a custom policy and then clicks daily or none, this block clears listOfCustomPolicies but leaves policyInEdit and policyBeingEdited alive. The editor stays open, and Save/Cancel can re-add the custom policy alongside the preset, so the supposedly exclusive selector ends up submitting both.

🩹 Minimal fix
         } else if (selectedPolicyGroup !== 'custom') {
             listOfCustomPolicies = [];
             showCustomPolicy = false;
+            policyInEdit = null;
+            policyBeingEdited = null;
 
             presetPolicies.update((policies) => {
                 return policies.map((policy) => ({
📝 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.

Suggested change
let selectedPolicyGroup: null | string = null;
$: if (selectedPolicyGroup) {
if (selectedPolicyGroup === 'custom') {
if (listOfCustomPolicies.length === 0) {
showCustomPolicy = true;
}
presetPolicies.update((policies) => {
return policies.map((policy) => ({
...policy,
checked: false
}));
});
} else if (selectedPolicyGroup !== 'custom') {
listOfCustomPolicies = [];
showCustomPolicy = false;
presetPolicies.update((policies) => {
return policies.map((policy) => ({
...policy,
checked: selectedPolicyGroup !== 'none' && policy.id === selectedPolicyGroup
}));
});
}
let selectedPolicyGroup: null | string = null;
$: if (selectedPolicyGroup) {
if (selectedPolicyGroup === 'custom') {
if (listOfCustomPolicies.length === 0) {
showCustomPolicy = true;
}
presetPolicies.update((policies) => {
return policies.map((policy) => ({
...policy,
checked: false
}));
});
} else if (selectedPolicyGroup !== 'custom') {
listOfCustomPolicies = [];
showCustomPolicy = false;
policyInEdit = null;
policyBeingEdited = null;
presetPolicies.update((policies) => {
return policies.map((policy) => ({
...policy,
checked: selectedPolicyGroup !== 'none' && policy.id === selectedPolicyGroup
}));
});
}
🤖 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 183 - 206, When selectedPolicyGroup changes away from 'custom' you
need to fully clear the custom editing session; in the branch where
selectedPolicyGroup !== 'custom' (the same block that sets listOfCustomPolicies
= [] and showCustomPolicy = false and updates presetPolicies) also reset the
editor state by clearing policyInEdit and policyBeingEdited (set them to
null/false as used in this file) so the custom editor closes and no pending edit
can re-add a custom policy.

Comment on lines +302 to +313
{@const none = getPolicyById('none')}
{@const dailPreset = getPolicyById('daily')}
<Card.Selector
variant="secondary"
imageRadius="s"
id={dailPreset.id}
name={dailPreset.id}
value={dailPreset.id}
title="Backup every 24 hours"
bind:group={selectedPolicyGroup}>
One backup every 24 hours, retained for 30 days
</Card.Selector>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The card copy does not match the preset being submitted.

This selector binds the daily preset, but the description says it is retained for 30 days while presetPolicies defines that preset as 7 days. Users will choose a 7-day policy after reading 30-day copy.

🤖 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 302 - 313, The Card.Selector for the daily preset (dailPreset from
getPolicyById('daily')) has copy saying "retained for 30 days" which conflicts
with the actual presetPolicies retention (7 days); update the selector text to
match the actual preset retention (e.g., "One backup every 24 hours, retained
for 7 days") or, if the intent was 30 days, change the bound preset id from
'daily' to the correct preset id that has 30-day retention—ensure the
description in the Card.Selector and the preset referenced by
getPolicyById('daily') stay consistent.

Comment on lines +15 to +21
let {
state = null,
onUndo = null
}: {
state: 'saving' | 'saved' | null;
onUndo?: () => Promise<void> | void;
} = $props();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

state prop should be $bindable() if mutated internally.

The component mutates state on line 29, but state is not declared with $bindable(). In Svelte 5, props are readonly by default. This will cause a runtime error when the effect tries to set state = null.

🔧 Proposed fix
     let {
-        state = null,
+        state = $bindable(null),
         onUndo = null
     }: {
         state: 'saving' | 'saved' | null;
         onUndo?: () => Promise<void> | void;
     } = $props();
📝 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.

Suggested change
let {
state = null,
onUndo = null
}: {
state: 'saving' | 'saved' | null;
onUndo?: () => Promise<void> | void;
} = $props();
let {
state = $bindable(null),
onUndo = null
}: {
state: 'saving' | 'saved' | null;
onUndo?: () => Promise<void> | void;
} = $props();
🤖 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/save.svelte
around lines 15 - 21, The prop "state" is mutated internally (see assignment to
state in the save component), so change its declaration to use Svelte 5 binding
by making state $bindable() in the props destructure; update the existing let {
state = null, onUndo = null } ... = $props() to wrap the initial value with
$bindable (so the component can assign to state), keeping the same type union
'saving' | 'saved' | null and leaving onUndo unchanged.

Comment on lines +11 to +18
export function buildInitDoc() {
const now = new Date().toISOString();
return {
$id: ID.unique(),
$createdAt: toLocaleDateTime(now),
$updatedAt: toLocaleDateTime(now)
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how toLocaleDateTime is used and what format it returns
rg -n "toLocaleDateTime" --type ts -A 2 -B 2 | head -40

Repository: appwrite/console

Length of output: 2185


🏁 Script executed:

# Get the implementation of toLocaleDateTime
cat -n src/lib/helpers/date.ts | sed -n '38,60p'

Repository: appwrite/console

Length of output: 825


🏁 Script executed:

# Get the test cases to understand expected behavior
cat -n src/lib/helpers/date.test.ts | sed -n '1,50p'

Repository: appwrite/console

Length of output: 1730


🏁 Script executed:

# Check the full buildInitDoc function context in the target file
cat -n "src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.svelte" | sed -n '1,30p'

Repository: appwrite/console

Length of output: 1384


🏁 Script executed:

# Find where buildInitDoc is called
rg -n "buildInitDoc" --type ts --type svelte -B 3 -A 5

Repository: appwrite/console

Length of output: 90


🏁 Script executed:

# Also check what $createdAt and $updatedAt should be in Appwrite
rg -n "\$createdAt|\$updatedAt" --type ts --type svelte | head -30

Repository: appwrite/console

Length of output: 90


🏁 Script executed:

# Search for buildInitDoc usage without file type restriction
rg -n "buildInitDoc" -B 3 -A 5

Repository: appwrite/console

Length of output: 8796


🏁 Script executed:

# Check Appwrite SDK types for document metadata fields
rg -n "createdAt|updatedAt" --type ts | grep -E "(type|interface|Document)" | head -20

Repository: appwrite/console

Length of output: 2658


Remove toLocaleDateTime() conversion in buildInitDoc()—return ISO 8601 strings instead.

The function converts the ISO timestamp to a display format ('Nov 15, 2022, 08:26'), but Appwrite document metadata fields ($createdAt, $updatedAt) expect ISO 8601 strings. This will cause document creation to fail or produce malformed timestamps.

Replace toLocaleDateTime(now) with now directly:

Fix
export function buildInitDoc() {
    const now = new Date().toISOString();
    return {
        $id: ID.unique(),
        $createdAt: now,
        $updatedAt: now
    };
}
🤖 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]/+layout.svelte
around lines 11 - 18, The buildInitDoc() function is converting the ISO
timestamp via toLocaleDateTime() which produces a display format incompatible
with Appwrite's metadata; change buildInitDoc() so $createdAt and $updatedAt
receive the raw ISO string (the now variable) instead of toLocaleDateTime(now).
Locate buildInitDoc, remove calls to toLocaleDateTime for $createdAt and
$updatedAt and assign now (created by new Date().toISOString()) directly while
keeping $id generated by ID.unique().

Comment on lines +31 to +32
onSuccess={async () => {
await invalidate(Dependencies.TEAM);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check what dependency other collection settings invalidate
rg -n "invalidate\(Dependencies\." --type=svelte -g '**/collection-*/**' -C2

Repository: appwrite/console

Length of output: 90


🏁 Script executed:

cat -n src/routes/\(console\)/project-\[region\]-\[project\]/databases/database-\[database\]/collection-\[collection\]/settings/displayName.svelte

Repository: appwrite/console

Length of output: 2488


🏁 Script executed:

# Search for invalidate patterns in collection settings without file type restriction
rg -n "invalidate\(Dependencies\." src/routes -A1 -B1 | grep -A2 -B2 "collection"

Repository: appwrite/console

Length of output: 4245


🏁 Script executed:

# Look for other collection settings pages and their invalidation patterns
fd "settings" src/routes -t f | grep collection

Repository: appwrite/console

Length of output: 42


🏁 Script executed:

# Find other settings pages within collections
fd "settings" src/routes -t f -path "*collection-*" | head -20

Repository: appwrite/console

Length of output: 228


🏁 Script executed:

# Check what Dependencies.TEAM is used for
rg "Dependencies\.TEAM" src/routes --type=svelte -B2 -A2 | head -40

Repository: appwrite/console

Length of output: 90


🏁 Script executed:

# Verify the Dependencies enum definition
fd "constants" src -t f | xargs grep -l "Dependencies" 2>/dev/null

Repository: appwrite/console

Length of output: 80


🏁 Script executed:

# Read the Dependencies enum definition
cat -n src/lib/constants.ts | grep -A50 "Dependencies"

Repository: appwrite/console

Length of output: 2468


🏁 Script executed:

# Find settings pages in collection directories
find src/routes -path "*collection-*" -name "*.svelte" | grep settings

Repository: appwrite/console

Length of output: 313


🏁 Script executed:

# Check Dependencies.TEAM usage without file type
rg "Dependencies\.TEAM" src/routes -B2 -A2 | head -60

Repository: appwrite/console

Length of output: 4647


Change Dependencies.TEAM to Dependencies.COLLECTION on line 32.

Collection display name updates should invalidate the collection dependency, not the team dependency. Additionally, line 49 has inverted button logic: disabled={columnDisplayNameInput?.hasChanged()} disables the button when changes exist, but should disable it when no changes exist: disabled={!columnDisplayNameInput?.hasChanged()}.

🤖 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]/settings/displayName.svelte
around lines 31 - 32, Replace the invalidated dependency in the onSuccess
callback from Dependencies.TEAM to Dependencies.COLLECTION so collection display
name changes trigger collection cache invalidation (look for the onSuccess
handler that calls invalidate(Dependencies.TEAM)); also invert the button
disabled logic on the save/cancel button that uses
columnDisplayNameInput?.hasChanged() so it is disabled when there are no changes
(change disabled={columnDisplayNameInput?.hasChanged()} to
disabled={!columnDisplayNameInput?.hasChanged()}), ensuring the UI only enables
the action when the input has actually changed.

</svelte:fragment>

<svelte:fragment slot="actions">
<Button disabled={columnDisplayNameInput?.hasChanged()} submit>Update</Button>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Button disabled logic appears inverted.

The button is disabled when columnDisplayNameInput?.hasChanged() returns true. Typically, an "Update" button should be disabled when there are no changes (i.e., hasChanged() returns false), and enabled when there are changes.

🐛 Proposed fix
-            <Button disabled={columnDisplayNameInput?.hasChanged()} submit>Update</Button>
+            <Button disabled={!columnDisplayNameInput?.hasChanged()} submit>Update</Button>
📝 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.

Suggested change
<Button disabled={columnDisplayNameInput?.hasChanged()} submit>Update</Button>
<Button disabled={!columnDisplayNameInput?.hasChanged()} submit>Update</Button>
🤖 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]/settings/displayName.svelte
at line 49, The Update Button's disabled prop is inverted: change the logic in
the Button component that currently uses columnDisplayNameInput?.hasChanged() so
the button is disabled when there are no changes and enabled when there are
changes; replace the condition with the negation (i.e., use
!columnDisplayNameInput?.hasChanged()) so that Update is disabled when
hasChanged() is false and enabled when hasChanged() is true, referring to the
Button element and the columnDisplayNameInput?.hasChanged() call to locate the
fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants