[PATCH mumi 0/3] Add a button to copy a message Message-ID to the clipboard.

  • Done
  • quality assurance status badge
Details
4 participants
  • Arun Isaac
  • Felix Lechner
  • Maxim Cournoyer
  • Ricardo Wurmus
Owner
unassigned
Submitted by
Maxim Cournoyer
Severity
normal
M
M
Maxim Cournoyer wrote on 24 Jan 03:15 +0100
(address . guix-patches@gnu.org)(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
20240124021535.15946-1-maxim.cournoyer@gmail.com
This series adds a new HTML element to each message header to easily
copy the Message-ID of a message into the clipboard. It makes use of
the (already included) Pico CSS library for tooltips and some new
JavaScript event handler. The motivation was to make it easier to
retrieve the Message-ID for passing it to the 'b4 shazam' command when
applying long patches series.


Maxim Cournoyer (3):
README.org: Add new sections to help newcomers get started.
.gitignore: Register mumi.xapian and signing-key files.
html: Add a button to copy a Message-ID to the clipboard.

.gitignore | 2 ++
README.org | 24 ++++++++++++++++++++++
assets/js/mumi.js | 31 ++++++++++++++++++++++++++++-
assets/mumi.scss | 23 ++++++++++++++++++---
mumi/web/view/html.scm | 20 +++++++++++++++----
mumi/web/view/utils.scm | 44 +++++++++++++++++++++++++++--------------
6 files changed, 121 insertions(+), 23 deletions(-)


base-commit: 025fc600f1cb4c73042bf920aee3e07d5fb9c53a
--
2.41.0
M
M
Maxim Cournoyer wrote on 24 Jan 03:20 +0100
[PATCH mumi 1/3] README.org: Add new sections to help newcomers get started.
(address . 68680@debbugs.gnu.org)(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
20240124022055.16021-2-maxim.cournoyer@gmail.com
* README.org (Running a local instance of mumi): New section.
(Disabling browser caching): Likewise.
---

README.org | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

Toggle diff (34 lines)
diff --git a/README.org b/README.org
index fd1d77b..d092de7 100644
--- a/README.org
+++ b/README.org
@@ -11,3 +11,27 @@ run
#+BEGIN_SRC shell
$ guix shell -D mumi
#+END_SRC
+
+** Running a local instance of mumi
+
+First copy some test mail data to be indexed:
+
+#+begin_src shell
+ $ cp -a tests/data data
+#+end_src
+
+Then, to have these emails indexed, run:
+
+#+begin_src shell
+ $ ./pre-inst-env mumi fetch
+#+end_src
+
+You should now be able to visit http://0.0.0.0:1234 in your browser
+and see your local mumi instance running.
+
+** Disabling browser caching
+
+If you modify the CSS or JavaScript source files, you'll want to make
+sure your browser doesn't keep cached copies. This can be done by
+changing a preference in the development tools menus, which is called
+something like "Disable cache (while DevTools is active)".
--
2.41.0
M
M
Maxim Cournoyer wrote on 24 Jan 03:20 +0100
[PATCH mumi 2/3] .gitignore: Register mumi.xapian and signing-key files.
(address . 68680@debbugs.gnu.org)(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
20240124022055.16021-3-maxim.cournoyer@gmail.com
Signed-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>
---

.gitignore | 2 ++
1 file changed, 2 insertions(+)

Toggle diff (17 lines)
diff --git a/.gitignore b/.gitignore
index 2604e48..7247392 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,10 @@ config.log
config.status
configure
+mumi.xapian
mumi/config.scm
scripts/mumi
+signing-key
pre-inst-env
*.log
*.trs
--
2.41.0
M
M
Maxim Cournoyer wrote on 24 Jan 03:20 +0100
[PATCH mumi 3/3] html: Add a button to copy a Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
20240124022055.16021-4-maxim.cournoyer@gmail.com
* mumi/web/view/html.scm (issue-page)
<copy-message-id-button>: New HTML element.
* mumi/web/view/utils.scm (download-icon): Update source. Use 'rem'
as size unit.
(copy-icon): New variable.
(display-message-body) <download-part>: Add IDs to buttons. Add to
"message-button" class.
* assets/mumi.scss: Refactor spacing of message header buttons via a
flex display. Add a shrinking animation to message buttons on hover.
* assets/js/mumi.js (mumi): Register an event for it that copies the
Message-ID to the clipboard. Add js-indent-level prop line.

Signed-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>
---

assets/js/mumi.js | 31 ++++++++++++++++++++++++++++-
assets/mumi.scss | 23 ++++++++++++++++++---
mumi/web/view/html.scm | 20 +++++++++++++++----
mumi/web/view/utils.scm | 44 +++++++++++++++++++++++++++--------------
4 files changed, 95 insertions(+), 23 deletions(-)

Toggle diff (222 lines)
diff --git a/assets/js/mumi.js b/assets/js/mumi.js
index ab29f08..0d25c5a 100644
--- a/assets/js/mumi.js
+++ b/assets/js/mumi.js
@@ -1,4 +1,4 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later -*- js-indent-level: 2; -*-
var mumi = (function () {
const possibleTokens = [
{ text: 'is:open' },
@@ -129,12 +129,41 @@ var mumi = (function () {
var init = function () {
initTokenInput ();
};
+
+ // Copy a message Message-ID to the clipboard.
+ var setupMessageIdButtonHandler = function () {
+
+ let messageIdClickHandler = (evt) => {
+ messageIdButton = evt.currentTarget;
+ originalTooltip = messageIdButton.dataset.tooltip;
+ var messageId = messageIdButton.dataset.messageId;
+ if (!window.isSecureContext) {
+ console.log("not in a secure context -- " +
+ "cannot copy message-id to clipboard\n" +
+ "tip: for testing, open via http://localhost:1234");
+ return;
+ }
+ // Update button's tooltip for the next 3 s.
+ messageIdButton.dataset.tooltip = "Copied!";
+ setTimeout(() => { messageIdButton.dataset.tooltip = originalTooltip; },
+ 3000);
+ navigator.clipboard.writeText(messageId);
+ console.log("copied Message-ID " + messageId + " to clipboard");
+ };
+
+ var messageIdButton = document.getElementById("copy-message-id-button");
+ if (messageIdButton === null) { return; }
+ messageIdButton.addEventListener("click", messageIdClickHandler);
+ };
+
return({
'init': init,
'lines': setupLineHandler,
+ 'messageIdButtonHandler': setupMessageIdButtonHandler,
});
})();
window.addEventListener ("load", mumi.init);
window.addEventListener ("DOMContentLoaded", mumi.lines);
+window.addEventListener ("DOMContentLoaded", mumi.messageIdButtonHandler);
// @license-end
diff --git a/assets/mumi.scss b/assets/mumi.scss
index 822f110..60dabb1 100644
--- a/assets/mumi.scss
+++ b/assets/mumi.scss
@@ -506,11 +506,28 @@ details {
margin-right: 0.2em;
}
-.download-message,
.download-part {
float: right;
- font-size: 0.8em;
- font-style: italic;
+}
+
+.header-buttons {
+ display: flex;
+ flex-direction: row;
+ float: right;
+ justify-content: flex-end;
+ }
+
+.header-buttons > * {
+ margin: 0 0 0 0.5rem;
+ // Custom buttons: undo the Pico CSS default style.
+ background: revert;
+ border: revert;
+ color: revert;
+ padding: revert;
+}
+
+.message-button:hover {
+ transform: scale(0.95);
}
@media (min-width: 768px) {
diff --git a/mumi/web/view/html.scm b/mumi/web/view/html.scm
index 8f06a36..3709134 100644
--- a/mumi/web/view/html.scm
+++ b/mumi/web/view/html.scm
@@ -1,6 +1,7 @@
;;; mumi -- Mediocre, uh, mail interface
;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019, 2023 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -612,6 +613,7 @@ currently disabled."))
(not (bug-archived bug)))
mailer-form
disabled-mailer)))
+
(define (show-message message-number message previous-subject)
`((div
(a (@ (class "message-anchor")
@@ -642,10 +644,20 @@ currently disabled."))
message-number)))
(title ,(date->string (date message))))
,(time->string (date message)))))
- (div (@ (class "download-message"))
- (a (@ (href ,(format #f "/issue/~a/raw/~a"
- id message-number)))
- ,download-icon))
+ (div (@ (class "header-buttons"))
+ (div (@ (id "copy-message-id-button")
+ (class "message-button")
+ (role "button") ;specific to Pico CSS
+ (data-tooltip "Copy Message-ID")
+ (data-message-id ,(message-id message)))
+ ,copy-icon)
+ (div (@ (id "download-raw-message-button")
+ (class "message-button")
+ (role "button")
+ (data-tooltip "Download raw message"))
+ (a (@ (href ,(format #f "/issue/~a/raw/~a"
+ id message-number)))
+ ,download-icon)))
,@(if (string-suffix? previous-subject (subject message))
'()
`((div (@ (class "subject")) ,(subject message))))
diff --git a/mumi/web/view/utils.scm b/mumi/web/view/utils.scm
index 1ce7b64..ed83d15 100644
--- a/mumi/web/view/utils.scm
+++ b/mumi/web/view/utils.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -35,6 +36,7 @@
#:use-module (web uri)
#:export (prettify
avatar-color
+ copy-icon
download-icon
display-message-body
time->string))
@@ -215,23 +217,31 @@ numbers with the given MESSAGE-NUMBER."
;; https://icons.getbootstrap.com/icons/download/
(define download-icon
'(svg (@ (class "bi bi-download")
- (width "1em")
- (height "1em")
+ (width "1rem")
+ (height "1rem")
+ (viewBox "0 0 16 16")
+ (fill "currentColor")
+ (xmlns "http://www.w3.org/2000/svg"))
+ (path (@ (d "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 \
+1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 \
+1-2-2v-2.5a.5.5 0 0 1 .5-.5")))
+ (path (@ (d "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 \
+0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 \
+1 0-.708.708z")))))
+
+;; https://icons.getbootstrap.com/icons/copy/
+(define copy-icon
+ '(svg (@ (class "bi bi-copy")
+ (width "1rem")
+ (height "1rem")
(viewBox "0 0 16 16")
(fill "currentColor")
(xmlns "http://www.w3.org/2000/svg"))
- (title "Download")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M.5 8a.5.5 0 01.5.5V12a1 1 0 001 1h12a1 1 0 001-1\
-V8.5a.5.5 0 011 0V12a2 2 0 01-2 2H2a2 2 0 01-2-2V8.5A.5.5 0 01.5 8z")) "")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M5 7.5a.5.5 0 01.707 0L8 9.793 10.293 7.5a.5.5 0 \
-11.707.707l-2.646 2.647a.5.5 0 01-.708 0L5 8.207A.5.5 0 015 7.5z")) "")
(path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M8 1a.5.5 0 01.5.5v8a.5.5 0 01-1 0v-8A.5.5 0 018 1z")) "")))
+ (d "M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 \
+2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 \
+0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 \
+2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z")))))
(define* (display-message-body bug-num message-number message #:optional plain?)
"Convenience procedure to render MESSAGE (part of bug with number
@@ -285,7 +295,9 @@ lines when PLAIN? is #T."
"")))
((string-suffix? ".scm" attachment-name)
`(div (@ (class "multipart scheme"))
- (div (@ (class "download-part"))
+ (div (@ (id "download-scheme-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download Scheme file"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(highlights->sxml (highlight lex-scheme body))))
@@ -294,7 +306,9 @@ lines when PLAIN? is #T."
(list "multipart" (or (and content-type
(content-type->css-class content-type))
"")))))
- (div (@ (class "download-part"))
+ (div (@ (id "download-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download MIME part"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(cond
--
2.41.0
M
M
Maxim Cournoyer wrote on 24 Jan 03:29 +0100
Re: [bug#68680] [PATCH mumi 0/3] Add a button to copy a message Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
87h6j3zcou.fsf@gmail.com
+CC Ricardo and Arun in case they'd like to take a peek.

Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:

Toggle quote (24 lines)
> This series adds a new HTML element to each message header to easily
> copy the Message-ID of a message into the clipboard. It makes use of
> the (already included) Pico CSS library for tooltips and some new
> JavaScript event handler. The motivation was to make it easier to
> retrieve the Message-ID for passing it to the 'b4 shazam' command when
> applying long patches series.
>
>
> Maxim Cournoyer (3):
> README.org: Add new sections to help newcomers get started.
> .gitignore: Register mumi.xapian and signing-key files.
> html: Add a button to copy a Message-ID to the clipboard.
>
> .gitignore | 2 ++
> README.org | 24 ++++++++++++++++++++++
> assets/js/mumi.js | 31 ++++++++++++++++++++++++++++-
> assets/mumi.scss | 23 ++++++++++++++++++---
> mumi/web/view/html.scm | 20 +++++++++++++++----
> mumi/web/view/utils.scm | 44 +++++++++++++++++++++++++++--------------
> 6 files changed, 121 insertions(+), 23 deletions(-)
>
>
> base-commit: 025fc600f1cb4c73042bf920aee3e07d5fb9c53a

--
Thanks,
Maxim
M
M
Maxim Cournoyer wrote on 25 Jan 18:00 +0100
[PATCH mumi v2 0/3] Add a button to copy a message Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
20240125170042.12022-1-maxim.cournoyer@gmail.com
This series adds a new HTML element to each message header to easily
copy the Message-ID of a message into the clipboard. It makes use of
the (already included) Pico CSS library for tooltips and some new
JavaScript event handler. The motivation was to make it easier to
retrieve the Message-ID for passing it to the 'b4 shazam' command when
applying long patches series.

Changes in v2:
- Add timestamp to CSS and JavaScript file names to force reload

Maxim Cournoyer (3):
README.org: Add new sections to help newcomers get started.
.gitignore: Register mumi.xapian and signing-key files.
html: Add a button to copy a Message-ID to the clipboard.

.gitignore | 2 ++
README.org | 24 ++++++++++++++++++++++
assets/js/mumi.js | 31 ++++++++++++++++++++++++++++-
assets/mumi.scss | 23 ++++++++++++++++++---
mumi/web/view/html.scm | 24 ++++++++++++++++------
mumi/web/view/utils.scm | 44 +++++++++++++++++++++++++++--------------
6 files changed, 123 insertions(+), 25 deletions(-)


base-commit: 025fc600f1cb4c73042bf920aee3e07d5fb9c53a
--
2.41.0
M
M
Maxim Cournoyer wrote on 25 Jan 18:00 +0100
[PATCH mumi v2 1/3] README.org: Add new sections to help newcomers get started.
(address . 68680@debbugs.gnu.org)
20240125170042.12022-2-maxim.cournoyer@gmail.com
* README.org (Running a local instance of mumi): New section.
(Disabling browser caching): Likewise.
---

(no changes since v1)

README.org | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

Toggle diff (34 lines)
diff --git a/README.org b/README.org
index fd1d77b..d092de7 100644
--- a/README.org
+++ b/README.org
@@ -11,3 +11,27 @@ run
#+BEGIN_SRC shell
$ guix shell -D mumi
#+END_SRC
+
+** Running a local instance of mumi
+
+First copy some test mail data to be indexed:
+
+#+begin_src shell
+ $ cp -a tests/data data
+#+end_src
+
+Then, to have these emails indexed, run:
+
+#+begin_src shell
+ $ ./pre-inst-env mumi fetch
+#+end_src
+
+You should now be able to visit http://0.0.0.0:1234 in your browser
+and see your local mumi instance running.
+
+** Disabling browser caching
+
+If you modify the CSS or JavaScript source files, you'll want to make
+sure your browser doesn't keep cached copies. This can be done by
+changing a preference in the development tools menus, which is called
+something like "Disable cache (while DevTools is active)".
--
2.41.0
M
M
Maxim Cournoyer wrote on 25 Jan 18:00 +0100
[PATCH mumi v2 2/3] .gitignore: Register mumi.xapian and signing-key files.
(address . 68680@debbugs.gnu.org)
20240125170042.12022-3-maxim.cournoyer@gmail.com
---

(no changes since v1)

.gitignore | 2 ++
1 file changed, 2 insertions(+)

Toggle diff (17 lines)
diff --git a/.gitignore b/.gitignore
index 2604e48..7247392 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,10 @@ config.log
config.status
configure
+mumi.xapian
mumi/config.scm
scripts/mumi
+signing-key
pre-inst-env
*.log
*.trs
--
2.41.0
M
M
Maxim Cournoyer wrote on 25 Jan 18:00 +0100
[PATCH mumi v2 3/3] html: Add a button to copy a Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
20240125170042.12022-4-maxim.cournoyer@gmail.com
* mumi/web/view/html.scm (issue-page)
<copy-message-id-button>: New HTML element.
(layout): Bump timestamp on .css and .js files to force reload.
* mumi/web/view/utils.scm (download-icon): Update source. Use 'rem'
as size unit.
(copy-icon): New variable.
(display-message-body) <download-part>: Add IDs to buttons. Add to
"message-button" class.
* assets/mumi.scss: Refactor spacing of message header buttons via a
flex display. Add a shrinking animation to message buttons on hover.
* assets/js/mumi.js (mumi): Register an event for it that copies the
Message-ID to the clipboard. Add js-indent-level prop line.
* mumi/web/view/html.scm

---

Changes in v2:
- Add timestamp to CSS and JavaScript file names to force reload

assets/js/mumi.js | 31 ++++++++++++++++++++++++++++-
assets/mumi.scss | 23 ++++++++++++++++++---
mumi/web/view/html.scm | 24 ++++++++++++++++------
mumi/web/view/utils.scm | 44 +++++++++++++++++++++++++++--------------
4 files changed, 97 insertions(+), 25 deletions(-)

Toggle diff (236 lines)
diff --git a/assets/js/mumi.js b/assets/js/mumi.js
index ab29f08..0d25c5a 100644
--- a/assets/js/mumi.js
+++ b/assets/js/mumi.js
@@ -1,4 +1,4 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later -*- js-indent-level: 2; -*-
var mumi = (function () {
const possibleTokens = [
{ text: 'is:open' },
@@ -129,12 +129,41 @@ var mumi = (function () {
var init = function () {
initTokenInput ();
};
+
+ // Copy a message Message-ID to the clipboard.
+ var setupMessageIdButtonHandler = function () {
+
+ let messageIdClickHandler = (evt) => {
+ messageIdButton = evt.currentTarget;
+ originalTooltip = messageIdButton.dataset.tooltip;
+ var messageId = messageIdButton.dataset.messageId;
+ if (!window.isSecureContext) {
+ console.log("not in a secure context -- " +
+ "cannot copy message-id to clipboard\n" +
+ "tip: for testing, open via http://localhost:1234");
+ return;
+ }
+ // Update button's tooltip for the next 3 s.
+ messageIdButton.dataset.tooltip = "Copied!";
+ setTimeout(() => { messageIdButton.dataset.tooltip = originalTooltip; },
+ 3000);
+ navigator.clipboard.writeText(messageId);
+ console.log("copied Message-ID " + messageId + " to clipboard");
+ };
+
+ var messageIdButton = document.getElementById("copy-message-id-button");
+ if (messageIdButton === null) { return; }
+ messageIdButton.addEventListener("click", messageIdClickHandler);
+ };
+
return({
'init': init,
'lines': setupLineHandler,
+ 'messageIdButtonHandler': setupMessageIdButtonHandler,
});
})();
window.addEventListener ("load", mumi.init);
window.addEventListener ("DOMContentLoaded", mumi.lines);
+window.addEventListener ("DOMContentLoaded", mumi.messageIdButtonHandler);
// @license-end
diff --git a/assets/mumi.scss b/assets/mumi.scss
index 822f110..60dabb1 100644
--- a/assets/mumi.scss
+++ b/assets/mumi.scss
@@ -506,11 +506,28 @@ details {
margin-right: 0.2em;
}
-.download-message,
.download-part {
float: right;
- font-size: 0.8em;
- font-style: italic;
+}
+
+.header-buttons {
+ display: flex;
+ flex-direction: row;
+ float: right;
+ justify-content: flex-end;
+ }
+
+.header-buttons > * {
+ margin: 0 0 0 0.5rem;
+ // Custom buttons: undo the Pico CSS default style.
+ background: revert;
+ border: revert;
+ color: revert;
+ padding: revert;
+}
+
+.message-button:hover {
+ transform: scale(0.95);
}
@media (min-width: 768px) {
diff --git a/mumi/web/view/html.scm b/mumi/web/view/html.scm
index 8f06a36..b9603ec 100644
--- a/mumi/web/view/html.scm
+++ b/mumi/web/view/html.scm
@@ -1,6 +1,7 @@
;;; mumi -- Mediocre, uh, mail interface
;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019, 2023 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -62,11 +63,11 @@
(@ (rel "stylesheet")
(media "screen")
(type "text/css")
- (href "/css/mumi.css?20221231000000")))
+ (href "/css/mumi.css?20240125000000")))
(script
(@ (src "/js/tokeninput.js")))
(script
- (@ (src "/js/mumi.js")))
+ (@ (src "/js/mumi.js?20240125000000")))
,@head)
(body (script
(@ (src "/js/theme-switcher.js")))
@@ -612,6 +613,7 @@ currently disabled."))
(not (bug-archived bug)))
mailer-form
disabled-mailer)))
+
(define (show-message message-number message previous-subject)
`((div
(a (@ (class "message-anchor")
@@ -642,10 +644,20 @@ currently disabled."))
message-number)))
(title ,(date->string (date message))))
,(time->string (date message)))))
- (div (@ (class "download-message"))
- (a (@ (href ,(format #f "/issue/~a/raw/~a"
- id message-number)))
- ,download-icon))
+ (div (@ (class "header-buttons"))
+ (div (@ (id "copy-message-id-button")
+ (class "message-button")
+ (role "button") ;specific to Pico CSS
+ (data-tooltip "Copy Message-ID")
+ (data-message-id ,(message-id message)))
+ ,copy-icon)
+ (div (@ (id "download-raw-message-button")
+ (class "message-button")
+ (role "button")
+ (data-tooltip "Download raw message"))
+ (a (@ (href ,(format #f "/issue/~a/raw/~a"
+ id message-number)))
+ ,download-icon)))
,@(if (string-suffix? previous-subject (subject message))
'()
`((div (@ (class "subject")) ,(subject message))))
diff --git a/mumi/web/view/utils.scm b/mumi/web/view/utils.scm
index 1ce7b64..ed83d15 100644
--- a/mumi/web/view/utils.scm
+++ b/mumi/web/view/utils.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -35,6 +36,7 @@
#:use-module (web uri)
#:export (prettify
avatar-color
+ copy-icon
download-icon
display-message-body
time->string))
@@ -215,23 +217,31 @@ numbers with the given MESSAGE-NUMBER."
;; https://icons.getbootstrap.com/icons/download/
(define download-icon
'(svg (@ (class "bi bi-download")
- (width "1em")
- (height "1em")
+ (width "1rem")
+ (height "1rem")
+ (viewBox "0 0 16 16")
+ (fill "currentColor")
+ (xmlns "http://www.w3.org/2000/svg"))
+ (path (@ (d "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 \
+1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 \
+1-2-2v-2.5a.5.5 0 0 1 .5-.5")))
+ (path (@ (d "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 \
+0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 \
+1 0-.708.708z")))))
+
+;; https://icons.getbootstrap.com/icons/copy/
+(define copy-icon
+ '(svg (@ (class "bi bi-copy")
+ (width "1rem")
+ (height "1rem")
(viewBox "0 0 16 16")
(fill "currentColor")
(xmlns "http://www.w3.org/2000/svg"))
- (title "Download")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M.5 8a.5.5 0 01.5.5V12a1 1 0 001 1h12a1 1 0 001-1\
-V8.5a.5.5 0 011 0V12a2 2 0 01-2 2H2a2 2 0 01-2-2V8.5A.5.5 0 01.5 8z")) "")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M5 7.5a.5.5 0 01.707 0L8 9.793 10.293 7.5a.5.5 0 \
-11.707.707l-2.646 2.647a.5.5 0 01-.708 0L5 8.207A.5.5 0 015 7.5z")) "")
(path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M8 1a.5.5 0 01.5.5v8a.5.5 0 01-1 0v-8A.5.5 0 018 1z")) "")))
+ (d "M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 \
+2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 \
+0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 \
+2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z")))))
(define* (display-message-body bug-num message-number message #:optional plain?)
"Convenience procedure to render MESSAGE (part of bug with number
@@ -285,7 +295,9 @@ lines when PLAIN? is #T."
"")))
((string-suffix? ".scm" attachment-name)
`(div (@ (class "multipart scheme"))
- (div (@ (class "download-part"))
+ (div (@ (id "download-scheme-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download Scheme file"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(highlights->sxml (highlight lex-scheme body))))
@@ -294,7 +306,9 @@ lines when PLAIN? is #T."
(list "multipart" (or (and content-type
(content-type->css-class content-type))
"")))))
- (div (@ (class "download-part"))
+ (div (@ (id "download-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download MIME part"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(cond
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 03:26 +0100
[PATCH mumi v3 0/4] Add a button to copy a message Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
20240126022717.31305-1-maxim.cournoyer@gmail.com
This series adds a new HTML element to each message header to easily
copy the Message-ID of a message into the clipboard. It makes use of
the (already included) Pico CSS library for tooltips and some new
JavaScript event handler. The motivation was to make it easier to
retrieve the Message-ID for passing it to the 'b4 shazam' command when
applying long patches series.

Changes in v3:
- Allow using the new copy button via the keyboard
- Register event handlers on all copy message-id buttons
- Move download icon sizes to CSS to resolve warning in Firefox
- Add guard inside download button event to ensure only one event
runs at a time, avoiding tooltip getting stuck on 'Copied!'
- Use a class name instead of a unique ID for the message-id buttons
- Register handlers to every message-id buttons

Changes in v2:
- Add timestamp to CSS and JavaScript file names to force reload

Maxim Cournoyer (4):
README.org: Add new sections to help newcomers get started.
.gitignore: Register mumi.xapian and signing-key files.
Add .patman configuration file.
html: Add a button to copy a Message-ID to the clipboard.

.gitignore | 2 ++
.patman | 7 +++++
README.org | 24 +++++++++++++++++
assets/js/mumi.js | 59 ++++++++++++++++++++++++++++++++++++++++-
assets/mumi.scss | 28 ++++++++++++++++---
mumi/web/view/html.scm | 24 ++++++++++++-----
mumi/web/view/utils.scm | 40 +++++++++++++++++-----------
7 files changed, 159 insertions(+), 25 deletions(-)
create mode 100644 .patman


base-commit: 025fc600f1cb4c73042bf920aee3e07d5fb9c53a
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 03:26 +0100
[PATCH mumi v3 1/4] README.org: Add new sections to help newcomers get started.
(address . 68680@debbugs.gnu.org)
20240126022717.31305-2-maxim.cournoyer@gmail.com
* README.org (Running a local instance of mumi): New section.
(Disabling browser caching): Likewise.
---

(no changes since v1)

README.org | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

Toggle diff (34 lines)
diff --git a/README.org b/README.org
index fd1d77b..d092de7 100644
--- a/README.org
+++ b/README.org
@@ -11,3 +11,27 @@ run
#+BEGIN_SRC shell
$ guix shell -D mumi
#+END_SRC
+
+** Running a local instance of mumi
+
+First copy some test mail data to be indexed:
+
+#+begin_src shell
+ $ cp -a tests/data data
+#+end_src
+
+Then, to have these emails indexed, run:
+
+#+begin_src shell
+ $ ./pre-inst-env mumi fetch
+#+end_src
+
+You should now be able to visit http://0.0.0.0:1234 in your browser
+and see your local mumi instance running.
+
+** Disabling browser caching
+
+If you modify the CSS or JavaScript source files, you'll want to make
+sure your browser doesn't keep cached copies. This can be done by
+changing a preference in the development tools menus, which is called
+something like "Disable cache (while DevTools is active)".
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 03:26 +0100
[PATCH mumi v3 2/4] .gitignore: Register mumi.xapian and signing-key files.
(address . 68680@debbugs.gnu.org)
20240126022717.31305-3-maxim.cournoyer@gmail.com
---

(no changes since v1)

.gitignore | 2 ++
1 file changed, 2 insertions(+)

Toggle diff (17 lines)
diff --git a/.gitignore b/.gitignore
index 2604e48..7247392 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,10 @@ config.log
config.status
configure
+mumi.xapian
mumi/config.scm
scripts/mumi
+signing-key
pre-inst-env
*.log
*.trs
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 03:26 +0100
[PATCH mumi v3 3/4] Add .patman configuration file.
(address . 68680@debbugs.gnu.org)
20240126022717.31305-4-maxim.cournoyer@gmail.com
* .patman: New file.
---

(no changes since v1)

.patman | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 .patman

Toggle diff (15 lines)
diff --git a/.patman b/.patman
new file mode 100644
index 0000000..87b96e9
--- /dev/null
+++ b/.patman
@@ -0,0 +1,7 @@
+[settings]
+project: guix-patches
+patchwork_url: https://patches.guix-patches.cbaines.net
+add_signoff: False
+check_patch: False
+ignore_bad_tags: True
+keep_change_id: True
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 03:26 +0100
[PATCH mumi v3 4/4] html: Add a button to copy a Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
20240126022717.31305-5-maxim.cournoyer@gmail.com
* mumi/web/view/html.scm (issue-page)
<copy-message-id-button>: New HTML element.
(layout): Bump timestamp on .css and .js files to force reload.
* mumi/web/view/utils.scm (download-icon): Update source. Use 'rem'
as size unit.
(copy-icon): New variable.
(display-message-body) <download-part>: Add IDs to buttons. Add to
"message-button" class.
* assets/mumi.scss: Refactor spacing of message header buttons via a
flex display. Add a shrinking animation to message buttons on hover.
* assets/js/mumi.js (mumi): Register an event for it that copies the
Message-ID to the clipboard. Add js-indent-level prop line as well as
copyright notices.
* mumi/web/view/html.scm

---

Changes in v3:
- Allow using the new copy button via the keyboard
- Register event handlers on all copy message-id buttons
- Move download icon sizes to CSS to resolve warning in Firefox
- Add guard inside download button event to ensure only one event
runs at a time, avoiding tooltip getting stuck on 'Copied!'
- Use a class name instead of a unique ID for the message-id buttons
- Register handlers to every message-id buttons

Changes in v2:
- Add timestamp to CSS and JavaScript file names to force reload

assets/js/mumi.js | 59 ++++++++++++++++++++++++++++++++++++++++-
assets/mumi.scss | 28 ++++++++++++++++---
mumi/web/view/html.scm | 24 ++++++++++++-----
mumi/web/view/utils.scm | 40 +++++++++++++++++-----------
4 files changed, 126 insertions(+), 25 deletions(-)

Toggle diff (265 lines)
diff --git a/assets/js/mumi.js b/assets/js/mumi.js
index ab29f08..77b9276 100644
--- a/assets/js/mumi.js
+++ b/assets/js/mumi.js
@@ -1,4 +1,8 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later -*- js-indent-level: 2; -*-
+//
+// Copyright © 2019, 2022, 2023 Ricardo Wurmus <rekado@elephly.net>
+// Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+//
var mumi = (function () {
const possibleTokens = [
{ text: 'is:open' },
@@ -129,12 +133,65 @@ var mumi = (function () {
var init = function () {
initTokenInput ();
};
+
+ // Copy a message Message-ID to the clipboard.
+ var setupMessageIdButtonHandler = () => {
+
+ // Avoid having the async timeout code starting while a previous
+ // one is ongoing, which would corrupt the tooltip text.
+ var isMessageIdHandlerRunning = false;
+
+ let messageIdHandler = (evt) => {
+ if (isMessageIdHandlerRunning) return;
+ isMessageIdHandlerRunning = true;
+
+ // If the button was triggered by a keyup event, check if it was
+ // the Enter key.
+ if (evt.type === "keyup" && event.key !== "Enter") return;
+
+ messageIdButton = evt.currentTarget;
+ originalTooltip = messageIdButton.dataset.tooltip;
+ var messageId = messageIdButton.dataset.messageId;
+ if (!window.isSecureContext) {
+ console.log("not in a secure context -- " +
+ "cannot copy message-id to clipboard\n" +
+ "tip: for testing, open via http://localhost:1234");
+ return;
+ }
+
+ // Avoid the button being stuck in the focused state when a
+ // mouse is used, to avoid UI clutter.
+ if (evt.type === "click") {
+ messageIdButton.removeAttribute('tabindex');
+ }
+
+ // Update button's tooltip for the next 3 s.
+ messageIdButton.dataset.tooltip = "Copied!";
+ setTimeout(() => {
+ messageIdButton.dataset.tooltip = originalTooltip;
+ if (evt.type === "click") {
+ // Re-add the tabindex attribute.
+ messageIdButton.setAttribute("tabindex", "0")
+ isMessageIdHandlerRunning = false;
+ }}, 3000);
+
+ navigator.clipboard.writeText(messageId);
+ console.log("copied Message-ID " + messageId + " to clipboard");
+ };
+
+ document.querySelectorAll(".copy-message-id-button").forEach((btn) => {
+ btn.addEventListener("click", messageIdHandler);
+ btn.addEventListener("keyup", messageIdHandler)});
+ };
+
return({
'init': init,
'lines': setupLineHandler,
+ 'messageIdButtonHandler': setupMessageIdButtonHandler,
});
})();
window.addEventListener ("load", mumi.init);
window.addEventListener ("DOMContentLoaded", mumi.lines);
+window.addEventListener ("DOMContentLoaded", mumi.messageIdButtonHandler);
// @license-end
diff --git a/assets/mumi.scss b/assets/mumi.scss
index 822f110..b12a733 100644
--- a/assets/mumi.scss
+++ b/assets/mumi.scss
@@ -506,11 +506,33 @@ details {
margin-right: 0.2em;
}
-.download-message,
.download-part {
float: right;
- font-size: 0.8em;
- font-style: italic;
+}
+
+.header-buttons {
+ display: flex;
+ flex-direction: row;
+ float: right;
+ justify-content: flex-end;
+ }
+
+.header-buttons > * {
+ margin: 0 0 0 0.5rem;
+ // Custom buttons: undo the Pico CSS default style.
+ background: revert;
+ border: revert;
+ color: revert;
+ padding: revert;
+}
+
+.message-button {
+ height: 1rem;
+ width: 1rem;
+}
+
+.message-button:hover {
+ transform: scale(0.95);
}
@media (min-width: 768px) {
diff --git a/mumi/web/view/html.scm b/mumi/web/view/html.scm
index 8f06a36..8ae1a6f 100644
--- a/mumi/web/view/html.scm
+++ b/mumi/web/view/html.scm
@@ -1,6 +1,7 @@
;;; mumi -- Mediocre, uh, mail interface
;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019, 2023 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -62,11 +63,11 @@
(@ (rel "stylesheet")
(media "screen")
(type "text/css")
- (href "/css/mumi.css?20221231000000")))
+ (href "/css/mumi.css?20240125000002")))
(script
(@ (src "/js/tokeninput.js")))
(script
- (@ (src "/js/mumi.js")))
+ (@ (src "/js/mumi.js?20240125000002")))
,@head)
(body (script
(@ (src "/js/theme-switcher.js")))
@@ -612,6 +613,7 @@ currently disabled."))
(not (bug-archived bug)))
mailer-form
disabled-mailer)))
+
(define (show-message message-number message previous-subject)
`((div
(a (@ (class "message-anchor")
@@ -642,10 +644,20 @@ currently disabled."))
message-number)))
(title ,(date->string (date message))))
,(time->string (date message)))))
- (div (@ (class "download-message"))
- (a (@ (href ,(format #f "/issue/~a/raw/~a"
- id message-number)))
- ,download-icon))
+ (div (@ (class "header-buttons"))
+ (div (@ (class "copy-message-id-button message-button")
+ (tabindex "0") ;make it keyboard-usable
+ (role "button") ;specific to Pico CSS
+ (data-tooltip "Copy Message-ID")
+ (data-message-id ,(message-id message)))
+ ,copy-icon)
+ (div (@ (id "download-raw-message-button")
+ (class "message-button")
+ (role "button")
+ (data-tooltip "Download raw message"))
+ (a (@ (href ,(format #f "/issue/~a/raw/~a"
+ id message-number)))
+ ,download-icon)))
,@(if (string-suffix? previous-subject (subject message))
'()
`((div (@ (class "subject")) ,(subject message))))
diff --git a/mumi/web/view/utils.scm b/mumi/web/view/utils.scm
index 1ce7b64..712d198 100644
--- a/mumi/web/view/utils.scm
+++ b/mumi/web/view/utils.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -35,6 +36,7 @@
#:use-module (web uri)
#:export (prettify
avatar-color
+ copy-icon
download-icon
display-message-body
time->string))
@@ -215,23 +217,27 @@ numbers with the given MESSAGE-NUMBER."
;; https://icons.getbootstrap.com/icons/download/
(define download-icon
'(svg (@ (class "bi bi-download")
- (width "1em")
- (height "1em")
(viewBox "0 0 16 16")
(fill "currentColor")
(xmlns "http://www.w3.org/2000/svg"))
- (title "Download")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M.5 8a.5.5 0 01.5.5V12a1 1 0 001 1h12a1 1 0 001-1\
-V8.5a.5.5 0 011 0V12a2 2 0 01-2 2H2a2 2 0 01-2-2V8.5A.5.5 0 01.5 8z")) "")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M5 7.5a.5.5 0 01.707 0L8 9.793 10.293 7.5a.5.5 0 \
-11.707.707l-2.646 2.647a.5.5 0 01-.708 0L5 8.207A.5.5 0 015 7.5z")) "")
+ (path (@ (d "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 \
+1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 \
+1-2-2v-2.5a.5.5 0 0 1 .5-.5")))
+ (path (@ (d "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 \
+0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 \
+1 0-.708.708z")))))
+
+;; https://icons.getbootstrap.com/icons/copy/
+(define copy-icon
+ '(svg (@ (class "bi bi-copy")
+ (viewBox "0 0 16 16")
+ (fill "currentColor")
+ (xmlns "http://www.w3.org/2000/svg"))
(path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M8 1a.5.5 0 01.5.5v8a.5.5 0 01-1 0v-8A.5.5 0 018 1z")) "")))
+ (d "M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 \
+2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 \
+0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 \
+2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z")))))
(define* (display-message-body bug-num message-number message #:optional plain?)
"Convenience procedure to render MESSAGE (part of bug with number
@@ -285,7 +291,9 @@ lines when PLAIN? is #T."
"")))
((string-suffix? ".scm" attachment-name)
`(div (@ (class "multipart scheme"))
- (div (@ (class "download-part"))
+ (div (@ (id "download-scheme-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download Scheme file"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(highlights->sxml (highlight lex-scheme body))))
@@ -294,7 +302,9 @@ lines when PLAIN? is #T."
(list "multipart" (or (and content-type
(content-type->css-class content-type))
"")))))
- (div (@ (class "download-part"))
+ (div (@ (id "download-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download MIME part"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(cond
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 18:13 +0100
[PATCH mumi v4 1/4] README.org: Add new sections to help newcomers get started.
(address . 68680@debbugs.gnu.org)
20240126171358.20291-2-maxim.cournoyer@gmail.com
* README.org (Running a local instance of mumi): New section.
(Disabling browser caching): Likewise.
---

(no changes since v1)

README.org | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

Toggle diff (34 lines)
diff --git a/README.org b/README.org
index fd1d77b..d092de7 100644
--- a/README.org
+++ b/README.org
@@ -11,3 +11,27 @@ run
#+BEGIN_SRC shell
$ guix shell -D mumi
#+END_SRC
+
+** Running a local instance of mumi
+
+First copy some test mail data to be indexed:
+
+#+begin_src shell
+ $ cp -a tests/data data
+#+end_src
+
+Then, to have these emails indexed, run:
+
+#+begin_src shell
+ $ ./pre-inst-env mumi fetch
+#+end_src
+
+You should now be able to visit http://0.0.0.0:1234 in your browser
+and see your local mumi instance running.
+
+** Disabling browser caching
+
+If you modify the CSS or JavaScript source files, you'll want to make
+sure your browser doesn't keep cached copies. This can be done by
+changing a preference in the development tools menus, which is called
+something like "Disable cache (while DevTools is active)".
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 18:13 +0100
[PATCH mumi v4 0/4] Add a button to copy a message Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
20240126171358.20291-1-maxim.cournoyer@gmail.com
This series adds a new HTML element to each message header to easily
copy the Message-ID of a message into the clipboard. It makes use of
the (already included) Pico CSS library for tooltips and some new
JavaScript event handler. The motivation was to make it easier to
retrieve the Message-ID for passing it to the 'b4 shazam' command when
applying long patches series.

I've deployed it on Berlin, so anyone can try it already and provide feedback.

Changes in v4:
- Set icon sizes via CSS instead of HTML, which improves layout

Changes in v3:
- Allow using the new copy button via the keyboard
- Register event handlers on all copy message-id buttons
- Move download icon sizes to CSS to resolve warning in Firefox
- Add guard inside download button event to ensure only one event
runs at a time, avoiding tooltip getting stuck on 'Copied!'
- Use a class name instead of a unique ID for the message-id buttons
- Register handlers to every message-id buttons

Changes in v2:
- Add timestamp to CSS and JavaScript file names to force reload

Maxim Cournoyer (4):
README.org: Add new sections to help newcomers get started.
.gitignore: Register mumi.xapian and signing-key files.
Add .patman configuration file.
html: Add a button to copy a Message-ID to the clipboard.

.gitignore | 2 ++
.patman | 7 +++++
README.org | 24 +++++++++++++++++
assets/js/mumi.js | 59 ++++++++++++++++++++++++++++++++++++++++-
assets/mumi.scss | 31 +++++++++++++++++++---
mumi/web/view/html.scm | 24 ++++++++++++-----
mumi/web/view/utils.scm | 40 +++++++++++++++++-----------
7 files changed, 162 insertions(+), 25 deletions(-)
create mode 100644 .patman


base-commit: 025fc600f1cb4c73042bf920aee3e07d5fb9c53a
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 18:13 +0100
[PATCH mumi v4 2/4] .gitignore: Register mumi.xapian and signing-key files.
(address . 68680@debbugs.gnu.org)
20240126171358.20291-3-maxim.cournoyer@gmail.com
---

(no changes since v1)

.gitignore | 2 ++
1 file changed, 2 insertions(+)

Toggle diff (17 lines)
diff --git a/.gitignore b/.gitignore
index 2604e48..7247392 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,10 @@ config.log
config.status
configure
+mumi.xapian
mumi/config.scm
scripts/mumi
+signing-key
pre-inst-env
*.log
*.trs
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 18:13 +0100
[PATCH mumi v4 3/4] Add .patman configuration file.
(address . 68680@debbugs.gnu.org)
20240126171358.20291-4-maxim.cournoyer@gmail.com
* .patman: New file.
---

(no changes since v1)

.patman | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 .patman

Toggle diff (15 lines)
diff --git a/.patman b/.patman
new file mode 100644
index 0000000..87b96e9
--- /dev/null
+++ b/.patman
@@ -0,0 +1,7 @@
+[settings]
+project: guix-patches
+patchwork_url: https://patches.guix-patches.cbaines.net
+add_signoff: False
+check_patch: False
+ignore_bad_tags: True
+keep_change_id: True
--
2.41.0
M
M
Maxim Cournoyer wrote on 26 Jan 18:13 +0100
[PATCH mumi v4 4/4] html: Add a button to copy a Message-ID to the clipboard.
(address . 68680@debbugs.gnu.org)
20240126171358.20291-5-maxim.cournoyer@gmail.com
* mumi/web/view/html.scm (issue-page)
<copy-message-id-button>: New HTML element.
(layout): Bump timestamp on .css and .js files to force reload.
* mumi/web/view/utils.scm (download-icon): Update source. Use 'rem'
as size unit.
(copy-icon): New variable.
(display-message-body) <download-part>: Add IDs to buttons. Add to
"message-button" class.
* assets/mumi.scss: Refactor spacing of message header buttons via a
flex display. Add a shrinking animation to message buttons on hover.
* assets/js/mumi.js (mumi): Register an event for it that copies the
Message-ID to the clipboard. Add js-indent-level prop line as well as
copyright notices.
* mumi/web/view/html.scm

---

Changes in v4:
- Set icon sizes via CSS instead of HTML, which improves layout.

Changes in v3:
- Allow using the new copy button via the keyboard
- Register event handlers on all copy message-id buttons
- Move download icon sizes to CSS to resolve warning in Firefox
- Add guard inside download button event to ensure only one event
runs at a time, avoiding tooltip getting stuck on 'Copied!'
- Use a class name instead of a unique ID for the message-id buttons
- Register handlers to every message-id buttons

Changes in v2:
- Add timestamp to CSS and JavaScript file names to force reload

assets/js/mumi.js | 59 ++++++++++++++++++++++++++++++++++++++++-
assets/mumi.scss | 31 +++++++++++++++++++---
mumi/web/view/html.scm | 24 ++++++++++++-----
mumi/web/view/utils.scm | 40 +++++++++++++++++-----------
4 files changed, 129 insertions(+), 25 deletions(-)

Toggle diff (268 lines)
diff --git a/assets/js/mumi.js b/assets/js/mumi.js
index ab29f08..77b9276 100644
--- a/assets/js/mumi.js
+++ b/assets/js/mumi.js
@@ -1,4 +1,8 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later -*- js-indent-level: 2; -*-
+//
+// Copyright © 2019, 2022, 2023 Ricardo Wurmus <rekado@elephly.net>
+// Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+//
var mumi = (function () {
const possibleTokens = [
{ text: 'is:open' },
@@ -129,12 +133,65 @@ var mumi = (function () {
var init = function () {
initTokenInput ();
};
+
+ // Copy a message Message-ID to the clipboard.
+ var setupMessageIdButtonHandler = () => {
+
+ // Avoid having the async timeout code starting while a previous
+ // one is ongoing, which would corrupt the tooltip text.
+ var isMessageIdHandlerRunning = false;
+
+ let messageIdHandler = (evt) => {
+ if (isMessageIdHandlerRunning) return;
+ isMessageIdHandlerRunning = true;
+
+ // If the button was triggered by a keyup event, check if it was
+ // the Enter key.
+ if (evt.type === "keyup" && event.key !== "Enter") return;
+
+ messageIdButton = evt.currentTarget;
+ originalTooltip = messageIdButton.dataset.tooltip;
+ var messageId = messageIdButton.dataset.messageId;
+ if (!window.isSecureContext) {
+ console.log("not in a secure context -- " +
+ "cannot copy message-id to clipboard\n" +
+ "tip: for testing, open via http://localhost:1234");
+ return;
+ }
+
+ // Avoid the button being stuck in the focused state when a
+ // mouse is used, to avoid UI clutter.
+ if (evt.type === "click") {
+ messageIdButton.removeAttribute('tabindex');
+ }
+
+ // Update button's tooltip for the next 3 s.
+ messageIdButton.dataset.tooltip = "Copied!";
+ setTimeout(() => {
+ messageIdButton.dataset.tooltip = originalTooltip;
+ if (evt.type === "click") {
+ // Re-add the tabindex attribute.
+ messageIdButton.setAttribute("tabindex", "0")
+ isMessageIdHandlerRunning = false;
+ }}, 3000);
+
+ navigator.clipboard.writeText(messageId);
+ console.log("copied Message-ID " + messageId + " to clipboard");
+ };
+
+ document.querySelectorAll(".copy-message-id-button").forEach((btn) => {
+ btn.addEventListener("click", messageIdHandler);
+ btn.addEventListener("keyup", messageIdHandler)});
+ };
+
return({
'init': init,
'lines': setupLineHandler,
+ 'messageIdButtonHandler': setupMessageIdButtonHandler,
});
})();
window.addEventListener ("load", mumi.init);
window.addEventListener ("DOMContentLoaded", mumi.lines);
+window.addEventListener ("DOMContentLoaded", mumi.messageIdButtonHandler);
// @license-end
diff --git a/assets/mumi.scss b/assets/mumi.scss
index 822f110..e605630 100644
--- a/assets/mumi.scss
+++ b/assets/mumi.scss
@@ -506,11 +506,36 @@ details {
margin-right: 0.2em;
}
-.download-message,
.download-part {
float: right;
- font-size: 0.8em;
- font-style: italic;
+}
+
+.header-buttons {
+ display: flex;
+ flex-direction: row;
+ float: right;
+ justify-content: flex-end;
+ }
+
+.header-buttons > * {
+ margin: 0 0 0 0.5rem;
+ // Custom buttons: undo the Pico CSS default style. We use
+ // buttons for inheriting their CSS style when focused via the
+ // keyboard.
+ background: revert;
+ border: revert;
+ color: revert;
+ padding: revert;
+}
+
+.bi-copy,
+.bi-download{
+ height: 1rem;
+ width: 1rem;
+}
+
+.message-button:hover {
+ transform: scale(0.95);
}
@media (min-width: 768px) {
diff --git a/mumi/web/view/html.scm b/mumi/web/view/html.scm
index 8f06a36..104162d 100644
--- a/mumi/web/view/html.scm
+++ b/mumi/web/view/html.scm
@@ -1,6 +1,7 @@
;;; mumi -- Mediocre, uh, mail interface
;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019, 2023 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -62,11 +63,11 @@
(@ (rel "stylesheet")
(media "screen")
(type "text/css")
- (href "/css/mumi.css?20221231000000")))
+ (href "/css/mumi.css?20240126000000")))
(script
(@ (src "/js/tokeninput.js")))
(script
- (@ (src "/js/mumi.js")))
+ (@ (src "/js/mumi.js?20240126000000")))
,@head)
(body (script
(@ (src "/js/theme-switcher.js")))
@@ -612,6 +613,7 @@ currently disabled."))
(not (bug-archived bug)))
mailer-form
disabled-mailer)))
+
(define (show-message message-number message previous-subject)
`((div
(a (@ (class "message-anchor")
@@ -642,10 +644,20 @@ currently disabled."))
message-number)))
(title ,(date->string (date message))))
,(time->string (date message)))))
- (div (@ (class "download-message"))
- (a (@ (href ,(format #f "/issue/~a/raw/~a"
- id message-number)))
- ,download-icon))
+ (div (@ (class "header-buttons"))
+ (div (@ (class "copy-message-id-button message-button")
+ (tabindex "0") ;make it keyboard-usable
+ (role "button") ;specific to Pico CSS
+ (data-tooltip "Copy Message-ID")
+ (data-message-id ,(message-id message)))
+ ,copy-icon)
+ (div (@ (id "download-raw-message-button")
+ (class "message-button")
+ (role "button")
+ (data-tooltip "Download raw message"))
+ (a (@ (href ,(format #f "/issue/~a/raw/~a"
+ id message-number)))
+ ,download-icon)))
,@(if (string-suffix? previous-subject (subject message))
'()
`((div (@ (class "subject")) ,(subject message))))
diff --git a/mumi/web/view/utils.scm b/mumi/web/view/utils.scm
index 1ce7b64..712d198 100644
--- a/mumi/web/view/utils.scm
+++ b/mumi/web/view/utils.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -35,6 +36,7 @@
#:use-module (web uri)
#:export (prettify
avatar-color
+ copy-icon
download-icon
display-message-body
time->string))
@@ -215,23 +217,27 @@ numbers with the given MESSAGE-NUMBER."
;; https://icons.getbootstrap.com/icons/download/
(define download-icon
'(svg (@ (class "bi bi-download")
- (width "1em")
- (height "1em")
(viewBox "0 0 16 16")
(fill "currentColor")
(xmlns "http://www.w3.org/2000/svg"))
- (title "Download")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M.5 8a.5.5 0 01.5.5V12a1 1 0 001 1h12a1 1 0 001-1\
-V8.5a.5.5 0 011 0V12a2 2 0 01-2 2H2a2 2 0 01-2-2V8.5A.5.5 0 01.5 8z")) "")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M5 7.5a.5.5 0 01.707 0L8 9.793 10.293 7.5a.5.5 0 \
-11.707.707l-2.646 2.647a.5.5 0 01-.708 0L5 8.207A.5.5 0 015 7.5z")) "")
+ (path (@ (d "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 \
+1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 \
+1-2-2v-2.5a.5.5 0 0 1 .5-.5")))
+ (path (@ (d "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 \
+0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 \
+1 0-.708.708z")))))
+
+;; https://icons.getbootstrap.com/icons/copy/
+(define copy-icon
+ '(svg (@ (class "bi bi-copy")
+ (viewBox "0 0 16 16")
+ (fill "currentColor")
+ (xmlns "http://www.w3.org/2000/svg"))
(path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M8 1a.5.5 0 01.5.5v8a.5.5 0 01-1 0v-8A.5.5 0 018 1z")) "")))
+ (d "M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 \
+2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 \
+0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 \
+2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z")))))
(define* (display-message-body bug-num message-number message #:optional plain?)
"Convenience procedure to render MESSAGE (part of bug with number
@@ -285,7 +291,9 @@ lines when PLAIN? is #T."
"")))
((string-suffix? ".scm" attachment-name)
`(div (@ (class "multipart scheme"))
- (div (@ (class "download-part"))
+ (div (@ (id "download-scheme-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download Scheme file"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(highlights->sxml (highlight lex-scheme body))))
@@ -294,7 +302,9 @@ lines when PLAIN? is #T."
(list "multipart" (or (and content-type
(content-type->css-class content-type))
"")))))
- (div (@ (class "download-part"))
+ (div (@ (id "download-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download MIME part"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(cond
--
2.41.0
A
A
Arun Isaac wrote on 26 Jan 22:18 +0100
Re: [PATCH mumi v2 1/3] README.org: Add new sections to help newcomers get started.
(address . rekado@elephly.net)
87mssrokts.fsf@systemreboot.net
Toggle quote (3 lines)
> +You should now be able to visit http://0.0.0.0:1234in your browser
> +and see your local mumi instance running.

Could you also mention just before this paragraph, the `mumi web'
command that starts the web server?
A
A
Arun Isaac wrote on 26 Jan 22:21 +0100
Re: [PATCH mumi v2 0/3] Add a button to copy a message Message-ID to the clipboard.
(address . rekado@elephly.net)
87jznvoknu.fsf@systemreboot.net
Toggle quote (3 lines)
> Changes in v2:
> - Add timestamp to CSS and JavaScript file names to force reload

Do we need to have timestamps on the CSS and JS filenames? If we
configured nginx to serve these static files, wouldn't caching and
reloading be handled automatically via the ETag or Last-Modified
headers?
A
A
Arun Isaac wrote on 26 Jan 22:24 +0100
(address . rekado@elephly.net)
87fryjokjz.fsf@systemreboot.net
Looks good to me otherwise. The patch running on berlin actually
works. So, all is well, I guess!
M
M
Maxim Cournoyer wrote on 27 Jan 04:04 +0100
(name . Arun Isaac)(address . arunisaac@systemreboot.net)
875xzf1np3.fsf@gmail.com
Hi,

Arun Isaac <arunisaac@systemreboot.net> writes:

Toggle quote (8 lines)
>> Changes in v2:
>> - Add timestamp to CSS and JavaScript file names to force reload
>
> Do we need to have timestamps on the CSS and JS filenames? If we
> configured nginx to serve these static files, wouldn't caching and
> reloading be handled automatically via the ETag or Last-Modified
> headers?

I haven't looked at our nginx configuration, but currently the js and
css files were not reloaded without this hack, no.

--
Thanks,
Maxim
M
M
Maxim Cournoyer wrote on 27 Jan 04:55 +0100
Re: [PATCH mumi v2 1/3] README.org: Add new sections to help newcomers get started.
(name . Arun Isaac)(address . arunisaac@systemreboot.net)
87o7d7zaye.fsf@gmail.com
Hi,

Arun Isaac <arunisaac@systemreboot.net> writes:

Toggle quote (6 lines)
>> +You should now be able to visit http://0.0.0.0:1234in your browser
>> +and see your local mumi instance running.
>
> Could you also mention just before this paragraph, the `mumi web'
> command that starts the web server?

Done.

--
Thanks,
Maxim
M
M
Maxim Cournoyer wrote on 27 Jan 04:57 +0100
Re: [PATCH mumi v2 0/3] Add a button to copy a message Message-ID to the clipboard.
(name . Arun Isaac)(address . arunisaac@systemreboot.net)
87jznvzaw1.fsf@gmail.com
Hi Arun,

Arun Isaac <arunisaac@systemreboot.net> writes:

Toggle quote (3 lines)
> Looks good to me otherwise. The patch running on berlin actually
> works. So, all is well, I guess!

Great! I'll bump mumi's version to 0.0.6 and update the package in
Guix.

--
Thanks,
Maxim
Closed
A
A
Arun Isaac wrote on 27 Jan 11:06 +0100
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
8734ujnl91.fsf@systemreboot.net
Toggle quote (3 lines)
> I haven't looked at our nginx configuration, but currently the js and
> css files were not reloaded without this hack, no.

Ok, maybe for another time, then. But, we should handle this kind of
thing in the nginx configuration of the mumi service.

Thank you for the patchset. Much appreciated! :-)
R
R
Ricardo Wurmus wrote on 27 Jan 13:20 +0100
(name . Arun Isaac)(address . arunisaac@systemreboot.net)
878r4bezlw.fsf@elephly.net
Arun Isaac <arunisaac@systemreboot.net> writes:

Toggle quote (6 lines)
>> I haven't looked at our nginx configuration, but currently the js and
>> css files were not reloaded without this hack, no.
>
> Ok, maybe for another time, then. But, we should handle this kind of
> thing in the nginx configuration of the mumi service.

I think we used to have (and maybe still have) a problem with caching
files that are served from the store with a zero timestamp.

--
Ricardo
A
A
Arun Isaac wrote on 30 Jan 00:41 +0100
(name . Ricardo Wurmus)(address . rekado@elephly.net)
87mssnlnc4.fsf@systemreboot.net
Toggle quote (3 lines)
> I think we used to have (and maybe still have) a problem with caching
> files that are served from the store with a zero timestamp.

Oh my, I forgot about the store. That's a bummer. We should workaround
this[1] with some other non-timestamp based caching strategy. Perhaps we
can set a max-age using the Cache-Control

[1]: later, and not part of this issue
F
F
Felix Lechner wrote on 23 Feb 14:23 +0100
(no subject)
(address . control@debbugs.gnu.org)
875xyf1fhb.fsf@lease-up.com
unarchive 68680
reassign 68680 mumi
archive 68680

unarchive 63802
reassign 63802 mumi
archive 63802

unarchive 63215
reassign 63215 mumi
archive 63215

unarchive 61645
reassign 61645 mumi
archive 61645

unarchive 60410
reassign 60410 mumi
archive 60410

unarchive 60292
reassign 60292 mumi
archive 60292

unarchive 60292
reassign 60292 mumi
archive 60292

unarchive 58573
reassign 58573 mumi
archive 58573

unarchive 54024
reassign 54024 mumi
archive 54024

unarchive 49115
reassign 49115 mumi
archive 49115

unarchive 48160
reassign 48160 mumi
archive 48160

unarchive 47739
reassign 47739 mumi
archive 47739

unarchive 47520
reassign 47520 mumi
archive 47520

unarchive 47121
reassign 47121 mumi
archive 47121

unarchive 45015
reassign 45015 mumi
archive 45015

unarchive 43661
reassign 43661 mumi
archive 43661

unarchiv 43166
reassign 43166 mumi
archive 43166

unarchive 41906
reassign 41906 mumi
archive 41906

unarchive 41098
reassign 41098 mumi
archive 41098

unarchive 39924
reassign 39924 mumi
archive 39924

unarchive 39924
reassign 39924 mumi
archive 39924

unarchive 39924
reassign 39924 mumi
archive 39924

thanks
?