From: Willy Tarreau Date: Mon, 6 Jul 2026 14:29:32 +0000 (+0200) Subject: DEV: patchbot: let the page save the review edits to the server X-Git-Url: http://git.kaiwu.me/stylesheets/%22data:,/static/gitweb.js?a=commitdiff_plain;h=0ed6d1f840cf74da5ad9e7650a395a7256c7f23a;p=haproxy.git DEV: patchbot: let the page save the review edits to the server This is the write side of the review syncing: a "Save changes" button next to "Get updates" collects the local edits and pushes them to update.cgi. An edit is a radio button change differing from the reference state (so clicking around and coming back to the reference sends nothing), or a note typed in the per-line input revealed by the new "[add note]" link under the AI explanation (500 chars max, matching the server-side cap). No directive carries a base value: states are last-write-wins and notes are append-only server-side, so two reviewers saving concurrently cannot conflict. On success the reference advances to the pushed values and the note inputs are cleared, so the page is clean without needing a refetch; on error (server busy or unreachable) everything stays local and a later click simply retries. --- diff --git a/dev/patchbot/scripts/post-ai.sh b/dev/patchbot/scripts/post-ai.sh index 0a7427cde..a80f7906f 100755 --- a/dev/patchbot/scripts/post-ai.sh +++ b/dev/patchbot/scripts/post-ai.sh @@ -210,13 +210,20 @@ function gen_state(i) { // browser restores them: this is desired, such differences are unsaved // local edits and must remain detected as such. function init_ref() { - var i; + var i, el; for (i = 1; i < nb_patches; i++) { orig[i] = gen_state(i); ref_state[i] = orig[i]; ref_notes[i] = ""; cidmap[cid[i]] = i; + + // the browser may also have restored an unsaved note into the hidden + // input: reveal it so that it remains visible and editable instead of + // being invisible yet silently pushed on the next save + el = document.getElementById("in_" + i); + if (el && el.value) + el.style.display = ""; } } @@ -298,6 +305,73 @@ function fetch_ref() { .catch(function() { sync_msg("fetch failed (server unreachable?)"); }); } +// "[add note]" link: reveals the extra-notes input of line , which holds +// the user's local note until it is pushed by "Save changes" +function add_note(i) { + var el = document.getElementById("in_" + i); + + if (el) { + el.style.display = ""; + el.focus(); + } +} + +// "Save changes" button: pushes the local edits, i.e. the states differing +// from the reference plus the non-empty extra notes, and advances the +// reference on success (failed saves keep everything local for a retry). +// No directive carries a base value: states are last-write-wins and notes +// are append-only server-side, so concurrent reviewers cannot conflict. +// Note that a state moved back to the reference by hand is simply not sent. +function save_ref() { + var st = [], nt = []; + var body = "", i, s, el, txt; + + if (!branch) + return; + + for (i = 1; i < nb_patches; i++) { + s = cur_state(i); + if (s && s != ref_state[i]) { + st[i] = s; + body += cid[i] + " state " + s + "\n"; + } + el = document.getElementById("in_" + i); + txt = el ? el.value.replace(/[\r\n]+/g, " ").trim() : ""; + if (txt) { + nt[i] = txt; + body += cid[i] + " notes " + txt + "\n"; + } + } + + if (!body) { + sync_msg("nothing to save"); + return; + } + + sync_msg("saving..."); + fetch(cgi_url + "?branch=" + branch, { method: "POST", body: body }) + .then(function(r) { if (!r.ok) throw 0; return r.text(); }) + .then(function() { + var i, el; + + for (i = 1; i < nb_patches; i++) { + if (st[i]) + ref_state[i] = st[i]; + if (nt[i]) { + // mirror the server-side coalescing so the display is right + // without refetching; the next fetch trues it up anyway + ref_notes[i] = ref_notes[i] ? ref_notes[i] + "; " + nt[i] : nt[i]; + show_notes(i); + el = document.getElementById("in_" + i); + el.value = ""; + el.style.display = "none"; + } + } + sync_msg("saved"); + }) + .catch(function() { sync_msg("save failed (busy?), edits kept"); }); +} + // first line to review var review = 0; @@ -457,7 +531,8 @@ echo "" # update.cgi with a bare relative URL so it must sit in the same directory. if [ -n "$VERSION" ]; then echo -n "
" - echo -n "" + echo -n " " + echo -n "" echo "
" fi @@ -585,8 +660,14 @@ for patch in "${PATCHES[@]}"; do echo -n "" # the div is the dedicated container for the shared reviewers' notes, - # filled by full replacement (never appended to) by the JS - echo -n "$resp
" + # filled by full replacement (never appended to) by the JS; the + # hidden input receives the user's own note to be pushed on save + echo -n "$resp
" + if [ -n "$VERSION" ]; then + echo -n "[add note]" + echo -n " " + fi + echo -n "" echo "" echo ((seq_num++))