Commit Graph
72 Commits
Author SHA1 Message Date
jcoffeyandClaude Opus 5 8a7ff5d42f Reorder folders by dragging, with special folders first (#402) (#405)
The folder tree ignored sortOrder: Inbox came first, then everything
A–Z, so Sent ended up among ordinary folders. The tree now lists Inbox,
then any order the user has chosen, then the other special folders
(Drafts, Sent, Archive, Junk, Trash), then the rest A–Z. Stalwart gives
every folder sortOrder 0 until someone orders it, so an existing
sidebar changes once, to that default.

Dropping a folder on the top or bottom quarter of a row puts it above or
below that row, with a line to show where it will land. Dropping on the
middle still nests it. Special folders can now be dragged, to be
reordered but never nested; on those, the whole row reorders by the
nearer half. The folder menu gains Move up and Move down, for the
keyboard and touch. Inbox stays first.

A reorder numbers the level 10 apart and writes only the folders whose
number changes, in one Mailbox/set. The order is saved on the server,
so it follows the account to every device and to other JMAP clients.

No new strings: Move up and Move down were already translated.

Fixes #402

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-19 14:06:21 -07:00
jcoffeyandClaude Opus 5 c201d34377 Open the composer full screen, as a setting (#401) (#404)
Settings > General > Composing has a new switch, "Open the composer full
screen". With it on, every new composer, whether a new message, reply,
forward or reopened draft, starts maximized. Restore still shrinks it to
a window. A draft put back after an undone or failed send keeps the size
it had. It's off by default, and on a phone, where the composer already
fills the screen, it changes nothing.

One new string, translated in all nine catalogs. The count falling back
to English stays at 16 in every language.

Fixes #401

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-19 14:06:18 -07:00
jcoffeyandmbjboon-netizen 05d1645ab7 Update nl.ts (#403)
Signed-off-by: mbjboon-netizen <[email protected]>
Co-authored-by: mbjboon-netizen <[email protected]>
2026-09-19 13:42:51 -07:00
jcoffey 091782ae3a Drag calendar events to another day in the week grid (#400)
A timed event in the week view now moves sideways across the columns
as well as up and down, landing on the new day at the hour it was
dragged to. All-day chips above the grid drag between days the way
month chips do. Both drags count from the day the event was picked up
on, so a multi-day event grabbed on its last day moves by the distance
dragged, not by its length.
2026-09-18 21:19:58 -07:00
jcoffeyandJoe Esteves c118184975 Match Shift+letter shortcuts (Shift+I, Shift+U) (#399)
comboOf() let a shifted letter encode Shift in its case, so Shift+I
produced "I" and never matched the "shift+i" / "shift+u" bindings for
mark as read / unread. Shifted letters now yield "shift+<letter>";
symbols such as "#" and "!" still carry Shift in the character.

Fixes #398

Co-authored-by: Joe Esteves <[email protected]>
2026-09-18 08:22:13 -07:00
jcoffey 2740129c6a Keep only the app page as the app page (#396)
The service worker answers app routes from its kept page (#395), and it
kept whatever the mount's root returned at install and whatever HTML a
navigation returned. Where the root is not the app -- demo.ihasmail.com
puts its landing page there -- a returning visitor got the landing page on
every route.

The kept page is now only ever the app page, recognised by the asset list
the build writes into it: install fetches /mail instead of /, a
navigation's page is kept only if it is the app's, and a foreign page left
by the earlier worker is dropped when this one activates. Only the app's
own routes are answered from it; the root and any page in front of the app
go to the network. The reload for a new build primes the kept page from
/mail for the same reason.
2026-09-16 15:07:45 -07:00
jcoffey 82dc877fe1 Start at once on a device marked as your own (#395)
* Start at once on a device marked as your own

On a distant link, opening the app waited on four round trips before the
inbox showed: the app page, the session, the folder list, then the folder.

A trusted device now starts from what it kept:

- the service worker answers an app route from its kept page and fetches a
  fresh one behind it; the app checks the server's version at start, and a
  reload for a new build puts the new page in place first, so it is not
  answered with the old one. Assets of the page just replaced are kept one
  build longer for a tab still running it.
- the session's public details, so requests for mail go out before the
  server has confirmed the session; the answer replaces it, and a session
  that has ended lands on the sign-in form as before.
- the folder list and the first page of up to four recently read folders,
  list properties only, so the folders and the inbox paint before any reply
  and the folder query does not wait on the folder list. The "folder no
  longer exists" check still waits for the server's list.

All of it goes through the storage gate: nothing is written or read on a
device not marked as the reader's own, and signing out clears it.

* Show nothing kept before the session is confirmed

Starting from a kept session put the kept inbox on screen before the
server had said the session was still good; a session that had ended
showed mail and then the sign-in form. The spinner stays until the
server answers, as before.

The kept session is gone -- it existed only to start early. The kept
folder list and rows are still applied, from setAccount, which runs once
the session is confirmed: the inbox paints the moment that answer
arrives, and the folder query goes out then without waiting on the
folder list. An unreachable server lands on the sign-in form as before.
2026-09-16 13:47:59 -07:00
jcoffey 4c67460450 Fetch the rest of a new build in the background (#394)
The app page names only what it loads at start. The composer, settings,
viewers and the rest were fetched when first used, and after every deploy
that first use waited on the server -- and the worker's tidy-up dropped
them again at the next deploy anyway.

The build now writes the list of all its files into the page as an inert
JSON block. The service worker keeps everything listed and, once a page
names files it does not hold, fetches them three at a time; a load cut
short is resumed at the next navigation. Language catalogs are listed
apart and left to be cached when used, and nothing is fetched ahead when
the browser is set to save data.
2026-09-16 13:29:57 -07:00
jcoffey e158ebac5a Fold a push's follow-up requests together (#393)
A pushed mail change took three round trips: Email/changes beside a
Mailbox/get, then Email/get for what changed, then the list, the open
thread and a second Mailbox/get. Each page of changes now carries its own
Email/get calls by back-reference, and the one Mailbox/get goes out with
it, so a push settles in two. New mail fetched this way is not asked for
again by the notice.

A reply's sessionState that differs from the session is announced once
rather than on every reply, and session refreshes in flight are shared.
The mock's session state now matches the sessionState on its replies, as
Stalwart's does; tying it to the data counter made every reply trigger a
session refresh in development.
2026-09-16 13:22:26 -07:00
jcoffey 786976312f Open conversations in one request, and start them early (#392)
On a 250 ms link, opening a conversation took two round trips: Thread/get,
then the bodies. It now takes one. A known thread sends Thread/get and the
missing bodies in the same tick; an unknown one chains Email/get off
Thread/get with a back-reference, and falls back to fetching in parts when
the thread is longer than one Email/get may carry.

Conversations also start loading before the click: when the pointer rests
on a row, as soon as a press begins, and for the row below the open one.
The open waits for that load and does not repeat it.

Going back to one of the last twelve folders shows its previous list at
once, less messages that have left it, while the query runs.
2026-09-16 13:15:21 -07:00
jcoffey 5fe89d6e15 Merge pull request #391 from Coffey-Labs/feat/share-confirm
Ask before opening a shared item in a message
2026-09-16 12:27:33 -07:00
jcoffey 4c1ceca8e9 Merge pull request #390 from Coffey-Labs/fix/accept-ranges
Advertise byte ranges on downloads, and record the live checks
2026-09-16 12:13:20 -07:00
jcoffey ebf678be73 Merge pull request #389 from Coffey-Labs/fix/push-subscriptions
Stop duplicate push notifications and piling up subscriptions
2026-09-16 11:41:37 -07:00
jcoffey 3d7602ce74 Merge pull request #388 from Coffey-Labs/fix/contact-photos
Save contact photos inline, and load cards so avatars show
2026-09-16 11:38:22 -07:00
jcoffey aa9bf1b9b2 Merge pull request #387 from Coffey-Labs/perf/client-memory
Let go of old message bodies and of exported files
2026-09-16 11:02:42 -07:00
jcoffey c63fd0dfe0 Merge pull request #386 from Coffey-Labs/perf/server-static-and-caches
Precompress the bundle, validate the shell, and pass byte ranges on
2026-09-16 11:02:37 -07:00
jcoffey 56bd48e891 Merge pull request #385 from mbjboon-netizen/mbjboon-netizen-patch-1
Mbjboon netizen patch 1
2026-09-16 10:50:14 -07:00
jcoffey da87925b9c Merge pull request #384 from Coffey-Labs/perf/contacts-calendar-changes
Sync contacts by what changed, and hold fewer calendar windows
2026-09-16 10:45:12 -07:00
jcoffey 6090442058 Merge pull request #383 from Coffey-Labs/perf/lazy-store-init
Ask shared accounts together, and about files only when Files opens
2026-09-16 10:06:53 -07:00
jcoffey 9560ad06f4 Merge pull request #382 from Coffey-Labs/perf/lazy-chunks
Load the composer, previews, dialogs and other sidebars on demand
2026-09-16 09:50:14 -07:00
jcoffey e3cd56314b Merge pull request #381 from Coffey-Labs/perf/message-list-rows
Render only the message rows that changed
2026-09-16 09:22:08 -07:00
jcoffey 460760ba12 Merge pull request #380 from Coffey-Labs/fix/sw-cache
Keep the service worker's cache to the current build
2026-09-16 09:01:20 -07:00
jcoffey a9302075e7 Merge pull request #379 from Coffey-Labs/fix/security-followups
Close the smaller gaps from the security review
2026-09-16 08:50:31 -07:00
jcoffey 9691a7bbf5 Merge pull request #378 from Coffey-Labs/fix/push-refresh
Keep list refreshes within the server's limits and stop repeating them
2026-09-16 08:33:01 -07:00
jcoffey 47a2477d9f Merge pull request #377 from Coffey-Labs/fix/server-hardening
Bound what a request can make the server hold
2026-09-16 07:58:47 -07:00
jcoffey b2e7db938c Merge commit from fork
Harden the email sanitizer's CSS handling
2026-09-16 07:40:38 -07:00
jcoffey d0b13272f3 Merge pull request #374 from Coffey-Labs/refactor/lib-clusters
Group six more lib clusters, and split the mock server
2026-09-15 23:25:01 -07:00
jcoffey 5cc31037c1 Merge pull request #373 from Coffey-Labs/refactor/split-mail-store
Split the extractable parts out of the mail store
2026-09-15 22:54:03 -07:00
jcoffey e42c81ab09 Merge pull request #372 from Coffey-Labs/refactor/lib-domain-folders
Group the admin and calendar modules, and stop calling screenshots docs
2026-09-15 22:53:34 -07:00
jcoffey 0bde2df69d Merge pull request #371 from Coffey-Labs/ci/pin-actions-to-shas
Pin every action to a commit SHA
2026-09-15 22:23:07 -07:00
jcoffey df06b8ea04 Merge pull request #370 from Coffey-Labs/docs/pull-request-template
Add the pull request template CONTRIBUTING.md already refers to
2026-09-15 22:23:03 -07:00
jcoffey 3bfe9396b4 Merge pull request #369 from Coffey-Labs/chore/us-spelling-license
Use American English spelling
2026-09-15 11:49:23 -07:00
jcoffey a7d36e1962 Merge pull request #368 from Coffey-Labs/docs/shorter-readme
Shorter README: an introduction and links
2026-09-15 10:54:17 -07:00
jcoffey 8639e9885b Merge pull request #366 from Coffey-Labs/feat/detect-stalwart-admin-url
Find Stalwart's administration instead of asking for it
2026-09-15 10:07:27 -07:00
jcoffey d3fef4acb7 Merge pull request #365 from Coffey-Labs/docs/schema-route-confirmed
Record the schema route working on production
2026-09-15 10:07:10 -07:00
jcoffey 66892c794d Merge pull request #367 from Coffey-Labs/docs/scrub-server-hostnames
Take the production server's domains out of KNOWN-ISSUES
2026-09-15 10:07:01 -07:00
jcoffey 53d9cd37fb Merge pull request #364 from Coffey-Labs/feat/admin-tenants
Add Tenants to Administration, and let an account be put in one
2026-09-15 09:51:05 -07:00
jcoffey 5f28393039 Merge pull request #363 from Coffey-Labs/feat/admin-roles
Add Roles to Administration, with Stalwart's permissions in every language
2026-09-15 09:50:55 -07:00
jcoffey 37a0e28871 Merge pull request #362 from Coffey-Labs/feat/admin-lists
Add Mailing lists to Administration
2026-09-15 09:50:42 -07:00
jcoffey 5a7a8019e9 Merge pull request #361 from Coffey-Labs/feat/admin-groups
Add Groups to Administration
2026-09-15 09:50:28 -07:00
jcoffey d17c9a6e1f Merge pull request #360 from Coffey-Labs/feat/admin-dashboard
Open Administration on a dashboard of what the role can read
2026-09-15 09:48:57 -07:00
jcoffey bb8d6eb92d Merge pull request #359 from Coffey-Labs/fix/keyboard-keyless-keydown
Ignore a keydown that carries no key
2026-09-15 07:29:33 -07:00
jcoffey 877566f1cd Merge pull request #358 from Coffey-Labs/fix/contacts-resizable-list
Let the contact list be resized, and give the contact the rest of the page
2026-09-15 07:28:06 -07:00
jcoffey 14e22c21fe Merge pull request #354 from Coffey-Labs/dependabot/npm_and_yarn/jsdom-30.0.1
Bump jsdom from 26.1.0 to 30.0.1
2026-09-15 07:17:46 -07:00
jcoffey 7d96cf22ac Merge pull request #353 from Coffey-Labs/dependabot/npm_and_yarn/vitest-5.0.0
Bump vitest from 4.1.11 to 5.0.0
2026-09-15 07:14:09 -07:00
jcoffey a4022b37ce Merge pull request #352 from Coffey-Labs/dependabot/npm_and_yarn/lucide-react-1.45.0
Bump lucide-react from 0.477.0 to 1.45.0
2026-09-15 07:13:25 -07:00
jcoffey 33d966ba44 Merge pull request #351 from Coffey-Labs/dependabot/npm_and_yarn/concurrently-10.0.5
Bump concurrently from 9.2.4 to 10.0.5
2026-09-15 07:12:53 -07:00
jcoffey 1bf6350d68 Merge pull request #350 from Coffey-Labs/dependabot/npm_and_yarn/minor-and-patch-e9d406726e
Bump @tanstack/react-virtual from 3.14.11 to 3.14.12 in the minor-and-patch group
2026-09-15 07:11:52 -07:00
jcoffey b735685416 Merge pull request #357 from Coffey-Labs/feat/move-folder-picker
Move a folder from its menu, with the same picker as moving mail
2026-09-15 07:11:09 -07:00
jcoffey 7940a15a43 Merge pull request #349 from Coffey-Labs/i18n/template-literal-attributes
Translate English built from template literals in attributes
2026-09-14 08:28:18 -07:00
jcoffey aa57c59703 Merge pull request #348 from Coffey-Labs/i18n/literal-check-component-props
Check component props for untranslated literals, and fail on a finding
2026-09-14 08:10:46 -07:00
jcoffey af092b3942 Merge pull request #347 from Coffey-Labs/feat/resizable-sidebar
Let the sidebar be resized by dragging its edge
2026-09-14 07:56:59 -07:00
jcoffey f0039c87fe Merge pull request #346 from Coffey-Labs/ci/weekly-release-off-the-hour
Move the weekly release off the top of the hour
2026-09-14 07:56:52 -07:00
jcoffey 1dc0caeae9 Merge pull request #344 from Coffey-Labs/docs/companion-tools
Point to the companion tools near the top of the README
2026-09-13 22:48:01 -07:00
jcoffey c587268c97 Merge pull request #343 from Coffey-Labs/docs/features-known-issues-0.16.22
Bring FEATURES and KNOWN-ISSUES up to 0.16.22
2026-09-13 18:00:26 -07:00
jcoffey 3dd8c7c2dd Merge pull request #342 from Coffey-Labs/mock/stalwart-0.16.22
Follow Stalwart 0.16.22 in the mock
2026-09-13 17:57:27 -07:00
jcoffey 029afc21c4 Merge pull request #341 from Coffey-Labs/docs/stalwart-0.16.22
Say 0.16.22 in the README
2026-09-13 17:52:51 -07:00
jcoffey 5f808f3033 Merge pull request #340 from Coffey-Labs/fix/translate-admin-errors
Say every Administration refusal in the reader's language
2026-09-13 17:21:07 -07:00
jcoffey 822314e8b7 Merge pull request #339 from Coffey-Labs/docs/administration
Record what Administration proved on the live server
2026-09-13 16:49:13 -07:00
jcoffey f44987e391 Merge pull request #338 from Coffey-Labs/feat/admin-trusted-device-only
Offer administration only on a device marked as your own
2026-09-13 16:36:45 -07:00
jcoffey b6cc762d23 Merge pull request #337 from Coffey-Labs/feat/admin-nav-in-sidebar
Move Administration's section list into the folder pane
2026-09-13 16:36:22 -07:00
jcoffey 93c9660421 Merge pull request #336 from Coffey-Labs/fix/account-type-filter
Filter accounts on @type, the name Stalwart uses
2026-09-13 15:58:52 -07:00
jcoffey b79db9098a Merge pull request #335 from Coffey-Labs/feat/admin-domains
Add Domains to Administration
2026-09-13 15:47:30 -07:00
jcoffey 16e0761ddf Merge pull request #334 from Coffey-Labs/feat/admin-accounts
Add Administration, starting with accounts
2026-09-13 15:46:46 -07:00
jcoffey 5f5672fed3 Merge pull request #333 from Coffey-Labs/fix/multi-server-account-requests
Send account requests to the account's own Stalwart
2026-09-13 15:46:20 -07:00
jcoffey b0564679e6 Merge pull request #332 from Coffey-Labs/deploy-version-without-node
Let the deploy compute its version without node
2026-09-12 12:29:25 -07:00
jcoffey a666cdbcdc Merge pull request #331 from Coffey-Labs/fix/composer-maximized-stacking
Paint a full-screen composer above the others
2026-09-12 12:24:34 -07:00
jcoffey c3d2dc2418 Merge pull request #329 from Coffey-Labs/prune-stale-catalogue-keys
Report the stale keys that are stale, and remove them
2026-09-10 16:01:41 -07:00
jcoffey 3c4f6a9f8e Merge pull request #328 from Coffey-Labs/i18n-scripts-typescript7
Give the i18n scripts a parser again
2026-09-10 14:24:06 -07:00
jcoffey 2a323d6270 Merge pull request #327 from Coffey-Labs/single-message-view
Let conversation view off mean off
2026-09-10 14:23:52 -07:00
jcoffey 9b497af756 Merge pull request #326 from Coffey-Labs/plain-text-line-breaks
Render plain-text mail with its line breaks
2026-09-10 13:39:12 -07:00
jcoffey a9923c48d9 Merge pull request #325 from Coffey-Labs/funding-username-jcoffey-dev
Point the Sponsor button at the current GitHub username
2026-09-10 09:19:28 -07:00