Commit Graph
457 Commits
Author SHA1 Message Date
Linus Rath 7c21b0d0f9 Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-10-11 18:59:34 +02:00
Linus Rath 9dc0f9c892 fix: label the composer toolbar buttons and group send options in a menu 2026-10-11 18:58:26 +02:00
Linus Rath 3efa370e42 fix: split typed addresses on commas and stop sends to invalid addresses 2026-10-11 18:55:46 +02:00
Linus Rath 50771cd082 fix: close the composer after a plugin send and keep the draft when it fails #1207 2026-10-11 17:44:26 +02:00
Linus Rath 1adb78db6a fix: translate the forward-unavailable notice in filter rules #1208 2026-10-11 17:31:22 +02:00
Linus Rath 44bfb7ebfd fix: translate the new Files app strings and label the picker root My files 2026-10-11 17:29:30 +02:00
Linus Rath 5877b31879 fix: hide forward in filter rules when the server allows no redirects #1208 2026-10-11 17:28:20 +02:00
Linus Rath 93969a1371 fix: show a live sample on every date format and region option 2026-10-11 17:09:55 +02:00
Linus Rath efefbd1358 fix: show the resolved date format on the automatic region option 2026-10-11 17:04:19 +02:00
Linus Rath 958aa500b8 feat(files): add right-click menus to My files, folders, starred and recent in the sidebar 2026-10-11 16:50:08 +02:00
Linus Rath e60840c0e6 fix(files): say the upload was canceled instead of counting it as done
Cancelling an upload ended the loop like a normal finish, and the Files
app then reported every picked file as uploaded. Uploads now return how
many files went up and whether they were cancelled, so a cancel shows
"Upload canceled" (with the count of files that made it, if any).

Folder uploads also passed no cancel signal or progress callback to the
blob upload, so Cancel did not stop the file in flight and the progress
line stood still; they now behave like file uploads.
2026-10-11 16:40:32 +02:00
Linus Rath cd5fe770e4 feat: show file uploads as a toast like every other notice
Uploads in Files had their own card with a thick progress bar, larger
corners and a heavier shadow, so they looked unlike the toasts around
them.

Toasts can now show work in progress: the thin line at the bottom fills
with progress instead of counting down, and the toast stays until it is
updated or removed. Uploads use it, with the file and percentage below
the title and Cancel as the toast action.
2026-10-11 16:38:05 +02:00
Linus Rath 87915f8bf1 feat(files): zoom and pan images in the preview, close by clicking beside them
The image viewer only zoomed with its buttons, scaled the image inside
a fixed box so a zoomed image could not be moved, and the area around
the image swallowed clicks, so clicking beside it did nothing.

Both the Files image viewer and the attachment preview now use one
viewer that:

- zooms with the wheel, trackpad or two-finger pinch, centred on the
  pointer, and with a zoom bar at the bottom (-, percentage, +, fit,
  rotate)
- toggles between fit and full size on double-click or double-tap
- pans by dragging, or with the arrow keys, while zoomed
- closes on a click or tap beside the image, but not after a drag
- keeps + / - / 0 / r as shortcuts and Escape to close
2026-10-11 16:32:51 +02:00
Linus Rath d07939fc04 feat(files): drop the large file upload warning 2026-10-11 16:25:11 +02:00
Linus Rath 4ba39cef0e feat(files): rework the Files app layout and interactions
The Files app had two layouts (folders inline or in a tree), a back bar
and a permanent warning above the list, a toolbar of ten unlabelled
icons, and a Recent list whose entries did nothing. In the tree layout
folders could not be renamed or deleted at all, and the default view,
default sort and hidden-files settings were ignored.

It now follows the contacts and calendar layout:

- a full-height sidebar with a "+" New menu, My files with the folder
  tree, Starred, Recent and Shared with me; folders accept dropped items
- a header with collapsing breadcrumbs (also drop targets), search, sort,
  list/grid switch and a details toggle; selecting items swaps it for an
  action bar
- list rows open from the name and select from the row, with hover
  actions; the grid shows folders as chips and files as cards with
  lazy, cached thumbnails
- a details panel for the selection or the current folder, empty-folder
  and no-results states, a floating upload card, a dismissible
  stability warning, and keyboard navigation with the arrow keys
- touch: tap opens, long-press selects, a "+" button in narrow panes

The tree is built from the listing the store already fetches instead of
one full fetch per folder, so it is current after every change. Recent
files open in their folder, and the settings for view, sort, hidden
files and icons now apply. The inline/sidebar setting is gone.
2026-10-11 16:23:19 +02:00
Linus Rath 6d9bd1e4d0 Merge remote-tracking branch 'origin/main' 2026-10-10 23:20:25 +02:00
Linus Rath d5ce67e167 feat(calendar): create events from a quick editor next to the clicked slot
Clicking or dragging over empty time in the week or day view used to
open the full event panel. On wide screens it now draws the new event
at that spot as a "(No title)" block and opens a small editor beside
it with a title field, the picked time, a calendar picker, Save and
"More options". More options carries the title, time and calendar
over into the full editor. Enter saves, Escape or a click elsewhere
discards. Phones keep opening the full editor.

The placeholder for an event being created is now drawn like a saved
event, in the calendar's colour, instead of a dashed outline.
2026-10-10 22:57:37 +02:00
Linus Rath 90b1db0432 feat(calendar): fold calendar lists and show options on hover in the sidebar
The calendar list in the sidebar now works like Google Calendar's:
- "My calendars" and a new "Other calendars" section (shared
  calendars, still grouped by owner) fold away, and stay folded
- each calendar has a checkbox filled in its colour with a check mark
- hovering a calendar shows an options button that opens the same
  menu as a right-click

In the mini month, today is the filled circle and the selected day is
tinted, so the two no longer look alike.
2026-10-10 22:34:35 +02:00
Linus Rath beda42a500 refactor(calendar): keep the webmail's own buttons in the new calendar bar
The previous commit copied Google Calendar's look along with its
layout. The bar and the sidebar now use the webmail's regular buttons,
sizes and title style again; only the arrangement stays: menu button,
Today and arrows with the title, the view menu on the right and the
create button at the top of the sidebar.
2026-10-10 22:30:56 +02:00
Linus Rath b5373bd528 feat(calendar): move the calendar bar above the sidebar like google calendar
The bar now spans the sidebar and the grid. It starts with a menu
button that hides or shows the sidebar (remembered across visits),
then a pill Today button, the arrows and a large period title. On
the right a view menu lists Day, Week, Month and Agenda (and Tasks)
with their shortcut keys, and import and subscribe moved into a
"more actions" menu instead of a button of their own.

The Create button moved to the top of the sidebar. While the sidebar
is hidden or an overlay, a compact create button sits in the bar.
2026-10-10 22:28:38 +02:00
Linus Rath 02923fc1f1 Merge pull request #1054 from lucamzanon/feat/multi-account-push
feat: enable push notifications for several accounts at once
2026-10-10 19:24:10 +02:00
Linus Rath 4af42858f0 Merge pull request #1168 from lucamzanon/feat/mountain-view-layout
feat: add Mountain View, an optional alternative layout
2026-10-10 19:23:59 +02:00
lucamzanon 9560a8b74f feat: optional encrypted backup of the account list
Users with several accounts can save the list of accounts in their browser
(address, server, label, colour) on the webmail server and bring it back on
another device. The list is encrypted in the browser with a password the user
chooses (PBKDF2-SHA-256, 600,000 iterations, AES-256-GCM, owner bound as
additional data); the server stores only the envelope, one file per owner
under SETTINGS_DATA_DIR/account-archives. No mailbox passwords are included.

Off by default behind the admin feature gate accountArchiveEnabled, pinned
off in Lite. Every method of /api/account-archive needs a session cookie of
the owner, matched without regard to case, whose credential is checked
against the mail server on each call; listing included.

Restored accounts this browser lacks are listed as awaiting sign-in: they
survive a reload, and opening one leads to the sign-in form with the address
filled in. Accounts already present get their archived label and colour.
2026-10-09 10:54:38 +02:00
lucamzanon ade30622f2 Merge remote-tracking branch 'origin/main' into up/feat/mountain-view-layout
# Conflicts:
#	components/mail/mail-app.tsx
2026-10-08 10:05:29 +02:00
Linus Rath eb84810f1e fix: translate the unverified sender warning into all languages 2026-10-07 20:06:35 +02:00
Linus Rath 8889346371 feat: warn when a message's sender can't be verified 2026-10-07 19:04:15 +02:00
Linus Rath ccf6bf7706 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	locales/cs/common.json
2026-10-07 01:03:34 +02:00
Linus Rath 8cc53e63d9 chore: translate files picker and bulk folder move strings 2026-10-07 01:02:20 +02:00
Linus Rath cbfcdf3b69 Merge pull request #1152 from dealerweb/feat/rule-periods-out-of-office
feat: out of office forwarding and recipients, filter rule periods
2026-10-06 23:28:58 +02:00
Linus Rath 3cb5482825 Merge pull request #1174 from cybersmurf/fix/czech-translations
fix(i18n): translate the remaining English strings in the Czech locale
2026-10-06 23:28:53 +02:00
Linus Rath 1aefeedf4f Merge pull request #1165 from owgreen-dev/fix/i18n-placeholders-fa-he-hu-mn-sk
fix(i18n): restore dropped and renamed placeholders in fa, he, hu, mn and sk
2026-10-06 23:28:52 +02:00
Linus Rath 1e10aa9bd6 feat: move several folders at once from the folder settings #1173 2026-10-06 15:49:53 +02:00
Linus Rath 92f1973bcc feat: attach files from the Files app in the composer #1179 2026-10-06 15:18:58 +02:00
sudandClaude Fable 5.1 7ebdf1db99 fix(i18n): translate the remaining English strings in the Czech locale
Forty strings in locales/cs/common.json were still identical to English:
removing an account, tinting list rows, the date-format region and time
zone settings, inbox-only notifications, cache refresh, file sharing,
contact groups, and a few folder roles and labels. Placeholders are
unchanged and the file keeps its CRLF line endings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 06:20:23 +02:00
lucamzanon d632956231 feat: add Mountain View, an optional alternative layout
Add an "Interface layout" setting at the top of Settings > Layout with two
options, Default and Mountain View. Default is the existing layout and stays
the default, so nothing changes unless a user opts in.

Mountain View rearranges the chrome while keeping the theme's colours, icons
and type:

- desktop: a top bar with a wide search field (filters drop from the field),
  an apps grid and the account avatar instead of the left app rail; flat
  navigation with Starred under Inbox and the rest behind "More"; a Compose
  pill; one list toolbar with select-all, refresh, overflow menu, a 1-N of
  total range and the batch actions; rows led by a checkbox and a star; an
  icon-only message toolbar with Reply / Reply all / Forward under the
  message; compose in a docked window; an account popover with per-account
  unread counts; j/k cursor, x to select and g-sequences
- phone: rounded search header, compact rows with the star on the preview
  line, and Reply / Reply all / Forward at the end of a message instead of
  the bottom action bar

It is one setting (`interfaceLayout`), written to a data attribute on <html>
that keys a block of CSS tokens in globals.css, plus a few components gated
on the flag. The mail layout in force is derived (effectiveMailLayout), so
the user's saved mail layout is never rewritten. The setting is listed in
the admin policy tab, and the new strings are translated in all locales.

Includes unit tests and a Playwright smoke test against a running instance
(scripts/mountain-view-smoke/).
2026-10-05 10:36:20 +02:00
owgreen-dev 6025da0388 fix(i18n): restore dropped and renamed placeholders in fa, he, hu, mn and sk
- hu: {elválasztó} → {delimiter} (3 strings)
- mn: {from}/{to} → {before}/{after}; account email/server/last-sync values
  held the label text instead of {email}/{server}/{time}; user+tag → user{delimiter}tag (2)
- he: user+tag → user{delimiter}tag, with the missing spaces around the address
- fa, sk: descriptions were cut short and lost {delimiter}, {appName},
  {filename} and {ext}; completed them
2026-10-03 11:40:11 -04:00
Linus Rath 0b4d0b0f3c feat: limit the day and week views to working hours and days #1164 2026-10-02 22:56:16 +02:00
Linus Rath 0e39b199a1 feat: link the running build's source from the About card #1161 2026-10-02 22:10:29 +02:00
Linus Rath 1c1bfb0ce8 fix: explain a refused token exchange instead of asking for Basic auth on a TOTP login
When Stalwart accepted the password and code but refused to issue
tokens (in Lite: `invalid_client` for an OAuth client with a secret),
login retried `password$totp` over Basic. Stalwart 0.16+ rejects that, so
the browser showed its own Basic-auth dialog and the login page then
reported a wrong code. The login now stops with a message pointing at
the OAuth client settings. Password-only logins keep the Basic fallback.
2026-10-02 16:32:15 +02:00
dealerweb f5fb7f9db9 feat: out of office forwarding and recipients, filter rule periods
Filter rules can be limited to a period: the rule dialog takes a start
and an end on the user's clock, the rule list shows whether a rule is
planned, active or expired, and the script tests the moment of
delivery with RFC 5260 currentdate in UTC. A rule is never written
without its period.

The vacation card becomes an out of office page: the period on top,
then the automatic reply and forwarding, each with its own switch.
Forwarding runs with or without the auto-reply, within the period,
never for spam, and keeps a copy here or not. Against the server's
redirect limit it counts as a rule ahead of all others, one that stops
the message unless it keeps a copy. The auto-reply can go to
internal or external senders only, told apart by the envelope sender
against the account's own domains. Both run from the filters script
that includes Stalwart's vacation script, which is put back in charge
when the server's own script takes over.

A script that uses any of this says metadata version 2, which older
builds leave alone instead of writing it back without these fields.
2026-10-02 11:29:32 +02:00
Linus Rath 9ee463084d Merge pull request #1150 from lucamzanon/feat/cross-account-copy
feat: copy messages to a folder of another connected account
2026-10-02 10:33:15 +02:00
dealerweb c55b9f4929 feat: a filter condition that matches every message
The rule editor had no way to say "every message that arrives"; the
workaround was a condition like "From contains @", which only works if
you know it. "All messages" is now a condition of its own, at the end of
the field list. It takes no comparator and no value, writes Sieve's
`true` test, and combines with other conditions as any condition does.
The rule list shows it on its own. A rule with it is never applied to
the messages already in a folder: it would act on all of them.
2026-10-01 14:58:00 +02:00
lucamzanon f02dbf3a40 feat: copy messages to a folder of another connected account
With several accounts connected, mail could only be moved between
them (drag to another account's folder). There was no way to file a
copy in another account and keep the original where it is.

crossAccountMoveEmails and copyEmailAcrossAccounts take an optional
`{ keepOriginal: true }`. With it the source message is not destroyed,
and the store leaves the list, the open message and the selection as
they are; only the destination's folders are refreshed. Without it
nothing changes.

The message menu gets "Copy to account..." when more than one account
is connected. It lists the writable folders of the other accounts
(their folder lists are fetched when the menu opens) and copies the
selection, or the message the menu was opened on, through the new
copyEmailsToAccount action. That groups the messages by the login and
JMAP account they live in and refuses a copy into the account a
message is already in.
2026-10-01 12:53:14 +02:00
Linus Rath 410d6b3532 Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-10-01 11:52:29 +02:00
Linus Rath 26cbca73cb feat: let @ recipient mentions be turned off and announce them to screen readers #1134
Mentions change what Enter and Tab do right after `@word` and open a
list for everyone, so they get a setting next to the empty subject
warning (`recipientMentionsEnabled`, on by default, translated in
every locale). Turned off, the composer offers no candidates and the
editor keeps its keys.

While the list is open, the editor now carries `aria-autocomplete`,
`aria-controls` and `aria-activedescendant`, as the To/Cc
autocomplete does, so screen readers hear the list and the highlighted
name. Each row now leads with the `@name` that will be inserted,
followed by the full name and the address: for a surname-first name
such as "Nagy János" the inserted word is not what the name alone
suggests.
2026-10-01 11:10:04 +02:00
Linus Rath 90c8195a00 Merge pull request #1134 from dealerweb/feat/recipient-mentions
feat: mention a recipient by first name with @ in the message body
2026-10-01 11:06:00 +02:00
Linus Rath 4f48af6307 fix: spam siege restyle 2026-10-01 10:29:20 +02:00
lucamzanon 717f18fc46 feat(unified): say how many accounts the unified mailbox holds while logins reconnect
After a load the logins other than the one on screen reconnect in the
background, and until they are all back the unified counts cover only
some of them. With many logins that lasts seconds, and a partial total
looks exactly like the whole one.

While that restore runs, the "All accounts" header shows how many logins
are already in the scope, e.g. "4/10", with a translated label for screen
readers. It goes away when the scope is complete or the restore is over -
a login that failed to reconnect does not keep it up.

`restoringAccounts` in the auth store marks the background restore; the
count itself is a pure function with its own tests.
2026-10-01 04:38:04 +02:00
Linus Rath 29c74c3b77 feat: sign in with an access token 2026-10-01 00:24:47 +02:00
dealerweb 2b5110e0e4 feat: mention a recipient by first name with @ in the message body
Typing @ at the start of a word in the rich-text body offers the To and
Cc recipients (contact groups expanded) and inserts the chosen one's
first name as plain text. The name comes from the display name; with a
firstname.lastname@ address, the address tells which word of the name is
the first name, and without a name the address supplies it. A bare
initial keeps the mailbox name (@m.mustermann), and recipients who share
a first name get their full name. Bcc recipients are never offered -
naming one in the text would disclose them to everyone else.

The list only opens while a recipient matches, so Enter and Escape
otherwise keep their usual meaning. While it is open, Escape closes the
list rather than the composer, which handles Escape in the capture phase,
and the list closes when the editor loses focus.

Built on @tiptap/suggestion, at the version of the other TipTap packages.
2026-09-30 22:43:59 +02:00