[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1082115: marked as done (bookworm-pu: package mailmindr/1.7.1-1~deb12u1)



Your message dated Sat, 11 Jan 2025 11:03:09 +0000
with message-id <E1tWZGn-009jZc-6G@coccia.debian.org>
and subject line Close 1082115
has caused the Debian Bug report #1082115,
regarding bookworm-pu: package mailmindr/1.7.1-1~deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1082115: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1082115
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: mailmindr@packages.debian.org, mechtilde@debian.org
Control: affects -1 + src:mailmindr
User: release.debian.org@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.
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@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@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@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@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@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@lists.alioth.debian.org>
 Uploaders: Mechtilde Stehmann <mechtilde@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@debian.org>
+Copyright: 2019-2024 Mechtilde Stehmann <mechtilde@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@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@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 @@
+@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%;
+}
+
+@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 => {

--- End Message ---
--- Begin Message ---
Version: 12.9
This update has been released as part of 12.9. Thank you for your contribution.

--- End Message ---

Reply to: