fix(mail): two attachment clicks that did nothing and said nothing

Both are in the message view, and neither left a trace anywhere.

The download link was a plain same-origin anchor, so Turbo Drive intercepted the
click, fetched the URL itself and dropped the response for not being HTML. The
request went out, the app answered 200 with the file, the access log looked
perfect, and the browser saved nothing — no console error, no exception, no
failed request to find. `download` is what tells Turbo to leave a link to the
browser; the backup export, the ICS subscribe link and the appearance export all
already carry it for exactly this reason, and these two call sites were missed.
The draft attachment list had the same link and the same silence.

"Save to…" opened a menu positioned `top-full` against an element carrying
`overflow-hidden` — the clipping that rounds the chip's two halves inside one
border. The menu opens below that box, so it was clipped away entirely: it had
a bounding rect and no paint, and hit-testing at its own centre found whatever
happened to be behind it. Clipping now belongs to an inner box and positioning
to the outer one, which is the only arrangement where both are true at once.

The spec covering save-to passed throughout, which is the more useful half of
this: toBeVisible() is satisfied by a rect, and Playwright clicks at coordinates
rather than at what a person can reach, so a menu painted nowhere tested exactly
like a menu on screen. Both specs now assert what someone would actually notice
— a download event carrying the right filename and bytes, and a menu whose own
centre hit-tests to itself — plus the POST that the save reaches the server
with. The upload beyond that boundary is not proven here: the test stack's
Nextcloud is unreachable by design, so what is pinned is that the click gets
out and that the answer gets back to the reader.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul LütznerandClaude Fable 5 committed 2026-08-11 13:06:44 +02:00
1 parent 6e7bf67ad0
commit 917a508566
5 files changed
+122 -12

No files matched your search

+4
View File
@@ -16,7 +16,11 @@ Variables: message
<span class="inline-flex items-center gap-2 pl-2.5 pr-1.5 py-1 rounded-lg text-xs
bg-sunken border border-line text-ink-soft">
<i class="fa-solid fa-paperclip text-[10px] text-ink-faint" aria-hidden="true"></i>
{# `download` for the same reason as in mail/_attachment_chip:
without it Turbo intercepts the click and throws the file
away, and the link does nothing at all. #}
<a href="{{ path('app_mail_attachment', { id: part.id }) }}?download=1"
download="{{ part.filename ?: 'attachment' }}"
class="truncate max-w-[11rem] hover:text-accent transition-colors">
{{- part.filename ?: 'attachment' -}}
</a>