Skip to content
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(web): members setting #1186

Merged
merged 50 commits into from
Oct 28, 2024
Merged

feat(web): members setting #1186

merged 50 commits into from
Oct 28, 2024

Conversation

ZTongci
Copy link
Contributor

@ZTongci ZTongci commented Oct 22, 2024

Overview

What I've done

Add member's page for workspace.

What I haven't done

How I tested

Which point I want you to review particularly

Memo

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced member management functionalities, including adding, updating, and removing members from workspaces.
    • Added a search feature for users by name or email within the workspace.
    • New Members component for managing workspace members.
    • Enhanced workspace settings with improved role management for members.
    • New icons added for better visual representation in the UI.
  • Bug Fixes

    • Improved error handling for workspace operations to ensure valid input is checked before execution.
  • Documentation

    • Updated English translations for user roles and workspace management terms, enhancing user experience.
    • Added new entries related to workspace operations and user management feedback.
  • Chores

    • Removed the disabled state from the "members" tab, enabling user interaction.

@ZTongci ZTongci requested a review from airslice as a code owner October 22, 2024 08:37
Copy link

@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: 0

🧹 Outside diff range and nitpick comments (5)
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (5)

28-59: Consider improving type definitions with JSDoc comments and specific error types.

Add JSDoc comments to document the Props interface and use a more specific error type instead of unknown.

+/**
+ * Props for the Members component
+ */
 type Props = {
+  /** Adds a new member to the workspace */
   handleAddMemberToWorkspace: ({
     teamId,
     userId,
     role
   }: WorkspacePayload) => Promise<void>;
+  /** Searches for a user by name or email */
   handleSearchUser: (nameOrEmail: string) =>
     | {
         searchUser: {
           __typename?: "User";
           id: string;
           name: string;
           email: string;
         } | null;
         searchUserStatus: string;
         error?: undefined;
       }
     | {
-        error: unknown;
+        error: Error;
         searchUser?: undefined;
         searchUserStatus?: undefined;
       };
   // ... rest of the props
 };

125-142: Add cleanup for search results state.

Consider adding a cleanup function to reset the search results when the component unmounts or when the search input is cleared.

 useEffect(() => {
   if (
     searchUser &&
     "name" in searchUser &&
     !memberSearchResults.find(
       (memberSearchResult) => memberSearchResult.id === searchUser.id
     )
   ) {
     setMemberSearchResults([
       ...memberSearchResults,
       {
         userName: searchUser.name,
         email: searchUser.email,
         id: searchUser.id
       }
     ]);
   }
+  return () => {
+    setMemberSearchResults([]);
+  };
 }, [memberSearchResults, searchUser]);

160-165: Add ARIA labels for better accessibility.

The table headers should have proper ARIA labels for better screen reader support.

-<Table>
+<Table role="table" aria-label={t("Workspace members")}>
-  <TableHeader>{t("User Name")}</TableHeader>
+  <TableHeader role="columnheader">{t("User Name")}</TableHeader>
-  <TableHeader>{t("Email")}</TableHeader>
+  <TableHeader role="columnheader">{t("Email")}</TableHeader>
-  <TableHeader>{t("Role")}</TableHeader>
+  <TableHeader role="columnheader">{t("Role")}</TableHeader>
-  <TableHeader />
+  <TableHeader role="columnheader" aria-label={t("Actions")} />

314-326: Add loading state feedback for search input.

The search input should provide visual feedback when the search is in progress.

 <TextInput
   placeholder="name@reearth.io"
   value={memberSearchInput}
+  loading={searchUserStatus === "loading"}
   onChange={(input) => {
     setMemberSearchInput(input);
   }}
   onKeyDown={(e) => {
     if (e.key === "Enter" && memberSearchInput.trim() !== "") {
       setMemberSearchInput("");
       setDebouncedInput(memberSearchInput.trim());
     }
   }}
 />

436-442: Use theme variables for DeleteIcon colors and add hover transition.

Replace hardcoded colors with theme variables and add a smooth transition for the hover effect.

-const DeleteIcon = styled(IconButton)(() => ({
+const DeleteIcon = styled(IconButton)(({ theme }) => ({
   cursor: "pointer",
-  color: "#fff",
+  color: theme.content.main,
+  transition: "color 0.2s ease-in-out",
   "&:hover": {
-    color: "red"
+    color: theme.danger.main
   }
 }));
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7a80757 and 20d4a34.

📒 Files selected for processing (2)
  • web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1 hunks)
  • web/src/services/state/index.ts (2 hunks)
🧰 Additional context used
🪛 Biome
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx

[error] 339-364: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (2)
web/src/services/state/index.ts (2)

4-4: LGTM: Clean type import addition

The TeamMember type import is well-placed and properly supports the type enhancement in the Workspace interface.


54-54: Type enhancement improves safety, verify usage

The change from any[] to TeamMember[] improves type safety and reduces potential runtime errors. However, as this is a breaking change, we should verify all usages of workspace.members have been updated accordingly.

Let's verify all usages of workspace.members:

✅ Verification successful

Let me try a different approach to search for usages of the members property.

This should help us find:

  1. All occurrences of "members" in TypeScript files with context
  2. The Workspace interface definition to understand the full context
  3. By analyzing the context of these results, we can determine if there are any compatibility issues with the type change

Let me try one more time with a different search strategy.

This should help us:

  1. Confirm we can find TypeScript files
  2. Find occurrences of "members" with context
  3. Find usage of the Workspace type to understand the impact

Based on the search results, I can see that the members property is extensively used throughout the codebase in the context of workspaces/teams. The type change from any[] to TeamMember[] is properly handled as:

  1. The GraphQL schema already defines members with proper typing (TeamMember type with user, userId, and role fields)
  2. All usages of workspace.members in components like Members, WorkspaceSettings, etc. expect and handle the TeamMember type
  3. The mutations (AddMemberToWorkspace, RemoveMemberFromWorkspace, etc.) all work with the properly typed TeamMember structure
  4. The state management and hooks are consistently using the TeamMember type

Type enhancement is safe and properly integrated

The change from any[] to TeamMember[] aligns with the existing codebase implementation and improves type safety without breaking existing functionality, as all consumers are already working with the TeamMember structure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of workspace.members to ensure compatibility with the new type

# Search for direct member access patterns
echo "Checking direct workspace.members access:"
rg -l "workspace\.members" --type ts --type tsx

# Search for destructured member access patterns
echo -e "\nChecking destructured members access:"
rg -l "const.*\{.*members.*\}.*=.*workspace" --type ts --type tsx

Length of output: 357


Script:

#!/bin/bash
# Search for any mentions of members in TypeScript files
echo "Searching for workspace members usage:"
rg "members" --type typescript -C 2

# Search for Workspace interface usage
echo -e "\nSearching for Workspace interface usage:"
ast-grep --pattern 'interface Workspace {
  $$$
}'

Length of output: 307


Script:

#!/bin/bash
# Search for files with .ts extension first
echo "TypeScript files in the repository:"
fd ".*\.ts$"

# Then search for members usage in those files
echo -e "\nSearching for members usage:"
rg "members" -t ts -C 2

# Look for Workspace type usage
echo -e "\nSearching for Workspace type usage:"
rg "Workspace" -t ts -C 2

Length of output: 258609

Copy link

@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: 6

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 20d4a34 and 24296d6.

📒 Files selected for processing (1)
  • web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx

[error] 340-365: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

web/src/beta/features/WorkspaceSetting/hooks.ts Outdated Show resolved Hide resolved
web/src/beta/features/WorkspaceSetting/hooks.ts Outdated Show resolved Hide resolved
web/src/beta/features/WorkspaceSetting/hooks.ts Outdated Show resolved Hide resolved
web/src/beta/features/WorkspaceSetting/hooks.ts Outdated Show resolved Hide resolved
Copy link

@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: 1

🧹 Outside diff range and nitpick comments (5)
web/src/beta/features/Dashboard/ContentsContainer/Members/ListItem.tsx (1)

Type compatibility verified with potential issue found

The type verification reveals a potential issue with the email field access. In the User type definition, email is marked as optional (email?: string), which matches with the component's safe optional chaining usage (member.user?.email). However, there's a risk of displaying empty content when email is undefined.

  • Consider adding a fallback value or conditional rendering when member.user?.email is undefined
  • All other accessed properties are correctly defined:
    • role is a required field in TeamMember
    • user is optional in TeamMember (correctly accessed with ?.)
    • name is a required string in User type
    • email is an optional string in User type
🔗 Analysis chain

Line range hint 6-31: Verify type compatibility with TeamMember interface

The component implementation looks good, but let's verify that all accessed properties are defined in the TeamMember interface.


Let me verify the User type definition to ensure it has the required fields (name and email) that are being accessed in the component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the TeamMember interface contains all required fields
# Expected fields: user.name, user.email, role

# Search for TeamMember type definition
ast-grep --pattern 'type TeamMember = {
  $$$
}'

# Alternative: Search for TeamMember interface definition
ast-grep --pattern 'interface TeamMember {
  $$$
}'

Length of output: 504


Script:

#!/bin/bash
# Search for User type definition to verify name and email fields
ast-grep --pattern 'type User = {
  $$$
}'

# Also search for Role type/enum since it's used in TeamMember
ast-grep --pattern 'enum Role {
  $$$
}'

Length of output: 754

web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (4)

28-59: Improve type safety and readability of Props interface

Consider these improvements to the Props interface:

  1. Type the role parameter explicitly as Role enum
  2. Consider inlining the WorkspacePayload type for better readability
type Props = {
  handleAddMemberToWorkspace: ({
    teamId,
    userId,
-   role
+   role: Role,
+   name?: string
  }: WorkspacePayload) => Promise<void>;
  // ... other handlers
};

61-66: Improve MembersData type definition

The type could be more specific and clearer:

-type MembersData = {
+interface Member {
+  id: string;
+  role: Role;
+  username: string; // Make required
+  email: string; // Make required
+}
+
+type MembersData = Member[];
-}[];

161-166: Improve table accessibility

The table structure needs proper ARIA roles and labels for better accessibility.

-<Table>
+<Table role="table" aria-label={t("Workspace members")}>
-  <TableHeader>{t("User Name")}</TableHeader>
+  <TableHeader role="columnheader">{t("User Name")}</TableHeader>
-  <TableHeader>{t("Email")}</TableHeader>
+  <TableHeader role="columnheader">{t("Email")}</TableHeader>
-  <TableHeader>{t("Role")}</TableHeader>
+  <TableHeader role="columnheader">{t("Role")}</TableHeader>
-  <TableHeader />
+  <TableHeader role="columnheader" aria-label={t("Actions")} />

373-380: Add reduced motion support for animations

Consider users who prefer reduced motion for accessibility reasons.

+const reducedMotion = keyframes`
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+`;
+
 const zoomIn = keyframes`
   from {
     opacity: 0;
+    transform: scale(0.95);
   }
   to {
     opacity: 1;
+    transform: scale(1);
   }
 `;
+
+const getAnimation = () => css`
+  @media (prefers-reduced-motion: no-preference) {
+    animation: ${zoomIn} 0.2s ease-in-out;
+  }
+  @media (prefers-reduced-motion: reduce) {
+    animation: ${reducedMotion} 0.2s ease-in-out;
+  }
+`;

Then update the components using the animation:

 const TableRow = styled("div")(({ theme }) => ({
   // ...other styles
-  animation: `${zoomIn} 0.2s ease-in-out`
+  ...getAnimation()
 }));

 const UserInfo = styled.div`
   // ...other styles
-  animation: ${zoomIn} 0.2s ease-in-out;
+  ${getAnimation()};
 `;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d878fa6 and f013644.

📒 Files selected for processing (2)
  • web/src/beta/features/Dashboard/ContentsContainer/Members/ListItem.tsx (1 hunks)
  • web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx

[error] 340-365: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (2)
web/src/beta/features/Dashboard/ContentsContainer/Members/ListItem.tsx (2)

2-2: LGTM: Proper typing from GraphQL schema

The import of TeamMember from the GraphQL services ensures type safety and consistency with the backend schema.


Line range hint 33-62: LGTM: Well-structured styled components

The styled components are well-organized and follow good practices:

  • Proper use of theme variables
  • Semantic naming
  • Responsive grid layout
  • Appropriate handling of text overflow

Copy link

@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: 5

🧹 Outside diff range and nitpick comments (1)
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1)

70-74: Follow TypeScript naming conventions

The type name memberSearchResult should follow PascalCase convention for consistency with other type definitions.

-type memberSearchResult = {
+type MemberSearchResult = {
   userName: string;
   email: string;
   id: string;
};
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f013644 and 8c7593f.

📒 Files selected for processing (2)
  • web/src/beta/features/WorkspaceSetting/hooks.ts (7 hunks)
  • web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx

[error] 368-387: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (4)
web/src/beta/features/WorkspaceSetting/hooks.ts (4)

1-1: LGTM! Type definitions align with the new functionality.

The optional name field in WorkspacePayload and the new imports support the member management features appropriately.

Also applies to: 6-6


27-28: LGTM! Hook initialization is correct.

The addition of useUpdateMemberOfWorkspace is consistent with the new member management functionality.


96-104: LGTM! Member update function follows established patterns.

The implementation is consistent with other member management functions.


125-127: LGTM! Return object properly exports all functions.

The new functions are correctly added to the return object.

Copy link

@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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8c7593f and f4e7c22.

📒 Files selected for processing (1)
  • web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx

[error] 368-387: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Copy link

@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

🧹 Outside diff range and nitpick comments (2)
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (2)

23-24: Simplify imports by importing 'Fragment' from 'react'

To maintain consistency with other React imports, consider importing Fragment directly from "react" instead of "react/jsx-runtime".

Apply this diff:

 import { FC, KeyboardEvent, useEffect, useState } from "react";
-import { Fragment } from "react/jsx-runtime";
+import { Fragment } from "react";

70-74: Ensure consistent naming for 'username' property

The property is named username in MemberData and userName in MemberSearchResult. For consistency and better readability, consider using username in both types.

Apply this diff to MemberSearchResult:

 type MemberSearchResult = {
-  userName: string;
+  username: string;
   email: string;
   id: string;
 };

And update all references of userName to username in the code.

Also applies to: 62-65

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f4e7c22 and 01390bd.

📒 Files selected for processing (1)
  • web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx

[error] 368-387: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (5)
web/src/beta/features/WorkspaceSetting/innerPages/Members/Members.tsx (5)

129-146: Optimize search results update logic

Including memberSearchResults in the dependency array while updating it can cause unnecessary re-renders. Consider removing it to optimize performance.


199-223: Handle errors when adding members to the workspace

To maintain UI consistency and handle potential failures, consider adding error handling to the handleAddMember function.


156-182: Add error handling when updating member roles

Including error handling in handleChangeRole ensures that any issues during the role update are properly managed and the user is informed.


185-197: Implement error handling when removing members

To prevent inconsistencies and inform the user of any issues, add error handling to handleRemoveMemberButtonClick.


266-267: ⚠️ Potential issue

Use unique keys when rendering list items

Using array indices as keys can lead to unexpected behavior. It's better to use a unique identifier like user.id for the key prop to ensure consistency during re-renders.

Apply this diff:

-{workspaceMembers?.map((user, index) => (
-  <Fragment key={index}>
+{workspaceMembers?.map((user) => (
+  <Fragment key={user.id}>

Likely invalid or redundant comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants