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.
Celebrate a landed change request, once
c8fa5759b293126f1b247abc746bc339791568cb · Keenan Nemetz · 13d ago · parent 53ff967b
Celebrate a landed change request, once A successful landing now redirects with ?merged=1, and app.js answers that parameter by fetching static/confetti.browser.js (canvas-confetti 1.9.3, ISC) and firing one burst. The flag is removed from the address as soon as it is read, so a reload, a bookmark or a shared link is an ordinary visit, and no page without the parameter ever requests the bundle. The library honours prefers-reduced-motion through disableForReducedMotion, and reset() before firing means a page restored from the back/forward cache cannot stack a second canvas. The asset is vendored the way htmx and Lucide are: the file is unmodified from the published npm tarball, with the license beside it, so script-src 'self' stays as it is. It is deliberately not in the page shell, because Static() serves assets uncompressed and a shell script would make every page pay for a celebration only one page uses. Refs #01M5XZ7T4R88BA9KV1KTSV7ZXP
server/ui_test.go +29
| @@ -84,6 +84,35 @@ func TestStaticAssetsAreServedFromTheBinary(t *testing.T) { | |||
| 84 | 84 | } | |
| 85 | 85 | } | |
| 86 | 86 | ||
| 87 | // The celebration library is a static asset like any other, but it is not in the | ||
| 88 | // shell: the shell would make every page load fetch it. app.js names it, and names | ||
| 89 | // it once, so the only request is the one a landing asks for. | ||
| 90 | func TestConfettiIsFetchedOnlyForALanding(t *testing.T) { | ||
| 91 | t.Parallel() | ||
| 92 | f := newFixture(t) | ||
| 93 | f.publish(f.repo) | ||
| 94 | code, body := f.get("/static/confetti.browser.js") | ||
| 95 | if code != 200 { | ||
| 96 | t.Fatalf("/static/confetti.browser.js = %d", code) | ||
| 97 | } | ||
| 98 | if !strings.Contains(body, "canvas-confetti v1.9.3") { | ||
| 99 | t.Fatalf("the vendored script is not canvas-confetti 1.9.3:\n%s", body[:min(len(body), 200)]) | ||
| 100 | } | ||
| 101 | code, app := f.get("/static/app.js") | ||
| 102 | if code != 200 { | ||
| 103 | t.Fatalf("/static/app.js = %d", code) | ||
| 104 | } | ||
| 105 | if n := strings.Count(app, "/static/confetti.browser.js"); n != 1 { | ||
| 106 | t.Fatalf("app.js names the confetti asset %d times, want 1", n) | ||
| 107 | } | ||
| 108 | for _, page := range []string{"/", "/r/" + f.repo + "/requests"} { | ||
| 109 | if code, html := f.get(page); code != 200 { | ||
| 110 | t.Fatalf("%s = %d", page, code) | ||
| 111 | } else if strings.Contains(html, "confetti") { | ||
| 112 | t.Fatalf("%s loads the celebration from the shell:\n%s", page, html) | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 87 | 116 | func TestRunsPageListsQueuedWork(t *testing.T) { | |
| 88 | 117 | t.Parallel() | |
| 89 | 118 | f := newFixture(t) | |