Skip to content

feat: teams page revamp#1510

Open
rohanchkrabrty wants to merge 18 commits intomainfrom
feat-teams-revamp
Open

feat: teams page revamp#1510
rohanchkrabrty wants to merge 18 commits intomainfrom
feat-teams-revamp

Conversation

@rohanchkrabrty
Copy link
Copy Markdown
Contributor

Summary

  • Revamp all settings pages (general, preferences, profile, sessions, members, security, projects, teams) using @raystack/apsara-v1 primitives under views-new/
  • Add reusable ViewContainer and ViewHeader layout components for consistent page structure
  • Introduce imperative dialog/menu handle pattern (Dialog.createHandle, AlertDialog.createHandle, Menu.createHandle) across all revamped pages
  • Add teams list and team details views with member management (add, remove, role update) mirroring the projects page pattern
  • Wire all new views into react/index.ts exports and client-demo app with routes and sidebar navigation

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 6, 2026

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

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Apr 9, 2026 9:41am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 6, 2026

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features
    • Added teams management section to settings with the ability to create, edit, and delete teams
    • Team member management including adding members, assigning roles, and removing members from teams
    • Team details page featuring a searchable member roster and role management capabilities

Walkthrough

Adds a new "teams" feature: SDK exports for Teams/TeamDetails views, multiple Teams UI components (views, dialogs, columns, member management), CSS modules, and client-demo routes/pages to surface teams under /:orgId/settings.

Changes

Cohort / File(s) Summary
Client-Demo Routing & Pages
web/apps/client-demo/src/Router.tsx, web/apps/client-demo/src/pages/Settings.tsx, web/apps/client-demo/src/pages/settings/Teams.tsx, web/apps/client-demo/src/pages/settings/TeamDetails.tsx
Added nested / :orgId/settings/teams and / :orgId/settings/teams/:teamId routes and a Settings sidebar entry; new page wrappers that integrate route params and navigation into SDK views.
SDK Public Exports
web/sdk/react/index.ts, web/sdk/react/views-new/teams/index.ts
Exported TeamsView, TeamDetailsView, and TeamDetailsViewProps from the React SDK barrel.
Teams Views
web/sdk/react/views-new/teams/teams-view.tsx, web/sdk/react/views-new/teams/team-details-view.tsx
New top-level Teams and TeamDetails view components: data fetching (groups, members, roles), permissions checks, tables, actions, and dialog/menu wiring.
Teams Components / Dialogs
web/sdk/react/views-new/teams/components/*
Added many components: add/edit/delete team dialogs, add-member menu, remove-member dialog, and related UI (forms, mutations, toasts, refetch flows).
Table Column Helpers
web/sdk/react/views-new/teams/components/team-columns.tsx, web/sdk/react/views-new/teams/components/member-columns.tsx
New column-definition helpers for teams and members tables including menu payload types and action logic.
Styling
web/sdk/react/views-new/teams/teams-view.module.css, web/sdk/react/views-new/teams/team-details-view.module.css
Added CSS modules for Teams and TeamDetails layouts and menu/list styling.
Barrel + Large Additions
web/sdk/react/views-new/teams/*.tsx, web/sdk/react/views-new/teams/components/*.tsx
Bulk addition of typed interfaces, hooks usage (useQuery/useMutation), Dialog/AlertDialog handles, and toast/error handling across new teams feature files.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • rohilsurana
  • rsbh

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.

@rohanchkrabrty rohanchkrabrty changed the title feat: revamp settings pages with apsara-v1 design system feat: teams page revamp Apr 6, 2026
@rohanchkrabrty rohanchkrabrty changed the base branch from main to feat-projects-revamp April 6, 2026 04:37
Base automatically changed from feat-projects-revamp to main April 6, 2026 05:38
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 7, 2026

Coverage Report for CI Build 24183450372

Coverage remained the same at 41.282%

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: 36389
Covered Lines: 15022
Line Coverage: 41.28%
Coverage Strength: 11.88 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: 10

🧹 Nitpick comments (7)
web/sdk/react/views-new/teams/components/add-member-menu.tsx (1)

41-51: Defer listOrganizationUsers until the menu is used.

This query fires on every editable team-details render, even if the user never opens the add-member menu. For larger orgs that is avoidable page-load work; tie it to menu-open or search interaction instead.

web/sdk/react/views-new/teams/components/team-columns.tsx (1)

41-48: Consider displaying "0 members" instead of hiding the count entirely.

When members_count is 0 (falsy), the cell renders null. This may confuse users who see an empty cell. Consider showing "0 members" for clarity.

Proposed fix
       cell: ({ getValue }) => {
         const value = getValue() as number;
-        return value ? (
+        return (
           <Text size="regular" variant="secondary">
             {value} {value === 1 ? 'member' : 'members'}
           </Text>
-        ) : null;
+        );
       }
web/sdk/react/views-new/teams/components/add-team-dialog.tsx (1)

27-32: Redundant length constraints in validation schema.

The min(3) and max(50) constraints are also enforced by the regex {3,50}. Consider removing the redundant .min() and .max() calls, or adjusting the regex to only validate character types.

Proposed fix (keep regex, remove min/max)
     name: yup
       .string()
       .required('Team name is required')
-      .min(3, 'Name must be at least 3 characters')
-      .max(50, 'Name must be at most 50 characters')
       .matches(
         /^[a-zA-Z0-9_-]{3,50}$/,
         "Only numbers, letters, '-', and '_' are allowed. Spaces are not allowed."
       )
web/sdk/react/views-new/teams/team-details-view.tsx (2)

66-70: Module-level dialog handles are singletons shared across all component instances.

These handles are created at module scope, meaning all instances of TeamDetailsView would share the same dialog state. If this component is rendered multiple times (e.g., in different tabs or routes), dialogs could interfere with each other.

Consider creating handles inside the component or using useMemo to ensure instance isolation.

Proposed fix - move handles inside component
+export function TeamDetailsView({
+  teamId,
+  teamsLabel = 'Teams',
+  onNavigateToTeams,
+  onDeleteSuccess
+}: TeamDetailsViewProps) {
+  const memberMenuHandle = useMemo(() => Menu.createHandle<MemberMenuPayload>(), []);
+  const editTeamDialogHandle = useMemo(() => Dialog.createHandle<EditTeamPayload>(), []);
+  const deleteTeamDialogHandle = useMemo(() => AlertDialog.createHandle<DeleteTeamPayload>(), []);
+  const removeMemberDialogHandle = useMemo(() => AlertDialog.createHandle<RemoveMemberPayload>(), []);
+
   const { activeOrganization: organization } = useFrontier();

And remove the module-level declarations.


446-446: teamActionsMenuHandle is also module-scoped.

Similar to the other handles, this could cause issues with multiple component instances.

web/sdk/react/views-new/teams/teams-view.tsx (2)

39-42: Module-level handles cause shared state across component instances.

These handles are created at module scope, so all instances of TeamsView share the same dialog/menu state. If multiple TeamsView components are rendered (e.g., in different tabs or views), opening a dialog in one instance would affect others.

Consider moving the handle creation inside the component with useMemo:

♻️ Suggested refactor
-const teamMenuHandle = Menu.createHandle<TeamMenuPayload>();
-const addTeamDialogHandle = Dialog.createHandle();
-const editTeamDialogHandle = Dialog.createHandle<EditTeamPayload>();
-const deleteTeamDialogHandle = AlertDialog.createHandle<DeleteTeamPayload>();
-
 export interface TeamsViewProps {
   title?: string;
   description?: string;
@@ -50,6 +44,11 @@ export function TeamsView({
   onTeamClick
 }: TeamsViewProps) {
   const [showOrgTeams, setShowOrgTeams] = useState(false);
+  const teamMenuHandle = useMemo(() => Menu.createHandle<TeamMenuPayload>(), []);
+  const addTeamDialogHandle = useMemo(() => Dialog.createHandle(), []);
+  const editTeamDialogHandle = useMemo(() => Dialog.createHandle<EditTeamPayload>(), []);
+  const deleteTeamDialogHandle = useMemo(() => AlertDialog.createHandle<DeleteTeamPayload>(), []);

105-116: Consider preventing duplicate error toasts on reference changes.

If teamsError changes reference (e.g., due to query re-execution returning the same error), the toast will fire again. This is typically rare but can occur with some query configurations.

♻️ Optional: Track shown errors with a ref
+const shownErrorRef = useRef<unknown>(null);
+
 useEffect(() => {
-  if (teamsError) {
+  if (teamsError && teamsError !== shownErrorRef.current) {
+    shownErrorRef.current = teamsError;
     toastManager.add({
       title: 'Something went wrong',
       description:
         teamsError instanceof Error
           ? teamsError.message
           : 'Failed to load teams',
       type: 'error'
     });
   }
 }, [teamsError]);

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0a15d1dd-995d-4e4f-a937-349bd86136b9

📥 Commits

Reviewing files that changed from the base of the PR and between 4e7b2be and e85b041.

📒 Files selected for processing (17)
  • web/apps/client-demo/src/Router.tsx
  • web/apps/client-demo/src/pages/Settings.tsx
  • web/apps/client-demo/src/pages/settings/TeamDetails.tsx
  • web/apps/client-demo/src/pages/settings/Teams.tsx
  • web/sdk/react/index.ts
  • web/sdk/react/views-new/teams/components/add-member-menu.tsx
  • web/sdk/react/views-new/teams/components/add-team-dialog.tsx
  • web/sdk/react/views-new/teams/components/delete-team-dialog.tsx
  • web/sdk/react/views-new/teams/components/edit-team-dialog.tsx
  • web/sdk/react/views-new/teams/components/member-columns.tsx
  • web/sdk/react/views-new/teams/components/remove-member-dialog.tsx
  • web/sdk/react/views-new/teams/components/team-columns.tsx
  • web/sdk/react/views-new/teams/index.ts
  • web/sdk/react/views-new/teams/team-details-view.module.css
  • web/sdk/react/views-new/teams/team-details-view.tsx
  • web/sdk/react/views-new/teams/teams-view.module.css
  • web/sdk/react/views-new/teams/teams-view.tsx

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

♻️ Duplicate comments (1)
web/sdk/react/views-new/teams/components/add-member-menu.tsx (1)

73-105: ⚠️ Potential issue | 🟠 Major

Prevent duplicate membership writes while add is in-flight.

addMember can be clicked repeatedly before the member list refreshes, which can send duplicate addGroupUsers writes for the same user.

Proposed fix
-import { useCallback, useEffect, useMemo } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
@@
 export function AddMemberMenu({
   teamId,
   canUpdateGroup,
   members,
   refetch
 }: AddMemberMenuProps) {
   const { activeOrganization: organization } = useFrontier();
+  const [isAddingMember, setIsAddingMember] = useState(false);
@@
   const { mutate: addGroupUsers } = useMutation(
     FrontierServiceQueries.addGroupUsers,
     {
       onSuccess: () => {
         toastManager.add({
           title: 'Member added',
           type: 'success'
         });
         refetch();
       },
       onError: (err: Error) => {
         toastManager.add({
           title: 'Something went wrong',
           description: err.message,
           type: 'error'
         });
+      },
+      onSettled: () => {
+        setIsAddingMember(false);
       }
     }
   );
@@
     (userId: string) => {
-      if (!userId || !organization?.id || !teamId) return;
+      if (!userId || !organization?.id || !teamId || isAddingMember) return;
+      setIsAddingMember(true);
       addGroupUsers(
         create(AddGroupUsersRequestSchema, {
           id: teamId,
           orgId: organization.id,
           userIds: [userId]
         })
       );
     },
-    [addGroupUsers, organization?.id, teamId]
+    [addGroupUsers, isAddingMember, organization?.id, teamId]
   );

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a6396305-043f-4759-a8a1-71aa8346b1b5

📥 Commits

Reviewing files that changed from the base of the PR and between e85b041 and 41857a5.

📒 Files selected for processing (5)
  • web/sdk/react/views-new/teams/components/add-member-menu.tsx
  • web/sdk/react/views-new/teams/components/delete-team-dialog.tsx
  • web/sdk/react/views-new/teams/components/team-columns.tsx
  • web/sdk/react/views-new/teams/team-details-view.tsx
  • web/sdk/react/views-new/teams/teams-view.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/sdk/react/views-new/teams/components/delete-team-dialog.tsx
  • web/sdk/react/views-new/teams/teams-view.tsx

Comment on lines +44 to +48
return value ? (
<Text size="regular" variant="secondary">
{value} {value === 1 ? 'member' : 'members'}
</Text>
) : null;
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 | 🟡 Minor

Render 0 members instead of a blank cell.

Line 44 treats 0 as falsy and returns null, so teams with zero members show an empty value. That hides valid data in the table.

Suggested fix
       cell: ({ getValue }) => {
         const value = getValue() as number;
-        return value ? (
+        if (value == null) return null;
+        return (
           <Text size="regular" variant="secondary">
             {value} {value === 1 ? 'member' : 'members'}
           </Text>
-        ) : null;
+        );
       }
📝 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.

Suggested change
return value ? (
<Text size="regular" variant="secondary">
{value} {value === 1 ? 'member' : 'members'}
</Text>
) : null;
if (value == null) return null;
return (
<Text size="regular" variant="secondary">
{value} {value === 1 ? 'member' : 'members'}
</Text>
);

Comment on lines +116 to +128
const {
data: membersData,
isLoading: isMembersLoading,
refetch: refetchMembers
} = useQuery(
FrontierServiceQueries.listGroupUsers,
create(ListGroupUsersRequestSchema, {
id: teamId || '',
orgId: organization?.id || '',
withRoles: true
}),
{ enabled: !!organization?.id && !!teamId }
);
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 | 🟡 Minor

Surface member-list query failures to users.

listGroupUsers failures are currently silent, unlike team/roles query failures.

Proposed fix
   const {
     data: membersData,
     isLoading: isMembersLoading,
+    error: membersError,
     refetch: refetchMembers
   } = useQuery(
@@
   );
+
+  useEffect(() => {
+    if (membersError) {
+      toastManager.add({
+        title: 'Something went wrong',
+        description: membersError.message,
+        type: 'error'
+      });
+    }
+  }, [membersError]);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants