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/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

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

Refresh the repository tab counts while the page is open

a2ec95616f4216c743cb1ae358ef8e9449ad8d1f · Keenan Nemetz · 9d ago · parent 0789f22e

Refresh the repository tab counts while the page is open

The header's open counts were only as fresh as the page load, so a reader
watching a repository had to reload to find out that an issue or a change had
been opened.

The tabs now poll /r/{name}/counts every 30s while the page is visible. The
response is the two badges as out-of-band updates, so the current tab, the
clone menu and anything the reader has typed stay where they are. A badge that
moves keeps one short ring, because a number changing elsewhere on the screen
is easy to miss. The endpoint answers 404 for a repository the viewer cannot
read, like every other page under /r/{name}.

server/web/page.go +22

@@ -6,6 +6,7 @@ package web
6 6 // admitted the request.
7 7
8 8 import (
9 "net/http"
9 10 "strings"
10 11
11 12 "github.com/rodent-software/vole/forge/access"
@@ -176,6 +177,24 @@ func (w *Web) siteDeployed(m *repo.Meta, acl *access.ACL) bool {
176 177 return ok
177 178 }
178 179
180 // RepoCounts answers the poll behind the repository tabs: the two open counts as
181 // out-of-band updates to the badges the header already shows. It reads the same
182 // counts the page did, so a new issue or change appears while the reader is on
183 // the page, and it sends nothing else, so the current tab, the clone menu and
184 // any form the reader has open stay where they are. A repository the viewer may
185 // not read answers 404 like every other page, so the poll cannot confirm that a
186 // private repository exists.
187 func (w *Web) RepoCounts(rw http.ResponseWriter, r *http.Request) {
188 m, ok := w.open(rw, r)
189 if !ok {
190 return
191 }
192 issues, requests := w.openCounts(memoOf(r), m)
193 w.render(rw, "repo_counts_live", repoNavData{
194 Name: m.Name, OpenIssues: issues, OpenRequests: requests, Live: true,
195 }, 0)
196 }
197
179 198 type repoNavData struct {
180 199 Name string
181 200 Description string
@@ -187,4 +206,7 @@ type repoNavData struct {
187 206 Site string
188 207 OpenIssues int
189 208 OpenRequests int
209 // Live marks a render of the count badges alone, where each one carries the
210 // out-of-band swap the header's poll answers with.
211 Live bool
190 212 }