Commit Graph
930 Commits
Author SHA1 Message Date
Linus Rath 5a6c340f18 Merge pull request #1013 from lucamzanon/fix/cross-account-thread-key
fix: scope thread identity to the owning account in unified views
2026-09-21 22:33:26 +02:00
Linus Rath ec67ab994b feat: add missing mail action toasts and show sonner toasts again 2026-09-21 20:52:02 +02:00
Linus Rath b03a0c1dd9 feat: show "email sent" toast after immediate sends 2026-09-21 19:36:01 +02:00
Linus Rath 49af83b37a fix: keep staged attachment until upload finishes 2026-09-21 19:18:54 +02:00
Linus Rath 77ef60caae feat: resolve deep links to the local instance 2026-09-20 19:59:37 +02:00
Linus Rath d7548a4bab refactor: migrate icon set from Lucide to Tabler Icons 2026-09-19 13:32:41 +02:00
Linus Rath fdfcb1711e feat: add Bulwark Lite build for Stalwart Applications 2026-09-19 00:53:53 +02:00
Linus Rath 2d4a562432 fix: harden Bulwark Lite login, deep-link replay and settings gating 2026-09-18 22:16:57 +02:00
lucamzanon 5b63993bfe fix: scope thread identity to the owning account in unified views #1012
JMAP thread ids are only unique within their account - Stalwart hands out
per-account counters such as "b" - so the cross-account views merged
unrelated conversations that happened to share an id, and every
client-side thread map (expansion, cache, loading flag, counts,
virtualizer key) mixed them up the same way.

Give ThreadGroup an account-scoped `threadKey` derived from the email's
source stamps and key grouping and all thread state by it. `threadId`
stays the raw id for Thread/get, which #281 already routes to the owning
account. fetchThreadEmailCounts now asks each source account for its own
threads instead of one client for every id. Single-account views carry no
stamps, so their key is the bare id and nothing changes there.
2026-09-18 18:33:02 +02:00
Linus Rath 5de98bc04b feat: add Bulwark Lite static export build 2026-09-17 23:54:33 +02:00
Linus Rath f6ad8a5942 feat: add per-message HTML/plain-text toggle #1022 2026-09-17 22:34:20 +02:00
Linus Rath bd825fb19f Merge pull request #1034 from shukiv/fix/viewer-image-own-max-width
fix(viewer): stop stretching images that carry their own max-width
2026-09-17 22:03:32 +02:00
Linus Rath ee4763d5c0 Merge pull request #1036 from dealerweb/fix/calendar-principal-fetch
fix(calendar): stop the account principal fetch from failing on every load
2026-09-17 22:03:26 +02:00
Linus Rath 0cc1602933 Merge pull request #1037 from dealerweb/fix/mini-calendar-jump
fix(calendar): jump to the day picked in the mini calendar
2026-09-17 22:03:21 +02:00
Linus Rath 2e88a0c830 Merge main into fix/calendar-participants
Resolves the two conflicts in components/calendar/event-modal.tsx created
by #967 (RSVP controls), both keep-both:

- #967's canRsvp memo and #986's resolveContactName hook are both kept;
  they are independent and were simply inserted at the same point.
- #967's RsvpBar component is kept, and StatusBadge takes #986's
  signature ({ status, t }) since #986 drops the isOrganizer prop and
  updates both call sites to match.
2026-09-17 21:54:08 +02:00
Linus Rath e2f50cbb88 Merge pull request #967 from wrycu/fix/ui-rsvp
fix: rsvp controls
2026-09-17 21:49:38 +02:00
Linus Rath 9bc54a4ef6 fix: keep security headers on dotted app paths and neutralise cid: blobs (GHSA-xvjh-v9c6-qcvc) 2026-09-17 21:08:37 +02:00
dealerweb 464586d0c1 fix(calendar): jump to the day picked in the mini calendar
Since the freely scrolling views (#759) the day, week and month views are
positioned by their own focus rather than by the selected date, and a grid
click deliberately only marks a day that is already on screen. The mini
calendar shared that handler, so picking a day there highlighted it but
left the view where it was. Give it its own handler that jumps to the day
(keeping the mobile month-to-day switch), the same path the prev/next/today
controls and deep links use.
2026-09-15 12:44:36 +02:00
dealerweb bc5302568d fix(calendar): wait for the JMAP client before loading the account principal
The calendar loads the principal's alias addresses so an alias-organised
event is recognised as the user's own. The fetch fired on mount, but after
a page load the JMAP client is restored asynchronously: the call failed
with "Not authenticated" in the console, and the once-only guard then
blocked the retry for the rest of the session, leaving the aliases empty.

Move the logic into useAccountPrincipalEmails, which waits for the client
and fetches once, and cover the sequence with a hook test.
2026-09-15 12:44:36 +02:00
Shuki Vaknin 68341a0b69 fix(viewer): stop stretching images that carry their own max-width
The viewer forces `img { max-width: 100% !important }` onto every image.
That !important also beats a sender's *inline* max-width, which breaks the
common newsletter idiom of sizing an image with max-width + max-height +
width:100%:

  <img width="200" height="134"
       style="display:block; max-height:134px; max-width:200px; width:100%;">

With the sender's max-width:200px overridden, width:100% grows the image to
the full pane, while the max-height:134px it left alone still clamps the
height - so the picture renders squashed flat.

Measured on a real Namecheap renewal notice (hero asset 300x200, natural
ratio 1.50) rendered with the viewer's own stylesheet: the hero laid out
540x134, an aspect ratio of 4.03 - stretched 2.7x. Identical at a 390px
pane. With this change it lays out 200x133, ratio 1.50.

Only force the cap on images that declare no width of their own, exactly as
the table rule alongside it already does for the same reason (#790). height
keeps its !important, so an image with a fixed inline height (the far more
common `style="width:600px;height:400px"`) is unaffected - verified
unchanged at 600x400.

Images with no inline max-width are still capped at 100%, still with
!important, so an email's own stylesheet cannot escape the pane - an email
carrying `img { max-width: none }` still measures 710px, not 2000px. An
image whose inline max-width exceeds the pane now overflows into the body's
existing horizontal scroll rather than being silently distorted: the same
trade-off #790 accepted for tables, and fitEmailBodyWidth() still scales it
to fit on a phone.

Applied to all three paths that build an email document: the reading pane,
the thread conversation cards, and the print view.

Claude-Session: https://claude.ai/code/session_019KwXZEwxijHRbfobfXmcK2
2026-09-14 20:49:04 +03:00
Linus Rath d6c923f20e Merge pull request #947 from shukiv/feat/list-attachment-chips
feat(list): show attachments on list rows and open them from there
2026-09-11 17:05:08 +02:00
Linus Rath 60b3d86004 Merge pull request #1005 from dealerweb/fix/hide-body-referenced-cid-parts
fix: hide body-embedded cid parts declared as octet-stream from the attachment list
2026-09-11 11:59:32 +02:00
Linus Rath 0b704f61e0 Merge pull request #1008 from Almost-Senseless-Coder/fix/list-label-accessibility
fix(a11y): Improved accessibility of the email list
2026-09-11 11:59:14 +02:00
dealerweb 1c00812ab7 fix: hide body-embedded cid parts declared as octet-stream from the attachment list
Some senders ship the images their HTML body embeds via cid: as
application/octet-stream with no Content-Disposition and no filename.
The body rendered them fine, but the "hide inline images" check only
recognised parts declared inline with an image/* type, so they also
showed up as nameless "Attachment" chips next to the real files.

Both viewers now scan the HTML they actually render for cid: references
(the same pattern the renderer rewrites to blob URLs) and hide a
referenced part when it is an image or generically typed. An explicit
attachment disposition always keeps its chip, as does a referenced part
with a real non-image type, since that chip is its only download. Plain
text rendering references nothing, so nothing is hidden there. The
shared rule lives in lib/attachment-visibility.ts so the desktop viewer,
the thread view and the decrypted-message path cannot drift apart.
2026-09-10 10:45:45 +02:00
Linus Rath fb24ef5d24 feat: sort contacts by last name #963 2026-09-09 19:47:33 +02:00
Almost-Senseless-Coder 4947c6c7a4 Improved accessibility of the email list 2026-09-09 19:37:43 +02:00
Linus Rath 565d5c1095 feat: choose exact-address or same-domain matching for reply from received address #1000 2026-09-09 19:27:08 +02:00
Linus Rath 9796b0b14d fix: index newer settings and flat calendar toggles in the settings search 2026-09-09 18:40:15 +02:00
Linus Rath ae403b06af feat: setting to turn off free scrolling in the calendar 2026-09-09 18:27:01 +02:00
Linus Rath 15a5497a12 feat: freely scrolling month, week and day views #759 2026-09-09 16:38:55 +02:00
Linus Rath 60e05c0041 feat: infinite scroll for the calendar agenda view 2026-09-09 15:19:53 +02:00
Linus Rath 4a057b2348 Merge pull request #990 from rotterp/fix/pro-compose-from-account
fix(pro): default the compose tab's From to the open mailbox
2026-09-07 22:39:04 +02:00
Linus Rath 26358c7a63 Merge pull request #991 from rotterp/fix/shared-mailbox-send-identity
fix(composer): send from the address a message was delivered to
2026-09-07 22:38:51 +02:00
Linus Rath 049a1a1292 Merge pull request #663 from shukiv/fix/read-view-auto-direction
fix(rtl): auto-detect text direction in read, print and plain-text views
2026-09-07 22:36:25 +02:00
Linus Rath f349500546 fix: preserve task alarms that the edit dialog does not show #504 2026-09-07 22:34:47 +02:00
Linus Rath 80dadfbbd4 fix: open search hits from shared folders in the right account #923 2026-09-07 22:34:47 +02:00
Linus Rath 8477acf217 fix: keep the mobile actions panel below the status bar #936 2026-09-07 22:34:47 +02:00
Linus Rath d28d8dcd86 fix: report calendar clear failures instead of counting zero #434 2026-09-07 22:34:47 +02:00
Linus Rath f3f0127c9d fix: only show the unified mailbox section when it can be populated #843 2026-09-07 22:34:47 +02:00
Linus Rath 07bbde4786 fix: make the iCal subscription size limit configurable and show the real error #692 2026-09-07 22:34:47 +02:00
Linus Rath 8e4296ae5b fix: add the missing scheduled folder role label #495 2026-09-07 22:34:47 +02:00
Linus Rath 12416d9c47 fix: wire the x shortcut to thread expansion #683 2026-09-07 22:34:47 +02:00
Linus Rath f4d2fd950c fix: sort folders in the role assignment dropdown #984 2026-09-07 22:34:47 +02:00
Linus Rath c633ce1ff4 fix: keep the reading-mode toggle mounted so toolbar buttons stop jumping #964 2026-09-07 22:34:47 +02:00
Linus Rath ab4bf91b20 fix: let sender tables keep their own max-width #790 2026-09-07 22:34:47 +02:00
Linus Rath b85ba9603d fix: upload composer attachments through the composing identity's account #943 2026-09-07 22:34:47 +02:00
Linus Rath 0efde2e61d fix: set the answered flag when the reply is sent with a delay #985 2026-09-07 22:34:47 +02:00
Linus Rath 8dc1564b72 fix: archive shared-inbox mail into the owner's archive #889 2026-09-07 22:34:47 +02:00
Linus Rath 2b32a0110b fix: report a missing archive mailbox instead of failing silently #578 2026-09-07 22:34:47 +02:00
Shuki VakninandClaude Opus 5 e2990da554 fix(rtl): auto-detect direction in the thread view and .eml preview
The same missing dir="auto" as the read view, in the two other places
that build an email document.

thread-conversation-view builds a full document for each card's iframe
and its <body> had no direction, so a thread of right-to-left mail read
left-to-right in the one view that shows several messages at once.

eml-preview hands srcDoc a fragment rather than a document, so the
<body> is the browser's implicit one and cannot be annotated at all.
The wrapper the fragment already needs carries dir="auto" instead: a
<div> around sanitized HTML, and the existing <pre> for plain text.
Neither changes layout - the implicit body and its default margin stay
exactly as they were.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019KwXZEwxijHRbfobfXmcK2
2026-09-07 22:37:17 +03:00