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
This commit is contained in:
@@ -29,6 +29,7 @@ import { plural, t } from "@/lib/i18n";
|
||||
import { withBase } from "@/lib/basePath";
|
||||
import { isDeviceTrusted, loadRaw, saveJson } from "@/lib/storage";
|
||||
import { MAILBOX_PROPS, LIST_PROPS, FULL_PROPS, BODY_PROPS } from "./props";
|
||||
import { compareFolders } from "@/lib/mailbox/folderOrder";
|
||||
import { type ListQuery, type MailState } from "./types";
|
||||
import { playNewMailSound, showNotification } from "@/lib/notify/notify";
|
||||
import { pushEnabledHere } from "@/lib/notify/webpush";
|
||||
@@ -161,7 +162,7 @@ export const useMail = create<MailState>((set, get) => ({
|
||||
childrenOf(parentId) {
|
||||
return Object.values(get().mailboxes)
|
||||
.filter((m) => (m.parentId ?? null) === parentId)
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name));
|
||||
.sort(compareFolders);
|
||||
},
|
||||
|
||||
async query(q, opts = {}) {
|
||||
@@ -762,6 +763,20 @@ export const useMail = create<MailState>((set, get) => ({
|
||||
if (before.length) await followFolders(before);
|
||||
},
|
||||
|
||||
async arrangeMailboxes(updates) {
|
||||
const accountId = get().accountId!;
|
||||
const moved = Object.keys(updates).filter((id) => updates[id]!.parentId !== undefined);
|
||||
const before = moved.flatMap((id) => folderRefs(get(), id));
|
||||
// One request for the whole level rather than one per folder. JMAP applies
|
||||
// each update on its own, so a refusal can leave the level part-numbered;
|
||||
// reloading shows whatever order the server actually kept.
|
||||
const res = await client.call<SetResponse>("Mailbox/set", { accountId, update: updates });
|
||||
const failed = Object.values(res.notUpdated ?? {})[0];
|
||||
await get().loadMailboxes();
|
||||
if (failed) throw new Error(setErrorMessage(failed));
|
||||
if (before.length) await followFolders(before);
|
||||
},
|
||||
|
||||
async destroyMailbox(id, removeEmails = true) {
|
||||
const accountId = get().accountId!;
|
||||
const before = folderRefs(get(), id);
|
||||
|
||||
Reference in New Issue
Block a user