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: support user search #1285

Merged
merged 10 commits into from
Nov 18, 2024
Merged

feat: support user search #1285

merged 10 commits into from
Nov 18, 2024

Conversation

yk-eukarya
Copy link
Contributor

@yk-eukarya yk-eukarya commented Oct 25, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced user search capabilities with two new queries: userSearch for keyword-based searches and userByNameOrEmail for specific user retrieval.
    • Updated Me type to include myWorkspaceId and auths fields for more user-specific information.
    • Improved MemberAddModal component for better user search and selection management.
  • Bug Fixes

    • Improved error handling and response validation in user-related queries.
  • Documentation

    • Updated GraphQL schema to reflect new user query structures and additional fields in the Me type.
    • Comprehensive overhaul of English and Japanese translations for user interface strings.

@yk-eukarya yk-eukarya self-assigned this Oct 25, 2024
@yk-eukarya yk-eukarya requested a review from rot1024 as a code owner October 25, 2024 13:00
Copy link
Contributor

coderabbitai bot commented Oct 25, 2024

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • go.work.sum is excluded by !**/*.sum

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The pull request introduces significant modifications to the user-related GraphQL functionalities. Key changes include renaming and restructuring existing test functions and GraphQL query methods to enhance clarity and specificity. A new search functionality has been added, allowing users to be retrieved by name or email or via a keyword search. The GraphQL schema and resolver implementations are updated accordingly, reflecting these changes, while the go.mod file sees an update in the dependency version for reearthx. Overall, the changes improve the organization and functionality of user queries.

Changes

File Change Summary
server/e2e/gql_user_test.go - Renamed TestSearchUser to TestUserByNameOrEmail.
- Added TestUserSearch for keyword-based user search.
server/go.mod - Updated dependency version for github.com/reearth/reearthx from v0.0.0-20241023075926-e29bdd6c4ae3 to v0.0.0-20241025125329-f01a05daf443.
server/internal/adapter/gql/generated.go - Replaced SearchUser with UserByNameOrEmail and UserSearch methods.
- Updated GraphQL query definitions accordingly.
server/internal/adapter/gql/loader_user.go - Renamed SearchUser to ByNameOrEmail.
- Added Search method for fetching users by keyword.
server/internal/adapter/gql/resolver_user.go - Removed SearchUser resolver.
- Added UserSearch and UserByNameOrEmail resolvers.
server/schemas/user.graphql - Replaced searchUser with userSearch and userByNameOrEmail in the GraphQL schema.
- Updated Me type to include new fields.
web/src/components/atoms/AutoComplete/index.ts - Added export for AutoCompleteProps type from antd.
web/src/components/molecules/Member/MemberAddModal/index.tsx - Updated props and state management for user search functionality.
- Replaced Search component with AutoComplete.
web/src/components/organisms/Settings/Members/hooks.ts - Updated user fetching query and state management for searched users.
web/src/components/organisms/Settings/Members/index.tsx - Renamed state variables for user search functionality and updated props for MemberAddModal.
web/src/gql/graphql-client-api.tsx - Renamed and restructured user-related queries to enhance clarity.
web/src/gql/queries/user.ts - Renamed GET_USER_BY_SEARCH to GET_USER_BY_NAME_OR_EMAIL and added GET_USERS query.
web/src/i18n/translations/en.yml - Complete replacement of English translations.
web/src/i18n/translations/ja.yml - Complete replacement of Japanese translations.

Possibly related PRs

Suggested reviewers

  • nourbalaha

🐰 In the meadow where bunnies play,
New queries bloom, brightening the day.
With names and keywords, we hop and search,
Finding our friends in a joyful lurch!
So let us cheer for the changes made,
In our GraphQL garden, let joy cascade! 🌼✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

netlify bot commented Oct 25, 2024

Deploy Preview for reearth-cms canceled.

Name Link
🔨 Latest commit e462a10
🔍 Latest deploy log https://app.netlify.com/sites/reearth-cms/deploys/673af9883e38eb00076e355f

Copy link
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

🧹 Outside diff range and nitpick comments (9)
server/schemas/user.graphql (1)

41-42: Add query descriptions and consider pagination

The new search queries lack descriptions explaining their behavior. Additionally, userSearch returns an unbounded array which could cause performance issues with large datasets.

Consider adding descriptions and implementing pagination:

 extend type Query {
   me: Me
-  userSearch(keyword: String!): [User!]!
-  userByNameOrEmail(nameOrEmail: String!): User
+  """
+  Search users by keyword matching against name and email
+  """
+  userSearch(
+    keyword: String!
+    first: Int
+    after: String
+  ): UserConnection!
+  """
+  Find a single user by exact name or email match
+  """
+  userByNameOrEmail(nameOrEmail: String!): User
 }

+"""
+Connection type for paginated user results
+"""
+type UserConnection {
+  edges: [UserEdge!]!
+  pageInfo: PageInfo!
+  totalCount: Int!
+}
+
+type UserEdge {
+  node: User!
+  cursor: String!
+}

This change:

  1. Adds clear descriptions of query behavior
  2. Implements cursor-based pagination for scalability
  3. Provides total count for UI features like "showing X of Y results"
server/internal/adapter/gql/loader_user.go (2)

44-52: Consider adding input validation for nameOrEmail parameter.

The method implementation looks good and the rename makes the purpose clearer. However, consider adding validation to ensure nameOrEmail is not empty or contains valid characters.

 func (c *UserLoader) ByNameOrEmail(ctx context.Context, nameOrEmail string) (*gqlmodel.User, error) {
+	if strings.TrimSpace(nameOrEmail) == "" {
+		return nil, errors.New("nameOrEmail cannot be empty")
+	}
 	res, err := c.usecase.FetchByNameOrEmail(ctx, nameOrEmail)

53-62: Consider adding pagination and input validation.

The implementation is clean and effectively uses lo.Map for type conversion. However, consider these improvements:

  1. Add pagination to handle potentially large result sets efficiently
  2. Add input validation for the search parameter
  3. Consider adding a minimum search term length requirement to prevent overly broad searches

Consider implementing cursor-based pagination:

-func (c *UserLoader) Search(ctx context.Context, nameOrEmail string) ([]*gqlmodel.User, error) {
+func (c *UserLoader) Search(ctx context.Context, nameOrEmail string, first int, after *string) (*gqlmodel.UserConnection, error) {
+	if strings.TrimSpace(nameOrEmail) == "" {
+		return nil, errors.New("search term cannot be empty")
+	}
+	if len(nameOrEmail) < 3 {
+		return nil, errors.New("search term must be at least 3 characters")
+	}
 	res, err := c.usecase.SearchUser(ctx, nameOrEmail)
 	if err != nil {
 		return nil, err
 	}
-	return lo.Map(res, func(u *user.Simple, _ int) *gqlmodel.User {
+	users := lo.Map(res, func(u *user.Simple, _ int) *gqlmodel.User {
 		return gqlmodel.SimpleToUser(u)
-	}), nil
+	})
+	return gqlmodel.NewUserConnection(users, first, after), nil
 }
server/e2e/gql_user_test.go (2)

Line range hint 210-243: Consider adding more test cases for comprehensive coverage.

While the current test cases cover basic name lookup and not found scenarios, consider adding:

  1. Email-based lookup test case
  2. Invalid input validation (empty string, special characters)
  3. Error cases (unauthorized access)

Would you like me to help generate these additional test cases?


Line range hint 210-300: Add test documentation for better maintainability.

Consider adding documentation comments to describe:

  1. The purpose and scope of each test function
  2. The test data setup requirements
  3. The expected behavior for each test case

Example documentation format:

// TestUserByNameOrEmail verifies the userByNameOrEmail GraphQL query
// by testing user lookup by name or email.
//
// Test cases:
// - Successful lookup by name
// - User not found
server/internal/adapter/gql/generated.go (4)

561-562: Add documentation comments for new methods

The new methods UserByNameOrEmail and UserSearch in the ComplexityRoot struct lack documentation comments. Adding comments will improve code maintainability and readability.


1026-1027: Add documentation comments for new interface methods

The methods UserSearch and UserByNameOrEmail in the QueryResolver interface should include documentation comments to explain their purpose and usage.


6627-6628: Add descriptions to new GraphQL query fields

The new query fields userSearch and userByNameOrEmail in the GraphQL schema lack descriptions. Adding GraphQL schema descriptions enhances API documentation.


Line range hint 45851-45857: Consistent error recovery in 'userByNameOrEmail' resolver

Ensure that the error recovery mechanism in the userByNameOrEmail resolver matches the patterns used elsewhere to maintain consistency.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 411360d and 923405d.

⛔ Files ignored due to path filters (2)
  • go.work.sum is excluded by !**/*.sum
  • server/go.sum is excluded by !**/*.sum
📒 Files selected for processing (6)
  • server/e2e/gql_user_test.go (3 hunks)
  • server/go.mod (1 hunks)
  • server/internal/adapter/gql/generated.go (12 hunks)
  • server/internal/adapter/gql/loader_user.go (1 hunks)
  • server/internal/adapter/gql/resolver_user.go (1 hunks)
  • server/schemas/user.graphql (1 hunks)
🔇 Additional comments (9)
server/schemas/user.graphql (1)

Line range hint 8-19: Add field descriptions and verify non-null constraints

The new fields myWorkspaceId and auths lack descriptions explaining their purpose. Additionally, both fields are marked as non-nullable which may cause issues with existing data.

Consider adding descriptions and verifying the constraints:

 type Me {
   id: ID!
   name: String!
   email: String!
   lang: Lang!
   theme: Theme!
   host: String
-  myWorkspaceId: ID!
-  auths: [String!]!
+  """
+  The ID of the user's primary workspace
+  """
+  myWorkspaceId: ID!
+  """
+  List of authentication methods enabled for this user
+  """
+  auths: [String!]!
   workspaces: [Workspace!]!
   myWorkspace: Workspace
   integrations: [Integration!]!
 }

Let's verify if all users have workspaces:

✅ Verification successful

Let's gather more specific information about workspace handling in the codebase.


Let's check one more aspect focusing on user creation and initialization:


Based on the evidence gathered, I can now generate the final response:

Non-null constraints for myWorkspaceId and auths are safe to implement

The codebase shows that:

  • Workspace ID is required during user signup (server/e2e/http_user_test.go)
  • User-workspace relationship is a core part of the system's design (CreateUserInput in http/user.go includes WorkspaceID)
  • Authentication is handled through the auth_client, ensuring users always have at least one auth method

Consider adding descriptions to improve schema documentation:

"""
The ID of the user's primary workspace. Always present as workspace is required during signup.
"""
myWorkspaceId: ID!

"""
List of authentication methods enabled for this user. Always contains at least one auth method.
"""
auths: [String!]!
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there are any existing users without workspaces
# Note: This helps validate if the non-null constraint is safe to add

# Search for user-related database queries or models
rg -l "workspace.*user|user.*workspace" --type go

# Search for workspace assignment logic
ast-grep --pattern 'func $$$($$$) {
  $$$
  workspace$$$
  $$$
}'

Length of output: 314


Script:

#!/bin/bash
# Check workspace-related code in auth_client and resolver
rg -A 10 "workspace.*user|user.*workspace" server/internal/app/auth_client.go server/internal/adapter/gql/resolver_workspace.go

# Look for workspace creation/assignment logic
ast-grep --pattern 'func $$$($$$) {
  $$$
  createWorkspace$$$
  $$$
}'

# Check if there's any default/fallback workspace logic
rg -A 5 "default.*workspace|fallback.*workspace" --type go

Length of output: 1971


Script:

#!/bin/bash
# Look for user creation/initialization logic
rg -A 10 "func.*CreateUser|func.*InitializeUser|func.*SignUp" --type go

# Check for workspace initialization during user creation
ast-grep --pattern 'type User struct {
  $$$
}'

# Look for user-workspace relationship in models/entities
rg -A 5 "type.*User" --type go

Length of output: 15096

server/internal/adapter/gql/resolver_user.go (2)

91-93: ⚠️ Potential issue

Enhance input validation and error handling

The current implementation could expose user enumeration vulnerabilities. Consider the following improvements:

  1. Validate email format when the input appears to be an email
  2. Return consistent error messages regardless of whether the user exists
  3. Add rate limiting to prevent brute force attempts

Let's check the loader implementation for existing validation:

#!/bin/bash
# Search for the ByNameOrEmail implementation in the loader
ast-grep --pattern 'type UserLoader struct {
  $$$
  ByNameOrEmail(ctx context.Context, nameOrEmail string) $$ {
    $$$
  }
  $$$
}'

Consider implementing:

func (r *queryResolver) UserByNameOrEmail(ctx context.Context, nameOrEmail string) (*gqlmodel.User, error) {
+       if strings.Contains(nameOrEmail, "@") {
+               if err := validateEmail(nameOrEmail); err != nil {
+                       return nil, gqlmodel.NewError(err)
+               }
+       }
        return loaders(ctx).User.ByNameOrEmail(ctx, nameOrEmail)
}

86-89: Consider adding input validation and pagination

The implementation could benefit from several improvements:

  1. Add input validation for the keyword parameter to prevent DoS attacks via extremely long search terms
  2. Implement pagination to handle large result sets efficiently
  3. Consider adding rate limiting to prevent abuse

Let's check if pagination is implemented in the loader:

Consider implementing:

  • Pagination using cursor-based or offset/limit approach
  • Input validation: if len(keyword) > MaxKeywordLength { return nil, ErrKeywordTooLong }
  • Rate limiting middleware for search endpoints
server/go.mod (1)

30-31: LGTM! Verify the reearthx dependency update.

The update of github.com/reearth/reearthx to the newer version looks good and aligns with the PR's user search feature implementation.

Let's verify the changes in the reearthx dependency:

✅ Verification successful

Based on the search results, I can see that the reearthx dependency is heavily used throughout the codebase, particularly for user-related functionality through the account/accountdomain/user package. The imports show it's used consistently in tests and implementation code for user authentication, workspace management, and GraphQL resolvers.

The dependency update appears safe to proceed.

  • The update is a minor version bump (two days difference in pseudo-versions)
  • The imports show the dependency is used in a stable way across the codebase
  • The user-related imports are primarily from the account package, which aligns with the PR's user search feature
  • No breaking changes are evident as the imports follow a consistent pattern
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for breaking changes in the reearthx dependency between the old and new versions

# Get the commit messages between the two versions to understand the changes
git clone https://github.com/reearth/reearthx.git /tmp/reearthx
cd /tmp/reearthx
git log --oneline v0.0.0-20241023075926-e29bdd6c4ae3..v0.0.0-20241025125329-f01a05daf443

# Check if there are any changes to user-related functionality
git diff v0.0.0-20241023075926-e29bdd6c4ae3..v0.0.0-20241025125329-f01a05daf443 -- "*user*"

Length of output: 707


Script:

#!/bin/bash
# Let's try a different approach to check the dependency changes

# First, let's check if there are any references to reearthx in the codebase
rg -l "reearthx" --type go

# Then, let's look for any user-related imports or usage from reearthx
rg "reearthx.*user" --type go -A 2

# Also check for any breaking changes in the go.sum
cat server/go.sum | grep "github.com/reearth/reearthx" | sort

Length of output: 24705

server/internal/adapter/gql/generated.go (5)

9688-9698: Ensure argument parsing handles all cases

In the function field_Query_userByNameOrEmail_args, verify that all possible argument scenarios are handled correctly, including error cases.


9720-9750: Proper handling of required 'keyword' argument

The field_Query_userSearch_args function should ensure that the keyword argument is properly validated, as it is a required field. The current implementation seems to handle it correctly.


Line range hint 25286-25313: Handle null results in 'UserByNameOrEmail' resolver

In the _Query_userByNameOrEmail resolver, ensure that the function correctly handles cases where a user is not found and returns null as per GraphQL specifications.


45820-45842: Ensure proper error handling in concurrent execution

In the concurrent execution logic for userSearch, make sure that errors are properly captured and returned to prevent panics during field resolution.


3485-3507: ⚠️ Potential issue

Syntax error: Incorrect colon in if statement

At line 3498, there is a colon : instead of an opening brace { in the if statement, which will result in a syntax error.

Apply this diff to fix the syntax error:

-		if e.complexity.Query.UserSearch == nil:
+		if e.complexity.Query.UserSearch == nil {

Likely invalid or redundant comment.

Comment on lines +245 to +300
func TestUserSearch(t *testing.T) {
e := StartServer(t, &app.Config{}, true, baseSeederUser)
query := fmt.Sprintf(` { userSearch(keyword: "%s"){ id name email } }`, "e2e")
request := GraphQLRequest{
Query: query,
}
jsonData, err := json.Marshal(request)
if err != nil {
assert.NoError(t, err)
}
res := e.POST("/api/graphql").
WithHeader("authorization", "Bearer test").
WithHeader("Content-Type", "application/json").
WithHeader("X-Reearth-Debug-User", uId1.String()).
WithBytes(jsonData).Expect().Status(http.StatusOK).JSON().Object()
ul := res.Value("data").Object().Value("userSearch").Array()
ul.Length().IsEqual(4)
o := ul.Value(0).Object()
o.Value("id").String().IsEqual(uId1.String())
o.Value("name").String().IsEqual("e2e")
o.Value("email").String().IsEqual("[email protected]")

query = fmt.Sprintf(` { userSearch(keyword: "%s"){ id name email } }`, "e2e2")
request = GraphQLRequest{
Query: query,
}
jsonData, err = json.Marshal(request)
if err != nil {
assert.NoError(t, err)
}
res = e.POST("/api/graphql").
WithHeader("authorization", "Bearer test").
WithHeader("Content-Type", "application/json").
WithHeader("X-Reearth-Debug-User", uId1.String()).
WithBytes(jsonData).Expect().Status(http.StatusOK).JSON().Object()
ul = res.Value("data").Object().Value("userSearch").Array()
ul.Length().IsEqual(1)
o = ul.Value(0).Object()
o.Value("id").String().IsEqual(uId2.String())
o.Value("name").String().IsEqual("e2e2")
o.Value("email").String().IsEqual("[email protected]")

query = fmt.Sprintf(` { userSearch(keyword: "%s"){ id name email } }`, "notfound")
request = GraphQLRequest{
Query: query,
}
jsonData, err = json.Marshal(request)
if err != nil {
assert.NoError(t, err)
}
e.POST("/api/graphql").
WithHeader("authorization", "Bearer test").
WithHeader("Content-Type", "application/json").
WithHeader("X-Reearth-Debug-User", uId1.String()).
WithBytes(jsonData).Expect().Status(http.StatusOK).JSON().Object().
Value("data").Object().Value("userSearch").Array().IsEmpty()
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve test reliability and coverage.

The current implementation has several areas that could be improved:

  1. The test is tightly coupled to specific test data:

    • Assumes exactly 4 users match "e2e"
    • Assumes specific ordering of results
  2. Missing test cases:

    • Pagination parameters
    • Case sensitivity
    • Special characters in search
    • Minimum keyword length validation

Consider refactoring the test to be more resilient to data changes:

- ul.Length().IsEqual(4)
+ ul.Length().Gt(0)  // Assert some results exist

Also, consider adding validation for result ordering or explicitly documenting if the order is undefined.

Would you like me to help implement the additional test cases and make the tests more resilient?

Committable suggestion was skipped due to low confidence.

Comment on lines 25220 to 25283
func (ec *executionContext) _Query_userSearch(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_userSearch(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().UserSearch(rctx, fc.Args["keyword"].(string))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]*gqlmodel.User)
fc.Result = res
return ec.marshalNUser2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑcmsᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUserᚄ(ctx, field.Selections, res)
}

func (ec *executionContext) fieldContext_Query_userSearch(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Query",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_User_id(ctx, field)
case "name":
return ec.fieldContext_User_name(ctx, field)
case "email":
return ec.fieldContext_User_email(ctx, field)
case "host":
return ec.fieldContext_User_host(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Query_userSearch_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Implement pagination for 'UserSearch' results

Returning all users in UserSearch without pagination could lead to performance issues with large user datasets.

Consider adding pagination parameters to the userSearch query to handle large datasets efficiently.

Copy link
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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 923405d and 98408ea.

⛔ Files ignored due to path filters (2)
  • go.work.sum is excluded by !**/*.sum
  • server/go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • server/go.mod (1 hunks)
  • server/internal/adapter/gql/resolver_user.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/go.mod
🔇 Additional comments (1)
server/internal/adapter/gql/resolver_user.go (1)

86-93: Implementation aligns well with PR objectives.

The code successfully implements user search functionality with two complementary methods:

  1. UserSearch for general keyword-based search
  2. UserByNameOrEmail for specific user lookup

The separation of concerns between these methods is clean and logical.

Let's verify the GraphQL schema matches these resolvers:

✅ Verification successful

Implementation aligns well with GraphQL schema and PR objectives

The GraphQL schema in server/schemas/user.graphql perfectly matches the resolver implementation:

extend type Query {
  userSearch(keyword: String!): [User!]!
  userByNameOrEmail(nameOrEmail: String!): User
}

Both the resolver methods and their corresponding schema definitions are consistent in terms of:

  • Method names
  • Parameter types
  • Return types
  • Nullability constraints
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the GraphQL schema defines these query fields
rg -A 2 'type Query' server/internal/adapter/gql/schema/*.graphql

Length of output: 154


Script:

#!/bin/bash
# Let's first find the GraphQL schema files
fd -e graphql -e gql

# Then check their content for Query type definitions
rg -A 5 'type Query'

Length of output: 19309

Comment on lines +86 to +89
// UserSearch is the resolver for the userSearch field.
func (r *queryResolver) UserSearch(ctx context.Context, keyword string) ([]*gqlmodel.User, error) {
return loaders(ctx).User.Search(ctx, keyword)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding input validation and pagination.

While the implementation is clean, consider these improvements for production readiness:

  1. Add input validation for the keyword parameter (e.g., minimum length)
  2. Implement pagination to handle large result sets efficiently

Example implementation with validation:

func (r *queryResolver) UserSearch(ctx context.Context, keyword string) ([]*gqlmodel.User, error) {
+       if len(strings.TrimSpace(keyword)) < 2 {
+               return nil, errors.New("search keyword must be at least 2 characters")
+       }
        return loaders(ctx).User.Search(ctx, keyword)
}

Committable suggestion was skipped due to low confidence.

Comment on lines +91 to +93
// UserByNameOrEmail is the resolver for the userByNameOrEmail field.
func (r *queryResolver) UserByNameOrEmail(ctx context.Context, nameOrEmail string) (*gqlmodel.User, error) {
return loaders(ctx).User.ByNameOrEmail(ctx, nameOrEmail)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation and clarify search behavior.

The implementation could benefit from:

  1. Input validation for the nameOrEmail parameter
  2. Documentation clarifying the search priority (name vs. email) and matching behavior

Example implementation with validation and documentation:

+// UserByNameOrEmail searches for a user by their name or email address.
+// The search is case-insensitive and returns the first matching user.
 func (r *queryResolver) UserByNameOrEmail(ctx context.Context, nameOrEmail string) (*gqlmodel.User, error) {
+       if nameOrEmail = strings.TrimSpace(nameOrEmail); nameOrEmail == "" {
+               return nil, errors.New("name or email parameter cannot be empty")
+       }
        return loaders(ctx).User.ByNameOrEmail(ctx, nameOrEmail)
}
📝 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
// UserByNameOrEmail is the resolver for the userByNameOrEmail field.
func (r *queryResolver) UserByNameOrEmail(ctx context.Context, nameOrEmail string) (*gqlmodel.User, error) {
return loaders(ctx).User.ByNameOrEmail(ctx, nameOrEmail)
// UserByNameOrEmail searches for a user by their name or email address.
// The search is case-insensitive and returns the first matching user.
func (r *queryResolver) UserByNameOrEmail(ctx context.Context, nameOrEmail string) (*gqlmodel.User, error) {
if nameOrEmail = strings.TrimSpace(nameOrEmail); nameOrEmail == "" {
return nil, errors.New("name or email parameter cannot be empty")
}
return loaders(ctx).User.ByNameOrEmail(ctx, nameOrEmail)
}

@caichi-t caichi-t requested a review from nourbalaha as a code owner October 28, 2024 11:44
@github-actions github-actions bot added the web label Oct 28, 2024
Copy link
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: 12

🧹 Outside diff range and nitpick comments (8)
web/src/gql/queries/user.ts (1)

Line range hint 15-21: Consider adding pagination and improving naming clarity.

While the query implementation is functional, consider these improvements:

  1. Add pagination to handle large result sets efficiently
  2. Consider renaming to GET_USERS_BY_KEYWORD for better clarity
  3. Consider adding a limit parameter to control result size

Here's a suggested implementation:

 export const GET_USERS = gql`
-  query GetUsers($keyword: String!) {
-    userSearch(keyword: $keyword) {
+  query GetUsersByKeyword($keyword: String!, $limit: Int, $offset: Int) {
+    userSearch(keyword: $keyword, limit: $limit, offset: $offset) {
       id
       name
       email
+      cursor
+    }
+    pageInfo {
+      hasNextPage
+      totalCount
+    }
   }
 `;
web/src/components/organisms/Settings/Members/hooks.ts (1)

258-264: Consider adding a TypeScript interface for the hook return type.

The hook returns a large object with many properties. Adding a TypeScript interface would improve maintainability and provide better type safety.

interface UseSettingsMembersReturn {
  searchedUsers: User[];
  selectedUsers: User[];
  handleUserSearch: (keyword: string) => Promise<void>;
  searchLoading: boolean;
  handleUserAdd: (user: User) => void;
  // ... other properties
}
web/src/i18n/translations/en.yml (2)

287-288: Standardize template string format

The template strings use a different syntax compared to other messages. Consider using a consistent format across all translations.

-Are you sure you want to delete this model: Are you sure you want to delete this model <strong>{{name}}</strong>?
+Are you sure you want to delete model "{{name}}"?: ''
-Are you sure you want to delete this group: Are you sure you want to delete this group <strong>{{name}}</strong>?
+Are you sure you want to delete group "{{name}}"?: ''

1-559: Consider organizing translations into logical sections

The translation file would benefit from a more structured organization. Consider:

  1. Grouping related translations using YAML sections
  2. Adding comments to separate different functional areas
  3. Using nested keys for better maintainability

Example structure:

# Common UI elements
common:
  loading: 'Loading...'
  error: 'Oops!'
  
# User management
users:
  search:
    title: 'Search Users'
    no_results: 'No Results Found'

This organization would make the file more maintainable and easier to update as the application grows.

web/src/i18n/translations/ja.yml (1)

395-395: Untranslated technical terms

Several technical terms are left untranslated, which might affect consistency in the Japanese UI:

  • "example" (line 395)
  • "WRITER", "READER", "MAINTAINER", "OWNER" (lines 422-425) are in all caps English

Consider translating these terms consistently:

-example: ''
+example: '例'

-WRITER: 編集者
+writer: 編集者
-READER: 閲覧者
+reader: 閲覧者
-MAINTAINER: メンテナー
+maintainer: メンテナー
-OWNER: オーナー
+owner: オーナー

Also applies to: 422-425

web/src/gql/graphql.schema.json (2)

Line range hint 10699-10727: LGTM! Consider adding field documentation.

The userByNameOrEmail query implementation looks good. The parameter and return types are appropriate for looking up a single user by name or email.

Consider adding a description field to document:

  • The query's purpose
  • The parameter format/requirements
  • When null might be returned
 "name": "userByNameOrEmail",
-"description": null,
+"description": "Lookup a single user by their name or email address. Returns null if no matching user is found.",

10728-10767: LGTM! Consider adding field documentation.

The userSearch query implementation looks good. The parameter and return types are appropriate for searching multiple users by keyword.

Consider adding a description field to document:

  • The query's purpose
  • The keyword parameter format/requirements
  • Search behavior (e.g., partial matches, case sensitivity)
 "name": "userSearch",
-"description": null,
+"description": "Search for users using a keyword that matches against names and email addresses. Returns an empty list if no matches are found.",
web/src/components/molecules/Member/MemberAddModal/index.tsx (1)

193-198: Ensure all users are displayed correctly

When rendering user information, ensure that all user details are accurately displayed and properly formatted, especially for users with long names or emails.

Consider adding styles to handle text overflow:

const UserName = styled.div`
  max-width: 50%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
`;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 98408ea and 837450c.

📒 Files selected for processing (9)
  • web/src/components/atoms/AutoComplete/index.ts (1 hunks)
  • web/src/components/molecules/Member/MemberAddModal/index.tsx (2 hunks)
  • web/src/components/organisms/Settings/Members/hooks.ts (4 hunks)
  • web/src/components/organisms/Settings/Members/index.tsx (2 hunks)
  • web/src/gql/graphql-client-api.tsx (5 hunks)
  • web/src/gql/graphql.schema.json (2 hunks)
  • web/src/gql/queries/user.ts (1 hunks)
  • web/src/i18n/translations/en.yml (1 hunks)
  • web/src/i18n/translations/ja.yml (1 hunks)
🔇 Additional comments (11)
web/src/components/atoms/AutoComplete/index.ts (2)

1-1: LGTM! Clean import statement.

The addition of AutoCompleteProps type import alongside the component follows TypeScript best practices for component typing.


3-4: LGTM! Clean export structure.

The file maintains a clean re-export pattern:

  • Default export for the component
  • Named export for the type definition

This follows the common pattern for component libraries and provides good TypeScript support for consumers.

web/src/gql/queries/user.ts (1)

5-13: LGTM! Verify backend compatibility.

The query is well-structured and the rename from GET_USER_BY_SEARCH to GET_USER_BY_NAME_OR_EMAIL better reflects its specific purpose.

Let's verify the backend implementation:

✅ Verification successful

Query rename is properly implemented and compatible with backend

The verification shows that the userByNameOrEmail query is fully implemented and integrated:

  • Backend schema defines the query in server/schemas/user.graphql
  • Backend resolver is implemented in server/internal/adapter/gql/resolver_user.go
  • E2E tests in server/e2e/gql_user_test.go verify the query functionality
  • Frontend types and query definition are properly updated in generated files
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the backend schema supports the new query name and structure

# Test: Check if the backend resolver and schema are properly updated
ast-grep --pattern 'func (*_) UserByNameOrEmail(ctx context.Context, nameOrEmail string) (*model.User, error)'

# Test: Check for any remaining references to the old query name
rg -l 'searchUser.*nameOrEmail'

Length of output: 146


Script:

#!/bin/bash
# Let's check the GraphQL schema and resolver files for the query definition
# First, find schema files
fd "schema.graphql|schema.gql" --type f --exec cat {}

# Then check resolver implementations
fd "resolver.*" --type f --exec cat {}

# Also check for any references to the old query name in the frontend
rg "GET_USER_BY_SEARCH"

Length of output: 76852


Script:

#!/bin/bash
# Let's check the GraphQL schema and type definitions for the query
fd "schema.graphql|schema.gql|user.ts" --type f --exec grep -l "userByNameOrEmail"

# Also check for any references to the old query name in test files
fd "test|spec|__tests__" --type f --exec grep -l "GET_USER_BY_SEARCH"

# Check for any imports or usages of the query
rg "userByNameOrEmail" -A 2 -B 2

Length of output: 8086

web/src/components/organisms/Settings/Members/index.tsx (2)

12-18: LGTM: Well-structured state management

The state variables are well-organized with clear separation between searched and selected users, following React conventions. The addition of searchLoading state properly handles loading states during user searches.


Line range hint 1-89: Verify consistent naming across the codebase

Let's ensure the new naming conventions are consistently used across related files.

✅ Verification successful

Naming conventions are consistent across the codebase

The variable searchedUsers and its related props are consistently used across all relevant files:

  • Component implementation in web/src/components/organisms/Settings/Members/index.tsx
  • Hook implementation in web/src/components/organisms/Settings/Members/hooks.ts
  • Modal component in web/src/components/molecules/Member/MemberAddModal/index.tsx

All instances follow the same plural form searchedUsers and there are no inconsistent naming patterns found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent naming of user search related variables and components

# Test 1: Check for old variable names that should have been updated
echo "Checking for old variable names that should have been updated..."
rg -l "searchedUser[^s]" --type=typescript --type=tsx

# Test 2: Verify MemberAddModal prop usage is consistent
echo "Checking MemberAddModal prop usage..."
ast-grep --pattern 'MemberAddModal $props'

# Test 3: Check related test files for updated variable names
echo "Checking test files for updated naming..."
fd -e test.tsx -e test.ts | xargs rg "searchedUser[^s]"

Length of output: 510


Script:

#!/bin/bash
# Let's try a different approach with correct file type flags

# Check for any variations of searchedUser in all files
echo "Checking for searchedUser variations..."
rg "searchedUser" --type-add 'ts:*.{ts,tsx}' --type ts

# Check MemberAddModal component usage
echo "Checking MemberAddModal usage..."
rg "<MemberAddModal" --type-add 'ts:*.{ts,tsx}' --type ts -A 10

# Check for related hook implementations
echo "Checking hook implementations..."
rg "searchedUsers.*=" --type-add 'ts:*.{ts,tsx}' --type ts

# Check test files specifically
echo "Checking test files..."
rg "searchedUser" --glob "**/*.test.{ts,tsx}"

Length of output: 2691

web/src/components/organisms/Settings/Members/hooks.ts (2)

43-44: LGTM! Clear state separation.

The state management changes improve clarity by separating search results (searchedUsers) from selected users (selectedUsers).


99-101: LGTM! Simple and focused handler.

The user add handler is straightforward and follows React's state update best practices.

web/src/i18n/translations/ja.yml (1)

1-559: Verify context-dependent translations

The translations appear technically correct, but some might benefit from additional context verification:

  1. Error messages (lines 439-559) follow a consistent pattern
  2. Technical terms are generally well translated
  3. UI elements have appropriate translations

Let's verify the usage context of these translations:

✅ Verification successful

Let's verify the usage context of some key translations by examining their implementation:


Let's check the actual usage of translations in the components to verify the context:


Based on the extensive code analysis, I can now provide a final assessment of the translations:

Japanese translations are properly implemented and contextually accurate

The translations in ja.yml are correctly used throughout the codebase with proper context:

  • UI elements use appropriate Japanese terms (e.g., モデル for "Model", フィールド for "Field")
  • Technical terms maintain consistency (e.g., アセット for "Asset", プレビュー for "Preview")
  • Form validations and error messages follow natural Japanese grammar
  • Action buttons use clear Japanese verbs (e.g., 保存 for "Save", 削除 for "Delete")
  • Status messages maintain proper formality level in Japanese

The translations are properly integrated via i18next with:

  • Fallback to English when needed
  • Support for phrase-based keys
  • Browser language detection
  • Proper initialization of both English and Japanese resources
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the usage of these translations in the codebase
rg -l "useTranslation|i18n" "web/src"

Length of output: 10237


Script:

#!/bin/bash
# Check usage of error messages and technical terms
rg -A 2 "Failed to|Successfully" "web/src/components/molecules"

# Check specific UI elements translations
rg -A 2 "useTranslation.*" "web/src/components/molecules/Content/Form"

Length of output: 506


Script:

#!/bin/bash
# Check translation usage in key components
rg -A 3 "t\(['\"]" "web/src/components/molecules/Content/Form" "web/src/components/molecules/Schema" "web/src/components/molecules/Asset"

# Check i18n setup and configuration
cat web/src/i18n/i18n.ts

Length of output: 82528

web/src/gql/graphql-client-api.tsx (2)

1318-1319: LGTM: Clean implementation of user lookup by name/email

The query is well-structured with appropriate return fields for user lookup functionality.


1417-1419: LGTM: Well-implemented keyword-based user search

The search query implementation is clean and consistent with the lookup query, providing flexible user search capability.

web/src/components/molecules/Member/MemberAddModal/index.tsx (1)

202-208: ⚠️ Potential issue

Correct the Form.Item name prop usage

The name prop should be a string or an array for nested fields. Wrapping user.id in an array when it's already a string may cause issues with form data handling.

Update the name prop:

- <FormItemRole name={[user.id]}>
+ <FormItemRole name={user.id}>

Likely invalid or redundant comment.

web/src/components/organisms/Settings/Members/hooks.ts Outdated Show resolved Hide resolved
web/src/i18n/translations/en.yml Outdated Show resolved Hide resolved
web/src/i18n/translations/en.yml Outdated Show resolved Hide resolved
web/src/i18n/translations/ja.yml Outdated Show resolved Hide resolved
@yk-eukarya yk-eukarya changed the title feat(server): support user search feat: support user search Oct 28, 2024
Copy link
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: 5

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 837450c and 7d772e2.

📒 Files selected for processing (4)
  • web/src/components/molecules/Member/MemberAddModal/index.tsx (2 hunks)
  • web/src/components/organisms/Settings/Members/hooks.ts (4 hunks)
  • web/src/i18n/translations/en.yml (1 hunks)
  • web/src/i18n/translations/ja.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/src/components/organisms/Settings/Members/hooks.ts
🔇 Additional comments (4)
web/src/i18n/translations/en.yml (1)

206-208: Verify all user search related translations are covered

Let's ensure we haven't missed any translations related to the user search feature.

✅ Verification successful

All user search related translations are present and consistent

The codebase search reveals that all necessary translations for the user search feature are covered in the translation file:

  • "Search user" - for the search input label
  • "No result" - for empty search results
  • "Email address or user name" - for input placeholder

These translations align with the feature's implementation in the codebase, particularly in MemberAddModal component where these strings are used.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any user search related keys in the codebase
rg -i "user.*search|search.*user" --type ts --type tsx

Length of output: 84


Script:

#!/bin/bash
# Search for user search related strings in the codebase with correct file extensions
rg -i "user.*search|search.*user"

# Also check the translation file directly to see all related keys
cat web/src/i18n/translations/en.yml

Length of output: 26149

web/src/i18n/translations/ja.yml (3)

206-207: LGTM! New translations for user search functionality.

The Japanese translations for "Search user" (ユーザー検索) and "No result" (見つかりませんでした) are accurate and appropriate.


Line range hint 3-3: Empty translation for "Oops!"


Line range hint 449-450: Empty translation and potential string interpolation issue

Comment on lines +206 to +207
Search user: ''
No result: ''
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Populate missing translations for user search feature

The translations for the user search feature are currently empty. These need to be populated to ensure a proper user experience:

Search user: 'Search Users'
No result: 'No Results Found'

web/src/i18n/translations/en.yml Show resolved Hide resolved
Copy link
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

🧹 Outside diff range and nitpick comments (2)
web/src/gql/graphql-client-api.tsx (2)

1325-1326: LGTM! Clean implementation of userByNameOrEmail query

The query is well-structured with proper typing and null handling.

Consider adding JSDoc comments to document the query's purpose and usage:

+/**
+ * Query to find a user by their name or email address
+ * @param nameOrEmail - The name or email to search for
+ * @returns User object if found, null otherwise
+ */
userByNameOrEmail?: Maybe<User>;

1424-1426: LGTM! Clean implementation of userSearch query

The query implementation is correct with proper array return type.

Consider adding JSDoc comments to document the query's purpose and usage:

+/**
+ * Query to search users by keyword
+ * @param keyword - The search term to filter users
+ * @returns Array of matching User objects
+ */
userSearch: Array<User>;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7d772e2 and 533164b.

⛔ Files ignored due to path filters (2)
  • go.work.sum is excluded by !**/*.sum
  • server/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • server/go.mod (1 hunks)
  • server/internal/adapter/gql/generated.go (12 hunks)
  • web/src/components/organisms/Settings/Members/hooks.ts (4 hunks)
  • web/src/components/organisms/Settings/Members/index.tsx (2 hunks)
  • web/src/gql/graphql-client-api.tsx (5 hunks)
  • web/src/gql/graphql.schema.json (2 hunks)
  • web/src/i18n/translations/en.yml (1 hunks)
  • web/src/i18n/translations/ja.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • server/go.mod
  • web/src/components/organisms/Settings/Members/index.tsx
  • web/src/i18n/translations/ja.yml
🔇 Additional comments (7)
server/internal/adapter/gql/generated.go (4)

563-564: Schema changes look good!

The new GraphQL queries are well-defined:

  • userSearch(keyword: String!): [User!]! - Returns a non-null array of non-null User objects
  • userByNameOrEmail(nameOrEmail: String!): User - Returns a nullable User object

The return types are appropriate for their use cases - search returns multiple results while lookup by name/email returns a single result.

Also applies to: 1029-1030, 6656-6657


Line range hint 9749-9811: Argument handling implementation is correct!

The argument handling code:

  • Properly validates required arguments
  • Implements correct type conversions
  • Includes appropriate error handling
  • Follows the standard GraphQL resolver pattern

25380-25409: Query execution implementations are robust!

Both query implementations include:

  • Proper error handling
  • Panic recovery
  • Middleware integration
  • Correct null handling
  • Type-safe result marshaling

Also applies to: 25445-25459


25411-25443: Verify completeness of User field handling

The field context implementations look correct, but let's verify that all User fields are properly handled in the child resolver.

Also applies to: 25473-25500

✅ Verification successful

Let me try a different search pattern to gather the necessary information.


All User fields are properly handled in the resolvers

Based on the search results, I can confirm that:

  • The GraphQL schema defines User type with 4 fields: id, name, email, and host
  • The generated code in server/internal/adapter/gql/generated.go includes field context implementations and resolvers for all 4 fields:
    • _User_id and fieldContext_User_id
    • _User_name and fieldContext_User_name
    • _User_email and fieldContext_User_email
    • _User_host and fieldContext_User_host

The field context implementations are complete and match the User type definition in the schema.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all User type fields are properly handled in the resolver

# Search for User type definition in schema
echo "Searching for User type definition..."
rg -A 10 "type User \{" 

# Search for User field resolvers
echo "Searching for User field resolvers..."
ast-grep --pattern 'func \(.*\) _User_.*\(ctx context.Context, obj \*.*User.*\)'

Length of output: 278


Script:

#!/bin/bash
# Search for User type definition in schema files
echo "Searching for User type definition in schema..."
fd -e graphql -e gql . | xargs rg -l "type User"

# If found, show the content
echo "Showing User type definition..."
fd -e graphql -e gql . | xargs rg -A 10 "type User"

# Search for User resolvers in generated.go
echo "Searching for User resolvers in generated code..."
rg "_User_" server/internal/adapter/gql/generated.go

# Search for User type struct
echo "Searching for User type struct..."
rg "type User struct" -A 5

Length of output: 4631

web/src/i18n/translations/en.yml (1)

217-218: ⚠️ Potential issue

Critical: Empty translations will affect user search functionality

These translations are essential for the new user search feature. Please refer to the existing review comments for suggested translations to maintain consistency in the UI.

web/src/gql/graphql.schema.json (2)

Line range hint 10740-10768: LGTM! The userByNameOrEmail query is well-defined.

The query has a clear purpose with appropriate nullability and parameter types for exact user lookup by name or email.


10769-10808: LGTM! The userSearch query is well-structured.

The query provides a flexible keyword-based search capability with appropriate non-null list return type for multiple results.

Copy link
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

🧹 Outside diff range and nitpick comments (1)
web/src/components/molecules/Member/MemberAddModal/index.tsx (1)

224-241: Consider constraining modal width

The modal width is not constrained, which could lead to inconsistent UI on different screen sizes.

Add width constraint:

 const StyledModal = styled(Modal)`
+  width: 100% !important;
+  max-width: 600px;
   .ant-modal-content {
     padding: 0;
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 533164b and 40d397e.

📒 Files selected for processing (1)
  • web/src/components/molecules/Member/MemberAddModal/index.tsx (2 hunks)
🔇 Additional comments (1)
web/src/components/molecules/Member/MemberAddModal/index.tsx (1)

17-27: LGTM: Type definitions are well-structured

The Props interface and FormValues type are well-defined for the new user search functionality. The use of React.Dispatch for setSelectedUsers ensures type safety.

Also applies to: 30-30

@yk-eukarya yk-eukarya merged commit 82acac3 into main Nov 18, 2024
21 checks passed
@yk-eukarya yk-eukarya deleted the feat/support-user-search branch November 18, 2024 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants