feat: mailbox order - #108
Open
r4nc0r wants to merge 5 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.TreeSorterdecides the order of the hierarchy, and it re-sorts on every node insert, so a manualinsertBeforewould be undone by the next hierarchy update. The user's order is therefore consulted inside the sorter rather than applied to the nodes: the newZarafa.hierarchy.data.StoreOrdersingleton holds the order andhierarchySort()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_namerather than bystore_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 inzarafa/v1/contexts/hierarchy/store_orderas a list of those names.The drop itself is only a signal.
HierarchyFolderDropZone#completeDropdoes not move tree nodes — it firesfolderdropand lets the hierarchy update rebuild them — so the new handler derives the resulting sequence from the drop position, hands it toStoreOrder, and every tree re-sorts on the resultingchangeevent. 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:
appendpoint, 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 existingisRootcheck, whose node UI has no element to measure.onBeforeNodeDrop(), which exists for folder moves, is skipped for a mailbox reorder.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()calledgetFolder()on it — aTypeError, 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.