-
Notifications
You must be signed in to change notification settings - Fork 199
UI changes for project-specific roles #2641
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
base: main
Are you sure you want to change the base?
Conversation
Console (appwrite/console)Project ID: Tip MCP server integration brings LLM superpowers to Claude Desktop and Cursor IDE |
WalkthroughThis PR introduces project-specific member role management functionality. It enables inviting and assigning members to specific projects with individual roles, particularly for SCALE billing plans. Key changes include: adding an Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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: 5
🧹 Nitpick comments (3)
src/lib/components/roles/roles.svelte (1)
10-14: Minor: Inconsistent punctuation in role text.The non-project-specific text ends with a period (
Analyst and Billing.) while the project-specific text does not (Editor and Analyst). Consider making punctuation consistent.- {isProjectSpecific - ? 'Owner, Developer, Editor and Analyst' - : 'Owner, Developer, Editor, Analyst and Billing.'} + {isProjectSpecific + ? 'Owner, Developer, Editor and Analyst.' + : 'Owner, Developer, Editor, Analyst and Billing.'}src/routes/(console)/organization-[organization]/members/project.svelte (1)
94-157: Consider loading state UX when paginating or searching.The conditional rendering prioritizes existing
results?.projects?.lengthoverisLoading. When paginating or searching, stale results display while new data loads. Consider showing a loading indicator overlay or clearing results before the request for better UX.src/routes/(console)/organization-[organization]/createMember.svelte (1)
79-83: Mixed Svelte 4/5 reactivity patterns.This file uses
$:reactive statement (Svelte 4 style), while related files likeedit.svelteuse$effect(Svelte 5 style). Consider migrating to$effectfor consistency across the codebase.- $: if (!showCreate) { - error = null; - email = null; - name = null; - } + $effect(() => { + if (!showCreate) { + error = null; + email = null; + name = null; + } + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/lib/components/roles/roles.svelte(1 hunks)src/lib/stores/billing.ts(1 hunks)src/routes/(console)/organization-[organization]/createMember.svelte(3 hunks)src/routes/(console)/organization-[organization]/members/+page.svelte(1 hunks)src/routes/(console)/organization-[organization]/members/edit.svelte(2 hunks)src/routes/(console)/organization-[organization]/members/project.svelte(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,svelte}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,svelte}: Import reusable modules from the src/lib directory using the $lib alias
Use minimal comments in code; reserve comments for TODOs or complex logic explanations
Use $lib, $routes, and $themes aliases instead of relative paths for module imports
Files:
src/lib/stores/billing.tssrc/lib/components/roles/roles.sveltesrc/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/edit.sveltesrc/routes/(console)/organization-[organization]/members/project.sveltesrc/routes/(console)/organization-[organization]/members/+page.svelte
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.ts: Define types inline or in .d.ts files, avoid creating separate .types.ts files
Use TypeScript in non-strict mode; any type is tolerated in this project
Files:
src/lib/stores/billing.ts
**/*.{ts,tsx,js,jsx,svelte,json}
📄 CodeRabbit inference engine (AGENTS.md)
Use 4 spaces for indentation, single quotes, 100 character line width, and no trailing commas per Prettier configuration
Files:
src/lib/stores/billing.tssrc/lib/components/roles/roles.sveltesrc/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/edit.sveltesrc/routes/(console)/organization-[organization]/members/project.sveltesrc/routes/(console)/organization-[organization]/members/+page.svelte
src/lib/components/**/*.svelte
📄 CodeRabbit inference engine (AGENTS.md)
Use PascalCase for component file names and place them in src/lib/components/[feature]/ directory structure
Files:
src/lib/components/roles/roles.svelte
**/*.svelte
📄 CodeRabbit inference engine (AGENTS.md)
Use Svelte 5 + SvelteKit 2 syntax with TypeScript for component development
Files:
src/lib/components/roles/roles.sveltesrc/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/edit.sveltesrc/routes/(console)/organization-[organization]/members/project.sveltesrc/routes/(console)/organization-[organization]/members/+page.svelte
src/routes/**/*.svelte
📄 CodeRabbit inference engine (AGENTS.md)
Use SvelteKit file conventions: +page.svelte for components, +page.ts for data loaders, +layout.svelte for wrappers, +error.svelte for error handling, and dynamic route params in square brackets like [param]
Files:
src/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/edit.sveltesrc/routes/(console)/organization-[organization]/members/project.sveltesrc/routes/(console)/organization-[organization]/members/+page.svelte
src/routes/**
📄 CodeRabbit inference engine (AGENTS.md)
Configure dynamic routes using SvelteKit convention with [param] syntax in route directory names
Files:
src/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/edit.sveltesrc/routes/(console)/organization-[organization]/members/project.sveltesrc/routes/(console)/organization-[organization]/members/+page.svelte
🧠 Learnings (6)
📚 Learning: 2025-09-08T13:20:47.308Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 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/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/edit.svelte
📚 Learning: 2025-10-13T05:13:54.542Z
Learnt from: ItzNotABug
Repo: appwrite/console PR: 2413
File: src/routes/(console)/project-[region]-[project]/databases/table.svelte:33-39
Timestamp: 2025-10-13T05:13:54.542Z
Learning: In Svelte 5, `import { page } from '$app/state'` provides a reactive state proxy that can be accessed directly (e.g., `page.params`), unlike the older `import { page } from '$app/stores'` which returns a readable store requiring the `$page` syntax for auto-subscription in components.
Applied to files:
src/routes/(console)/organization-[organization]/createMember.svelte
📚 Learning: 2025-11-25T03:15:27.510Z
Learnt from: CR
Repo: appwrite/console PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T03:15:27.510Z
Learning: Applies to src/routes/**/*.svelte : Use SvelteKit file conventions: +page.svelte for components, +page.ts for data loaders, +layout.svelte for wrappers, +error.svelte for error handling, and dynamic route params in square brackets like [param]
Applied to files:
src/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/project.sveltesrc/routes/(console)/organization-[organization]/members/+page.svelte
📚 Learning: 2025-11-25T03:15:27.510Z
Learnt from: CR
Repo: appwrite/console PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T03:15:27.510Z
Learning: Applies to **/*.svelte : Use Svelte 5 + SvelteKit 2 syntax with TypeScript for component development
Applied to files:
src/routes/(console)/organization-[organization]/createMember.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)/organization-[organization]/createMember.svelte
📚 Learning: 2025-11-19T11:22:42.553Z
Learnt from: atharvadeosthale
Repo: appwrite/console PR: 2512
File: src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte:51-83
Timestamp: 2025-11-19T11:22:42.553Z
Learning: In src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte, the Lovable integration URL format `https://lovable.dev/` with `autosubmit` and `prompt` as query parameters (set via searchParams) is correct and functional.
Applied to files:
src/routes/(console)/organization-[organization]/createMember.sveltesrc/routes/(console)/organization-[organization]/members/project.svelte
🪛 GitHub Actions: Tests
src/routes/(console)/organization-[organization]/createMember.svelte
[error] 1-1: Code style issues found. Run 'prettier --write' to fix formatting.
src/routes/(console)/organization-[organization]/members/edit.svelte
[error] 1-1: Code style issues found. Run 'prettier --write' to fix formatting.
src/routes/(console)/organization-[organization]/members/+page.svelte
[error] 1-1: Code style issues found. Run 'prettier --write' to fix formatting.
⏰ 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/lib/stores/billing.ts (1)
70-71: LGTM!Clean implementation to derive project-specific roles by filtering out the billing role. This appropriately separates organization-level roles from project-scoped roles.
src/routes/(console)/organization-[organization]/members/+page.svelte (1)
146-150: LGTM! Address Prettier formatting.The conditional logic correctly identifies project-scoped roles (prefixed with
project:) and displays "Custom" instead of attempting to parse complex role strings. The pipeline indicates formatting issues - runprettier --writeto fix.src/routes/(console)/organization-[organization]/members/project.svelte (1)
84-86: Potential unintended state sync from second$effect.This effect syncs
selectedProjectsWithRolewith the propprojectsWithRoleon every change. Combined with the first effect that triggersrequest()onshow, this could cause unexpected behavior: if the parent updatesprojectsWithRolewhile the modal is open, user selections get overwritten.Consider whether this is intentional, or if the sync should only occur when the modal opens.
src/routes/(console)/organization-[organization]/createMember.svelte (1)
44-51: LGTM! Correct multi-project roles payload structure.The roles array correctly includes
'member'as the base role followed by project-specific roles in theproject:<id>/<role>format. This aligns with the expected backend format for project-scoped permissions.
| {#each selectedProjectsWithRole as selected} | ||
| <Table.Row.Base {root}> | ||
| <Table.Cell column="project" {root}>{selected.project.name}</Table.Cell> | ||
| <Table.Cell column="role" {root}> | ||
| <InputSelect | ||
| required | ||
| id="role" | ||
| options={projectRoles} | ||
| bind:value={selected.role} /> | ||
| </Table.Cell> | ||
| <Table.Cell column="action" {root}> | ||
| <Button | ||
| compact | ||
| icon | ||
| on:click={() => removeProject(selected.project.$id)}> | ||
| <Icon icon={IconX} size="s" /> | ||
| </Button> | ||
| </Table.Cell> | ||
| </Table.Row.Base> | ||
| {/each} |
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.
Duplicate id="role" attributes in table rows.
Each InputSelect in the loop uses id="role", creating duplicate IDs in the DOM. This violates HTML standards and can cause accessibility issues with label association.
Consider using unique IDs per project.
- <InputSelect
- required
- id="role"
- options={projectRoles}
- bind:value={selected.role} />
+ <InputSelect
+ required
+ id={`role-${selected.project.$id}`}
+ options={projectRoles}
+ bind:value={selected.role} />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {#each selectedProjectsWithRole as selected} | |
| <Table.Row.Base {root}> | |
| <Table.Cell column="project" {root}>{selected.project.name}</Table.Cell> | |
| <Table.Cell column="role" {root}> | |
| <InputSelect | |
| required | |
| id="role" | |
| options={projectRoles} | |
| bind:value={selected.role} /> | |
| </Table.Cell> | |
| <Table.Cell column="action" {root}> | |
| <Button | |
| compact | |
| icon | |
| on:click={() => removeProject(selected.project.$id)}> | |
| <Icon icon={IconX} size="s" /> | |
| </Button> | |
| </Table.Cell> | |
| </Table.Row.Base> | |
| {/each} | |
| {#each selectedProjectsWithRole as selected} | |
| <Table.Row.Base {root}> | |
| <Table.Cell column="project" {root}>{selected.project.name}</Table.Cell> | |
| <Table.Cell column="role" {root}> | |
| <InputSelect | |
| required | |
| id={`role-${selected.project.$id}`} | |
| options={projectRoles} | |
| bind:value={selected.role} /> | |
| </Table.Cell> | |
| <Table.Cell column="action" {root}> | |
| <Button | |
| compact | |
| icon | |
| on:click={() => removeProject(selected.project.$id)}> | |
| <Icon icon={IconX} size="s" /> | |
| </Button> | |
| </Table.Cell> | |
| </Table.Row.Base> | |
| {/each} |
🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/createMember.svelte around
lines 130 to 149 the InputSelect inside the each loop uses a static id="role"
for every row, producing duplicate DOM IDs; change the id to a unique value per
iteration (for example by appending the project id or the loop index such as
id={`role-${selected.project.$id}`} or id={`role-${i}`}) and update any
corresponding labels' for attribute to match the new id so each input has a
unique, accessible identifier.
| let isProjectSpecificRoles = $derived( | ||
| selectedMember?.roles?.some((r) => r.startsWith('project:')) | ||
| ); | ||
| let teamRole = $derived(isProjectSpecificRoles ? defaultTeamRole : selectedMember?.roles?.[0]); | ||
| let isRestrictingToSpecificProjects = $derived(isProjectSpecificRoles); | ||
| let selectedProjectsWithRole: { project: Models.Project; role: string }[] = $state([]); |
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.
Critical: Binding to $derived value will fail.
isRestrictingToSpecificProjects is a $derived value (read-only), but it's used with bind:value on the InputSwitch (line 118). This will cause a runtime error when the user tries to toggle the switch.
Convert to $state and sync from the derived value on modal open instead.
- let isProjectSpecificRoles = $derived(
- selectedMember?.roles?.some((r) => r.startsWith('project:'))
- );
- let teamRole = $derived(isProjectSpecificRoles ? defaultTeamRole : selectedMember?.roles?.[0]);
- let isRestrictingToSpecificProjects = $derived(isProjectSpecificRoles);
+ let isProjectSpecificRoles = $derived(
+ selectedMember?.roles?.some((r) => r.startsWith('project:'))
+ );
+ let teamRole = $state(isSelfHosted ? 'owner' : 'developer');
+ let isRestrictingToSpecificProjects = $state(false);
+
+ $effect(() => {
+ if (showEdit && selectedMember) {
+ isRestrictingToSpecificProjects = isProjectSpecificRoles;
+ teamRole = isProjectSpecificRoles ? defaultTeamRole : (selectedMember?.roles?.[0] ?? defaultTeamRole);
+ }
+ });🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/members/edit.svelte around
lines 31 to 36, the boolean isRestrictingToSpecificProjects is defined as a
$derived (read-only) but is bound to the InputSwitch with bind:value, causing a
runtime error; change isRestrictingToSpecificProjects to a writable $state
boolean, remove the bind to the derived value, and when the edit modal opens
set/sync that state from the existing derived value (or selectedMember roles) so
the switch reflects current data and can be toggled without error.
| $effect(() => { | ||
| if (!showEdit || !isProjectSpecificRoles) { | ||
| return; | ||
| } | ||
| async function loadProjects() { | ||
| const projectIdToRole = selectedMember?.roles | ||
| ?.filter((r) => r.startsWith('project:')) | ||
| .reduce((acc, r) => { | ||
| const parts = r.split(':')[1]; | ||
| const [projectId, role] = parts.split('/'); | ||
| acc[projectId] = role; | ||
| return acc; | ||
| }, {}); | ||
| const projectIdsQuery = Object.keys(projectIdToRole).map((id) => | ||
| Query.equal('$id', id) | ||
| ); | ||
| const projectsList = await sdk.forConsole.projects.list({ | ||
| queries: [Query.equal('teamId', $organization.$id), Query.or(projectIdsQuery)] | ||
| }); | ||
| selectedProjectsWithRole = projectsList.projects.map((p) => ({ | ||
| project: p, | ||
| role: projectIdToRole[p.$id] | ||
| })); | ||
| } | ||
| loadProjects(); | ||
| }); |
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.
🧩 Analysis chain
Verify Query.or behavior with empty array.
If selectedMember.roles has no project: prefixed roles, projectIdsQuery will be an empty array. Verify that Query.or([]) doesn't cause an API error.
🏁 Script executed:
#!/bin/bash
# Search for Query.or usage patterns to understand how empty arrays are handled
rg -n "Query\.or\(" --type=ts --type=svelte -C 3Length of output: 30
🏁 Script executed:
#!/bin/bash
# Search for Query.or usage patterns in all files
rg -n "Query\.or\(" -C 3Length of output: 1775
🏁 Script executed:
#!/bin/bash
# Find where Query is imported/defined
rg -n "import.*Query" -C 2Length of output: 63767
🏁 Script executed:
#!/bin/bash
# Look for Appwrite SDK files that might contain Query definition
fd -e ts -e js -e svelte | xargs grep -l "Query\.or" 2>/dev/null | head -20Length of output: 1441
🏁 Script executed:
#!/bin/bash
# Search for patterns with empty array handling in similar contexts
rg -n "Query\.or\(\[\]" -C 3Length of output: 0
🌐 Web query:
Appwrite Query.or empty array behavior documentation
💡 Result:
Short answer: Appwrite’s query APIs do not have special handling for an empty array passed into OR/other query builders — passing an empty array can produce unexpected results. Best practice is to skip adding Query.or (or any query that would receive an empty array) when the array is empty (i.e., check client-side and only build the OR when you have one or more sub-queries). (appwrite.io)
Sources:
- Appwrite Queries docs (usage and OR semantics). (appwrite.io)
- Community threads / issues noting array-query limitations and recommending guarding against empty arrays. (appwrite.io)
Citations:
- 1: https://appwrite.io/docs/products/databases/legacy/queries?utm_source=openai
- 2: https://appwrite.io/docs/products/databases/legacy/queries?utm_source=openai
- 3: https://appwrite.io/threads/1115356592947335249?utm_source=openai
Add guard clause before Query.or() to prevent empty array.
Appwrite's Query.or() does not handle empty arrays gracefully and passing an empty array can produce unexpected results. When selectedMember.roles contains no project: prefixed roles, projectIdsQuery will be an empty array, causing Query.or([]) to trigger unexpected API behavior.
Add a check: only include Query.or(projectIdsQuery) in the queries array when projectIdsQuery.length > 0.
🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/members/edit.svelte around
lines 83 to 110, projectIdsQuery can be an empty array which makes Query.or([])
produce unexpected API behavior; modify the code that builds the queries array
so that Query.or(projectIdsQuery) is only included when projectIdsQuery.length >
0 (e.g., create a base queries array with Query.equal('teamId',
$organization.$id) and conditionally push Query.or(projectIdsQuery) only if the
array is non-empty), then call sdk.forConsole.projects.list with that
conditional queries array.
| {#each selectedProjectsWithRole as selected} | ||
| <Table.Row.Base {root}> | ||
| <Table.Cell column="project" {root}>{selected.project.name}</Table.Cell> | ||
| <Table.Cell column="role" {root}> | ||
| <InputSelect | ||
| required | ||
| id="role" | ||
| options={projectRoles} | ||
| bind:value={selected.role} /> | ||
| </Table.Cell> | ||
| <Table.Cell column="action" {root}> | ||
| <Button | ||
| compact | ||
| icon | ||
| on:click={() => removeProject(selected.project.$id)}> | ||
| <Icon icon={IconX} size="s" /> | ||
| </Button> | ||
| </Table.Cell> | ||
| </Table.Row.Base> | ||
| {/each} |
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.
Duplicate id="role" attributes in table rows.
Same issue as in createMember.svelte: each InputSelect uses id="role", creating duplicate IDs. Use unique IDs per project row.
<Table.Cell column="role" {root}>
<InputSelect
required
- id="role"
+ id={`role-${selected.project.$id}`}
options={projectRoles}
bind:value={selected.role} />
</Table.Cell>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {#each selectedProjectsWithRole as selected} | |
| <Table.Row.Base {root}> | |
| <Table.Cell column="project" {root}>{selected.project.name}</Table.Cell> | |
| <Table.Cell column="role" {root}> | |
| <InputSelect | |
| required | |
| id="role" | |
| options={projectRoles} | |
| bind:value={selected.role} /> | |
| </Table.Cell> | |
| <Table.Cell column="action" {root}> | |
| <Button | |
| compact | |
| icon | |
| on:click={() => removeProject(selected.project.$id)}> | |
| <Icon icon={IconX} size="s" /> | |
| </Button> | |
| </Table.Cell> | |
| </Table.Row.Base> | |
| {/each} | |
| {#each selectedProjectsWithRole as selected} | |
| <Table.Row.Base {root}> | |
| <Table.Cell column="project" {root}>{selected.project.name}</Table.Cell> | |
| <Table.Cell column="role" {root}> | |
| <InputSelect | |
| required | |
| id={`role-${selected.project.$id}`} | |
| options={projectRoles} | |
| bind:value={selected.role} /> | |
| </Table.Cell> | |
| <Table.Cell column="action" {root}> | |
| <Button | |
| compact | |
| icon | |
| on:click={() => removeProject(selected.project.$id)}> | |
| <Icon icon={IconX} size="s" /> | |
| </Button> | |
| </Table.Cell> | |
| </Table.Row.Base> | |
| {/each} |
🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/members/edit.svelte around
lines 145 to 164 the InputSelect elements all use the same id="role", causing
duplicate IDs; change the id to be unique per row (for example append the
project id or the loop index like id={`role-${selected.project.$id}`} or
id={`role-${index}`}) and update any corresponding label/for attributes if
present so each InputSelect has a distinct id.
| <Empty title="No projects yet. Create a project to see it here." type="secondary"> | ||
| <Typography.Text slot="description"> | ||
| Need a hand? Learn more in our <Link.Anchor | ||
| href="https://appwrite.io/docs/products/auth/users" | ||
| target="_blank" | ||
| rel="noopener noreferrer"> | ||
| documentation</Link.Anchor | ||
| >. | ||
| </Typography.Text> |
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.
Documentation link mismatch.
The empty state links to auth/users documentation, but this component is for selecting projects. Consider updating to a more relevant documentation link.
<Typography.Text slot="description">
Need a hand? Learn more in our <Link.Anchor
- href="https://appwrite.io/docs/products/auth/users"
+ href="https://appwrite.io/docs/advanced/platform/projects"
target="_blank"
rel="noopener noreferrer">
documentation</Link.Anchor📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Empty title="No projects yet. Create a project to see it here." type="secondary"> | |
| <Typography.Text slot="description"> | |
| Need a hand? Learn more in our <Link.Anchor | |
| href="https://appwrite.io/docs/products/auth/users" | |
| target="_blank" | |
| rel="noopener noreferrer"> | |
| documentation</Link.Anchor | |
| >. | |
| </Typography.Text> | |
| <Empty title="No projects yet. Create a project to see it here." type="secondary"> | |
| <Typography.Text slot="description"> | |
| Need a hand? Learn more in our <Link.Anchor | |
| href="https://appwrite.io/docs/advanced/platform/projects" | |
| target="_blank" | |
| rel="noopener noreferrer"> | |
| documentation</Link.Anchor | |
| >. | |
| </Typography.Text> |
🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/members/project.svelte
around lines 146 to 154 the Empty state links to the Auth users docs but this
component is for selecting projects; update the anchor href to the appropriate
projects documentation (e.g. https://appwrite.io/docs/products/projects or your
app's projects guide) and ensure the link text/context reflects "projects" or
"project management" instead of "auth/users" so the empty state points users to
relevant documentation.

Closes SER-542
Summary by CodeRabbit
New Features
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.