feat(teams): Team Management v0.8.0 Step 5 — Control Center UI - #35
Merged
Merged
Conversation
Team Management v0.8.0 Step 5 -- wires Control Center's Teams UI up to
the per-member endpoints omnibioai-auth Steps 1-4 already shipped
(invite/role-change/remove/leave, plus PATCH rename), replacing the old
full-replace membership picker.
Frontend (frontend/cc-ui):
- teams.ts: drop updateTeamMembers (old bulk PUT .../members), add
fetchTeamMembers/inviteTeamMember/updateTeamMemberRole/
removeTeamMember/leaveTeam/updateTeam, matching omnibioai-auth's
TeamMemberOut/TeamUpdate schemas exactly.
- TeamMembersPanel.tsx (new): per-member roster with role select,
invite form, remove (two-step confirm), and self-service leave.
Replaces TeamMemberSelector.tsx (removed) -- no remaining references.
- TeamRow.tsx / TeamsCard.tsx: wire in TeamMembersPanel, add the
rename/description edit form, description on the create form.
- Every mutating control renders unconditionally regardless of the
viewer's guessed role; the backend's require_team_manage_permission
is what actually decides, same "frontend hiding is not authorization"
posture this app already established (PR3B/PR3C). No team_role is
ever sent to the backend; no X-Team-Id/X-Workspace-Id header.
- OrganizationDetailPage.test.tsx: mocks TeamsCard instead of
re-asserting its internals (TeamsCard/TeamRow/TeamMembersPanel now
carry that coverage directly), mirroring TeamsPage.test.tsx's
existing precedent for this same component.
Backend (backend/src/control_center):
- routes_team_proxy.py had never been extended for Steps 1-4's
per-member endpoints -- only the original 4 Phase 3 PR3C routes were
proxied. Adds the 6 missing routes (PATCH /{team_id}, GET .../members,
POST .../invite, PUT .../members/{user_id}/role,
DELETE .../members/{user_id}, POST .../leave) so this UI is actually
reachable; without this the new controls above 404 in the real app.
Same thin-relay pattern as every existing proxy route -- no
authorization decision made here.
Tests: 436/436 frontend (vitest), 949/949 backend (pytest, 99.80% cov).
tsc -b --noEmit clean. No lint config in this repo.
No workspace-isolation or collaboration work included.
man4ish
added a commit
that referenced
this pull request
Aug 12, 2026
Mode B Phase 2: adds a top-bar TeamSwitcher that lets a user move between their personal workspace (team_id: null) and any team they belong to, backed by the existing auth-service POST /auth/switch-team. - backend: routes_auth_proxy.py gains a pure relay for /auth/switch-team (same _proxy_to_auth pattern as every other route in this file; this service never inspects or trusts team_id). - frontend: auth.ts adds SessionUser.teamId/teamRole and switchTeam(), which persists the reissued access token and re-validates the session before the caller may reload -- never a locally-computed team_id, no X-Team-Id/X-Workspace-Id header. - frontend: new TeamSwitcher.tsx/test.tsx, wired into TopAppBar. Rebased onto main (PR #35, Team Management v0.8.0 Step 5); two test fixtures (TeamSwitcher.test.tsx's Team mocks, TeamMembersPanel.test.tsx's SessionUser mock) updated to match the interfaces both branches now share -- no functional changes to Step 5's own implementation. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Steps 1–4 of Team Management v0.8.0 are already merged in
omnibioai-auth(PR #41). This PR implements Step 5 only: the Control Center UI catch-up for the per-member endpoints those steps shipped.fetchTeamMembers,inviteTeamMember,updateTeamMemberRole,removeTeamMember,leaveTeam,updateTeam) are now wired intofrontend/cc-ui/src/teams.ts, matchingomnibioai-auth's currentroutes_teams.py/schemas/teams.pycontract exactly.TeamMemberSelector.tsx,updateTeamMembers) is removed — no remaining references anywhere in the app.TeamMembersPanel.tsxprovides the per-member roster: role changes, invite, remove (two-step confirm), and self-service leave, plus a rename/description edit form onTeamRow.tsx.backend/src/control_center/api/routes_team_proxy.pyhad never been extended for Steps 1–4's per-member endpoints — only the original 4 Phase 3 PR3C routes were proxied. Without the 6 routes added here (PATCH /{team_id},GET .../members,POST .../invite,PUT .../members/{user_id}/role,DELETE .../members/{user_id},POST .../leave), the new frontend controls would 404 in the real deployed app. Same thin-relay pattern as every existing proxy route — no authorization decision made in this layer.Security
team_role(or any authorization flag) is ever sent from the client — the backend'srequire_team_manage_permission(Step 4) is authoritative; every mutating control renders unconditionally regardless of the viewer's guessed role, same "frontend hiding is not authorization" posture this app already established (PR3B/PR3C).X-Team-Id/X-Workspace-Idheader introduced anywhere.Team/TeamMemberdata, never free-typed.Tests
tsc -b --noEmitclean.🤖 Generated with Claude Code