Skip to content

feat: migrate SDK to use SetProjectMemberRole and RemoveProjectMember RPCs#1508

Open
whoAbhishekSah wants to merge 7 commits intomainfrom
feat/sdk-project-member-management
Open

feat: migrate SDK to use SetProjectMemberRole and RemoveProjectMember RPCs#1508
whoAbhishekSah wants to merge 7 commits intomainfrom
feat/sdk-project-member-management

Conversation

@whoAbhishekSah
Copy link
Copy Markdown
Member

@whoAbhishekSah whoAbhishekSah commented Apr 3, 2026

Summary

Replace policy-based project member management with the new atomic RPCs across React SDK (views + views-new) and Admin SDK.

Before: SDK manipulated policies directly (createPolicyForProject, listPolicies → deletePolicy x N → createPolicy)
After: SDK uses SetProjectMemberRole and RemoveProjectMember

Inconsistency found and fixed

The "Add member" flow was passing role names (e.g., app_project_viewer) as the roleId, while the "Change role" dropdown was passing role UUIDs from the fetched roles list. The backend SetProjectMemberRole expects a UUID.

Fix: All flows now fetch project-scoped roles via listRoles and resolve the role UUID before calling the RPC.

Files changed

React SDK (views):

File Change
project-members.tsx addMember/addTeam use SetProjectMemberRole with role UUID
project-member-columns.tsx updateRole uses SetProjectMemberRole, passes memberType for remove
project-detail-page.tsx Passes memberType (user/group) through remove flow
remove-project-member-dialog.tsx Uses RemoveProjectMember with correct principalType

React SDK (views-new):

File Change
add-member-menu.tsx Uses SetProjectMemberRole with fetched viewer role UUID
project-details-view.tsx Uses SetProjectMemberRole for role change, passes memberType for remove
remove-member-dialog.tsx Uses RemoveProjectMember with correct principalType from payload

Service account flows:

File Change
add-service-account-dialog.tsx Uses SetProjectMemberRole with fetched owner role UUID
manage-service-user-projects-dialog.tsx Uses both RPCs for enable/disable project access

Admin SDK:

File Change
use-add-project-members.tsx Uses SetProjectMemberRole with fetched viewer role UUID
remove-member.tsx Uses RemoveProjectMember
assign-role.tsx Uses SetProjectMemberRole

Closes #1462

Test plan

  • Add member to project (user + team) — views + views-new
  • Role change on project member — views + views-new
  • Remove user from project — views + views-new
  • Remove group from project — views + views-new
  • Service account project assignment
  • Manage service user projects toggle
  • Admin add/remove/assign-role flows
  • No policy RPCs in network tab

🤖 Generated with Claude Code

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Apr 8, 2026 6:40am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces client-side policy CRUD (listPolicies/deletePolicy/createPolicy/createPolicyForProject) with direct role-based mutations (setProjectMemberRole, removeProjectMember) across Admin and React SDK UIs, adding role lookups (listRoles) where needed and simplifying request bodies to principalId/principalType/roleId.

Changes

Cohort / File(s) Summary
Admin SDK member role management
web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx, web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx, web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx
Removed policy-diff and per-policy delete/create flows; replaced with setProjectMemberRole / removeProjectMember calls and added listRoles role-id resolution. Removed Connect/transport and policy request schemas.
React SDK project members (classic)
web/sdk/react/views/projects/details/project-member-columns.tsx, web/sdk/react/views/projects/details/project-members.tsx, web/sdk/react/views/projects/details/remove-project-member-dialog.tsx
Replaced multi-step policy replacement/deletion with setProjectMemberRole and removeProjectMember mutations; added viewer/role resolution gating and principalType handling; updated hook deps and removed policy queries.
React SDK project members (new UI)
web/sdk/react/views-new/projects/components/add-member-menu.tsx, web/sdk/react/views-new/projects/components/remove-member-dialog.tsx, web/sdk/react/views-new/projects/project-details-view.tsx
Switched from createPolicyForProject/listPolicies+deletes to listRoles + setProjectMemberRole / removeProjectMember; compute principalType from member type and gate actions on resolved role ids.
React SDK service accounts / API keys
web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx, web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx
Replaced createPolicyForProject with setProjectMemberRole; added listRoles to compute owner role id and error/gate when missing; revoked access now calls removeProjectMember.
Dialogs & hooks updates
web/sdk/react/views-new/projects/components/remove-member-dialog.tsx, web/sdk/react/views/projects/details/remove-project-member-dialog.tsx, web/sdk/admin/.../remove-member.tsx, web/sdk/admin/.../use-add-project-members.tsx
Introduced optional memberType (`'user'
Docs
docs/membership-package-tasks.md
Added documentation describing a new core/membership package and migration tasks for consolidating membership RPCs and behavior (no code API changes).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • rsbh
  • rohanchkrabrty
  • paanSinghCoder
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive The PR includes additional documentation (membership-package-tasks.md) describing future core/membership package work that appears beyond the current scope of #1462 SDK migrations. Confirm whether the membership-package-tasks.md documentation is intended as part of this PR or should be separated into a distinct documentation task.
✅ Passed checks (1 passed)
Check name Status Explanation
Linked Issues check ✅ Passed All React and Admin SDK files from issue #1462 have been migrated to use SetProjectMemberRole and RemoveProjectMember RPCs, replacing policy-based orchestration workflows.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

❤️ Share

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

@whoAbhishekSah
Copy link
Copy Markdown
Member Author

Manual Testing — PASS

Tested locally with client demo app on clean Frontier + SpiceDB.

Flow Principal Result
Add member to project User PASS
Add member to project Group PASS
Change role on project member User PASS
Remove member from project User PASS
Service account project assignment Service User PASS
Manage service user projects toggle Service User PASS

All flows use SetProjectMemberRole / RemoveProjectMember RPCs. No policy RPCs (createPolicyForProject, listPolicies, deletePolicy) in network tab.

@whoAbhishekSah whoAbhishekSah requested review from rohanchkrabrty and rsbh and removed request for rohanchkrabrty April 3, 2026 07:03
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (2)
web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx (1)

88-107: ⚠️ Potential issue | 🔴 Critical

setProjectMemberRole only preserves the last role in this loop.

This RPC replaces the member’s project role set; it does not append to it. Iterating assignedRolesArr here means each call overwrites the previous one, so only the last role survives while onRoleUpdate still reports every selected role locally.

Suggested fix
   const onSubmit = async (data: FormData) => {
     try {
       const assignedRolesArr = Array.from(data.roleIds);
+      if (assignedRolesArr.length !== 1) {
+        throw new Error("Project members can only have one direct project role");
+      }

-      for (const roleId of assignedRolesArr) {
-        await setProjectMemberRole(
-          create(SetProjectMemberRoleRequestSchema, {
-            projectId,
-            principalId: user?.id || "",
-            principalType: "app/user",
-            roleId,
-          }),
-        );
-      }
+      await setProjectMemberRole(
+        create(SetProjectMemberRoleRequestSchema, {
+          projectId,
+          principalId: user?.id || "",
+          principalType: "app/user",
+          roleId: assignedRolesArr[0],
+        }),
+      );
web/sdk/react/views/projects/details/remove-project-member-dialog.tsx (1)

20-25: ⚠️ Potential issue | 🟠 Major

Make memberType required instead of defaulting to 'user'.

This makes missing caller updates look valid. web/sdk/react/views/projects/details/project-detail-page.tsx:255-260 still opens the dialog without memberType, so removing a team member will continue to send app/user and fail. Making the prop required forces the remaining call sites to pass the correct principal type.

Suggested fix
 export interface RemoveProjectMemberDialogProps {
     open: boolean;
     onOpenChange?: (value: boolean) => void;
     projectId: string;
     memberId: string;
-    memberType?: 'user' | 'group';
+    memberType: 'user' | 'group';
 }
@@
 export const RemoveProjectMemberDialog = ({
     open,
     onOpenChange,
     projectId,
     memberId,
-    memberType = 'user'
+    memberType
 }: RemoveProjectMemberDialogProps) => {

Also applies to: 32-33, 52-57


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96b266ff-0062-46b1-bc94-f27ec9d10147

📥 Commits

Reviewing files that changed from the base of the PR and between 1b73eaf and ccc1d41.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx
  • web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx
  • web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx
  • web/sdk/package.json
  • web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
  • web/sdk/react/views/projects/details/project-member-columns.tsx
  • web/sdk/react/views/projects/details/project-members.tsx
  • web/sdk/react/views/projects/details/remove-project-member-dialog.tsx

@coveralls
Copy link
Copy Markdown

coveralls commented Apr 7, 2026

Coverage Report for CI Build 24121714139

Coverage remained the same at 41.146%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 36298
Covered Lines: 14935
Line Coverage: 41.15%
Coverage Strength: 11.89 hits per line

💛 - Coveralls

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx (1)

179-223: ⚠️ Potential issue | 🟠 Major

Add ownerRoleId to the callback dependencies.

onAccessChange reads ownerRoleId on Lines 188 and 194, but Line 223 omits it. When listRoles resolves after the dialog opens, the callback can keep the initial empty string and continue throwing “Project owner role not found” on grant attempts until another dependency changes.

Suggested fix
-    [serviceUserId, setProjectMemberRole, removeProjectMember]
+    [serviceUserId, ownerRoleId, setProjectMemberRole, removeProjectMember]

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9cfd1e26-ef92-4f05-9d62-76ad0532fd3c

📥 Commits

Reviewing files that changed from the base of the PR and between ccc1d41 and d873d1e.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx
  • web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx
  • web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx
  • web/sdk/package.json
  • web/sdk/react/views-new/projects/components/add-member-menu.tsx
  • web/sdk/react/views-new/projects/components/remove-member-dialog.tsx
  • web/sdk/react/views-new/projects/project-details-view.tsx
  • web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
  • web/sdk/react/views/projects/details/project-member-columns.tsx
  • web/sdk/react/views/projects/details/project-members.tsx
  • web/sdk/react/views/projects/details/remove-project-member-dialog.tsx
✅ Files skipped from review due to trivial changes (3)
  • web/sdk/package.json
  • web/sdk/react/views/projects/details/project-member-columns.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx

Comment on lines 88 to +101
const onSubmit = async (data: FormData) => {
try {
const client = createClient(FrontierService, transport);
const policiesResp = await client.listPolicies(
create(ListPoliciesRequestSchema, {
projectId: projectId,
userId: user?.id,
}),
);
const policies = policiesResp.policies || [];

const removedRolesPolicies = policies.filter(
(policy) => !(policy.roleId && data.roleIds.has(policy.roleId)),
);
await Promise.all(
removedRolesPolicies.map((policy) =>
deletePolicy(
create(DeletePolicyRequestSchema, { id: policy.id || "" }),
),
),
);

const resource = `app/project:${projectId}`;
const principal = `app/user:${user?.id}`;

const assignedRolesArr = Array.from(data.roleIds);
await Promise.all(
assignedRolesArr.map((roleId) =>
createPolicy(
create(CreatePolicyRequestSchema, {
body: {
roleId,
resource,
principal,
},
}),
),
),
);

for (const roleId of assignedRolesArr) {
await setProjectMemberRole(
create(SetProjectMemberRoleRequestSchema, {
projectId,
principalId: user?.id || "",
principalType: "app/user",
roleId,
}),
);
}
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Apr 7, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find setProjectMemberRole definition and usage
rg "setProjectMemberRole" -t ts -t tsx -B 3 -A 3

Repository: raystack/frontier

Length of output: 88


🏁 Script executed:

# Find SetProjectMemberRoleRequestSchema definition
rg "SetProjectMemberRoleRequestSchema" -t ts -t tsx -B 5 -A 10

Repository: raystack/frontier

Length of output: 88


🏁 Script executed:

# Check the full assign-role.tsx file to understand form flow
find . -name "assign-role.tsx" -path "*/projects/members/*" | head -1 | xargs cat

Repository: raystack/frontier

Length of output: 5223


🏁 Script executed:

# Look for any role removal or reconciliation logic
rg "removeProjectMemberRole\|deleteProjectMemberRole\|clearRoles" -t ts -t tsx -B 2 -A 2

Repository: raystack/frontier

Length of output: 88


🏁 Script executed:

# Find where SetProjectMemberRoleRequestSchema comes from
rg "SetProjectMemberRoleRequestSchema" -t js -t ts --max-count 5 | head -20

Repository: raystack/frontier

Length of output: 2236


🏁 Script executed:

# Search for setProjectMemberRole in proto files
find . -name "*.proto" | xargs grep -l "setProjectMemberRole\|SetProjectMemberRole" 2>/dev/null

Repository: raystack/frontier

Length of output: 45


🏁 Script executed:

# Look for the backend implementation in Go (service files)
find . -name "*service*.go" -path "*/project/*" | head -5

Repository: raystack/frontier

Length of output: 253


🏁 Script executed:

# Check if there's any API documentation or schema files
find . -name "*.proto" -o -name "*.openapi*" | head -10

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Search for the project service implementation
find . -path "*/core/project/*.go" -name "*.go" | xargs ls -la | head -20

Repository: raystack/frontier

Length of output: 1152


🏁 Script executed:

# Look for SetProjectMemberRole implementation in Go
rg "SetProjectMemberRole\|setProjectMemberRole" --type go -B 5 -A 15

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Check if there's any role removal/deletion in the codebase
rg "RemoveProjectMember\|DeleteProjectMember\|RemoveRole.*Project\|RemoveProjectRole" --type go -B 3 -A 10

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Look for any unset/delete operations on project members
rg "unsetProjectMemberRole\|UnsetProjectMemberRole" --type go

Repository: raystack/frontier

Length of output: 43


🏁 Script executed:

# Read the project service.go to find SetProjectMemberRole implementation
cat -n ./core/project/service.go | grep -A 30 -i "setprojectmemberrole\|setmemberrole"

Repository: raystack/frontier

Length of output: 1279


🏁 Script executed:

# Try broader search for member role methods
cat -n ./core/project/service.go | grep -i "member.*role\|role.*member"

Repository: raystack/frontier

Length of output: 335


🏁 Script executed:

# Search for any method that modifies roles
grep -n "func.*Member\|func.*Role" ./core/project/service.go | head -20

Repository: raystack/frontier

Length of output: 375


🏁 Script executed:

# Get more context of SetMemberRole to see the complete implementation
sed -n '362,405p' ./core/project/service.go

Repository: raystack/frontier

Length of output: 1346


🏁 Script executed:

# Check if there are any tests for SetMemberRole that confirm the behavior
grep -A 20 "SetMemberRole\|setMemberRole" ./core/project/service_test.go | head -50

Repository: raystack/frontier

Length of output: 1206


The multi-role selection UI is incompatible with the API's single-role replace semantics.

SetMemberRole deletes all existing policies and creates exactly one (see core/project/service.go:362-405). Since the form submits each selected role separately in a loop, only the last role persists—earlier selections are silently overwritten without error. If a user selects roles [A, B, C], only C will be assigned.

Either switch the dialog to single-select, or implement a proper multi-role endpoint that handles the full desired role set atomically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@rsbh @rohanchkrabrty Should we do this ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +25 to +33
memberType?: 'user' | 'group';
}

export const RemoveProjectMemberDialog = ({
open,
onOpenChange,
projectId,
memberId
memberId,
memberType = 'user'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make memberType required instead of defaulting to 'user'.

This dialog now supports both users and groups, but the primary caller in web/sdk/react/views/projects/details/project-detail-page.tsx still opens it without memberType. With the default at Lines 25-33, group removals silently take the 'app/user' branch at Lines 52-57 and fail against group memberships.

Also applies to: 52-57

whoAbhishekSah and others added 4 commits April 8, 2026 11:21
… RPCs

Replace policy-based member management (createPolicyForProject,
listPolicies, deletePolicy, createPolicy) with the new atomic RPCs.

React SDK:
- project-members.tsx: addMember/addTeam use SetProjectMemberRole
- project-member-columns.tsx: updateRole uses SetProjectMemberRole
- remove-project-member-dialog.tsx: uses RemoveProjectMember
- add-service-account-dialog.tsx: uses SetProjectMemberRole
- manage-service-user-projects-dialog.tsx: uses both RPCs

Admin SDK:
- use-add-project-members.tsx: uses SetProjectMemberRole
- remove-member.tsx: uses RemoveProjectMember
- assign-role.tsx: uses SetProjectMemberRole

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ions

Fetch project-scoped roles via listRoles and resolve the role UUID
before calling SetProjectMemberRole. Consistent with the role change
dropdown which already uses UUIDs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AddMemberDropdown is a separate child component that needs the
roles array to resolve the viewer role UUID.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… RemoveProjectMember

Update the design-revamped SDK views to use the new atomic RPCs:
- add-member-menu.tsx: use SetProjectMemberRole with fetched role UUID
- remove-member-dialog.tsx: use RemoveProjectMember
- project-details-view.tsx: use SetProjectMemberRole for role change

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (3)
web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx (2)

128-153: ⚠️ Potential issue | 🟠 Major

Validate ownerRoleId before creating the service user.

The validation at line 145 occurs after createServiceUser (line 133). If ownerRoleId is empty (e.g., roles query is slow or the role name doesn't match), the service user will be created but left orphaned without project access.

Suggested fix: validate early
   const onSubmit = useCallback(
     async (data: FormData) => {
       if (!orgId) return;
+      if (!ownerRoleId) {
+        toast.error('Something went wrong', {
+          description: 'Project owner role not found'
+        });
+        return;
+      }

       try {
         const serviceUserResponse = await createServiceUser(
           create(CreateServiceUserRequestSchema, {
             orgId,
             body: create(ServiceUserRequestBodySchema, {
               title: data.title
             })
           })
         );

         const serviceUserId = serviceUserResponse.serviceuser?.id;
         if (!serviceUserId) return;

-        if (!ownerRoleId) throw new Error('Project owner role not found');
         await setProjectMemberRole(

201-209: ⚠️ Potential issue | 🟠 Major

Add ownerRoleId to the dependency array.

The callback uses ownerRoleId (lines 145, 151) but it's missing from the dependency array. This causes a stale closure: the callback captures the initial empty string even after listRoles resolves, leading to "Project owner role not found" errors.

Suggested fix
     [
       orgId,
+      ownerRoleId,
       createServiceUser,
       setProjectMemberRole,
       createServiceUserToken,
       queryClient,
       transport,
       onCreated
     ]
web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx (1)

68-89: ⚠️ Potential issue | 🟡 Minor

Silent failure when viewerRoleId is missing.

The early return at line 70 silently exits without user feedback if viewerRoleId is empty (e.g., role not found or query still loading). Users clicking "Add" see no response.

Consider adding a toast or ensuring the add button is disabled while roles are loading.

Suggested fix
   const addMember = useCallback(
     async (userId: string) => {
-      if (!userId || !projectId || !viewerRoleId) return;
+      if (!userId || !projectId) return;
+      if (!viewerRoleId) {
+        toast.error("Unable to add member", { description: "Project viewer role not found" });
+        return;
+      }
       try {
♻️ Duplicate comments (1)
web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx (1)

179-224: ⚠️ Potential issue | 🟠 Major

onAccessChange closes over a stale ownerRoleId.

The callback uses ownerRoleId at lines 188 and 194, but it's missing from the dependency array at line 223. When the dialog opens and listRoles populates the role ID, onAccessChange still holds the stale empty string from initial render, causing "Project owner role not found" errors.

Suggested fix
-    [serviceUserId, setProjectMemberRole, removeProjectMember]
+    [serviceUserId, ownerRoleId, setProjectMemberRole, removeProjectMember]

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3466a0ec-412a-4b4e-a218-712d1f8d0ba5

📥 Commits

Reviewing files that changed from the base of the PR and between c7c1ca0 and cfeb60b.

📒 Files selected for processing (11)
  • web/sdk/admin/views/organizations/details/projects/members/assign-role.tsx
  • web/sdk/admin/views/organizations/details/projects/members/remove-member.tsx
  • web/sdk/admin/views/organizations/details/projects/use-add-project-members.tsx
  • web/sdk/react/views-new/projects/components/add-member-menu.tsx
  • web/sdk/react/views-new/projects/components/remove-member-dialog.tsx
  • web/sdk/react/views-new/projects/project-details-view.tsx
  • web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
  • web/sdk/react/views/projects/details/project-member-columns.tsx
  • web/sdk/react/views/projects/details/project-members.tsx
  • web/sdk/react/views/projects/details/remove-project-member-dialog.tsx
✅ Files skipped from review due to trivial changes (2)
  • web/sdk/react/views-new/projects/components/remove-member-dialog.tsx
  • web/sdk/react/views/projects/details/project-member-columns.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/sdk/react/views-new/projects/components/add-member-menu.tsx
  • web/sdk/react/views/projects/details/project-members.tsx

- Fix hardcoded principalType in views-new remove-member-dialog:
  pass memberType through payload to support group removal
- Add ownerRoleId to dependency arrays in manage-service-user-projects
  and add-service-account dialogs to prevent stale closures
- Move ownerRoleId validation before service user creation to avoid
  orphaned service users

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
docs/membership-package-tasks.md (1)

31-41: Consider adding language specifiers to fenced code blocks.

Several code blocks use plain triple-backticks without a language identifier. While these are pseudo-code/call-chain diagrams rather than compilable code, adding a language hint (e.g., ```text or ```plaintext) would satisfy markdown linters and improve rendering consistency.

Example fix for one block
-```
-Before:
+```text
+Before:

Also applies to: 180-218, 222-234, 323-344, 400-432, 497-515, 586-600


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 89a2c7f1-7a7c-4a9b-9b88-c6324742f82d

📥 Commits

Reviewing files that changed from the base of the PR and between cfeb60b and 0428bb6.

📒 Files selected for processing (4)
  • docs/membership-package-tasks.md
  • web/sdk/react/views-new/projects/components/remove-member-dialog.tsx
  • web/sdk/react/views/api-keys/details/manage-service-user-projects-dialog.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/sdk/react/views-new/projects/components/remove-member-dialog.tsx
  • web/sdk/react/views/api-keys/list/add-service-account-dialog.tsx

Both views and views-new now pass the member type (user/group) from
the column action through to the remove dialog and into the
RemoveProjectMember RPC call.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate React SDK and Admin SDK to use new role-based RPCs

2 participants