@bobfrankston/rmfmail 1.1.249 → 1.1.251
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/android-bootstrap.bundle.js +12 -3
- package/client/android-bootstrap.bundle.js.map +1 -1
- package/client/app.bundle.js +32 -24
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +11 -13
- package/client/app.js.map +1 -1
- package/client/app.ts +10 -12
- package/client/components/message-list.js +13 -5
- package/client/components/message-list.js.map +1 -1
- package/client/components/message-list.ts +14 -6
- package/client/compose/compose.bundle.js +12 -3
- package/client/compose/compose.bundle.js.map +1 -1
- package/client/lib/message-state.js +23 -8
- package/client/lib/message-state.js.map +1 -1
- package/client/lib/message-state.ts +24 -10
- package/package.json +3 -3
|
@@ -52,25 +52,40 @@ export function getMessages() {
|
|
|
52
52
|
* backward when the deletion is at the bottom.
|
|
53
53
|
*/
|
|
54
54
|
export function removeMessages(uids, currentlyFocused) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
// Key on (account, FOLDER, uid) when a folderId is supplied. IMAP UIDs are
|
|
56
|
+
// per-folder, so in a mixed view (e.g. a search spanning INBOX + Trash) a
|
|
57
|
+
// Trash row can share a uid with a SURVIVING INBOX message — keying on
|
|
58
|
+
// (account, uid) alone then kept the deleted Trash row visible (Bob
|
|
59
|
+
// 2026-06-12: "the trash ones did not disappear"). Legacy callers that
|
|
60
|
+
// don't pass folderId fall back to the loose (account, uid) match — those
|
|
61
|
+
// are single-folder contexts with no collision risk.
|
|
62
|
+
const fullSet = new Set();
|
|
63
|
+
const looseSet = new Set();
|
|
64
|
+
for (const u of uids) {
|
|
65
|
+
if (u.folderId != null)
|
|
66
|
+
fullSet.add(`${u.accountId}:${u.folderId}:${u.uid}`);
|
|
67
|
+
else
|
|
68
|
+
looseSet.add(`${u.accountId}:${u.uid}`);
|
|
69
|
+
}
|
|
70
|
+
const isRemoved = (m) => (m.folderId != null && fullSet.has(`${m.accountId}:${m.folderId}:${m.uid}`)) ||
|
|
71
|
+
looseSet.has(`${m.accountId}:${m.uid}`);
|
|
72
|
+
const focusedWasRemoved = currentlyFocused !== null && isRemoved(currentlyFocused);
|
|
58
73
|
let nextSurvivor = null;
|
|
59
74
|
if (focusedWasRemoved) {
|
|
60
75
|
let lastRemovedIdx = -1;
|
|
61
76
|
for (let i = 0; i < messages.length; i++) {
|
|
62
|
-
if (
|
|
77
|
+
if (isRemoved(messages[i]))
|
|
63
78
|
lastRemovedIdx = i;
|
|
64
79
|
}
|
|
65
80
|
for (let i = lastRemovedIdx + 1; i < messages.length; i++) {
|
|
66
|
-
if (!
|
|
81
|
+
if (!isRemoved(messages[i])) {
|
|
67
82
|
nextSurvivor = messages[i];
|
|
68
83
|
break;
|
|
69
84
|
}
|
|
70
85
|
}
|
|
71
86
|
if (!nextSurvivor) {
|
|
72
87
|
for (let i = lastRemovedIdx - 1; i >= 0; i--) {
|
|
73
|
-
if (!
|
|
88
|
+
if (!isRemoved(messages[i])) {
|
|
74
89
|
nextSurvivor = messages[i];
|
|
75
90
|
break;
|
|
76
91
|
}
|
|
@@ -83,11 +98,11 @@ export function removeMessages(uids, currentlyFocused) {
|
|
|
83
98
|
// messageId matches a removed one.
|
|
84
99
|
const removedIds = new Set();
|
|
85
100
|
for (const m of messages) {
|
|
86
|
-
if (
|
|
101
|
+
if (isRemoved(m) && m.messageId) {
|
|
87
102
|
removedIds.add(m.messageId);
|
|
88
103
|
}
|
|
89
104
|
}
|
|
90
|
-
messages = messages.filter(m => !
|
|
105
|
+
messages = messages.filter(m => !isRemoved(m));
|
|
91
106
|
if (removedIds.size > 0) {
|
|
92
107
|
for (const m of messages) {
|
|
93
108
|
if (m.messageId && removedIds.has(m.messageId) && typeof m.dupeCount === "number") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-state.js","sourceRoot":"","sources":["message-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAkBH,IAAI,QAAQ,GAAkB,EAAE,CAAC;AAQjC,MAAM,SAAS,GAAuB,EAAE,CAAC;AAEzC,MAAM,UAAU,SAAS,CAAC,EAAoB;IAC1C,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnB,OAAO,GAAG,EAAE;QACR,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC;AACN,CAAC;AACD,SAAS,MAAM;IACX,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC;YAAC,EAAE,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,2CAA2C,CAAC,CAAC;IACvE,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,WAAW,CAAC,IAAmB;IAC3C,QAAQ,GAAG,IAAI,CAAC;IAChB,MAAM,EAAE,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW;IACvB,OAAO,QAAQ,CAAC;AACpB,CAAC;AAcD;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC1B,
|
|
1
|
+
{"version":3,"file":"message-state.js","sourceRoot":"","sources":["message-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -88,28 +88,42 @@ export interface RemovalOutcome {
|
|
|
88
88
|
* backward when the deletion is at the bottom.
|
|
89
89
|
*/
|
|
90
90
|
export function removeMessages(
|
|
91
|
-
uids: { accountId: string; uid: number }[],
|
|
92
|
-
currentlyFocused: { accountId: string; uid: number } | null,
|
|
91
|
+
uids: { accountId: string; uid: number; folderId?: number }[],
|
|
92
|
+
currentlyFocused: { accountId: string; uid: number; folderId?: number } | null,
|
|
93
93
|
): RemovalOutcome {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
// Key on (account, FOLDER, uid) when a folderId is supplied. IMAP UIDs are
|
|
95
|
+
// per-folder, so in a mixed view (e.g. a search spanning INBOX + Trash) a
|
|
96
|
+
// Trash row can share a uid with a SURVIVING INBOX message — keying on
|
|
97
|
+
// (account, uid) alone then kept the deleted Trash row visible (Bob
|
|
98
|
+
// 2026-06-12: "the trash ones did not disappear"). Legacy callers that
|
|
99
|
+
// don't pass folderId fall back to the loose (account, uid) match — those
|
|
100
|
+
// are single-folder contexts with no collision risk.
|
|
101
|
+
const fullSet = new Set<string>();
|
|
102
|
+
const looseSet = new Set<string>();
|
|
103
|
+
for (const u of uids) {
|
|
104
|
+
if (u.folderId != null) fullSet.add(`${u.accountId}:${u.folderId}:${u.uid}`);
|
|
105
|
+
else looseSet.add(`${u.accountId}:${u.uid}`);
|
|
106
|
+
}
|
|
107
|
+
const isRemoved = (m: { accountId: string; uid: number; folderId?: number }): boolean =>
|
|
108
|
+
(m.folderId != null && fullSet.has(`${m.accountId}:${m.folderId}:${m.uid}`)) ||
|
|
109
|
+
looseSet.has(`${m.accountId}:${m.uid}`);
|
|
110
|
+
const focusedWasRemoved = currentlyFocused !== null && isRemoved(currentlyFocused);
|
|
97
111
|
|
|
98
112
|
let nextSurvivor: ListMessage | null = null;
|
|
99
113
|
if (focusedWasRemoved) {
|
|
100
114
|
let lastRemovedIdx = -1;
|
|
101
115
|
for (let i = 0; i < messages.length; i++) {
|
|
102
|
-
if (
|
|
116
|
+
if (isRemoved(messages[i])) lastRemovedIdx = i;
|
|
103
117
|
}
|
|
104
118
|
for (let i = lastRemovedIdx + 1; i < messages.length; i++) {
|
|
105
|
-
if (!
|
|
119
|
+
if (!isRemoved(messages[i])) {
|
|
106
120
|
nextSurvivor = messages[i];
|
|
107
121
|
break;
|
|
108
122
|
}
|
|
109
123
|
}
|
|
110
124
|
if (!nextSurvivor) {
|
|
111
125
|
for (let i = lastRemovedIdx - 1; i >= 0; i--) {
|
|
112
|
-
if (!
|
|
126
|
+
if (!isRemoved(messages[i])) {
|
|
113
127
|
nextSurvivor = messages[i];
|
|
114
128
|
break;
|
|
115
129
|
}
|
|
@@ -123,11 +137,11 @@ export function removeMessages(
|
|
|
123
137
|
// messageId matches a removed one.
|
|
124
138
|
const removedIds = new Set<string>();
|
|
125
139
|
for (const m of messages) {
|
|
126
|
-
if (
|
|
140
|
+
if (isRemoved(m) && m.messageId) {
|
|
127
141
|
removedIds.add(m.messageId);
|
|
128
142
|
}
|
|
129
143
|
}
|
|
130
|
-
messages = messages.filter(m => !
|
|
144
|
+
messages = messages.filter(m => !isRemoved(m));
|
|
131
145
|
if (removedIds.size > 0) {
|
|
132
146
|
for (const m of messages) {
|
|
133
147
|
if (m.messageId && removedIds.has(m.messageId) && typeof (m as any).dupeCount === "number") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/rmfmail",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.251",
|
|
4
4
|
"description": "Local-first email client with IMAP sync and standalone native app",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/mailx.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@bobfrankston/iflow-direct": "^0.1.53",
|
|
40
40
|
"@bobfrankston/mailx-host": "^0.1.13",
|
|
41
|
-
"@bobfrankston/mailx-imap": "^0.1.
|
|
41
|
+
"@bobfrankston/mailx-imap": "^0.1.91",
|
|
42
42
|
"@bobfrankston/mailx-store-web": "^0.1.27",
|
|
43
43
|
"@bobfrankston/mailx-sync": "^0.1.22",
|
|
44
44
|
"@bobfrankston/miscinfo": "^1.0.13",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"dependencies": {
|
|
119
119
|
"@bobfrankston/iflow-direct": "^0.1.53",
|
|
120
120
|
"@bobfrankston/mailx-host": "^0.1.13",
|
|
121
|
-
"@bobfrankston/mailx-imap": "^0.1.
|
|
121
|
+
"@bobfrankston/mailx-imap": "^0.1.91",
|
|
122
122
|
"@bobfrankston/mailx-store-web": "^0.1.27",
|
|
123
123
|
"@bobfrankston/mailx-sync": "^0.1.22",
|
|
124
124
|
"@bobfrankston/miscinfo": "^1.0.13",
|