-
Notifications
You must be signed in to change notification settings - Fork 191
Feat: ai suggestions #2373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: ai suggestions #2373
Conversation
ConsoleProject ID: Sites (2)
Note Appwrite has a Discord community with over 16 000 members. |
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds an AI-powered column-suggestions feature and related plumbing: new Svelte components (empty, input, options, ai icon), a suggestions store with types/mapping/mock data, SDK exposure of Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/lib/actions/analytics.ts (1)
289-296
: Table analytics are mapped to Row event names.**These look like copy/paste leftovers and will skew analytics.
Apply:
- TableCreate = 'submit_row_create', - TableDelete = 'submit_row_delete', - TableUpdateName = 'submit_row_update_name', - TableUpdatePermissions = 'submit_row_update_permissions', - TableUpdateSecurity = 'submit_row_update_security', - TableUpdateEnabled = 'submit_row_update_enabled', - TableUpdateDisplayNames = 'submit_row_update_display_names', + TableCreate = 'submit_table_create', + TableDelete = 'submit_table_delete', + TableUpdateName = 'submit_table_update_name', + TableUpdatePermissions = 'submit_table_update_permissions', + TableUpdateSecurity = 'submit_table_update_security', + TableUpdateEnabled = 'submit_table_update_enabled', + TableUpdateDisplayNames = 'submit_table_update_display_names',src/lib/stores/sdk.ts (1)
101-108
: Likely bug: setMode(endpoint) and duplicate setEndpoint on clientRealtime.Passing an endpoint string to setMode is suspicious; duplicate setEndpoint on clientRealtime is redundant.
Apply:
if (!building) { - clientConsole.setEndpoint(endpoint).setProject('console'); - scopedConsoleClient.setMode(endpoint).setProject('console'); - - clientRealtime.setEndpoint(endpoint).setProject('console'); - clientProject.setEndpoint(endpoint).setMode('admin'); - clientRealtime.setEndpoint(endpoint).setProject('console'); + clientConsole.setEndpoint(endpoint).setProject('console'); + scopedConsoleClient.setEndpoint(endpoint).setProject('console'); + + clientRealtime.setEndpoint(endpoint).setProject('console'); + clientProject.setEndpoint(endpoint).setMode('admin'); }
🧹 Nitpick comments (22)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte (1)
56-59
: Consider extracting magic numbers into named constants.The hardcoded values
1rem
and70.5px
make the code less maintainable and harder to understand without the accompanying comments.Apply this diff to extract the magic numbers:
+ const BANNER_ADJUSTMENT = '1rem'; + const CONTAINER_HEIGHT = '70.5px'; + // If banner open, `-1rem` to adjust banner size, else `-70.5px`. // 70.5px is the size of the container of the banner holder and not just the banner! // Needed because things vary a bit much on how different browsers treat bottom layouts. - const bottomNavHeight = $derived(`calc(20% ${$bannerSpacing ? '- 1rem' : '- 70.5px'})`); + const bottomNavHeight = $derived(`calc(20% ${$bannerSpacing ? `- ${BANNER_ADJUSTMENT}` : `- ${CONTAINER_HEIGHT}`})`);src/lib/actions/analytics.ts (1)
128-141
: SSR safety for isTrackingAllowed.This references window.* without a browser guard. If invoked on the server it can throw.
Use the SvelteKit browser flag:
-export function isTrackingAllowed() { - if (ENV.TEST) { - return; - } - if (window.navigator?.doNotTrack) { - if (navigator.doNotTrack === '1' || navigator.doNotTrack === 'yes') { - return false; - } else { - return true; - } - } else { - return true; - } -} +export function isTrackingAllowed() { + if (!browser) return false; + if (ENV.TEST) return false; + const dnt = window.navigator?.doNotTrack; + return !(dnt === '1' || dnt === 'yes'); +}src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (2)
33-46
: Tighten ColumnInput typing.Consider constraining type to known column kinds to reduce downstream checks.
Example:
-export type ColumnInput = { +export type ColumnInput = { name: string; - type: string; + type: + | 'string' + | 'integer' + | 'double' + | 'boolean' + | 'datetime' + | 'enum' + | 'relationship';
48-65
: String constraints not mapped.If formatOptions.min/max are used for strings, they’re currently ignored.
Optionally extend mapping to include string length constraints if supported.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte (1)
65-65
: Faker column creation analytics: good placement.Import and event emission look correct and are behind global tracking gates.
Include count of generated columns for richer telemetry:
- trackEvent(Submit.ColumnCreate, { type: 'faker' }); + trackEvent(Submit.ColumnCreate, { type: 'faker', count: columns?.length ?? 0 });Also applies to: 260-261
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte (1)
153-154
: Manual column creation analytics: good; consider richer payload.Add selectedOption and required/array to analyze usage.
- trackEvent(Submit.ColumnCreate, { type: 'manual' }); + trackEvent(Submit.ColumnCreate, { + type: 'manual', + kind: selectedOption, + required: !!data.required, + array: !!data.array + });src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte (1)
146-153
: Switch to onTableCreated callback: OK.Flow is simpler and avoids custom events.
Consider emitting analytics on table creation:
onTableCreated={async (table) => { await invalidate(Dependencies.DATABASE); + // trackEvent(Submit.TableCreate, { tableId: table.$id }); await goto(
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte (2)
27-31
: Link helper text to the control.Tie the description to the switch for AT.
-<Typography.Text color="--fgcolor-neutral-secondary"> +<Typography.Text id="suggestions-help" color="--fgcolor-neutral-secondary"> Enable AI to suggest useful columns based on your table name </Typography.Text>
33-43
: Guard textarea binding against null and reflect busy state.Store currently initializes context to null; binding null can render "null". Also disable input while thinking.
<InputTextarea id="context" rows={3} maxlength={255} autofocus - bind:value={$tableColumnSuggestions.context} + bind:value={$tableColumnSuggestions.context ?? ''} + disabled={$tableColumnSuggestions.thinking} + aria-busy={$tableColumnSuggestions.thinking} placeholder="Optional: Add context to improve suggestions" />src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/icon/ai.svelte (2)
5-11
: Add accessible semantics to the SVG icon.If this icon is decorative, mark it as aria-hidden and non-focusable; if meaningful, expose a label. This avoids stray focus and improves screen reader output.
Apply one of the following:
-<Layout.Stack inline alignItems="center" justifyContent="center" class="ai-icon-holder"> - <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" fill="none"> +<Layout.Stack inline alignItems="center" justifyContent="center" class="ai-icon-holder"> + <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" fill="none" aria-hidden="true" focusable="false">Or, if meaningful:
- <svg ...> + <svg role="img" aria-label="AI" ...>
22-33
: Prevent gradient ID collisions across multiple instances.Hardcoded IDs like paint0_linear_3662_39953 can collide when rendering this component multiple times on a page. Prefix them to reduce risk.
- fill="url(#paint0_linear_3662_39953)" + fill="url(#ai_paint0_linear)" ... - fill="url(#paint1_linear_3662_39953)" + fill="url(#ai_paint1_linear)" ... - fill="url(#paint2_linear_3662_39953)" + fill="url(#ai_paint2_linear)" ... - <linearGradient id="paint0_linear_3662_39953" + <linearGradient id="ai_paint0_linear" ... - <linearGradient id="paint1_linear_3662_39953" + <linearGradient id="ai_paint1_linear" ... - <linearGradient id="paint2_linear_3662_39953" + <linearGradient id="ai_paint2_linear"Note: For full safety with repeated instances, consider accepting an optional idSuffix prop and appending it to these IDs.
Also applies to: 34-52, 7-21
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte (3)
163-164
: Remove unused results accumulator.results is never read.
- const results = []; ... - results.push(columnResult); + // no-opAlso applies to: 257-258
289-296
: Use stable keys in the list to avoid UI glitches.Keying by index can mis-bind inputs after removals. Key by column.key.
-{#each draft as column, index (index)} +{#each draft as column, index (column.key)} <Layout.Stack direction="row" justifyContent="space-between" alignItems="center"> - <InputText required id={'name-' + column.key} bind:value={draft[index].key} /> + <InputText required id={'name-' + column.key} bind:value={draft[index].key} /> <InputSelect required id={'type-' + column.key} value={getCurrentValue(draft[index])} options={columnTypeOptions} on:change={(event) => { draft[index] = normalizeColumnType(event.detail, draft[index]); draft = [...draft]; }} /> ... - {/each} + {/each}Note: Using index for array access is fine; the important change is the keyed identity.
Also applies to: 300-301, 312-316
271-279
: Harden error handling for unknown error types.error.message may be undefined. Prefer a safe fallback.
- } catch (error) { - trackError(error, Submit.ColumnCreate); + } catch (error) { + trackError(error, Submit.ColumnCreate); addNotification({ type: 'error', - message: error.message + message: error instanceof Error ? error.message : String(error) }); } finally {Apply similarly to the dismiss Confirm handler if you add error flows there.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (2)
244-251
: Safer error message extraction.Handle non-Error throws.
- } catch (error) { + } catch (error) { addNotification({ type: 'error', - message: error.message + message: error instanceof Error ? error.message : String(error) }); trackError(error, Submit.ColumnSuggestions);
311-321
: Minor: dead branch in header rendering.column.isAction is never set; branch is unreachable. Consider removing 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}src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte (6)
52-55
: Harden error handling.
e.message
assumes an Error. Normalize to an Error instance before extracting the message; also pass a real Error to analytics. Covered in the earlier diff.
68-69
: Keep state types consistent when clearing.You set
name = id = null;
butname
is a string elsewhere. Prefer resetting to empty string and only nulling the optional id.- name = id = null; + name = ''; + id = null;Additionally, adjust the declarations to reflect nullable types outside this hunk:
// Declarations (outside selected range) let id: string | null = $state(null); let error: string | null = $state(null);
14-19
: Make the new onTableCreated contract safe across call sites.If the callback is now required, ensure all parents are updated. Alternatively, make it optional (used with
?.
) and default it to a no-op.Would you like me to open a follow-up to sweep/adjust all usages?
122-122
: SuggestionsInput integration: verify store lifecycle.Given the store is shared, confirm it’s reset appropriately when the modal closes (either in
updateAndCleanup()
or the!showCreate
effect) so stale table data doesn’t leak into subsequent opens.
59-67
: Analytics payload: consider including table identifiers.You currently track only
{ customId: !!id }
. Consider addingtableId
andtableName
(or a hashed/length-limited version) for richer telemetry, if allowed by your analytics policy.
30-57
: Optional: centralize error message extraction.If used across the console, a tiny helper avoids repetition and keeps analytics consistent.
function toErr(e: unknown): Error { return e instanceof Error ? e : new Error(String(e)); }Use as:
const err = toErr(e); error = err.message; trackError(err, Submit.TableCreate);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
package.json
(1 hunks)src/lib/actions/analytics.ts
(1 hunks)src/lib/stores/sdk.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/icon/ai.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/index.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte
(4 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte
(3 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
(3 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
(0 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
(1 hunks)
💤 Files with no reviewable changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
🔇 Additional comments (12)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte (3)
7-7
: LGTM!The import of
bannerSpacing
from the headerAlert component is correctly added to support the new dynamic height calculation.
156-159
: Verify the layout behavior change from sticky to relative positioning.The layout stack has changed from sticky positioning (implied by previous implementation) to relative positioning with calculated height. This could affect the visual behavior and user experience.
Please test the following scenarios to ensure the layout behaves correctly:
- Navigation behavior when the banner is open vs closed
- Scroll behavior in the table content area
- Bottom navigation positioning at different viewport sizes
- Transition behavior when banner state changes
155-159
: Address TODO: account for $bannerSpacing in bottom nav layoutSearch produced no matches (ripgrep didn’t recognize .svelte), so I couldn’t verify existing banner/header-alert state — confirm whether a $bannerSpacing (or headerAlert) value exists and update Layout.Stack’s computed height to include that spacing so the bottom nav doesn’t overlap the banner. File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte Lines: 155-159.
src/lib/actions/analytics.ts (1)
281-282
: Enum addition looks good.Submit.ColumnSuggestions is consistent with existing naming and usage patterns.
src/lib/stores/sdk.ts (1)
129-131
: Exposing console on sdkForProject: OK — verify call sites
Matches the new suggestions flow; ensure usage is scoped to suggestions operations only. Automated search returned no matches; confirm there are no call sites using sdk.forProject(...).console. To re-check locally run:rg -nP --type=ts '\bsdk\.forProject\([^)]*\)\.console\b' -C2 rg -nP --type=ts '\bsdk\.forProject\([^)]*\)' -C2package.json (1)
25-30
: Pinned commit tarballs resolved — no peer warnings; verify pink-icons version mismatch
- pnpm install produced no peer warnings; svelte 5.25.3 satisfies peers for @appwrite.io/console, @appwrite.io/pink-svelte and @appwrite.io/pink-icons-svelte.
- Pinned URLs resolved to: @appwrite.io/console → 1.10.0 (pinned f08cb74); @appwrite.io/pink-icons-svelte → 2.0.0‑RC.1 and @appwrite.io/pink-svelte → 2.0.0‑RC.2 (pinned f4da718) — pink-svelte → pink-icons-svelte dependency is consistent.
- Remaining action: @appwrite.io/[email protected] pulls @appwrite.io/[email protected] while package.json pins @appwrite.io/[email protected], resulting in multiple versions; align pins or confirm this is intentional. (package.json, lines 25–30)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte (1)
227-233
: Suggestions flow integration looks correct.Conditional gating by $tableColumnSuggestions and table id is sound; the callback wiring to open the review modal is clear.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/index.ts (1)
1-4
: Barrel exports LGTM.Clear surface: store plus Empty/Input/Review re-exports. No issues spotted.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte (1)
173-229
: SDK method names and type→method mapping — verifyRepo search found createLineColumn (src/lib/helpers/faker.ts ~lines 58–60) and several createXColumn uses, but createFloatColumn was not found. Confirm whether the SDK exposes a different name for double columns (e.g., createDoubleColumn) and verify presence/naming of createIpColumn, createUrlColumn, and createEnumColumn; update the mapping where needed. Also applies to: 244-255
src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte (3)
96-96
: Modal submit wiring looks good.Binding
error
and delegating tocreateTable
is correct given the refactor.If Modal prevents resubmits on Enter while
creatingTable
is true, we’re covered. Otherwise, consider guardingcreateTable
entry whencreatingTable
is already true.
9-12
: Imports LGTM.Correctly pulls
ID
,Models
, Suggestions components, and database sub-navigation store.
14-19
: Repo-wide check — CreateTable migration verified; remaining on:created listeners are for other components
- onTableCreated is already used in src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte.
- Leftover on:created listeners exist but are for other create/modals (examples): src/routes/(console)/project-[region]-[project]/messaging/topics/+page.svelte, src/routes/(console)/project-[region]-[project]/updateVariables.svelte, src/routes/(console)/project-[region]-[project]/settings/webhooks/create/step2.svelte, src/routes/(console)/project-[region]-[project]/storage/+page.svelte, src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte, src/routes/(console)/project-[region]-[project]/databases/+page.svelte.
Leave as-is unless you intend to rename those components' created events to component-specific callbacks.
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Outdated
Show resolved
Hide resolved
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte
Show resolved
Hide resolved
...onsole)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
Outdated
Show resolved
Hide resolved
...onsole)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
Outdated
Show resolved
Hide resolved
...onsole)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
Outdated
Show resolved
Hide resolved
...es/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
Show resolved
Hide resolved
...routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte
Show resolved
Hide resolved
...routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte
Outdated
Show resolved
Hide resolved
...routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte
Show resolved
Hide resolved
...console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
🧹 Nitpick comments (5)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte (5)
289-289
: Use stable key for list rendering.Key by
column.key
to avoid DOM reuse bugs when reordering/removing.-{#each draft as column, index (index)} +{#each draft as column, index (column.key)}
128-153
: Defaults for geometry types are generated but never sent.Either pass defaults if the API supports them, or stop generating them to avoid confusion and dead code.
Also applies to: 244-254
271-276
: Harden error handling for unknown thrown values.Avoid assuming
error.message
exists.- } catch (error) { - trackError(error, Submit.ColumnCreate); - addNotification({ - type: 'error', - message: error.message - }); + } catch (error) { + // trackError event name updated in a separate diff + const errMsg = error instanceof Error ? error.message : String(error); + addNotification({ + type: 'error', + message: errMsg + });
165-258
: Atomicity/partial-failure behavior.If one column fails mid-loop, prior columns remain created. Consider batching, transactional API (if available), or
allSettled
with a summary UI so users know what succeeded vs. failed.
76-94
: Set size per format (email/url/ip) to sensible maxima.Improve UX and reduce later migrations: email ≈320, URL ≈2048, IP ≈64; fall back to 255.
- updated.size = option.format === 'ip' ? 64 : 255; + if (option.format === 'email') { + updated.size = 320; + } else if (option.format === 'url') { + updated.size = 2048; + } else if (option.format === 'ip') { + updated.size = 64; + } else { + updated.size = 255; + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
(1 hunks)
⏰ 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 (5)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte (5)
83-85
: Verify faker API availability for IP generation.Confirm
faker.internet.ip()
exists in the pinned faker version; otherwise useipv4()
/ipv6()
or custom helper.
17-23
: Align prop types with runtime nulls and guard initial state.
columns
is set tonull
on dismiss/confirm but typed as array;draft/original
initialization will break ifcolumns
is null.- let { - show = $bindable(), - columns = $bindable() - }: { - show: boolean; - columns: SuggestedColumnSchema[]; - } = $props(); + let { + show = $bindable(), + columns = $bindable<SuggestedColumnSchema[] | null>() + }: { + show: boolean; + columns: SuggestedColumnSchema[] | null; + } = $props(); - let draft = $state(columns); + let draft = $state((columns ?? []) as SuggestedColumnSchema[]); @@ - const original = structuredClone(columns); + const original = structuredClone(columns ?? []);Also applies to: 25-31, 262-264, 347-351
60-66
: Defensive guard when option not found in columnOptions.Avoid crashes on unknown
newValue
.- const option = columnOptions.find((opt) => (opt.format || opt.type) === newValue); + const option = columnOptions.find((opt) => (opt.format || opt.type) === newValue); + if (!option) { + return column; // no-op if value not recognized + }Also applies to: 75-76, 155-156
176-196
: Enum creation must use provided elements and validate presence.Currently sends
elements: []
, creating a useless enum and likely failing server-side.- case 'enum': - columnResult = await client.tablesDB.createEnumColumn({ - ...baseParams, - elements: [] - }); + case 'enum': + if (!Array.isArray(column.elements) || column.elements.length === 0) { + throw new Error(`Enum column "${column.key}" requires at least one element.`); + } + columnResult = await client.tablesDB.createEnumColumn({ + ...baseParams, + elements: column.elements + });
303-306
: Confirm Input.Select change payload shape. Input.Select is from @appwrite.io/pink-svelte (not in the repo); several local inputs (e.g., inputSearch, inputPoint) dispatch 'change' with the raw value in event.detail. Verify the external component’s change event — if it emits { value } update the handler in src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte (around lines 303–306) to use event.detail.value instead of event.detail.
...onsole)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
Outdated
Show resolved
Hide resolved
...onsole)/project-[region]-[project]/databases/database-[database]/(suggestions)/review.svelte
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
🧹 Nitpick comments (4)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (1)
135-135
: Avoid brittle slice() — filter out relationship explicitly.Assumes the last option is always Relationship; order changes would break this.
-export const basicColumnOptions = columnOptions.slice(0, -1); +export const basicColumnOptions = columnOptions.filter((opt) => opt.type !== 'relationship');src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte (1)
5-13
: DefaultonShowStateChanged
should beundefined
(type-safe).Initializer
= null
is incompatible with the declared function type.let { children, tooltipChildren, - onShowStateChanged = null + onShowStateChanged = undefined }: { children: Snippet<[toggle: (event: Event) => void]>; tooltipChildren: Snippet<[toggle: (event: Event) => void]>; onShowStateChanged?: (showing: boolean) => void; } = $props();src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (2)
591-591
: Use stable keys for each blocks.Index keys cause unnecessary re-renders when columns change.
-{#each spreadsheetColumns as column, index (index)} +{#each spreadsheetColumns as column (column.id)}
327-334
: Type-safe error handling incatch
.
error.message
onunknown
may cause TS errors; guard it.- } catch (error) { + } catch (error: unknown) { addNotification({ type: 'error', - message: error.message + message: error instanceof Error ? error.message : String(error) }); trackError(error, Submit.ColumnSuggestions);- } catch (error) { + } catch (error: unknown) { trackError(error, Submit.ColumnCreate); addNotification({ type: 'error', - message: error.message + message: error instanceof Error ? error.message : String(error) }); } finally {Also applies to: 486-491
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
🧰 Additional context used
🧬 Code graph analysis (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts (1)
columnOptions
(76-198)
⏰ 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 (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts (1)
7-13
: Fix type/store mismatch forcontext
andtable
(nulls).
context
andtable
are initialized withnull
but the types disallow it. This still causes TS errors.Apply this diff:
export type TableColumnSuggestions = { enabled: boolean; thinking: boolean; - context?: string | undefined; + context: string | null; /* for safety when in tables page */ - table: { - id: string; - name: string; - }; + table: { + id: string; + name: string; + } | null; }; export const tableColumnSuggestions = writable<TableColumnSuggestions>({ enabled: false, context: null, thinking: false, table: null });Also applies to: 27-32
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Show resolved
Hide resolved
...es/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
Show resolved
Hide resolved
fix: clicks not working on mobile.
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/routes/(console)/project-[region]-[project]/storage/+page.svelte (1)
56-56
: Pagination name mismatch.The pagination component shows "Databases" but this is the storage page for buckets. This should be "Buckets" to match the actual content.
- <PaginationWithLimit - name="Databases" - limit={data.limit} - offset={data.offset} - total={data.buckets.total} /> + <PaginationWithLimit + name="Buckets" + limit={data.limit} + offset={data.offset} + total={data.buckets.total} />src/routes/(console)/project-[region]-[project]/databases/+page.svelte (1)
17-17
: Fix CI: remove unusedLayout
import.TS error: 'Layout' is declared but its value is never read. Remove it to unblock the pipeline.
Apply this diff:
-import { Icon, Layout } from '@appwrite.io/pink-svelte'; +import { Icon } from '@appwrite.io/pink-svelte';
🧹 Nitpick comments (6)
src/routes/(console)/project-[region]-[project]/databases/+page.svelte (1)
49-60
: Avoid two-way binding to PageData; bind to a localview
variable instead.Mutating
data.view
couples UI state to thePageData
prop and can be brittle with SvelteKit updates. Bind to a localview
and use that for the grid/table toggle.Apply this diff within this block:
- bind:view={data.view} + bind:view={view}Add outside this range (in <script>):
let view = data.view;Also update the conditional to use the local variable (outside this range):
{#if view === 'grid'} <Grid {data} bind:showCreate /> {:else} <Table {data} /> {/if}Please also verify that changing the view updates URL/state as intended (back/forward navigation and reload preserve the selection).
src/routes/(console)/project-[region]-[project]/+layout.svelte (1)
126-137
: Confirm mobile behavior: element stays fixed; is that intended?The base rule uses
position: fixed; right: 0; bottom: 0;
. The media query no longer overrides position (previously likelyrelative
). On small screens this can overlay content. If you intended a full‑width bottom bar, consider anchoring both sides; if you intended it to flow with content, restoreposition: relative
.Option A (keep fixed, span full width):
@media (max-width: 768px) { .layout-level-progress-bars { width: 100%; + left: 0; + right: 0; + width: auto; /* spans between left/right */ + box-sizing: border-box; align-items: center; } }Option B (flow with document, no overlay):
@media (max-width: 768px) { .layout-level-progress-bars { - width: 100%; + position: relative; + right: auto; + bottom: auto; + width: 100%; + box-sizing: border-box; align-items: center; } }Also applies to: 139-144
src/lib/layout/notifications.svelte (2)
31-33
: Avoid magic 3.25px; align spacing with tokens and support RTL3.25px looks accidental and misaligns mobile spacing (was 12px). Use a design token or at least 12px, and prefer logical properties for RTL.
Apply:
- right: 3.25px; + right: 12px; /* fallback for older browsers */ + inset-inline-end: 12px;Optional: if a z-index token exists (e.g., var(--z-toast)), consider using it instead of a hardcoded 1001 to avoid stacking conflicts with new suggestion popovers.
7-7
: Gate rendering to avoid empty fixed containerRender only when there are notifications to prevent an empty fixed section in the DOM.
Apply:
-{#if $notifications} +{#if $notifications?.length}src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte (2)
62-66
: Always invalidate files, even if removing from uploader failsAwaiting
uploader.removeFile
introduces a failure path whereinvalidate
might not run. Wrap in try/finally to keep the UI fresh regardless of errors.async function fileDeleted(event: CustomEvent<Models.File>) { showDelete = false; - await uploader.removeFile(event.detail); - await invalidate(Dependencies.FILES); + try { + await uploader.removeFile(event.detail); + } finally { + await invalidate(Dependencies.FILES); + } }
154-154
: Avoid passingundefined
forwidth
; omit the key conditionallyPrevents accidental overriding of Table defaults with
undefined
.- { id: 'filename', width: $isSmallViewport ? 24 : undefined }, + { id: 'filename', ...($isSmallViewport ? { width: 24 } : {}) },Also, please confirm that
24
matches the Table API’s expected unit (e.g., px vs. flex weight). If it’s px and intended to be responsive, consider a min width object instead:{ width: { min: 140 } }
.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
package.json
(1 hunks)src/lib/layout/notifications.svelte
(2 hunks)src/routes/(console)/project-[region]-[project]/+layout.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/+page.svelte
(2 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/storage/+page.svelte
(2 hunks)src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
- package.json
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte
🧰 Additional context used
🪛 GitHub Actions: Tests
src/routes/(console)/project-[region]-[project]/databases/+page.svelte
[error] 17-17: 'Layout' 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 (7)
src/routes/(console)/project-[region]-[project]/storage/+page.svelte (2)
7-7
: Clean import refactoring aligns with ResponsiveContainerHeader migration.The import changes properly remove unused components (SearchQuery, ViewSelector, Layout) and add the new ResponsiveContainerHeader. The Icon import is correctly updated to only import what's needed.
Also applies to: 9-9, 15-15
35-46
: ResponsiveContainerHeader implementation looks good.The migration from the old two-column header layout to ResponsiveContainerHeader is well-implemented. The component properly:
- Binds the view to
data.view
for grid/table switching- Includes search functionality with appropriate placeholder
- Maintains the conditional Create bucket button for authorized users
- Uses proper event binding and icon integration
src/routes/(console)/project-[region]-[project]/databases/+page.svelte (2)
5-5
: Consolidated component imports look good.Empty and PaginationWithLimit are used correctly below.
7-7
: Header refactor import looks good.Container + ResponsiveContainerHeader import path and names look correct.
src/lib/layout/notifications.svelte (2)
4-4
: LGTM: import order tweak onlyNo functional impact.
38-41
: LGTM: desktop offsetChange preserves intended spacing.
src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte (1)
36-36
: Viewport store import: LGTM — SSR-safeupdateViewport (src/lib/stores/viewport.ts) guards with typeof window !== 'undefined' before calling window.matchMedia, so no hydration mismatch expected.
There was a problem hiding this 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
🧹 Nitpick comments (3)
src/routes/(console)/project-[region]-[project]/databases/+page.svelte (1)
49-61
: Avoid two‑way binding directly todata.view
; use a local stateBinding to
data.view
mutates page data and may conflict with how SvelteKit treats load data. Prefer a localview
variable and drive the UI from it.Apply this diff within this file:
--- a/+page.svelte +++ b/+page.svelte @@ export let data: PageData; let showCreate = false; +let view = data.view; const project = page.params.project; @@ - <ResponsiveContainerHeader + <ResponsiveContainerHeader hasSearch {columns} - bind:view={data.view} + bind:view={view} searchPlaceholder="Search by name or ID">And update the conditional usage below to reference
view
(outside the header block):- {#if data.databases.total} - {#if data.view === 'grid'} + {#if data.databases.total} + {#if view === 'grid'} <Grid {data} bind:showCreate /> {:else} <Table {data} /> {/if}If the header is responsible for syncing the
view
to the URL, no further changes are needed. Otherwise, persistview
via query params to survive reloads.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte (2)
31-31
: Avoid side effects in markup for onShowStateChanged.Inline invocation runs on every render. Prefer emitting on open/close events from Popover (if supported) or gate calls via a reactive effect keyed by (showing || showSheet) to avoid redundant callbacks.
43-45
: Make tooltip width responsive.Prevent overflow on narrow viewports by capping to viewport width.
- <div let:toggle slot="tooltip" style:width="480px" style:padding="16px"> + <div let:toggle slot="tooltip" style:width="min(calc(100vw - 32px), 480px)" style:padding="16px">
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
package.json
(1 hunks)src/routes/(console)/project-[region]-[project]/+layout.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/+page.svelte
(3 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/index.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte
(1 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]/layout/sidesheet.svelte
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/sidesheet.svelte
🚧 Files skipped from review as they are similar to previous changes (5)
- src/routes/(console)/project-[region]-[project]/+layout.svelte
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/index.ts
- package.json
- 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 (3)
src/routes/(console)/project-[region]-[project]/databases/+page.svelte (3)
5-5
: LGTM on consolidated components importNo issues with
Empty
andPaginationWithLimit
import.
17-17
: Icon usage looks correctUsing
Icon
withIconPlus
andslot="start"
aligns with Pink Svelte patterns.
7-7
: Confirm ResponsiveContainerHeader bind API and view value semanticsCould not locate ResponsiveContainerHeader.svelte in the repo; unable to verify automatically. Confirm manually:
- Exports a bindable view:
export let view
and updates it internally (required forbind:view
).- Emits the exact enum values this page expects:
'grid'
and'table'
(not'list'
or different strings).Location: import in src/routes/(console)/project-[region]-[project]/databases/+page.svelte (line 7)
...nsole)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte
Show resolved
Hide resolved
… quite annoying when using stage!
There was a problem hiding this 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
🧹 Nitpick comments (1)
.env.example (1)
6-7
: Keep.env.example
keys sorted to satisfy linting.
dotenv-linter
expects the public keys in alphabetical order. Please move the newPUBLIC_GROWTH_ENDPOINT
andPUBLIC_CONSOLE_EMAIL_VERIFICATION
entries abovePUBLIC_STRIPE_KEY
, and add a trailing newline so the lint warning drops.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.env.example
(1 hunks)src/lib/components/alerts/emailVerificationBanner.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
🧰 Additional context used
🪛 dotenv-linter (3.3.0)
.env.example
[warning] 6-6: [UnorderedKey] The PUBLIC_GROWTH_ENDPOINT key should go before the PUBLIC_STRIPE_KEY key
(UnorderedKey)
[warning] 7-7: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 7-7: [UnorderedKey] The PUBLIC_CONSOLE_EMAIL_VERIFICATION key should go before the PUBLIC_CONSOLE_FEATURE_FLAGS key
(UnorderedKey)
⏰ 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/lib/system.ts (1)
13-15
: Normalize env flag before comparison
$env/dynamic/public
hands us raw strings, so"TRUE"
(or trailing whitespace from certain platforms) would currently flip the flag off. Normalizing before the comparison keeps the toggle resilient across environments.- EMAIL_VERIFICATION: env.PUBLIC_CONSOLE_EMAIL_VERIFICATION === 'true' + EMAIL_VERIFICATION: + (env.PUBLIC_CONSOLE_EMAIL_VERIFICATION ?? '').trim().toLowerCase() === 'true'
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/lib/components/alerts/emailVerificationBanner.svelte
(1 hunks)src/lib/system.ts
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/lib/system.ts (1)
build.js (1)
env
(7-7)
⏰ 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 (1)
src/lib/components/alerts/emailVerificationBanner.svelte (1)
15-22
: Gating logic looks solidPulling the parsed boolean from
VARS
resolves the previous truthy-string issue and keeps the banner hidden unless explicitly enabled.
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte
(3 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
(0 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte
(3 hunks)
💤 Files with no reviewable changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
🚧 Files skipped from review as they are similar to previous changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ItzNotABug
PR: appwrite/console#2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:536-552
Timestamp: 2025-09-25T04:21:57.051Z
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.
📚 Learning: 2025-09-25T04:21:57.051Z
Learnt from: ItzNotABug
PR: appwrite/console#2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte:536-552
Timestamp: 2025-09-25T04:21:57.051Z
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]/(suggestions)/empty.svelte
📚 Learning: 2025-09-25T04:33:19.616Z
Learnt from: ItzNotABug
PR: appwrite/console#2373
File: src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte:28-33
Timestamp: 2025-09-25T04:33:19.616Z
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]/(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). (1)
- GitHub Check: e2e
🔇 Additional comments (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (1)
327-337
: Stop mutating the suggestions store in place.Directly setting
$tableColumnSuggestions.*
bypasses the store’sset/update
, so subscribers never see the new value (e.g., the “thinking” state/overlay never clears). UsetableColumnSuggestions.update
(orset
) everywhere instead.function resetSuggestionsStore(fullReset: boolean = true) { - if (fullReset) { - // these are referenced in - // `table-[table]/+page.svelte` - $tableColumnSuggestions.table = null; - $tableColumnSuggestions.enabled = false; - } - - $tableColumnSuggestions.context = null; - $tableColumnSuggestions.thinking = false; + tableColumnSuggestions.update((state) => { + const next = { + ...state, + context: null, + thinking: false + }; + + if (fullReset) { + next.table = null; + next.enabled = false; + } + + return next; + }); } async function suggestColumns() { - $tableColumnSuggestions.thinking = true; + tableColumnSuggestions.update((state) => ({ ...state, thinking: true })); let suggestedColumns: { total: number; columns: ColumnInput[]; @@ - } finally { - resetSuggestionsStore(false); - } + } finally { + resetSuggestionsStore(false); + } } @@ onSubmit={() => { customColumns = []; resetSuggestionsStore(); }}>Also applies to: 345-346, 392-393, 845-847
...ject-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces AI-powered column suggestions for database tables, allowing users to get intelligent column recommendations based on table names and optional context. The feature includes a toggleable interface, editable suggestions, and responsive design patterns.
- Smart column suggestions with AI-powered recommendations
- Responsive header components for databases and storage pages
- Enhanced analytics tracking for column-related actions
Reviewed Changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/ | New AI suggestions feature files including store, components, and empty state |
src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte | Updated table creation to support AI suggestions workflow |
src/routes/(console)/project-[region]-[project]/databases/+page.svelte | Replaced manual header layout with ResponsiveContainerHeader |
src/routes/(console)/project-[region]-[project]/storage/+page.svelte | Applied ResponsiveContainerHeader for consistency |
src/lib/actions/analytics.ts | Added column suggestions tracking event |
package.json | Updated dependencies for AI suggestions support |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
...es/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
Outdated
Show resolved
Hide resolved
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Outdated
Show resolved
Hide resolved
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Show resolved
Hide resolved
update: change border colors for custom columns.
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/lib/layout/progress.svelte (1)
2-107
: Release the store subscription on destroy
navigationCancelled.subscribe
keeps the callback alive even after this layout is torn down, preventing the component from being garbage‑collected and risking state mutations on a dead instance. Wrap the subscription with anonDestroy
teardown (or switch to the$navigationCancelled
reactive shorthand) so the layout cleans up after itself.Apply this diff to add the teardown:
import { afterNavigate, beforeNavigate } from '$app/navigation'; + import { onDestroy } from 'svelte'; @@ - navigationCancelled.subscribe((cancelled) => { + const unsubscribeNavigationCancelled = navigationCancelled.subscribe((cancelled) => { if (cancelled) { complete(); navigationCancelled.set(false); } }); + + onDestroy(() => { + unsubscribeNavigationCancelled(); + });src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte (1)
30-71
: Fix create flow gating and success timing
creatingTable
never flips to true, so the new disabled buttons / loader never engage and the handler can be invoked repeatedly. In addition,updateAndCleanup()
fires beforeonTableCreated
resolves, so any downstream failure still shows a success toast and triggers navigation updates before the error is surfaced. Move the success work after the callback and ensure we gate/clean up around the async call.- async function createTable() { - error = null; - try { + async function createTable() { + if (creatingTable) { + return; + } + + creatingTable = true; + error = null; + try { const table = await sdk .forProject(page.params.region, page.params.project) .tablesDB.createTable({ databaseId, tableId: id ? id : ID.unique(), name }); tableColumnSuggestions.update((store) => ({ ...store, table: { id: table.$id, name: table.name } })); - updateAndCleanup(); - await onTableCreated(table); + updateAndCleanup(); name = id = null; showCreate = false; - creatingTable = false; } catch (e) { - error = e.message; - trackError(e, Submit.TableCreate); - } + error = e instanceof Error ? e.message : String(e); + trackError(e, Submit.TableCreate); + } finally { + creatingTable = false; + } }
🧹 Nitpick comments (9)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (5)
623-623
: Throttle window scroll handler to reduce layout thrash.
on:scroll={recalcAll}
runs on every scroll tick and does DOM reads/writes. Use the throttled variant as you already do on the inner scroller.Apply:
-<svelte:window on:resize={recalcAll} on:scroll={recalcAll} on:beforeunload={handleBeforeUnload} /> +<svelte:window on:resize={recalcAll} on:scroll={recalcAllThrottled} on:beforeunload={handleBeforeUnload} />
126-135
: Hide overlay when there are no custom columns.You force
rangeOverlayEl.style.display = 'block'
before immediately returning for the empty state, leaving the overlay visible across the grid. Hide it for the empty state.Apply:
- if (rangeOverlayEl) { - rangeOverlayEl.style.display = 'block'; - } - - if (customColumns.length === 0) { + if (customColumns.length === 0) { + if (rangeOverlayEl) { + rangeOverlayEl.style.display = 'none'; + } spreadsheetContainer.style.setProperty('--group-left', '40px'); spreadsheetContainer.style.setProperty('--group-width', '100%'); return; } + if (rangeOverlayEl) { + rangeOverlayEl.style.display = 'block'; + }
495-496
: Remove unusedresults
accumulator.
results
is never read; avoid unused work.Apply:
- const results = []; + // no-op- results.push(columnResult); + // no-opAlso applies to: 589-589
506-587
: Handle unsupported column types defensively.If an unexpected
column.type
slips through,columnResult
remains undefined and follow-up logic can break. Fail fast with a clear message.Apply:
switch (column.type) { @@ case 'polygon': columnResult = await client.tablesDB.createPolygonColumn(baseParams); break; + default: + addNotification({ + type: 'error', + message: `Unsupported column type: ${String(column.type)}` + }); + continue; }
437-440
: Guard error messaging.
error.message
may be undefined. Fall back toString(error)
.Apply:
- addNotification({ - type: 'error', - message: error.message - }); + addNotification({ + type: 'error', + message: (error && (error as any).message) || String(error) + });Repeat the same change in the create flow catch.
Also applies to: 603-605
src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte (4)
6-8
: Decouple banner state from a component importImporting
bannerSpacing
directly from a.svelte
component tightly couples modules and risks SSR/hydration side effects or circular deps. Prefer exporting this as a store from a plain module (e.g.,$lib/stores/banner.ts
) that both components consume.Can you confirm
headerAlert.svelte
exportsbannerSpacing
from module context (no DOM access on import) so SSR stays safe?
57-61
: Avoid magic number and negative heights; clamp the computed heightHard-coding
70.5px
is brittle andcalc(20% - …)
can go negative on short viewports. Clamp the height to a safe range.Apply this diff:
-const bottomNavHeight = $derived(`calc(20% ${$bannerSpacing ? '- 1rem' : '- 70.5px'})`); +const bottomNavHeight = $derived( + `clamp(0px, calc(20% ${$bannerSpacing ? '- 1rem' : '- 70.5px'}), 40vh)` +);Optionally, replace the magic number with a CSS var provided by the banner (e.g.,
var(--banner-offset, 0px)
) rather than a JS conditional.
148-156
: Ensure createTableRequest can retrigger; verify id vs $id
- If the consumer doesn’t reset the boolean, setting
$createTableRequest = true
again won’t fire observers. Toggle or ensure the consumer resets tofalse
after handling.- Check
tableColumnSuggestions.table?.id
vs the rest of the app using$id
for tables to avoid mismatches.If a toggle is acceptable, apply:
- $createTableRequest = true; + $createTableRequest = !$createTableRequest;Otherwise, confirm the handler resets the flag so subsequent clicks work.
163-167
: Relative + bottom offset is fragile; prefer flow spacingUsing
position: relative; bottom: 1rem;
can cause layout jitter across browsers. Prefer flow-based spacing (margin/padding) with the computed height.Apply this diff:
- style="bottom: 1rem; position: relative; height: {bottomNavHeight}" + style="margin-block-end: 1rem; height: {bottomNavHeight}"Please sanity-check Safari/Firefox with and without the banner visible.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/lib/layout/progress.svelte
(2 hunks)src/lib/stores/navigation.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte
(4 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte
(4 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: ItzNotABug
PR: appwrite/console#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.
📚 Learning: 2025-09-25T04:33:19.632Z
Learnt from: ItzNotABug
PR: appwrite/console#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]/createTable.svelte
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-25T04:21:57.071Z
Learnt from: ItzNotABug
PR: appwrite/console#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]/createTable.svelte
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
📚 Learning: 2025-09-08T13:20:47.308Z
Learnt from: ItzNotABug
PR: appwrite/console#2316
File: src/routes/(console)/project-[region]-[project]/functions/create-function/deploy/+page.svelte:29-29
Timestamp: 2025-09-08T13:20:47.308Z
Learning: The Form.svelte component in the Appwrite console creates a FormContext with isSubmitting as writable(false) and expects consumers to work with Svelte writable stores, not plain booleans.
Applied to files:
src/lib/stores/navigation.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). (2)
- GitHub Check: build
- GitHub Check: e2e
🔇 Additional comments (4)
src/lib/stores/navigation.ts (1)
1-3
: Store initialization looks correct
navigationCancelled
is typed asWritable<boolean>
with the expected initial state, matching how other Svelte stores are usually declared.src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (2)
592-600
: LGTM on success path state handling.Relying on
await invalidate(Dependencies.TABLE)
to destroy this view and reset UI is correct here; no manual cleanup needed. Based on learnings.
381-389
: Don’t mutate Svelte stores directly; use update/set.Directly changing
$tableColumnSuggestions
fields won’t notify subscribers; UI can desync. This was flagged earlier.Apply:
- if (fullReset) { - // these are referenced in - // `table-[table]/+page.svelte` - $tableColumnSuggestions.table = null; - $tableColumnSuggestions.enabled = false; - } - - $tableColumnSuggestions.context = null; - $tableColumnSuggestions.thinking = false; + if (fullReset) { + tableColumnSuggestions.update((s) => ({ + ...s, + table: null, + enabled: false + })); + } + tableColumnSuggestions.update((s) => ({ + ...s, + context: null, + thinking: false + }));- $tableColumnSuggestions.thinking = true; + tableColumnSuggestions.update((s) => ({ ...s, thinking: true }));Also applies to: 397-397
src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte (1)
31-31
: LGTM: suggestions store imports
createTableRequest
andtableColumnSuggestions
imports align with the new flow and are used correctly below.
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Show resolved
Hide resolved
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-25T04:21:57.071Z
Learnt from: ItzNotABug
PR: appwrite/console#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]/(suggestions)/empty.svelte
📚 Learning: 2025-09-25T04:33:19.632Z
Learnt from: ItzNotABug
PR: appwrite/console#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]/(suggestions)/empty.svelte
📚 Learning: 2025-09-26T06:48:57.915Z
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.915Z
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
⏰ 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 (3)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte (3)
380-389
: Do not mutate Svelte store; use update/set for $tableColumnSuggestions.Direct mutations on
$tableColumnSuggestions
won’t notify subscribers; UI can desync.Apply:
- if (fullReset) { - // these are referenced in - // `table-[table]/+page.svelte` - $tableColumnSuggestions.table = null; - $tableColumnSuggestions.enabled = false; - } - - $tableColumnSuggestions.context = null; - $tableColumnSuggestions.thinking = false; + tableColumnSuggestions.update((s) => { + if (fullReset) { + return { + ...s, + table: null, + enabled: false, + context: null, + thinking: false + }; + } + return { ...s, context: null, thinking: false }; + });Also applies to other direct mutations in this file. Based on learnings.
397-397
: Do not mutate store value; use update to set thinking=true.Ensure subscribers are notified.
Apply:
- $tableColumnSuggestions.thinking = true; + tableColumnSuggestions.update((s) => ({ ...s, thinking: true }));
746-766
: Prevent runtime crash: guard cell-editor when columnObj is undefined.Non-custom columns render the editor and bind
columnObj.key
whilecolumnObj
is undefined.Apply:
- <svelte:fragment slot="cell-editor"> - {#if !$isTabletViewport} + <svelte:fragment slot="cell-editor"> + {#if isColumnInteractable && !$isTabletViewport && columnObj} <div class="cell-editor"> <InputText id="key" autofocus required bind:value={columnObj.key} pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$"> <svelte:fragment slot="end"> {#if columnIcon} <Icon size="s" icon={columnIcon} color={columnIconColor} /> {/if} </svelte:fragment> </InputText> </div> {/if} </svelte:fragment>
...console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte (1)
166-194
: Bottom nav height miscalculates when header alert is visible
bannerSpacing
holds the actual pixel offset (e.g.0
vs48
) emitted by the header-alert component. Treating it as a boolean means we always pick- 1rem
even when the alert is hidden (because"0"
is still truthy), so the bottom nav jumps up by 16px and overlaps the table list. Use the numeric spacing instead of a boolean toggle.Apply this diff so the spacing mirrors the real banner height:
- const bottomNavHeight = $derived(`calc(20% ${$bannerSpacing ? '- 1rem' : '- 70.5px'})`); + const bottomNavHeight = $derived(() => { + const spacing = Number.parseFloat($bannerSpacing) || 0; + return `calc(20% - ${spacing}px)`; + });(If
bannerSpacing
can already be a number, drop theparseFloat
.)
🧹 Nitpick comments (1)
.env.example (1)
6-8
: **Consider organizing environment variables alphabetically.**The static analysis suggests organizing environment variables alphabetically and adding a blank line at the end. While prefixing variables with the project or service name to avoid conflicts is a good practice and organizing environment variables "improves the organization", alphabetical ordering isn't strictly required for functionality. The content of these environment variables is appropriate for the AI suggestions feature.Apply this diff to organize variables alphabetically and add the missing blank line:
PUBLIC_CONSOLE_MODE=self-hosted PUBLIC_CONSOLE_FEATURE_FLAGS= PUBLIC_APPWRITE_MULTI_REGION=false PUBLIC_APPWRITE_ENDPOINT=http://localhost/v1 -PUBLIC_STRIPE_KEY= -PUBLIC_GROWTH_ENDPOINT= PUBLIC_CONSOLE_EMAIL_VERIFICATION=false PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS=true +PUBLIC_GROWTH_ENDPOINT= +PUBLIC_STRIPE_KEY= +
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.env.example
(1 hunks).github/workflows/publish.yml
(4 hunks)Dockerfile
(2 hunks)src/lib/system.ts
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
(1 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/subNavigation.svelte
(4 hunks)src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
(0 hunks)
💤 Files with no reviewable changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte
🚧 Files skipped from review as they are similar to previous changes (1)
- src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte
🧰 Additional context used
🧬 Code graph analysis (1)
src/lib/system.ts (1)
build.js (1)
env
(7-7)
🪛 dotenv-linter (3.3.0)
.env.example
[warning] 6-6: [UnorderedKey] The PUBLIC_GROWTH_ENDPOINT key should go before the PUBLIC_STRIPE_KEY key
(UnorderedKey)
[warning] 7-7: [UnorderedKey] The PUBLIC_CONSOLE_EMAIL_VERIFICATION key should go before the PUBLIC_CONSOLE_FEATURE_FLAGS key
(UnorderedKey)
[warning] 8-8: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 8-8: [UnorderedKey] The PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS key should go before the PUBLIC_CONSOLE_MODE key
(UnorderedKey)
⏰ 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 (8)
Dockerfile (2)
26-26
: LGTM!Build argument properly added for mock AI suggestions feature flag.
38-38
: LGTM!Environment variable correctly forwards the build argument to runtime.
.github/workflows/publish.yml (4)
44-44
: LGTM!Mock AI suggestions disabled for production cloud builds as expected.
85-85
: LGTM!Mock AI suggestions disabled for cloud-stage builds as expected.
123-123
: LGTM!Mock AI suggestions disabled for self-hosted builds as expected.
162-162
: LGTM!Mock AI suggestions disabled for cloud-no-regions builds as expected.
src/lib/system.ts (2)
13-13
: Variable rename appears to be part of broader changes.The variable name change from
STRIPE_KEY
toPUBLIC_STRIPE_KEY
aligns with the existing naming convention for public environment variables.
14-15
: LGTM! Environment flags properly implemented.The new boolean flags are correctly derived from environment variables with appropriate defaults:
EMAIL_VERIFICATION
defaults tofalse
when not setMOCK_AI_SUGGESTIONS
defaults totrue
when not set, which is appropriate for development
What does this PR do?
This.
Suggestions.UI.mp4
Test Plan
Manual.
Related PRs and Issues
N/A.
Have you read the Contributing Guidelines on issues?
Yes.
Summary by CodeRabbit
New Features
UI/UX
Analytics
Settings
Chores