Skip to content

feat: mailbox order - #108

Open
r4nc0r wants to merge 5 commits into
grommunio:masterfrom
r4nc0r:feature/mailbox-order
Open

feat: mailbox order#108
r4nc0r wants to merge 5 commits into
grommunio:masterfrom
r4nc0r:feature/mailbox-order

Conversation

@r4nc0r

@r4nc0r r4nc0r commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Closes #68.

Shared mailboxes can now be dragged to a position of the user's choosing in the folder pane, the way Outlook allows accounts to be reordered. The chosen order is stored per user and applies to every hierarchy tree in the client, so mail, calendar, contacts, tasks and notes all show the mailboxes in the same sequence.

The own mailbox stays pinned to the top and the Public store stays pinned to the bottom, exactly as before; only the shared mailboxes in between can be moved. Their default remains alphabetical, so nothing changes for a user who never drags anything, and a mailbox opened after the last reorder appears at the end of the shared mailboxes rather than in an arbitrary spot.

This works in a filtered tree as well, such as the calendar folder list. There a shared mailbox is not represented by its IPM_SUBTREE at all: the subtree does not pass the tree's container-class filter, so the loader lifts the mailbox's visible folders to the top level instead. Those nodes stand for their mailbox, so dragging one of them reorders the mailboxes just as dragging the mailbox itself does in the mail folder pane, and the two views always agree because they read the same stored order.

A filtered folder list also had no way to remove a shared mailbox from it. A mailbox opened as a whole has no IPM_SUBTREE node in such a tree for "Close store" to apply to, and no shared-folder key for "Close folder" to apply to, so both items were hidden and the entry could not be got rid of at all. Such a node now offers Remove, which closes the shared mailbox — the same thing "Close store" does on the mailbox itself, and the only granularity a mailbox opened as a whole has. It appears only on a top level node of a shared mailbox where neither existing item applies, so it neither duplicates them nor turns up on an ordinary folder inside a shared mailbox.

How it works

Zarafa.hierarchy.ui.TreeSorter decides the order of the hierarchy, and it re-sorts on every node insert, so a manual insertBefore would be undone by the next hierarchy update. The user's order is therefore consulted inside the sorter rather than applied to the nodes: the new Zarafa.hierarchy.data.StoreOrder singleton holds the order and hierarchySort() asks it first, falling back to the existing alphabetical comparison when the order has nothing to say. That comparison returns "no opinion" unless both stores are ones the user may reorder, which is what keeps the own and the Public store in place — in a filtered tree they are ordinary top level nodes and are not held by the IPM_SUBTREE rules.

Stores are identified by user_name rather than by store_entryid, because that is the identifier the shared-store settings are already keyed on and it stays valid when a mailbox is closed and opened again. The order lives in zarafa/v1/contexts/hierarchy/store_order as a list of those names.

The drop itself is only a signal. HierarchyFolderDropZone#completeDrop does not move tree nodes — it fires folderdrop and lets the hierarchy update rebuild them — so the new handler derives the resulting sequence from the drop position, hands it to StoreOrder, and every tree re-sorts on the resulting change event. Because a filtered tree can show several top level nodes for one mailbox, one per visible folder, the handler works on mailboxes rather than on nodes: it collects them in the order their nodes appear, drops duplicates, and reinserts the dragged one at its new position. A drop onto another node of the same mailbox is not a reorder and does nothing. Writing the full sequence on every drop also means the stored order never drifts from what is on screen, and mailboxes that have since been closed fall out of it by themselves.

Three drag-and-drop details were needed to make the gesture behave:

  • A mailbox has no append point, since dropping a mailbox into another mailbox has no meaning. getDropPoint() therefore splits a row in half for a mailbox drag instead of in thirds, so the whole row is a usable target rather than only its top and bottom third. It stays below the existing isRoot check, whose node UI has no element to measure.
  • Every mailbox hangs off the same invisible root node, so reordering is a same-parent drop by definition. The same-parent guard in onBeforeNodeDrop(), which exists for folder moves, is skipped for a mailbox reorder.
  • A top level node stands for a mailbox, so dragging one can only ever mean moving that mailbox. isValidDropPoint() treats every top level node that way, including the ones that cannot be dragged, rather than letting them fall through to the folder-move path where the target may be the invisible root node.

Included fix

The first commit is a separate, self-contained fix that this change made visible: a folder could be dropped above or below a mailbox root node. The effective drop target is then the invisible root node of the hierarchy, which is not a folder, and onFolderDrop() called getFolder() on it — a TypeError, and the folder move silently did not happen. Such a drop is now refused in the drop zone, with a guard in the move handler as a second line of defence. It is kept as its own commit because it stands on its own; say the word if you would rather see it as a separate pull request.

@r4nc0r r4nc0r changed the title Feature/mailbox order feat: mailbox order Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature-request: allow changing the order of mailboxes

1 participant