[Pkg-mozext-maintainers] Bug#1082115: bookworm-pu: package mailmindr/1.7.1-1~deb12u1

Mechtilde Stehmann mechtilde at debian.org
Wed Sep 18 15:13:12 BST 2024


Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: mailmindr at packages.debian.org, mechtilde at debian.org
Control: affects -1 + src:mailmindr
User: release.debian.org at packages.debian.org
Usertags: pu

[ Reason ]
Thunderbird will come with a new version (>=128.2.x) into stable. This need an
update for the Add-Ons (here: mailmindr) too

[ Impact ]
If the update isn't approved the user can't anymore use it
in recent thunderbird

[ Tests ]
The same upstream code works with thunderbird >= 128.2 in testing.

[ Risks ]
code is trivial so no risk

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
The new version of thunderbird needs a new version of webext-mailmindr.

[ Other info ]
The only reason is the new upcomming version of the thunderbird.
-------------- next part --------------
diffstat for mailmindr-1.4.0 mailmindr-1.7.1

 _locales/de/messages.json                         |   36 
 _locales/en/messages.json                         |   80 +
 api/messages.js                                   |  147 --
 debian/changelog                                  |   31 
 debian/control                                    |    5 
 debian/copyright                                  |    4 
 images/mailmindr-flag--rainbow-shadow.svg         |  201 ---
 images/mailmindr-flag_marker--white.svg           |   87 +
 images/mailmindr-flag_marker.svg                  |   87 +
 manifest.json                                     |   48 
 modules/core-utils.mjs.js                         |  206 ++-
 modules/defaults.mjs.js                           |   37 
 modules/logger.mjs.js                             |   47 
 modules/message-actions.mjs.js                    |  187 ++
 modules/message-utils.mjs.js                      |  135 +-
 modules/storage.mjs.js                            |    2 
 modules/store/actions/actionTypes.mjs.js          |   16 
 modules/store/actions/actions.mjs.js              |   91 +
 modules/store/actions/executeMindr.mjs.js         |  215 +++
 modules/store/actions/heartBeat.mjs.js            |   49 
 modules/store/actions/index.mjs.js                |    7 
 modules/store/actions/setReplyReceived.mjs.js     |   24 
 modules/store/actions/showMindrAlert.mjs.js       |  105 +
 modules/store/actions/snoozeMindrs.mjs.js         |   29 
 modules/store/reducers/createOrUpdateDraft.mjs.js |   33 
 modules/store/reducers/createOrUpdateMindr.mjs.js |   26 
 modules/store/reducers/index.mjs.js               |  216 +++
 modules/store/reducers/removeMindr.mjs.js         |   52 
 modules/store/selectors/index.mjs.js              |   68 +
 modules/store/state-manager.mjs.js                |  142 ++
 modules/string-utils.mjs.js                       |    2 
 modules/ui-utils.mjs.js                           |  136 +-
 schema.json                                       |   20 
 scripts/mailmindr-background.js                   | 1465 +++++++---------------
 scripts/mailmindr-message-script.js               |   23 
 views/dialogs/create-mindr/index.css              |   27 
 views/dialogs/create-mindr/index.js               |  114 -
 views/dialogs/mindr-alert/index.js                |   22 
 views/options/index.html                          |   19 
 views/options/index.js                            |   43 
 views/popups/create-outgoing-mindr/index.css      |  173 ++
 views/popups/create-outgoing-mindr/index.html     |   73 +
 views/popups/create-outgoing-mindr/index.js       |  417 ++++++
 views/popups/list-all/index.css                   |   59 
 views/popups/list-all/index.html                  |   19 
 views/popups/list-all/index.js                    |   90 +
 46 files changed, 3563 insertions(+), 1552 deletions(-)

diff -Nru mailmindr-1.4.0/api/messages.js mailmindr-1.7.1/api/messages.js
--- mailmindr-1.4.0/api/messages.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/api/messages.js	1970-01-01 01:00:00.000000000 +0100
@@ -1,147 +0,0 @@
-var { ExtensionCommon } = ChromeUtils.import(
-    'resource://gre/modules/ExtensionCommon.jsm'
-);
-
-var { ExtensionParent } = ChromeUtils.import(
-    'resource://gre/modules/ExtensionParent.jsm'
-);
-
-var extension = ExtensionParent.GlobalManager.getExtension(
-    'mailmindr at arndissler.net'
-);
-
-const { XPCOMUtils } = ChromeUtils.import(
-    'resource://gre/modules/XPCOMUtils.jsm'
-);
-
-const { MailUtils } = ChromeUtils.import('resource:///modules/MailUtils.jsm');
-
-XPCOMUtils.defineLazyModuleGetters(this, {
-    MailServices: 'resource:///modules/MailServices.jsm',
-    Services: 'resource://gre/modules/Services.jsm'
-    // 
-});
-
-var mailmindrMessagesApi = class extends ExtensionCommon.ExtensionAPI {
-    getAPI(context) {
-        return {
-            // 
-            mailmindrMessagesApi: {
-                openMessageByMessageHeaderId: async function(headerMessageId) {
-                    const msgId = headerMessageId
-                        .replace('>', '')
-                        .replace('<', '')
-                        .trim();
-
-                    try {
-                        if (MailUtils.openMessageByMessageId) {
-                            MailUtils.openMessageByMessageId(msgId);
-                        } else {
-                            const getFirstMessageHeaderForMessageId = (
-                                msgId,
-                                startServer
-                            ) => {
-                                console.warn(
-                                    `MailUtils.openMessageByMessageId doesn't exist, using fallback to manual traveral`
-                                );
-
-                                const findMsgIdInFolder = (msgId, folder) => {
-                                    let msgHdr;
-                                    // 
-                                    if (!folder.isServer) {
-                                        msgHdr = folder.msgDatabase.getMsgHdrForMessageID(
-                                            msgId
-                                        );
-                                        if (msgHdr) {
-                                            return msgHdr;
-                                        }
-                                    }
-
-                                    // 
-                                    for (let currentFolder of folder.subFolders) {
-                                        msgHdr = findMsgIdInFolder(
-                                            msgId,
-                                            currentFolder
-                                        );
-                                        if (msgHdr) {
-                                            return msgHdr;
-                                        }
-                                    }
-                                    return null;
-                                };
-
-                                let allServers =
-                                    MailServices.accounts.allServers;
-                                if (startServer) {
-                                    allServers = [startServer].concat(
-                                        allServers.filter(
-                                            s => s.key != startServer.key
-                                        )
-                                    );
-                                }
-                                for (let server of allServers) {
-                                    if (
-                                        server &&
-                                        server.canSearchMessages &&
-                                        !server.isDeferredTo
-                                    ) {
-                                        let msgHdr = findMsgIdInFolder(
-                                            msgId,
-                                            server.rootFolder
-                                        );
-                                        if (msgHdr) {
-                                            return msgHdr;
-                                        }
-                                    }
-                                }
-                                return null;
-                            };
-
-                            let msgHdr = null;
-                            if (MailUtils.getMsgHdrForMsgId) {
-                                msgHdr = MailUtils.getMsgHdrForMsgId(msgId);
-                            } else {
-                                console.warn(
-                                    `MailUtils.getMsgHdrForMsgId doesn't exist, falling back to manual traversal to find msgHdr`
-                                );
-                                msgHdr = getFirstMessageHeaderForMessageId(
-                                    msgId
-                                );
-                            }
-
-                            if (msgHdr) {
-                                if (MailUtils.displayMessage) {
-                                    MailUtils.displayMessage(msgHdr);
-                                } else {
-                                    console.error(
-                                        `MailUtils.displayMessage doesn't exist, no fallback available (${navigator &&
-                                            navigator.userAgent})`
-                                    );
-                                }
-                            } else {
-                                console.warn(
-                                    `No headers found for msgId: '${msgId}'`
-                                );
-                            }
-                        }
-                    } catch (e) {
-                        console.error(
-                            '[mailmindr] mailmindrMessagesApi.openMessageByMessageHeaderId: ',
-                            e
-                        );
-                    }
-                }
-            }
-        };
-    }
-
-    onShutdown(isAppShutdown) {
-        if (isAppShutdown) {
-            return;
-        }
-
-        // 
-
-        Services.obs.notifyObservers(null, 'startupcache-invalidate', null);
-    }
-};
diff -Nru mailmindr-1.4.0/debian/changelog mailmindr-1.7.1/debian/changelog
--- mailmindr-1.4.0/debian/changelog	2022-09-24 20:08:36.000000000 +0200
+++ mailmindr-1.7.1/debian/changelog	2024-09-18 16:00:14.000000000 +0200
@@ -1,3 +1,34 @@
+mailmindr (1.7.1-1~deb12u1) bookworm; urgency=medium
+
+  * Prepared for bookworm proposed-update
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Wed, 18 Sep 2024 16:00:14 +0200
+
+mailmindr (1.7.1-1) unstable; urgency=medium
+
+  [ Mechtilde ]
+  * [c69b29d] New upstream version 1.7.1
+  * [c0d7293] Bumped version of dependencies in d/control
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Sun, 01 Sep 2024 16:26:31 +0200
+
+mailmindr (1.6.1-1) unstable; urgency=medium
+
+  [ Mechtilde ]
+  * [919abc8] New upstream version 1.6.1
+  * [1891988] Bumped standard version - no changes needed;
+              bumpd version of dependency
+  * [f1ea3a7] Bumped year in d/copyright
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Wed, 15 May 2024 17:26:47 +0200
+
+mailmindr (1.6.0-1) unstable; urgency=medium
+
+  [ Mechtilde ]
+  * [534d272] New upstream version 1.6.0
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Tue, 03 Oct 2023 18:07:14 +0200
+
 mailmindr (1.4.0-1) unstable; urgency=medium
 
   [ Mechtilde ]
diff -Nru mailmindr-1.4.0/debian/control mailmindr-1.7.1/debian/control
--- mailmindr-1.4.0/debian/control	2022-09-24 20:04:02.000000000 +0200
+++ mailmindr-1.7.1/debian/control	2024-09-01 15:02:05.000000000 +0200
@@ -4,7 +4,7 @@
 Maintainer: Debian Mozilla Extension Maintainers <pkg-mozext-maintainers at lists.alioth.debian.org>
 Uploaders: Mechtilde Stehmann <mechtilde at debian.org>
 Build-Depends: debhelper-compat (=13), zip
-Standards-Version: 4.6.1
+Standards-Version: 4.7.0
 Rules-Requires-Root: no
 Vcs-Git: https://salsa.debian.org/webext-team/mailmindr.git
 Vcs-Browser: https://salsa.debian.org/webext-team/mailmindr
@@ -13,7 +13,8 @@
 Package: webext-mailmindr
 Architecture: all
 Depends: ${misc:Depends}
- , thunderbird (>=1:102.2)
+ , thunderbird (>=1:110.10)
+ , thunderbird (<= 1:129.x)
 Description: Reminder for emails
  mailmindr is an addon for the email client "Mozilla Thunderbird".
  It offers additional functionality to handle the everyday work
diff -Nru mailmindr-1.4.0/debian/copyright mailmindr-1.7.1/debian/copyright
--- mailmindr-1.4.0/debian/copyright	2022-09-24 20:02:40.000000000 +0200
+++ mailmindr-1.7.1/debian/copyright	2024-05-15 17:16:01.000000000 +0200
@@ -3,11 +3,11 @@
 Source: https://mailmindr.net/
 
 Files: *
-Copyright: 2013-2022 Arnd I?ler
+Copyright: 2013-2024 Arnd I?ler
 License:   MPL-2
 
 Files: debian/*
-Copyright: 2019-2022 Mechtilde Stehmann <mechtilde at debian.org>
+Copyright: 2019-2024 Mechtilde Stehmann <mechtilde at debian.org>
 License:   MPL-2
 
 License: MPL-2
diff -Nru mailmindr-1.4.0/images/mailmindr-flag_marker.svg mailmindr-1.7.1/images/mailmindr-flag_marker.svg
--- mailmindr-1.4.0/images/mailmindr-flag_marker.svg	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/images/mailmindr-flag_marker.svg	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="160"
+   height="160"
+   viewBox="0 0 42.333332 42.333332"
+   version="1.1"
+   id="svg8"
+   inkscape:version="1.0.2 (e86c8708, 2021-01-15)"
+   sodipodi:docname="mailmindr-flag.svg"
+   inkscape:export-filename="/Users/arndissler/mailmindr-flag.png"
+   inkscape:export-xdpi="96"
+   inkscape:export-ydpi="96">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.3558361"
+     inkscape:cx="184.86935"
+     inkscape:cy="43.23945"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     inkscape:document-rotation="0"
+     showgrid="true"
+     inkscape:pagecheckerboard="false"
+     units="px"
+     inkscape:window-width="1464"
+     inkscape:window-height="1113"
+     inkscape:window-x="120"
+     inkscape:window-y="66"
+     inkscape:window-maximized="0">
+    <inkscape:grid
+       type="xygrid"
+       id="grid833"
+       spacingx="2.6458333"
+       spacingy="2.6458333"
+       snapvisiblegridlinesonly="true"
+       empspacing="4" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+       x="0"
+       y="44.979168"
+       id="text896"><tspan
+         sodipodi:role="line"
+         id="tspan894"
+         x="0"
+         y="44.979168"
+         style="stroke-width:0.264583" /></text>
+    <path
+       style="fill:#ad3bff;stroke:#0c0c0c;stroke-width:3.0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 10.583333,37.041666 c 0,-29.1041661 0,-29.1041661 0,-29.1041661 h 19.402778 l -4.850695,7.2760411 4.850695,7.276042 H 10.583333"
+       id="path872" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="zzz" />
+</svg>
diff -Nru mailmindr-1.4.0/images/mailmindr-flag_marker--white.svg mailmindr-1.7.1/images/mailmindr-flag_marker--white.svg
--- mailmindr-1.4.0/images/mailmindr-flag_marker--white.svg	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/images/mailmindr-flag_marker--white.svg	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="160"
+   height="160"
+   viewBox="0 0 42.333332 42.333332"
+   version="1.1"
+   id="svg8"
+   inkscape:version="1.0.2 (e86c8708, 2021-01-15)"
+   sodipodi:docname="mailmindr-flag.svg"
+   inkscape:export-filename="/Users/arndissler/mailmindr-flag.png"
+   inkscape:export-xdpi="96"
+   inkscape:export-ydpi="96">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.3558361"
+     inkscape:cx="184.86935"
+     inkscape:cy="43.23945"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     inkscape:document-rotation="0"
+     showgrid="true"
+     inkscape:pagecheckerboard="false"
+     units="px"
+     inkscape:window-width="1464"
+     inkscape:window-height="1113"
+     inkscape:window-x="120"
+     inkscape:window-y="66"
+     inkscape:window-maximized="0">
+    <inkscape:grid
+       type="xygrid"
+       id="grid833"
+       spacingx="2.6458333"
+       spacingy="2.6458333"
+       snapvisiblegridlinesonly="true"
+       empspacing="4" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+       x="0"
+       y="44.979168"
+       id="text896"><tspan
+         sodipodi:role="line"
+         id="tspan894"
+         x="0"
+         y="44.979168"
+         style="stroke-width:0.264583" /></text>
+    <path
+       style="fill:#ad3bff;stroke:#f9f9fa;stroke-width:3.0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 10.583333,37.041666 c 0,-29.1041661 0,-29.1041661 0,-29.1041661 h 19.402778 l -4.850695,7.2760411 4.850695,7.276042 H 10.583333"
+       id="path872" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="zzz" />
+</svg>
diff -Nru mailmindr-1.4.0/images/mailmindr-flag--rainbow-shadow.svg mailmindr-1.7.1/images/mailmindr-flag--rainbow-shadow.svg
--- mailmindr-1.4.0/images/mailmindr-flag--rainbow-shadow.svg	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/images/mailmindr-flag--rainbow-shadow.svg	1970-01-01 01:00:00.000000000 +0100
@@ -1,201 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="160"
-   height="160"
-   viewBox="0 0 42.333332 42.333332"
-   version="1.1"
-   id="svg8"
-   inkscape:version="1.0.2 (e86c8708, 2021-01-15)"
-   sodipodi:docname="mailmindr-flag--rainbow-shadow.svg"
-   inkscape:export-filename="/Users/arndissler/mailmindr-flag--rainbow-shadow.png"
-   inkscape:export-xdpi="285"
-   inkscape:export-ydpi="285">
-  <defs
-     id="defs2">
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient861">
-      <stop
-         style="stop-color:#9400ff;"
-         offset="0"
-         id="stop875" />
-      <stop
-         style="stop-color:#ad3bff;"
-         offset="1"
-         id="stop877" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient861"
-       id="linearGradient863"
-       x1="-0.66145998"
-       y1="21.166666"
-       x2="42.994793"
-       y2="21.166666"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(1.125,0,0,1.125,-5.2916666,-5.2916666)" />
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="8.5227625"
-     inkscape:cx="22.992513"
-     inkscape:cy="122.66854"
-     inkscape:document-units="mm"
-     inkscape:current-layer="layer1"
-     inkscape:document-rotation="0"
-     showgrid="true"
-     inkscape:pagecheckerboard="false"
-     units="px"
-     inkscape:window-width="1733"
-     inkscape:window-height="1202"
-     inkscape:window-x="1438"
-     inkscape:window-y="81"
-     inkscape:window-maximized="0">
-    <inkscape:grid
-       type="xygrid"
-       id="grid833"
-       spacingx="2.6458333"
-       spacingy="2.6458333"
-       snapvisiblegridlinesonly="true"
-       empspacing="4" />
-  </sodipodi:namedview>
-  <metadata
-     id="metadata5">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1">
-    <rect
-       style="fill:url(#linearGradient863);fill-opacity:1;stroke:none;stroke-width:1.48828"
-       id="rect32"
-       width="47.625"
-       height="47.625"
-       x="-5.2916665"
-       y="-5.2916665" />
-    <path
-       id="rect928-0"
-       style="fill:#8000d7;fill-opacity:1;stroke:none;stroke-width:1.40479"
-       d="M 21.166666,24.870834 49.179345,52.475994 36.840754,63.987328 8.8280779,36.382168 8.9946579,24.711111 Z"
-       sodipodi:nodetypes="cccccc" />
-    <path
-       id="rect928-0-1-4"
-       style="fill:#6200a4;fill-opacity:1;stroke:none;stroke-width:0.272986"
-       d="m 10.790166,34.395833 10.3765,10.583333 -2.323503,2.308367 -10.3764971,-10.583332 0.031366,-2.340398 z"
-       sodipodi:nodetypes="cccccc" />
-    <path
-       id="rect928"
-       style="fill:#8000d7;fill-opacity:1;stroke:none;stroke-width:1.32292"
-       d="M 31.75,5.8208333 58.298387,31.652372 47.227728,43.030251 20.679343,17.198715 20.525733,5.9744453 Z"
-       sodipodi:nodetypes="cccccc" />
-    <path
-       id="rect928-0-1"
-       style="fill:#6200a4;fill-opacity:1;stroke:none;stroke-width:1.32141"
-       d="M 23.8125,13.229166 49.347141,40.024992 38.100038,51.198834 12.565399,24.403009 12.717243,13.074126 Z"
-       sodipodi:nodetypes="cccccc" />
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
-       x="0"
-       y="44.979168"
-       id="text896"><tspan
-         sodipodi:role="line"
-         id="tspan894"
-         x="0"
-         y="44.979168"
-         style="stroke-width:0.264583" /></text>
-    <path
-       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.16237;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-       d="M 7.4839361,21.166667 19.579163,7.9374999"
-       id="path960" />
-    <path
-       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.16237;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-       d="M 20.183933,21.166667 32.279181,7.9374999"
-       id="path978" />
-    <path
-       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.16237;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-       d="M 24.417271,21.166667 36.512541,7.9374999"
-       id="path984" />
-    <g
-       id="g1022">
-      <path
-         id="path869"
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fc0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77953;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
-         d="M 46.248047 34 L 46 34.271484 L 46 51.984375 L 62.414062 34.03125 L 62.378906 34 L 46.248047 34 z "
-         transform="scale(0.26458333)" />
-      <path
-         id="path962"
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77953;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 62.246094 34 L 46 51.767578 L 46 69.482422 L 78.410156 34.03125 L 78.375 34 L 62.246094 34 z "
-         transform="scale(0.26458333)" />
-      <path
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.16237;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 11.717268,21.166667 23.812495,7.9374999"
-         id="path966" />
-      <path
-         id="path968"
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77953;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 78.25 34 L 46 69.269531 L 46 76 L 56.042969 76 L 94.40625 34.03125 L 94.373047 34 L 78.25 34 z "
-         transform="scale(0.26458333)" />
-      <path
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.16237;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 15.950601,21.166667 28.045831,7.9374999"
-         id="path972" />
-      <path
-         id="path974"
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77953;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 94.246094 34 L 55.873047 75.966797 L 55.910156 76 L 72.041016 76 L 89.246094 57.181641 L 88 55 L 100 34 L 94.246094 34 z "
-         transform="scale(0.26458333)" />
-      <path
-         id="path980"
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77953;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 89.171875 57.048828 L 71.876953 75.966797 L 71.914062 76 L 88.044922 76 L 95.400391 67.951172 L 89.171875 57.048828 z "
-         transform="scale(0.26458333)" />
-      <path
-         id="path986"
-         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#800080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77953;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
-         d="M 95.324219 67.818359 L 87.873047 75.966797 L 87.910156 76 L 100 76 L 95.324219 67.818359 z "
-         transform="scale(0.26458333)" />
-    </g>
-    <path
-       style="fill:none;stroke:#0c0c0c;stroke-width:3.969;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 10.583333,36.512499 c 0,-29.1041658 0,-29.1041658 0,-29.1041658 h 19.402778 l -4.850695,7.2760408 4.850695,7.276042 H 10.583333"
-       id="path872" />
-    <path
-       id="rect928-1"
-       style="fill:#8000d7;fill-opacity:1;stroke:none;stroke-width:1.32292"
-       d="M 60.854164,-18.520833 H 97.895832 V -2.6458333 H 60.854166 l -7.9375,-7.9374997 z"
-       sodipodi:nodetypes="cccccc" />
-    <path
-       id="rect928-4"
-       style="fill:#8000d7;fill-opacity:1;stroke:none;stroke-width:0.364777"
-       d="m 72.152807,35.111142 7.222192,7.222191 -3.095224,3.095225 -7.222192,-7.222191 v -3.095225 z"
-       sodipodi:nodetypes="cccccc" />
-  </g>
-  <g
-     inkscape:groupmode="layer"
-     id="layer2"
-     inkscape:label="zzz" />
-</svg>
diff -Nru mailmindr-1.4.0/_locales/de/messages.json mailmindr-1.7.1/_locales/de/messages.json
--- mailmindr-1.4.0/_locales/de/messages.json	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/_locales/de/messages.json	2024-08-04 22:14:20.000000000 +0200
@@ -17,6 +17,25 @@
     "mailmindrMessageDisplayButton": {
         "message": "Wiedervorlage"
     },
+    "mailmindrComposeMessageButton": {
+        "message": "Wiedervorlage setzen"
+    },
+    "mailmindrComposeMessageButton.edit": {
+        "message": "Wiedervorlage bearbeiten"
+    },
+    "mailmindrComposeMessageButton.detailed": {
+        "message": "$DATE$ um $TIME$",
+        "placeholders": {
+            "date": {
+                "content": "$1",
+                "example": "2021-12-24"
+            },
+            "time": {
+                "content": "$2",
+                "example": "09:00"
+            }
+        }
+    },
     "module.string-utils.chunk.and": {
         "message": "und"
     },
@@ -380,6 +399,12 @@
     "view.options.default-action-preset.description": {
         "message": "Voreingestellte Aktion bei der Erstellung einer Wiedervorlage"
     },
+    "view.options.default-reminder-preset.label": {
+        "message": "Standard-Erinnerung:"
+    },
+    "view.options.default-reminder-preset.description": {
+        "message": "Voreingestellte Zeit, wann an eine Wiedervorlage im Voraus erinnert werden soll."
+    },
     "view.options.snooze-time.label": {
         "message": "Schlummerfunktion:",
         "description": "Default snooze time for alerts"
@@ -476,6 +501,9 @@
     "view.message-display.notification.button.edit": {
         "message": "Wiedervorlage bearbeiten"
     },
+    "view.message-display.notification.button.remove": {
+        "message": "Wiedervorlage entfernen"
+    },
     "view.message-display.notification.button.message": {
         "message": "Eine Wiedervorlage ist gesetzt: $1"
     },
@@ -529,7 +557,7 @@
     "mailmindr.utils.core.timePair": {
         "message": "#1 #2"
     },
-    "mailmindr.utils.core.relative.weeks": {
+    "mailmindr.utils.core.relative.weeks.one": {
         "message": "in einer Woche;in #1 Wochen"
     },
     "mailmindr.utils.core.relative.days": {
@@ -592,5 +620,11 @@
     },
     "mailmindr.utils.core.remindme.before.no-reminder.other": {
         "message": "Keine Erinnerung"
+    },
+    "mailmindrShortcut_OpenList": {
+        "message": "Liste mit den Wiedervorlagen ?ffnen"
+    },
+    "mailmindrShortcut_SetFollowUp": {
+        "message": "Wiedervorlage setzen"
     }
 }
diff -Nru mailmindr-1.4.0/_locales/en/messages.json mailmindr-1.7.1/_locales/en/messages.json
--- mailmindr-1.4.0/_locales/en/messages.json	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/_locales/en/messages.json	2024-08-04 22:14:20.000000000 +0200
@@ -17,6 +17,25 @@
     "mailmindrMessageDisplayButton": {
         "message": "Follow-Up"
     },
+    "mailmindrComposeMessageButton": {
+        "message": "Set follow-up"
+    },
+    "mailmindrComposeMessageButton.edit": {
+        "message": "Edit follow-up"
+    },
+    "mailmindrComposeMessageButton.detailed": {
+        "message": "$DATE$ at $TIME$",
+        "placeholders": {
+            "date": {
+                "content": "$1",
+                "example": "2021-12-24"
+            },
+            "time": {
+                "content": "$2",
+                "example": "09:00"
+            }
+        }
+    },
     "module.string-utils.chunk.and": {
         "message": "and"
     },
@@ -380,6 +399,12 @@
     "view.options.default-action-preset.description": {
         "message": "Pre-selected action setting when creating a new reminder"
     },
+    "view.options.default-reminder-preset.label": {
+        "message": "Default reminder:"
+    },
+    "view.options.default-reminder-preset.description": {
+        "message": "Pre-selected time for when the reminder dialog appears"
+    },
     "view.options.snooze-time.label": {
         "message": "Snooze time in Minutes:",
         "description": "Default snooze time for alerts"
@@ -476,9 +501,58 @@
     "view.message-display.notification.button.edit": {
         "message": "Edit follow-up"
     },
+    "view.message-display.notification.button.remove": {
+        "message": "Remove follow-up"
+    },
     "view.message-display.notification.button.message": {
         "message": "Follow-up is set for $1"
     },
+
+    "view.dialog.create-outgoing-mindr.title.create": {
+        "message": "Create reminder"
+    },
+    "view.dialog.create-outgoing-mindr.title.edit": {
+        "message": "Edit reminder"
+    },
+    "view.dialog.create-outgoing-mindr.label.subject": {
+        "message": "Subject:"
+    },
+    "view.dialog.create-outgoing-mindr.label.due": {
+        "message": "Reply until:"
+    },
+    "view.dialog.create-outgoing-mindr.label.action": {
+        "message": "Action:"
+    },
+    "view.dialog.create-outgoing-mindr.label.icebox": {
+        "message": "Move to icebox folder"
+    },
+    "view.dialog.create-outgoing-mindr.label.icebox.placeholder": {
+        "message": "move to icebox folder: $FOLDERNAME$",
+        "placeholders": {
+            "foldername": {
+                "content": "$1",
+                "example": "Inbox"
+            }
+        }
+    },
+    "view.dialog.create-outgoing-mindr.label.remind-me": {
+        "message": "Remind me:"
+    },
+    "view.dialog.create-outgoing-mindr.caption.remove-follow-up": {
+        "message": "Remove follow-up"
+    },
+    "view.dialog.create-outgoing-mindr.caption.create-mindr": {
+        "message": "Create"
+    },
+    "view.dialog.create-outgoing-mindr.caption.update-mindr": {
+        "message": "Update"
+    },
+    "view.dialog.create-outgoing-mindr.caption.cancel": {
+        "message": "Cancel"
+    },
+    "view.dialog.create-outgoing-mindr.header": {
+        "message": "Set follow-up"
+    },
     "mailmindr.utils.core.plural.beforestart.minutes.one": {
         "message": "$1 minute before due",
         "description": "Menu entry, e.g. '1 minute before due'"
@@ -592,5 +666,11 @@
     },
     "mailmindr.utils.core.remindme.before.no-reminder.other": {
         "message": "No reminder"
+    },
+    "mailmindrShortcut_OpenList": {
+        "message": "Open follow-up list"
+    },
+    "mailmindrShortcut_SetFollowUp": {
+        "message": "Set follow-up"
     }
 }
diff -Nru mailmindr-1.4.0/manifest.json mailmindr-1.7.1/manifest.json
--- mailmindr-1.4.0/manifest.json	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/manifest.json	2024-08-04 22:14:20.000000000 +0200
@@ -6,13 +6,13 @@
     "applications": {
         "gecko": {
             "id": "mailmindr at arndissler.net",
-            "strict_min_version": "78.0",
-            "strict_max_version": "103.0"
+            "strict_min_version": "102.0",
+            "strict_max_version": "129.*"
         }
     },
     "author": "Arnd Issler",
     "homepage_url": "https://mailmindr.net/",
-    "version": "1.4.0",
+    "version": "1.7.1",
     "icons": {
         "16": "images/mailmindr-flag--rainbow.svg",
         "32": "images/mailmindr-flag--rainbow.svg"
@@ -20,15 +20,33 @@
     "permissions": [
         "activeTab",
         "accountsRead",
+        "compose",
         "menus",
         "messagesModify",
         "messagesMove",
         "messagesRead",
+        "messagesUpdate",
         "storage",
         "tabs",
-        "tabHide",
         "unlimitedStorage"
     ],
+    "compose_action": {
+        "browser_style": true,
+        "default_title": "__MSG_mailmindrComposeMessageButton__",
+        "default_popup": "views/popups/create-outgoing-mindr/index.html",
+        "theme_icons": [
+            {
+                "dark": "images/mailmindr-flag.svg",
+                "light": "images/mailmindr-flag--white.svg",
+                "size": 16
+            },
+            {
+                "dark": "images/mailmindr-flag.svg",
+                "light": "images/mailmindr-flag--white.svg",
+                "size": 32
+            }
+        ]
+    },
     "browser_action": {
         "browser_style": true,
         "default_title": "__MSG_mailmindrMainToolbarButton__",
@@ -77,7 +95,8 @@
                 "mac": "Command+Shift+1",
                 "chromeos": "Ctrl+Shift+1",
                 "linux": "Ctrl+Shift+1"
-            }
+            },
+            "description": "__MSG_mailmindrShortcut_SetFollowUp__"
         },
         "mailmindr_open_list": {
             "suggested_key": {
@@ -85,23 +104,8 @@
                 "mac": "Command+Shift+0",
                 "chromeos": "Ctrl+Shift+0",
                 "linux": "Ctrl+Shift+0"
-            }
-        }
-    },
-    "experiment_apis": {
-        "mailmindrMessagesApi": {
-            "schema": "schema.json",
-            "parent": {
-                "scopes": [
-                    "addon_parent"
-                ],
-                "paths": [
-                    [
-                        "mailmindrMessagesApi"
-                    ]
-                ],
-                "script": "api/messages.js"
-            }
+            },
+            "description": "__MSG_mailmindrShortcut_OpenList__"
         }
     }
 }
diff -Nru mailmindr-1.4.0/modules/core-utils.mjs.js mailmindr-1.7.1/modules/core-utils.mjs.js
--- mailmindr-1.4.0/modules/core-utils.mjs.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/modules/core-utils.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -5,7 +5,42 @@
 } from './string-utils.mjs.js';
 import { createLogger } from './logger.mjs.js';
 
-const logger = createLogger('core-utils');
+const logger = createLogger('modules/core-utils');
+
+export const throttle = (func, interval) => {
+    let shouldFire = true;
+    return () => {
+        if (shouldFire) {
+            func();
+            shouldFire = false;
+            setTimeout(() => {
+                shouldFire = true;
+            }, interval);
+        }
+    };
+};
+
+export const sanitizeHeaderMessageId = headerMessageId =>
+    headerMessageId
+        .replace('>', '')
+        .replace('<', '')
+        .trim();
+
+export const sendConnectionMessageEx = async (
+    openConnections,
+    message,
+    connectionName
+) => {
+    logger.info(`open connections?`, openConnections, 'send message', message);
+    const connection = openConnections.find(con => con.name === connectionName);
+    if (connection) {
+        await connection.postMessage(message);
+    } else {
+        logger.warn(
+            `No connection found in ${openConnections.length} open connections`
+        );
+    }
+};
 
 /**
  * Finds the currently running Thunderbird version
@@ -33,7 +68,8 @@
 export const buildQueryInfoForMessageAndFolder = (messageDetails, folder) => {
     const { headerMessageId, author, subject: _ } = messageDetails;
     const queryInfo = {
-        headerMessageId: headerMessageId.substr(1, headerMessageId.length - 2),
+        // 
+        headerMessageId: sanitizeHeaderMessageId(headerMessageId),
         author: getMailAddress(author),
         folder: {
             accountId: folder.accountId,
@@ -64,7 +100,8 @@
  * @returns {boolean} `true` if the mindrs are the same by `headerMessageId` and (internal) `guid`
  */
 export const isSameMindr = (mindrA, mindrB) =>
-    mindrA.headerMessageId === mindrB.headerMessageId &&
+    sanitizeHeaderMessageId(mindrA.headerMessageId) ===
+        sanitizeHeaderMessageId(mindrB.headerMessageId) &&
     mindrA.guid === mindrB.guid;
 
 export const createMailmindrId = scope =>
@@ -80,6 +117,20 @@
 export const isExecuted = mindr => mindr.isExecuted;
 
 /**
+ * Returns true when a mindr is waiting for a reply
+ * @param {Mindr} mindr
+ * @returns Boolean
+ */
+export const hasReply = mindr =>
+    mindr.isWaitingForReply &&
+    mindr.metaData &&
+    'string' === typeof mindr.metaData.replyHeaderMessageId;
+
+export const showReminderForMindr = mindr =>
+    String(mindr.remindMeMinutesBefore) !== '-1' ||
+    mindr.action.showReminder !== false;
+
+/**
  * Checks if a indr is overdue
  * @param {Mindr} mindr
  * @returns {boolean}
@@ -282,6 +333,20 @@
     return actionTemplates;
 };
 
+export const createRemindMeMinutesBefore = () => {
+    const remindMeMinutesBefore = [
+        { minutes: 0, display: 0, unit: 'on-time' },
+        { minutes: 5, display: 5, unit: 'minutes' },
+        { minutes: 15, display: 15, unit: 'minutes' },
+        { minutes: 30, display: 30, unit: 'minutes' },
+        { minutes: 60, display: 1, unit: 'hours' },
+        { minutes: 120, display: 2, unit: 'hours' },
+        { minutes: 240, display: 4, unit: 'hours' },
+        { minutes: -1, display: null, unit: 'no-reminder' }
+    ];
+    return remindMeMinutesBefore;
+};
+
 /**
  * Extracts the email address of an email author
  * @param {string} author The author of an email message, might be an email address or in format Firstname Surname <email at example.com>
@@ -304,7 +369,9 @@
     return author;
 };
 
-export const createMindrFromActionTemplate = async mindrData => {
+export const createMindrFromActionTemplate = async (
+    /** @type {Mindr} */ mindrData
+) => {
     const {
         guid,
         headerMessageId,
@@ -313,7 +380,8 @@
         due,
         remindMeMinutesBefore,
         metaData,
-        isExecuted = false
+        isExecuted = false,
+        isWaitingForReply = false
     } = mindrData;
     const {
         flag,
@@ -346,7 +414,8 @@
         notes,
         metaData,
         isExecuted,
-        modified
+        modified,
+        isWaitingForReply
     };
 };
 
@@ -434,6 +503,10 @@
     }
 
     const { accountId, name, path, type } = folder;
+    if (!accountId) {
+        return null;
+    }
+
     const account = await browser.accounts.get(accountId);
     const identityEmailAddressList = account.identities.map(
         identity => identity.email
@@ -465,8 +538,13 @@
         }
     }
 
+    if (accountId) {
+        // 
+        return { accountId, name, path, type };
+    }
+
     // 
-    return { accountId, name, path, type };
+    return null;
 };
 
 export const genericFoldersAreEqual = (a, b) =>
@@ -516,7 +594,7 @@
     const { due, remindMeMinutesBefore } = mindr;
     const dueTime = due.getTime();
     const minutesBefore = remindMeMinutesBefore; // Math.max(remindMeMinutesBefore, 0);
-    console.warn(`* minutes before: ${minutesBefore}`);
+    // 
     const reminderLookahead = (minutesBefore || lookeahedInMinutes) * 60 * 1000;
     const remindMeAt = dueTime - reminderLookahead;
 
@@ -563,58 +641,6 @@
     }, seed);
 };
 
-export const snoozeMindrs = async (
-    dispatch,
-    mindrGuidList,
-    mindrs,
-    snoozeTimeMinutes,
-    correlationId
-) => {
-    do {
-        const guid = mindrGuidList.pop();
-        const theMindr = mindrs.find(mindr => mindr.guid === guid);
-
-        if (theMindr) {
-            const mindr = { ...theMindr };
-            const { due, isExecuted, remindMeMinutesBefore } = mindr;
-            // 
-            // 
-
-            const dueTime = due.getTime();
-            const now = Date.now();
-
-            if (dueTime < now) {
-                logger.log(
-                    `set snooze (from now): ${mindr.remindMeMinutesBefore}`,
-                    { correlationId, mindrGuid: mindr.guid }
-                );
-
-                if (isExecuted) {
-                    mindr.remindMeMinutesBefore =
-                        -1 * (now - dueTime) + (snoozeTimeMinutes || 0);
-                } else {
-                    // 
-                    const diff = Math.floor(
-                        (now + snoozeTimeMinutes * 60 * 1000 - dueTime) /
-                            60 /
-                            1000
-                    );
-                    mindr.remindMeMinutesBefore = -1 * diff;
-                }
-            }
-
-            logger.log(`snoozed by: ${mindr.remindMeMinutesBefore}`, {
-                correlationId,
-                mindrGuid: mindr.guid
-            });
-
-            await dispatch('mindr:create-or-update', mindr);
-        } else {
-            console.log(`ugh: ${theMindr}`);
-        }
-    } while (mindrGuidList.length);
-};
-
 /**
  *
  * @param {string} identityMailAddress
@@ -632,7 +658,9 @@
     );
 
     const isIceboxFolderSet = Boolean(iceboxFolderSettings?.folder);
-    const isDefaultIceboxFolderSet = Boolean(settings?.defaultIceboxFolder);
+    const isDefaultIceboxFolderSet = Boolean(
+        settings?.defaultIceboxFolder?.folder
+    );
 
     logger.info('icebox folder available?', {
         identityMailAddress,
@@ -645,8 +673,62 @@
     }
 
     if (isDefaultIceboxFolderSet) {
-        return await localFolderToGenericFolder(settings.defaultIceboxFolder);
+        return await localFolderToGenericFolder(
+            settings.defaultIceboxFolder.folder
+        );
     }
 
     return null;
 };
+
+/**
+ *
+ * @param {Mindr} mindr
+ * @param { { readonly snoozeTimeMinutes: number; readonly correlationId: string; } } param1
+ * @returns {Mindr}
+ */
+export const snoozeMindr = (
+    mindr,
+    { snoozeTimeMinutes, correlationId = '<correlationId not set>' }
+) => {
+    const /** @type {EditableMindr} */ modifiedMindr = structuredClone(mindr);
+    const { due, isExecuted, remindMeMinutesBefore } = modifiedMindr;
+
+    const dueTime = due.getTime();
+    const now = Date.now();
+
+    // 
+    if (dueTime < now) {
+        const { remindMeMinutesBefore } = modifiedMindr;
+
+        if (isExecuted) {
+            // 
+            // 
+            // 
+
+            if (modifiedMindr.remindMeMinutesBefore < 0) {
+                modifiedMindr.action.showReminder = false;
+            }
+
+            modifiedMindr.remindMeMinutesBefore =
+                // 
+                -1 *
+                Math.floor(
+                    (now - dueTime + snoozeTimeMinutes * 60 * 1000) / 60 / 1000
+                );
+        } else {
+            // 
+
+            modifiedMindr.due = new Date(
+                Date.now() + snoozeTimeMinutes * 60 * 1000
+            );
+        }
+    } else {
+        console.warn(`mindr.remindMeMinutesBefore is not modified`);
+        modifiedMindr.due = new Date(
+            Date.now() + remindMeMinutesBefore * 60 * 1000
+        );
+    }
+
+    return modifiedMindr;
+};
diff -Nru mailmindr-1.4.0/modules/defaults.mjs.js mailmindr-1.7.1/modules/defaults.mjs.js
--- mailmindr-1.4.0/modules/defaults.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/defaults.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,37 @@
+/** @type {MailmindrState} */
+export const initialState = {
+    presets: {
+        actions: [],
+        time: []
+    },
+    settings: {
+        defaultActionPreset: {
+            copyMessageTo: null,
+            moveMessageTo: null,
+            text: null,
+            tagWithLabel: null,
+            flag: null,
+            isSystemAction: false,
+            markUnread: false,
+            showReminder: false
+        },
+        defaultIceboxFolder: '',
+        defaultTimepreset: {
+            days: 0,
+            hours: 0,
+            minutes: 0,
+            isGenerated: true,
+            isRelative: false,
+            isSelectable: false,
+            text: null
+        },
+        iceboxFolders: [],
+        snoozeTime: 15
+    },
+    mindrs: [],
+    active: [],
+    overdue: [],
+    openDialogs: [],
+    openConnections: [],
+    __inExecution: []
+};
diff -Nru mailmindr-1.4.0/modules/logger.mjs.js mailmindr-1.7.1/modules/logger.mjs.js
--- mailmindr-1.4.0/modules/logger.mjs.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/modules/logger.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -44,9 +44,38 @@
         this._connected = false;
         this._retry = true;
         this._buffer = [];
+        this._enabledScopes = [];
 
         console.log(`starting logger for scope '${this.scope}'`);
-        this.tryConnectAndSendBuffer();
+
+        this.getFilterFromStorage().then(enabledScopes => {
+            this._enabledScopes = enabledScopes;
+            let enabled = false;
+            for (let localScope in enabledScopes) {
+                let severityString = enabledScopes[localScope];
+                let severity = LogLevel[severityString] || LogLevel.WARN;
+                if (localScope.indexOf('*') >= 0) {
+                    let theScope = localScope.substring(
+                        0,
+                        localScope.indexOf('*')
+                    );
+                    if (enabled === false) {
+                        const item = this._scopes.find(s =>
+                            s.name.startsWith(theScope)
+                        );
+                        enabled = item !== undefined;
+                    }
+                } else {
+                    if (enabled === false) {
+                        // 
+                        enabled = this._scopes.find(s => s.name === localScope);
+                    }
+                }
+                this._severity = severity;
+            }
+
+            this.tryConnectAndSendBuffer();
+        });
     }
 
     createContextLogger(scope) {
@@ -65,6 +94,18 @@
         }
     }
 
+    async getFilterFromStorage() {
+        try {
+            const { logFilter } = await messenger.storage.local.get(
+                'logFilter'
+            );
+
+            return logFilter;
+        } catch (exception) {
+            return [];
+        }
+    }
+
     async tryConnectAndSendBuffer() {
         let count = 0;
         while (this._connected === false && this._retry) {
@@ -115,6 +156,10 @@
             context
         };
 
+        if (this._severity > severity) {
+            return;
+        }
+
         this.trySend(logItem);
 
         switch (severity) {
diff -Nru mailmindr-1.4.0/modules/message-actions.mjs.js mailmindr-1.7.1/modules/message-actions.mjs.js
--- mailmindr-1.4.0/modules/message-actions.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/message-actions.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,187 @@
+import { createCorrelationId, createLogger } from '../modules/logger.mjs.js';
+import {
+    genericFolderToLocalFolder,
+    getFlatFolderList
+} from '../modules/core-utils.mjs.js';
+import {
+    applyActionToMessageInFolder,
+    doMoveMessageToFolder
+} from './message-utils.mjs.js';
+
+const logger = createLogger('modules/message-actions');
+
+export const executeMindr = async mindr => {
+    const { headerMessageId, metaData, action, guid } = mindr;
+    logger.log(`START executeMindr ${guid} w/ msgHdrId: '${headerMessageId}'`, {
+        guid,
+        headerMessageId
+    });
+    const {
+        author,
+        subject,
+        folderAccountId,
+        folderName,
+        folderPath,
+        folderType,
+        folderAccountIdentityMailAddress
+    } = metaData;
+    const correlationId = createCorrelationId('executeMindr');
+    const executionStart = Date.now();
+    const { copyMessageTo, moveMessageTo } = action;
+
+    const applyAction = async (messageId, action) => {
+        const {
+            flag,
+            markUnread,
+            showReminder,
+            tagWithLabel,
+            copyMessageTo,
+            moveMessageTo
+        } = action;
+        const messageProps = {
+            ...(flag && { flagged: true }),
+            ...(markUnread && { read: false })
+        };
+
+        logger.info(`? apply update to message ${messageId}`, messageProps);
+
+        await messenger.messages.update(messageId, messageProps);
+    };
+
+    const destinationFolder = moveMessageTo
+        ? await genericFolderToLocalFolder(moveMessageTo)
+        : null;
+    const possibleSourceFolder = await genericFolderToLocalFolder({
+        accountId: folderAccountId,
+        path: folderPath,
+        identityEmailAddress: folderAccountIdentityMailAddress
+    });
+    const flatFolderList = await getFlatFolderList();
+    const localFlatFolderList = await Promise.all(
+        flatFolderList
+            .filter(({ type }) => type === 'folder')
+            .map(async ({ folder }) => await genericFolderToLocalFolder(folder))
+    );
+    const folders = [
+        possibleSourceFolder,
+        ...localFlatFolderList.filter(
+            fldr =>
+                fldr.accountId !== possibleSourceFolder.accountId &&
+                fldr.path !== possibleSourceFolder.path
+        )
+    ];
+
+    logger.log(`BEGIN execution of ${mindr.guid}`, {
+        correlationId,
+        guid
+    });
+    const startTime = performance.now();
+
+    const targetFolders = folders;
+
+    let hasError = false;
+    let iterationCount = 0;
+
+    logger.log(`BEGIN targetFolder iteration`, {
+        guid,
+        correlationId,
+        targetFolderCount: (targetFolders || []).length,
+        targetFolders
+    });
+
+    const applyActionToMessage = async (message, messageFolder) => {
+        const { id } = message;
+
+        logger.log(`BEGIN applyActionToMessage`);
+        await applyAction(id, action);
+        logger.log(
+            `Do we have a destination folder? ${
+                destinationFolder ? 'yes' : 'no'
+            }`,
+            destinationFolder
+        );
+        if (destinationFolder) {
+            await doMoveMessageToFolder(
+                message,
+                destinationFolder,
+                correlationId
+            );
+        }
+        logger.log(`END applyActionToMessage`);
+    };
+
+    const applyActionToFirstMessageInFolders = async () => {
+        for await (let folder of targetFolders) {
+            logger.log(` -- executeMindr: folder loop (${folder.name})`, {
+                correlationId,
+                folder
+            });
+
+            try {
+                const actionResult = await applyActionToMessageInFolder(
+                    folder,
+                    { headerMessageId, author },
+                    applyActionToMessage,
+                    true
+                );
+                const { done, value } = await actionResult.next();
+                const success = Boolean(done && value && value.executed);
+                if (success) {
+                    return true;
+                }
+            } catch (ex) {
+                logger.error('ERROR: execute mindr // mailmindr: >> !!', {
+                    correlationId,
+                    guid,
+                    exception: ex
+                });
+                hasError = true;
+            }
+            iterationCount++;
+        }
+        return false;
+    };
+
+    await applyActionToFirstMessageInFolders();
+
+    logger.log(`END targetFolder iteration`, {
+        correlationId,
+        guid,
+        targetFolderCount: (targetFolders || []).length,
+        targetFolders
+    });
+
+    const endTime = performance.now();
+    logger.log(
+        `mailmindr: execution finished in ${endTime - startTime}ms`,
+        moveMessageTo
+    );
+
+    const executionEnd = Date.now();
+    const executionDuration = (executionEnd - executionStart) / 1000;
+
+    if (executionDuration > 3 * 60) {
+        logger.error(
+            `Execution of mindr '${guid}' took more than 180 seconds`,
+            { guid, correlationId, executionDuration }
+        );
+    } else if (executionDuration > 60) {
+        logger.warn(`Execution of mindr '${guid}' took more than 60 seconds`, {
+            guid,
+            correlationId,
+            executionDuration
+        });
+    } else {
+        logger.warn(
+            `Execution of mindr '${guid}' took ${executionDuration} seconds`,
+            { guid, correlationId, executionDuration }
+        );
+    }
+    logger.log(`END execution of ${mindr.guid}`, { correlationId, guid });
+    logger.log(`END executeMindr ${guid} w/ msgHdrId: '${headerMessageId}'`, {
+        guid,
+        headerMessageId
+    });
+
+    return !hasError;
+};
diff -Nru mailmindr-1.4.0/modules/message-utils.mjs.js mailmindr-1.7.1/modules/message-utils.mjs.js
--- mailmindr-1.4.0/modules/message-utils.mjs.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/modules/message-utils.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -1,10 +1,27 @@
 import {
     buildQueryInfoForMessageAndFolder,
-    getMailAddress
+    getMailAddress,
+    sanitizeHeaderMessageId
 } from './core-utils.mjs.js';
 import { createLogger, createCorrelationId } from './logger.mjs.js';
 
-const logger = createLogger('modules.message-utils');
+const logger = createLogger('modules/message-utils');
+
+export const getMessages = async function*(
+    /** @type {messenger.messages.MessageList} */ list
+) {
+    let page = list;
+    for (let message of page.messages) {
+        yield message;
+    }
+
+    while (page.id) {
+        page = await messenger.messages.continueList(page.id);
+        for (let message of page.messages) {
+            yield message;
+        }
+    }
+};
 
 const findMessage = async (
     messages,
@@ -55,9 +72,11 @@
             }
 
             const msgWithHeader = await browser.messages.getFull(id);
-            const msgHdrId0 = msgWithHeader.headers['message-id'][0];
+            const msgHdrId0 = sanitizeHeaderMessageId(
+                msgWithHeader.headers['message-id'][0]
+            );
 
-            if (msgHdrId0 === headerMessageId) {
+            if (msgHdrId0 === sanitizeHeaderMessageId(headerMessageId)) {
                 logger.log(
                     `SUCCESS headerMessageId found: '${headerMessageId}' === '${msgHdrId0}'`
                 );
@@ -106,7 +125,21 @@
         queryInfo
     });
 
-    let queryResult = await messenger.messages.query(queryInfo);
+    let queryResult = null;
+    try {
+        queryResult = await messenger.messages.query(queryInfo);
+    } catch (queryError) {
+        // 
+        queryResult = null;
+        logger.error(`applyActionToMessageInFolder: initial query failed`, {
+            queryError,
+            queryInfo
+        });
+
+        throw queryError;
+
+        return Promise.resolve(null);
+    }
 
     logger.log(`messages query done, result is`, {
         correlationId,
@@ -159,3 +192,95 @@
 
     return Promise.resolve(null);
 }
+
+export const doMoveMessageToFolder = async (
+    message,
+    destinationFolder,
+    parentCorrelationId
+) => {
+    const correlationId = createCorrelationId(
+        'doMoveMessageToFolder',
+        parentCorrelationId
+    );
+    try {
+        const { id } = message;
+        const { accountId, path } = destinationFolder;
+        logger.log(`BEGIN move message ${id}`, {
+            correlationId,
+            message
+        });
+        await messenger.messages.move([id], { accountId, path });
+        logger.log(`END move message ${id}`, {
+            correlationId,
+            message
+        });
+        return true;
+    } catch (error) {
+        logger.error(error, { correlationId });
+        return false;
+    }
+};
+
+export const moveMessageToFolder = async (
+    messageDetails,
+    sourceFolder,
+    targetFolder
+) => {
+    const correlationId = createCorrelationId('moveMessagesToFolder');
+    try {
+        logger.info('moveMessageToFolder target', {
+            correlationId,
+            targetFolder
+        });
+
+        const moveMessageToFolderAction = async (
+            message,
+            _messageSourceFolder
+        ) => {
+            await doMoveMessageToFolder(message, targetFolder, correlationId);
+        };
+
+        logger.info(`BEGIN applying action to folder`, {
+            correlationId,
+            sourceFolder,
+            messageDetails
+        });
+        const actionResult = await applyActionToMessageInFolder(
+            sourceFolder,
+            messageDetails,
+            moveMessageToFolderAction,
+            true
+        );
+        const { done, value } = await actionResult.next();
+
+        // 
+        const success = Boolean(done);
+
+        const logMessage = `moveMessageToFolder : applyActionToMessageInFolder returns { done: ${done}, value: ${value} }`;
+        if (success) {
+            logger.info(logMessage, { correlationId, result: { done, value } });
+        } else {
+            logger.warn(logMessage, { correlationId, result: { done, value } });
+        }
+
+        if (value === null) {
+            logger.error(
+                `moveMessageToFolder : applyActionToMessageInFolder message not found in folder`
+            );
+        }
+
+        logger.info(`END applying action to folder`, {
+            correlationId,
+            sourceFolder,
+            messageDetails
+        });
+    } catch (e) {
+        logger.error(`moveMessageToFolder failed: ${e.message}`, {
+            correlationId,
+            error: e
+        });
+        return false;
+    }
+
+    return true;
+};
diff -Nru mailmindr-1.4.0/modules/storage.mjs.js mailmindr-1.7.1/modules/storage.mjs.js
--- mailmindr-1.4.0/modules/storage.mjs.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/modules/storage.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -1,6 +1,6 @@
 import { createCorrelationId, createLogger } from './logger.mjs.js';
 
-const logger = createLogger('background');
+const logger = createLogger('modules/storage');
 
 const tryParseOrReturnDefault = (content, defaultValue) => {
     if (typeof content === 'object' && content !== null) {
diff -Nru mailmindr-1.4.0/modules/store/actions/actions.mjs.js mailmindr-1.7.1/modules/store/actions/actions.mjs.js
--- mailmindr-1.4.0/modules/store/actions/actions.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/actions.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,91 @@
+import {
+    ACTION__CONNECTION_CLOSE,
+    ACTION__CONNECTION_OPEN,
+    ACTION__DIALOG_CLOSE,
+    ACTION__DIALOG_OPEN,
+    ACTION__HEARTBEAT,
+    ACTION__LOCK_MINDR_FOR_EXECUTION,
+    ACTION__MINDR_CREATE_OR_UPDATE,
+    ACTION__MINDR_CREATE_OR_UPDATE_DRAFT,
+    ACTION__MINDR_REMOVE,
+    ACTION__MINDR_REMOVE_DRAFT,
+    ACTION__PRESET_TIMESPAN_CREATE,
+    ACTION__PRESET_TIMESPAN_REMOVE,
+    ACTION__PRESET_TIMESPAN_UPDATE,
+    ACTION__SETTINGS_UPDATE,
+    ACTION__UNLOCK_MINDR
+} from './actionTypes.mjs.js';
+
+export const heartBeat = () => ({
+    type: ACTION__HEARTBEAT
+});
+
+export const lockMindrForExecution = mindr => ({
+    type: ACTION__LOCK_MINDR_FOR_EXECUTION,
+    payload: { guid: mindr.guid }
+});
+
+export const unlockMindr = mindr => ({
+    type: ACTION__UNLOCK_MINDR,
+    payload: { guid: mindr.guid }
+});
+
+export const createOrUpdateDraft = draft => ({
+    type: ACTION__MINDR_CREATE_OR_UPDATE_DRAFT,
+    payload: draft
+});
+
+export const createOrUpdateMindr = mindr => ({
+    type: ACTION__MINDR_CREATE_OR_UPDATE,
+    payload: { mindr }
+});
+
+export const openDialog = (dialogId, dialogType, details) => ({
+    type: ACTION__DIALOG_OPEN,
+    payload: { dialogId, dialogType, details }
+});
+
+export const closeDialog = dialogId => ({
+    type: ACTION__DIALOG_CLOSE,
+    payload: { dialogId }
+});
+
+export const removeMindr = guid => ({
+    type: ACTION__MINDR_REMOVE,
+    payload: { guid }
+});
+
+export const removeDraft = (/** @type {MindrDraft} */ draft) => ({
+    type: ACTION__MINDR_REMOVE_DRAFT,
+    payload: { draft }
+});
+
+export const connectionOpened = port => ({
+    type: ACTION__CONNECTION_OPEN,
+    payload: { port }
+});
+
+export const connectionClosed = port => ({
+    type: ACTION__CONNECTION_CLOSE,
+    payload: { port }
+});
+
+export const createTimespanPreset = current => ({
+    type: ACTION__PRESET_TIMESPAN_CREATE,
+    payload: { current }
+});
+
+export const updateTimespanPreset = (current, source) => ({
+    type: ACTION__PRESET_TIMESPAN_UPDATE,
+    payload: { current, source }
+});
+
+export const removeTimespanPreset = presets => ({
+    type: ACTION__PRESET_TIMESPAN_REMOVE,
+    payload: { presets }
+});
+
+export const updateSetting = (name, value) => ({
+    type: ACTION__SETTINGS_UPDATE,
+    payload: { name, value }
+});
diff -Nru mailmindr-1.4.0/modules/store/actions/actionTypes.mjs.js mailmindr-1.7.1/modules/store/actions/actionTypes.mjs.js
--- mailmindr-1.4.0/modules/store/actions/actionTypes.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/actionTypes.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,16 @@
+export const ACTION__HEARTBEAT = 'heartbeat';
+export const ACTION__LOCK_MINDR_FOR_EXECUTION = 'state:lock-execution';
+export const ACTION__UNLOCK_MINDR = 'state:unlock-execution';
+export const ACTION__MINDR_CREATE_OR_UPDATE_DRAFT =
+    'mindr:create-or-update-draft';
+export const ACTION__MINDR_CREATE_OR_UPDATE = 'mindr:create-or-update';
+export const ACTION__MINDR_REMOVE = 'mindr:remove';
+export const ACTION__MINDR_REMOVE_DRAFT = 'mindr:remove-draft';
+export const ACTION__SETTINGS_UPDATE = 'setting:update';
+export const ACTION__DIALOG_OPEN = 'dialog:open';
+export const ACTION__DIALOG_CLOSE = 'dialog:close';
+export const ACTION__CONNECTION_OPEN = 'connection:open';
+export const ACTION__CONNECTION_CLOSE = 'connection:close';
+export const ACTION__PRESET_TIMESPAN_CREATE = 'preset:timespan-create';
+export const ACTION__PRESET_TIMESPAN_UPDATE = 'preset:timespan-update';
+export const ACTION__PRESET_TIMESPAN_REMOVE = 'preset:timespan-remove';
diff -Nru mailmindr-1.4.0/modules/store/actions/executeMindr.mjs.js mailmindr-1.7.1/modules/store/actions/executeMindr.mjs.js
--- mailmindr-1.4.0/modules/store/actions/executeMindr.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/executeMindr.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,215 @@
+import {
+    genericFolderToLocalFolder,
+    getFlatFolderList
+} from '../../core-utils.mjs.js';
+import { createCorrelationId, createLogger } from '../../logger.mjs.js';
+import {
+    applyActionToMessageInFolder,
+    doMoveMessageToFolder
+} from '../../message-utils.mjs.js';
+import {
+    lockMindrForExecution,
+    unlockMindr,
+    createOrUpdateMindr
+} from './actions.mjs.js';
+
+const logger = createLogger('modules/store/actions/executeMindr');
+
+export const executeMindr = mindr => async (dispatch, getState) => {
+    const { headerMessageId, metaData, action, guid } = mindr;
+    logger.log(`START executeMindr ${guid} w/ msgHdrId: '${headerMessageId}'`, {
+        guid,
+        headerMessageId
+    });
+
+    dispatch(lockMindrForExecution(mindr));
+
+    const {
+        author,
+        subject,
+        folderAccountId,
+        folderName,
+        folderPath,
+        folderType,
+        folderAccountIdentityMailAddress
+    } = metaData;
+    const correlationId = createCorrelationId('executeMindr');
+    const executionStart = Date.now();
+    const { copyMessageTo, moveMessageTo } = action;
+
+    const applyAction = async (messageId, action) => {
+        const {
+            flag,
+            markUnread,
+            showReminder,
+            tagWithLabel,
+            copyMessageTo,
+            moveMessageTo
+        } = action;
+        const messageProps = {
+            ...(flag && { flagged: true }),
+            ...(markUnread && { read: false })
+        };
+
+        logger.info(`? apply update to message ${messageId}`, messageProps);
+
+        const timeout = new Promise(resolve => setTimeout(resolve, 1000));
+        const updater = messenger.messages.update(messageId, messageProps);
+
+        await Promise.all([updater, timeout]);
+    };
+
+    const destinationFolder = moveMessageTo
+        ? await genericFolderToLocalFolder(moveMessageTo)
+        : null;
+    const possibleSourceFolder = await genericFolderToLocalFolder({
+        accountId: folderAccountId,
+        path: folderPath,
+        identityEmailAddress: folderAccountIdentityMailAddress
+    });
+    const flatFolderList = await getFlatFolderList();
+    const localFlatFolderList = await Promise.all(
+        flatFolderList
+            .filter(({ type }) => type === 'folder')
+            .map(async ({ folder }) => await genericFolderToLocalFolder(folder))
+    );
+    const folders = possibleSourceFolder
+        ? [
+              possibleSourceFolder,
+              ...localFlatFolderList.filter(
+                  fldr =>
+                      fldr.accountId !== possibleSourceFolder.accountId &&
+                      fldr.path !== possibleSourceFolder.path
+              )
+          ]
+        : localFlatFolderList;
+
+    logger.log(`BEGIN execution of ${mindr.guid}`, {
+        correlationId,
+        guid
+    });
+    const startTime = performance.now();
+
+    const targetFolders = folders;
+
+    let hasError = false;
+    let iterationCount = 0;
+
+    logger.log(`BEGIN targetFolder iteration`, {
+        guid,
+        correlationId,
+        targetFolderCount: (targetFolders || []).length,
+        targetFolders
+    });
+
+    const applyActionToMessage = async (message, messageFolder) => {
+        const { id } = message;
+
+        logger.log(`BEGIN applyActionToMessage`);
+        await applyAction(id, action);
+        logger.log(
+            `Do we have a destination folder? ${
+                destinationFolder ? 'yes' : 'no'
+            }`,
+            destinationFolder
+        );
+        if (destinationFolder) {
+            await doMoveMessageToFolder(
+                message,
+                destinationFolder,
+                correlationId
+            );
+        }
+        logger.log(`END applyActionToMessage`);
+    };
+
+    const applyActionToFirstMessageInFolders = async () => {
+        for await (let folder of targetFolders) {
+            logger.log(
+                ` -- executeMindr: folder loop, apply action to message in folder '(${folder.name})'`,
+                {
+                    correlationId,
+                    folder,
+                    targetFolders
+                }
+            );
+
+            try {
+                const actionResult = await applyActionToMessageInFolder(
+                    folder,
+                    { headerMessageId, author },
+                    applyActionToMessage,
+                    true
+                );
+                const { done, value } = await actionResult.next();
+                const success = Boolean(done && value && value.executed);
+                if (success) {
+                    return true;
+                }
+            } catch (ex) {
+                logger.error('ERROR: execute mindr // mailmindr: >> !!', {
+                    correlationId,
+                    guid,
+                    exception: ex
+                });
+                hasError = true;
+            }
+            iterationCount++;
+        }
+        return false;
+    };
+
+    logger.log(`BEFORE applying actions`, { correlationId });
+    await applyActionToFirstMessageInFolders();
+    logger.log(`END applying actions`, { correlationId });
+
+    logger.log(`END targetFolder iteration`, {
+        correlationId,
+        guid,
+        targetFolderCount: (targetFolders || []).length,
+        targetFolders
+    });
+
+    const endTime = performance.now();
+    logger.log(
+        `mailmindr: execution finished in ${endTime - startTime}ms`,
+        moveMessageTo
+    );
+
+    const executionEnd = Date.now();
+    const executionDuration = (executionEnd - executionStart) / 1000;
+
+    if (executionDuration > 3 * 60) {
+        logger.error(
+            `Execution of mindr '${guid}' took more than 180 seconds`,
+            { guid, correlationId, executionDuration }
+        );
+    } else if (executionDuration > 60) {
+        logger.warn(`Execution of mindr '${guid}' took more than 60 seconds`, {
+            guid,
+            correlationId,
+            executionDuration
+        });
+    } else {
+        logger.warn(
+            `Execution of mindr '${guid}' took ${executionDuration} seconds`,
+            { guid, correlationId, executionDuration }
+        );
+    }
+    logger.log(`END execution of ${mindr.guid}`, { correlationId, guid });
+    logger.log(`END executeMindr ${guid} w/ msgHdrId: '${headerMessageId}'`, {
+        guid,
+        headerMessageId
+    });
+
+    const modifiedMindr = structuredClone(mindr);
+    modifiedMindr.isExecuted = true;
+
+    dispatch(unlockMindr(modifiedMindr));
+
+    if (!hasError) {
+        dispatch(createOrUpdateMindr(modifiedMindr));
+    }
+
+    return !hasError;
+};
diff -Nru mailmindr-1.4.0/modules/store/actions/heartBeat.mjs.js mailmindr-1.7.1/modules/store/actions/heartBeat.mjs.js
--- mailmindr-1.4.0/modules/store/actions/heartBeat.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/heartBeat.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,49 @@
+import { isExecuted, showReminderForMindr } from '../../core-utils.mjs.js';
+import { createLogger } from '../../logger.mjs.js';
+import { executeMindr } from './executeMindr.mjs.js';
+import { showMindrAlert } from './index.mjs.js';
+
+const logger = createLogger('modules/store/actions/heartBeat');
+
+export const heartBeatEx = () => async (dispatch, getState) => {
+    const { overdue, active, __inExecution } = getState();
+    const overdueNotExecuted = overdue.filter(item => !item.isExecuted);
+
+    logger.log(`heartBeatEx -- `, { overdue, active, overdueNotExecuted });
+
+    if (Array.isArray(__inExecution) && __inExecution.length > 0) {
+        logger.warn(
+            `Mindr is executing (${__inExecution.length} in total), skipping further executions`,
+            { overdue, active, __inExecution }
+        );
+        return;
+    }
+
+    logger.log(`overdueNotExecuted: `, overdueNotExecuted);
+    for (let mindr of overdueNotExecuted) {
+        dispatch(executeMindr(mindr));
+    }
+
+    // 
+    // 
+    const overdueAndUnexecuted = overdue.filter(
+        mindr => !isExecuted(mindr) && showReminderForMindr(mindr)
+    );
+
+    const activeMindrs = active.filter(showReminderForMindr);
+
+    if (overdueAndUnexecuted.length > 0 || activeMindrs.length > 0) {
+        logger.info(`heartbeat: show dialog with mindrs `, {
+            overdueAndUnexecuted,
+            active: activeMindrs
+        });
+        dispatch(
+            showMindrAlert({
+                overdue: overdueAndUnexecuted,
+                active: activeMindrs
+            })
+        );
+    } else {
+        logger.log('No reason to show a dialog', { overdueAndUnexecuted });
+    }
+};
diff -Nru mailmindr-1.4.0/modules/store/actions/index.mjs.js mailmindr-1.7.1/modules/store/actions/index.mjs.js
--- mailmindr-1.4.0/modules/store/actions/index.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/index.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,7 @@
+export { executeMindr } from './executeMindr.mjs.js';
+export { snoozeMindrs } from './snoozeMindrs.mjs.js';
+export { heartBeatEx } from './heartBeat.mjs.js';
+export { showMindrAlert } from './showMindrAlert.mjs.js';
+export { setReplyReceived } from './setReplyReceived.mjs.js';
+
+export * from './actions.mjs.js';
diff -Nru mailmindr-1.4.0/modules/store/actions/setReplyReceived.mjs.js mailmindr-1.7.1/modules/store/actions/setReplyReceived.mjs.js
--- mailmindr-1.4.0/modules/store/actions/setReplyReceived.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/setReplyReceived.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,24 @@
+import { createLogger } from '../../logger.mjs.js';
+import { createOrUpdateMindr } from './index.mjs.js';
+
+const logger = createLogger('actions/setReplyReceived');
+
+export const setReplyReceived = (
+    /** @type {Mindr} */ theMindr,
+    /** @type {string} */ replyHeaderMessageId
+) => async (dispatch, _getState) => {
+    if (theMindr) {
+        const mindr = structuredClone(theMindr); // { ...theMindr };
+        const modifiedMindr = {
+            ...mindr,
+            /** @type {Mindr['metaData']} */ metaData: {
+                ...mindr.metaData,
+                replyHeaderMessageId
+            }
+        };
+
+        await dispatch(createOrUpdateMindr(modifiedMindr));
+    } else {
+        logger.error(`mindr is not defined: ${theMindr}`);
+    }
+};
diff -Nru mailmindr-1.4.0/modules/store/actions/showMindrAlert.mjs.js mailmindr-1.7.1/modules/store/actions/showMindrAlert.mjs.js
--- mailmindr-1.4.0/modules/store/actions/showMindrAlert.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/showMindrAlert.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,105 @@
+import {
+    createMailmindrId,
+    sendConnectionMessageEx
+} from '../../core-utils.mjs.js';
+import { createLogger } from '../../logger.mjs.js';
+import {
+    selectDialogForType,
+    selectOpenConnections
+} from '../selectors/index.mjs.js';
+import { closeDialog, openDialog } from './actions.mjs.js';
+
+const logger = createLogger('modules/store/actions/showMindrAlert');
+
+export const showMindrAlert = ({ overdue, active }) => async (
+    dispatch,
+    getState
+) => {
+    const dialogType = 'mailmindr:mindr-alert';
+    const state = getState();
+    const openConnections = selectOpenConnections(state);
+
+    const dialogs = (await messenger.tabs.query({})).filter(tab => {
+        if (tab && tab.url) {
+            return tab.url.indexOf('/mindr-alert/') > 0;
+        }
+        return false;
+    });
+    const alertDialog = dialogs && dialogs.length && dialogs[0];
+    const dialog = alertDialog
+        ? { details: { id: alertDialog.windowId, tabId: alertDialog.id } }
+        : null;
+
+    if (dialog) {
+        logger.log('we already have a message dialog', dialog);
+
+        if ((overdue || []).length === 0 && (active || []).length === 0) {
+            logger.log(`no overdue or active mindrs ? we can close the dialog`);
+
+            // 
+            dispatch(closeDialog(dialog.details.id));
+            messenger.windows.remove(dialog.details.id);
+        } else {
+            logger.log(`we have a dialog and send data to it`, {
+                overdue,
+                active
+            });
+
+            // 
+            await sendConnectionMessageEx(
+                openConnections,
+                {
+                    overdue,
+                    active
+                },
+                'connection:mindr-alert'
+            );
+            await messenger.windows.update(dialog.details.id, {
+                focused: false,
+                drawAttention: true
+            });
+        }
+    } else {
+        logger.log(
+            'need to open a new dialog with active/overdue mindrs',
+            active,
+            overdue
+        );
+        if ((active || []).length === 0 && (overdue || []).length === 0) {
+            logger.log('no dialog needed');
+            return;
+        }
+        const dialogId = createMailmindrId('mailmindr:dialog:mindr-alert');
+
+        const parameters = new URLSearchParams();
+        parameters.set('dialogId', dialogId);
+
+        const { width: screenWidth, availHeight: screenHeight } = screen;
+        const height = 200;
+        const width = 400;
+        const left = screenWidth - width;
+        const top = screenHeight - height;
+        const url = `/views/dialogs/mindr-alert/index.html?${parameters}`;
+        const details = await messenger.windows.create({
+            left,
+            top,
+            height,
+            width,
+            url,
+            type: 'popup',
+            state: 'normal',
+            allowScriptsToClose: true
+        });
+
+        await messenger.windows.update(details.id, {
+            top,
+            left,
+            width,
+            height,
+            focused: true,
+            drawAttention: true
+        });
+
+        dispatch(openDialog(dialogId, dialogType, details));
+    }
+};
diff -Nru mailmindr-1.4.0/modules/store/actions/snoozeMindrs.mjs.js mailmindr-1.7.1/modules/store/actions/snoozeMindrs.mjs.js
--- mailmindr-1.4.0/modules/store/actions/snoozeMindrs.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/actions/snoozeMindrs.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,29 @@
+import { snoozeMindr } from '../../core-utils.mjs.js';
+import { createLogger } from '../../logger.mjs.js';
+import { createOrUpdateMindr } from './index.mjs.js';
+
+const logger = createLogger('modules/store/actions/snoozeMindrs');
+
+export const snoozeMindrs = (
+    mindrGuidList,
+    mindrs,
+    snoozeTimeMinutes,
+    correlationId
+) => async (dispatch, getState) => {
+    do {
+        const guid = mindrGuidList.pop();
+        const theMindr = mindrs.find(mindr => mindr.guid === guid);
+
+        if (theMindr) {
+            const mindr = structuredClone(theMindr); // { ...theMindr };
+            const modifiedMindr = snoozeMindr(mindr, {
+                snoozeTimeMinutes,
+                correlationId
+            });
+
+            await dispatch(createOrUpdateMindr(modifiedMindr));
+        } else {
+            logger.log(`ugh: ${theMindr}`);
+        }
+    } while (mindrGuidList.length);
+};
diff -Nru mailmindr-1.4.0/modules/store/reducers/createOrUpdateDraft.mjs.js mailmindr-1.7.1/modules/store/reducers/createOrUpdateDraft.mjs.js
--- mailmindr-1.4.0/modules/store/reducers/createOrUpdateDraft.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/reducers/createOrUpdateDraft.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,33 @@
+import { createLogger } from '../../logger.mjs.js';
+import {
+    ACTION__MINDR_CREATE_OR_UPDATE,
+    ACTION__MINDR_CREATE_OR_UPDATE_DRAFT
+} from '../actions/actionTypes.mjs.js';
+
+const logger = createLogger('reducers/createOrUpdateDraft');
+
+export const createOrUpdateDraftReducer = (
+    /** @type {MailmindrState} */ state,
+    action
+) => {
+    const { type, payload } = action;
+    if (type !== ACTION__MINDR_CREATE_OR_UPDATE_DRAFT) {
+        return state;
+    }
+
+    const { mindr, sender } = payload;
+    const { __drafts: drafts, ...stateWithoutMindrs } = state;
+    const mindrsWithoutUpdatedMindr = (drafts || []).filter(
+        item =>
+            item.sender.id !== sender.id &&
+            item.sender.windowId !== sender.windowId
+    );
+    const updatedDrafts = [...mindrsWithoutUpdatedMindr, payload];
+
+    const localState = {
+        ...stateWithoutMindrs,
+        __drafts: updatedDrafts
+    };
+
+    return localState;
+};
diff -Nru mailmindr-1.4.0/modules/store/reducers/createOrUpdateMindr.mjs.js mailmindr-1.7.1/modules/store/reducers/createOrUpdateMindr.mjs.js
--- mailmindr-1.4.0/modules/store/reducers/createOrUpdateMindr.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/reducers/createOrUpdateMindr.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,26 @@
+import { isSameMindr } from '../../core-utils.mjs.js';
+import { createLogger } from '../../logger.mjs.js';
+import { ACTION__MINDR_CREATE_OR_UPDATE } from '../actions/actionTypes.mjs.js';
+
+const logger = createLogger('modules/store/reducers/createOrUpdateMindr');
+
+export const createOrUpdateMindrReducer = (state, action) => {
+    const { type, payload } = action;
+    if (type !== ACTION__MINDR_CREATE_OR_UPDATE) {
+        return state;
+    }
+
+    const { mindr } = payload;
+    const { mindrs: allMindrs, ...stateWithoutMindrs } = state;
+    const mindrsWithoutUpdatedMindr = allMindrs.filter(
+        item => !isSameMindr(item, mindr)
+    );
+    const mindrs = [...mindrsWithoutUpdatedMindr, mindr];
+
+    const localState = {
+        ...stateWithoutMindrs,
+        mindrs
+    };
+
+    return localState;
+};
diff -Nru mailmindr-1.4.0/modules/store/reducers/index.mjs.js mailmindr-1.7.1/modules/store/reducers/index.mjs.js
--- mailmindr-1.4.0/modules/store/reducers/index.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/reducers/index.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,216 @@
+import {
+    equalTimePresetValues,
+    getActiveAndOverdueMindrs
+} from '../../core-utils.mjs.js';
+import { createLogger } from '../../logger.mjs.js';
+import {
+    ACTION__CONNECTION_CLOSE,
+    ACTION__CONNECTION_OPEN,
+    ACTION__DIALOG_CLOSE,
+    ACTION__DIALOG_OPEN,
+    ACTION__HEARTBEAT,
+    ACTION__LOCK_MINDR_FOR_EXECUTION,
+    ACTION__MINDR_CREATE_OR_UPDATE,
+    ACTION__MINDR_CREATE_OR_UPDATE_DRAFT,
+    ACTION__MINDR_REMOVE,
+    ACTION__MINDR_REMOVE_DRAFT,
+    ACTION__PRESET_TIMESPAN_CREATE,
+    ACTION__PRESET_TIMESPAN_REMOVE,
+    ACTION__PRESET_TIMESPAN_UPDATE,
+    ACTION__SETTINGS_UPDATE,
+    ACTION__UNLOCK_MINDR
+} from '../actions/actionTypes.mjs.js';
+import { selectOpenConnections } from '../selectors/index.mjs.js';
+import { createOrUpdateDraftReducer } from './createOrUpdateDraft.mjs.js';
+import { createOrUpdateMindrReducer } from './createOrUpdateMindr.mjs.js';
+import { removeMindrReducer } from './removeMindr.mjs.js';
+
+const logger = createLogger('modules/store/reducers/root');
+
+const rootReducer = (/** @type {MailmindrState} */ state, action) => {
+    const { type, payload } = action;
+    switch (type) {
+        case ACTION__HEARTBEAT:
+            const { mindrs: mindrList } = state;
+
+            const { mindrs, overdue, active } = getActiveAndOverdueMindrs(
+                mindrList
+            );
+
+            // 
+            // 
+            // 
+
+            return { ...state, mindrs, active, overdue };
+        case ACTION__CONNECTION_OPEN: {
+            const { port } = payload;
+            const openConnections = [...selectOpenConnections(state), port];
+
+            logger.log(
+                `open connections: ${openConnections.length}`,
+                openConnections
+            );
+
+            return { ...state, openConnections };
+        }
+        case ACTION__CONNECTION_CLOSE: {
+            const { port } = payload;
+            const { name } = port;
+            const { openConnections: connections } = state;
+
+            const openConnections = connections.filter(
+                connection => connection.name !== name
+            );
+
+            return { ...state, openConnections };
+        }
+        case ACTION__MINDR_CREATE_OR_UPDATE_DRAFT:
+            return createOrUpdateDraftReducer(state, action);
+        case ACTION__MINDR_CREATE_OR_UPDATE:
+            return createOrUpdateMindrReducer(state, action);
+        case ACTION__MINDR_REMOVE:
+            return removeMindrReducer(state, action);
+        case ACTION__MINDR_REMOVE_DRAFT: {
+            const { /** @type {MindrDraft}*/ draft } = payload;
+            const localState = {
+                ...state,
+                __drafts: state.__drafts.filter(
+                    item =>
+                        item.sender.id !== draft.sender.id &&
+                        item.sender.windowId !== draft.sender.windowId
+                )
+            };
+            return localState;
+        }
+        case ACTION__LOCK_MINDR_FOR_EXECUTION: {
+            // 
+            // 
+            const { guid } = payload;
+
+            const localState = {
+                ...state,
+                __inExecution: [...state.__inExecution, guid]
+            };
+
+            return localState;
+        }
+        case ACTION__UNLOCK_MINDR: {
+            // 
+            const { guid } = payload;
+
+            const localState = {
+                ...state,
+                __inExecution: state.__inExecution.filter(item => item !== guid)
+            };
+
+            return localState;
+        }
+        case ACTION__SETTINGS_UPDATE: {
+            const { name, value } = payload;
+
+            const localState = {
+                ...state,
+                settings: { ...state.settings, [name]: value }
+            };
+
+            return localState;
+        }
+        case ACTION__PRESET_TIMESPAN_CREATE: {
+            const { presets } = state;
+            const { time } = presets;
+            const { current } = payload;
+
+            const localState = {
+                ...state,
+                presets: {
+                    ...presets,
+                    time: [...time, current]
+                }
+            };
+
+            return localState;
+        }
+        case ACTION__PRESET_TIMESPAN_UPDATE: {
+            const { presets } = state;
+            const { time: timePresets } = presets;
+            const { current, source } = payload;
+
+            const time = timePresets.map(item =>
+                equalTimePresetValues(item, source) ? current : item
+            );
+
+            logger.info(`new presets:`, time);
+
+            const newState = {
+                ...state,
+                presets: {
+                    ...presets,
+                    time
+                }
+            };
+
+            return newState;
+        }
+        case ACTION__PRESET_TIMESPAN_REMOVE: {
+            const { presets } = state;
+            const { time: timePresets } = presets;
+            const { presets: toBeRemoved = [] } = payload;
+
+            let time = [...timePresets];
+            toBeRemoved.forEach(toBeRemovedPreset => {
+                time = time.filter(
+                    preset => !equalTimePresetValues(preset, toBeRemovedPreset)
+                );
+            });
+
+            const newState = {
+                ...state,
+                presets: {
+                    ...presets,
+                    time
+                }
+            };
+
+            return newState;
+        }
+        case ACTION__DIALOG_OPEN: {
+            const newDialogDetails = payload;
+            const openDialogs = [...state.openDialogs, newDialogDetails];
+
+            return { ...state, openDialogs };
+        }
+        case ACTION__DIALOG_CLOSE: {
+            const { dialogId } = payload;
+            const { openDialogs: dialogs } = state;
+            const dialogDetails = dialogs.find(
+                dialogInfo => dialogId === dialogInfo.dialogId
+            );
+
+            if (dialogDetails) {
+                const openDialogs = dialogs.filter(
+                    openDialog => openDialog.dialogId !== dialogId
+                );
+                logger.info(`remaining open dialogs: ${openDialogs.length}`);
+                return {
+                    ...state,
+                    openDialogs
+                };
+            } else {
+                logger.warn(
+                    `cannot find details for open dialog ID: '${dialogId}'`,
+                    {
+                        payload,
+                        dialogId,
+                        openDialogs: dialogs
+                    }
+                );
+            }
+
+            return state;
+        }
+        default:
+            return state;
+    }
+};
+
+export default rootReducer;
diff -Nru mailmindr-1.4.0/modules/store/reducers/removeMindr.mjs.js mailmindr-1.7.1/modules/store/reducers/removeMindr.mjs.js
--- mailmindr-1.4.0/modules/store/reducers/removeMindr.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/reducers/removeMindr.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,52 @@
+import { createLogger } from '../../logger.mjs.js';
+import { ACTION__MINDR_REMOVE } from '../actions/actionTypes.mjs.js';
+
+const logger = createLogger('modules/store/reducers/removeMindr');
+
+export const removeMindrReducer = (state, action) => {
+    const { type, payload } = action;
+    if (type !== ACTION__MINDR_REMOVE) {
+        return state;
+    }
+
+    const { guid } = payload;
+    const {
+        mindrs: stateMindrs,
+        overdue: stateOverdue,
+        active: stateActive
+    } = state;
+
+    const mindrCount = {
+        mindrs: (stateMindrs || []).length,
+        overdue: (stateOverdue || []).length,
+        active: (stateActive || []).length
+    };
+
+    logger.log(`mindr to be removed: ${guid}`, { guid, mindrCount });
+
+    // 
+    const mindrs = stateMindrs.filter(item => item.guid !== guid);
+
+    const overdue = (stateOverdue || []).filter(mindr => mindr.guid !== guid);
+    const active = (stateActive || []).filter(mindr => mindr.guid !== guid);
+
+    if (
+        mindrCount.overdue === overdue.length &&
+        mindrCount.active === active.length &&
+        mindrCount.mindrs === mindrs.length
+    ) {
+        // 
+        logger.log(`no mindr was removed, state remains untouched`);
+
+        return state;
+    }
+
+    const localState = {
+        ...state,
+        mindrs,
+        active,
+        overdue
+    };
+
+    return localState;
+};
diff -Nru mailmindr-1.4.0/modules/store/selectors/index.mjs.js mailmindr-1.7.1/modules/store/selectors/index.mjs.js
--- mailmindr-1.4.0/modules/store/selectors/index.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/selectors/index.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,68 @@
+import { sanitizeHeaderMessageId } from '../../core-utils.mjs.js';
+import { createLogger } from '../../logger.mjs.js';
+
+const logger = createLogger('modules/store/selectors');
+
+export const selectMindrs = (/** @type {MailmindrState} */ state) =>
+    state.mindrs || [];
+
+export const selectMindrByGuid = (
+    /** @type {MailmindrState} */ state,
+    guid
+) => {
+    const mindrs = selectMindrs(state);
+    const result = (mindrs || []).find(item => item.guid === guid);
+
+    return result;
+};
+
+export const selectMindrByHeaderMessageId = (
+    /** @type {MailmindrState} */ state,
+    headerMessageId
+) => {
+    const mindrs = selectMindrs(state);
+    const result = (mindrs || []).find(
+        item =>
+            sanitizeHeaderMessageId(item.headerMessageId) ===
+            sanitizeHeaderMessageId(headerMessageId)
+    );
+
+    return result;
+};
+
+export const selectOpenDialogs = (/** @type {MailmindrState} */ state) =>
+    state.openDialogs || [];
+
+export const selectDialogForType = (
+    /** @type {MailmindrState} */ state,
+    dialogType
+) => {
+    const openDialogs = selectOpenDialogs(state);
+    logger.log(selectDialogForType.name, { state, openDialogs });
+    return openDialogs.find(dialog => dialog.dialogType === dialogType);
+};
+
+export const selectSettings = (/** @type {MailmindrState} */ state) =>
+    state.settings;
+
+export const selectPresets = (/** @type {MailmindrState} */ state) =>
+    state.presets;
+
+export const selectOpenConnections = (/** @type {MailmindrState} */ state) =>
+    state.openConnections || [];
+
+export const selectDrafts = (/** @type {MailmindrState} */ state) => {
+    return state.__drafts || [];
+};
+
+export const selectDraftForSenderTabOrNull = (
+    /** @type {MailmindrState} */ state,
+    /** @type {MindrDraft['sender']} */ sender
+) => {
+    const drafts = selectDrafts(state);
+    const result = drafts.find(
+        ({ sender: { id, windowId } }) =>
+            id === sender.id && windowId === sender.windowId
+    );
+    return result || null;
+};
diff -Nru mailmindr-1.4.0/modules/store/state-manager.mjs.js mailmindr-1.7.1/modules/store/state-manager.mjs.js
--- mailmindr-1.4.0/modules/store/state-manager.mjs.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/modules/store/state-manager.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,142 @@
+import { createLogger } from '../logger.mjs.js';
+
+const logger = createLogger('modules/store/state-manager');
+
+export const createStore = (reducer, initialState) => {
+    logger.log(`Initializing state w/ `, { initialState });
+    let localState = initialState;
+    let dispatching = false;
+    let isCorrupt = false;
+    let actions = [];
+    const handlers = {
+        change: new Set()
+    };
+
+    const defaultGetState = function() {
+        if (dispatching) {
+            throw new MailmindrStateError(
+                'Cannot get state while in dispatching mode'
+            );
+        }
+        return localState;
+    };
+
+    const defaultDispatch = function(action) {
+        if (dispatching) {
+            throw new MailmindrStateError(
+                'Cannot update state while state is in dispatching mode'
+            );
+        }
+        try {
+            dispatching = true;
+            logger.log(`? start reduce '${action.type}'`, {
+                localState,
+                action
+            });
+            actions.push({ name: action.type });
+            localState = reducer(localState, action);
+            if (!localState) {
+                logger.error(`Action corrupted the state: ${action.type}`);
+            }
+            if (handlers.change.size) {
+                for (let handler of handlers.change.values()) {
+                    setTimeout(() => handler(localState), 0);
+                }
+            }
+            logger.log(`? end reduce '${action.type}'`, { localState });
+            dispatching = false;
+        } catch (error) {
+            dispatching = false;
+            isCorrupt = true;
+            logger.error(
+                `Something went wrong during dispatching the action '${action.type}'`,
+                {
+                    action,
+                    actions,
+                    error
+                }
+            );
+        }
+
+        return action;
+    };
+
+    const extendedDispatch = function(action) {
+        if (action && action.constructor && action.constructor.name) {
+            const constructorName = action.constructor.name.toLocaleLowerCase();
+            switch (constructorName) {
+                case 'promise':
+                    logger.warn('Promise as action?', action);
+                    return action;
+                case 'asyncfunction':
+                    return new Promise(async (success, failure) => {
+                        try {
+                            const result = await action(
+                                extendedDispatch,
+                                defaultGetState
+                            );
+                            actions.push({
+                                name: `[async] ${action.name}`
+                            });
+                            success(result);
+                        } catch (asyncFunctionError) {
+                            failure(asyncFunctionError);
+                        }
+                    });
+                case 'function':
+                    try {
+                        actions.push({ name: `[func] ${action.name}` });
+                        return action(extendedDispatch, defaultGetState);
+                    } catch (functionError) {
+                        throw new MailmindrStateError(
+                            `Error in function ${action.name}`,
+                            functionError
+                        );
+                    }
+                default:
+                    return defaultDispatch(action);
+            }
+        }
+    };
+
+    let def = {
+        dispatch: extendedDispatch,
+        getState: defaultGetState,
+        addEventListener: (eventName, eventHandler) => {
+            const eventNameNormalized = eventName.toLocaleLowerCase();
+            if (Object.keys(handlers).includes(eventNameNormalized)) {
+                if (handlers[eventNameNormalized].has(eventHandler)) {
+                    logger.warn(`Handler for ${eventName} already defined.`);
+                } else {
+                    handlers[eventNameNormalized].add(eventHandler);
+                }
+            } else {
+                logger.error(
+                    `No event handler for event '${eventNameNormalized}' exist.`
+                );
+            }
+        },
+        removeEventListener: (eventName, eventHandler) => {
+            const eventNameNormalized = eventName.toLocaleLowerCase();
+            if (Object.keys(handlers).includes(eventNameNormalized)) {
+                if (handlers[eventNameNormalized].has(eventHandler)) {
+                    handlers[eventNameNormalized].delete(eventHandler);
+                } else {
+                    logger.warn(`Handler for ${eventName} is not registered.`);
+                }
+            } else {
+                logger.error(
+                    `No event handler for event '${eventNameNormalized}' exist.`
+                );
+            }
+        }
+    };
+
+    return def;
+};
+
+export class MailmindrStateError extends Error {
+    constructor(...args) {
+        super(...args);
+    }
+}
diff -Nru mailmindr-1.4.0/modules/string-utils.mjs.js mailmindr-1.7.1/modules/string-utils.mjs.js
--- mailmindr-1.4.0/modules/string-utils.mjs.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/modules/string-utils.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -1,6 +1,6 @@
 import { createLogger } from './logger.mjs.js';
 
-const logger = createLogger('string-utils');
+const logger = createLogger('modules/string-utils');
 
 const simplePluralize = (num, identifier) => {
     const pluralizer = new Intl.PluralRules(navigator.language, {
diff -Nru mailmindr-1.4.0/modules/ui-utils.mjs.js mailmindr-1.7.1/modules/ui-utils.mjs.js
--- mailmindr-1.4.0/modules/ui-utils.mjs.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/modules/ui-utils.mjs.js	2024-08-04 22:14:20.000000000 +0200
@@ -3,8 +3,9 @@
     equalTimePresetValues
 } from './core-utils.mjs.js';
 import { createLogger } from './logger.mjs.js';
+import { pluralize } from './string-utils.mjs.js';
 
-const logger = createLogger('ui-utils');
+const logger = createLogger('modules/ui-utils');
 
 export const appendI18n = element => {
     if (!element) {
@@ -61,19 +62,135 @@
 };
 
 export const selectDefaultActionPreset = (element, defaultActionPreset) => {
-    const availablePresets = Array.from(element.options)
-        .map(item => ({
-            index: item.index,
-            actionPreset: JSON.parse(item.value)
-        }))
+    const presetsFromOptions = Array.from(element.options).map(item => ({
+        index: item.index,
+        actionPreset: JSON.parse(item.value)
+    }));
+    const availablePresets = presetsFromOptions
         .filter(({ actionPreset }) =>
-            equalActionPresetValues(actionPreset, defaultActionPreset)
+            // 
+            areActionsEqual(actionPreset, defaultActionPreset, true)
         )
         .map(({ index }) => index);
     const selectedIndex = availablePresets.shift() || 0;
+
     element.selectedIndex = selectedIndex;
 };
 
+export const areActionsEqual = (
+    someAction,
+    someOtherAction,
+    ignoreShowReminder = false
+) => {
+    if (!someAction || !someOtherAction) {
+        return false;
+    }
+
+    const props = [
+        'flag',
+        'markUnread',
+        'tagWithLabel',
+        'copyMessageTo',
+        'moveMessageTo',
+        ignoreShowReminder ? void 0 : 'showReminder'
+    ];
+
+    let result = true;
+    props.forEach(prop => {
+        let equal = someAction[prop] === someOtherAction[prop];
+        if (!equal) {
+            logger.info(
+                `prop '${prop}' failed: '${someAction[prop]}' !== '${someOtherAction[prop]}'`
+            );
+            result = result && false;
+        }
+    });
+
+    logger.info(`--- checks: ${result}`);
+    return result;
+};
+
+/**
+ * Selects the index of an action preset from a list of action presets
+ * @param {Array<{ readonly index: number; readonly actionPreset: MailmindrAction }>} list
+ * @param {MailmindrAction} defaultActionPreset
+ */
+export const selectDefaultActionPresetIndexFromList = (
+    list,
+    defaultActionPreset
+) => {
+    const availablePresets = list
+        .filter(({ actionPreset }) =>
+            equalActionPresetValues(actionPreset, defaultActionPreset)
+        )
+        .map(({ index }) => index);
+    const selectedIndex = availablePresets.shift() || 0;
+
+    return selectedIndex;
+};
+
+export const selectDefaultRemindeMeMinutesBeforePreset = (
+    element,
+    presets,
+    selectedRemindMeBeforeValue
+) => {
+    const remindMeMinutesBefore = presets;
+    if (selectedRemindMeBeforeValue !== null) {
+        const selectedIndex = remindMeMinutesBefore.findIndex(
+            item =>
+                parseInt(item.minutes, 10) ===
+                parseInt(selectedRemindMeBeforeValue, 10)
+        );
+        if (selectedIndex >= 0) {
+            element.selectedIndex = selectedIndex;
+        }
+    }
+};
+
+export const createRemindMeBeforePicker = (
+    document,
+    element,
+    presets,
+    selectedRemindMeBeforeValue = null
+) => {
+    const remindMeMinutesBefore = presets;
+    remindMeMinutesBefore.forEach(item => {
+        const option = document.createElement('option');
+        const { minutes, unit, display: displayedValue } = item;
+
+        option.value = String(minutes);
+
+        if (unit === 'on-time') {
+            option.innerText = pluralize(
+                displayedValue,
+                'mailmindr.utils.core.remindme.before.on-time'
+            );
+        } else if (unit === 'minutes') {
+            option.innerText = pluralize(
+                displayedValue,
+                'mailmindr.utils.core.remindme.before.minutes'
+            );
+        } else if (unit === 'hours') {
+            option.innerText = pluralize(
+                displayedValue,
+                'mailmindr.utils.core.remindme.before.hours'
+            );
+        } else if (unit === 'no-reminder') {
+            option.innerText = pluralize(
+                displayedValue,
+                'mailmindr.utils.core.remindme.before.no-reminder'
+            );
+        }
+        element.appendChild(option);
+    });
+
+    selectDefaultRemindeMeMinutesBeforePreset(
+        element,
+        presets,
+        selectedRemindMeBeforeValue
+    );
+};
+
 // 
 // 
 // 
@@ -114,3 +231,8 @@
 export const clearContents = parentElement => {
     Array.from(parentElement.children).forEach(child => child.remove());
 };
+
+export const isDarkMode = () => {
+    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+    return mediaQuery.matches;
+};
diff -Nru mailmindr-1.4.0/schema.json mailmindr-1.7.1/schema.json
--- mailmindr-1.4.0/schema.json	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/schema.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,20 +0,0 @@
-[
-    {
-        "namespace": "mailmindrMessagesApi",
-        "functions": [
-            {
-                "name": "openMessageByMessageHeaderId",
-                "type": "function",
-                "description": "Open message by given messageHeaderId.",
-                "async": true,
-                "parameters": [
-                    {
-                        "name": "messageHeaderId",
-                        "type": "string",
-                        "description": "headerMessageId of the message that should be opened."
-                    }
-                ]
-            }
-        ]
-    }
-]
diff -Nru mailmindr-1.4.0/scripts/mailmindr-background.js mailmindr-1.7.1/scripts/mailmindr-background.js
--- mailmindr-1.4.0/scripts/mailmindr-background.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/scripts/mailmindr-background.js	2024-08-04 22:14:20.000000000 +0200
@@ -2,70 +2,66 @@
 /// <reference types="../../.typings/browser" />
 /// <reference types="../../.typings/mailmindr" />
 import {
-    createMindrFromActionTemplate,
     createMailmindrId,
+    createMindrFromActionTemplate,
+    createRemindMeMinutesBefore,
     createSystemActions,
     createSystemTimespans,
-    localFolderToGenericFolder,
-    isSameMindr,
-    equalTimePresetValues,
+    findThunderbirdVersion,
     genericFolderToLocalFolder,
-    getFlatFolderList,
-    isExecuted,
-    getActiveAndOverdueMindrs,
-    snoozeMindrs,
-    getGenericIceboxFolderForIdentityOrNull
+    getGenericIceboxFolderForIdentityOrNull,
+    localFolderToGenericFolder,
+    sanitizeHeaderMessageId,
+    sendConnectionMessageEx,
+    showReminderForMindr,
+    throttle
 } from '../modules/core-utils.mjs.js';
 import {
     getCurrentStorageAdapterVersion,
     getStorageAdapter
 } from '../modules/storage.mjs.js';
 import { createCorrelationId, createLogger } from '../modules/logger.mjs.js';
-import { applyActionToMessageInFolder } from '../modules/message-utils.mjs.js';
+import { createStore } from '../modules/store/state-manager.mjs.js';
+import { initialState } from '../modules/defaults.mjs.js';
+import {
+    closeDialog,
+    connectionClosed,
+    connectionOpened,
+    createOrUpdateDraft,
+    createOrUpdateMindr,
+    createTimespanPreset,
+    heartBeat,
+    heartBeatEx,
+    openDialog,
+    removeDraft,
+    removeMindr,
+    removeTimespanPreset,
+    setReplyReceived,
+    showMindrAlert,
+    snoozeMindrs,
+    updateSetting,
+    updateTimespanPreset
+} from '../modules/store/actions/index.mjs.js';
+import {
+    selectDialogForType,
+    selectDraftForSenderTabOrNull,
+    selectMindrByGuid,
+    selectMindrByHeaderMessageId,
+    selectMindrs,
+    selectOpenConnections,
+    selectOpenDialogs,
+    selectPresets,
+    selectSettings
+} from '../modules/store/selectors/index.mjs.js';
+import {
+    getMessages,
+    moveMessageToFolder
+} from '../modules/message-utils.mjs.js';
+import rootReducer from '../modules/store/reducers/index.mjs.js';
 
 const logger = createLogger('background');
 
-/** @type {MailmindrState} */
-let state = {
-    presets: {
-        actions: [],
-        time: []
-    },
-    settings: {
-        defaultActionPreset: {
-            copyMessageTo: null,
-            moveMessageTo: null,
-            text: null,
-            tagWithLabel: null,
-            flag: null,
-            isSystemAction: false,
-            markUnread: false,
-            showReminder: false
-        },
-        defaultIceboxFolder: '',
-        defaultTimepreset: {
-            days: 0,
-            hours: 0,
-            minutes: 0,
-            isGenerated: true,
-            isRelative: false,
-            isSelectable: false,
-            text: null
-        },
-        iceboxFolders: [],
-        snoozeTime: 15
-    },
-    mindrs: [],
-    active: [],
-    overdue: [],
-    openDialogs: [],
-    openConnections: [],
-    __inExecution: []
-};
-
-const getState = () => {
-    return state;
-};
+let store; //  = createStore(() => {}, initialState);
 
 const createInitialSettings = (presets, _settings) => ({
     snoozeTime: 15, // 15 minutes is initial default,
@@ -74,23 +70,36 @@
     defaultTimePreset:
         presets.time?.[presets.time?.find(item => item.isSelectable) || 0], // get first preset (if any)
     defaultActionPreset:
-        presets.actions?.[presets.actions?.find(item => item.isSelectable) || 0] // get first preset (if any)
+        presets.actions?.[
+            presets.actions?.find(item => item.isSelectable) || 0
+        ], // get first preset (if any)
+    defaultRemindMeMinutesBefore: 15
 });
 
 const createSystemPresets = () => ({
     time: createSystemTimespans(),
-    actions: createSystemActions()
+    actions: createSystemActions(),
+    remindMeMinutesBefore: createRemindMeMinutesBefore()
 });
 
+const getStorage = async () => {
+    // 
+    const storage = await browser.storage.local.get(null);
+    const storageVersion = storage?.storageVersion || 1;
+
+    // 
+    const { loadState, storeState } = getStorageAdapter(storageVersion);
+    return { loadState, storeState, storageVersion };
+};
+
 const initializeStorage = async () => {
     try {
-        // 
-        const storage = await browser.storage.local.get(null);
-        const persistedStorageVersion = storage?.storageVersion || 1;
-
-        // 
+        const {
+            loadState,
+            storeState,
+            storageVersion: persistedStorageVersion
+        } = await getStorage();
         const storageVersion = getCurrentStorageAdapterVersion();
-        const { loadState, storeState } = getStorageAdapter(storageVersion);
 
         // 
         if (storageVersion > persistedStorageVersion) {
@@ -114,7 +123,8 @@
         // 
         const {
             time: systemGeneratedTimePresets,
-            actions
+            actions,
+            remindMeMinutesBefore
         } = createSystemPresets();
         const defaultSettings = createInitialSettings({
             systemGeneratedTimePresets,
@@ -142,7 +152,8 @@
             settings,
             presets: {
                 time,
-                actions
+                actions,
+                remindMeMinutesBefore
             },
             overdue: [], // can be computed
             active: [], // can be computed
@@ -163,66 +174,13 @@
     }
 };
 
-const getSettings = () => {
-    const { presets, settings } = getState();
-    return { presets, settings };
-};
-
-const onHeartBeat = async () => {
-    const windows = await messenger.windows.getAll({
-        windowTypes: ['normal', 'app']
-    });
-    if (!windows.length) {
-        return;
-    }
-
-    await dispatch('heartbeat');
-
-    const executeOverdueMindrs = async () => {
-        const { overdue, active, __inExecution } = getState();
-        const overdueNotExecuted = overdue.filter(item => !item.isExecuted);
-
-        if (Array.isArray(__inExecution) && __inExecution.length > 0) {
-            logger.warn(
-                `Mindr is executing (${__inExecution.length} in total), skipping further executions`,
-                { overdue, active, __inExecution }
-            );
-            return;
-        }
-
-        for (let mindr of overdueNotExecuted) {
-            const { guid } = mindr;
-            await dispatch('state:lock-execution', { guid });
-            const executed = await executeMindr(mindr);
-            await dispatch('state:unlock-execution', { guid });
-            if (executed) {
-                await dispatch('mindr:create-or-update', {
-                    ...mindr,
-                    isExecuted: true
-                });
-            }
-        }
-    };
-
-    const showAlertDialog = async () => {
-        const { overdue, active } = getState();
-        const overdueAndUnexecuted = overdue.filter(
-            mindr =>
-                !isExecuted(mindr) &&
-                String(mindr.remindMeMinutesBefore) !== '-1'
-        );
-
-        if (overdueAndUnexecuted.length > 0 || active.length > 0) {
-            await showMindrAlert({ overdue: overdueAndUnexecuted, active });
-        }
-    };
-
-    await executeOverdueMindrs();
-    await showAlertDialog();
+const onHeartBeatHandler = async () => {
+    store.dispatch(heartBeat());
+    store.dispatch(heartBeatEx());
 };
 
 const startHeartbeat = () => {
-    setInterval(onHeartBeat, 1000 * 45);
+    setInterval(onHeartBeatHandler, 1000 * 45);
 };
 
 const setMindrForCurrentMessage = async optionalCurrentMessage => {
@@ -247,7 +205,7 @@
             await showCreateOrUpdateMindrDialog(currentMessage, mindr);
         }
     } else {
-        console.warn('?? The current message cannot be determined.');
+        logger.warn('?? The current message cannot be determined.');
     }
 };
 
@@ -255,523 +213,17 @@
     /* intentionally left blank */
 };
 
-const createOrUpdateMindr = async (state, mindr) => {
-    const { mindrs: allMindrs, ...stateWithoutMindrs } = state;
-    const mindrsWithoutUpdatedMindr = allMindrs.filter(
-        item => !isSameMindr(item, mindr)
-    );
-    const mindrs = [...mindrsWithoutUpdatedMindr, mindr];
-
-    const storageVersion = getCurrentStorageAdapterVersion();
-    const { storeState } = getStorageAdapter(storageVersion);
-
-    const localState = {
-        ...stateWithoutMindrs,
-        mindrs
-    };
-
-    await storeState(localState);
-
-    return localState;
-};
-
-const executeMindr = async mindr => {
-    const { headerMessageId, metaData, action, guid } = mindr;
-    logger.log(`START executeMindr ${guid} w/ msgHdrId: '${headerMessageId}'`, {
-        guid,
-        headerMessageId
-    });
-    const {
-        author,
-        subject,
-        folderAccountId,
-        folderName,
-        folderPath,
-        folderType,
-        folderAccountIdentityMailAddress
-    } = metaData;
-    const correlationId = createCorrelationId('executeMindr');
-    const executionStart = Date.now();
-    const { copyMessageTo, moveMessageTo } = action;
-
-    const applyAction = async (messageId, action) => {
-        const {
-            flag,
-            markUnread,
-            showReminder,
-            tagWithLabel,
-            copyMessageTo,
-            moveMessageTo
-        } = action;
-        const messageProps = {
-            ...(flag && { flagged: true }),
-            ...(markUnread && { read: false })
-        };
-
-        logger.info(`? apply update to message ${messageId}`, messageProps);
-
-        await messenger.messages.update(messageId, messageProps);
-    };
-
-    const destinationFolder = moveMessageTo
-        ? await genericFolderToLocalFolder(moveMessageTo)
-        : null;
-    const possibleSourceFolder = await genericFolderToLocalFolder({
-        accountId: folderAccountId,
-        path: folderPath,
-        identityEmailAddress: folderAccountIdentityMailAddress
-    });
-    const flatFolderList = await getFlatFolderList();
-    const localFlatFolderList = await Promise.all(
-        flatFolderList
-            .filter(({ type }) => type === 'folder')
-            .map(async ({ folder }) => await genericFolderToLocalFolder(folder))
-    );
-    const folders = [
-        possibleSourceFolder,
-        ...localFlatFolderList.filter(
-            fldr =>
-                fldr.accountId !== possibleSourceFolder.accountId &&
-                fldr.path !== possibleSourceFolder.path
-        )
-    ];
-
-    logger.log(`BEGIN execution of ${mindr.guid}`, {
-        correlationId,
-        guid
-    });
-    const startTime = performance.now();
-
-    const targetFolders = folders;
-
-    let hasError = false;
-    let iterationCount = 0;
-
-    logger.log(`BEGIN targetFolder iteration`, {
-        guid,
-        correlationId,
-        targetFolderCount: (targetFolders || []).length,
-        targetFolders
-    });
-
-    const applyActionToMessage = async (message, messageFolder) => {
-        const { id } = message;
-
-        logger.log(`BEGIN applyActionToMessage`);
-        await applyAction(id, action);
-        logger.log(
-            `Do we have a destination folder? ${
-                destinationFolder ? 'yes' : 'no'
-            }`,
-            destinationFolder
-        );
-        if (destinationFolder) {
-            await doMoveMessageToFolder(
-                message,
-                destinationFolder,
-                correlationId
-            );
-        }
-        logger.log(`END applyActionToMessage`);
-    };
-
-    const applyActionToFirstMessageInFolders = async () => {
-        for await (let folder of targetFolders) {
-            logger.log(` -- executeMindr: folder loop (${folder.name})`, {
-                correlationId,
-                folder
-            });
-
-            try {
-                const actionResult = await applyActionToMessageInFolder(
-                    folder,
-                    { headerMessageId, author },
-                    applyActionToMessage,
-                    true
-                );
-                const { done, value } = await actionResult.next();
-                const success = Boolean(done && value && value.executed);
-                if (success) {
-                    return true;
-                }
-            } catch (ex) {
-                logger.error('ERROR: execute mindr // mailmindr: >> !!', {
-                    correlationId,
-                    guid,
-                    exception: ex
-                });
-                hasError = true;
-            }
-            iterationCount++;
-        }
-        return false;
-    };
-
-    await applyActionToFirstMessageInFolders();
-
-    logger.log(`END targetFolder iteration`, {
-        correlationId,
-        guid,
-        targetFolderCount: (targetFolders || []).length,
-        targetFolders
-    });
-
-    const endTime = performance.now();
-    logger.log(
-        `mailmindr: execution finished in ${endTime - startTime}ms`,
-        moveMessageTo
-    );
-
-    const executionEnd = Date.now();
-    const executionDuration = (executionEnd - executionStart) / 1000;
-
-    if (executionDuration > 3 * 60) {
-        logger.error(
-            `Execution of mindr '${guid}' took more than 180 seconds`,
-            { guid, correlationId, executionDuration }
-        );
-    } else if (executionDuration > 60) {
-        logger.warn(`Execution of mindr '${guid}' took more than 60 seconds`, {
-            guid,
-            correlationId,
-            executionDuration
-        });
-    } else {
-        logger.warn(
-            `Execution of mindr '${guid}' took ${executionDuration} seconds`,
-            { guid, correlationId, executionDuration }
-        );
-    }
-    logger.log(`END execution of ${mindr.guid}`, { correlationId, guid });
-    logger.log(`END executeMindr ${guid} w/ msgHdrId: '${headerMessageId}'`, {
-        guid,
-        headerMessageId
-    });
-
-    return !hasError;
-};
-
-const dispatch = async (action, payload) => {
-    const correlationId = createCorrelationId('dispatch');
-
-    const getUpdatedState = async (theAction, thePayload) => {
-        const storageVersion = getCurrentStorageAdapterVersion();
-        const { storeState } = getStorageAdapter(storageVersion);
-
-        try {
-            switch (theAction) {
-                case 'heartbeat': {
-                    const { mindrs: mindrList } = getState();
-
-                    const {
-                        mindrs,
-                        overdue,
-                        active
-                    } = getActiveAndOverdueMindrs(mindrList);
-
-                    // 
-                    // 
-                    // 
-
-                    return { ...state, mindrs, active, overdue };
-                }
-                case 'connection:open': {
-                    const { port } = payload;
-
-                    const openConnections = [...state.openConnections, port];
-                    logger.log(
-                        `open connections: ${openConnections.length}`,
-                        openConnections
-                    );
-                    return { ...state, openConnections };
-                }
-                case 'connection:close': {
-                    const { port } = payload;
-                    const { name } = port;
-
-                    const openConnections = getState().openConnections.filter(
-                        connection => connection.name !== name
-                    );
-
-                    return { ...state, openConnections };
-                }
-                case 'dialog:open': {
-                    const newDialogDetails = thePayload;
-                    const openDialogs = [
-                        ...state.openDialogs,
-                        newDialogDetails
-                    ];
-                    return { ...state, openDialogs };
-                }
-                case 'dialog:close': {
-                    const { dialogId } = thePayload;
-                    const { openDialogs: dialogs } = getState();
-                    const dialogDetails = dialogs.find(
-                        dialogInfo => dialogId === dialogInfo.dialogId
-                    );
-                    if (dialogDetails) {
-                        const openDialogs = dialogs.filter(
-                            openDialog => openDialog.dialogId !== dialogId
-                        );
-                        logger.info(
-                            `remaining open dialogs: ${openDialogs.length}`
-                        );
-                        return {
-                            ...state,
-                            openDialogs
-                        };
-                    } else {
-                        logger.warn(
-                            `cannot find details for open dialog ID: '${dialogId}'`,
-                            {
-                                payload: thePayload,
-                                dialogId,
-                                openDialogs: dialogs
-                            }
-                        );
-                    }
-                    return state;
-                }
-                case 'state:initialize':
-                    return await initializeStorage();
-                case 'mindr:create-or-update': {
-                    return await createOrUpdateMindr(state, thePayload);
-                }
-                case 'mindr:remove': {
-                    const { guid } = thePayload;
-                    const currentState = getState();
-                    const {
-                        mindrs: stateMindrs,
-                        overdue: stateOverdue,
-                        active: stateActive
-                    } = currentState;
-
-                    const mindrCount = {
-                        mindrs: (stateMindrs || []).length,
-                        overdue: (stateOverdue || []).length,
-                        active: (stateActive || []).length
-                    };
-
-                    // 
-                    const mindrs = stateMindrs.filter(
-                        item => item.guid !== guid
-                    );
-
-                    const overdue = (stateOverdue || []).filter(
-                        mindr => mindr.guid !== guid
-                    );
-                    const active = (stateActive || []).filter(
-                        mindr => mindr.guid !== guid
-                    );
-
-                    if (
-                        mindrCount.overdue === overdue.length &&
-                        mindrCount.active === active.length &&
-                        mindrCount.mindrs === mindrs.length
-                    ) {
-                        // 
-                        logger.log(
-                            `no mindr was removed, state remains untouched`
-                        );
-
-                        return getState();
-                    }
-
-                    const localState = {
-                        ...currentState,
-                        mindrs,
-                        active,
-                        overdue
-                    };
-
-                    await storeState(localState);
-
-                    return localState;
-                }
-                case 'preset:timespan-create': {
-                    const currentState = getState();
-                    const { presets } = currentState;
-                    const { time } = presets;
-                    const { current } = thePayload;
-
-                    const localState = {
-                        ...currentState,
-                        presets: {
-                            ...presets,
-                            time: [...time, current]
-                        }
-                    };
-
-                    await storeState(localState);
-
-                    return localState;
-                }
-                case 'preset:timespan-update': {
-                    const currentState = getState();
-                    const { presets } = currentState;
-                    const { time: timePresets } = presets;
-                    const { current, source } = thePayload;
-                    const time = timePresets.map(item =>
-                        equalTimePresetValues(item, source) ? current : item
-                    );
-
-                    logger.info(`new presets:`, time);
-
-                    const newState = {
-                        ...currentState,
-                        presets: {
-                            ...presets,
-                            time
-                        }
-                    };
-
-                    await browser.storage.local.set({
-                        presets: newState.presets
-                    });
-
-                    return newState;
-                }
-                case 'preset:timespan-remove': {
-                    const currentState = getState();
-                    const { presets } = currentState;
-                    const { time: timePresets } = presets;
-                    const { presets: toBeRemoved = [] } = thePayload;
-
-                    let time = [...timePresets];
-                    toBeRemoved.forEach(toBeRemovedPreset => {
-                        time = time.filter(
-                            preset =>
-                                !equalTimePresetValues(
-                                    preset,
-                                    toBeRemovedPreset
-                                )
-                        );
-                    });
-
-                    const newState = {
-                        ...currentState,
-                        presets: {
-                            ...presets,
-                            time
-                        }
-                    };
-
-                    await browser.storage.local.set({
-                        presets: newState.presets
-                    });
-
-                    return newState;
-                }
-                case 'setting:update': {
-                    const currentState = getState();
-                    const { name, value } = thePayload;
-
-                    const localState = {
-                        ...currentState,
-                        settings: { ...state.settings, [name]: value }
-                    };
-
-                    await storeState(localState);
-
-                    return localState;
-                }
-                case 'state:lock-execution': {
-                    // 
-                    // 
-                    const currentState = getState();
-                    const { guid } = thePayload;
-
-                    const localState = {
-                        ...currentState,
-                        __inExecution: [...currentState.__inExecution, guid]
-                    };
-
-                    storeState(localState);
-
-                    return localState;
-                }
-                case 'state:unlock-execution': {
-                    // 
-                    const currentState = getState();
-                    const { guid } = thePayload;
-
-                    const localState = {
-                        ...currentState,
-                        __inExecution: currentState.__inExecution.filter(
-                            item => item !== guid
-                        )
-                    };
-
-                    storeState(localState);
-
-                    return localState;
-                }
-            }
-        } catch (exception) {
-            logger.error(
-                `ugh, we're compromising the state w/ msg '${theAction}' :`,
-                exception
-            );
-            throw exception;
-        }
-    };
-
-    try {
-        logger.log(`:: acn :: ${action}`, { correlationId, action, payload });
-        const mutatedState = await getUpdatedState(action, payload);
-        if (!mutatedState) {
-            logger.error(`:: acn :: ${action} failed`, {
-                correlationId,
-                action,
-                payload
-            });
-            return false;
-        }
-
-        state = mutatedState;
-
-        try {
-            await refreshButtons();
-        } catch (buttonUpdateException) {
-            /* there's silence */
-        }
-    } catch (e) {
-        logger.error(`mailmindr crashed due to ${e.message}`, {
-            correlationId,
-            error: e
-        });
-
-        return false;
-    }
-
-    return true;
-};
-
 const sendConnectionMessage = async (connectionName, message) => {
-    const { openConnections } = getState();
-    logger.info(`open connections?`, openConnections, 'send message', message);
-    const connection = openConnections.find(con => con.name === connectionName);
-    if (connection) {
-        await connection.postMessage(message);
-    }
-};
-
-const findDialogForType = dialogType => {
-    const { openDialogs } = getState();
-    return openDialogs.find(dialog => dialog.dialogType === dialogType);
-};
-
-const findMindrByGuid = guid => {
-    const { mindrs } = getState();
-    const result = (mindrs || []).find(item => item.guid === guid);
-
-    return result;
+    const state = store.getState();
+    const openConnections = selectOpenConnections(state);
+    await sendConnectionMessageEx(openConnections, message, connectionName);
 };
 
 const editMindrByGuid = async guid => {
     const correlationId = createCorrelationId('editMindrByGuid');
     logger.log('BEGIN editMindrByGuid', { correlationId, guid });
-    const mindr = findMindrByGuid(guid);
+    const state = store.getState();
+    const mindr = selectMindrByGuid(state, guid);
     const {
         headerMessageId,
         author,
@@ -799,7 +251,8 @@
 };
 
 const bringDialogToFront = async dialogType => {
-    const dialog = await findDialogForType(dialogType);
+    const state = store.getState();
+    const dialog = selectDialogForType(state, dialogType);
 
     if (!dialog) {
         return false;
@@ -812,32 +265,6 @@
     return true;
 };
 
-const closeCreateOrUpdateMindrDialog = async () => {
-    const correlationId = createCorrelationId('closeCreateOrUpdateMindrDialog');
-    const dialogType = 'mailmindr:dialog:set-mindr';
-    const dialog = findDialogForType(dialogType);
-
-    logger.log(`BEGIN closeCreateOrUpdateMindrDialog`, {
-        correlationId,
-        dialogType,
-        dialog
-    });
-
-    if (dialog) {
-        await dispatch('dialog:close', {
-            dialogId: dialog.dialogId
-        });
-
-        await messenger.windows.remove(dialog.details.id);
-    }
-
-    logger.log(`END closeCreateOrUpdateMindrDialog`, {
-        correlationId,
-        dialogType,
-        dialog
-    });
-};
-
 const showCreateOrUpdateMindrDialog = async (currentMessage, mindr) => {
     const dialogType = 'mailmindr:dialog:set-mindr';
     const { headerMessageId, author, folder, subject } = currentMessage;
@@ -846,13 +273,6 @@
     logger.info('generic folder', genericFolder);
 
     const { accountId, name, path, type, identityEmailAddress } = genericFolder;
-    // 
-    // 
-    // 
-    // 
-    // 
-    // 
-
     const dialogId = createMailmindrId('mailmindr:dialog:set-mindr');
 
     const parameters = new URLSearchParams();
@@ -883,7 +303,7 @@
         allowScriptsToClose: true
     });
 
-    await dispatch('dialog:open', { dialogId, dialogType, details });
+    store.dispatch(openDialog(dialogId, dialogType, details));
 
     // 
     // 
@@ -891,75 +311,6 @@
     // 
 };
 
-const showMindrAlert = async ({ overdue, active }) => {
-    const dialogType = 'mailmindr:mindr-alert';
-    const dialog = findDialogForType(dialogType);
-
-    if (dialog) {
-        logger.log('we already have a message dialog', dialog);
-
-        if ((overdue || []).length === 0 && (active || []).length === 0) {
-            // 
-            await dispatch('dialog:close', {
-                dialogId: dialog.details.id
-            });
-            messenger.windows.remove(dialog.details.id);
-        } else {
-            // 
-            await sendConnectionMessage('connection:mindr-alert', {
-                overdue,
-                active
-            });
-            await messenger.windows.update(dialog.details.id, {
-                // 
-                drawAttention: true
-            });
-        }
-    } else {
-        logger.log(
-            'need to open a new dialog with active/overdue mindrs',
-            active,
-            overdue
-        );
-        if ((active || []).length === 0 && (overdue || []).length === 0) {
-            logger.log('no dialog needed');
-            return;
-        }
-        const dialogId = createMailmindrId('mailmindr:dialog:mindr-alert');
-
-        const parameters = new URLSearchParams();
-        parameters.set('dialogId', dialogId);
-
-        const { width: screenWidth, availHeight: screenHeight } = screen;
-        const height = 200;
-        const width = 400;
-        const left = screenWidth - width;
-        const top = screenHeight - height;
-        const url = `/views/dialogs/mindr-alert/index.html?${parameters}`;
-        const details = await messenger.windows.create({
-            left,
-            top,
-            height,
-            width,
-            url,
-            type: 'popup',
-            state: 'normal',
-            allowScriptsToClose: true
-        });
-
-        await messenger.windows.update(details.id, {
-            top,
-            left,
-            width,
-            height,
-            focused: true,
-            drawAttention: true
-        });
-
-        await dispatch('dialog:open', { dialogId, dialogType, details });
-    }
-};
-
 const showTimespanPresetEditor = async timePreset => {
     const dialogType = 'mailmindr:time-preset-editor';
     const hasDialog = await bringDialogToFront(dialogType);
@@ -988,33 +339,31 @@
         allowScriptsToClose: true
     });
 
-    await dispatch('dialog:open', { dialogId, dialogType, details });
+    store.dispatch(openDialog(dialogId, dialogType, details));
 };
 
 const handleStartup = async () => {
-    const MAX_RETRIES = 5;
-    const initailze = async () => {
-        for (let retryCount = 0; retryCount < MAX_RETRIES; retryCount++) {
-            const success = await dispatch('state:initialize');
-            if (success) {
-                return true;
-            }
-            await new Promise(resolve => setTimeout(() => resolve(), 1000));
-        }
-        logger.error(
-            `Initialization failed after ${MAX_RETRIES} attempts. Aborting mailmindr.`
-        );
-        return false;
-    };
+    try {
+        const storedState = await initializeStorage();
+        const localState = storedState || initialState;
+
+        const { storeState } = await getStorage();
+
+        const saveState = async () => {
+            const state = store.getState();
+
+            await storeState(state);
+        };
+        const saveStateThrottled = throttle(saveState, 250);
+
+        store = createStore(rootReducer, localState);
+        store.addEventListener('change', saveStateThrottled);
 
-    const success = await initailze();
-    if (success) {
         setupUI();
         startHeartbeat();
-        messenger.messageDisplayScripts.register({
-            js: [{ file: '/scripts/mailmindr-message-script.js' }]
-        });
-    } else {
+    } catch (startupError) {
+        logger.error(`mailmindr failed to start`, startupError);
+        // 
         const errorButtonCaption = browser.i18n.getMessage(
             'errorInitializationBrowserButtonText'
         );
@@ -1026,11 +375,16 @@
     const { id, windowId } = tab;
     const msg = message || (await getCurrentDisplayedMessage({ id, windowId }));
     if (msg) {
+        logger.log(`findExistingMindrForTab`, store);
         const { headerMessageId } = msg;
-        const { mindrs } = getState();
+        const sanitizedHeaderMessageId = sanitizeHeaderMessageId(
+            headerMessageId
+        );
+        const { mindrs } = store.getState();
         const mindr = mindrs.find(
             mindr =>
-                mindr.headerMessageId === headerMessageId && !!headerMessageId
+                sanitizeHeaderMessageId(mindr.headerMessageId) ===
+                    sanitizedHeaderMessageId && !!sanitizedHeaderMessageId
         );
 
         return mindr;
@@ -1040,15 +394,22 @@
 };
 
 const handleSelectedMessagesChanged = async (tab, messageList) => {
-    const mindr = await findExistingMindrForTab(tab);
+    const { id, windowId } = tab;
+    const msg = await getCurrentDisplayedMessage({ id, windowId });
+    if (!msg) {
+        logger.log(`handleSelectedMessagesChanged: no message selected, exit.`);
+        return;
+    }
+
+    const mindr = await findExistingMindrForTab(tab, msg);
     const title = !!mindr ? '!' : null;
     const details = { text: title };
-    const { id, windowId: _ } = tab;
 
     messenger.messageDisplayAction.setBadgeText(details);
 
     const tabInfo = await messenger.tabs.get(id);
-    if (!tabInfo.mailTab) {
+    if (!tabInfo.mailTab && tabInfo.type !== 'messageDisplay') {
+        logger.error(`this is not a mail tab`, tabInfo);
         return;
     }
 
@@ -1057,19 +418,26 @@
     );
 
     if (!mindr) {
+        logger.log(`There's no mindr present for this tab`, { tabInfo, msg });
         await messenger.tabs.executeScript(id, {
             code: `typeof removeExistingMessageBars === 'function' && removeExistingMessageBars()`
         });
         return;
     }
 
-    messenger.messageDisplayAction.setBadgeBackgroundColor({
+    await messenger.messageDisplayAction.setBadgeBackgroundColor({
         color: '#ad3bff'
     });
-    messenger.tabs.insertCSS(id, {
+    await messenger.tabs.insertCSS(id, {
         file: '/styles/message-bar.css'
     });
+
+    await messenger.tabs.executeScript(id, {
+        file: '/scripts/mailmindr-message-script.js'
+        // 
+    });
     await messenger.tabs.executeScript(id, {
+        // 
         code: `createMindrBar('${JSON.stringify(mindr.guid)}')`
     });
 };
@@ -1077,14 +445,6 @@
 const getCurrentDisplayedMessage = async tab => {
     const correlationId = createCorrelationId('getCurrentDisplayedMessage');
     const { id: tabId, windowId = messenger.windows.WINDOW_ID_CURRENT } = tab;
-    const query = {
-        windowId
-    };
-    const tabs = await browser.tabs.query(query);
-
-    if (!tabs || tabs.length === 0) {
-        return undefined;
-    }
 
     const message = await browser.messageDisplay.getDisplayedMessage(tabId);
     if (!message) {
@@ -1133,16 +493,15 @@
 
         return {
             ...message,
-            headerMessageId
+            headerMessageId: sanitizeHeaderMessageId(headerMessageId)
         };
     }
 
     return message;
 };
 
-const refreshButtons = async () => {
+const refreshButtons = async mindrs => {
     try {
-        const { mindrs } = getState();
         const hasMindrs = mindrs.length;
         const current = await messenger.tabs.query({
             currentWindow: true,
@@ -1168,14 +527,22 @@
     }
 };
 
-async function onLoadDialog(dialogOpenInfo) {
+const onLoadDialog = dialogOpenInfo => {
     const { name, ...rest } = dialogOpenInfo;
+    const state = store.getState();
+
+    if (!store || !state) {
+        logger.error(`State '(${state})' or store '(${store})' isn't defined`, {
+            state,
+            store
+        });
+    }
     switch (name) {
         case 'set-mindr': {
-            const { settings, presets, mindrs } = getState();
             const { guid } = rest;
-
-            const mindr = mindrs.find(mindr => mindr.guid === guid);
+            const settings = selectSettings(state);
+            const presets = selectPresets(state);
+            const mindr = selectMindrByGuid(state, guid);
 
             return {
                 settings,
@@ -1183,9 +550,30 @@
                 mindr
             };
         }
+        case 'set-outgoing-mindr': {
+            const settings = selectSettings(state);
+            const presets = selectPresets(state);
+            const {
+                sender: { windowId, id }
+            } = rest;
+            const draft = selectDraftForSenderTabOrNull(state, {
+                windowId,
+                id
+            });
+
+            return {
+                settings,
+                presets,
+                draft
+            };
+        }
         case 'mindr-alert': {
-            const { active, overdue } = getState();
-            return { active, overdue };
+            // 
+            const { active, overdue } = store.getState();
+            return {
+                active: active.filter(showReminderForMindr),
+                overdue: overdue.filter(showReminderForMindr)
+            };
         }
         case 'time-preset-editor': {
             logger.log('REST', rest);
@@ -1197,12 +585,16 @@
                 `mailmindr:onLoadDialog // no data loadable for dialog '${name}'`
             );
     }
-}
+};
 
 const onWindowRemoved = async windowId => {
     const log = logger.createContextLogger({ name: 'onWindowRemoved' });
 
-    const { openDialogs } = getState();
+    const state = store.getState();
+    const openDialogs = selectOpenDialogs(state);
+    const settings = selectSettings(state);
+    const presets = selectPresets(state);
+
     const dialogInfo = openDialogs.find(
         dialog => dialog.details.id === windowId
     );
@@ -1216,119 +608,35 @@
             case 'mailmindr:time-preset-editor':
                 await sendConnectionMessage('connection:mailmindr-options', {
                     topic: 'settings:unlock',
-                    message: { settings: getSettings() }
+                    message: { settings: { settings, presets } }
                 });
                 break;
         }
-        await dispatch('dialog:close', { dialogId });
+        store.dispatch(closeDialog(dialogId));
     }
 };
 
-const doMoveMessageToFolder = async (
-    message,
-    destinationFolder,
-    parentCorrelationId
-) => {
-    const correlationId = createCorrelationId(
-        'doMoveMessageToFolder',
-        parentCorrelationId
+const findIceboxFolderForAccountIdentityMailAddress = async identityMailAddress => {
+    const { settings } = store.getState();
+    const defaultIceboxFolder = await getGenericIceboxFolderForIdentityOrNull(
+        identityMailAddress,
+        settings
     );
-    try {
-        const { id } = message;
-        const { accountId, path } = destinationFolder;
-        logger.log(`BEGIN move message ${id}`, {
-            correlationId,
-            message
-        });
-        await messenger.messages.move([id], { accountId, path });
-        logger.log(`END move message ${id}`, {
-            correlationId,
-            message
-        });
-        return true;
-    } catch (error) {
-        logger.error(error, { correlationId });
-        return false;
-    }
-};
-
-const moveMessageToFolder = async (
-    messageDetails,
-    sourceFolder,
-    targetFolder
-) => {
-    const correlationId = createCorrelationId('moveMessagesToFolder');
-    try {
-        logger.info('moveMessageToFolder target', {
-            correlationId,
-            targetFolder
-        });
-
-        const moveMessageToFolderAction = async (
-            message,
-            _messageSourceFolder
-        ) => {
-            await doMoveMessageToFolder(message, targetFolder, correlationId);
-        };
-
-        logger.info(`BEGIN applying action to folder`, {
-            correlationId,
-            sourceFolder,
-            messageDetails
-        });
-        const actionResult = await applyActionToMessageInFolder(
-            sourceFolder,
-            messageDetails,
-            moveMessageToFolderAction,
-            true
-        );
-        const { done, value } = await actionResult.next();
-
-        // 
-        const success = Boolean(done);
-
-        const logMessage = `moveMessageToFolder : applyActionToMessageInFolder returns { done: ${done}, value: ${value} }`;
-        if (success) {
-            logger.info(logMessage, { correlationId, result: { done, value } });
-        } else {
-            logger.warn(logMessage, { correlationId, result: { done, value } });
-        }
-
-        if (value === null) {
-            logger.error(
-                `moveMessageToFolder : applyActionToMessageInFolder message not found in folder`
-            );
-        }
 
-        logger.info(`END applying action to folder`, {
-            correlationId,
-            sourceFolder,
-            messageDetails
-        });
-    } catch (e) {
-        logger.error(`moveMessageToFolder failed: ${e.message}`, {
-            correlationId,
-            error: e
-        });
-        return false;
-    }
-
-    return true;
+    return defaultIceboxFolder;
 };
 
 const moveToIcebox = async (headerMessageId, metaData) => {
-    const { settings } = getState();
-
     const { folderAccountIdentityMailAddress } = metaData;
 
-    const defaultIceboxFolder = await getGenericIceboxFolderForIdentityOrNull(
-        folderAccountIdentityMailAddress,
-        settings
+    const defaultIceboxFolder = await findIceboxFolderForAccountIdentityMailAddress(
+        folderAccountIdentityMailAddress
     );
 
     if (!defaultIceboxFolder) {
         return false;
     }
+
     const correlationId = createCorrelationId('moveToIcebox');
     logger.log('BEGIN moveToIcebox', {
         correlationId,
@@ -1367,26 +675,30 @@
 
 const messageHandler = async (request, _sender, _sendResponse) => {
     const { action, payload } = request;
+
     let result = null;
 
     switch (action) {
         case 'dialog:open':
             result = {
                 status: 'ok',
-                payload: await onLoadDialog(payload)
+                payload: onLoadDialog(payload)
             };
 
             return result;
         case 'dialog:close':
-            const dialogId = payload;
-            const { openDialogs } = getState();
-            const dialog = openDialogs.find(
-                dialog => dialog.dialogId === dialogId
-            );
+            {
+                const dialogId = payload;
+                const state = store.getState();
+                const openDialogs = selectOpenDialogs(state);
+                const dialog = openDialogs.find(
+                    dialog => dialog.dialogId === dialogId
+                );
 
-            await dispatch('dialog:close', { dialogId });
+                store.dispatch(closeDialog(dialogId));
 
-            return { status: 'ok', dialog };
+                return { status: 'ok', dialog };
+            }
             break;
         case 'dialog:bring-to-front':
             const { dialogType } = payload;
@@ -1397,14 +709,39 @@
                 return { status: 'error', paylad: null };
             }
             break;
-        case 'mindrs:list':
+        case 'mindrs:list': {
+            const state = store.getState();
+            const mindrsList = selectMindrs(state);
             result = {
                 status: 'ok',
                 payload: {
-                    mindrs: state.mindrs
+                    mindrs: mindrsList
                 }
             };
             return result;
+        }
+        case 'mindr:create-outgoing': {
+            const correlationId = createCorrelationId(
+                `messageHandler:mindr:create`
+            );
+            logger.log(`BEGIN messageHandler:mindr:create-outgoing`, {
+                correlationId,
+                payload
+            });
+
+            store.dispatch(createOrUpdateDraft(payload));
+
+            const result = {
+                status: 'ok',
+                payload: {}
+            };
+            logger.log(`END messageHandler:mindr:create-outgoing`, {
+                correlationId,
+                payload
+            });
+
+            return result;
+        }
         case 'mindr:create': {
             const { guid, headerMessageId, metaData, doMoveToIcebox } = payload;
             const correlationId = createCorrelationId(
@@ -1431,7 +768,11 @@
                         // 
                         // 
                         if (!createdMindr.action.moveMessageTo) {
-                            const existingMindr = findMindrByGuid(guid);
+                            const state = store.getState();
+                            const existingMindr = selectMindrByGuid(
+                                state,
+                                guid
+                            );
                             if (existingMindr) {
                                 logger.log(
                                     `updating existing mindr, set icebox folder from original mindr`,
@@ -1457,9 +798,9 @@
                                 };
 
                                 // 
-                                const {
-                                    settings: { defaultIceboxFolder }
-                                } = getState();
+                                const defaultIceboxFolder = await findIceboxFolderForAccountIdentityMailAddress(
+                                    metaData.folderAccountIdentityMailAddress
+                                );
                                 const iceBoxFolder = await genericFolderToLocalFolder(
                                     defaultIceboxFolder
                                 );
@@ -1481,7 +822,7 @@
                     }
                 }
 
-                await dispatch('mindr:create-or-update', createdMindr);
+                store.dispatch(createOrUpdateMindr(createdMindr));
 
                 result = {
                     status: createdMindr ? 'ok' : 'error',
@@ -1491,7 +832,9 @@
                 };
 
                 logger.log('refresh buttons', { correlationId });
-                await refreshButtons();
+                const state = store.getState();
+
+                await refreshButtons(selectMindrs(state));
                 // 
             } catch (error) {
                 logger.error(`FAIL messageHandler:mindr:create`, {
@@ -1508,9 +851,18 @@
 
             return result;
         }
+        case 'mindr:remove-outgoing-mindr': {
+            const { sender } = payload;
+            const state = store.getState();
+            const draft = selectDraftForSenderTabOrNull(state, sender);
+
+            store.dispatch(removeDraft(draft));
+
+            return { status: 'ok', paylad: null };
+        }
         case 'mindr:remove': {
             const { guid } = payload;
-            await dispatch('mindr:remove', { guid });
+            store.dispatch(removeMindr(guid));
 
             return { status: 'ok', paylad: null };
         }
@@ -1518,7 +870,7 @@
             logger.log('mindr:get-information', payload);
             const { guid } = payload;
 
-            const { mindrs } = getState();
+            const { mindrs } = store.getState();
             const mindr = mindrs.find(mindr => mindr.guid === guid);
 
             logger.log(`mindr:get-information: ${mindr.headerMessageId}`);
@@ -1531,25 +883,34 @@
             break;
         }
         case 'navigate:open-message-by-mindr-guid':
-            // 
-            // 
-            const { guid } = payload;
-            const { mindrs } = getState();
-            const mindr = mindrs.find(mindr => mindr.guid === guid);
-            if (mindr) {
-                const { headerMessageId } = mindr;
-                if (messenger.messageDisplay.open) {
-                    await messenger.messageDisplay.open({
-                        headerMessageId,
-                        active: true
-                    });
-                } else {
-                    await browser.mailmindrMessagesApi.openMessageByMessageHeaderId(
-                        headerMessageId
+            {
+                // 
+                // 
+                const { guid } = payload;
+                const state = store.getState();
+                const mindr = selectMindrByGuid(state, guid);
+
+                if (mindr) {
+                    const headerMessageId = sanitizeHeaderMessageId(
+                        mindr.headerMessageId
                     );
+                    if (messenger.messageDisplay.open) {
+                        logger.log(
+                            `Open message by headerMessageId [nativeAPI] < '${headerMessageId}' >`
+                        );
+                        try {
+                            await messenger.messageDisplay.open({
+                                headerMessageId,
+                                active: true
+                            });
+                        } catch (openMessageError) {
+                            logger.error(
+                                `The message cannot be opened`,
+                                openMessageError
+                            );
+                        }
+                    }
                 }
-
-                // 
             }
             break;
         case 'refresh:buttons':
@@ -1561,24 +922,30 @@
                 `messageHandler:mindr:snooze`
             );
 
-            const { mindrs } = getState();
-            const { presets, settings } = getSettings();
+            const localState = store.getState();
+            const mindrs = selectMindrs(localState);
+            const presets = selectPresets(localState);
+            const settings = selectSettings(localState);
+
             const { snoozeTime } = settings;
 
-            await snoozeMindrs(
-                dispatch,
-                list,
-                mindrs,
+            logger.log(`mindr:snooze // snoozeTime: ${snoozeTime}`, {
                 snoozeTime,
-                correlationId
+                mindrs
+            });
+
+            store.dispatch(
+                snoozeMindrs(list, mindrs, snoozeTime, correlationId)
             );
 
-            await dispatch('heartbeat');
+            store.dispatch(heartBeat());
 
-            const { active, overdue } = getState();
+            const { active, overdue } = store.getState();
             const overdueNotExecuted = overdue.filter(item => !item.isExecuted);
 
-            await showMindrAlert({ overdue: overdueNotExecuted, active });
+            store.dispatch(
+                showMindrAlert({ overdue: overdueNotExecuted, active })
+            );
 
             return { status: 'ok', paylad: null };
         }
@@ -1588,13 +955,15 @@
             do {
                 const guid = list.pop();
 
-                await dispatch('mindr:remove', { guid });
+                store.dispatch(removeMindr(guid));
             } while (list.length);
 
-            const { active, overdue } = getState();
+            const { active, overdue } = store.getState();
             const overdueNotExecuted = overdue.filter(item => !item.isExecuted);
 
-            await showMindrAlert({ overdue: overdueNotExecuted, active });
+            store.dispatch(
+                showMindrAlert({ overdue: overdueNotExecuted, active })
+            );
 
             return { status: 'ok', paylad: null };
         }
@@ -1604,39 +973,53 @@
             if (source) {
                 // 
                 logger.warn(`updating timespan`, current, source);
-                await dispatch('preset:timespan-update', { current, source });
+                store.dispatch(updateTimespanPreset(current, source));
             } else {
                 // 
                 logger.info(`creating new timespan`, current);
-                await dispatch('preset:timespan-create', { current });
+                store.dispatch(createTimespanPreset(current));
             }
 
+            const state = store.getState();
+            const settings = selectSettings(state);
+            const presets = selectPresets(state);
+
             await sendConnectionMessage('connection:mailmindr-options', {
                 topic: 'settings:unlock',
-                message: { settings: getSettings() }
+                message: { settings: { settings, presets } }
             });
 
             return { status: 'ok', paylad: null };
         }
         case 'preset:remove-timespans': {
-            const { presets } = payload;
+            const { presets: currentPresets } = payload;
+
+            if (
+                currentPresets &&
+                Array.isArray(currentPresets) &&
+                currentPresets.length
+            ) {
+                store.dispatch(removeTimespanPreset(currentPresets));
+                const state = store.getState();
+                const settings = selectSettings(state);
+                const presets = selectPresets(state);
 
-            if (presets && Array.isArray(presets) && presets.length) {
-                await dispatch('preset:timespan-remove', { presets: presets });
                 await sendConnectionMessage('connection:mailmindr-options', {
                     topic: 'settings:updated',
-                    message: { settings: getSettings() }
+                    message: { settings: { settings, presets } }
                 });
             }
 
             return { status: 'ok', paylad: null };
         }
         case 'options:get-settings': {
-            const payload = getSettings();
+            const state = store.getState();
+            const settings = selectSettings(state);
+            const presets = selectPresets(state);
 
             await sendConnectionMessage('connection:mailmindr-options', {
                 topic: 'settings:updated',
-                message: { settings: payload }
+                message: { settings: { settings, presets } }
             });
             break;
         }
@@ -1644,7 +1027,8 @@
             let { name, value } = payload;
             logger.info(`? set '${name}' to '${value}'`, value);
 
-            const { settings } = getSettings();
+            const state = store.getState();
+            const settings = selectSettings(state);
             const propNames = Object.keys(settings);
 
             switch (name) {
@@ -1681,13 +1065,14 @@
             }
 
             if (propNames.indexOf(name) >= 0) {
-                await dispatch('setting:update', { name, value });
-
-                const payload = getSettings();
+                store.dispatch(updateSetting(name, value));
+                const state = store.getState();
+                const settings = selectSettings(state);
+                const presets = selectPresets(state);
 
                 await sendConnectionMessage('connection:mailmindr-options', {
                     topic: 'settings:updated',
-                    message: { settings: payload }
+                    message: { settings: { settings, presets } }
                 });
             } else {
                 logger.error(
@@ -1697,9 +1082,12 @@
             break;
         }
         case 'settings:force-unlock': {
+            const state = store.getState();
+            const settings = selectSettings(state);
+            const presets = selectPresets(state);
             await sendConnectionMessage('connection:mailmindr-options', {
                 topic: 'settings:unlock',
-                message: { settings: getSettings() }
+                message: { settings: { settings, presets } }
             });
             break;
         }
@@ -1710,8 +1098,9 @@
         }
         case 'do:mindr-action-remove': {
             const { guid } = payload;
-            const { mindrs } = getState();
-            const mindr = mindrs.find(mindr => mindr.guid === guid);
+            const state = store.getState();
+            const mindr = selectMindrByGuid(state, guid);
+
             if (!mindr) {
                 return;
             }
@@ -1743,7 +1132,10 @@
     }
 
     // 
-    if (state.mindrs.length) {
+    const localState = store.getState();
+    const mindrs = selectMindrs(localState);
+
+    if (mindrs.length) {
         messenger.browserAction.enable();
     } else {
         messenger.browserAction.disable();
@@ -1771,63 +1163,71 @@
         return;
     }
 
+    logger.log(`connectionHandler called for ${name}`);
     if (name === 'connection:mindr-alert') {
         port.onMessage.addListener(onConnectionMessage);
-        port.onDisconnect.addListener(
-            async () => await dispatch('connection:close', { port })
+        port.onDisconnect.addListener(() =>
+            store.dispatch(connectionClosed(port))
         );
-        await dispatch('connection:open', { port });
+        store.dispatch(connectionOpened(port));
 
         // 
-        const { overdue, active } = getState();
+        const { overdue, active } = store.getState();
         await sendConnectionMessage(name, {
-            overdue,
-            active
+            overdue: overdue.filter(showReminderForMindr),
+            active: active.filter(showReminderForMindr)
         });
     } else if (name === 'connection:mailmindr-options') {
         port.onMessage.addListener(onConnectionMessage);
-        port.onDisconnect.addListener(
-            async () => await dispatch('connection:close', { port })
+        port.onDisconnect.addListener(() =>
+            store.dispatch(connectionClosed(port))
         );
-        await dispatch('connection:open', { port });
-
-        // 
-
-        // 
-        // 
-        // 
-        // 
+        store.dispatch(connectionOpened(port));
     }
 };
 
 browser.tabs.onMoved.addListener(async ({}) => {});
 
 browser.tabs.onActivated.addListener(async activeInfo => {
+    if (!store) {
+        logger.error(`tabs.onActivated:handler: store is undefined`);
+        return;
+    }
+
     const { tabId, windowId } = activeInfo || {};
-    console.log(`tab activated: ${tabId}, ${windowId} <- ${activeInfo}`);
-    await refreshButtons();
+    const { mindrs } = store.getState();
+    // 
+    await refreshButtons(mindrs);
 });
 
 browser.mailTabs.onSelectedMessagesChanged.addListener(
     handleSelectedMessagesChanged
 );
 
-browser.messageDisplayAction.onClicked.addListener(async ({ id, windowId }) => {
-    const currentMessage = await getCurrentDisplayedMessage({ id, windowId });
-    const mindr = await findExistingMindrForTab(
-        {
+browser.messageDisplayAction.onClicked.addListener(
+    async ({ id, windowId, type }) => {
+        const currentMessage = await getCurrentDisplayedMessage({
             id,
             windowId
-        },
-        currentMessage
-    );
+        });
+        const mindr = await findExistingMindrForTab(
+            {
+                id,
+                windowId
+            },
+            currentMessage
+        );
 
-    await showCreateOrUpdateMindrDialog(currentMessage, mindr);
-    // 
-});
+        await showCreateOrUpdateMindrDialog(currentMessage, mindr);
+        // 
+    }
+);
 
 browser.menus.onShown.addListener(info => {
-    const contexts = ['message_list', 'page'];
+    const /** @type {browser.menus.ContextType[]} */ contexts = [
+            'message_list',
+            'page'
+        ];
     // 
     if (
         info &&
@@ -1871,6 +1271,77 @@
     messageHandler
 );
 
+// 
+// 
+// 
+// 
+// 
+// 
+// 
+// 
+// 
+
+messenger.compose.onBeforeSend.addListener((tab, details) => {
+    logger.log(`ONBEFORESEND -- `, { tab, details });
+    return { cancel: false };
+});
+
+messenger.compose.onAfterSend.addListener(async (tab, sendInfo) => {
+    const { messages, mode, error, headerMessageId } = sendInfo;
+
+    const findHeaderMessageId = ({ messages, headerMessageId }) => {
+        if (headerMessageId) {
+            logger.log(`? sent headerMessageId: ${headerMessageId}`);
+            return headerMessageId;
+        } else if (messages && messages.length) {
+            const message = messages[0];
+            return message.headerMessageId;
+        } else {
+            return null;
+        }
+    };
+
+    const hdrMsgId = findHeaderMessageId({ messages, headerMessageId });
+    if (hdrMsgId) {
+        // 
+        const maybeDraft = selectDraftForSenderTabOrNull(store.getState(), tab);
+        if (maybeDraft && maybeDraft.mindr) {
+            const { mindr } = maybeDraft;
+            const {
+                author = '',
+                subject = '',
+                folder = null
+            } = sendInfo?.messages?.[0];
+            const sourceFolder = await localFolderToGenericFolder(folder);
+            const {
+                accountId: folderAccountId,
+                identityEmailAddress: folderAccountIdentityMailAddress,
+                name: folderName,
+                path: folderPath,
+                type: folderType
+            } = sourceFolder;
+            const createdMindr = await createMindrFromActionTemplate({
+                ...mindr,
+                headerMessageId,
+                metaData: {
+                    headerMessageId,
+                    author,
+                    subject,
+                    folderAccountId,
+                    folderName,
+                    folderPath,
+                    folderType,
+                    folderAccountIdentityMailAddress
+                }
+            });
+
+            store.dispatch(createOrUpdateMindr(createdMindr));
+        }
+    }
+
+    logger.log(`ONAFTERSEND -- `, { tab, sendInfo });
+});
+
 browser.runtime.onConnect.addListener(connectionHandler);
 
 browser.commands.onCommand.addListener(async command => {
@@ -1885,4 +1356,56 @@
     }
 });
 
+const thunderbirdVersion = findThunderbirdVersion();
+const handleNewMailReceived = async (
+    /** @type {messenger.folders.MailFolder} */ folder,
+    /** @type {messenger.messages.MessageList} */ messages
+) => {
+    const /** @type {(mindr: string) => Mindr} */ selectByHeaderMessageId = selectMindrByHeaderMessageId.bind(
+            null,
+            store.getState()
+        );
+    const /** @type { { messageHeaderId: string, replyToHeaderMessageId: string }[] } */ headerMessageIds = [];
+    for await (let msg of getMessages(messages)) {
+        const messageId = msg.id;
+        const message = await messenger.messages.getFull(messageId);
+        // 
+        const { headers } = message;
+        const messageHeaderId = msg.headerMessageId;
+        const inReplyTo = headers?.['in-reply-to'];
+        if (inReplyTo) {
+            headerMessageIds.push(
+                ...inReplyTo.map(item => ({
+                    messageHeaderId,
+                    replyToHeaderMessageId: sanitizeHeaderMessageId(item)
+                }))
+            );
+        }
+    }
+
+    const mindrs = headerMessageIds
+        .map(({ replyToHeaderMessageId, messageHeaderId }) => {
+            const mindr = selectByHeaderMessageId(replyToHeaderMessageId);
+            if (mindr) {
+                return { mindr, messageHeaderId };
+            } else return undefined;
+        })
+        .filter(Boolean);
+
+    await Promise.all(
+        mindrs.map(async ({ mindr, messageHeaderId }) => {
+            await store.dispatch(setReplyReceived(mindr, messageHeaderId));
+        })
+    );
+};
+
+if (thunderbirdVersion <= 121) {
+    browser.messages.onNewMailReceived.addListener(handleNewMailReceived);
+} else {
+    browser.messages.onNewMailReceived.addListener(
+        handleNewMailReceived,
+        false
+    );
+}
+
 handleStartup();
diff -Nru mailmindr-1.4.0/scripts/mailmindr-message-script.js mailmindr-1.7.1/scripts/mailmindr-message-script.js
--- mailmindr-1.4.0/scripts/mailmindr-message-script.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/scripts/mailmindr-message-script.js	2024-08-04 22:14:20.000000000 +0200
@@ -1,4 +1,4 @@
-const removeExistingMessageBars = () => {
+var removeExistingMessageBars = () => {
     const messageBars = document.querySelectorAll('.mailmindr-message-bar');
     if (!messageBars) {
         return;
@@ -11,10 +11,10 @@
 
 /** @typedef {() => HTMLDivElement} getExistingessageBarFunction */
 /** @type {getExistingessageBarFunction}  */
-const getExistingMessageBar = () =>
+var getExistingMessageBar = () =>
     document.querySelector('.mailmindr-message-bar');
 
-const createUI = (guid, dueDateTimeText) => {
+var createUI = (guid, dueDateTimeText) => {
     const mailmindrBar = document.createElement('div');
     mailmindrBar.className = 'mailmindr-message-bar';
 
@@ -54,6 +54,21 @@
         });
     });
 
+    const mailmindrRemoveBtn = document.createElement('button');
+    mailmindrRemoveBtn.className = 'mailmindr-button mailmindr-button--micro';
+    mailmindrRemoveBtn.innerText = browser.i18n.getMessage(
+        'view.message-display.notification.button.remove'
+    );
+    mailmindrRemoveBtn.addEventListener('click', async () => {
+        await messenger.runtime.sendMessage({
+            action: 'do:mindr-action-remove',
+            payload: {
+                guid
+            }
+        });
+    });
+
+    mailmindrButtonWrapper.appendChild(mailmindrRemoveBtn);
     mailmindrButtonWrapper.appendChild(mailmindrEditBtn);
     mailmindrButtonWrapper.appendChild(mailmindrCloseBtn);
 
@@ -68,7 +83,7 @@
     window.document.body.insertBefore(mailmindrBar, messageWrapper);
 };
 
-const createMindrBar = async guid => {
+var createMindrBar = async guid => {
     const mindrGuid = JSON.parse(guid)
         .replace(/"/g, '')
         .replace(/'/g, '');
diff -Nru mailmindr-1.4.0/views/dialogs/create-mindr/index.css mailmindr-1.7.1/views/dialogs/create-mindr/index.css
--- mailmindr-1.4.0/views/dialogs/create-mindr/index.css	2022-08-12 15:32:09.000000000 +0200
+++ mailmindr-1.7.1/views/dialogs/create-mindr/index.css	2024-08-04 22:14:20.000000000 +0200
@@ -23,7 +23,9 @@
 }
 
 input[type='checkbox'] {
-    display: none;
+    /* display: none; */
+    height: 16px;
+    width: 16px;
 }
 
 input[type='checkbox'] + label {
@@ -34,7 +36,7 @@
     color: silver;
 }
 
-input[type='checkbox'] + label::before {
+/* input[type='checkbox'] + label::before {
     content: '';
     display: block;
     float: left;
@@ -43,17 +45,19 @@
     border: 1px solid rgba(12, 12, 13, 0.1);
     border-radius: 2px;
     background-color: var(--grey-90-a10);
-}
+} */
 
-input[type='checkbox']:checked + label::before {
+/* input[type='checkbox']:checked + label::before {
     background-image: url(chrome://global/skin/icons/check.svg);
+    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHklEQVQ4T2NkoBAwUqifYdQAhtEwACai0XQwGMIAACaYABGnE9aRAAAAAElFTkSuQmCC');
     background-position: center;
     background-repeat: no-repeat;
-}
+    background-color: blue;
+} */
 
-input[type='checkbox'] + label:hover::before {
+/* input[type='checkbox'] + label:hover::before {
     background-color: var(--grey-90-a20);
-}
+} */
 
 /* input[type='checkbox']:checked:hover + label::before {
     background-color: var(--blue-70);
@@ -130,6 +134,15 @@
 }
 
 @media (prefers-color-scheme: dark) {
+    * {
+        color: #f9f9fa;
+    }
+
+    body {
+        color: #f9f9fa;
+        background-color: #2a2a2e;
+    }
+
     input[type='text'],
     input[type='number'],
     select {
diff -Nru mailmindr-1.4.0/views/dialogs/create-mindr/index.js mailmindr-1.7.1/views/dialogs/create-mindr/index.js
--- mailmindr-1.4.0/views/dialogs/create-mindr/index.js	2022-08-12 15:32:09.000000000 +0200
+++ mailmindr-1.7.1/views/dialogs/create-mindr/index.js	2024-08-04 22:14:20.000000000 +0200
@@ -6,11 +6,11 @@
 } from '../../../modules/core-utils.mjs.js';
 import {
     clearContents,
+    createRemindMeBeforePicker,
     createTimePresetPicker,
     selectDefaultActionPreset,
     selectDefaultTimePreset
 } from '../../../modules/ui-utils.mjs.js';
-import { pluralize } from '../../../modules/string-utils.mjs.js';
 import {
     createCorrelationId,
     createLogger
@@ -104,37 +104,46 @@
     } = getDialogParameters();
 
     const remindMe = document.getElementById('mailmindr--preset-remind-me');
-    const remindMeMinutesBefore =
-        /** @type {HTMLInputElement} */ (remindMe).value || 0;
+    const remindMeMinutesBefore = parseInt(
+        /** @type {HTMLInputElement} */ (remindMe).value || '0',
+        10
+    );
 
     const due = getDateTimefromPickers();
-    const actionTemplate = getActionTemplateFromPicker();
+    const actionTemplate = /** @type {} */ getActionTemplateFromPicker();
+    if (typeof remindMeMinutesBefore === 'number') {
+        if (remindMeMinutesBefore >= 0) {
+            actionTemplate.showReminder = true;
+        } else {
+            actionTemplate.showReminder = false;
+        }
+    }
     const iceBox = /** @type {HTMLInputElement} */ (document.getElementById(
         'mailmindr--icebox'
     ));
     const doMoveToIcebox = iceBox.disabled ? false : iceBox.checked;
-
+    const payload = {
+        guid,
+        headerMessageId,
+        due,
+        remindMeMinutesBefore,
+        actionTemplate,
+        notes: '',
+        metaData: {
+            headerMessageId,
+            author,
+            subject,
+            folderAccountId,
+            folderName,
+            folderPath,
+            folderType,
+            folderAccountIdentityMailAddress
+        },
+        doMoveToIcebox
+    };
     const result = await messenger.runtime.sendMessage({
         action: 'mindr:create',
-        payload: {
-            guid,
-            headerMessageId,
-            due,
-            remindMeMinutesBefore,
-            actionTemplate,
-            notes: '',
-            metaData: {
-                headerMessageId,
-                author,
-                subject,
-                folderAccountId,
-                folderName,
-                folderPath,
-                folderType,
-                folderAccountIdentityMailAddress
-            },
-            doMoveToIcebox
-        }
+        payload
     });
     doCancel();
 };
@@ -280,7 +289,7 @@
     const {
         payload: {
             settings,
-            presets: { time, actions },
+            presets: { time, actions, remindMeMinutesBefore },
             mindr
         }
     } = result;
@@ -325,7 +334,15 @@
     const moveToIceBox = /** @type {HTMLInputElement} */ (document.getElementById(
         'mailmindr--icebox'
     ));
-    moveToIceBox.disabled = editMindr || !isIceboxFolderSet;
+
+    if (editMindr) {
+        moveToIceBox.disabled = true;
+    } else if (!isIceboxFolderSet) {
+        moveToIceBox.disabled = true;
+    } else {
+        moveToIceBox.disabled = false;
+    }
+
     moveToIceBox.checked = editMindr
         ? sourceFolderIsIceboxFolder
         : isIceboxFolderSet;
@@ -425,46 +442,13 @@
         )} | mailmindr`;
     }
 
-    const remindMeMinutesBefore = [
-        { minutes: 0, display: 0, unit: 'on-time' },
-        { minutes: 5, display: 5, unit: 'minutes' },
-        { minutes: 15, display: 15, unit: 'minutes' },
-        { minutes: 30, display: 30, unit: 'minutes' },
-        { minutes: 60, display: 1, unit: 'hours' },
-        { minutes: 120, display: 2, unit: 'hours' },
-        { minutes: 240, display: 4, unit: 'hours' },
-        { minutes: -1, display: null, unit: 'no-reminder' }
-    ];
     const remindMe = document.getElementById('mailmindr--preset-remind-me');
-    remindMeMinutesBefore.forEach(item => {
-        const option = document.createElement('option');
-        const { minutes, unit, display: displayedValue } = item;
-
-        option.value = String(minutes);
-
-        if (unit === 'on-time') {
-            option.innerText = pluralize(
-                displayedValue,
-                'mailmindr.utils.core.remindme.before.on-time'
-            );
-        } else if (unit === 'minutes') {
-            option.innerText = pluralize(
-                displayedValue,
-                'mailmindr.utils.core.remindme.before.minutes'
-            );
-        } else if (unit === 'hours') {
-            option.innerText = pluralize(
-                displayedValue,
-                'mailmindr.utils.core.remindme.before.hours'
-            );
-        } else if (unit === 'no-reminder') {
-            option.innerText = pluralize(
-                displayedValue,
-                'mailmindr.utils.core.remindme.before.no-reminder'
-            );
-        }
-        remindMe.appendChild(option);
-    });
+    createRemindMeBeforePicker(
+        document,
+        remindMe,
+        remindMeMinutesBefore,
+        settings.defaultRemindMeMinutesBefore
+    );
 
     translateDocument(document);
 
diff -Nru mailmindr-1.4.0/views/dialogs/mindr-alert/index.js mailmindr-1.7.1/views/dialogs/mindr-alert/index.js
--- mailmindr-1.4.0/views/dialogs/mindr-alert/index.js	2022-08-12 15:32:09.000000000 +0200
+++ mailmindr-1.7.1/views/dialogs/mindr-alert/index.js	2024-08-04 22:14:20.000000000 +0200
@@ -24,6 +24,15 @@
 
 // 
 
+const openMindrByGuid = async guid => {
+    await messenger.runtime.sendMessage({
+        action: 'navigate:open-message-by-mindr-guid',
+        payload: {
+            guid
+        }
+    });
+};
+
 const onMindrClick = mindr => {
     const headerItem = document.getElementsByTagName('header').item(0);
     [...headerItem.childNodes].forEach(child => child.remove());
@@ -31,12 +40,7 @@
     headerItem.appendChild(item);
 
     item.addEventListener('click', async () => {
-        await messenger.runtime.sendMessage({
-            action: 'navigate:open-message-by-mindr-guid',
-            payload: {
-                guid: mindr.guid
-            }
-        });
+        await openMindrByGuid(mindr.guid);
     });
 
     selectListItem(mindr);
@@ -105,6 +109,7 @@
     mindrs.forEach(mindr => {
         const item = createListItem(mindr);
         item.onclick = () => onMindrClick(mindr);
+        item.ondblclick = () => openMindrByGuid(mindr.guid);
         listElement.appendChild(item);
     });
 };
@@ -187,7 +192,7 @@
     const { active, overdue } = message;
     const selectedGuid = findSelectedGuid();
 
-    logger.log(`active: `, active, `overdue: `, overdue);
+    logger.log(`alert -- active/overdue: `, { active, overdue });
     const mindrs = [...overdue, ...active].filter(
         (item, index, list) =>
             list.findIndex(value => value.guid === item.guid) === index
@@ -209,7 +214,7 @@
         name: 'connection:mindr-alert'
     });
 
-    await port.postMessage({
+    const _result = await port.postMessage({
         action: 'dialog:open',
         payload: { name: 'mindr-alert' }
     });
@@ -255,6 +260,7 @@
 };
 
 document.addEventListener('DOMContentLoaded', onLoad, { once: true });
+
 document.addEventListener('keydown', async event => {
     if (event.code === 'Escape') {
         clearList();
diff -Nru mailmindr-1.4.0/views/options/index.html mailmindr-1.7.1/views/options/index.html
--- mailmindr-1.4.0/views/options/index.html	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/views/options/index.html	2024-08-04 22:14:20.000000000 +0200
@@ -144,6 +144,25 @@
                     <div class="mailmindr-options mailmindr-options--oneline">
                         <div>
                             <label
+                                data-i18n="view.options.default-reminder-preset.label"
+                            ></label>
+                            <span
+                                class="mailmindr-option-description"
+                                id="mailmindr-options_default-reminder-preset--description"
+                                data-i18n="view.options.default-reminder-preset.description"
+                            >
+                            </span>
+                        </div>
+                        <div>
+                            <select
+                                id="mailmindr-options_default-reminder-preset"
+                            >
+                            </select>
+                        </div>
+                    </div>
+                    <div class="mailmindr-options mailmindr-options--oneline">
+                        <div>
+                            <label
                                 data-i18n="view.options.default-icebox-folder.label"
                             ></label>
                             <span
diff -Nru mailmindr-1.4.0/views/options/index.js mailmindr-1.7.1/views/options/index.js
--- mailmindr-1.4.0/views/options/index.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/views/options/index.js	2024-08-04 22:14:20.000000000 +0200
@@ -5,6 +5,7 @@
 } from '../../modules/core-utils.mjs.js';
 import {
     clearContents,
+    createRemindMeBeforePicker,
     createTimePresetPicker,
     selectDefaultActionPreset,
     selectDefaultTimePreset,
@@ -147,7 +148,7 @@
 
 const displaySettings = async options => {
     const { presets, settings } = options;
-    const { time, actions } = presets;
+    const { time, actions, remindMeMinutesBefore } = presets;
 
     displayTimePresets(time);
 
@@ -156,6 +157,7 @@
         defaultTimePreset,
         defaultActionPreset,
         defaultIceboxFolder,
+        defaultRemindMeMinutesBefore,
         snoozeTime
     } = settings;
 
@@ -177,6 +179,16 @@
 
     selectDefaultActionPreset(defaultActionPresetPicker, defaultActionPreset);
 
+    const defaultRemindMeBeforePicker = document.getElementById(
+        'mailmindr-options_default-reminder-preset'
+    );
+    createRemindMeBeforePicker(
+        document,
+        defaultRemindMeBeforePicker,
+        remindMeMinutesBefore,
+        defaultRemindMeMinutesBefore
+    );
+
     // 
     // 
     // 
@@ -201,7 +213,10 @@
 
     const defaultIceBoxPicker = findIceboxPickerForIdentity('default');
     if (defaultIceBoxPicker && defaultIceboxFolder) {
-        selectDefaultIceboxFolder(defaultIceBoxPicker, defaultIceboxFolder);
+        selectDefaultIceboxFolder(
+            defaultIceBoxPicker,
+            defaultIceboxFolder.folder
+        );
     }
 };
 
@@ -228,8 +243,6 @@
 const onMessage = async message => {
     const { topic = '' } = message;
 
-    logger.warn(`received topic: '${topic}'`);
-
     switch (topic) {
         case 'settings:updated': {
             const {
@@ -380,6 +393,15 @@
         logger.log(`select default action preset:`, value);
     });
 
+    const defaultRemindMeBeforePicker = document.getElementById(
+        'mailmindr-options_default-reminder-preset'
+    );
+    defaultRemindMeBeforePicker.addEventListener('change', async sender => {
+        const value = JSON.parse(sender.target.value);
+        logger.log(`select default remindMeMinutesBefore preset:`, value);
+        await set('defaultRemindMeMinutesBefore', value);
+    });
+
     // 
     // 
     // 
@@ -433,9 +455,9 @@
     });
 };
 
-document.addEventListener('DOMContentLoaded', async () => {
-    await onLoad();
-});
+// 
+// 
+// 
 
 const createIceboxSettingLabel = (text, uniqueId) => {
     const label = document.createElement('label');
@@ -462,7 +484,10 @@
         const value = JSON.parse(sender.target.value);
         const accountIdentity = sender.srcElement.dataset.accountIdentity;
         if (accountIdentity === 'default') {
-            await set('defaultIceboxFolder', { accountIdentity, value });
+            await set('defaultIceboxFolder', {
+                accountIdentity,
+                folder: value
+            });
         } else {
             await set('setIceBoxFolder', { accountIdentity, folder: value });
         }
@@ -479,3 +504,5 @@
 
     return iceBoxPicker;
 };
+
+onLoad();
diff -Nru mailmindr-1.4.0/views/popups/create-outgoing-mindr/index.css mailmindr-1.7.1/views/popups/create-outgoing-mindr/index.css
--- mailmindr-1.4.0/views/popups/create-outgoing-mindr/index.css	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/views/popups/create-outgoing-mindr/index.css	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,173 @@
+ at import url('../../mailmindr-core.css');
+
+html {
+    padding: 0.5em;
+}
+
+body.mailmindr-inline-popup main * {
+    font-size: 13px;
+}
+
+body {
+    /* min-height: 320px; */
+    /* min-width: 430px; */
+    background-color: -moz-dialog;
+    /* -moz-default-background-color; */
+}
+
+h1 {
+    margin: 0 0 8px;
+    font-size: 22px;
+    font-weight: 300;
+    line-height: 1.3em;
+}
+
+label {
+    user-select: none;
+}
+
+input[type='checkbox'] {
+    /* display: none; */
+    height: 16px;
+    width: 16px;
+}
+
+input[type='checkbox'] + label {
+    padding: 0 0.5em;
+}
+
+input[type='checkbox']:disabled + label {
+    color: silver;
+}
+
+/* input[type='checkbox'] + label::before {
+    content: '';
+    display: block;
+    float: left;
+    height: 16px;
+    width: 16px;
+    border: 1px solid rgba(12, 12, 13, 0.1);
+    border-radius: 2px;
+    background-color: var(--grey-90-a10);
+} */
+
+/* input[type='checkbox']:checked + label::before {
+    background-image: url(chrome://global/skin/icons/check.svg);
+    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHklEQVQ4T2NkoBAwUqifYdQAhtEwACai0XQwGMIAACaYABGnE9aRAAAAAElFTkSuQmCC');
+    background-position: center;
+    background-repeat: no-repeat;
+    background-color: blue;
+} */
+
+/* input[type='checkbox'] + label:hover::before {
+    background-color: var(--grey-90-a20);
+} */
+
+/* input[type='checkbox']:checked:hover + label::before {
+    background-color: var(--blue-70);
+} */
+
+input[type='date'],
+input[type='time'] {
+    font-size: 100%;
+    padding: 4px 8px;
+    margin-bottom: 5px;
+    width: 100%;
+}
+
+main {
+    display: flex;
+    flex-direction: column;
+}
+
+.mailmindr-dialog {
+    display: grid;
+    /* grid-template-columns: 100px auto; */
+    grid-template-columns: auto;
+    column-gap: 10px;
+    row-gap: 4px;
+    grid-auto-flow: row;
+}
+
+.mailmindr-fieldwrapper--caption {
+    font-weight: bold;
+    min-height: 21px;
+}
+
+.mailmindr-fieldwrapper--caption > label {
+    vertical-align: -webkit-baseline-middle;
+}
+
+.mailmindr-fieldwrapper--content {
+    min-width: 0;
+}
+
+.mailmindr-fieldwrapper--content > label {
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+    display: block;
+}
+
+.mailmindr-buttonbar {
+    margin: 0.5em -0.25em;
+    color: initial;
+    /* grid-column: 2; */
+    display: flex;
+    justify-content: flex-end;
+    /* width: 100%; */
+
+    /* bottom: 0;
+    position: fixed;
+    left: 0;
+    right: 0; */
+}
+
+.mailmindr-buttonbar--wrapper {
+    display: flex;
+    width: 100%;
+    flex-direction: column;
+}
+
+button {
+    text-align: center;
+}
+
+select {
+    color: inherit !important;
+    border: 1px solid transparent;
+    border-radius: 2px;
+    min-height: 30px;
+    font-weight: 400;
+    padding: 0 8px;
+    text-decoration: none;
+    font-size: 1em;
+    background-color: rgba(12, 12, 13, 0.1);
+    width: 100%;
+}
+
+ at media (prefers-color-scheme: dark) {
+    * {
+        color: #f9f9fa;
+    }
+
+    body {
+        color: #f9f9fa;
+        background-color: #2a2a2e;
+    }
+
+    input[type='text'],
+    input[type='number'],
+    select {
+        border-color: rgba(249, 249, 250, 0.2);
+    }
+
+    input[type='date'],
+    input[type='time'] {
+        color: #f9f9fa;
+        background-color: #2a2a2e;
+        border-color: rgba(249, 249, 250, 0.2);
+        border-width: 1px;
+        border-radius: 2px;
+    }
+}
diff -Nru mailmindr-1.4.0/views/popups/create-outgoing-mindr/index.html mailmindr-1.7.1/views/popups/create-outgoing-mindr/index.html
--- mailmindr-1.4.0/views/popups/create-outgoing-mindr/index.html	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/views/popups/create-outgoing-mindr/index.html	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <link rel="stylesheet" href="chrome://global/locale/global.css" />
+        <link rel="stylesheet" href="./index.css" />
+        <title>mailmindr</title>
+    </head>
+    <body class="mailmindr-inline-popup">
+        <header>
+            <h1 data-i18n="view.dialog.create-outgoing-mindr.header"></h1>
+        </header>
+        <main>
+            <form class="mailmindr-dialog">
+                <div class="mailmindr-fieldwrapper--caption">
+                    <label
+                        data-i18n="view.dialog.create-outgoing-mindr.label.due"
+                    ></label>
+                </div>
+                <div class="mailmindr-fieldwrapper--content">
+                    <div>
+                        <select id="mailmindr--preset-time"></select>
+                    </div>
+                </div>
+                <div></div>
+                <div class="mailmindr-fieldwrapper--content">
+                    <div>
+                        <input id="mailmindr--date-picker" type="date" />
+                        <input id="mailmindr--time-picker" type="time" />
+                    </div>
+                </div>
+                <div class="mailmindr-fieldwrapper--caption">
+                    <label
+                        data-i18n="view.dialog.create-outgoing-mindr.label.action"
+                    ></label>
+                </div>
+                <div class="mailmindr-fieldwrapper--content">
+                    <select id="mailmindr--preset-action"></select>
+                </div>
+                <div class="mailmindr-fieldwrapper--caption">
+                    <label
+                        data-i18n="view.dialog.create-outgoing-mindr.label.remind-me"
+                    ></label>
+                </div>
+                <div class="mailmindr-fieldwrapper--content">
+                    <select id="mailmindr--preset-remind-me"></select>
+                </div>
+            </form>
+        </main>
+        <footer class="mailmindr-buttonbar">
+            <div class="mailmindr-buttonbar--wrapper">
+                <button
+                    style="display: none;"
+                    class="mailmindr-button mailmindr-button--remove"
+                    id="mailmindr--do-remove-mindr"
+                    data-i18n="view.dialog.create-outgoing-mindr.caption.remove-follow-up"
+                ></button>
+                <button
+                    class="mailmindr-button"
+                    id="mailmindr--do-create-mindr"
+                    type="submit"
+                    data-i18n="view.dialog.create-outgoing-mindr.caption.create-mindr"
+                ></button>
+                <button
+                    class="mailmindr-button"
+                    id="mailmindr--do-cancel-create-mindr"
+                    data-i18n="view.dialog.create-outgoing-mindr.caption.cancel"
+                ></button>
+            </div>
+        </footer>
+        <script type="module" src="./index.js"></script>
+    </body>
+</html>
diff -Nru mailmindr-1.4.0/views/popups/create-outgoing-mindr/index.js mailmindr-1.7.1/views/popups/create-outgoing-mindr/index.js
--- mailmindr-1.4.0/views/popups/create-outgoing-mindr/index.js	1970-01-01 01:00:00.000000000 +0100
+++ mailmindr-1.7.1/views/popups/create-outgoing-mindr/index.js	2024-08-04 22:14:20.000000000 +0200
@@ -0,0 +1,417 @@
+import {
+    genericFoldersAreEqual,
+    getGenericIceboxFolderForIdentityOrNull,
+    getParsedJsonOrDefaultValue,
+    localFolderToGenericFolder
+} from '../../../modules/core-utils.mjs.js';
+import {
+    clearContents,
+    createRemindMeBeforePicker,
+    createTimePresetPicker,
+    isDarkMode,
+    selectDefaultActionPreset,
+    selectDefaultTimePreset
+} from '../../../modules/ui-utils.mjs.js';
+import {
+    createCorrelationId,
+    createLogger
+} from '../../../modules/logger.mjs.js';
+import { translateDocument } from '../../../modules/ui-utils.mjs.js';
+
+const logger = createLogger('views/popups/create-outgoing-mindr');
+
+const getDialogParameters = () => {
+    const correlationId = createCorrelationId(`getDialogParameters`);
+    logger.log('BEGIN getDialogParameters', { correlationId });
+    const params = new URLSearchParams(window.location.search.substr(1));
+    const result = {
+        dialogId: params.get('dialogId'),
+        headerMessageId: params.get('headerMessageId'),
+        author: params.get('author'),
+        subject: params.get('subject'),
+        folderAccountId: params.get('folderAccountId'),
+        folderName: params.get('folderName'),
+        folderPath: params.get('folderPath'),
+        folderType: params.get('folderType'),
+        guid: params.get('guid'),
+        folderAccountIdentityMailAddress: params.get(
+            'folderAccountIdentityMailAddress'
+        )
+    };
+
+    logger.log('dialog result', { correlationId, result });
+    logger.log('END getDialogParameters', { correlationId });
+
+    return result;
+};
+
+const closePopup = async () => {
+    const correlationId = createCorrelationId('closePopup');
+    logger.log(`BEGIN closePopup`, { correlationId });
+    logger.log(`try to get dialog parameters`);
+    try {
+        const { dialogId } = getDialogParameters();
+        logger.log(`closing dialog ${dialogId}`);
+        window.close();
+    } catch (e) {
+        logger.error('create-outgoing-mindr::closePopup', e);
+    }
+    logger.log('END closePopup', { correlationId });
+};
+
+const doCancel = async () => await closePopup();
+
+const resetComposeActionIconAndLabel = async id => {
+    const path = isDarkMode()
+        ? '/images/mailmindr-flag--white.svg'
+        : '/images/mailmindr-flag.svg';
+    await Promise.all([
+        messenger.composeAction.setIcon({
+            path,
+            tabId: id
+        }),
+        messenger.composeAction.setLabel({
+            label: messenger.i18n.getMessage('mailmindrComposeMessageButton'),
+            tabId: id
+        })
+    ]);
+};
+
+const handleChangeTimePreset = event => {
+    const {
+        target: { value }
+    } = event;
+
+    const preset = getParsedJsonOrDefaultValue(value, {});
+    const { days, hours, minutes, isRelative, isSelectable } = preset;
+
+    if (!isSelectable) {
+        logger.log('nothing to change here');
+        return;
+    }
+
+    const millisecondsForDays = days * 24 * 60 * 60 * 1000;
+    let now = Date.now() + millisecondsForDays;
+
+    if (isRelative) {
+        now +=
+            hours * 60 * 60 * 1000 /* add hours */ +
+            minutes * 60 * 1000; /* add minutes */
+    }
+
+    const nowAsDate = new Date(now);
+    const newDate = new Date(
+        Date.UTC(
+            nowAsDate.getFullYear(),
+            nowAsDate.getMonth(),
+            nowAsDate.getDate()
+        )
+    );
+    /** @type {HTMLInputDateElement} */
+    const datePicker = document.getElementById('mailmindr--date-picker');
+    /** @type {HTMLInputTimeElement} */
+    const timePicker = document.getElementById('mailmindr--time-picker');
+
+    datePicker.valueAsDate = newDate;
+
+    if (isRelative) {
+        const hourString = `0${nowAsDate.getHours()}`.substr(-2);
+        const minuteString = `0${nowAsDate.getMinutes()}`.substr(-2);
+        const newTimePickerValue = `${hourString}:${minuteString}`;
+
+        timePicker.value = newTimePickerValue;
+    } else {
+        const hourString = `0${hours}`.substr(-2);
+        const minuteString = `0${minutes}`.substr(-2);
+        const newTimePickerValue = `${hourString}:${minuteString}`;
+
+        timePicker.value = newTimePickerValue;
+
+        const pickedDateTime = getDateTimefromPickers();
+
+        logger.info(pickedDateTime, new Date());
+
+        if (pickedDateTime <= new Date()) {
+            logger.info(
+                'adjusting time by adding a day, adjusted to: ',
+                getDateTimefromPickers()
+            );
+            // 
+            datePicker.valueAsDate = new Date(Date.now() + 24 * 60 * 60 * 1000);
+        }
+    }
+};
+
+const getDateTimefromPickers = () => {
+    /** @type {HTMLInputDateElement} */
+    const datePicker = document.getElementById('mailmindr--date-picker');
+    /** @type {HTMLInputTimeElement} */
+    const timePicker = document.getElementById('mailmindr--time-picker');
+
+    const timePickerValue = timePicker.value;
+    const [hours, minutes] = timePickerValue
+        .split(':')
+        .map(item => Number.parseInt(item, 10));
+
+    const [year, month, day] = datePicker.value.split('-');
+    const newDate = new Date(year, month - 1, day, hours, minutes, 0, 0);
+
+    logger.warn(
+        'current date from datepicker without adjusting time and timezone',
+        newDate
+    );
+
+    return newDate;
+};
+
+const getActionTemplateFromPicker = () => {
+    const actionTemplatePicker = /** @type {HTMLInputElement} */ (document.getElementById(
+        'mailmindr--preset-action'
+    ));
+    const actionTemplate = JSON.parse(actionTemplatePicker.value);
+
+    return actionTemplate;
+};
+
+const doRemove = async () => {
+    const { windowId, id } = await messenger.tabs.getCurrent();
+    const sender = { windowId, id };
+    const removed = await messenger.runtime.sendMessage({
+        action: 'mindr:remove-outgoing-mindr',
+        payload: { sender }
+    });
+
+    if (removed && removed.status && removed.status === 'ok') {
+        await resetComposeActionIconAndLabel(id);
+        doCancel();
+    }
+};
+
+const onLoad = async () => {
+    const { windowId, id } = await messenger.tabs.getCurrent();
+    const result = await messenger.runtime.sendMessage({
+        action: 'dialog:open',
+        payload: { name: 'set-outgoing-mindr', sender: { windowId, id } }
+    });
+
+    const {
+        payload: {
+            settings,
+            presets: { time, actions, remindMeMinutesBefore },
+            draft
+        }
+    } = result;
+
+    const editMindr = Boolean(draft);
+    const removeButton = document.getElementById('mailmindr--do-remove-mindr');
+    removeButton.addEventListener('click', doRemove);
+    removeButton.setAttribute(
+        'style',
+        editMindr ? 'display: block;' : 'display: none;'
+    );
+
+    const cancelButton = document.getElementById(
+        'mailmindr--do-cancel-create-mindr'
+    );
+    cancelButton.addEventListener('click', doCancel);
+
+    const acceptButton = document.getElementById('mailmindr--do-create-mindr');
+    acceptButton.addEventListener('click', async (
+        source,
+        /** @type{ MouseEvent} */ event
+    ) => {
+        const sender = await messenger.windows.getLastFocused({
+            windowTypes: ['messageCompose']
+        });
+        doAccept(sender);
+    });
+
+    /** @type {HTMLInputDateElement} */
+    const datePicker = document.getElementById('mailmindr--date-picker');
+    /** @type {HTMLInputTimeElement} */
+    const timePicker = document.getElementById('mailmindr--time-picker');
+
+    const now = new Date();
+    const hours = `0${now.getHours()}`.substr(-2);
+    const minutes = `0${now.getMinutes()}`.substr(-2);
+
+    timePicker.value = [hours, minutes].join(':');
+    datePicker.valueAsDate = now;
+
+    const actionPresets = document.getElementById('mailmindr--preset-action');
+    actions.map(actionPreset => {
+        const actionOption = document.createElement('option');
+        actionOption.value = JSON.stringify(actionPreset);
+        actionOption.innerText = actionPreset.text;
+
+        actionPresets.appendChild(actionOption);
+    });
+
+    const timePresets = createTimePresetPicker(
+        document.getElementById('mailmindr--preset-time'),
+        time
+    );
+    const handlePickerChange = () => {
+        const presetTimePicker = /** @type {HTMLSelectElement} */ (document.getElementById(
+            'mailmindr--preset-time'
+        ));
+        presetTimePicker.selectedIndex = 0;
+    };
+
+    datePicker.addEventListener('change', handlePickerChange);
+    timePicker.addEventListener('change', handlePickerChange);
+    timePresets.addEventListener('change', handleChangeTimePreset);
+
+    if (editMindr) {
+        const { mindr } = draft;
+        const due = mindr.due;
+        const dueHours = `0${due.getHours()}`.substr(-2);
+        const dueMinutes = `0${due.getMinutes()}`.substr(-2);
+
+        timePicker.value = [dueHours, dueMinutes].join(':');
+        datePicker.valueAsDate = due;
+
+        timePresets.selectedIndex = 0;
+
+        const preselectedAction = mindr?.actionTemplate
+            ? { ...mindr?.actionTemplate, moveMessageTo: undefined }
+            : undefined;
+
+        selectDefaultActionPreset(actionPresets, preselectedAction);
+    } else {
+        const defaultTimePreset = settings?.defaultTimePreset;
+        const defaultActionPreset = settings?.defaultActionPreset;
+
+        selectDefaultTimePreset(timePresets, defaultTimePreset);
+        selectDefaultActionPreset(actionPresets, defaultActionPreset);
+
+        const changeEvent = new Event('change');
+        timePresets.dispatchEvent(changeEvent);
+    }
+
+    const remindMe = document.getElementById('mailmindr--preset-remind-me');
+    // 
+    createRemindMeBeforePicker(
+        document,
+        remindMe,
+        remindMeMinutesBefore,
+        settings.defaultRemindMeMinutesBefore
+    );
+
+    translateDocument(document);
+};
+
+document.addEventListener('DOMContentLoaded', onLoad, { once: true });
+document.addEventListener('keydown', async event => {
+    if (event.code === 'Escape') {
+        await doCancel();
+    }
+});
+
+const doAccept = async (/** @type {Window} */ sender) => {
+    // 
+    const remindMe = document.getElementById('mailmindr--preset-remind-me');
+    const remindMeMinutesBefore = parseInt(
+        /** @type {HTMLInputElement} */ (remindMe).value || '0',
+        10
+    );
+
+    const due = getDateTimefromPickers();
+    const actionTemplate = getActionTemplateFromPicker();
+
+    // 
+    // 
+    // 
+    // 
+    // 
+    // 
+    // 
+    // 
+    // 
+
+    // 
+
+    const {
+        guid,
+        headerMessageId,
+        author,
+        subject,
+        folderAccountId,
+        folderName,
+        folderPath,
+        folderType,
+        folderAccountIdentityMailAddress
+    } = getDialogParameters();
+
+    if (remindMeMinutesBefore) {
+        if (remindMeMinutesBefore >= 0) {
+            actionTemplate.showReminder = true;
+        } else {
+            actionTemplate.showReminder = false;
+        }
+    }
+
+    const { windowId, id } = await messenger.tabs.getCurrent();
+    const payload = {
+        mindr: {
+            guid,
+            headerMessageId,
+            due,
+            remindMeMinutesBefore,
+            actionTemplate,
+            notes: '',
+            metaData: {
+                headerMessageId,
+                author,
+                subject,
+                folderAccountId,
+                folderName,
+                folderPath,
+                folderType,
+                folderAccountIdentityMailAddress
+            },
+            isWaitingForReply: true,
+            doMoveToIcebox: false
+        },
+        sender: { windowId, id }
+    };
+    const result = await messenger.runtime.sendMessage({
+        action: 'mindr:create-outgoing',
+        payload
+    });
+    if (result && result.status === 'ok') {
+        // 
+        const path = isDarkMode()
+            ? '/images/mailmindr-flag_marker--white.svg'
+            : '/images/mailmindr-flag_marker.svg';
+        const currentLocale = navigator.language;
+        const formattedTime = new Intl.DateTimeFormat(currentLocale, {
+            timeStyle: 'short'
+        }).format(due);
+        const formattedDate = new Intl.DateTimeFormat(currentLocale, {
+            dateStyle: 'short'
+        }).format(due);
+        const formattedDateAndTime = new Intl.DateTimeFormat(currentLocale, {
+            dateStyle: 'medium',
+            timeStyle: 'short'
+        }).format(due);
+
+        await Promise.all([
+            messenger.composeAction.setIcon({
+                path,
+                tabId: id
+            }),
+            messenger.composeAction.setLabel({
+                label: messenger.i18n.getMessage(
+                    'mailmindrComposeMessageButton.detailed',
+                    [formattedDate, formattedTime, formattedDateAndTime]
+                ),
+                tabId: id
+            })
+        ]);
+
+        doCancel();
+    } else {
+        await resetComposeActionIconAndLabel(id);
+    }
+};
diff -Nru mailmindr-1.4.0/views/popups/list-all/index.css mailmindr-1.7.1/views/popups/list-all/index.css
--- mailmindr-1.4.0/views/popups/list-all/index.css	2022-08-12 15:32:09.000000000 +0200
+++ mailmindr-1.7.1/views/popups/list-all/index.css	2024-08-04 22:14:20.000000000 +0200
@@ -23,15 +23,28 @@
     text-align: center;
 }
 
+button.mailmindr-button--micro {
+    font-size: 12px;
+    height: unset;
+    min-height: 21px;
+}
+
 button:hover {
     border-color: transparent;
 }
 
 .mailmindr-popup-header {
     border-bottom: 0.5px solid silver;
-    padding: 0.75em 1em;
+    /* padding: 0.75em 1em; */
+    padding: 0.25em 0.5em;
     text-align: center;
-    background: linear-gradient(45deg, var(--purple-40), var(--purple-50));
+    /* background: linear-gradient(45deg, var(--purple-40), var(--purple-50)); */
+    background-color: #eee;
+}
+
+.mailmindr-popup-header button {
+    margin: 0.25em;
+    min-height: 23px;
 }
 
 .mailmindr-popup-header a {
@@ -195,11 +208,53 @@
     color: var(--grey-90);
 }
 
+.mailmindr-list-label-wrapper {
+    padding-left: 12px;
+    margin-bottom: 2px;
+}
+
+.mailmindr-list-label {
+    border-radius: 4px;
+    color: var(--grey-90);
+    text-transform: uppercase;
+    padding: 2px 6px;
+    margin: 2px;
+    font-size: smaller;
+    background-color: var(--yellow-50);
+    display: inline;
+}
+
+.mailmindr-list-label--awaiting::before {
+    content: '';
+    height: 12px;
+    width: 12px;
+    background-image: url(chrome://messenger/skin/icons/hourglass.svg);
+    background-repeat: no-repeat;
+    background-position: center center;
+    padding: 10px;
+}
+.mailmindr-list-label--awaiting-reply-received {
+    text-decoration: line-through;
+}
+
 @media (prefers-color-scheme: dark) {
+    * {
+        color: #f9f9fa;
+    }
+
+    body {
+        color: #f9f9fa;
+        background-color: #2a2a2e;
+    }
+
     footer {
         background-color: var(--grey-90-a80);
     }
 
+    .mailmindr-popup-header {
+        background-color: var(--grey-90-a80);
+    }
+
     .mailmindr-list-placeholder p {
         color: var(--grey-10);
     }
diff -Nru mailmindr-1.4.0/views/popups/list-all/index.html mailmindr-1.7.1/views/popups/list-all/index.html
--- mailmindr-1.4.0/views/popups/list-all/index.html	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/views/popups/list-all/index.html	2024-08-04 22:14:20.000000000 +0200
@@ -34,11 +34,30 @@
         </ul> -->
         <main>
             <div class="mailmindr-popup-header">
+                <!--
                 <a
                     href="https://mailmindr.net/release-notes"
                     target="_blank"
                     data-i18n="view.popups.list-all.link.whats.new"
                 ></a>
+                !-->
+                <label>
+                    <span aria-hidden="true">
+                        Filter:
+                    </span>
+                    <input
+                        id="mailmindr--search-field"
+                        type="text"
+                        aria-label="Filter follow-ups"
+                    />
+                </label>
+                <button
+                    class="mailmindr-button mailmindr-button--micro"
+                    aria-label="Clear filter"
+                    id="mailmindr--search-field-clear"
+                >
+                    <span aria-hidden="true" title="Clear filter">?</span>
+                </button>
             </div>
             <ul id="mailmindr--list" class="mailmindr-list" tabindex="0">
                 <div class="mailmindr-list-placeholder">
diff -Nru mailmindr-1.4.0/views/popups/list-all/index.js mailmindr-1.7.1/views/popups/list-all/index.js
--- mailmindr-1.4.0/views/popups/list-all/index.js	2022-08-12 15:32:08.000000000 +0200
+++ mailmindr-1.7.1/views/popups/list-all/index.js	2024-08-04 22:14:20.000000000 +0200
@@ -5,6 +5,7 @@
 import { createLogger } from '../../../modules/logger.mjs.js';
 import { webHandler } from '../../../modules/ui-utils.mjs.js';
 import { translateDocument } from '../../../modules/ui-utils.mjs.js';
+import { hasReply } from '../../../modules/core-utils.mjs.js';
 
 let currentMindrGuid = null;
 
@@ -38,11 +39,18 @@
     window.close();
 };
 
+/**
+ * Render item markup for a mindr
+ *
+ * @param {Mindr} mindr
+ * @returns HTMLElement
+ */
 const createMindrItem = mindr => {
     const {
         guid,
         due,
-        metaData: { author, subject }
+        metaData: { author, subject },
+        isWaitingForReply = false
     } = mindr;
     const relative = due - Date.now();
     const item = document.createElement('li');
@@ -111,6 +119,28 @@
     contentWrapper.appendChild(authorWrapper);
     contentWrapper.appendChild(dueWrapper);
 
+    if (isWaitingForReply) {
+        const markerWrapper = document.createElement('div');
+        const markerItem = document.createElement('div');
+
+        markerWrapper.className = 'mailmindr-list-label-wrapper';
+
+        markerItem.classList.add('mailmindr-list-label');
+        markerItem.classList.add('mailmindr-list-label--awaiting');
+
+        if (hasReply(mindr)) {
+            markerItem.classList.add(
+                'mailmindr-list-label--awaiting-reply-received'
+            );
+        }
+
+        const markerLabel = document.createTextNode('awaiting reply');
+
+        markerItem.appendChild(markerLabel);
+        markerWrapper.appendChild(markerItem);
+        contentWrapper.appendChild(markerWrapper);
+    }
+
     item.appendChild(contentWrapper);
     item.addEventListener('click', async () => openMessageByGuid(guid));
     item.addEventListener('mouseover', async () => {
@@ -155,26 +185,16 @@
 const selectNextElement = (listElement, guid, direction) => {
     const children = Array.from(listElement.children);
     if (guid) {
-        /** @type {HTMLLIElement} */
-        const selectedElement = document.querySelector(
-            `li[data-guid='${guid}'`
-        );
         toggleItemSelection(guid, false);
 
-        let nextElement = selectedElement;
         const index = children.findIndex(
             element => element.dataset.guid === guid
         );
 
-        if (direction !== 0) {
-            if (index === children.length - 1) {
-                nextElement = children[0];
-            } else if (index === 0 && direction < 0) {
-                nextElement = children[children.length - 1];
-            } else {
-                nextElement = children[index + direction];
-            }
-        }
+        const newIndex =
+            (index + children.length + direction) % children.length;
+        const nextElement = children[newIndex];
+
         currentMindrGuid = nextElement.dataset.guid;
         toggleItemSelection(currentMindrGuid, true);
     } else {
@@ -210,6 +230,7 @@
     if (mindrs.length) {
         clearList(listElement);
         displayList(listElement, mindrs);
+        selectNextElement(listElement, mindrs[0].guid, 0);
 
         // 
         /** @type {HTMLElement} */
@@ -233,6 +254,45 @@
         // 
     }
 
+    const searchField = /** @type {HTMLInputElement} */ document.getElementById(
+        'mailmindr--search-field'
+    );
+    searchField.addEventListener('keydown', event => {
+        const { code, shiftKey, metaKey, altKey, ctrlKey } = event;
+
+        const text = searchField.value;
+        let items = mindrs;
+        if (code === 'Delete' && shiftKey && !metaKey && !altKey && !ctrlKey) {
+            // 
+            searchField.value = '';
+        } else if (text.length >= 3) {
+            items = mindrs.filter(item => {
+                const {
+                    metaData: { author, subject }
+                } = item;
+                return (
+                    (author || '').toLowerCase().indexOf(text) >= 0 ||
+                    (subject || '').toLowerCase().indexOf(text) >= 0
+                );
+            });
+        }
+
+        clearList(listElement);
+        displayList(listElement, items);
+        if (items && items.length) {
+            selectNextElement(listElement, items[0].guid, 0);
+        }
+    });
+
+    const clearFilterButton = document.getElementById(
+        'mailmindr--search-field-clear'
+    );
+    clearFilterButton.addEventListener('click', () => {
+        searchField.value = '';
+        clearList(listElement);
+        displayList(listElement, mindrs);
+    });
+
     Array.from(
         document.querySelectorAll('button.mailmindr-button-web')
     ).forEach(btn => {


More information about the Pkg-mozext-maintainers mailing list