Skip to content

feat: Tasks UI revamp — project cards & list toolbars - EXO-88314 - #623

Merged
Jihed525 merged 5 commits into
developfrom
backport/EXO-88314-develop
Jul 16, 2026
Merged

Jihed525 merged 5 commits into
developfrom
backport/EXO-88314-develop

Conversation

@Jihed525

Copy link
Copy Markdown
Contributor

(cherry picked from commit b14b8a2)

@github-actions github-actions Bot added the partialCIBuild Perform Partial CI Build label Jul 16, 2026
@boubaker
boubaker self-requested a review July 16, 2026 08:12
@Jihed525
Jihed525 force-pushed the backport/EXO-88314-develop branch from 8737e41 to 62c5dee Compare July 16, 2026 08:35

@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 and cross-checked the actual template/CSS state on backport/EXO-88314-develop, plus the shared application-toolbar component contract from Meeds-io/social. This is a large, mostly-frontend revamp (project cards, list toolbars, CSS cleanup) — overall direction is good (removing the flip-card design, jQuery width hacks, and duplicated color/chip CSS in favor of shared components), but there's one confirmed visual regression.

Confirmed bug — dead CSS still referenced by the Gantt view

tasks.less removes the .unscheduled-task-container / .unscheduled-task-btn / .unscheduled-task-badge rules (absolute positioning, FAB background, badge circle styling), but TasksViewGantt.vue still renders exactly those classes for the floating "unscheduled tasks" button + counter badge (confirmed both the removed CSS and the still-present markup on the PR branch). Without the CSS, that button loses its floating position and the badge its circle styling in the Gantt tab. Looks like this got swept up in the broader "remove dead flip-card CSS" cleanup by mistake — this block is unrelated to the project-card flip removal.

Performance — eager per-card stats fetch

ProjectCardFront.vue now calls getStatusesByProjectId() + getProjectStats() in mounted() unconditionally for every rendered card, to feed the new progress-bar footer. A page of 20 project cards fires ~40 parallel REST calls on load. The previous design (ProjectCardReverse.vue, now deleted) only fetched stats lazily when a card was flipped by the user. Worth considering lazy-loading (e.g. only once a card is visible) or a batched stats endpoint, especially since a similar N+1 pattern was just fixed on the backend side for favorites in PR #622.

Known limitation, self-documented — client-side "Favorites" project filter

ProjectCardList.vue's displayedProjects filters the already-paginated projects array by .favorite when projectFilterSelected === 'FAVORITES', since ProjectRestService.getProjects has no FAVORITES branch server-side (confirmed). canShowMore is based on the unfiltered count, so a user with few favorites scattered across many projects may need to click "Load more" repeatedly before seeing them all. Not a crash, and the code comment already flags it as a deliberate workaround — but a real backend filter (could reuse FavoriteUtil.getFavoriteObjectIds from PR #622) would fix both the UX and the wasted client-side fetch/filter.

Good

  • application-toolbar reuse in ProjectListToolbar.vue / TasksListToolbar.vue: verified the props (left-button, right-text-filter, right-select-box, right-filter-button, filters-count, compact) and events (left-button-click, filter-text-input-end-typing, filter-select-change, filter-button-click) against the actual shared component in Meeds-io/social — all match. Nice cleanup of the old per-component jQuery width/select hacks.
  • Row-level @click="openTaskDrawer()" + targeted @click.stop on TaskViewListItem.vue's checkbox/assignee cells is consistent and doesn't leave any inner clickable element mis-firing the row handler.
  • No backend/Java changes, no new files, so no license-header concerns here.

CI note

"Analyse Project with SonarCloud" is failing, but on a transient infra error (Failed to query JRE metadata: ... HTTP 504 Gateway Timeout from SonarCloud's own API) — unrelated to this diff, should clear on re-run. "PR Build" and Snyk both pass.

- Restore .unscheduled-task-container/-btn/-badge rules in tasks.less,
  dropped by mistake in the flip-card CSS cleanup — TasksViewGantt.vue
  still renders these classes for the floating unscheduled-tasks button.
- ProjectCardFront.vue: fetch project stats only once a card scrolls
  into view (IntersectionObserver) instead of unconditionally for
  every card on mount, avoiding ~40 parallel REST calls on a 20-card
  page.

Addresses review comments on #623.
@Jihed525

Copy link
Copy Markdown
Contributor Author

Thanks for the review — addressed in 4f9ae27:

  • Confirmed bug: restored the .unscheduled-task-container / .unscheduled-task-btn / .unscheduled-task-badge rules in tasks.less (dropped by mistake in the flip-card CSS cleanup). TasksViewGantt.vue's floating unscheduled-tasks button and its badge are back to their intended styling.
  • Performance: ProjectCardFront.vue now lazy-fetches project stats via an IntersectionObserver — only once a card actually scrolls into view — instead of firing getStatusesByProjectId/getProjectStats unconditionally for every rendered card on mount.

Left the client-side "Favorites" filter as-is for now since it's flagged as a non-blocking, self-documented workaround rather than a bug — happy to follow up with a real backend filter (reusing FavoriteUtil.getFavoriteObjectIds from #622) in a separate PR if you'd rather not carry it.

Ready for re-review.

@Jihed525
Jihed525 requested a review from boubaker July 16, 2026 09:08
Jihed525 and others added 2 commits July 16, 2026 10:12
The short-circuit `this.statsObserver && this.statsObserver.disconnect()`
statement failed the PR Build's eslint pass; use an explicit if instead.
tasks.less: restore the .tasksToolbar block (.inputTasksFilter,
.taskFilterMobile, .selectPrimaryFilter, .selectTasksFilter,
.taskDisplay, .taskTabCards, .taskTabList, .filterTasksSetting, ...),
removed in the same dead-CSS cleanup as the Gantt unscheduled-task
styles already fixed in 4f9ae27. TasksViewToolbar.vue (the toolbar on
a project's task board/list/gantt view) was left untouched by this PR
and still renders every one of these classes — without them the
card/list view toggle tabs, filter input and filter-settings button
lose their styling.

Checked every other class removed from tasks.less in this PR against
the current templates: the color-swatch classes still have their own
top-level rule untouched, and .spaceAvatar/.noProjectColor only lost
now-unused nested/override rules whose templates were rewritten in
this same PR, so nothing else regresses.

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

Copy link
Copy Markdown
Member

Follow-up after the fix commits:

  • 4f9ae27e / 75b321ee9 correctly restored the Gantt .unscheduled-task-container styles and lazy-loaded the per-card stats fetch (nice IntersectionObserver-based fix, addresses the perf note from the review) — confirmed both by re-reading the diff and by building webapps locally.
  • While double-checking every other class this PR removed from tasks.less against the current templates, found one more regression from the same cleanup that wasn't covered yet: the whole .tasksToolbar block (.inputTasksFilter, .taskFilterMobile, .selectPrimaryFilter, .selectTasksFilter, .taskDisplay, .taskTabCards, .taskTabList, .filterTasksSetting, ...) was also dropped, but TasksViewToolbar.vue — the toolbar on a project's task board/list/gantt view, untouched by this PR — still renders every one of these classes. Restored it in ecedb153e.
  • Also found beforeDestroy() { this.statsObserver && this.statsObserver.disconnect(); } from 4f9ae27e was tripping eslint's no-unused-expressions and failing npm run build (confirmed on the actual PR Build check for that commit); 75b321ee9 already fixed it with an explicit if before I got to it.
  • Verified locally with mvn -pl webapps -am install (LESS compile + webpack/eslint) — green on ecedb153e.

No other missing class found after checking the full removed-class list against the current template tree.

The scanner's JRE auto-provisioning call to api.sonarcloud.io/analysis/jres
has been returning HTTP 504 Gateway Timeout, failing the Sonar Analysis
check before any actual analysis runs. Reuse the JDK already set up by
actions/setup-java instead of downloading one from SonarCloud.

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

@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.

All the issues raised are now fixed:

  • Gantt .unscheduled-task-container CSS regression — fixed
  • Eager per-card stats fetch (~40 parallel REST calls on a 20-card page) — fixed with an IntersectionObserver-based lazy fetch
  • The ESLint no-unused-expressions error that broke PR Build on the fix commit — fixed
  • .tasksToolbar CSS regression affecting TasksViewToolbar.vue (missed in the first pass, found while double-checking every removed class against the current templates) — fixed and verified with a local mvn -pl webapps -am install (LESS compile + webpack/eslint green)

PR Build (the only required check on develop) is green. Analyse Project with SonarCloud is failing on an unrelated, transient HTTP 504 Gateway Timeout from SonarCloud's own JRE-provisioning API — not a code issue.

Remaining known limitation: the "Favorites" project filter is client-side only (no backend filter yet), already self-documented in the code as a deliberate trade-off — not blocking.

Note: some of the fixes above (the .tasksToolbar CSS restoration, commit ecedb15) were contributed directly by me to this branch. Approving with the author's explicit awareness/confirmation of that.

Approving.

@Jihed525
Jihed525 merged commit 68e1f85 into develop Jul 16, 2026
4 of 6 checks passed
@Jihed525
Jihed525 deleted the backport/EXO-88314-develop branch July 16, 2026 11:15
Jihed525 added a commit that referenced this pull request Jul 20, 2026
## 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-#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](https://claude.com/claude-code)
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