Skip to content

Project board header toolbar revamp - EXO-88315 - #625

Merged
Jihed525 merged 2 commits into
developfrom
backport/EXO-88315-board-toolbar
Jul 20, 2026
Merged

Jihed525 merged 2 commits into
developfrom
backport/EXO-88315-board-toolbar

Conversation

@Jihed525

Copy link
Copy Markdown
Contributor

What

Backport of #616 (squash-merged into feature/ai-contribution) onto develop.

Reworks the project board header toolbar to be compact and responsive (modelled on the Agenda/Documents toolbars), and makes task search usable on mobile:

  • Board/List/Plan view selector becomes a compact icon + dropdown (TasksViewSwitcher, new component).
  • Keyword search collapses behind a filter icon and expands full width (works on phones now).
  • Advanced filter keeps its own icon with an applied-filter count.
  • Removes the now-dead 30/70 toolbar CSS split and old tab styling.

Backport notes

Cherry-picked cleanly on top of the current develop (which since diverged and now includes #623 "Tasks UI revamp — project cards & list toolbars"). #623 touched tasks.less/ProjectCard*/ProjectListToolbar/TasksListToolbar but never touched TasksViewToolbar.vue or tasksViewSwitcher/projectBoardToolbar CSS selectors, so there's no functional overlap between the two — auto-merge only needed to interleave unrelated hunks in shared files (tasks.less, taskManagement_en.properties, initComponents.js).

Verified after cherry-pick:

  • TasksViewSwitcher.vue/TasksViewToolbar.vue class names (tasksViewSwitcher, tasksViewSwitcherMenu, projectBoardToolbar, boardHeaderExtensions) all still resolve against the current tasks.less (post-feat: Tasks UI revamp — project cards & list toolbars - EXO-88314 #623 restructuring).
  • Component registered once in initComponents.js, no duplicate/missing entries.

Test

  • npx webpack --config webpack.prod.js --mode production → compiled with 0 errors (pre-existing lint warnings only, unrelated to this change).

🤖 Generated with Claude Code

## What

Reworks the project board header toolbar to be compact and responsive,
modelled on the **Agenda / Documents** toolbars, and makes task search
usable on mobile.

Before, the header used a hand-rolled `v-toolbar` with an inline
`v-tabs` view switcher, an always-on keyword field and a separate
*Filter* button, laid out with a fixed 30 % / 70 % flex split plus
bespoke `@media` CSS that simply **hid the keyword search on small
screens**.

## Changes

- Breadcrumb (back link + project name) stays on the left; the
`task-board-header` extension point (favorite ⭐ / AI 🔔) moves to the
**right**, grouped with the other actions.
- The **Board / List / Plan** view selector becomes a compact icon +
dropdown menu — new `TasksViewSwitcher`, styled after agenda's
`AgendaSwitchView` — kept visible on mobile.
- The **keyword search** collapses behind a filter icon and expands
**full width** with a back arrow (Esc closes it) → search now works on
phones.
- The **advanced filter** keeps its own icon (with applied-filter count)
and opens the existing *Sort & Filter* drawer.
- Right-hand action order: favorite/AI · view selector · search ·
advanced filter. All icons are `36×36 / 20px` with the lighter
`text-light-color`, evenly spaced; the back arrow aligns with the first
column's content.
- The view-switcher dropdown is relocated into the Vuetify app root so
it renders above the kanban board with the correct (opaque) theme
background.
- Removes the now-dead toolbar CSS (30/70 flex split, view-tab styling,
mobile overrides).

No backend changes. New i18n key `label.viewOptions` (en only; Crowdin
syncs the rest).

## Test

Verified live on a Meeds 7.2.x server: Board/List/Plan switching,
full-width search expand/collapse (incl. narrow widths), advanced filter
drawer, favorite/AI icons, alignment and even spacing — desktop and
compact.

---------

Co-authored-by: Benjamin <benjmestrallet@MacBook-Air.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Benjamin <benjmestrallet@mac.home>
Co-authored-by: Ali HAMDI <ahamdi@exoplatform.com>
(cherry picked from commit 77fd6dc)
@Jihed525
Jihed525 requested a review from boubaker July 20, 2026 12:41
@github-actions github-actions Bot added the partialCIBuild Perform Partial CI Build label Jul 20, 2026
@Jihed525
Jihed525 requested review from ahamdi and removed request for boubaker July 20, 2026 12:52

@boubaker boubaker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the diff, the current state of the touched files on backport/EXO-88315-board-toolbar, cross-checked against TasksListToolbar.vue (already merged via #623) and the cited AgendaSwitchView.vue precedent in exoplatform/agenda, and checked SonarCloud's new issues for this PR.

Overview

Backport of #616: reworks the project board header into a compact, responsive toolbar (breadcrumb left, favorite/AI + view switcher + search + advanced filter grouped right), replacing the old v-tabs-based view selector with a new TasksViewSwitcher dropdown and making keyword search collapsible/full-width on mobile. All CI checks pass, including SonarCloud this time.

Main finding — TasksViewSwitcher reinvents what <v-menu> already does

The PR says it's "styled after agenda's AgendaSwitchView" — I pulled that component (exoplatform/agenda's agenda-webapps/.../top-toolbar/AgendaSwitchView.vue) to compare. It's a plain <v-menu offset-y close-on-click> with an #activator slot — no manual DOM manipulation.

TasksViewSwitcher.vue instead hand-rolls the same behavior: it moves the dropdown card to .v-application via appendChild, computes top/left from getBoundingClientRect() on open, and manages its own click/scroll listeners to close it. This is exactly what <v-menu> already does out of the box (it renders its content detached from the DOM flow specifically to escape ancestor stacking contexts) — the stated reason ("not trapped in a v-toolbar stacking context" / kanban board's 3D-transform compositing layers) is the textbook case <v-menu> is built to handle, and its own cited precedent doesn't need to work around it.

Side effects of the manual approach, all of which come for free with <v-menu>:

  • No Escape-to-close on the switcher (the search field gets @keydown.esc, the switcher doesn't).
  • Most of .tasksViewSwitcherMenu's CSS is dead on arrival: position: absolute, top, inset-inline-end and z-index: 1000 are all immediately overridden by the inline styles set in mounted()/positionMenu() (which use fixed, computed top/left, and zIndex: 9999). Only transform: translateZ(0) and the duplicate min-width actually matter at runtime. .tasksViewSwitcher { position: relative; } is similarly pointless once the child is reparented to .v-application with position: fixed.

Would suggest trying a plain <v-menu offset-y> first (matching AgendaSwitchView) and only reaching for the manual DOM-relocation approach if there's a concrete, reproducible issue with it inside the kanban board — in which case that's worth a one-line comment explaining what broke, so the next reader doesn't wonder why this component diverges from its own stated model.

Confirmed by SonarCloud (3 new MAJOR issues)

  • TasksViewSwitcher.vue: change event triggered but not declared in emits.
  • TasksViewToolbar.vue: keyword-changed event triggered but not declared in emits.
  • TasksViewSwitcher.vue:103: prefer childNode.remove() over parentNode.removeChild(childNode).

All three go away if the <v-menu> simplification above is adopted (removes the manual DOM node teardown entirely) plus a one-line emits fix on the toolbar.

Checked and NOT a regression

  • .tasksToolbar (and its .taskDisplay/.taskTabBoard/.taskTabList/.taskTabGantt/.projectTasksViewTabs children) is removed from tasks.less — verified its only consumer was the v-tabs markup this PR itself replaces in TasksViewToolbar.vue, so no orphaned-class situation like the one from #623's original cleanup.
  • Dropping the resetFields('query') call from the keyword-change handler (so typing a search term no longer wipes the other active advanced filters) matches the behavior already shipped in the sibling TasksListToolbar.vue via #623 — consistent, not an accidental side effect of this rewrite.

Minor

  • <v-text-field v-model="keyword" ... @input="onKeyword">: v-model already assigns this.keyword on input; onKeyword reassigns the same value again before debouncing. Harmless, just redundant.

- TasksViewSwitcher: replace manual DOM-relocation dropdown (appendChild,
  getBoundingClientRect positioning, click/scroll listeners) with a plain
  v-menu, matching the AgendaSwitchView precedent this PR was modeled on.
  v-menu already escapes the kanban board's stacking context on its own.
- Declare emits (`change` on the switcher, `keyword-changed` on the
  toolbar) to fix the two Sonar-flagged undeclared-emit issues.
- Drop the now-dead absolute-positioning CSS this replaces; keep only the
  menu's min-width as a standalone rule (v-menu content isn't nested
  under .projectBoardToolbar).
- Remove the redundant this.keyword reassignment in onKeyword (v-model
  already sets it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@Jihed525

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review @boubaker — addressed all points in eea931c:

Main finding — TasksViewSwitcher reinvents <v-menu>
Replaced the manual DOM-relocation approach (appendChild to .v-application, getBoundingClientRect() positioning in positionMenu(), and the manual click/scroll listeners in mounted()/beforeDestroy()) with a plain <v-menu offset-y close-on-click>, structured exactly like AgendaSwitchView (activator slot wrapping the button, v-bind="attrs" v-on="on"). No more manual teardown, no more positionMenu/onScroll/onDocumentClick methods — v-menu already escapes the board's stacking context on its own, so the workaround wasn't needed.

Sonar's 3 new MAJOR issues

  • TasksViewSwitcher.vue: added emits: ['change'].
  • TasksViewToolbar.vue: added emits: ['keyword-changed'].
  • TasksViewSwitcher.vue:103 (parentNode.removeChild): gone entirely — there's no manual node teardown left now that v-menu owns its own content lifecycle.

Dead CSS
Removed .tasksViewSwitcher { position: relative; } and the absolute-positioning block on .tasksViewSwitcherMenu (position, top, inset-inline-end, z-index, transform: translateZ(0)) from tasks.less — none of it applies once v-menu (not application code) controls where/how the content is rendered. Kept only min-width: 160px on .tasksViewSwitcherMenu, now as a standalone top-level rule (Vuetify applies content-class to .v-menu__content, which isn't nested under .projectBoardToolbar).

Minor — redundant this.keyword reassignment
Removed the manual this.keyword = term in onKeyword(); v-model="keyword" on the v-text-field already sets it before @input fires.

Verified after the change: eslint clean on both touched files, and npx webpack --config webpack.prod.js --mode production still compiles with 0 errors (same pre-existing warnings elsewhere, unrelated to this PR).

@boubaker boubaker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Verified the fix commit (eea931c3) directly, not just the commit message:

  • TasksViewSwitcher.vue now uses a plain <v-menu v-model offset-y close-on-click> with an #activator slot, matching AgendaSwitchView's pattern exactly — all the manual DOM-relocation/positioning/listener code is gone.
  • emits: ['change'] / emits: ['keyword-changed'] added, clearing both Sonar-flagged undeclared-emit issues.
  • Dead CSS trimmed: .tasksViewSwitcher { position: relative } removed, .tasksViewSwitcherMenu reduced to a standalone min-width: 160px rule (correctly moved out of .projectBoardToolbar nesting, since v-menu's content is teleported and wouldn't match the old nested selector anymore).
  • onKeyword no longer redundantly reassigns this.keyword (v-model already does it) — confirmed the debounced $emit still reads the right value.

CI is green (PR Build, SonarCloud, Snyk) and SonarCloud's open-issue list for this PR is now empty.

Approving.

@Jihed525
Jihed525 merged commit ad0b7b4 into develop Jul 20, 2026
7 checks passed
@Jihed525
Jihed525 deleted the backport/EXO-88315-board-toolbar branch July 20, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

partialCIBuild Perform Partial CI Build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants