Skip to content

refactor(sidebar): Reuse Item component & pure css for collapsable animation (backport #6412)#6413

Merged
siduck merged 2 commits into
masterfrom
mergify/bp/master/pr-6412
May 12, 2026
Merged

refactor(sidebar): Reuse Item component & pure css for collapsable animation (backport #6412)#6413
siduck merged 2 commits into
masterfrom
mergify/bp/master/pr-6412

Conversation

@mergify

@mergify mergify Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Remove duplicate code

Before

  • Since search, notifcation btns arent link elements i made separate components for them duplicating the style logic of the Item.vue in sidebar

After

  • Make single Item.vue to allow :is prop so we can make it render a link tag/button or whatever

Remove JS for ItemGroup

  • ItemGroup is the collapsable section you see in the sidebar

Before

  • Simple vue state to toggle the itemgroup
  • CollapseTransition wrapper component for animating it

Now

  • native <details> element to toggle content. no need of js
  • use grid-template-rows for pure css animations

This is an automatic backport of pull request #6412 done by [Mergify](https://mergify.com).

@greptile-apps

greptile-apps Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR eliminates duplicate sidebar component code by making Item.vue polymorphic (via an is prop), and replaces the JS-driven collapsible ItemGroup with a native <details> element and a CSS grid-template-rows animation.

  • Item.vue is now a single shared component that renders as router-link, button, summary, or any element, accepting typed NavItemProps and exposing prefix/suffix slots; SearchItem and Notifications are updated to consume it.
  • ItemGroup.vue drops Vue state + CollapseTransition in favour of a <details open> binding and a Tailwind peer-open: sibling transition on a separate <div>; the peer-open: selector uses a general sibling combinator (~) which will bleed to later peer divs if a second ItemGroup is ever added.
  • Notifications.vue forwards $attrs explicitly to the inner <Item> without declaring inheritAttrs: false, so attributes are applied to both the <Popover> root and the button.

Confidence Score: 4/5

Safe to merge; the sidebar refactor is a clean simplification with no data-path changes, and all identified concerns are non-blocking style or future-proofing issues.

The peer-open: general-sibling approach works correctly with the current single ItemGroup, but would silently expand unrelated groups if a second one is added. The $attrs double-forwarding in Notifications.vue and the Ctrl+k capitalisation are minor polish items that don't affect runtime behaviour today.

ItemGroup.vue (peer CSS selector pattern) and Notifications.vue (inheritAttrs handling)

Important Files Changed

Filename Overview
dashboard/src/components/navigation/sidebar/Item.vue Refactored to a polymorphic component using NavItemProps + withDefaults; adds prefix/suffix slots and a configurable is prop. :to="route" is always bound but is safely omitted by Vue when route is undefined for non-router-link elements.
dashboard/src/components/navigation/sidebar/ItemGroup.vue Replaces Vue state + CollapseTransition with native <details> + CSS grid animation using Tailwind peer selectors; the peer-open: general sibling combinator will bleed to later ItemGroup divs if a second group is ever added.
dashboard/src/components/navigation/sidebar/NavList.vue Switches to v-bind spread for Item/ItemGroup props and passes only disabled to custom components; adds a -mt-1 class to the Marketplace nav entry.
dashboard/src/components/navigation/sidebar/Notifications.vue Replaces custom button markup with the shared Item component; uses v-bind='$attrs' without inheritAttrs: false, causing attributes to be forwarded to both the Popover root and the Item button.
dashboard/src/components/navigation/sidebar/SearchItem.vue Simplified to use the shared Item component; non-Mac shortcut label changed from Ctrl+K to Ctrl+k (lowercase).
dashboard/src/components/navigation/sidebar/types.ts New file introducing the shared NavItemProps interface for typed sidebar item props.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    NL[NavList.vue] -->|v-bind item| IG[ItemGroup.vue]
    NL -->|v-bind item| IT[Item.vue]
    NL -->|:is customComponent| CC[Custom Component]

    IG -->|is=summary| IT
    IG -->|v-bind subItem| IT

    CC -->|Notifications.vue v-bind attrs| IT
    CC -->|SearchItem.vue| IT

    IT -->|is=router-link default| RL[router-link]
    IT -->|is=BUTTON| BT[button]
    IT -->|is=summary| SM[summary inside details]

    subgraph ItemGroup Animation
        DT[details.group.peer :open=isActive]
        DIV[div.peer-open:grid-rows-1fr]
        DT -. CSS tilde sibling .-> DIV
    end
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
dashboard/src/components/navigation/sidebar/ItemGroup.vue:22
**`peer-open:` general sibling selector bleeds across multiple groups**

Tailwind's `peer-open:` generates a CSS `~` (general sibling) selector: `.peer:open ~ .peer-open\:grid-rows-\[1fr\]`. This matches **every** subsequent sibling with the `peer-open:` class, not just the immediately adjacent one. If a second `ItemGroup` is ever added to the sidebar, opening the first group would also expand the second group's content `<div>` — because that `<div>` is a later sibling of the same `peer details:open`. Scoping with a Tailwind custom variant or wrapping the pair in a container would prevent the bleed.

### Issue 2 of 3
dashboard/src/components/navigation/sidebar/SearchItem.vue:12
The non-Mac shortcut changed from `Ctrl+K` (uppercase) to `Ctrl+k` (lowercase `k`). `Ctrl+K` is the conventional representation of this shortcut and matches the old label; lowercase `k` looks inconsistent with the Mac `⌘ K` shown alongside it.

```suggestion
        {{ isMac() ? '⌘ K' : 'Ctrl+K' }}
```

### Issue 3 of 3
dashboard/src/components/navigation/sidebar/Notifications.vue:201
**`$attrs` double-forwarded without `inheritAttrs: false`**

`Notifications.vue` explicitly passes `v-bind='$attrs'` to the inner `<Item>`, but the component does not declare `inheritAttrs: false`. Because the root element is `<Popover>`, Vue 3 also automatically applies `$attrs` to `<Popover>`. Any attribute passed to `Notifications` (currently `disabled` from `NavList`) ends up forwarded to both the `<Popover>` root **and** the `<Item>` button. Adding `inheritAttrs: false` in the script block would restrict forwarding to the explicit `v-bind='$attrs'` site only.

Reviews (1): Last reviewed commit: "chore(sidebar): Avoid using $attrs" | Re-trigger Greptile

/>
</div>
</CollapseTransition>
<div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 peer-open:grid-rows-[1fr]">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 peer-open: general sibling selector bleeds across multiple groups

Tailwind's peer-open: generates a CSS ~ (general sibling) selector: .peer:open ~ .peer-open\:grid-rows-\[1fr\]. This matches every subsequent sibling with the peer-open: class, not just the immediately adjacent one. If a second ItemGroup is ever added to the sidebar, opening the first group would also expand the second group's content <div> — because that <div> is a later sibling of the same peer details:open. Scoping with a Tailwind custom variant or wrapping the pair in a container would prevent the bleed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/components/navigation/sidebar/ItemGroup.vue
Line: 22

Comment:
**`peer-open:` general sibling selector bleeds across multiple groups**

Tailwind's `peer-open:` generates a CSS `~` (general sibling) selector: `.peer:open ~ .peer-open\:grid-rows-\[1fr\]`. This matches **every** subsequent sibling with the `peer-open:` class, not just the immediately adjacent one. If a second `ItemGroup` is ever added to the sidebar, opening the first group would also expand the second group's content `<div>` — because that `<div>` is a later sibling of the same `peer details:open`. Scoping with a Tailwind custom variant or wrapping the pair in a container would prevent the bleed.

How can I resolve this? If you propose a fix, please make it concise.

<Item is='BUTTON' name='Search' :icon='LucideSearch' @click="() => (searchModalOpen = true)">
<template #suffix>
<span class="inline-flex items-center text-sm gap-1">
{{ isMac() ? '⌘ K' : 'Ctrl+k' }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 The non-Mac shortcut changed from Ctrl+K (uppercase) to Ctrl+k (lowercase k). Ctrl+K is the conventional representation of this shortcut and matches the old label; lowercase k looks inconsistent with the Mac ⌘ K shown alongside it.

Suggested change
{{ isMac() ? '⌘ K' : 'Ctrl+k' }}
{{ isMac() ? '⌘ K' : 'Ctrl+K' }}
Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/components/navigation/sidebar/SearchItem.vue
Line: 12

Comment:
The non-Mac shortcut changed from `Ctrl+K` (uppercase) to `Ctrl+k` (lowercase `k`). `Ctrl+K` is the conventional representation of this shortcut and matches the old label; lowercase `k` looks inconsistent with the Mac `⌘ K` shown alongside it.

```suggestion
        {{ isMac() ? '⌘ K' : 'Ctrl+K' }}
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

}}
</span>
</button>
<Item is='BUTTON' v-bind='$attrs' aria-label="Notifications btn" name='Notifications' @click="togglePopover">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 $attrs double-forwarded without inheritAttrs: false

Notifications.vue explicitly passes v-bind='$attrs' to the inner <Item>, but the component does not declare inheritAttrs: false. Because the root element is <Popover>, Vue 3 also automatically applies $attrs to <Popover>. Any attribute passed to Notifications (currently disabled from NavList) ends up forwarded to both the <Popover> root and the <Item> button. Adding inheritAttrs: false in the script block would restrict forwarding to the explicit v-bind='$attrs' site only.

Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/components/navigation/sidebar/Notifications.vue
Line: 201

Comment:
**`$attrs` double-forwarded without `inheritAttrs: false`**

`Notifications.vue` explicitly passes `v-bind='$attrs'` to the inner `<Item>`, but the component does not declare `inheritAttrs: false`. Because the root element is `<Popover>`, Vue 3 also automatically applies `$attrs` to `<Popover>`. Any attribute passed to `Notifications` (currently `disabled` from `NavList`) ends up forwarded to both the `<Popover>` root **and** the `<Item>` button. Adding `inheritAttrs: false` in the script block would restrict forwarding to the explicit `v-bind='$attrs'` site only.

How can I resolve this? If you propose a fix, please make it concise.

@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.71%. Comparing base (29349a4) to head (c46a138).

Files with missing lines Patch % Lines
...rc/components/navigation/sidebar/Notifications.vue 76.19% 5 Missing ⚠️
...d/src/components/navigation/sidebar/SearchItem.vue 90.90% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master    #6413       +/-   ##
===========================================
+ Coverage   49.44%   59.71%   +10.27%     
===========================================
  Files         941      110      -831     
  Lines       78180    17348    -60832     
  Branches      352      355        +3     
===========================================
- Hits        38657    10360    -28297     
+ Misses      39500     6965    -32535     
  Partials       23       23               
Flag Coverage Δ
dashboard 59.71% <91.66%> (-0.11%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@siduck siduck merged commit d524ba0 into master May 12, 2026
13 checks passed
@siduck siduck deleted the mergify/bp/master/pr-6412 branch May 12, 2026 05:34
@frappe-pr-bot

Copy link
Copy Markdown
Collaborator

🎉 This PR is included in version 0.31.5 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants