Skip to content

Conversation

@anmolsinghbhatia
Copy link
Collaborator

@anmolsinghbhatia anmolsinghbhatia commented Dec 1, 2025

Description

This PR includes the following changes:

  • Fixes unwanted panel reopen by distinguishing programmatic vs. user-initiated focus using onMouseDown.
  • Refactors shared expandable search logic into a reusable useExpandableSearch hook.
  • Ensures panels still open automatically when the user starts typing.

Type of Change

  • Bug fix
  • Improvement
  • Code refactoring

Summary by CodeRabbit

  • New Features

    • Improved expandable search with consistent open/close, better focus behavior, and auto-opening when typing.
  • Refactor

    • Centralized search state and event handling for more reliable interactions.
    • Responsive tab layout now responds to container changes.
  • Bug Fixes

    • Right-side sidebar actions only show on the Projects view to avoid irrelevant controls.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new hook to centralize expandable-search UI state and handlers; refactors the top navigation to use that hook; updates a responsive tab ResizeObserver to depend on the container ref; conditionally renders the right-side action group in the sidebar only when the title is "Projects"; minor formatting changes to two locale files.

Changes

Cohort / File(s) Summary
New Hook for Centralized Search State
apps/web/core/hooks/use-expandable-search.ts
Adds useExpandableSearch and UseExpandableSearchOptions. Manages isOpen, refs (containerRef, inputRef), click/focus tracking, outside-click detection, and exposes handlers (handleClose, handleMouseDown, handleFocus, openPanel, etc.).
Top navigation refactor to use hook
apps/web/core/components/navigation/top-nav-power-k.tsx
Replaces local open-state, local refs, and manual outside-click/focus logic with the new hook; uses hook-provided isOpen, refs and handlers; wires input interactions to open panel and delegates close/reset logic to the hook.
Responsive tab layout effect adjustment
apps/web/core/components/navigation/use-responsive-tab-layout.ts
Introduces container = containerRef?.current; updates the ResizeObserver effect to use the alias and use [container] as the dependency so the effect re-runs when the container changes.
Sidebar conditional rendering change
apps/web/core/components/sidebar/sidebar-wrapper.tsx
Right-side action group (Preferences button and AppSidebarToggleButton) is now rendered only when the sidebar title equals "Projects"; previously it was always rendered.
Localization formatting-only changes
packages/i18n/src/locales/de/empty-state.ts, packages/i18n/src/locales/pt-BR/empty-state.ts
Multiline reformatting of restricted_description string literals (no semantic/runtime changes).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect use-expandable-search for proper cleanup of outside-click detection and focus/click flag semantics.
  • Verify top-nav-power-k.tsx uses the hook API consistently (handler names and onClose behavior) and that search state resets correctly.
  • Confirm use-responsive-tab-layout ResizeObserver teardown and that [container] dependency doesn't cause excessive re-runs.
  • Check that the sidebar conditional preserves layout and accessibility for other titles.
  • Locale files are formatting-only; no functional review needed.

Poem

🐇 I hopped through lines with twinkling eyes,
I stitched a hook where the search now flies.
Panels open on a mindful click,
Tabs watch well, the ResizeObserver ticks.
Sidebar waits — "Projects" earns the prize. 🎉

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: preventing search panels from reopening on programmatic focus restoration. It directly relates to the core fix implemented in the PR.
Description check ✅ Passed The description covers the main objectives and includes the type of change. However, it lacks detailed explanation of how the changes work and is missing the optional but helpful sections like screenshots and test scenarios.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 chore-expandable-search-improvements-and-refactor

📜 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 60bd2c0 and f0667fa.

📒 Files selected for processing (4)
  • apps/web/core/components/navigation/top-nav-power-k.tsx (9 hunks)
  • apps/web/core/hooks/use-expandable-search.ts (1 hunks)
  • packages/i18n/src/locales/de/empty-state.ts (1 hunks)
  • packages/i18n/src/locales/pt-BR/empty-state.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/i18n/src/locales/pt-BR/empty-state.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/core/hooks/use-expandable-search.ts
  • apps/web/core/components/navigation/top-nav-power-k.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{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:

  • packages/i18n/src/locales/de/empty-state.ts
⏰ 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). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
packages/i18n/src/locales/de/empty-state.ts (1)

31-32: LGTM: Formatting-only change.

The multiline formatting of the restricted_description string has no functional impact and maintains the same text content.


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 Dec 1, 2025

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

@anmolsinghbhatia anmolsinghbhatia self-assigned this Dec 1, 2025
@anmolsinghbhatia anmolsinghbhatia marked this pull request as ready for review December 1, 2025 10:20
Copilot AI review requested due to automatic review settings December 1, 2025 10:20
aaryan610
aaryan610 previously approved these changes Dec 1, 2025
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/core/components/navigation/top-nav-power-k.tsx (1)

131-199: Add missing dependency to handleKeyDown callback.

The handleKeyDown callback uses isOpen directly (lines 162, 187) but doesn't include it in the dependency array (line 198). This creates a stale closure where the callback retains the old value of isOpen, potentially causing the arrow key and Enter key handlers to operate on outdated state.

Apply this diff to add the missing dependency:

     [searchTerm, activePage, context, shouldShowContextBasedActions, setActivePage, closePanel]
+    [searchTerm, activePage, context, shouldShowContextBasedActions, setActivePage, closePanel, isOpen]
   );

Note: containerRef doesn't need to be added since refs are stable across renders.

🧹 Nitpick comments (2)
apps/web/core/hooks/use-expandable-search.ts (2)

4-6: Export the type for better developer experience.

The UseExpandableSearchOptions type should be exported so consuming code can reference it for type safety and documentation purposes.

Apply this diff to export the type:

-type UseExpandableSearchOptions = {
+export type UseExpandableSearchOptions = {
   onClose?: () => void;
 };

50-55: Consider stabilizing openPanel to avoid unnecessary re-renders.

The openPanel callback includes isOpen as a dependency, causing it to be recreated whenever the panel opens or closes. This could trigger unnecessary re-renders in consuming components that depend on this callback.

Consider using a functional state update to eliminate the dependency:

 // Helper to open panel (for typing/onChange)
-const openPanel = useCallback(() => {
-  if (!isOpen) {
-    setIsOpen(true);
-  }
-}, [isOpen]);
+const openPanel = useCallback(() => {
+  setIsOpen((prev) => prev ? prev : true);
+}, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8db95d9 and e1f8fc0.

📒 Files selected for processing (2)
  • apps/web/core/components/navigation/top-nav-power-k.tsx (9 hunks)
  • apps/web/core/hooks/use-expandable-search.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{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/navigation/top-nav-power-k.tsx
  • apps/web/core/hooks/use-expandable-search.ts
🧠 Learnings (2)
📚 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/navigation/top-nav-power-k.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/navigation/top-nav-power-k.tsx
🧬 Code graph analysis (1)
apps/web/core/components/navigation/top-nav-power-k.tsx (1)
apps/web/core/hooks/use-expandable-search.ts (1)
  • useExpandableSearch (12-72)
⏰ 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 and lint web apps
🔇 Additional comments (2)
apps/web/core/components/navigation/top-nav-power-k.tsx (2)

34-49: Well-integrated hook usage!

The integration of the useExpandableSearch hook is clean and properly centralizes the expandable search behavior. The onClose callback correctly resets the related state, and the destructured values are used appropriately throughout the component.


223-228: Excellent implementation of the user interaction distinction.

The combination of openPanel on input change and handleMouseDown on the input element correctly distinguishes between user-initiated focus (which should open the panel) and programmatic focus restoration (which should not). This directly addresses the PR objective of preventing unwanted panel reopening.

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 fixes an issue where search panels would inadvertently reopen when focus was restored programmatically (rather than by user interaction). The solution distinguishes between user-initiated focus (via mouse clicks) and programmatic focus by tracking mouse-down events. Additionally, the PR refactors the expandable search behavior into a reusable useExpandableSearch hook that can be shared across components.

Key changes:

  • Created a new useExpandableSearch hook that manages focus state and prevents unwanted panel reopening on programmatic focus restoration
  • Refactored TopNavPowerK component to use the new hook, reducing code duplication and improving maintainability
  • Added onMouseDown handler to track explicit user clicks, distinguishing them from programmatic focus events

Reviewed changes

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

File Description
apps/web/core/hooks/use-expandable-search.ts New reusable hook implementing expandable search logic with focus management, outside-click detection, and programmatic vs. user-initiated focus distinction
apps/web/core/components/navigation/top-nav-power-k.tsx Refactored to use the new useExpandableSearch hook, removing duplicate state/ref management and consolidating panel close logic into a single closePanel function

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

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 (1)
apps/web/core/components/navigation/use-responsive-tab-layout.ts (1)

45-45: Optional chaining is unnecessary.

The optional chaining operator (?.) on line 45 is redundant. containerRef is initialized with useRef<HTMLDivElement>(null) on line 34, so it's never null or undefined—only its .current property can be null.

Apply this diff:

-  const container = containerRef?.current;
+  const container = containerRef.current;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1f8fc0 and 60bd2c0.

📒 Files selected for processing (2)
  • apps/web/core/components/navigation/use-responsive-tab-layout.ts (2 hunks)
  • apps/web/core/components/sidebar/sidebar-wrapper.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{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/navigation/use-responsive-tab-layout.ts
  • apps/web/core/components/sidebar/sidebar-wrapper.tsx
🧬 Code graph analysis (1)
apps/web/core/components/sidebar/sidebar-wrapper.tsx (2)
packages/propel/src/icons/actions/preferences-icon.tsx (1)
  • PreferencesIcon (6-13)
apps/web/core/components/sidebar/sidebar-toggle-button.tsx (1)
  • AppSidebarToggleButton (7-23)
⏰ 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). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/web/core/components/navigation/use-responsive-tab-layout.ts (1)

45-62: LGTM! This fixes a timing bug with ResizeObserver setup.

The dependency array change from [] to [container] ensures the ResizeObserver is properly set up when the DOM element is attached. The previous code would only run once on mount, potentially before the ref was attached, causing the observer to never be initialized.

apps/web/core/components/sidebar/sidebar-wrapper.tsx (1)

52-63: No UX impact on other sidebars from this conditional rendering.

The Preferences and toggle buttons are only rendered when title === "Projects", but SidebarWrapper is currently used in only one location with title="Projects". There are no other sidebars using this component with different title values, so this change does not break existing functionality. The conditional is scoped appropriately to the current usage pattern.

Likely an incorrect or invalid review comment.

@aaryan610 aaryan610 self-requested a review December 1, 2025 12:08
aaryan610
aaryan610 previously approved these changes Dec 1, 2025
@pushya22 pushya22 merged commit 980428b into preview Dec 1, 2025
6 checks passed
@pushya22 pushya22 deleted the chore-expandable-search-improvements-and-refactor branch December 1, 2025 13:07
ClarenceChen0627 pushed a commit to ClarenceChen0627/plane that referenced this pull request Dec 5, 2025
ClarenceChen0627 pushed a commit to ClarenceChen0627/plane that referenced this pull request Dec 5, 2025
ClarenceChen0627 pushed a commit to ClarenceChen0627/plane that referenced this pull request Dec 5, 2025
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.

4 participants