Improved message cache handling and drop unused NEW_MESSAGE_CACHE

This commit is contained in:
the-djmaze 2022-06-07 11:54:19 +02:00
parent 757d71cd40
commit a60d027169
9 changed files with 83 additions and 161 deletions

View file

@ -24,8 +24,6 @@ import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { import {
MessageFlagsCache, MessageFlagsCache,
setFolderHash,
getFolderHash,
getFolderInboxName, getFolderInboxName,
getFolderFromCacheList getFolderFromCacheList
} from 'Common/Cache'; } from 'Common/Cache';
@ -222,17 +220,16 @@ export class AppUser extends AbstractApp {
(iError, data) => { (iError, data) => {
if (!iError && data.Result) { if (!iError && data.Result) {
const result = data.Result, const result = data.Result,
hash = getFolderHash(result.Folder),
folderFromCache = getFolderFromCacheList(result.Folder); folderFromCache = getFolderFromCacheList(result.Folder);
if (folderFromCache) { if (folderFromCache) {
const oldHash = folderFromCache.hash,
unreadCountChange = (folderFromCache.unreadEmails() !== result.unreadEmails);
// folderFromCache.revivePropertiesFromJson(result);
folderFromCache.expires = Date.now(); folderFromCache.expires = Date.now();
folderFromCache.uidNext = result.UidNext;
setFolderHash(result.Folder, result.Hash); folderFromCache.hash = result.Hash;
folderFromCache.totalEmails(result.totalEmails); folderFromCache.totalEmails(result.totalEmails);
let unreadCountChange = (folderFromCache.unreadEmails() !== result.unreadEmails);
folderFromCache.unreadEmails(result.unreadEmails); folderFromCache.unreadEmails(result.unreadEmails);
if (unreadCountChange) { if (unreadCountChange) {
@ -247,13 +244,9 @@ export class AppUser extends AbstractApp {
MessagelistUserStore.reloadFlagsAndCachedMessage(); MessagelistUserStore.reloadFlagsAndCachedMessage();
} }
MessagelistUserStore.initUidNextAndNewMessages( MessagelistUserStore.notifyNewMessages(folderFromCache.fullName, result.NewMessages);
folderFromCache.fullName,
result.UidNext,
result.NewMessages
);
if (!hash || unreadCountChange || result.Hash !== hash) { if (!oldHash || unreadCountChange || result.Hash !== oldHash) {
if (folderFromCache.fullName === FolderUserStore.currentFolderFullName()) { if (folderFromCache.fullName === FolderUserStore.currentFolderFullName()) {
MessagelistUserStore.reload(); MessagelistUserStore.reload();
} else if (getFolderInboxName() === folderFromCache.fullName) { } else if (getFolderInboxName() === folderFromCache.fullName) {

View file

@ -4,7 +4,6 @@ import { isArray } from 'Common/Utils';
let FOLDERS_CACHE = {}, let FOLDERS_CACHE = {},
FOLDERS_NAME_CACHE = {}, FOLDERS_NAME_CACHE = {},
MESSAGE_FLAGS_CACHE = {}, MESSAGE_FLAGS_CACHE = {},
NEW_MESSAGE_CACHE = {},
REQUESTED_MESSAGE_CACHE = {}, REQUESTED_MESSAGE_CACHE = {},
inboxFolderName = 'INBOX'; inboxFolderName = 'INBOX';
@ -16,7 +15,6 @@ export const
FOLDERS_CACHE = {}; FOLDERS_CACHE = {};
FOLDERS_NAME_CACHE = {}; FOLDERS_NAME_CACHE = {};
MESSAGE_FLAGS_CACHE = {}; MESSAGE_FLAGS_CACHE = {};
NEW_MESSAGE_CACHE = {};
REQUESTED_MESSAGE_CACHE = {}; REQUESTED_MESSAGE_CACHE = {};
}, },
@ -40,29 +38,6 @@ export const
*/ */
hasRequestedMessage = (folder, uid) => true === REQUESTED_MESSAGE_CACHE[getMessageKey(folder, uid)], hasRequestedMessage = (folder, uid) => true === REQUESTED_MESSAGE_CACHE[getMessageKey(folder, uid)],
/**
* @param {string} folderFullName
* @param {string} uid
*/
addNewMessageCache = (folderFullName, uid) => NEW_MESSAGE_CACHE[getMessageKey(folderFullName, uid)] = true,
/**
* @param {string} folderFullName
* @param {string} uid
*/
hasNewMessageAndRemoveFromCache = (folderFullName, uid) => {
if (NEW_MESSAGE_CACHE[getMessageKey(folderFullName, uid)]) {
NEW_MESSAGE_CACHE[getMessageKey(folderFullName, uid)] = null;
return true;
}
return false;
},
/**
* @returns {void}
*/
clearNewMessageCache = () => NEW_MESSAGE_CACHE = {},
/** /**
* @returns {string} * @returns {string}
*/ */
@ -91,13 +66,6 @@ export const
FOLDERS_NAME_CACHE[folder.fullNameHash] = folder.fullName; FOLDERS_NAME_CACHE[folder.fullNameHash] = folder.fullName;
}, },
/**
* @param {string} folderFullName
* @returns {string}
*/
getFolderHash = folderFullName =>
FOLDERS_CACHE[folderFullName] ? FOLDERS_CACHE[folderFullName].hash : '',
/** /**
* @param {string} folderFullName * @param {string} folderFullName
* @param {string} folderHash * @param {string} folderHash
@ -105,20 +73,6 @@ export const
setFolderHash = (folderFullName, folderHash) => setFolderHash = (folderFullName, folderHash) =>
FOLDERS_CACHE[folderFullName] && (FOLDERS_CACHE[folderFullName].hash = folderHash), FOLDERS_CACHE[folderFullName] && (FOLDERS_CACHE[folderFullName].hash = folderHash),
/**
* @param {string} folderFullName
* @returns {string}
*/
getFolderUidNext = folderFullName =>
FOLDERS_CACHE[folderFullName] ? FOLDERS_CACHE[folderFullName].uidNext : 0,
/**
* @param {string} folderFullName
* @param {string} uidNext
*/
setFolderUidNext = (folderFullName, uidNext) =>
FOLDERS_CACHE[folderFullName] && (FOLDERS_CACHE[folderFullName].uidNext = uidNext),
/** /**
* @param {string} folderFullName * @param {string} folderFullName
* @returns {?FolderModel} * @returns {?FolderModel}

View file

@ -2,10 +2,8 @@ import { isArray, arrayLength } from 'Common/Utils';
import { import {
MessageFlagsCache, MessageFlagsCache,
setFolderHash, setFolderHash,
getFolderHash,
getFolderInboxName, getFolderInboxName,
getFolderFromCacheList, getFolderFromCacheList
getFolderUidNext
} from 'Common/Cache'; } from 'Common/Cache';
import { SettingsUserStore } from 'Stores/User/Settings'; import { SettingsUserStore } from 'Stores/User/Settings';
import { FolderUserStore } from 'Stores/User/Folder'; import { FolderUserStore } from 'Stores/User/Folder';
@ -34,7 +32,8 @@ sortFolders = folders => {
*/ */
fetchFolderInformation = (fCallback, folder, list = []) => { fetchFolderInformation = (fCallback, folder, list = []) => {
let fetch = !arrayLength(list); let fetch = !arrayLength(list);
const uids = []; const uids = [],
folderFromCache = getFolderFromCacheList(folder);
if (!fetch) { if (!fetch) {
list.forEach(messageListItem => { list.forEach(messageListItem => {
@ -57,7 +56,7 @@ fetchFolderInformation = (fCallback, folder, list = []) => {
Remote.request('FolderInformation', fCallback, { Remote.request('FolderInformation', fCallback, {
Folder: folder, Folder: folder,
FlagsUids: uids, FlagsUids: uids,
UidNext: getFolderUidNext(folder) // Used to check for new messages UidNext: (folderFromCache && folderFromCache.uidNext) || 0 // Used to check for new messages
}); });
} else if (SettingsUserStore.useThreads()) { } else if (SettingsUserStore.useThreads()) {
MessagelistUserStore.reloadFlagsAndCachedMessage(); MessagelistUserStore.reloadFlagsAndCachedMessage();
@ -140,25 +139,23 @@ folderInformationMultiply = (boot = false) => {
if (!iError && arrayLength(oData.Result)) { if (!iError && arrayLength(oData.Result)) {
const utc = Date.now(); const utc = Date.now();
oData.Result.forEach(item => { oData.Result.forEach(item => {
const hash = getFolderHash(item.Folder), const folder = getFolderFromCacheList(item.Folder);
folder = getFolderFromCacheList(item.Folder);
if (folder) { if (folder) {
const oldHash = folder.hash,
unreadCountChange = folder.unreadEmails() !== item.unreadEmails;
// folder.revivePropertiesFromJson(item);
folder.expires = utc; folder.expires = utc;
folder.hash = item.Hash;
setFolderHash(item.Folder, item.Hash);
folder.totalEmails(item.totalEmails); folder.totalEmails(item.totalEmails);
let unreadCountChange = folder.unreadEmails() !== item.unreadEmails;
folder.unreadEmails(item.unreadEmails); folder.unreadEmails(item.unreadEmails);
if (unreadCountChange) { if (unreadCountChange) {
MessageFlagsCache.clearFolder(folder.fullName); MessageFlagsCache.clearFolder(folder.fullName);
} }
if (!hash || item.Hash !== hash) { if (!oldHash || item.Hash !== oldHash) {
if (folder.fullName === FolderUserStore.currentFolderFullName()) { if (folder.fullName === FolderUserStore.currentFolderFullName()) {
MessagelistUserStore.reload(); MessagelistUserStore.reload();
} }

View file

@ -3,7 +3,7 @@ import { AbstractCollectionModel } from 'Model/AbstractCollection';
import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { isArray, getKeyByValue, forEachObjectEntry, b64EncodeJSONSafe } from 'Common/Utils'; import { isArray, getKeyByValue, forEachObjectEntry, b64EncodeJSONSafe } from 'Common/Utils';
import { ClientSideKeyNameExpandedFolders, FolderType, FolderMetadataKeys } from 'Common/EnumsUser'; import { ClientSideKeyNameExpandedFolders, FolderType, FolderMetadataKeys } from 'Common/EnumsUser';
import { getFolderFromCacheList, setFolder, setFolderInboxName, setFolderHash } from 'Common/Cache'; import { getFolderFromCacheList, setFolder, setFolderInboxName } from 'Common/Cache';
import { Settings, SettingsGet, fireEvent } from 'Common/Globals'; import { Settings, SettingsGet, fireEvent } from 'Common/Globals';
import * as Local from 'Storage/Client'; import * as Local from 'Storage/Client';
@ -138,13 +138,24 @@ export class FolderCollectionModel extends AbstractCollectionModel
let oCacheFolder = getFolderFromCacheList(oFolder.FullName), let oCacheFolder = getFolderFromCacheList(oFolder.FullName),
type = FolderType[getKeyByValue(SystemFolders, oFolder.FullName)]; type = FolderType[getKeyByValue(SystemFolders, oFolder.FullName)];
if (!oCacheFolder) { if (oCacheFolder) {
// oCacheFolder.revivePropertiesFromJson(oFolder);
if (oFolder.Hash) {
oCacheFolder.hash = oFolder.Hash;
}
if (null != oFolder.totalEmails) {
oCacheFolder.totalEmails(oFolder.totalEmails);
}
if (null != oFolder.unreadEmails) {
oCacheFolder.unreadEmails(oFolder.unreadEmails);
}
} else {
oCacheFolder = FolderModel.reviveFromJson(oFolder); oCacheFolder = FolderModel.reviveFromJson(oFolder);
if (!oCacheFolder) if (!oCacheFolder)
return null; return null;
if (1 == type) { if (1 == type) {
oCacheFolder.type(FolderType.Inbox); oCacheFolder.type(type);
setFolderInboxName(oFolder.FullName); setFolderInboxName(oFolder.FullName);
} }
setFolder(oCacheFolder); setFolder(oCacheFolder);
@ -158,18 +169,6 @@ export class FolderCollectionModel extends AbstractCollectionModel
|| !isArray(expandedFolders) || !isArray(expandedFolders)
|| !expandedFolders.includes(oCacheFolder.fullName)); || !expandedFolders.includes(oCacheFolder.fullName));
if (oFolder.Hash) {
setFolderHash(oCacheFolder.fullName, oFolder.Hash);
}
if (null != oFolder.totalEmails) {
oCacheFolder.totalEmails(oFolder.totalEmails);
}
if (null != oFolder.unreadEmails) {
oCacheFolder.unreadEmails(oFolder.unreadEmails);
}
return oCacheFolder; return oCacheFolder;
}); });
@ -240,8 +239,9 @@ export class FolderModel extends AbstractModel {
this.exists = true; this.exists = true;
// this.hash = ''; this.hash = '';
// this.uidNext = 0; // this.id = null;
this.uidNext = null;
this.addObservables({ this.addObservables({
name: '', name: '',

View file

@ -2,8 +2,7 @@ import { AbstractCollectionModel } from 'Model/AbstractCollection';
import { MessageModel } from 'Model/Message'; import { MessageModel } from 'Model/Message';
import { import {
MessageFlagsCache, MessageFlagsCache
hasNewMessageAndRemoveFromCache
} from 'Common/Cache'; } from 'Common/Cache';
'use strict'; 'use strict';
@ -34,16 +33,10 @@ export class MessageCollectionModel extends AbstractCollectionModel
* @returns {MessageCollectionModel} * @returns {MessageCollectionModel}
*/ */
static reviveFromJson(object, cached) { static reviveFromJson(object, cached) {
let newCount = 0;
return super.reviveFromJson(object, message => { return super.reviveFromJson(object, message => {
message = MessageModel.reviveFromJson(message); message = MessageModel.reviveFromJson(message);
if (message) { if (message) {
if (hasNewMessageAndRemoveFromCache(message.folder, message.uid) && 5 >= newCount) {
++newCount;
}
message.deleted(false); message.deleted(false);
cached ? MessageFlagsCache.initMessage(message) : MessageFlagsCache.store(message); cached ? MessageFlagsCache.initMessage(message) : MessageFlagsCache.store(message);
return message; return message;
} }

View file

@ -1,8 +1,6 @@
import { pString, pInt, b64EncodeJSONSafe } from 'Common/Utils'; import { pString, pInt, b64EncodeJSONSafe } from 'Common/Utils';
import { import {
getFolderHash,
getFolderUidNext,
getFolderFromCacheList getFolderFromCacheList
} from 'Common/Cache'; } from 'Common/Cache';
@ -25,13 +23,14 @@ class RemoteUserFetch extends AbstractFetchRemote {
messageList(fCallback, params, bSilent = false) { messageList(fCallback, params, bSilent = false) {
const const
sFolderFullName = pString(params.Folder), sFolderFullName = pString(params.Folder),
folderHash = getFolderHash(sFolderFullName); folder = getFolderFromCacheList(sFolderFullName),
folderHash = (folder && folder.hash) || '';
params = Object.assign({ params = Object.assign({
Offset: 0, Offset: 0,
Limit: SettingsUserStore.messagesPerPage(), Limit: SettingsUserStore.messagesPerPage(),
Search: '', Search: '',
UidNext: getFolderUidNext(sFolderFullName), // Used to check for new messages UidNext: (folder && folder.uidNext) || 0, // Used to check for new messages
Sort: FolderUserStore.sortMode(), Sort: FolderUserStore.sortMode(),
Hash: folderHash + SettingsGet('AccountHash') Hash: folderHash + SettingsGet('AccountHash')
}, params); }, params);

View file

@ -8,12 +8,9 @@ import { addObservablesTo, addComputablesTo } from 'External/ko';
import { import {
getFolderInboxName, getFolderInboxName,
addNewMessageCache,
setFolderUidNext,
getFolderFromCacheList, getFolderFromCacheList,
setFolderHash, setFolderHash,
MessageFlagsCache, MessageFlagsCache
clearNewMessageCache
} from 'Common/Cache'; } from 'Common/Cache';
import { mailBox } from 'Common/Links'; import { mailBox } from 'Common/Links';
@ -114,45 +111,40 @@ MessagelistUserStore.hasCheckedOrSelected = koComputable(() =>
|| MessagelistUserStore.find(item => item.checked())) || MessagelistUserStore.find(item => item.checked()))
).extend({ rateLimit: 50 }); ).extend({ rateLimit: 50 });
MessagelistUserStore.initUidNextAndNewMessages = (folder, uidNext, newMessages) => { MessagelistUserStore.notifyNewMessages = (folder, newMessages) => {
if (getFolderInboxName() === folder && uidNext) { if (getFolderInboxName() === folder && arrayLength(newMessages)) {
if (arrayLength(newMessages)) {
newMessages.forEach(item => addNewMessageCache(folder, item.Uid));
NotificationUserStore.playSoundNotification(); NotificationUserStore.playSoundNotification();
const len = newMessages.length; const len = newMessages.length;
if (3 < len) { if (3 < len) {
NotificationUserStore.displayDesktopNotification(
AccountUserStore.email(),
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
COUNT: len
}),
{ Url: mailBox(newMessages[0].Folder) }
);
} else {
newMessages.forEach(item => {
NotificationUserStore.displayDesktopNotification( NotificationUserStore.displayDesktopNotification(
AccountUserStore.email(), EmailCollectionModel.reviveFromJson(item.From).toString(),
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', { item.subject,
COUNT: len { Folder: item.Folder, Uid: item.Uid }
}),
{ Url: mailBox(newMessages[0].Folder) }
); );
} else { });
newMessages.forEach(item => {
NotificationUserStore.displayDesktopNotification(
EmailCollectionModel.reviveFromJson(item.From).toString(),
item.subject,
{ Folder: item.Folder, Uid: item.Uid }
);
});
}
} }
setFolderUidNext(folder, uidNext);
} }
} }
/** /**
* @param {boolean=} bDropPagePosition = false * @param {boolean=} bDropPagePosition = false
* @param {boolean=} bDropCurrenFolderCache = false * @param {boolean=} bDropCurrentFolderCache = false
*/ */
MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrenFolderCache = false) => { MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrentFolderCache = false) => {
let iOffset = (MessagelistUserStore.page() - 1) * SettingsUserStore.messagesPerPage(); let iOffset = (MessagelistUserStore.page() - 1) * SettingsUserStore.messagesPerPage();
if (bDropCurrenFolderCache) { if (bDropCurrentFolderCache) {
setFolderHash(FolderUserStore.currentFolderFullName(), ''); setFolderHash(FolderUserStore.currentFolderFullName(), '');
} }
@ -189,9 +181,10 @@ MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrenFolderCache
folder = getFolderFromCacheList(collection.Folder), folder = getFolderFromCacheList(collection.Folder),
folderInfo = collection.FolderInfo; folderInfo = collection.FolderInfo;
if (folder && !bCached) { if (folder && !bCached) {
// folder.revivePropertiesFromJson(result);
folder.expires = Date.now(); folder.expires = Date.now();
folder.uidNext = folderInfo.UidNext;
setFolderHash(collection.Folder, collection.FolderHash); folder.hash = collection.FolderHash;
if (null != folderInfo.totalEmails) { if (null != folderInfo.totalEmails) {
folder.totalEmails(folderInfo.totalEmails); folder.totalEmails(folderInfo.totalEmails);
@ -213,7 +206,7 @@ MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrenFolderCache
}); });
folder.permanentFlags(folderInfo.PermanentFlags); folder.permanentFlags(folderInfo.PermanentFlags);
MessagelistUserStore.initUidNextAndNewMessages(folder.fullName, folderInfo.UidNext, collection.NewMessages); MessagelistUserStore.notifyNewMessages(folder.fullName, collection.NewMessages);
} }
MessagelistUserStore.count(collection.MessageResultCount); MessagelistUserStore.count(collection.MessageResultCount);
@ -238,8 +231,6 @@ MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrenFolderCache
MessagelistUserStore(collection); MessagelistUserStore(collection);
MessagelistUserStore.isIncomplete(false); MessagelistUserStore.isIncomplete(false);
clearNewMessageCache();
if (folder && (bCached || unreadCountChange || SettingsUserStore.useThreads())) { if (folder && (bCached || unreadCountChange || SettingsUserStore.useThreads())) {
rl.app.folderInformation(folder.fullName, collection); rl.app.folderInformation(folder.fullName, collection);
} }
@ -341,19 +332,24 @@ MessagelistUserStore.removeMessagesFromList = (
messages.forEach(item => item && item.isUnseen() && ++unseenCount); messages.forEach(item => item && item.isUnseen() && ++unseenCount);
if (fromFolder && !copy) { if (fromFolder) {
fromFolder.totalEmails( fromFolder.hash = '';
0 <= fromFolder.totalEmails() - uidForRemove.length ? fromFolder.totalEmails() - uidForRemove.length : 0 if (!copy) {
); fromFolder.totalEmails(
0 <= fromFolder.totalEmails() - uidForRemove.length ? fromFolder.totalEmails() - uidForRemove.length : 0
if (0 < unseenCount) {
fromFolder.unreadEmails(
0 <= fromFolder.unreadEmails() - unseenCount ? fromFolder.unreadEmails() - unseenCount : 0
); );
if (0 < unseenCount) {
fromFolder.unreadEmails(
0 <= fromFolder.unreadEmails() - unseenCount ? fromFolder.unreadEmails() - unseenCount : 0
);
}
} }
} }
if (toFolder) { if (toFolder) {
toFolder.hash = '';
if (trashFolder === toFolder.fullName || spamFolder === toFolder.fullName) { if (trashFolder === toFolder.fullName || spamFolder === toFolder.fullName) {
unseenCount = 0; unseenCount = 0;
} }
@ -385,14 +381,6 @@ MessagelistUserStore.removeMessagesFromList = (
} }
} }
if (fromFolderFullName) {
setFolderHash(fromFolderFullName, '');
}
if (toFolderFullName) {
setFolderHash(toFolderFullName, '');
}
if (MessagelistUserStore.threadUid()) { if (MessagelistUserStore.threadUid()) {
if ( if (
messageList.length && messageList.length &&

View file

@ -1,5 +1,4 @@
import { i18n, getNotification } from 'Common/Translator'; import { i18n, getNotification } from 'Common/Translator';
import { setFolderHash } from 'Common/Cache';
import { MessageUserStore } from 'Stores/User/Message'; import { MessageUserStore } from 'Stores/User/Message';
import { MessagelistUserStore } from 'Stores/User/Messagelist'; import { MessagelistUserStore } from 'Stores/User/Messagelist';
@ -45,8 +44,7 @@ export class FolderClearPopupView extends AbstractViewPopup {
folderToClear.totalEmails(0); folderToClear.totalEmails(0);
folderToClear.unreadEmails(0); folderToClear.unreadEmails(0);
folderToClear.hash = '';
setFolderHash(folderToClear.fullName, '');
Remote.request('FolderClear', iError => { Remote.request('FolderClear', iError => {
this.clearingProcess(false); this.clearingProcess(false);

View file

@ -3,7 +3,7 @@ import ko from 'ko';
import { Scope } from 'Common/Enums'; import { Scope } from 'Common/Enums';
import { moveAction, addShortcut } from 'Common/Globals'; import { moveAction, addShortcut } from 'Common/Globals';
import { mailBox, settings } from 'Common/Links'; import { mailBox, settings } from 'Common/Links';
import { setFolderHash } from 'Common/Cache'; //import { setFolderHash } from 'Common/Cache';
import { addComputablesTo } from 'External/ko'; import { addComputablesTo } from 'External/ko';
import { AppUserStore } from 'Stores/User/App'; import { AppUserStore } from 'Stores/User/App';
@ -100,11 +100,11 @@ export class MailFolderList extends AbstractViewLeft {
if (!SettingsUserStore.usePreviewPane()) { if (!SettingsUserStore.usePreviewPane()) {
MessageUserStore.message(null); MessageUserStore.message(null);
} }
/*
if (folder.fullName === FolderUserStore.currentFolderFullName()) { if (folder.fullName === FolderUserStore.currentFolderFullName()) {
setFolderHash(folder.fullName, ''); setFolderHash(folder.fullName, '');
} }
*/
hasher.setHash( hasher.setHash(
mailBox(folder.fullNameHash, 1, mailBox(folder.fullNameHash, 1,
(event.target.matches('.flag-icon') && !folder.isFlagged()) ? 'flagged' : '' (event.target.matches('.flag-icon') && !folder.isFlagged()) ? 'flagged' : ''