Skip to content

Conversation

@vihar
Copy link
Contributor

@vihar vihar commented Oct 23, 2025

Summary

  • hide suspended members from the member selection dropdown unless they are already assigned
  • surface assigned members first in the dropdown list to reduce scrolling
  • pass selected member ids into the dropdown options so ordering and filtering can be computed

Testing

  • pnpm lint --filter web (fails: Command "lint" not found)

https://chatgpt.com/codex/tasks/task_e_68fa0d42d260832a88154355df1f4f58

Summary by CodeRabbit

  • New Features
    • Member dropdown lists now prioritize previously selected members by displaying them at the top for quicker re-access.
    • Suspended members are filtered from availability except when already selected, improving list clarity and usability.

Copilot AI review requested due to automatic review settings October 23, 2025 11:24
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 23, 2025

Walkthrough

The changes extend the member dropdown component to accept a new selectedMemberIds prop, which enables filtering of suspended users (keeping only those previously selected) and prioritizes selected members at the top of the list. The base component derives this prop from its existing value, and the options component implements the filtering and sorting logic.

Changes

Cohort / File(s) Summary
Member Dropdown Enhancement
apps/web/core/components/dropdowns/member/base.tsx, apps/web/core/components/dropdowns/member/member-options.tsx
Added selectedMemberIds prop to MemberOptions; base component computes it from value prop. MemberOptions now filters suspended users (excluding those in selectedMemberIdsSet), adds isSuspended flag to options, implements prioritization sort placing previously selected members first, strengthens type safety with type-guard filter, and updates UI styling based on suspension and selection state.

Sequence Diagram

sequenceDiagram
    participant Base as MemberDropdownBase
    participant Options as MemberOptions
    participant UI as Render

    Base->>Base: Derive selectedMemberIds from value
    Base->>Options: Pass selectedMemberIds prop
    Options->>Options: Create Set<selectedMemberIds> for O(1) lookup
    Options->>Options: Map member list, compute isSuspended flag
    Options->>Options: Filter: remove suspended (except if in selectedMemberIdsSet)
    Options->>Options: Prioritize: sort selected members to top
    Options->>UI: Render with updated option.isSuspended & disabled states
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

The changes span two related files with new filtering logic, Set-based optimization, type-guarding improvements, and prioritization sorting. While individual pieces are straightforward, the combination of suspension handling, conditional inclusion, and list reordering requires careful verification of the filtering and sorting behavior.

Poem

🐰 With whiskers twitched and ears held high,
We filter out the suspended fry,
The chosen few now shine up top,
Their selections set to never drop!
A sorted list, both clean and tight—
The dropdown dances left and right!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description is incomplete relative to the provided template. While the author provided a Summary section with clear bullet points describing the changes and included a reference link, critical template sections are missing or inadequately addressed. Specifically, the "Type of Change" section with checkboxes is completely unfilled (the template requires selecting one or more options like Bug fix, Feature, Improvement, etc.), and the "Test Scenarios" section only documents a failed lint command without describing actual test cases or verification steps. The "Screenshots and Media" section is also not addressed, even though it could note if it's not applicable. To meet the repository's description requirements, please: (1) Select the appropriate "Type of Change" checkbox(es) that best categorize this PR (appears to be a Feature or Improvement), (2) Provide detailed test scenarios describing what was tested and how verification was performed, noting why the lint command failed and what other tests passed, and (3) Clarify the "Screenshots and Media" section by noting it's not applicable if no visual changes are present. Ensure the description follows the complete template structure before merging.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "Hide suspended members in assignee dropdown" directly and clearly summarizes the primary objective of the changeset. It accurately reflects the main functionality being introduced: filtering out suspended members from the dropdown unless they are already selected. The title is concise, specific, and uses clear language that allows a reviewer scanning PR history to immediately understand the core change without confusion or ambiguity.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-user-assignment-dropdown-behavior

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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR improves the member selection dropdown by hiding suspended members (unless already assigned) and prioritizing selected members at the top of the list for easier access.

Key Changes:

  • Hide suspended members from dropdown unless they are currently assigned
  • Sort selected members to appear first in the dropdown list
  • Pass selected member IDs to enable filtering and ordering logic

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
apps/web/core/components/dropdowns/member/member-options.tsx Implements filtering of suspended members, adds sorting to prioritize selected members, and optimizes repeated isUserSuspended calls
apps/web/core/components/dropdowns/member/base.tsx Passes selected member IDs to the options component

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

)
}
disabled={isUserSuspended(option.value, workspaceSlug?.toString())}
disabled={option.isSuspended && !selectedMemberIdsSet.has(option.value)}
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

[nitpick] The disabled condition uses selectedMemberIdsSet.has(option.value) while line 173 uses !selected. These should be consistent - consider using the selected parameter from the render prop instead of rechecking the Set for better maintainability.

Copilot uses AI. Check for mistakes.
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: 0

🧹 Nitpick comments (2)
apps/web/core/components/dropdowns/member/member-options.tsx (2)

122-128: LGTM! Selected members correctly prioritized.

The sort logic correctly surfaces selected members at the top of the list while maintaining stable ordering within each group (selected vs. unselected).

For improved readability, consider extracting the comparator:

+const prioritizeSelected = (a: typeof options[number], b: typeof options[number]) => {
+  const isASelected = selectedMemberIdsSet.has(a.value);
+  const isBSelected = selectedMemberIdsSet.has(b.value);
+  if (isASelected === isBSelected) return 0;
+  return isASelected ? -1 : 1;
+};
+
-   ?.sort((a, b) => {
-     const isASelected = selectedMemberIdsSet.has(a.value);
-     const isBSelected = selectedMemberIdsSet.has(b.value);
-
-     if (isASelected === isBSelected) return 0;
-     return isASelected ? -1 : 1;
-   });
+   ?.sort(prioritizeSelected);

173-173: Verify consistency between selected and selectedMemberIdsSet.

Line 173 uses the selected prop from Headless UI's render function, while line 176 uses selectedMemberIdsSet.has(option.value). These should be equivalent since both derive from the parent's value prop, but using different sources for related decisions could introduce subtle bugs if the Combobox state updates independently.

For consistency and to eliminate any risk of state desynchronization, consider using the same check in both places.

Apply this diff to use a consistent check:

                      className={({ active, selected }) =>
                        cn(
                          "flex w-full select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5",
                          active && "bg-custom-background-80",
                          selected ? "text-custom-text-100" : "text-custom-text-200",
-                         option.isSuspended && !selected ? "cursor-not-allowed" : "cursor-pointer"
+                         option.isSuspended && !selectedMemberIdsSet.has(option.value) ? "cursor-not-allowed" : "cursor-pointer"
                        )
                      }
                      disabled={option.isSuspended && !selectedMemberIdsSet.has(option.value)}

Also applies to: 176-176

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e710f5b and 52745cd.

📒 Files selected for processing (2)
  • apps/web/core/components/dropdowns/member/base.tsx (1 hunks)
  • apps/web/core/components/dropdowns/member/member-options.tsx (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/core/components/dropdowns/member/member-options.tsx (1)
packages/propel/src/icons/suspended-user.tsx (1)
  • SuspendedUserIcon (5-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
apps/web/core/components/dropdowns/member/base.tsx (1)

180-180: LGTM! Clean value normalization.

The ternary chain correctly normalizes the value prop into an array format that MemberOptions expects, handling both single and multiple selection modes gracefully.

apps/web/core/components/dropdowns/member/member-options.tsx (5)

32-32: LGTM! Efficient prop handling and lookup structure.

The optional selectedMemberIds prop with a default empty array is well-typed, and converting it to a Set enables O(1) lookups throughout the filtering and rendering logic.

Also applies to: 44-44, 90-90


94-96: LGTM! Filtering suspended members as intended.

The logic correctly hides suspended users unless they're already selected, precisely matching the PR objective. The early return is efficient and the Set lookup is O(1).


105-118: LGTM! Consistent visual treatment for suspended users.

The suspended state is correctly reflected in the UI through icon substitution, dimmed text color, and propagation to the option object for downstream rendering decisions.


121-121: LGTM! Proper type narrowing.

The type guard correctly removes nulls introduced by the suspension filter and strengthens type safety for the subsequent sort and render operations.


182-186: LGTM! Clear visual indicator for suspended state.

The "Suspended" pill provides clear feedback to users about member status, enhancing the user experience when reviewing assigned members.

@pushya22 pushya22 marked this pull request as draft October 27, 2025 10:50
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