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.
Load only live status data for the change poll
1b1fa7a5bd224cb5af7ce1a7347100f76c2edc36 · Keenan Nemetz · 10d ago · parent 707dfd10
Load only live status data for the change poll The live endpoint still built the full sidebar view, so every poll loaded linked-issue rows, the entity-number map, and branch-picker options that only the stateful regions render. requestStatus now computes the live regions and page actions; requestSidebar adds the stateful pieces for a full page or a write that owns them.
server/web/request_view.go +33−26
| @@ -186,19 +186,12 @@ func (v requestSidebarView) withLanding(l requestLandingView) requestSidebarView | |||
| 186 | 186 | return v | |
| 187 | 187 | } | |
| 188 | 188 | ||
| 189 | // requestSidebarWithLanding is requestSidebar plus the diff and merge facts the | ||
| 190 | // Review and Changes sections show. Writes use it so an HTMX replacement is the | ||
| 191 | // same complete sidebar a page render gives. | ||
| 192 | func (w *Web) requestSidebarWithLanding(r *http.Request, m *repo.Meta, req *metadata.Request, title, errMsg string) requestSidebarView { | ||
| 193 | return w.requestSidebar(r, m, req, title, errMsg).withLanding(w.requestLanding(m, req)) | ||
| 194 | } | ||
| 195 | |||
| 196 | // requestLiveWrite is the same data as a full sidebar render, marked so every | ||
| 197 | // region that belongs to the live group carries hx-swap-oob. The response is a | ||
| 198 | // set of targeted updates, not a replacement for the sidebar: a write can update | ||
| 199 | // the status regions without throwing away an issue search or a target picker. | ||
| 189 | // requestLiveWrite is the status data marked so every region that belongs to the | ||
| 190 | // live group carries hx-swap-oob. The response is a set of targeted updates, not a | ||
| 191 | // replacement for the sidebar: a write can update the status regions without | ||
| 192 | // loading or throwing away an issue search or a target picker. | ||
| 200 | 193 | func (w *Web) requestLiveWrite(r *http.Request, m *repo.Meta, req *metadata.Request, errMsg string) requestSidebarView { | |
| 201 | v := w.requestSidebarWithLanding(r, m, req, "", errMsg) | ||
| 194 | v := w.requestStatus(r, m, req, "", errMsg).withLanding(w.requestLanding(m, req)) | ||
| 202 | 195 | v.Live = true | |
| 203 | 196 | return v | |
| 204 | 197 | } | |
| @@ -213,7 +206,12 @@ type requestPageView struct { | |||
| 213 | 206 | Thread threadView | |
| 214 | 207 | } | |
| 215 | 208 | ||
| 216 | func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Request, title, errMsg string) requestSidebarView { | ||
| 209 | // requestStatus computes the data the live regions and the page actions use: | ||
| 210 | // approvals, checks, landing facts, merge state, and the capabilities that decide | ||
| 211 | // which controls exist. It deliberately leaves out the stateful regions — the | ||
| 212 | // branch picker, the linked-issue list, and the issue numbering — so a poll does | ||
| 213 | // not load the data only an editor needs. | ||
| 214 | func (w *Web) requestStatus(r *http.Request, m *repo.Meta, req *metadata.Request, title, errMsg string) requestSidebarView { | ||
| 217 | 215 | acl, _ := m.ACL() | |
| 218 | 216 | approvals := make([]requestApproval, 0, len(req.Approvals)) | |
| 219 | 217 | current := 0 | |
| @@ -261,12 +259,6 @@ func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Reques | |||
| 261 | 259 | // an older tip than the branch, and the head control is the way to catch up. | |
| 262 | 260 | approvable := req.Open() && canApproveRequest(acl, who, req.Author) && headRefNote != "branch moved" | |
| 263 | 261 | canRetarget := req.Open() && canTriage(acl, who, req.Author) | |
| 264 | var baseOptions, headOptions []branchOption | ||
| 265 | if canRetarget { | ||
| 266 | branches := branchNames(m) | ||
| 267 | baseOptions = branchOptions(branches, req.Base) | ||
| 268 | headOptions = branchOptions(headBranches(branches, acl, who), req.HeadRef) | ||
| 269 | } | ||
| 270 | 262 | // Preflight the landing rather than guessing from the approval count: the same | |
| 271 | 263 | // gate the handler calls is asked here, so the button and the write agree about | |
| 272 | 264 | // approvals, checks and conflicts. | |
| @@ -361,16 +353,13 @@ func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Reques | |||
| 361 | 353 | } | |
| 362 | 354 | } | |
| 363 | 355 | } | |
| 364 | nums := w.entityNumbers(m) | ||
| 365 | 356 | return requestSidebarView{ | |
| 366 | 357 | Page: w.page(r, title), Name: m.Name, Request: req, | |
| 367 | Number: nums[req.ID], | ||
| 368 | LinkedIssues: w.requestLinkedIssues(m, req, nums), | ||
| 369 | Approvals: approvals, Checks: checks, Required: required, Current: current, | ||
| 358 | Approvals: approvals, Checks: checks, Required: required, Current: current, | ||
| 370 | 359 | CanApprove: approvable, CanClose: canClose, HeadRefNote: headRefNote, | |
| 371 | 360 | CanEditIssues: req.Open() && canClose, | |
| 372 | CanRetarget: canRetarget, BaseOptions: baseOptions, HeadOptions: headOptions, | ||
| 373 | CanMerge: mergeable, MergePending: mergePending, MergeArmed: mergeArmed, | ||
| 361 | CanRetarget: canRetarget, | ||
| 362 | CanMerge: mergeable, MergePending: mergePending, MergeArmed: mergeArmed, | ||
| 374 | 363 | MergeBlocked: mergeBlocked, | |
| 375 | 364 | CombinedNeeded: combinedNeeded, CombinedSHA: combinedSHA, | |
| 376 | 365 | CombinedRuns: combinedRuns, CombinedState: combinedState, | |
| @@ -380,6 +369,24 @@ func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Reques | |||
| 380 | 369 | } | |
| 381 | 370 | } | |
| 382 | 371 | ||
| 372 | // requestSidebar adds the stateful regions to requestStatus: the branch picker's | ||
| 373 | // options, the change number, and the linked-issue rows. Only a full page or a | ||
| 374 | // write that belongs to one of those regions needs them. | ||
| 375 | func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Request, title, errMsg string) requestSidebarView { | ||
| 376 | v := w.requestStatus(r, m, req, title, errMsg) | ||
| 377 | if v.CanRetarget { | ||
| 378 | acl, _ := m.ACL() | ||
| 379 | who := w.accountName(r) | ||
| 380 | branches := branchNames(m) | ||
| 381 | v.BaseOptions = branchOptions(branches, req.Base) | ||
| 382 | v.HeadOptions = branchOptions(headBranches(branches, acl, who), req.HeadRef) | ||
| 383 | } | ||
| 384 | nums := w.entityNumbers(m) | ||
| 385 | v.Number = nums[req.ID] | ||
| 386 | v.LinkedIssues = w.requestLinkedIssues(m, req, nums) | ||
| 387 | return v | ||
| 388 | } | ||
| 389 | |||
| 383 | 390 | // requestLinkedIssues reads the issues a request promises to close. The index | |
| 384 | 391 | // supplies the rows the overview uses, and a row the index cannot name is read | |
| 385 | 392 | // from the issue itself rather than dropped: the request still holds the link. | |
| @@ -581,7 +588,7 @@ func (w *Web) RequestLive(rw http.ResponseWriter, r *http.Request) { | |||
| 581 | 588 | w.notFound(rw, r) | |
| 582 | 589 | return | |
| 583 | 590 | } | |
| 584 | view := w.requestSidebar(r, m, req, "", "").withLanding(w.requestLanding(m, req)) | ||
| 591 | view := w.requestStatus(r, m, req, "", "").withLanding(w.requestLanding(m, req)) | ||
| 585 | 592 | view.Live = true | |
| 586 | 593 | w.render(rw, "request_live", view, 0) | |
| 587 | 594 | } | |