Skip to content

Conversation

@anmolsinghbhatia
Copy link
Collaborator

@anmolsinghbhatia anmolsinghbhatia commented Jan 8, 2026

Description

This PR includes improvement for dropdown options hierarchy.

Type of Change

  • Improvement (change that would cause existing functionality to not work as expected)

Summary by CodeRabbit

  • Improvements
    • Enhanced dropdown option ordering across Member, Module, and Project selectors to prioritize and better organize selected items for improved usability.
    • Refined filtering logic in dropdowns for consistent, predictable option presentation.

✏️ Tip: You can customize this high-level summary in your review settings.

@anmolsinghbhatia anmolsinghbhatia self-assigned this Jan 8, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

This pull request adds sorting utility functions for dropdown options and propagates a value prop through member and module dropdown components to enable selected-first sorting. Multiple dropdown components now use these utilities to prioritize selected items in their option lists.

Changes

Cohort / File(s) Summary
Sorting Utilities
packages/utils/src/array.ts
Added two exported helper functions: sortBySelectedFirst and sortByCurrentUserThenSelected. Both sort dropdown options to prioritize selected items, with the latter also prioritizing current user. Functions handle generic types with value property and gracefully handle undefined/null inputs.
Member Dropdown
apps/web/core/components/dropdowns/member/base.tsx, apps/web/core/components/dropdowns/member/member-options.tsx
Extended MemberOptions props with optional value prop. Added import of sortByCurrentUserThenSelected and modified filtering logic to sort options by current user then selected values.
Module Dropdown
apps/web/core/components/dropdowns/module/base.tsx, apps/web/core/components/dropdowns/module/module-options.tsx
Extended ModuleOptions props with optional value prop. Modified filtering logic to use sortBySelectedFirst for prioritizing selected options.
Project Dropdown
apps/web/core/components/dropdowns/project/base.tsx
Introduced sortBySelectedFirst to filtering flow to ensure selected options appear first while maintaining stable ordering.
Label Dropdown
apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
Wrapped options filtering with sortBySelectedFirst and improved null-safety checks before accessing filtered options length.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop, sort, and hop once more,
Selected items hop to the fore,
Each dropdown now knows its place,
With sorted grace across the space!
The order flows, the user knows,
Which item's picked—and off it goes! 🎯

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a summary and type of change but lacks details on testing, screenshots, and explicit references to the issue, making it incomplete against the template requirements. Add test scenarios describing what was validated, include before/after screenshots if applicable, and add a reference to issue WEB-1201 as indicated in the title.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change—improving dropdown options hierarchy—and is concise and specific enough to convey the primary purpose of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

@makeplane
Copy link

makeplane bot commented Jan 8, 2026

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

@anmolsinghbhatia anmolsinghbhatia marked this pull request as ready for review January 8, 2026 14:50
Copilot AI review requested due to automatic review settings January 8, 2026 14:50
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)
packages/utils/src/array.ts (2)

219-228: Prefer toSorted() for immutability.

The current implementation uses [...options].sort() to avoid mutation. Per the project's TypeScript guidelines, prefer the toSorted() method which is more explicit about immutability and doesn't require manual spreading.

♻️ Refactor to use toSorted()
-  // Create a shallow copy to avoid mutating the original array
-  return [...options].sort((a, b) => {
+  return options.toSorted((a, b) => {
     const aSelected = a.value !== null && selectedSet.has(a.value);
     const bSelected = b.value !== null && selectedSet.has(b.value);
 
     // If both selected or both unselected, maintain original order
     if (aSelected === bSelected) return 0;
 
     // Selected items come first
     return aSelected ? -1 : 1;
   });

As per coding guidelines, TypeScript 5.2+ supports copying array methods for immutable operations.


253-271: Prefer toSorted() for immutability.

Similar to sortBySelectedFirst, this function uses [...options].sort() which works but isn't the preferred pattern per project guidelines. Use toSorted() for more explicit immutability.

♻️ Refactor to use toSorted()
-  // Create a shallow copy to avoid mutating the original array
-  return [...options].sort((a, b) => {
+  return options.toSorted((a, b) => {
     const aIsCurrent = currentUserId && a.value === currentUserId;
     const bIsCurrent = currentUserId && b.value === currentUserId;
 
     // Current user always comes first
     if (aIsCurrent && !bIsCurrent) return -1;
     if (!aIsCurrent && bIsCurrent) return 1;
     if (aIsCurrent && bIsCurrent) return 0;
 
     // If neither is current user, sort by selection state
     const aSelected = a.value !== null && selectedSet.has(a.value);
     const bSelected = b.value !== null && selectedSet.has(b.value);
 
     // If both selected or both unselected, maintain original order
     if (aSelected === bSelected) return 0;
 
     // Selected items come before unselected
     return aSelected ? -1 : 1;
   });

As per coding guidelines, TypeScript 5.2+ supports copying array methods for immutable operations.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b83d460 and a856afb.

📒 Files selected for processing (7)
  • apps/web/core/components/dropdowns/member/base.tsx
  • apps/web/core/components/dropdowns/member/member-options.tsx
  • apps/web/core/components/dropdowns/module/base.tsx
  • apps/web/core/components/dropdowns/module/module-options.tsx
  • apps/web/core/components/dropdowns/project/base.tsx
  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • packages/utils/src/array.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}

📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.{ts,tsx,mts,cts}: Use const type parameters for more precise literal inference in TypeScript 5.0+
Use the satisfies operator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicit is return types in filter/check functions
Use NoInfer<T> utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing in switch(true) blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacy experimentalDecorators
Use using declarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Use with { type: "json" } for import attributes; avoid deprecated assert syntax (TypeScript 5.3/5.8+)
Use import type explicitly when importing types to ensure they are erased during compilation, respecting verbatimModuleSyntax flag
Use .ts, .mts, .cts extensions in import type statements (TypeScript 5.2+)
Use import type { Type } from "mod" with { "resolution-mode": "import" } for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize new Set methods like union, intersection, etc., when available (TypeScript 5.5+)
Use Object.groupBy / Map.groupBy standard methods for grouping instead of external libraries (TypeScript 5.4+)
Use Promise.withResolvers() for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted, toSpliced, with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields via super in classes (TypeScript 5....

Files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • apps/web/core/components/dropdowns/member/member-options.tsx
  • apps/web/core/components/dropdowns/module/module-options.tsx
  • apps/web/core/components/dropdowns/member/base.tsx
  • packages/utils/src/array.ts
  • apps/web/core/components/dropdowns/project/base.tsx
  • apps/web/core/components/dropdowns/module/base.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Enable TypeScript strict mode and ensure all files are fully typed

Files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • apps/web/core/components/dropdowns/member/member-options.tsx
  • apps/web/core/components/dropdowns/module/module-options.tsx
  • apps/web/core/components/dropdowns/member/base.tsx
  • packages/utils/src/array.ts
  • apps/web/core/components/dropdowns/project/base.tsx
  • apps/web/core/components/dropdowns/module/base.tsx
**/*.{js,jsx,ts,tsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier with Tailwind plugin for code formatting, run pnpm fix:format

Files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • apps/web/core/components/dropdowns/member/member-options.tsx
  • apps/web/core/components/dropdowns/module/module-options.tsx
  • apps/web/core/components/dropdowns/member/base.tsx
  • packages/utils/src/array.ts
  • apps/web/core/components/dropdowns/project/base.tsx
  • apps/web/core/components/dropdowns/module/base.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately

Files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • apps/web/core/components/dropdowns/member/member-options.tsx
  • apps/web/core/components/dropdowns/module/module-options.tsx
  • apps/web/core/components/dropdowns/member/base.tsx
  • packages/utils/src/array.ts
  • apps/web/core/components/dropdowns/project/base.tsx
  • apps/web/core/components/dropdowns/module/base.tsx
🧠 Learnings (6)
📚 Learning: 2025-11-25T10:18:05.172Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: .github/instructions/typescript.instructions.md:0-0
Timestamp: 2025-11-25T10:18:05.172Z
Learning: Applies to **/*.{ts,tsx,mts,cts} : Use copying array methods (`toSorted`, `toSpliced`, `with`) for immutable array operations (TypeScript 5.2+)

Applied to files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • packages/utils/src/array.ts
  • apps/web/core/components/dropdowns/project/base.tsx
📚 Learning: 2025-10-10T13:25:14.810Z
Learnt from: gakshita
Repo: makeplane/plane PR: 7949
File: apps/web/core/components/issues/issue-modal/form.tsx:183-189
Timestamp: 2025-10-10T13:25:14.810Z
Learning: In `apps/web/core/components/issues/issue-modal/form.tsx`, the form reset effect uses a `dataResetProperties` dependency array prop (default: []) to give parent components explicit control over when the form resets. Do not suggest adding the `data` prop itself to the dependency array, as this would cause unwanted resets on every render when the data object reference changes, disrupting user input. The current pattern is intentional and allows the parent to trigger resets only when specific conditions are met.

Applied to files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
📚 Learning: 2025-10-21T17:22:05.204Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7989
File: apps/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx:45-46
Timestamp: 2025-10-21T17:22:05.204Z
Learning: In the makeplane/plane repository, the refactor from useParams() to params prop is specifically scoped to page.tsx and layout.tsx files in apps/web/app (Next.js App Router pattern). Other components (hooks, regular client components, utilities) should continue using the useParams() hook as that is the correct pattern for non-route components.

Applied to files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
  • apps/web/core/components/dropdowns/member/member-options.tsx
📚 Learning: 2025-10-09T20:42:31.843Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T20:42:31.843Z
Learning: In the makeplane/plane repository, React types are globally available through TypeScript configuration. Type annotations like React.FC, React.ReactNode, etc. can be used without explicitly importing the React namespace. The codebase uses the modern JSX transform, so React imports are not required for JSX or type references.

Applied to files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to packages/plane/ui/**/*.{ts,tsx} : Build components in `plane/ui` package with Storybook for isolated development

Applied to files:

  • apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx
📚 Learning: 2025-03-11T19:42:41.769Z
Learnt from: janreges
Repo: makeplane/plane PR: 6743
File: packages/i18n/src/store/index.ts:160-161
Timestamp: 2025-03-11T19:42:41.769Z
Learning: In the Plane project, the file 'packages/i18n/src/store/index.ts' already includes support for Polish language translations with the case "pl".

Applied to files:

  • apps/web/core/components/dropdowns/module/module-options.tsx
🧬 Code graph analysis (4)
apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx (1)
packages/utils/src/array.ts (1)
  • sortBySelectedFirst (207-229)
apps/web/core/components/dropdowns/member/member-options.tsx (1)
packages/utils/src/array.ts (1)
  • sortByCurrentUserThenSelected (242-272)
apps/web/core/components/dropdowns/module/module-options.tsx (1)
packages/utils/src/array.ts (1)
  • sortBySelectedFirst (207-229)
apps/web/core/components/dropdowns/project/base.tsx (1)
packages/utils/src/array.ts (1)
  • sortBySelectedFirst (207-229)
⏰ 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: Agent
  • GitHub Check: CodeQL analysis (javascript-typescript)
  • GitHub Check: Build packages
🔇 Additional comments (13)
apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx (3)

17-17: LGTM! Correct import for dropdown hierarchy improvement.

The import of sortBySelectedFirst aligns with the PR objective to improve dropdown options hierarchy by prioritizing selected items.


114-121: LGTM! Correct implementation of selected-first sorting.

The filteredOptions computation correctly wraps the existing filter logic with sortBySelectedFirst to prioritize selected labels. The dependency array properly includes value to ensure re-computation when selections change.


271-271: LGTM! Appropriate null-safety improvement.

The added null check is necessary since sortBySelectedFirst can return undefined. This prevents potential runtime errors when accessing the length property.

apps/web/core/components/dropdowns/module/base.tsx (1)

190-190: LGTM! Correct prop propagation for value-aware sorting.

Forwarding the value prop to ModuleOptions enables the component to implement selected-first sorting, consistent with the PR's objective to improve dropdown hierarchy.

apps/web/core/components/dropdowns/member/base.tsx (1)

180-180: LGTM! Correct prop propagation for value-aware sorting.

Forwarding the value prop to MemberOptions enables the component to implement current-user-then-selected sorting, aligning with the PR's dropdown hierarchy improvements.

apps/web/core/components/dropdowns/project/base.tsx (2)

11-11: LGTM! Correct import for dropdown hierarchy improvement.

The import of sortBySelectedFirst enables prioritizing selected projects in the dropdown options.


113-119: LGTM! Excellent use of type predicates and sorting.

The filtering logic correctly:

  1. Excludes the current project
  2. Filters by search query when present
  3. Uses a type predicate (o): o is NonNullable<typeof o> to properly narrow the type from (T | undefined)[] to T[]
  4. Sorts selected projects first

The type predicate is excellent TypeScript practice that provides compile-time type safety.

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

14-14: LGTM! Correct import for member hierarchy sorting.

The import of sortByCurrentUserThenSelected enables the dropdown to prioritize the current user first, then selected members, improving UX.


29-29: LGTM! Correct prop type for value-aware sorting.

The value prop is correctly typed as optional with a union type (string[] | string | null) to support both single and multiple selection modes.


116-120: LGTM! Correct implementation of hierarchical member sorting.

The filteredOptions computation correctly uses sortByCurrentUserThenSelected to establish a clear hierarchy:

  1. Current user appears first
  2. Selected members appear next
  3. Other members appear last

This significantly improves UX by making it easy to find relevant members.

apps/web/core/components/dropdowns/module/module-options.tsx (3)

10-10: LGTM!

The import correctly references the new utility function added to the shared utils package.


30-30: LGTM!

The value prop is correctly typed to support both single-select (string | null) and multi-select (string[]) scenarios, matching the signature expected by sortBySelectedFirst.


104-107: LGTM!

The filtering and sorting logic is well-structured: it first applies text-based filtering when a query exists, then uses sortBySelectedFirst to prioritize selected items. The value prop is correctly threaded through to enable this behavior.

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 dropdown options hierarchy by implementing sorting functions that prioritize selected items and current users in dropdown lists. The changes enhance user experience by making relevant options more accessible.

Key Changes:

  • Added two new utility functions (sortBySelectedFirst and sortByCurrentUserThenSelected) for sorting dropdown options
  • Integrated sorting logic across label, project, module, and member dropdowns
  • Enhanced null/undefined handling in the project dropdown

Reviewed changes

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

Show a summary per file
File Description
packages/utils/src/array.ts Added two new sorting utility functions with comprehensive JSDoc documentation for sorting dropdown options by selection state and current user
apps/web/core/components/issues/issue-layouts/properties/label-dropdown.tsx Integrated sortBySelectedFirst to prioritize selected labels in the dropdown
apps/web/core/components/dropdowns/project/base.tsx Applied sortBySelectedFirst with improved undefined filtering for project options
apps/web/core/components/dropdowns/module/module-options.tsx Added value prop and integrated sortBySelectedFirst for module sorting
apps/web/core/components/dropdowns/module/base.tsx Passed value prop to ModuleOptions component for sorting support
apps/web/core/components/dropdowns/member/member-options.tsx Added value prop and integrated sortByCurrentUserThenSelected to prioritize current user and selected members
apps/web/core/components/dropdowns/member/base.tsx Passed value prop to MemberOptions component for sorting support

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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