Skip to content

[WEB-4457] refactor: decouple work item properties from mobx store#7363

Merged
pushya22 merged 5 commits intopreviewfrom
refactor-work-item-property-dropdowns
Jul 18, 2025
Merged

[WEB-4457] refactor: decouple work item properties from mobx store#7363
pushya22 merged 5 commits intopreviewfrom
refactor-work-item-property-dropdowns

Conversation

@prateekshourya29
Copy link
Member

@prateekshourya29 prateekshourya29 commented Jul 8, 2025

Description

Type of Change

  • Code refactoring

Summary by CodeRabbit

  • New Features

    • Introduced new dropdown components for members, modules, projects, and states with improved flexibility and external data sourcing.
    • Added a helper function to safely retrieve nested form errors.
    • Added a new asynchronous handler to support creating sub work items in issue modals.
  • Refactor

    • Refactored dropdown and select components to decouple them from internal data stores, requiring data and callbacks to be passed as props.
    • Renamed several components and updated their props for clarity and consistency.
    • Streamlined label creation and selection by delegating data handling to parent components.
    • Replaced internal fetching logic in dropdown options with external data retrieval callbacks.
    • Updated project dropdown filtering to use project IDs directly for permission checks.
    • Replaced issue additional properties component with a new work item modal additional properties component.
  • Bug Fixes

    • Improved parameter handling in dropdown filtering and condition callbacks for better reliability.
  • Chores

    • Cleaned up and reorganized imports and export paths for dropdown modules.
    • Updated exports to point to new dropdown subdirectories and adjusted public API exports accordingly.
    • Removed unused exports related to deprecated components.

@prateekshourya29 prateekshourya29 self-assigned this Jul 8, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 8, 2025

Walkthrough

This change refactors dropdown and select components for projects, modules, members, states, and labels to decouple them from internal store/state dependencies. Components now receive explicit data and lookup functions as props, and new wrapper components are introduced to bridge store data to these base components. The renderCondition callback for project dropdowns now receives a project ID instead of a project object. Additionally, label creation and issue modal sub-work item creation flows are updated to use new handler props, and a helper function for nested form error retrieval is added.

Changes

File(s) Change Summary
.../cycles/form.tsx
.../modules/form.tsx
.../issues/issue-modal/components/project-select.tsx
Updated renderCondition prop in ProjectDropdown to accept a project ID instead of a project object.
.../dropdowns/index.ts Changed export paths for dropdown components to point to new subdirectories.
.../dropdowns/member/base.tsx
.../dropdowns/member/member-options.tsx
Refactored MemberDropdown to MemberDropdownBase, removed store dependencies, updated props to require external data and callbacks.
.../dropdowns/member/dropdown.tsx Added new MemberDropdown wrapper component to connect store data to MemberDropdownBase.
.../dropdowns/module/base.tsx
.../dropdowns/module/module-options.tsx
Refactored ModuleDropdown to ModuleDropdownBase, updated to use external data and lookup props, removed internal store usage.
.../dropdowns/module/button-content.tsx Added new ModuleButtonContent component for module selection UI.
.../dropdowns/module/dropdown.tsx Added new ModuleDropdown wrapper component to provide store data to ModuleDropdownBase.
.../dropdowns/project/base.tsx Refactored ProjectDropdown to ProjectDropdownBase, changed to use project IDs and lookup props, updated renderCondition signature.
.../dropdowns/project/dropdown.tsx Added new ProjectDropdown wrapper component to connect store data to ProjectDropdownBase.
.../dropdowns/state/base.tsx Refactored StateDropdown to WorkItemStateDropdownBase, updated props for external state data and handlers, removed internal fetching.
.../dropdowns/state/dropdown.tsx Added new StateDropdown wrapper to handle store data and pass to WorkItemStateDropdownBase.
.../issues/issue-modal/form.tsx Updated to use new createLabel prop for label creation, removed direct projectId prop for CreateLabelModal.
.../issues/select/base.tsx Refactored IssueLabelSelect to WorkItemLabelSelectBase, decoupled from store, now expects label IDs and lookup function as props.
.../issues/select/dropdown.tsx Added new IssueLabelSelect wrapper to provide store data to WorkItemLabelSelectBase.
.../issues/select/index.ts Changed export to re-export from new dropdown module.
.../labels/create-label-modal.tsx Refactored to remove routing and store dependencies; now expects a createLabel function prop.
.../helpers/react-hook-form.helper.ts Added new helper function getNestedError to safely access nested errors in React Hook Form.
.../ce/components/issues/issue-modal/additional-properties.ts(x) Removed IssueAdditionalProperties component and related exports.
.../ce/components/issues/issue-modal/modal-additional-properties.tsx Added new WorkItemModalAdditionalProperties component returning null.
.../ce/components/issues/issue-modal/provider.tsx Added new async handler handleCreateSubWorkItem to context value in IssueModalProvider.
.../core/components/issues/issue-modal/base.tsx Added call to handleCreateSubWorkItem after issue creation in CreateUpdateIssueModalBase.
.../core/components/issues/issue-modal/context/issue-modal-context.tsx Extended TIssueModalContext with handleCreateSubWorkItem method and added TCreateSubWorkItemProps type alias.

Sequence Diagram(s)

sequenceDiagram
    participant Store
    participant WrapperComponent
    participant BaseComponent

    Store->>WrapperComponent: Provides data (IDs, lookup functions)
    WrapperComponent->>BaseComponent: Passes IDs, lookup, and handlers as props
    BaseComponent->>BaseComponent: Renders UI using provided data
    BaseComponent-->>WrapperComponent: Calls event handlers (e.g., onDropdownOpen)
    WrapperComponent-->>Store: Triggers data fetch if needed
Loading

Possibly related PRs

Suggested labels

🛠️refactor, 🌐frontend, ready to merge

Suggested reviewers

  • sriramveeraghanta
  • aaryan610

Poem

In dropdown fields where data flows,
The rabbit hops and dropdowns grow.
No longer tangled in the store,
Props bring what’s needed—less is more!
With lookup keys and IDs bright,
The code is clean, the UI light.
🐇✨—Refactor’s delight!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac77c8 and c715f37.

📒 Files selected for processing (3)
  • apps/web/ce/components/issues/issue-modal/index.ts (0 hunks)
  • apps/web/core/components/dropdowns/member/member-options.tsx (2 hunks)
  • apps/web/core/components/issues/issue-modal/context/issue-modal-context.tsx (3 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/ce/components/issues/issue-modal/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/core/components/dropdowns/member/member-options.tsx
  • apps/web/core/components/issues/issue-modal/context/issue-modal-context.tsx
✨ 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
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this 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.

@makeplane
Copy link

makeplane bot commented Jul 8, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

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 comments (2)
apps/web/core/components/dropdowns/module/base.tsx (1)

167-167: Avoid using as any type casting.

The onChange prop is being cast to any, which bypasses TypeScript's type checking and could hide potential type mismatches. Consider fixing the type definitions to ensure type safety.

-              onChange={onChange as any}
+              onChange={onChange}

If there's a type mismatch, update the ModuleButtonContent props type to properly handle both single and multiple selection onChange signatures, or create a union type that accommodates both cases.

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

93-110: Use filter-map pattern to avoid undefined values in array.

The current implementation creates undefined values in the options array when renderCondition returns false, which are filtered out later. Consider using a filter-map pattern for cleaner code.

-  const options = projectIds?.map((projectId) => {
-    const projectDetails = getProjectById(projectId);
-    if (renderCondition && !renderCondition(projectId)) return;
-    return {
-      value: projectId,
-      query: `${projectDetails?.name}`,
-      content: (
-        <div className="flex items-center gap-2">
-          {projectDetails?.logo_props && (
-            <span className="grid place-items-center flex-shrink-0 h-4 w-4">
-              <Logo logo={projectDetails?.logo_props} size={12} />
-            </span>
-          )}
-          <span className="flex-grow truncate">{projectDetails?.name}</span>
-        </div>
-      ),
-    };
-  });
+  const options = projectIds
+    ?.filter((projectId) => !renderCondition || renderCondition(projectId))
+    ?.map((projectId) => {
+      const projectDetails = getProjectById(projectId);
+      return {
+        value: projectId,
+        query: `${projectDetails?.name}`,
+        content: (
+          <div className="flex items-center gap-2">
+            {projectDetails?.logo_props && (
+              <span className="grid place-items-center flex-shrink-0 h-4 w-4">
+                <Logo logo={projectDetails?.logo_props} size={12} />
+              </span>
+            )}
+            <span className="flex-grow truncate">{projectDetails?.name}</span>
+          </div>
+        ),
+      };
+    });

This eliminates the need to filter out undefined values in filteredOptions.

🧹 Nitpick comments (4)
apps/web/helpers/react-hook-form.helper.ts (1)

10-19: Consider edge case handling for path validation.

The function handles object traversal well, but consider adding validation for edge cases like empty paths or malformed paths.

export const getNestedError = <T extends FieldValues>(errors: T, path: string): FieldError | undefined => {
+ // Handle empty or invalid paths
+ if (!path || !path.trim()) {
+   return undefined;
+ }
+ 
  const keys = path.split(".");
  let current: unknown = errors;

This would gracefully handle cases where an empty string or whitespace-only path is passed.

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

52-52: Remove unnecessary nullish coalescing.

The moduleIds ?? [] is unnecessary since moduleIds is already guaranteed to be an array (either from getProjectModuleIds() or the fallback [] on line 42).

-      moduleIds={moduleIds ?? []}
+      moduleIds={moduleIds}
apps/web/core/components/dropdowns/member/dropdown.tsx (1)

44-44: Remove unnecessary nullish coalescing.

The memberIds ?? [] is unnecessary since the resolution logic in lines 30-34 already ensures memberIds is not null/undefined (it falls back to workspaceMemberIds).

-      memberIds={memberIds ?? []}
+      memberIds={memberIds}
apps/web/core/components/dropdowns/module/button-content.tsx (1)

40-40: Consider decoupling from store hooks for consistency.

The component uses useModule hook internally, which is inconsistent with the overall refactoring pattern of decoupling components from store dependencies. Consider receiving getModuleById as a prop instead.

-// store hooks
-const { getModuleById } = useModule();
+type ModuleButtonContentProps = {
+  getModuleById: (moduleId: string) => IModule | null;
   disabled: boolean;
   // ... other props
};

Then update the component to use the prop:

export const ModuleButtonContent: React.FC<ModuleButtonContentProps> = (props) => {
  const {
+    getModuleById,
     disabled,
     // ... other props
   } = props;
-  // store hooks
-  const { getModuleById } = useModule();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd9da31 and ee09f82.

📒 Files selected for processing (21)
  • apps/web/core/components/cycles/form.tsx (1 hunks)
  • apps/web/core/components/dropdowns/index.ts (1 hunks)
  • apps/web/core/components/dropdowns/member/base.tsx (3 hunks)
  • apps/web/core/components/dropdowns/member/dropdown.tsx (1 hunks)
  • apps/web/core/components/dropdowns/member/member-options.tsx (2 hunks)
  • apps/web/core/components/dropdowns/module/base.tsx (6 hunks)
  • apps/web/core/components/dropdowns/module/button-content.tsx (1 hunks)
  • apps/web/core/components/dropdowns/module/dropdown.tsx (1 hunks)
  • apps/web/core/components/dropdowns/module/module-options.tsx (3 hunks)
  • apps/web/core/components/dropdowns/project/base.tsx (6 hunks)
  • apps/web/core/components/dropdowns/project/dropdown.tsx (1 hunks)
  • apps/web/core/components/dropdowns/state/base.tsx (4 hunks)
  • apps/web/core/components/dropdowns/state/dropdown.tsx (1 hunks)
  • apps/web/core/components/issues/issue-modal/components/project-select.tsx (1 hunks)
  • apps/web/core/components/issues/issue-modal/form.tsx (4 hunks)
  • apps/web/core/components/issues/select/base.tsx (3 hunks)
  • apps/web/core/components/issues/select/dropdown.tsx (1 hunks)
  • apps/web/core/components/issues/select/index.ts (1 hunks)
  • apps/web/core/components/labels/create-label-modal.tsx (3 hunks)
  • apps/web/core/components/modules/form.tsx (1 hunks)
  • apps/web/helpers/react-hook-form.helper.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
apps/web/core/components/issues/issue-modal/components/project-select.tsx (2)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
apps/web/core/components/modules/form.tsx (2)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
apps/web/core/components/issues/issue-modal/form.tsx (2)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7061
File: web/core/components/workspace-notifications/root.tsx:18-18
Timestamp: 2025-05-14T13:16:23.323Z
Learning: In the Plane project codebase, the path alias `@/plane-web` resolves to the `ce` directory, making imports like `@/plane-web/hooks/use-notification-preview` correctly resolve to files in `web/ce/hooks/`.
apps/web/core/components/cycles/form.tsx (2)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
apps/web/core/components/dropdowns/index.ts (2)
Learnt from: mathalav55
PR: makeplane/plane#6107
File: web/ce/components/workspace-notifications/sidebar/notification-card/options/read.tsx:11-12
Timestamp: 2024-11-28T07:02:15.514Z
Learning: Some components are still in core and have not been moved yet, so their import paths remain the same.
Learnt from: mathalav55
PR: makeplane/plane#6107
File: web/ce/components/workspace-notifications/sidebar/notification-card/options/archive.tsx:11-14
Timestamp: 2024-11-28T07:02:54.664Z
Learning: When components are still located in `core`, it's appropriate for files to import them using `@/components/...`, and the migration to the new import paths is not necessary in such cases.
apps/web/core/components/issues/select/dropdown.tsx (1)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
apps/web/core/components/labels/create-label-modal.tsx (1)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
apps/web/core/components/dropdowns/module/module-options.tsx (1)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
apps/web/core/components/dropdowns/project/base.tsx (3)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7061
File: web/core/components/workspace-notifications/root.tsx:18-18
Timestamp: 2025-05-14T13:16:23.323Z
Learning: In the Plane project codebase, the path alias `@/plane-web` resolves to the `ce` directory, making imports like `@/plane-web/hooks/use-notification-preview` correctly resolve to files in `web/ce/hooks/`.
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
apps/web/core/components/issues/select/base.tsx (1)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
apps/web/core/components/dropdowns/state/base.tsx (1)
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
🧬 Code Graph Analysis (7)
apps/web/core/components/dropdowns/project/dropdown.tsx (1)
apps/web/core/components/dropdowns/project/base.tsx (1)
  • ProjectDropdownBase (44-287)
apps/web/core/components/dropdowns/module/dropdown.tsx (1)
apps/web/core/components/dropdowns/module/base.tsx (1)
  • ModuleDropdownBase (45-198)
apps/web/core/components/dropdowns/module/button-content.tsx (2)
packages/utils/src/common.ts (1)
  • cn (8-8)
packages/ui/src/tooltip/tooltip.tsx (1)
  • Tooltip (36-110)
apps/web/core/components/issues/select/dropdown.tsx (1)
apps/web/core/components/issues/select/base.tsx (2)
  • TWorkItemLabelSelectBaseProps (18-32)
  • WorkItemLabelSelectBase (34-267)
apps/web/core/components/dropdowns/member/base.tsx (2)
packages/utils/src/common.ts (1)
  • cn (8-8)
apps/web/core/components/dropdowns/member/member-options.tsx (1)
  • MemberOptions (30-161)
apps/web/core/components/dropdowns/module/base.tsx (1)
apps/web/core/components/dropdowns/module/button-content.tsx (1)
  • ModuleButtonContent (25-129)
apps/web/core/components/dropdowns/state/dropdown.tsx (1)
apps/web/core/components/dropdowns/state/base.tsx (2)
  • TWorkItemStateDropdownBaseProps (22-40)
  • WorkItemStateDropdownBase (42-253)
🪛 Biome (1.9.4)
apps/web/core/components/dropdowns/state/base.tsx

[error] 80-80: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

⏰ 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). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (31)
apps/web/helpers/react-hook-form.helper.ts (2)

1-8: LGTM! Good documentation and imports.

The imports are appropriate and the JSDoc documentation clearly explains the function's purpose and parameters.


9-27: Well-structured utility function that aligns with the refactoring goals.

This helper function provides a clean, type-safe way to access nested form errors, which supports the broader architectural shift toward more controlled and decoupled form components mentioned in the PR objectives.

apps/web/core/components/issues/select/index.ts (1)

1-1: API change aligns with refactor objectives.

The export change from "./label" to "./dropdown" is part of the coordinated refactor to decouple dropdown components from store dependencies. This change ensures consumers receive the updated dropdown-based implementation.

apps/web/core/components/issues/issue-modal/components/project-select.tsx (1)

49-49: API update correctly implements the refactor pattern.

The renderCondition prop change from accepting a project object to a project ID string is consistent with the broader refactor to decouple dropdown components from store dependencies. The logic correctly uses direct ID lookup in allowedProjectIds.includes(projectId).

apps/web/core/components/issues/issue-modal/form.tsx (3)

35-35: Hook import supports the decoupling refactor.

The useLabel hook import is correctly added to support the new label creation pattern where the modal receives an explicit createLabel function instead of relying on internal store hooks.


127-127: Correct destructuring of createLabel function.

The createLabel function is properly destructured from the useLabel hook to support the new prop-based label creation approach.


366-366: Proper function binding for decoupled modal.

The createLabel function is correctly bound with workspaceSlug and projectId parameters before being passed to CreateLabelModal. This approach provides the necessary context while maintaining the decoupled API design.

apps/web/core/components/cycles/form.tsx (1)

86-86: Correctly implements the standardized renderCondition API.

The renderCondition prop change from accepting a project object to a project ID string is consistent with the broader refactor. The permission check logic correctly uses direct ID lookup with !!projectsWithCreatePermissions?.[projectId].

apps/web/core/components/modules/form.tsx (1)

96-96: Consistent implementation of the refactor pattern.

The renderCondition prop change from accepting a project object to a project ID string aligns with the coordinated refactor across all dropdown components. The permission check logic correctly uses !!projectsWithCreatePermissions?.[projectId] and maintains existing functionality.

apps/web/core/components/dropdowns/index.ts (1)

1-1: Export paths correctly updated to reflect new component structure.

The export paths have been properly updated to point to the new dropdown wrapper components in their respective subdirectories. This aligns with the refactoring pattern where base components are separated from store-connected wrapper components.

Also applies to: 7-7, 9-10

apps/web/core/components/issues/select/dropdown.tsx (2)

13-35: Well-structured wrapper component following the refactoring pattern.

The component correctly implements the wrapper pattern by:

  • Using observer for reactive updates
  • Extracting store data and providing it to the base component
  • Implementing conditional fetching logic
  • Properly forwarding props

The implementation aligns well with the refactoring objectives.


22-25: Conditional fetching logic is correct and needs no changes
getProjectLabelIds returns undefined only when labels haven’t been fetched yet and thereafter always returns an array (possibly empty). The current check (projectLabelIds === undefined) will reliably trigger exactly one fetch and never misinterpret null or an empty array as “not fetched.”

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

30-35: Simple and correct wrapper implementation.

The component correctly implements the wrapper pattern by using the project store hook and passing the data to the base component. The implementation is clean and follows the established pattern.

Note that unlike other dropdown wrappers, this one doesn't include conditional fetching logic, which suggests project data is already available when needed.


9-28: Well-designed union type for single/multiple selection modes.

The union type correctly enforces that multiple, onChange, and value props are consistent with each other. This prevents invalid combinations like multiple: true with a non-array value.

apps/web/core/components/dropdowns/module/dropdown.tsx (2)

17-17: Consider making projectId required.

Since the component's functionality depends heavily on projectId (for both getting module IDs and fetching modules), consider making it required rather than optional. An undefined projectId results in an empty array and no fetching capability.

⛔ Skipped due to learnings
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.

44-46: Fix the conditional fetching logic.

The condition !moduleIds will be true when moduleIds is an empty array [], which is falsy in JavaScript. This means the component will attempt to fetch modules even when an empty array is intentionally returned (e.g., when a project has no modules).

Consider checking for undefined or null specifically:

-  const onDropdownOpen = () => {
-    if (!moduleIds && projectId && workspaceSlug) fetchModules(workspaceSlug.toString(), projectId);
-  };
+  const onDropdownOpen = () => {
+    if (moduleIds === undefined && projectId && workspaceSlug) fetchModules(workspaceSlug.toString(), projectId);
+  };
⛔ Skipped due to learnings
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
apps/web/core/components/dropdowns/member/dropdown.tsx (2)

30-34: Well-structured member ID resolution logic.

The cascading logic for determining member IDs is well-structured:

  1. Use explicitly provided memberIds if available
  2. Fall back to project member IDs if projectId is provided
  3. Use workspace member IDs as final fallback

This provides good flexibility for different use cases.


36-38: Fix the conditional fetching logic.

Similar to the ModuleDropdown, the condition !memberIds will be true when memberIds is an empty array []. This could cause unnecessary fetching when a project intentionally has no members.

-  const onDropdownOpen = () => {
-    if (!memberIds && projectId && workspaceSlug) fetchProjectMembers(workspaceSlug.toString(), projectId);
-  };
+  const onDropdownOpen = () => {
+    if (memberIds === undefined && projectId && workspaceSlug) fetchProjectMembers(workspaceSlug.toString(), projectId);
+  };

Likely an incorrect or invalid review comment.

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

21-24: Good refactoring to decouple from store dependencies.

The new props interface effectively separates data fetching from UI rendering by requiring getUserDetails callback and accepting memberIds as a prop. This improves testability and component reusability.


79-95: Confirm Upstream Guest-User Filtering

I wasn’t able to find any logic in MemberOptions or its parent components that excludes guest users. Before merging, please verify that guest accounts are still being filtered out upstream—otherwise they’ll appear in this dropdown.

Points to double-check:

  • Where memberIds is populated (e.g. your data-fetch hook or selector that returns project members)
  • Any service/API layers (e.g. fetchProjectMembers or GraphQL queries) that should omit guests
  • The component that passes memberIds into (in base.tsx)
apps/web/core/components/dropdowns/module/module-options.tsx (2)

26-33: Consistent refactoring pattern with improved separation of concerns.

The new props interface follows the same pattern as other dropdown components, receiving data via getModuleById callback and moduleIds prop. This effectively decouples the component from internal store dependencies.


81-93: Clean data transformation using callback pattern.

The options construction now uses the getModuleById callback instead of internal store selectors, maintaining the same functionality while improving modularity.

apps/web/core/components/labels/create-label-modal.tsx (2)

23-27: Excellent refactoring to a pure presentational component.

The new createLabel prop interface successfully decouples the modal from routing and store concerns, making it more testable and reusable. The component now focuses solely on UI logic and form handling.


70-83: Clean error handling with delegated label creation.

The onSubmit handler now uses the provided createLabel function directly, maintaining proper error handling while delegating the actual creation logic to the parent component.

apps/web/core/components/dropdowns/state/dropdown.tsx (2)

18-47: Well-structured wrapper component with proper loading state management.

The new StateDropdown component effectively separates data fetching concerns from UI rendering. The loading state (stateLoader) is properly managed during asynchronous operations, and the component correctly passes data down to WorkItemStateDropdownBase.


30-36: Efficient lazy loading implementation.

The onDropdownOpen function implements proper lazy loading by only fetching states when needed (when stateIds is undefined) and includes proper loading state management.

apps/web/core/components/dropdowns/module/button-content.tsx (2)

25-41: Good UI logic extraction with comprehensive prop interface.

The component effectively handles both single and multiple module selection scenarios with a well-designed props interface. The component supports various display options and interaction states.


43-116: Robust handling of multiple module selection with proper UX.

The array handling logic properly supports both count display and individual module chips, with tooltips and remove functionality. The edge cases (empty arrays, single vs multiple items) are handled correctly.

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

1-183: Clean refactoring to decouple from store dependencies.

The component has been successfully refactored to receive data and callbacks via props, making it more reusable and testable. The implementation follows the established pattern across other dropdown components.

apps/web/core/components/issues/select/base.tsx (1)

1-267: Well-structured refactoring following the established pattern.

The component has been successfully decoupled from store dependencies and now receives data via props. The implementation is clean and maintains proper separation of concerns.

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

1-253: Excellent refactoring with comprehensive prop configuration.

The component has been successfully refactored with a rich set of configuration props, making it highly flexible and reusable. The implementation maintains consistency with other dropdown components in the codebase.

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee09f82 and 6ac77c8.

📒 Files selected for processing (7)
  • apps/web/ce/components/issues/issue-modal/additional-properties.tsx (0 hunks)
  • apps/web/ce/components/issues/issue-modal/index.ts (0 hunks)
  • apps/web/ce/components/issues/issue-modal/modal-additional-properties.tsx (1 hunks)
  • apps/web/ce/components/issues/issue-modal/provider.tsx (1 hunks)
  • apps/web/core/components/issues/issue-modal/base.tsx (2 hunks)
  • apps/web/core/components/issues/issue-modal/context/issue-modal-context.tsx (3 hunks)
  • apps/web/core/components/issues/issue-modal/form.tsx (5 hunks)
💤 Files with no reviewable changes (2)
  • apps/web/ce/components/issues/issue-modal/index.ts
  • apps/web/ce/components/issues/issue-modal/additional-properties.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/web/ce/components/issues/issue-modal/modal-additional-properties.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/core/components/issues/issue-modal/form.tsx
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: prateekshourya29
PR: makeplane/plane#7363
File: apps/web/core/components/issues/select/dropdown.tsx:9-11
Timestamp: 2025-07-08T13:41:01.610Z
Learning: The `getProjectLabelIds` function in the label store handles undefined projectId internally, so it's safe to pass undefined values to it without explicit checks in the calling component.
Learnt from: prateekshourya29
PR: makeplane/plane#7188
File: web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx:40-45
Timestamp: 2025-06-18T09:46:08.566Z
Learning: When reviewing breadcrumb components that accept projectId or similar props, check if empty strings are being passed during loading states, which can result in invalid URLs. The preferred approach is to handle these loading states internally within the component rather than requiring each consumer to manage the loading logic.
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
apps/web/core/components/issues/issue-modal/base.tsx (2)
Learnt from: vamsikrishnamathala
PR: makeplane/plane#7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Learnt from: prateekshourya29
PR: makeplane/plane#7363
File: apps/web/core/components/issues/select/dropdown.tsx:9-11
Timestamp: 2025-07-08T13:41:01.610Z
Learning: The `getProjectLabelIds` function in the label store handles undefined projectId internally, so it's safe to pass undefined values to it without explicit checks in the calling component.
apps/web/core/components/issues/issue-modal/context/issue-modal-context.tsx (1)
Learnt from: prateekshourya29
PR: makeplane/plane#7363
File: apps/web/helpers/react-hook-form.helper.ts:9-19
Timestamp: 2025-07-08T13:41:19.881Z
Learning: In the apps/web/helpers/react-hook-form.helper.ts file, the getNestedError function's FieldError detection logic using "message" property check is sufficient for their use case, and more robust type checking is not required.
🔇 Additional comments (5)
apps/web/ce/components/issues/issue-modal/provider.tsx (1)

47-47: LGTM: Consistent stub implementation pattern

The no-op implementation of handleCreateSubWorkItem follows the established pattern of other handler functions in the CE provider. This is appropriate for a Community Edition stub.

apps/web/core/components/issues/issue-modal/base.tsx (1)

71-71: LGTM: Proper extraction of handler function

The handleCreateSubWorkItem function is correctly extracted from the issue modal context.

apps/web/core/components/issues/issue-modal/context/issue-modal-context.tsx (3)

4-4: LGTM: Import reorganization

Moving the TIssueFields import earlier in the import section is a minor reorganization that doesn't affect functionality.


31-35: LGTM: Well-defined type for sub work item creation

The TCreateSubWorkItemProps type is clearly defined with appropriate required properties. The type follows the existing naming and structure patterns in the codebase.


74-74: LGTM: Consistent interface extension

The handleCreateSubWorkItem method addition to the TIssueModalContext interface is consistent with other handler functions and properly typed.

@pushya22 pushya22 marked this pull request as draft July 14, 2025 10:56
@prateekshourya29 prateekshourya29 marked this pull request as ready for review July 18, 2025 11:24
@pushya22 pushya22 merged commit f3daac6 into preview Jul 18, 2025
5 of 6 checks passed
@pushya22 pushya22 deleted the refactor-work-item-property-dropdowns branch July 18, 2025 15:08
@aheckmann
Copy link
Contributor

@prateekshourya29 This PR broke the web app build. Please fix first thing Monday.

web:build: ./ee/components/issues/issue-modal/additional-properties.tsx:1:15
web:build: Type error: Cannot find module 'ce/components/issues/issue-modal/additional-properties' or its corresponding type declarations.
web:build: 
web:build: > 1 | export * from "ce/components/issues/issue-modal/additional-properties";`

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.

4 participants