Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Update the change page as live regions, not one sidebar swap

707dfd10f309461a77a4a8f73dcce74b07c91fd6 · Keenan Nemetz · 10d ago · parent 9f5efa3c

Update the change page as live regions, not one sidebar swap

The 20-second poll replaced the entire sidebar, so every new widget needed its own reason to opt out and live updates stopped while it was in use. The sidebar is now a set of regions: review status, changes, approvals, checks, and the combined result are data-only live regions returned with hx-swap-oob; the target picker, issue search, and composers are outside every polled swap. Approval and the other multi-region writes use the same out-of-band group, and the page action group refreshes from the write without replacing unrelated state.

server/web/writes.go +6−6

@@ -187,7 +187,7 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
187 187 return
188 188 }
189 189 sidebar := func(msg string) (string, any) {
190 return "request_sidebar", w.requestSidebarWithLanding(r, m, req, "", msg)
190 return "request_live_write", w.requestLiveWrite(r, m, req, msg)
191 191 }
192 192 // The form carries the base and head the page displayed. If a push moved the
193 193 // followed branch, or the request was retargeted, the writer refuses rather than
@@ -210,10 +210,10 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
210 210 if htmxRequest(r) {
211 211 updated, err := metadata.GetRequest(m.Git(), id)
212 212 if err != nil {
213 w.render(rw, "request_sidebar", w.requestSidebarWithLanding(r, m, req, "", err.Error()), 0)
213 w.render(rw, "request_live_write", w.requestLiveWrite(r, m, req, err.Error()), 0)
214 214 return
215 215 }
216 w.render(rw, "request_sidebar", w.requestSidebarWithLanding(r, m, updated, "", ""), 0)
216 w.render(rw, "request_live_write", w.requestLiveWrite(r, m, updated, ""), 0)
217 217 return
218 218 }
219 219 http.Redirect(rw, r, "/r/"+m.Name+"/requests/"+id, http.StatusSeeOther)
@@ -650,9 +650,9 @@ func (w *Web) armMerge(rw http.ResponseWriter, r *http.Request, m *repo.Meta, re
650 650 }
651 651 w.audit("web.request.merge_when_ready", actor, m.Name, req.ID)
652 652 if htmxRequest(r) {
653 view := w.requestSidebarWithLanding(r, m, req, "", "")
653 view := w.requestLiveWrite(r, m, req, "")
654 654 view.Notice = notice
655 w.render(rw, "request_sidebar", view, 0)
655 w.render(rw, "request_live_write", view, 0)
656 656 return
657 657 }
658 658 http.Redirect(rw, r, "/r/"+m.Name+"/requests/"+req.ID+"?merging=1", http.StatusSeeOther)
@@ -687,7 +687,7 @@ func (w *Web) CancelMerge(rw http.ResponseWriter, r *http.Request) {
687 687 // block and the controls that explain it.
688 688 func (w *Web) mergeRefused(rw http.ResponseWriter, r *http.Request, m *repo.Meta, req *metadata.Request, msg string) {
689 689 if htmxRequest(r) {
690 w.render(rw, "request_sidebar", w.requestSidebarWithLanding(r, m, req, "", msg), 0)
690 w.render(rw, "request_live_write", w.requestLiveWrite(r, m, req, msg), 0)
691 691 return
692 692 }
693 693 w.renderRequestPage(rw, r, msg, http.StatusConflict)