Skip to content

Conversation

@ItzNotABug
Copy link
Member

@ItzNotABug ItzNotABug commented Oct 19, 2025

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

  • New Features

    • Added AI-powered column suggestion modal for generating table columns.
    • Introduced card-based actions in empty states for improved UI navigation.
    • Added external link handling with new target="_blank" support.
  • Improvements

    • Enhanced form controls with global disable state propagation across input components.
    • Improved empty table interface with better action organization and visual feedback.
    • Added tooltip integrations and hover effects for better usability.

@ItzNotABug ItzNotABug self-assigned this Oct 19, 2025
@railway-app
Copy link

railway-app bot commented Oct 19, 2025

This PR was not deployed automatically as @ItzNotABug does not have access to the Railway project.

In order to get automatic PR deploys, please add @ItzNotABug to your workspace on Railway.

@appwrite
Copy link

appwrite bot commented Oct 19, 2025

Console

Project ID: 688b7bf400350cbd60e9

Sites (2)
Site Status Logs Preview QR
 console-stage
688b7cf6003b1842c9dc
Queued Queued View Logs Preview URL QR Code
 console-cloud
688b7c18002b9b871a8f
Building Building View Logs Preview URL QR Code

Tip

Appwrite has a Discord community with over 16 000 members.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 19, 2025

Walkthrough

This pull request introduces a column suggestions feature for cloud users, adds a disabled prop that flows through form input hierarchies, refactors core empty state rendering with dynamic column management and deletion capabilities, and updates multiple column type editors to support uniform disablement. The changes include new components (ColumnsSuggestions, EmptySheetCards, aiForButton), type expansions in the suggestion store, updated prop signatures across column editors, and significant refactoring of the EmptySheet component to support snippet-based actions and overlay positioning.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • src/routes/(console)/.../table-[table]/layout/emptySheet.svelte: Major refactoring with overlay positioning logic, ResizeObserver integration, dynamic column width calculations, and Snippet-based API changes. Requires careful verification of rendering behavior and layout calculations.
  • src/routes/(console)/.../databases/database-[database]/(suggestions)/empty.svelte: Substantial expansion with column deletion/undo logic (10-second timer), column selection state management, tooltip positioning, and derived state for user columns. Complex state interactions require thorough review.
  • src/routes/(console)/.../databases/database-[database]/(suggestions)/store.ts: Type system changes expanding SuggestedColumnSchema and ColumnInput; new force field and showColumnsSuggestionsModal store add to the suggestions feature surface.
  • src/routes/(console)/.../table-[table]/columns/*: Repetitive disabled prop additions across 13 column editor files (boolean, datetime, email, enum, float, integer, ip, line, point, polygon, relationship, string, url, requiredArrayCheckboxes). While the pattern is consistent, verify each integration correctly combines disabled with existing logic.
  • src/lib/elements/forms/*: Disabled prop propagation through inputPolygon → inputLine → inputPoint hierarchy; verify threading is complete.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main objective of the changeset: redesigning the Suggestions UI. The changes across multiple files consistently implement UI enhancements, component refactoring, and new features for the suggestions workflow, directly aligning with the stated title.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch revamp-designs

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9206e3b and 631e349.

📒 Files selected for processing (7)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte (1 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (39 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (5 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte (1 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (4 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
📚 Learning: 2025-09-25T04:21:57.071Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:536-552
Timestamp: 2025-09-25T04:21:57.071Z
Learning: In the Appwrite console database suggestions flow, after successfully creating columns via `createColumns()`, the `await invalidate(Dependencies.TABLE)` call causes the view to be destroyed and another view (populated table view) to be rendered, automatically cleaning up component state without needing manual reset.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
📚 Learning: 2025-10-13T05:16:07.656Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2413
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte:54-58
Timestamp: 2025-10-13T05:16:07.656Z
Learning: In SvelteKit apps, shared layout components (like headers) 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, so optional chaining prevents runtime errors when navigating between routes with different data shapes (e.g., between `/databases` and `/databases/database-[database]`).

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
📚 Learning: 2025-09-25T04:33:19.632Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte:28-33
Timestamp: 2025-09-25T04:33:19.632Z
Learning: In the Appwrite console createTable component, manual submit state management (like setting creatingTable = true) is not needed because: 1) The Modal component handles submit state internally via submissionLoader, preventing double submissions, and 2) After successful table creation, the entire view is destroyed and replaced with the populated table view, ending the component lifecycle.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
📚 Learning: 2025-10-09T12:22:41.099Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2413
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/view.svelte:84-84
Timestamp: 2025-10-09T12:22:41.099Z
Learning: In the Appwrite console databases UI, user-facing labels like "Columns" should remain unchanged even when internal terminology changes to "fields". The multi-terminology support refactors internal data models without changing the user-facing text.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
📚 Learning: 2025-10-07T14:17:11.597Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2413
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts:28-28
Timestamp: 2025-10-07T14:17:11.597Z
Learning: In src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts, the empty `vectordb: {}` entry in baseTerminology is intentional. The vectordb database type is not currently used because the backend API is not finalized, and no database type returns 'vectordb' at the moment.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-25T04:31:05.213Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte:33-42
Timestamp: 2025-09-25T04:31:05.213Z
Learning: Svelte 5 uses `onclick` instead of `on:click` for event handlers. Event handlers are now properties like any other rather than directives that require the `on:` prefix.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-11-06T06:47:24.645Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2567
File: src/lib/elements/forms/inputSelect.svelte:26-36
Timestamp: 2025-11-06T06:47:24.645Z
Learning: In the appwrite.io/pink-svelte library, the Input.Select component internally uses an `input` element (not a `select` element) that triggers the `on:input` event, so event.target should be cast as HTMLInputElement in event handlers.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-25T04:31:05.213Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte:33-42
Timestamp: 2025-09-25T04:31:05.213Z
Learning: In Svelte 5, the `on:` directive syntax (like `on:click`) has been replaced with direct property syntax (like `onclick`). This is part of the migration from Svelte 4 to Svelte 5 where event handlers are treated as regular properties.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-26T06:48:57.938Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:629-631
Timestamp: 2025-09-26T06:48:57.938Z
Learning: In the Appwrite console codebase using appwrite.io/pink-svelte, the Icon component automatically handles CSS variable names passed to its color prop by internally wrapping them with var(). Therefore, passing '--some-css-variable' as a string to the Icon color prop works correctly without needing to manually wrap it with var().

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
📚 Learning: 2025-09-04T03:59:03.485Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2290
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte:952-961
Timestamp: 2025-09-04T03:59:03.485Z
Learning: In the Appwrite console spreadsheet component, for relationship columns, the columnId corresponds to the tableId of the related table. When calling openSideSheetForRelationsToMany(tableId, rows), the columnId can be passed directly as the tableId parameter for relationship columns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: e2e
  • GitHub Check: build
🔇 Additional comments (18)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (3)

71-103: LGTM: Column width adjustments are reasonable.

The reduced widths for 'key' (280→250) and 'type' (220→200) columns improve layout balance and maintain adequate space for content.


304-347: LGTM: EmptySheet refactor with proper cloud gating.

The snippet-based approach provides better composition, and the "Suggest indexes" card is correctly gated by isCloud (line 319), ensuring it only appears in cloud environments where the feature is available.


350-397: LGTM: "No columns yet" state correctly implemented.

The documentation links correctly point to tables#columns (lines 357, 394), addressing the past review concern. Cloud-specific features are properly gated, and the UI provides appropriate actions for both cloud and self-hosted environments.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (5)

166-230: LGTM: Layout refinements improve consistency.

The added gap="s" and explicit icon sizing enhance visual consistency without altering functionality.


246-246: LGTM: Force check correctly implemented.

The !== true comparison properly handles undefined/null values, ensuring the spreadsheet renders when force is not explicitly true. This addresses the past review concern.


251-269: LGTM: Filtered state refactored to use snippets.

The snippet-based approach cleanly separates the action button from the EmptySheet logic.


271-293: LGTM: Row creation actions correctly implemented.

Both "Create rows" and "Generate sample data" are standard operations available to all users, appropriately ungated by cloud checks.


297-349: LGTM: "No columns" state correctly structured.

The cloud gating is appropriate. The "Suggest columns" card (lines 313-321) appears in the fallback branch when canShowSuggestionsSheet is false, allowing users to trigger the suggestions modal—a valid UX pattern. The documentation appears only on cloud (lines 340-347) while self-hosted shows inline docs (lines 299-309).

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (10)

49-55: LGTM: Props now properly integrated.

Both userColumns and userDataRows are actively used in column layout (line 70), width calculations (line 534), rendering (line 1534), and empty cell counts (line 585), addressing the past review concern about unused props.


60-99: LGTM: User column width management is well-structured.

The getUserColumnWidth function properly retrieves persisted widths, and staticUserColumns correctly applies both width and ordering preferences while filtering system columns.


209-359: LGTM: Overlay positioning logic handles multiple scenarios.

The boundary calculation correctly considers placeholder vs. real columns, user column positions (lines 222-236), selection area constraints (lines 249-255), and visible viewport bounds (lines 268-294). The fallback attribute search pattern (lines 226-231) ensures robustness.


362-403: LGTM: Scroll logic correctly targets appropriate column.

The function intelligently selects the last user column (lines 381-386) or first custom column (lines 387-390) based on context, ensuring proper initial viewport positioning.


405-477: LGTM: Column highlighting with careful boundary management.

The function properly calculates overlay position, adjusts for first/last column edge cases (lines 434-436), prevents actions column overlap (lines 439-454), and dynamically positions tooltips based on available space (lines 459-476).


797-847: LGTM: Visibility and scroll helpers are robust.

isColumnVisible correctly accounts for 40px sticky columns on both sides (lines 810-814), and scrollColumnIntoView smoothly centers the target column (lines 835-839).


849-927: LGTM: Delete/undo implementation is solid.

The deletion flow properly validates column existence (lines 863-865), preserves the deletion index for accurate restoration (line 871), and implements a 10-second undo window (lines 878-884). The undoDelete function correctly restores the column at its original position (lines 902-903).


1110-1123: LGTM: Column selection with auto-scroll.

The function elegantly handles visibility checks (line 1115), deferred selection after scroll (line 1117), and state cleanup (line 1122).


1605-1729: LGTM: Floating action bars properly coordinated.

The delete/undo bar (lines 1611-1674) correctly uses computed state (lines 1607-1609) to show appropriate content, while the review bar (lines 1676-1728) adapts its positioning based on selection state (line 1681). The conditional rendering ensures clean UX transitions.


1744-1848: LGTM: Snippets provide clean component composition.

The rowCellInteractiveButton (lines 1744-1778), changeColumnTypePopover (lines 1780-1827), and edgeGradients (lines 1829-1848) snippets properly encapsulate reusable UI patterns with appropriate conditional logic and event handling.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/relationship.svelte (1)

188-207: Asymmetry confirmed: Primary key should also be readonly during editing.

The verification reveals the asymmetry is real but indicates a design inconsistency:

  • twoWayKey (line 207): readonly={editing} is correct because the API call doesn't include a newTwoWayKey parameter—it cannot be modified at all.
  • Primary key (line 195): The API call sends newKey: data.key !== originalKey ? data.key : undefined (line 53), allowing the key to be renamed during updates.

However, the helper text at lines 205-206 states: "Once created, column key cannot be adjusted to maintain data integrity." This applies to both keys conceptually, but only the twoWayKey is prevented from editing.

Add readonly={editing} to the primary key input (line 195) to prevent modification after relationship creation, making the behavior consistent with the helper message and the twoWayKey logic.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (1)

1110-1136: Duplicate id="key" in repeated inputs; generate unique IDs per column.

Repeated static IDs harm a11y and label association.

-                                                <InputText
-                                                    id="key"
+                                                <InputText
+                                                    id={`key-${column.id}`}
                                                     autofocus
@@
-                                            <InputText
-                                                id="key"
+                                            <InputText
+                                                id={`key-${id}`}
                                                 label="Key"

Also applies to: 1153-1160

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (2)

89-91: Null-safety for hasColumns to avoid runtime on undefined columns

Direct .length on possibly undefined can throw. Mirror your hasValidColumns optional chaining.

-    $: hasColumns = !!$table.columns.length;
+    $: hasColumns = !!$table?.columns?.length;

73-79: Inverted filter for system columns in Filters options

You exclude $id when selected but include system columns only when selected. Likely both should exclude when selected.

-        ].filter((col) => !!selected.includes(col.id));
+        ].filter((col) => !selected.includes(col.id));
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte (1)

95-104: Overlay offsets not updated on scroll; add listeners

ResizeObserver won’t catch scroll. Update offsets/heights on scroll/viewport resize to keep the overlay aligned.

 onMount(async () => {
     if (spreadsheetContainer) {
         resizeObserver = new ResizeObserver(debouncedUpdateOverlayHeight);
         resizeObserver.observe(spreadsheetContainer);

         overlayOffsetHandler = new ResizeObserver(updateOverlayLeftOffset);
         overlayOffsetHandler.observe(spreadsheetContainer);
     }
+
+    const onScrollOrResize = () => {
+        updateOverlayLeftOffset();
+        debouncedUpdateOverlayHeight();
+    };
+    window.addEventListener('scroll', onScrollOrResize, { passive: true });
+    window.addEventListener('resize', onScrollOrResize, { passive: true });
 });
 
 onDestroy(() => {
     if (resizeObserver) {
         resizeObserver.disconnect();
     }
 
     if (overlayOffsetHandler) {
         overlayOffsetHandler.disconnect();
     }
+    window.removeEventListener('scroll', onScrollOrResize);
+    window.removeEventListener('resize', onScrollOrResize);
 });

Also applies to: 105-113

🧹 Nitpick comments (15)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/url.svelte (1)

59-69: Consider simplifying the reactive pattern.

The createConservative helper adds indirection by creating stores that mirror data.required and data.array, syncing them via listen(data), and then using those stores in a reactive statement. Since the UI binds directly to data.required and data.array (lines 84, 92), this could be simplified to:

-const {
-    stores: { required, array },
-    listen
-} = createConservative<Partial<Models.ColumnUrl>>({
-    required: false,
-    array: false,
-    ...data
-});
-$: listen(data);
-
-$: handleDefaultState($required || $array);
+$: handleDefaultState(data.required || data.array);

If createConservative provides specific optimizations (e.g., preventing unnecessary re-renders), this pattern is acceptable, but the added complexity warrants verification.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte (1)

63-74: Consider using stores consistently for reactivity.

The createConservative helper creates reactive stores for required and array, which are used in the handleDefaultState effect (line 74). However, the disabled expressions (lines 81, 89, 97) access data.required and data.array directly. This creates two sources of truth that might drift out of sync.

If intentional for performance or reactivity reasons, this is fine. Otherwise, consider using either the stores consistently throughout or direct data access everywhere.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte (1)

235-249: Consider using CSS variables instead of hardcoded values.

The custom styling uses hardcoded spacing values. For consistency with the design system, consider using existing CSS variable names if they're semantically appropriate.

 .custom-inline-alert {
     & :global(article) {
-        padding: var(--space-4, 8px);
+        padding: var(--space-xs);
     }

This assumes --space-xs maps to 8px in your design system. If var(--space-4, 8px) is the correct pattern, then this change isn't needed.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/icon/aiForButton.svelte (1)

10-21: Consider using CSS variables for the icon color.

The fill color is hardcoded to #97979B. For better theming support and consistency with the design system, consider using a CSS variable.

 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
     <path
         fill-rule="evenodd"
         clip-rule="evenodd"
         d="M5.00049 2C5.55277 2 6.00049 2.44772 6.00049 3V4H7.00049C7.55277 4 8.00049 4.44772 8.00049 5C8.00049 5.55228 7.55277 6 7.00049 6H6.00049V7C6.00049 7.55228 5.55277 8 5.00049 8C4.4482 8 4.00049 7.55228 4.00049 7V6H3.00049C2.4482 6 2.00049 5.55228 2.00049 5C2.00049 4.44772 2.4482 4 3.00049 4H4.00049V3C4.00049 2.44772 4.4482 2 5.00049 2ZM5.00049 12C5.55277 12 6.00049 12.4477 6.00049 13V14H7.00049C7.55277 14 8.00049 14.4477 8.00049 15C8.00049 15.5523 7.55277 16 7.00049 16H6.00049V17C6.00049 17.5523 5.55277 18 5.00049 18C4.4482 18 4.00049 17.5523 4.00049 17V16H3.00049C2.4482 16 2.00049 15.5523 2.00049 15C2.00049 14.4477 2.4482 14 3.00049 14H4.00049V13C4.00049 12.4477 4.4482 12 5.00049 12Z"
-        fill="#97979B" />
+        fill="var(--fgcolor-neutral-tertiary)" />
     <path
         fill-rule="evenodd"
         clip-rule="evenodd"
         d="M12.0004 2C12.4542 2 12.851 2.30548 12.9671 2.74411L14.1464 7.19893L17.5002 9.13381C17.8097 9.3124 18.0004 9.64262 18.0004 10C18.0004 10.3574 17.8097 10.6876 17.5002 10.8662L14.1464 12.8011L12.9671 17.2559C12.851 17.6945 12.4542 18 12.0004 18C11.5467 18 11.1498 17.6945 11.0337 17.2559L9.85451 12.8011L6.50076 10.8662C6.19121 10.6876 6.00049 10.3574 6.00049 10C6.00049 9.64262 6.19121 9.31241 6.50076 9.13382L9.85451 7.19893L11.0337 2.74411C11.1498 2.30548 11.5467 2 12.0004 2Z"
-        fill="#97979B" />
+        fill="var(--fgcolor-neutral-tertiary)" />
 </svg>

Verify that --fgcolor-neutral-tertiary (or the appropriate variable from your design system) resolves to the desired color.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte (1)

30-53: Ensure route change settles before reading page data.

After await goto(...), consider await tick() before using page.data (for name fallback) to avoid transient stale values post-navigation.

-        if (!isOnRowsPage) {
-            await goto(
+        if (!isOnRowsPage) {
+            await goto(
                 resolve(
                     '/(console)/project-[region]-[project]/databases/database-[database]/table-[table]',
                     {
                         region: page.params.region,
                         project: page.params.project,
                         database: page.params.database,
                         table: page.params.table
                     }
                 )
-            );
+            );
+            await tick();
         }
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte (1)

23-31: Prevent clicks when disabled; avoid firing onClick for disabled cards.

Currently onClick fires regardless of disabled. Guard it to match visual state and avoid accidental actions.

-    on:click={() => onClick?.()}>
+    on:click={(e) => {
+        if (disabled) {
+            e.preventDefault();
+            e.stopPropagation();
+            return;
+        }
+        onClick?.();
+    }}>
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (4)

1012-1013: Throttle window scroll handler to reduce layout thrash.

recalcAll is heavy; reuse recalcAllThrottled for window scroll.

-<svelte:window on:resize={recalcAll} on:scroll={recalcAll} on:click={handleGlobalClick} />
+<svelte:window on:resize={recalcAll} on:scroll={recalcAllThrottled} on:click={handleGlobalClick} />

591-595: Also clear selectedColumnName on deselect to avoid stale labels.

Prevents stale badge text if UI reopens quickly after a deselect.

     function resetSelectedColumn() {
         selectedColumnId = null;
         previousColumnId = null;
-        /*selectedColumnName = null;*/
+        selectedColumnName = null;
     }

542-553: Use rAF instead of setTimeout(0) for mobile overlay updates.

rAF aligns DOM writes with paint for smoother visuals.

-    async function updateOverlaysForMobile(value: boolean) {
+    async function updateOverlaysForMobile(value: boolean) {
         if ($isSmallViewport) {
-            setTimeout(() => {
+            requestAnimationFrame(() => {
                 [rangeOverlayEl, fadeBottomOverlayEl].forEach((el) => {
                     if (el) {
                         el.style.opacity = value ? '0' : '1';
                     }
                 });
-            }, 0);
+            });
         }
     }

472-483: Align min with known backend cap to fill placeholders.

You request min: 6 while placeholders are 7 and backend max is 7. Consider min: 7 to fully populate initial slots. Based on learnings.

-                        min: 6
+                        min: 7
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (1)

246-253: Add analytics for “Generate random data” to match Clear filters/Import CSV

For parity and funnel tracking, fire a click/submit event when opening the random‑data modal.

Example:

                             onClick={() => {
-                                $randomDataModalState.show = true;
+                                $randomDataModalState.show = true;
+                                trackEvent(Click.DatabaseRandomDataOpen);
                             }} />

If Click.DatabaseRandomDataOpen doesn’t exist, align with your analytics enum naming.

Also applies to: 277-284

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte (4)

130-161: Hard-coded 1387px width is brittle; compute filler width

When no custom columns, actions: 1387 will break across viewports. Compute from container width and other fixed columns.

-        let columnWidths = {
+        const viewportWidth =
+            spreadsheetContainer?.clientWidth ||
+            (typeof window !== 'undefined' ? window.innerWidth : 0);
+
+        let columnWidths = {
             id: fixedWidths.id,
             createdAt: fixedWidths.id,
             updatedAt: fixedWidths.id,
             custom: minColumnWidth,
-            actions: hasCustomColumns ? fixedWidths.actions : 1387
+            actions: hasCustomColumns
+                ? fixedWidths.actions
+                : Math.max(
+                      minColumnWidth,
+                      viewportWidth - (fixedWidths.id + 2 * minColumnWidth) // $id + created/updated
+                  )
         };

Also applies to: 200-209


324-332: dynamicOverlayHeight is written but not used; apply or remove

You set style:--dynamic-overlay-height but the CSS never reads it. Either apply it or drop the state to reduce complexity.

Option A — apply:

 .spreadsheet-fade-bottom {
+    height: var(--dynamic-overlay-height, 60.5vh);
     right: 0;
     bottom: 0;
     position: fixed;

Option B — remove the state and related code if bottom anchoring is sufficient.

Also applies to: 414-435


284-305: Remove unreachable nested column.isAction branch

Inside the non‑action branch, column.isAction is always false. Drop the inner check for clarity.

-                            {#if column.isAction}
-                                <Button.Button icon variant="extra-compact">
-                                    <Icon icon={IconPlus} color="--fgcolor-neutral-primary" />
-                                </Button.Button>
-                            {:else if column.id === 'actions' || column.id === 'empty'}
+                            {#if column.id === 'actions' || column.id === 'empty'}
                                 {column.title}
                             {:else}
                                 <Layout.Stack

86-89: Avoid magic number 89px for collapsed tabs

89px is fragile. Source this from a CSS var or compute from the header element height.

Example:

-            if (!$expandTabs) {
-                dynamicOverlayHeight = `calc(${dynamicHeight}px - 89px)`;
-            }
+            if (!$expandTabs && headerElement) {
+                const headerExtra = headerElement.offsetHeight ?? 0;
+                dynamicOverlayHeight = `calc(${dynamicHeight}px - ${headerExtra}px)`;
+            }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa80084 and 292829d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • package.json (1 hunks)
  • src/lib/components/card.svelte (2 hunks)
  • src/lib/elements/forms/inputLine.svelte (4 hunks)
  • src/lib/elements/forms/inputPoint.svelte (3 hunks)
  • src/lib/elements/forms/inputPolygon.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte (1 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (32 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/icon/aiForButton.svelte (1 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/indexes.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/boolean.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/email.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/enum.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/ip.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/line.svelte (4 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/point.svelte (4 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/polygon.svelte (4 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/relationship.svelte (8 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/string.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/url.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte (5 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (3 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte (9 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte (1 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
PR: appwrite/console#2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
📚 Learning: 2025-10-04T11:46:32.504Z
Learnt from: ItzNotABug
PR: appwrite/console#2442
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte:88-88
Timestamp: 2025-10-04T11:46:32.504Z
Learning: In the Appwrite Console codebase, for float/double column inputs in database table column configuration files (like float.svelte), use step={0.1} for InputNumber components, not step="any". This is the established pattern for float/double precision inputs.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: e2e
🔇 Additional comments (55)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/ip.svelte (1)

42-42: LGTM! Clean implementation of the disabled prop.

The disabled prop is correctly exported and consistently propagated to all three form controls (InputText and both Selector.Checkbox components). The logic properly extends existing disabled conditions without disruption, maintaining the component's existing behavior while enabling external control of interactivity.

Also applies to: 77-77, 85-85, 93-93

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/boolean.svelte (1)

42-102: LGTM! Disabled prop correctly propagated.

The disabled prop is properly introduced and threaded through to all relevant UI controls (default value selector, required checkbox, and array checkbox). The logic correctly combines the new prop with existing disabled conditions using OR operations, ensuring that when disabled is true, all controls are appropriately disabled without breaking existing behavior.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte (1)

863-863: LGTM! Hover effect added appropriately.

The hoverEffect prop is correctly added to data rows while being intentionally excluded from loading rows (lines 842-855). This follows the existing pattern where interactive features like showSelectOnHover are only applied to actual data rows, not placeholder loading rows.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/point.svelte (2)

46-46: LGTM! Disabled state integration is well-implemented.

The addition of the disabled prop and its propagation to form controls follows the standard pattern. Explicit defaults for data, editing, and disabled in the props destructuring improve clarity and prevent undefined values. The disabled state is correctly passed to all relevant UI controls (Required checkbox, Default value checkbox, and InputPoint component) without disrupting existing logic.

Also applies to: 50-57, 107-107, 118-118, 139-139


47-47: Line marked as changed but appears unchanged.

Line 47 is annotated as modified but shows no visible difference. This may be a whitespace change, formatting adjustment, or annotation inconsistency.

src/lib/elements/forms/inputPoint.svelte (1)

13-13: LGTM! Clean implementation of disabled prop.

The disabled prop is properly defined, destructured, and propagated to both the number inputs and delete button. The delete button correctly combines all disabling conditions.

Also applies to: 26-26, 43-43, 51-51

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/line.svelte (1)

46-46: LGTM! Consistent disabled prop implementation.

The disabled prop is properly integrated throughout the component:

  • Correctly defined with a sensible default (false)
  • Properly propagated to both checkboxes and the InputLine component
  • The destructuring pattern is clean and follows Svelte conventions

Also applies to: 50-54, 114-114, 125-125, 146-146

src/lib/elements/forms/inputPolygon.svelte (1)

20-20: LGTM! Proper disabled prop propagation.

The disabled prop is correctly added and forwarded to all InputLine instances, enabling unified disable behavior across polygon line inputs.

Also applies to: 30-32, 39-39

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/polygon.svelte (1)

46-46: LGTM! Well-integrated disabled state.

The disabled prop is properly implemented and propagated throughout:

  • Correctly defined with a sensible default (false)
  • Properly forwarded to both checkboxes and the InputPolygon component
  • Follows the same pattern established across other column editors

Also applies to: 50-57, 128-128, 140-140, 161-161

src/lib/elements/forms/inputLine.svelte (1)

17-17: LGTM! Complete disabled prop integration.

The disabled prop is correctly implemented:

  • Properly propagated to all InputPoint instances
  • Add coordinate button correctly combines both disabling conditions (nullable || disabled)
  • Completes the cascading disable behavior through the input component hierarchy

Also applies to: 28-30, 45-45, 58-64

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/enum.svelte (4)

42-45: LGTM! Import additions are properly used.

The new imports (createConservative and IconInfo) are correctly utilized in the component.


48-48: LGTM! Disabled prop follows Svelte conventions.

The new disabled prop is correctly declared and enables external control of the form's disabled state.


90-102: Verify: Should the Elements input also respect the disabled state?

The InputTags component for "Elements" doesn't receive the disabled prop, while all other form inputs (default value, required, array) do. Consider whether this is intentional or if the Elements input should also be disabled when the parent component's disabled prop is true for consistency.


107-107: LGTM! Disabled logic is correctly implemented.

The disabled conditions for each form input properly combine business rules with the component-level disabled prop:

  • Default value disabled when array/required (no default needed) or form disabled
  • Required disabled when array (mutually exclusive) or form disabled
  • Array disabled when required (mutually exclusive), editing (immutable), or form disabled

Also applies to: 117-117, 125-125

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/float.svelte (4)

45-46: LGTM! New imports align with UI revamp.

The new imports for createConservative, Layout, and Selector are properly utilized throughout the component and align with the pink-svelte UI library adoption mentioned in the AI summary.


49-49: LGTM! Disabled prop correctly added to public API.

The new disabled prop with a default value of false is correctly exposed and aligns with the pattern being applied across all column editors in this PR.


82-111: LGTM! Disabled state correctly propagated to all InputNumber components.

The disabled prop is properly threaded through all InputNumber components with appropriate logic:

  • Min/Max inputs: simple disabled prop
  • Default value input: correctly combines data.required || data.array || disabled to prevent defaults on required or array fields

The step={0.1} is correctly maintained as per established pattern.

Based on learnings


113-127: LGTM! Disabled state correctly propagated to checkboxes with proper business rules.

The disabled prop is appropriately integrated into both checkboxes while maintaining existing business rules:

  • Required checkbox: disabled={data.array || disabled} - prevents required when array is true
  • Array checkbox: disabled={data.required || editing || disabled} - prevents array when required is true or in edit mode

The mutual exclusion between required and array fields is correctly preserved.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/email.svelte (4)

41-42: LGTM: New imports support disabled state management.

The Selector component from the external UI library and createConservative helper are appropriately imported to support the new disabled prop functionality and reactive state tracking.


45-45: LGTM: Disabled prop correctly added to public interface.

The disabled prop with a default value of false provides parent components control over the form's interactive state.


59-70: LGTM: Reactive state management correctly handles default value logic.

The createConservative helper appropriately tracks required and array state changes to trigger handleDefaultState, which correctly clears the default value when either condition is true (required fields must be provided, array fields default to empty arrays).


72-94: LGTM: Disabled logic correctly implements mutual exclusion and prop threading.

The disabled state is properly threaded through all form inputs with correct business logic:

  • InputEmail: Disabled when a default value doesn't apply (required or array fields)
  • Required/Array checkboxes: Mutual exclusion prevents both being true simultaneously
  • Array checkbox: Additionally disabled during editing (array type can't change post-creation)
  • All inputs respect the parent's disabled prop
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/string.svelte (2)

58-58: LGTM! Disabled prop correctly propagated through form controls.

The new disabled prop is properly integrated with existing disabled logic across all form inputs and checkboxes. The OR combination ensures the component respects both the global disabled state and field-specific constraints.

Also applies to: 92-92, 107-107, 115-115, 123-123, 137-137


129-130: LGTM! Container styling properly updated for disabled state.

The cursor and CSS class bindings on the popover holder correctly incorporate the new disabled prop, ensuring appropriate visual feedback when the encrypt controls are disabled.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/integer.svelte (4)

45-46: LGTM! Imports are properly utilized.

The new imports are correctly integrated: createConservative is used for reactive store management (lines 69-77), and the UI components are used for layout and form controls throughout the template.


49-49: LGTM! Disabled prop properly introduced.

The new disabled prop is correctly typed and defaulted to false, consistent with the broader pattern of centralized disablement across column editors mentioned in the AI summary.


82-98: LGTM! Disabled state properly propagated to min/max inputs.

The disabled prop is correctly passed to both InputNumber components, ensuring consistent behavior when the component is in a disabled state.


110-124: LGTM! Checkbox disabled states properly configured.

Both checkboxes correctly combine business rules with the component-level disabled prop:

  • Required checkbox (line 115): Disabled when array=true or the component is disabled
  • Array checkbox (line 123): Disabled when required=true, in editing mode, or the component is disabled

The logic properly prevents conflicting states while respecting the disabled prop.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/url.svelte (3)

41-42: LGTM! Imports are used correctly.

Both imports are actively utilized:

  • Selector for the checkbox components (lines 80, 88)
  • createConservative for reactive store management (lines 59-66)

45-46: LGTM! Disabled prop correctly added.

The disabled prop with a sensible default aligns with the broader pattern of disabled state propagation across column editors mentioned in the PR summary. The property is properly exported and consistently propagated to child components.


77-93: LGTM! Disabled logic is correctly implemented.

The disabled prop is appropriately propagated to all interactive elements with sound logic:

  • InputURL (line 77): Disabled when required (no default for required fields), array (constraint), or globally disabled
  • Required checkbox (line 85): Disabled when array (mutual exclusivity) or globally disabled
  • Array checkbox (line 93): Disabled when required (mutual exclusivity), editing (immutability after creation), or globally disabled

The mutual exclusivity between required and array, combined with immutability of the array property during editing, is correctly enforced.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte (3)

45-46: LGTM! Clean import additions.

The new imports are properly utilized: Selector for the checkbox components and createConservative for reactive state management.


77-98: LGTM! Disabled logic properly implements business rules.

The disabled prop is correctly threaded through all UI controls with appropriate business logic:

  • Default value disabled when required, array, or globally disabled
  • Required checkbox disabled when array or globally disabled
  • Array checkbox disabled when required, editing, or globally disabled

The implementation correctly prevents invalid state combinations.


49-49: No action required—disabled prop is correctly implemented.

The disabled prop is properly declared with a sensible default and consistently applied throughout the component. All column editor components follow the same pattern (integer, float, string, boolean, etc.), suggesting this is an established convention in the codebase. The prop correctly controls disabled state on form elements.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/relationship.svelte (2)

72-72: LGTM! Disabled prop correctly added.

The new disabled prop follows the established pattern and allows parent components to control the disabled state of all interactive elements within the relationship column editor.


162-217: Pattern verified—no changes needed. The disabled state strategy is correct and consistent with other column editors.

The composite disabled={editing || disabled} applied to structural fields (way, related table, relationship type) matches the established pattern used for immutable fields across all column editors. Other editors similarly lock the array checkbox with disabled={data.required || editing || disabled} to prevent structural changes once created. Keys remaining editable with simple {disabled} aligns with how other editors keep value fields editable during edit mode. The approach correctly distinguishes immutable structural properties from editable value properties.

package.json (1)

27-29: LGTM! Dependency updates support new UI components.

The updated pink-icons-svelte and pink-svelte dependencies align with the new AI suggestions UI, icon components, and form enhancements introduced in this PR.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/indexes.svelte (2)

11-11: LGTM! Simplified imports after removing confirmation flow.

The removal of the Confirm component import aligns with the simplified dismiss flow where users can directly cancel without an additional confirmation step.


355-355: LGTM! Direct dismissal improves UX.

The Cancel button now directly invokes dismissIndexes(), streamlining the user experience by removing an unnecessary confirmation step. The implementation is consistent with the mobile cancel flow at Line 384.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte (2)

41-42: Verify that the feature is production-ready.

The feature flag is hardcoded to true with a comment stating "flow isn't complete yet!" This could expose incomplete functionality to users.

Consider using an environment variable or feature flag service to control this:

-// flow isn't complete yet!
-const isSuggestionsFeatureEnabled = true;
+const isSuggestionsFeatureEnabled = import.meta.env.VITE_ENABLE_AI_SUGGESTIONS === 'true';

Or if the flow is actually complete, remove the comment to avoid confusion.


189-203: LGTM! AI suggestion integration is well-structured.

The inline alert provides a clear call-to-action for users to leverage AI-powered column suggestions. The modal state management correctly hides the create column sheet while showing the suggestions modal.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (2)

293-345: LGTM! Enhanced empty states with AI suggestions.

The empty state updates provide users with clear options for both AI-assisted and manual workflows. The dual-action cards (AI suggestions and manual creation) improve discoverability and offer flexibility based on user preference.

The conditional logic properly handles two scenarios:

  • No indexes but columns exist → suggest indexes or create manually
  • No columns → create columns or use AI suggestions

69-76: Review comment mischaracterizes the width implementation pattern.

The column widths are not actually "fixed" as described. The getColumnWidth function (lines 117-122) retrieves saved user preferences and returns the user's resized value if available, otherwise returns the default. Since resizable: true is set on each column, users can resize and persist custom widths via the preferences system. This is a flexible, persistence-based approach—not a transition to truly fixed pixel values. The same pattern is used consistently across other pages (spreadsheet.svelte, columns/+page.svelte), making it an intentional architectural choice.

Likely an incorrect or invalid review comment.

src/lib/components/card.svelte (2)

23-31: LGTM! Enhanced prop flexibility.

The prop type refinements improve the component API:

  • isButton is now a flexible boolean instead of a literal
  • external prop enables controlled new-tab behavior for links
  • AnchorProps.isButton is now optional, providing more flexibility

These changes maintain backwards compatibility while expanding the API surface for more use cases.


50-62: LGTM! Clean conditional spread for external links.

The use of a conditional spread operator {...external ? { target: '_blank' } : {}} is an elegant pattern for conditionally applying the target attribute. This ensures links only open in new tabs when explicitly requested via the external prop.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (2)

6-6: LGTM! Optional force field added to suggestion type.

The force?: boolean field extends TableColumnSuggestions without breaking existing code. The field likely controls whether to force regeneration of suggestions or bypass certain logic in the AI-driven workflow.


52-52: LGTM! New modal state store.

The showColumnsSuggestionsModal writable store provides clean state management for the column suggestions modal visibility. This follows the same pattern as showIndexesSuggestions at Line 50.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte (2)

10-23: LGTM! Clean API extension for mobile footer actions.

The new props enhance the component's flexibility:

  • mobileFooterChildren: Optional snippet for custom mobile footer content
  • onChildrenClick: Optional callback for click handling

Both are properly typed as optional and maintain backwards compatibility.


63-65: LGTM! Footer snippet integration.

The footer snippet correctly passes the toggle function to mobileFooterChildren, maintaining consistency with the pattern used elsewhere in the component. The optional chaining ensures the snippet is only rendered when provided.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte (2)

10-15: Prop addition LGTM.

Public prop isModal with default false is clear and typed.


30-36: Modal-aware copy and switch visibility LGTM.

Subtitle logic and hiding the switch in modal mode match the intended UX.

Also applies to: 53-61

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte (2)

11-16: Bindable show prop LGTM.

Using $bindable for show enables clean two-way binding from layout.


55-62: Modal content and actions LGTM.

Input respects modal mode; Cancel fully resets suggestion state.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte (2)

68-73: Imports are correctly configured; no tree-shaking issues.

The index file properly re-exports all symbols from store.ts via export * from './store', including showColumnsSuggestionsModal. The import statement in +layout.svelte correctly sources from the ../(suggestions) aggregator, which chains to the store exports. No mismatches exist.


490-491: Remove this review comment — code is correctly implemented.

The binding is properly configured. The show prop in ColumnsSuggestions is marked with $bindable(), and showColumnsSuggestionsModal is a writable store. Two-way binding directly to a $-prefixed store value in component props is supported in Svelte 5 when the child prop is declared bindable and the store is writable. Both conditions are met here, so no refactoring is needed.

Likely an incorrect or invalid review comment.

Copy link
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: 2

♻️ Duplicate comments (4)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (1)

337-343: Gate "Suggest columns" card to Cloud/feature availability.

Similar to the indexes card, this "Suggest columns" card is visible regardless of cloud availability or feature enablement, potentially misleading users in non-cloud environments.

Apply the same gating pattern as recommended for the suggest indexes card:

+                    {#if isCloud && $tableColumnSuggestions.enabled}
                     <EmptySheetCards
                         icon={IconAI}
                         title="Suggest columns"
                         subtitle="Use AI to generate columns"
                         onClick={() => {
                             $showColumnsSuggestionsModal = true;
-                        }} />
+                        }} />
+                    {/if}
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (1)

269-276: Gate "Suggest columns" card to Cloud/feature availability.

The TODO comment and past review both flag this: the card is always rendered even when suggestions are disabled or unavailable. Users noted this for internal design evaluation but it remains unaddressed.

Wrap the card in a conditional:

+                    {#if isCloud && $tableColumnSuggestions.enabled}
                     <EmptySheetCards
                         icon={IconAI}
                         title="Suggest columns"
                         subtitle="Use AI to generate columns"
                         onClick={() => {
                             $showColumnsSuggestionsModal = true;
-                        }} />
+                        }} />
+                    {/if}
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (2)

280-280: Use standard scroll behavior value.

ScrollToOptions accepts 'auto' or 'smooth'; 'instant' is non-standard and browsers may ignore it.

Apply this diff:

             directAccessScroller.scrollTo({
                 left: Math.max(0, scrollLeft),
-                behavior: 'instant'
+                behavior: 'auto'
             });

679-695: Fix type annotation for columnSchema.

Line 683 uses = null (value assignment) instead of | null (type union), which doesn't make columnSchema nullable in TypeScript. While the guard at 693-695 prevents the crash mentioned in past reviews, the type is still incorrect.

Apply this diff:

     function deleteColumn(columnId: string) {
         if (!columnId) return;
 
         let columnIndex = -1;
-        let columnSchema: SuggestedColumnSchema = null;
+        let columnSchema: SuggestedColumnSchema | null = null;
 
         for (let index = 0; index < customColumns.length; index++) {
🧹 Nitpick comments (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (1)

46-50: Remove unused userColumns prop.

The userColumns prop is accepted but never used. Line 403 has it commented out, and line 419 includes it only to silence linting. This adds unnecessary API surface.

Remove the prop or document its intended future use:

-    let {
-        userColumns = []
-    }: {
-        userColumns?: Column[];
-    } = $props();

And remove line 419:

-        userColumns; /* silences lint check, variable not read */

Also applies to: 403-403, 419-419

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 292829d and daf83bf.

📒 Files selected for processing (5)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte (1 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (32 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (2 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
PR: appwrite/console#2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: e2e
  • GitHub Check: build
🔇 Additional comments (9)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte (1)

69-76: LGTM: Column width configuration.

The minimum width constraints for the key and type columns are appropriate and improve readability.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (3)

238-252: LGTM: EmptySheetCards integration for rows.

The action cards provide clear options for creating rows and generating test data, improving the empty state UX.


216-231: Approve refactored filtered rows empty state.

The actions snippet pattern simplifies the component structure and maintains functionality.


208-208: Store initialization confirmed—no issues found.

The tableColumnSuggestions store initializes force as false (not undefined/null), making the condition !== true correctly allow grid rendering in the initial state while respecting explicit force: true toggles.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (5)

788-796: LGTM: Column key validation.

The guard prevents creating columns with invalid/empty keys and provides clear user feedback.


679-724: Approve delete/undo workflow with 10-second timer.

The implementation correctly handles column deletion with a timed undo option, stores the index for restoration, and cleans up state appropriately.


285-309: Approve column highlight positioning.

The dynamic CSS variable approach for positioning the highlight overlay is clean and integrates well with the spreadsheet layout.


627-677: LGTM: Column visibility and scroll-into-view logic.

The visibility checks account for sticky columns and viewport bounds correctly, and the smooth scrolling centers the column appropriately.


1381-1428: Approve changeColumnTypePopover snippet extraction.

The snippet pattern reduces duplication and makes the column type selector reusable across header and editor contexts.

Copy link
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: 1

♻️ Duplicate comments (2)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (2)

749-753: Uncomment selectedColumnName reset for state consistency.

The selectedColumnName is assigned in multiple places (lines 871, 912, 1098) but isn't reset in resetSelectedColumn() due to the commented line 752. This creates inconsistent state management where selectedColumnId is cleared but selectedColumnName persists.

Apply this diff:

 function resetSelectedColumn() {
     selectedColumnId = null;
     previousColumnId = null;
-    /*selectedColumnName = null;*/
+    selectedColumnName = null;
 }

837-882: Fix TypeScript type for columnSchema.

Line 841 declares columnSchema as SuggestedColumnSchema = null, which assigns null to a non-nullable type. This should be typed as nullable.

Apply this diff:

 function deleteColumn(columnId: string) {
     if (!columnId) return;
 
     let columnIndex = -1;
-    let columnSchema: SuggestedColumnSchema = null;
+    let columnSchema: SuggestedColumnSchema | null = null;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9039c60 and ae9ac4e.

📒 Files selected for processing (2)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (37 hunks)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (10 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
PR: appwrite/console#2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
🪛 GitHub Actions: Tests
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte

[error] 1696-1696: svelte-check: 'customTooltip' is declared but its value is never read. (ts)


[error] svelte-check reported 1 error and 0 warnings in 1 file.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (10)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (3)

5-57: LGTM: Type extensions and store initialization.

The new fields (force, array, encrypt, elements, isPlaceholder) are properly typed with appropriate optional markers, and the stores are correctly initialized.


141-160: Verify: array field hardcoded to false.

Line 146 always sets array: false for all suggested columns. If the column suggestions API can return array-type columns or if this will be a future enhancement, consider making this field configurable via the ColumnInput type or deriving it from the input data.

If array columns are intentionally not supported in suggestions, this is fine—but worth confirming.


59-124: LGTM: Mock data field renaming.

The mock suggestion field names have been updated to more generic terms (e.g., publishedYearyear, genrecategory). This improves the mock data's reusability.

src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (7)

48-95: LGTM: userColumns prop is now properly utilized.

The userColumns prop that was previously flagged as unused is now actively used in the staticUserColumns derived state (line 68+), where it's mapped with width/ordering logic. The previous concern no longer applies.


106-133: LGTM: State management for column interactions.

The new state variables for selection, hover, tooltips, and deletion/undo are properly initialized. The 10-second undo timer limit is reasonable for UX.


176-394: LGTM: Overlay bounds calculation handles user columns.

The overlay positioning logic correctly accounts for both user-defined columns and custom suggested columns, with appropriate fallbacks when elements aren't found (e.g., lines 218-222).


396-496: LGTM: Column highlight and scroll handling.

The updateColumnHighlight function properly calculates overlay positioning with viewport-aware tooltip placement. The scroll handler correctly resets selection/hover states when columns scroll out of view.


942-1077: LGTM: Column creation with validation and encrypt support.

The column creation flow properly validates keys before submission (lines 946-954) and conditionally includes the encrypt property only when present (line 965), preventing undefined values in the payload.


1249-1249: Event handlers are valid for Svelte 5.

The code uses vanilla event attributes (onmousemove, onfocusin, onfocusout, onmouseenter, onclick) which are valid in Svelte 5.25.3. These past concerns from previous reviews are no longer applicable as Svelte 5 supports both onevent and on:event syntaxes.

Also applies to: 1383-1395, 1504-1518, 1519-1527


1946-1952: LGTM: interpolate-size properly feature-detected.

The experimental interpolate-size property is now correctly wrapped in an @supports query (lines 1949-1951), addressing the previous browser compatibility concern.

Copy link
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: 3

♻️ Duplicate comments (5)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (5)

1250-1251: Fix Svelte event bindings (use on:*) and set button type.

Plain DOM attributes won’t bind; selection/hover and editor focus handlers won’t fire. Also add type="button" to avoid unintended submits.

-    style:--non-overlay-icon-color="--fgcolor-neutral-weak"
-    onmousemove={columnHoverMouseTracker}>
+    style:--non-overlay-icon-color="var(--fgcolor-neutral-weak)"
+    on:mousemove={columnHoverMouseTracker}>
@@
-                                                onfocusin={() => {
+                                                on:focusin={() => {
                                                     isInlineEditing = true;
                                                     showHeadTooltip = false;
                                                     resetSelectedColumn();
                                                     handlePreviousColumnsBorder(column.id);
                                                 }}
-                                                onfocusout={() => {
+                                                on:focusout={() => {
                                                     showHeadTooltip = true;
                                                     isInlineEditing = false;
                                                     handlePreviousColumnsBorder(
                                                         column.id,
                                                         false
                                                     );
                                                 }}>
@@
-                            <button
+                            <button
+                                type="button"
                                 class="column-selector-button"
                                 aria-label="Select column"
                                 data-column-hover={column.id}
-                                onmouseenter={() => {
+                                on:mouseenter={() => {
                                     if (
                                         isColumnInteractable &&
                                         !selectedColumnId &&
                                         !isInlineEditing &&
                                         !$isTabletViewport &&
                                         !$isSmallViewport &&
                                         !$tableColumnSuggestions.thinking &&
                                         !creatingColumns &&
                                         hoveredColumnId !== column.id
                                     ) {
                                         hoveredColumnId = column.id;
                                         tooltipTopPosition = 35 + Math.random() * 20;
                                     }
                                 }}
-                                onclick={() => {
+                                on:click={() => {
                                     if (isColumnInteractable) {
                                         if (!$isTabletViewport) {
                                             selectColumnWithId(column);
                                         } else if ($isSmallViewport) {
                                             triggerColumnId = column.id;
                                         }
                                     }
                                 }}>

Also applies to: 1385-1398, 1503-1530


389-392: Use a standard scroll behavior.

ScrollToOptions doesn’t support 'instant'. Replace with 'auto' (or 'smooth' if desired).

-            directAccessScroller.scrollTo({
-                left: Math.max(0, scrollLeft),
-                behavior: 'instant'
-            });
+            directAccessScroller.scrollTo({
+                left: Math.max(0, scrollLeft),
+                behavior: 'auto'
+            });

749-753: Reset selectedColumnName for consistent deselect state.

Avoid stale badge/labels after deselect.

     function resetSelectedColumn() {
         selectedColumnId = null;
         previousColumnId = null;
-        /*selectedColumnName = null;*/
+        selectedColumnName = null;
     }

1579-1642: Gate Delete/Undo bar by selection or undo.

Prevents empty badge and confusing “is selected” copy with nothing selected.

-{#if !creatingColumns}
-    <div class="floating-action-wrapper expanded" class:selection={hasSelection}>
+{#if !creatingColumns && hasSelection}
+    <div class="floating-action-wrapper expanded" class:selection={true}>
         <FloatingActionBar>

1700-1710: Fix pipeline: remove unused customTooltip snippet (or re-use it).

svelte-check error: “customTooltip is declared but its value is never read.” Remove the snippet or restore its usage; removal is simplest.

-{#snippet customTooltip({ text, show })}
-    <div
-        transition:fadeSlide
-        class="custom-tooltip"
-        style:top={`${tooltipTopPosition}%`}
-        class:show-tooltip={show && !$isTabletViewport}>
-        <Typography.Text>
-            {text}
-        </Typography.Text>
-    </div>
-{/snippet}
+<!-- removed unused customTooltip snippet to fix svelte-check -->
🧹 Nitpick comments (3)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (3)

233-251: Clamp overlay width to non-negative to avoid invalid CSS.

Width can go negative if left overshoots actionsLeft. Clamp to 0.

-                const width = actionsLeft - left;
+                const width = Math.max(0, actionsLeft - left);
@@
-        const width = right - left;
+        const width = Math.max(0, right - left);

Also applies to: 343-349


419-467: Cast hovered boolean explicitly.

isHovered holds a string; cast to boolean for clarity. No runtime change.

-        const isHovered = !selectedColumnId && hoveredColumnId;
+        const isHovered = !selectedColumnId && Boolean(hoveredColumnId);

699-709: Use rAF instead of setTimeout(0) for mobile overlay opacity flip.

Minor polish for visual sync with paint.

-        if ($isSmallViewport) {
-            setTimeout(() => {
+        if ($isSmallViewport) {
+            requestAnimationFrame(() => {
                 [rangeOverlayEl, fadeBottomOverlayEl, snowFadeBottomOverlayEl].forEach((el) => {
                     if (el) {
                         el.style.opacity = value ? '0' : '1';
                     }
                 });
-            }, 0);
+            });
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae9ac4e and 01daaa1.

📒 Files selected for processing (1)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (36 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
PR: appwrite/console#2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
🪛 GitHub Actions: Tests
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte

[error] 1700-1700: customTooltip is declared but its value is never read. (ts)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (4)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (4)

106-108: Placeholder count matches backend max (7).

Good alignment with suggestColumns limit; keeps UI skeleton consistent. Based on learnings


498-518: Nit: ensure suggested columns are non-resizable consistently.

You already set resizable: false; keep consistent across mapped arrays. LGTM otherwise.

Also applies to: 560-562


576-587: Preferences load on mount: good.

columnsOrder/columnsWidth hydration before render is correct; avoids layout jumps.


132-134: Store resets and tracking look correct.

Undo timer constant, store resets, and analytics events are coherent.

Also applies to: 688-697, 1063-1064

Copy link
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: 1

♻️ Duplicate comments (8)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (8)

749-753: Uncomment selectedColumnName reset for complete state cleanup.

selectedColumnName is set in multiple places (lines 871, 912, 1102) but isn't reset here, creating inconsistent state management.

Apply this diff:

     function resetSelectedColumn() {
         selectedColumnId = null;
         previousColumnId = null;
-        /*selectedColumnName = null;*/
+        selectedColumnName = null;
     }

389-392: Use standard scroll behavior value.

behavior: 'instant' is not standard in ScrollToOptions (only 'auto' and 'smooth' are). Browsers may ignore this non-standard value.

Apply this diff:

             directAccessScroller.scrollTo({
                 left: Math.max(0, scrollLeft),
-                behavior: 'instant'
+                behavior: 'auto'
             });

524-549: Don't override persisted user column widths.

staticUserColumns already have their widths set from getUserColumnWidth (lines 79-81), which respects saved preferences. But line 543 replaces them with distributedWidth, discarding user preferences.

Apply this diff to preserve persisted widths and only distribute to suggested columns:

-        const equalWidthColumns = [...staticUserColumns, ...customSuggestedColumns];
+        const customCount = customSuggestedColumns.length;
+        
+        // calculate total width used by user columns (with their saved widths)
+        const userTotalWidth = staticUserColumns.reduce((sum, col) => {
+            const w = col.width;
+            return sum + (typeof w === 'number' ? w : (w && 'min' in w ? w.min : minColumnWidth));
+        }, 0);
 
         const totalBaseWidth =
             fixedWidths.id +
             fixedWidths.actions +
             fixedWidths.selection +
-            equalWidthColumns.length * minColumnWidth;
+            userTotalWidth +
+            customCount * minColumnWidth;
 
         const viewportWidth =
             spreadsheetContainer?.clientWidth ||
             (typeof window !== 'undefined' ? window.innerWidth : totalBaseWidth);
 
         const excessSpace = Math.max(0, viewportWidth - totalBaseWidth);
         const extraPerColumn =
-            equalWidthColumns.length > 0 ? excessSpace / equalWidthColumns.length : 0;
+            customCount > 0 ? excessSpace / customCount : 0;
         const distributedWidth = minColumnWidth + extraPerColumn;
 
-        const userColumnsWithWidth = staticUserColumns.map((col) => ({
-            ...col,
-            width: distributedWidth
-        }));
+        const userColumnsWithWidth = staticUserColumns; // keep their saved widths
 
         const finalCustomColumns = customSuggestedColumns.map((col) => ({
             ...col,
             width: { min: distributedWidth }
         }));

1252-1252: Wrap CSS variable reference with var().

When setting a CSS custom property to reference another CSS variable, you must use var(). Without it, the value is treated as a literal string.

Apply this diff:

-    style:--non-overlay-icon-color="--fgcolor-neutral-weak"
+    style:--non-overlay-icon-color="var(--fgcolor-neutral-weak)"

837-882: Fix type error: columnSchema must allow null.

Line 841 initializes columnSchema to null but declares it as SuggestedColumnSchema, causing a TypeScript error. The guard at line 851 already handles the null case correctly.

Apply this diff:

     function deleteColumn(columnId: string) {
         if (!columnId) return;
 
         let columnIndex = -1;
-        let columnSchema: SuggestedColumnSchema = null;
+        let columnSchema: SuggestedColumnSchema | null = null;
 
         for (let index = 0; index < customColumns.length; index++) {

1253-1253: Fix Svelte event binding: use on:mousemove.

The onmousemove attribute won't bind in Svelte. Column hover tracking will fail.

Apply this diff:

     style:--overlay-icon-color="#fd366e99"
     style:--non-overlay-icon-color="var(--fgcolor-neutral-weak)"
-    onmousemove={columnHoverMouseTracker}>
+    on:mousemove={columnHoverMouseTracker}>

1582-1646: Only render delete/undo bar when there's an active selection.

The delete/undo floating bar (lines 1582-1646) currently renders whenever !creatingColumns, but should only appear when hasSelection is true (column selected or undo active). This can show an empty badge and confusing UI when nothing is selected.

Apply this diff:

-        {#if !creatingColumns}
+        {#if !creatingColumns && hasSelection}
             <div class="floating-action-wrapper expanded" class:selection={hasSelection}>

Based on learnings.


1505-1532: Fix Svelte event bindings: use on:mouseenter and on:click (and add button type).

Lines 1509 and 1524 use onmouseenter and onclick which won't bind in Svelte. Column hover and selection won't work. Also add type="button" to prevent form submission.

Apply this diff:

                         <Spreadsheet.Cell {root} column={column.id} isEditable={false}>
                             <button
+                                type="button"
                                 class="column-selector-button"
                                 aria-label="Select column"
                                 data-column-hover={column.id}
-                                onmouseenter={() => {
+                                on:mouseenter={() => {
                                     if (
                                         isColumnInteractable &&
                                         !selectedColumnId &&
                                         !isInlineEditing &&
                                         !$isTabletViewport &&
                                         !$isSmallViewport &&
                                         !$tableColumnSuggestions.thinking &&
                                         !creatingColumns &&
                                         hoveredColumnId !== column.id
                                     ) {
                                         hoveredColumnId = column.id;
                                         tooltipTopPosition = 35 + Math.random() * 20;
                                     }
                                 }}
-                                onclick={() => {
+                                on:click={() => {
                                     if (isColumnInteractable) {
                                         if (!$isTabletViewport) {
                                             selectColumnWithId(column);
                                         } else if ($isSmallViewport) {
                                             triggerColumnId = column.id;
                                         }
                                     }
                                 }}></button>
                         </Spreadsheet.Cell>
🧹 Nitpick comments (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (1)

1703-1713: Remove unused customTooltip snippet or restore its usage.

The customTooltip snippet is defined but never used—its only call site is commented out at line 1282. Remove this dead code or uncomment line 1282 if the tooltip is intended to be shown.

To remove:

-{#snippet customTooltip({ text, show })}
-    <div
-        transition:fadeSlide
-        class="custom-tooltip"
-        style:top={`${tooltipTopPosition}%`}
-        class:show-tooltip={show && !$isTabletViewport}>
-        <Typography.Text>
-            {text}
-        </Typography.Text>
-    </div>
-{/snippet}
-

Or uncomment line 1282 to restore usage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b223e9e and 2b7bf48.

📒 Files selected for processing (1)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (37 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
PR: appwrite/console#2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-26T06:48:57.938Z
Learnt from: ItzNotABug
PR: appwrite/console#2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:629-631
Timestamp: 2025-09-26T06:48:57.938Z
Learning: In the Appwrite console codebase using appwrite.io/pink-svelte, the Icon component automatically handles CSS variable names passed to its color prop by internally wrapping them with var(). Therefore, passing '--some-css-variable' as a string to the Icon color prop works correctly without needing to manually wrap it with var().

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte

Copy link
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: 1

♻️ Duplicate comments (5)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (5)

520-571: Preserve user column widths instead of overriding with distributedWidth.

Lines 541-544 override the carefully preserved widths from staticUserColumns (which uses getUserColumnWidth to respect stored preferences) by mapping every column to distributedWidth. This discards user column resize preferences.

Apply this diff to preserve user widths and only distribute excess space to suggested columns:

-        const equalWidthColumns = [...staticUserColumns, ...customSuggestedColumns];
+        const customCount = customSuggestedColumns.length;

         const totalBaseWidth =
             fixedWidths.id +
             fixedWidths.actions +
             fixedWidths.selection +
-            equalWidthColumns.length * minColumnWidth;
+            staticUserColumns.reduce((sum, col) => {
+                const w = col.width;
+                return sum + (typeof w === 'number' ? w : (w && 'min' in w ? w.min : minColumnWidth));
+            }, 0) +
+            customCount * minColumnWidth;

         const viewportWidth =
             spreadsheetContainer?.clientWidth ||
             (typeof window !== 'undefined' ? window.innerWidth : totalBaseWidth);

         const excessSpace = Math.max(0, viewportWidth - totalBaseWidth);
-        const extraPerColumn =
-            equalWidthColumns.length > 0 ? excessSpace / equalWidthColumns.length : 0;
+        const extraPerColumn = customCount > 0 ? excessSpace / customCount : 0;
         const distributedWidth = minColumnWidth + extraPerColumn;

-        const userColumnsWithWidth = staticUserColumns.map((col) => ({
-            ...col,
-            width: distributedWidth
-        }));
+        const userColumnsWithWidth = staticUserColumns; // preserve stored widths

         const finalCustomColumns = customSuggestedColumns.map((col) => ({
             ...col,
             width: { min: distributedWidth }
         }));

1253-1253: Fix Svelte event bindings: use on: directive syntax.

Multiple event handlers use plain DOM attributes (onmousemove, onfocusin, onfocusout, onmouseenter, onclick) which don't bind correctly in Svelte. These will break hover tracking, focus handling, and click interactions.

Apply this diff:

     style:--overlay-icon-color="#fd366e99"
     style:--non-overlay-icon-color="--fgcolor-neutral-weak"
-    onmousemove={columnHoverMouseTracker}>
+    on:mousemove={columnHoverMouseTracker}>
                                             <div
                                                 class="cell-editor"
-                                                onfocusin={() => {
+                                                on:focusin={() => {
                                                     isInlineEditing = true;
                                                     showHeadTooltip = false;
                                                     resetSelectedColumn();
                                                     handlePreviousColumnsBorder(column.id);
                                                 }}
-                                                onfocusout={() => {
+                                                on:focusout={() => {
                                                     showHeadTooltip = true;
                                                     isInlineEditing = false;
                             <button
+                                type="button"
                                 class="column-selector-button"
                                 aria-label="Select column"
                                 data-column-hover={column.id}
-                                onmouseenter={() => {
+                                on:mouseenter={() => {
-                                onclick={() => {
+                                on:click={() => {
                                     if (isColumnInteractable) {

Also applies to: 1388-1388, 1394-1394, 1509-1509, 1524-1524


837-882: Fix TypeScript error: allow null for columnSchema.

Line 841 assigns null to a variable typed as SuggestedColumnSchema, causing a type error. The variable must be nullable since it's initialized to null and guarded at line 851.

Apply this diff:

     function deleteColumn(columnId: string) {
         if (!columnId) return;

         let columnIndex = -1;
-        let columnSchema: SuggestedColumnSchema = null;
+        let columnSchema: SuggestedColumnSchema | null = null;

         for (let index = 0; index < customColumns.length; index++) {

749-753: Uncomment selectedColumnName reset for complete state cleanup.

Line 752 leaves selectedColumnName commented out, but this variable is set in multiple places (lines 871, 912, 1102). This creates inconsistent state management.

Apply this diff:

     function resetSelectedColumn() {
         selectedColumnId = null;
         previousColumnId = null;
-        /*selectedColumnName = null;*/
+        selectedColumnName = null;
     }

1252-1252: Wrap CSS variable reference with var().

Line 1252 forwards a CSS custom property without using var(), resulting in the literal string "--fgcolor-neutral-weak" instead of the variable's value.

Apply this diff:

     style:--overlay-icon-color="#fd366e99"
-    style:--non-overlay-icon-color="--fgcolor-neutral-weak"
+    style:--non-overlay-icon-color="var(--fgcolor-neutral-weak)"
     on:mousemove={columnHoverMouseTracker}>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b7bf48 and 805e477.

📒 Files selected for processing (1)
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (37 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-30T07:41:06.679Z
Learnt from: ItzNotABug
PR: appwrite/console#2425
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:454-468
Timestamp: 2025-09-30T07:41:06.679Z
Learning: In `src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte`, the column suggestions API (console.suggestColumns) has a maximum limit of 7 columns returned, which aligns with the initial placeholder count of 7 in customColumns.

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-26T06:48:57.938Z
Learnt from: ItzNotABug
PR: appwrite/console#2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:629-631
Timestamp: 2025-09-26T06:48:57.938Z
Learning: In the Appwrite console codebase using appwrite.io/pink-svelte, the Icon component automatically handles CSS variable names passed to its color prop by internally wrapping them with var(). Therefore, passing '--some-css-variable' as a string to the Icon color prop works correctly without needing to manually wrap it with var().

Applied to files:

  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
🪛 GitHub Actions: Tests
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte

[warning] 1796-1796: Unused CSS selector ".custom-tooltip". See https://svelte.dev/e/css_unused_selector (svelte)


[warning] 1796-1796: Unused CSS selector ".custom-tooltip.show-tooltip". See https://svelte.dev/e/css_unused_selector (svelte)


[error] 121-121: 'tooltipTopPosition' is declared but its value is never read. (ts)


[error] 1113-1113: 'fadeSlide' is declared but its value is never read. (ts)

@ItzNotABug ItzNotABug merged commit eecf4e9 into main Nov 12, 2025
5 of 8 checks passed
@ItzNotABug ItzNotABug deleted the revamp-designs branch November 12, 2025 09:41
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.

3 participants