Skip to content

[OP-20110] Anchor the popover on the visible entry - #25124

Open
myabc wants to merge 2 commits into
bug/op-19358-popover-values-verbatimfrom
bug/op-20110-clipped-entry-popover
Open

[OP-20110] Anchor the popover on the visible entry#25124
myabc wants to merge 2 commits into
bug/op-19358-popover-values-verbatimfrom
bug/op-20110-clipped-entry-popover

Conversation

@myabc

@myabc myabc commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Note

Stacked on #25123 (OP-19358). Only the last two commits belong to this PR.

Ticket

https://community.openproject.org/wp/OP-20110

What are you trying to accomplish?

The "My spent time" calendar scrolls horizontally, but its entry popover was anchored on the entry's full box. For an entry partly hidden behind the widget's right edge the popover opened beside the hidden part, floating over the neighbouring widget with its caret pointing into the clipped area, and it stayed there when the calendar scrolled.

Screenshots

My spent time widget

Before After
Popover of a clipped entry floating beside its hidden part, before the fix Popover anchored on the visible part of the clipped entry, after the fix

Project timeline widget

Screenshot 2026-09-03 at 22 00 04

What approach did you choose and why?

Two small helpers next to the shared placement in anchored-popover/:

  • visibleRect(element) clips the element's rect by the padding boxes of its overflow ancestors, so borders and scrollbars do not count as visible. Transforms, clip-path and shadow boundaries are out of scope; both intended callers are plain light-DOM descendants of their scrollers.
  • liveRect(source) wraps that in a DOMRect proxy that re-reads the source on every access. Primer's getAnchoredPosition reads a non-element anchor as the rect itself, so its own updates (window scroll, resize, its ResizeObserver) never see a stale box.

The calendar anchors the popover on liveRect(() => visibleRect(entry)) and re-places the open popover on any scroll (one capture-phase listener per component, so the calendar's own scroller is covered as well as the page). Repositioning rather than closing matters for keyboard users: focusing a clipped entry scrolls it into view, and the popover follows instead of vanishing. This also removes the "caret stale after page scroll" limitation noted in #25112.

Scope, as agreed on the work package: the caret and anchor target the visible slice of the entry. The popover itself may still extend past the widget edge, as any popover on the last visible column does; flipping it into the widget (option 2 on the work package) was left out.

The project timeline widget's tooltip had the same exposure for items half hidden by the timeline's centre panel, so its second commit anchors that tooltip on the same live visible rect. It keeps closing on scroll, as it is hover-only.

Merge checklist

  • Added/updated tests (visible-rect.spec.ts, te-calendar.component.spec.ts and project-timeline-tooltip.popover.spec.ts also in Firefox and WebKit)
  • Added/updated documentation in Lookbook (patterns, previews, etc)
  • Tested major browsers (Chrome, Firefox, Edge, ...)

@myabc
myabc requested a lite review from Copilot September 3, 2026 20:19
@myabc myabc added needs review javascript Pull requests that update Javascript code labels Sep 3, 2026
@myabc myabc added this to the 17.9.x milestone Sep 3, 2026
@myabc myabc added the bugfix label Sep 3, 2026

Copilot AI left a comment

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.

🟡 Changes recommended

Popover repositioning state (placeOpenPopover) can get out of sync when the popover="hint" element toggles via native interactions (e.g., Escape/light-dismiss), so it should be synchronized via the popover’s toggle event.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR improves the “My spent time” calendar entry popover positioning by anchoring it to the visible portion of a horizontally clipped entry and keeping the popover correctly positioned while scrolling.

Changes:

  • Added visibleRect() to compute the visible slice of an element by clipping its bounding rect to overflow ancestors’ padding boxes.
  • Added liveRect() to provide a DOMRect-compatible, live-updating rect source for anchoring.
  • Updated the time entry calendar popover to anchor to liveRect(() => visibleRect(entryEl)) and to re-place an open popover on scroll; added unit tests for the new helpers and calendar behavior.
File summaries
File Description
frontend/src/app/shared/components/anchored-popover/visible-rect.ts New helper computing the visible (clipped) rectangle of an element.
frontend/src/app/shared/components/anchored-popover/visible-rect.spec.ts Unit tests validating clipping behavior across scroll/border/scrollbar cases.
frontend/src/app/shared/components/anchored-popover/live-rect.ts New helper providing a live-updating DOMRect proxy for anchoring.
frontend/src/app/shared/components/anchored-popover/live-rect.spec.ts Unit tests verifying live reads and integration with popover placement.
frontend/src/app/features/calendar/te-calendar/te-calendar.component.ts Uses visibleRect+liveRect for anchoring and repositions an open popover on scroll.
frontend/src/app/features/calendar/te-calendar/te-calendar.component.spec.ts Integration-style tests covering clipped-entry anchoring and scroll-follow behavior.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread frontend/src/app/features/calendar/te-calendar/te-calendar.component.ts Outdated
@myabc
myabc force-pushed the bug/op-20110-clipped-entry-popover branch from 5d9314d to e69d2d5 Compare September 3, 2026 20:46
@myabc
myabc marked this pull request as ready for review September 3, 2026 20:48
The widget calendar scrolls horizontally, but the popover was anchored
on the entry's full box, so for an entry half hidden behind the scroller
edge it opened beside the hidden part with its caret pointing into it,
and it stayed there when the calendar scrolled.

Anchors on the entry's rect clipped by its overflow ancestors' padding
boxes, handed to Primer as a live rect so its own updates never read a
stale box, and re-places the open popover on any scroll, which also
keeps it beside an entry that focus scrolls into view.

https://community.openproject.org/wp/OP-20110
vis-timeline hides items that scroll past its centre panel, so a tooltip
on a half-hidden item opened beside the hidden part. Uses the calendar's
live visible rect for the anchor as well.
@myabc
myabc force-pushed the bug/op-20110-clipped-entry-popover branch from a6ac69c to cf0678a Compare September 4, 2026 08:33
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]
🤖 Ask Copilot to investigate

Copy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer.

@copilot The following spec(s) are flaky in CI (first seen on PR #25124, linked for reference only):

- `rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]`

Treat this as a standalone task, unrelated to PR #25124. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #25124 or reuse that branch.

Follow the playbook in docs/development/testing/handling-flaky-tests/README.md to find the root cause and fix the underlying race — do not skip, delete, or weaken the spec to make it pass; disabling is a last resort per the playbook, and only with a bug ticket. Verify the fix by running the spec(s) repeatedly (e.g. `script/bulk_run_rspec --run-count 10`).

If you cannot reproduce the flake or are not confident in a fix after reasonable investigation, do not fabricate a change or skip the spec to force CI green. Instead, leave the pull request in draft and document what you tried, the suspected cause, and any leads in its description, then assign @myabc to take over.

Once the fix is verified, title the PR after the spec(s) it fixes, and use the PR description to explain the root cause, how the change resolves it, and the before/after results. Label the PR `flaky-spec`, assign @myabc, and request a review from @myabc.
On every commit, set @myabc as the sole co-author with a `Co-authored-by:` trailer (use their GitHub no-reply email so it links to their account), so it is traceable who dispatched the fix.

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

Labels

bugfix javascript Pull requests that update Javascript code needs review

Development

Successfully merging this pull request may close these issues.

2 participants