thunderbird-patch-review
Easy-to-use patch review interface for Thunderbird
Contribute: ~marcc/thunderbird-review-plugin@lists.sr.ht
git clone git://mccd.space/thunderbird-patch-review
| Log | Files | Refs | README | LICENSE |
commit 0280f8ffaa21e93d514b04a3cb29bade12bb28a3 parent 96828e747f84883fa26d6320ace855eb047be15d Author: Pi Agent <agent@pi.local> Date: Sat, 18 Jul 2026 13:46:03 +0200 review: confirm before Send review; fold sourcehut status into the confirm dialog Send review and its drop-down options (Send now / Preview in compose) now\nopen a confirmation modal summarizing how many patches have a draft\ncomment and what will happen on confirm. The sourcehut set-status\ncheckbox and dropdown move out of the top bar into that dialog, so the\nreviewer picks the patchset status only when actually committing to send. Diffstat:
| M | extension/review/review.css | | | 70 | +++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
| M | extension/review/review.html | | | 23 | +++++++++++++++++------ |
| M | extension/review/review.js | | | 42 | ++++++++++++++++++++++++++++++++++++++++-- |
3 files changed, 110 insertions(+), 25 deletions(-)
diff --git a/extension/review/review.css b/extension/review/review.css
@@ -82,23 +82,6 @@ body {
font-family: ui-monospace, monospace;
}
-#srht-status {
- display: flex;
- align-items: center;
- gap: 0.3rem;
- color: var(--muted);
- white-space: nowrap;
-}
-
-#srht-status select {
- padding: 0.2rem 0.3rem;
- border: 1px solid var(--border);
- border-radius: 6px;
- background: var(--bg);
- color: var(--fg);
- font: inherit;
-}
-
button {
padding: 0.3rem 0.8rem;
border: 1px solid var(--border);
@@ -361,6 +344,59 @@ tr.comment-row td { padding: 0; }
border-radius: 0 0 5px 5px;
}
+#send-confirm {
+ position: fixed;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0, 0, 0, 0.4);
+ z-index: 5;
+}
+
+#send-confirm .modal-card {
+ width: min(32rem, 90vw);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ background: var(--bg);
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
+ padding: 1.2rem 1.4rem;
+}
+
+#send-confirm h2 {
+ margin: 0 0 0.4rem;
+ font-size: 15px;
+}
+
+#send-confirm-summary {
+ margin: 0 0 0.8rem;
+ color: var(--muted);
+ font-size: 12px;
+}
+
+#send-confirm #srht-status {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ margin: 0 0 0.8rem;
+ color: var(--muted);
+}
+
+#send-confirm #srht-status select {
+ padding: 0.2rem 0.3rem;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ background: var(--bg);
+ color: var(--fg);
+ font: inherit;
+}
+
+#send-confirm .modal-actions {
+ display: flex;
+ gap: 0.5rem;
+ justify-content: flex-end;
+}
+
#status {
position: fixed;
inset: auto 1rem 1rem auto;
diff --git a/extension/review/review.html b/extension/review/review.html
@@ -20,12 +20,6 @@
<button data-mode="download">Download patchset…</button>
</div>
</div>
- <label id="srht-status" hidden
- title="Sourcehut list detected: add an X-Sourcehut-Patchset-Update header to the review">
- <input id="srht-enable" type="checkbox">
- set status
- <select id="srht-select"></select>
- </label>
<div class="split" id="send-split">
<button id="btn-send" class="primary" title="Send one reply per commented patch">Send review</button>
<button class="menu-toggle primary" title="Send options">â–¾</button>
@@ -40,6 +34,23 @@
<main id="content"></main>
+ <div id="send-confirm" hidden>
+ <div class="modal-card">
+ <h2 id="send-confirm-title">Send review</h2>
+ <p id="send-confirm-summary"></p>
+ <label id="srht-status" hidden
+ title="Sourcehut list detected: add an X-Sourcehut-Patchset-Update header to the review">
+ <input id="srht-enable" type="checkbox">
+ set status
+ <select id="srht-select"></select>
+ </label>
+ <div class="modal-actions">
+ <button id="btn-send-cancel">Cancel</button>
+ <button id="btn-send-confirm" class="primary">Send review</button>
+ </div>
+ </div>
+ </div>
+
<div id="status" hidden>
<pre id="status-text"></pre>
<div id="status-buttons">
diff --git a/extension/review/review.js b/extension/review/review.js
@@ -537,9 +537,47 @@ function setupSplit(splitId, onPick) {
});
}
-setupSplit("send-split", sendReview);
+setupSplit("send-split", (mode) => openSendConfirm(mode));
setupSplit("apply-split", applySeries);
-$("#btn-send").addEventListener("click", () => sendReview("send"));
+$("#btn-send").addEventListener("click", () => openSendConfirm("send"));
+
+$("#btn-send-cancel").addEventListener("click", closeSendConfirm);
+$("#btn-send-confirm").addEventListener("click", async () => {
+ const mode = state.pendingSendMode;
+ closeSendConfirm();
+ await sendReview(mode);
+});
+
+function openSendConfirm(mode) {
+ closeMenus();
+ state.pendingSendMode = mode;
+ $("#send-confirm").addEventListener("click", onSendConfirmBackdrop);
+ const n = state.series.length;
+ const commented = state.series.filter((_, i) =>
+ Object.keys(state.comments[i]).length
+ ).length;
+ const verb = mode === "preview" ? "open in compose" : "send immediately";
+ $("#send-confirm-title").textContent = mode === "preview" ? "Preview review" : "Send review";
+ $("#btn-send-confirm").textContent = mode === "preview" ? "Open in compose" : "Send review";
+ $("#send-confirm-summary").textContent =
+ `${commented} of ${n} patch${n === 1 ? "" : "es"} has a draft comment; ` +
+ `clicking confirm will ${verb}.`;
+ $("#send-confirm").hidden = false;
+}
+
+function closeSendConfirm() {
+ $("#send-confirm").hidden = true;
+ state.pendingSendMode = null;
+ $("#send-confirm").removeEventListener("click", onSendConfirmBackdrop);
+}
+
+function onSendConfirmBackdrop(e) {
+ if (e.target === $("#send-confirm")) closeSendConfirm();
+}
+
+document.addEventListener("keydown", (e) => {
+ if (e.key === "Escape" && !$("#send-confirm").hidden) closeSendConfirm();
+});
$("#btn-apply").addEventListener("click", () => applySeries("apply"));
document.addEventListener("click", (e) => {