@bobfrankston/rmfmail 1.2.67 → 1.2.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client/app.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Wires together all UI components and WebSocket connection.
4
4
  */
5
5
  import { initFolderTree, refreshFolderTree, updateFolderCounts, setFolderSynced, getFolderSynced, setOutboxTotal } from "./components/folder-tree.js";
6
- import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, reloadCurrentFolder, clearSearchMode, getSelectedMessages, markBodiesCached, getCurrentFocused, releaseFocus, removeMessagesAndReconcile, setRowFlagged, scrollFocusedIntoView, refreshPriorityIndex, showSelectionMenu, revealMessage } from "./components/message-list.js";
6
+ import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, reloadCurrentFolder, clearSearchMode, getSelectedMessages, markBodiesCached, getCurrentFocused, releaseFocus, removeMessagesAndReconcile, setRowFlagged, scrollFocusedIntoView, refreshPriorityIndex, showSelectionMenu, revealMessage, selectAllVisible } from "./components/message-list.js";
7
7
  import { seenOf, flaggedOf, draftOf, setSeen, setFlagged } from "@bobfrankston/mailx-types";
8
8
  import { initTabs, setActiveView as setActiveTabView, openTab } from "./components/tabs.js";
9
9
  import { getCurrentMessage, initViewer, popOutCurrentMessage, printCurrentMessage, toggleFullscreenPreview, showPreviewBodyMenu, wrapHtmlBody } from "./components/message-viewer.js";
@@ -1682,7 +1682,7 @@ async function performUndo() {
1682
1682
  const flagsAfter = entry.prevFlagged
1683
1683
  ? [flag] // simplest restore — full set is unknown here
1684
1684
  : [];
1685
- await updateFlags(entry.accountId, entry.uid, flagsAfter);
1685
+ await updateFlags(entry.accountId, entry.uid, flagsAfter, entry.folderId);
1686
1686
  setRowFlagged(entry.accountId, entry.uid, entry.prevFlagged);
1687
1687
  messageState.updateMessageFlags(entry.accountId, entry.uid, flagsAfter);
1688
1688
  }
@@ -1913,7 +1913,7 @@ async function bulkFlagSelected() {
1913
1913
  const anyUnflagged = rows.some(r => !flaggedOf(r));
1914
1914
  const targetFlagged = anyUnflagged; // mixed or all-unflagged → flag; all-flagged → unflag
1915
1915
  const undoPayload = rows.map(r => ({
1916
- accountId: r.accountId, uid: r.uid, prevFlagged: flaggedOf(r),
1916
+ accountId: r.accountId, uid: r.uid, prevFlagged: flaggedOf(r), folderId: r.folderId,
1917
1917
  }));
1918
1918
  const { updateFlags } = await import("./lib/api-client.js");
1919
1919
  for (const r of rows) {
@@ -1923,7 +1923,7 @@ async function bulkFlagSelected() {
1923
1923
  setRowFlagged(r.accountId, r.uid, targetFlagged);
1924
1924
  messageState.updateMessageFlags(r.accountId, r.uid, r.flags);
1925
1925
  try {
1926
- await updateFlags(r.accountId, r.uid, r.flags);
1926
+ await updateFlags(r.accountId, r.uid, r.flags, r.folderId);
1927
1927
  }
1928
1928
  catch (e) {
1929
1929
  console.error(`Bulk flag failed for ${r.accountId}/${r.uid}: ${e?.message || e}`);
@@ -1945,7 +1945,7 @@ document.getElementById("btn-flag")?.addEventListener("click", async () => {
1945
1945
  setFlagged(sel, !wasFlagged);
1946
1946
  updateFlagButton();
1947
1947
  try {
1948
- await updateFlags(sel.accountId, sel.uid, sel.flags);
1948
+ await updateFlags(sel.accountId, sel.uid, sel.flags, sel.folderId);
1949
1949
  messageState.updateMessageFlags(sel.accountId, sel.uid, sel.flags);
1950
1950
  // Row owns its own DOM \u2014 go through the row object so class + star
1951
1951
  // update atomically and the list/preview stay in sync.
@@ -2075,7 +2075,7 @@ document.getElementById("btn-mark-unread")?.addEventListener("click", () => {
2075
2075
  return;
2076
2076
  const wasSeen = seenOf(sel);
2077
2077
  setSeen(sel, !wasSeen);
2078
- updateFlags(sel.accountId, sel.uid, sel.flags).then(() => {
2078
+ updateFlags(sel.accountId, sel.uid, sel.flags, sel.folderId).then(() => {
2079
2079
  messageState.updateMessageFlags(sel.accountId, sel.uid, sel.flags);
2080
2080
  const row = document.querySelector(`.ml-row[data-uid="${sel.uid}"][data-account-id="${sel.accountId}"]`);
2081
2081
  if (row)
@@ -3682,7 +3682,10 @@ document.addEventListener("keydown", (e) => {
3682
3682
  const mlBody = document.getElementById("ml-body");
3683
3683
  if (mlBody) {
3684
3684
  e.preventDefault();
3685
- mlBody.querySelectorAll(".ml-row").forEach(r => r.classList.add("selected"));
3685
+ // selectAllVisible() also sets `multi-select-on` so a following ★
3686
+ // click clears the WHOLE selection, not just the clicked row
3687
+ // (Bob 2026-06-26). Plain add-.selected was the bug.
3688
+ selectAllVisible();
3686
3689
  }
3687
3690
  }
3688
3691
  // Ctrl+D or Delete = Delete selected messages.
@@ -3739,7 +3742,7 @@ document.addEventListener("keydown", (e) => {
3739
3742
  e.preventDefault();
3740
3743
  const applySeen = (m, seen) => {
3741
3744
  setSeen(m, seen);
3742
- updateFlags(m.accountId, m.uid, m.flags).then(() => {
3745
+ updateFlags(m.accountId, m.uid, m.flags, m.folderId).then(() => {
3743
3746
  messageState.updateMessageFlags(m.accountId, m.uid, m.flags);
3744
3747
  const row = document.querySelector(`.ml-row[data-uid="${m.uid}"][data-account-id="${CSS.escape(m.accountId)}"]`);
3745
3748
  if (row)
@@ -5954,13 +5957,18 @@ function saveBootSnapshot() {
5954
5957
  // (e.g. user clicked a folder, list is empty for a tick) would
5955
5958
  // otherwise clobber the previous good snapshot.
5956
5959
  const ftHtml = folderTree?.innerHTML?.trim() || "";
5957
- const mlHtml = messageList?.innerHTML?.trim() || "";
5960
+ // Search is ephemeral: never snapshot the list while a search is
5961
+ // showing, or a cold start would repaint stale search results before
5962
+ // the real folder/inbox loads (Bob 2026-06-26). Empty string = the
5963
+ // loader skips this region and the normal boot load fills it.
5964
+ const searching = (searchInput?.value.trim() || "") !== "";
5965
+ const mlHtml = searching ? "" : (messageList?.innerHTML?.trim() || "");
5958
5966
  if (!ftHtml && !mlHtml)
5959
5967
  return;
5960
5968
  const snap = {
5961
5969
  folderTree: ftHtml,
5962
5970
  messageList: mlHtml,
5963
- folderTitle: folderTitle?.innerHTML?.trim() || "",
5971
+ folderTitle: searching ? "" : (folderTitle?.innerHTML?.trim() || ""),
5964
5972
  savedAt: Date.now(),
5965
5973
  };
5966
5974
  localStorage.setItem("mailx-boot-snapshot", JSON.stringify(snap));