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 | } | |