feat(web): owner inbox page and home button
- commit
- bc6524ce22edf8d1d57debf44b4d4324876a00ec
- author
- brice · · 2026-10-19 06:37 UTC
- parent
- ab38ed2
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
23 files · +1617 -378
M docs/issues.md +6 -0
| @@ -33,3 +33,9 @@ ermite token create claude --preset agent --scope issue:write --repo <repo> --br | |||
| 33 | 33 | ## Numbering | |
| 34 | 34 | ||
| 35 | 35 | Merge requests and issues of a repository draw `#n` from one sequence, so a number names one thing: `ermite mr show myrepo 1`, `ermite issue show myrepo 2`. | |
| 36 | + | ||
| 37 | + | ## Inbox | |
| 38 | + | ||
| 39 | + | The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues. | |
| 40 | + | ||
| 41 | + | The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows. | |
| @@ -33,3 +33,9 @@ ermite token create claude --preset agent --scope issue:write --repo <repo> --br | |||||
| 33 | ## Numbering | 33 | ## Numbering | ||
| 34 | 34 | ||||
| 35 | Merge requests and issues of a repository draw `#n` from one sequence, so a number names one thing: `ermite mr show myrepo 1`, `ermite issue show myrepo 2`. | 35 | Merge requests and issues of a repository draw `#n` from one sequence, so a number names one thing: `ermite mr show myrepo 1`, `ermite issue show myrepo 2`. | ||
| 36 | + | ||||
| 37 | + | ## Inbox | |||
| 38 | + | ||||
| 39 | + | The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues. | |||
| 40 | + | ||||
| 41 | + | The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows. | |||
M internal/adapters/web/events.go +31 -2
| @@ -27,6 +27,7 @@ import ( | |||
| 27 | 27 | // the HTML fragments the page shows, sent as Server-Sent Events: | |
| 28 | 28 | // | |
| 29 | 29 | // GET /-/events?topic=home | |
| 30 | + | // GET /-/events?topic=owner&view=inbox[&repo=<name>] (the signed-in owner only) | |
| 30 | 31 | // GET /-/events?topic=repo:<name>&view=summary|refs | |
| 31 | 32 | // GET /-/events?topic=repo:<name>&view=commits&ref=<branch>&head=<sha> | |
| 32 | 33 | // GET /-/events?topic=repo:<name>&view=mrs | |
| @@ -84,9 +85,14 @@ const ( | |||
| 84 | 85 | retryAfter = 10 | |
| 85 | 86 | ) | |
| 86 | 87 | ||
| 87 | - | // parseTopic reads "home" or "repo:<name>"; repo is "" for home. | |
| 88 | + | // ownerTopic is the stream of the inbox: the merge requests and issues of every | |
| 89 | + | // repository, for the owner. | |
| 90 | + | const ownerTopic = "owner" | |
| 91 | + | ||
| 92 | + | // parseTopic reads "home", "owner" or "repo:<name>"; repo is "" for home and | |
| 93 | + | // owner. | |
| 88 | 94 | func parseTopic(topic string) (repo string, ok bool) { | |
| 89 | - | if topic == "home" { | |
| 95 | + | if topic == "home" || topic == ownerTopic { | |
| 90 | 96 | return "", true | |
| 91 | 97 | } | |
| 92 | 98 | if name, found := strings.CutPrefix(topic, "repo:"); found && name != "" { | |
| @@ -95,6 +101,21 @@ func parseTopic(topic string) (repo string, ok bool) { | |||
| 95 | 101 | return "", false | |
| 96 | 102 | } | |
| 97 | 103 | ||
| 104 | + | // ownerStreamOK tells whether the request may follow the owner topic: the | |
| 105 | + | // signed-in owner, with the inbox view and a valid repository filter, on a | |
| 106 | + | // server that has the inbox. | |
| 107 | + | func (s *Server) ownerStreamOK(ctx context.Context, q url.Values) bool { | |
| 108 | + | if s.cfg.Inbox == nil || !SignedIn(ctx) || q.Get("view") != "inbox" { | |
| 109 | + | return false | |
| 110 | + | } | |
| 111 | + | if f := q.Get("repo"); f != "" { | |
| 112 | + | if _, err := domain.ParseRepoName(f); err != nil { | |
| 113 | + | return false | |
| 114 | + | } | |
| 115 | + | } | |
| 116 | + | return true | |
| 117 | + | } | |
| 118 | + | ||
| 98 | 119 | // events is GET /-/events. | |
| 99 | 120 | func (s *Server) events(w http.ResponseWriter, r *http.Request) { | |
| 100 | 121 | if s.cfg.Events == nil { | |
| @@ -104,6 +125,11 @@ func (s *Server) events(w http.ResponseWriter, r *http.Request) { | |||
| 104 | 125 | q := r.URL.Query() | |
| 105 | 126 | topic := q.Get("topic") | |
| 106 | 127 | repo, ok := parseTopic(topic) | |
| 128 | + | if topic == ownerTopic { | |
| 129 | + | // Anyone but the signed-in owner gets the answer of an unknown topic. | |
| 130 | + | ok = s.ownerStreamOK(r.Context(), q) | |
| 131 | + | repo = "" | |
| 132 | + | } | |
| 107 | 133 | if !ok { | |
| 108 | 134 | denyStream(w, http.StatusBadRequest, "topic must be home or repo:<name>") | |
| 109 | 135 | return | |
| @@ -227,6 +253,9 @@ func (s *Server) events(w http.ResponseWriter, r *http.Request) { | |||
| 227 | 253 | } | |
| 228 | 254 | ||
| 229 | 255 | st := &liveStream{s: s, repo: repo, view: q.Get("view"), ref: q.Get("ref"), head: q.Get("head"), n: q.Get("n"), job: q.Get("job"), sha: sha} | |
| 256 | + | if topic == ownerTopic { | |
| 257 | + | st.filter = q.Get("repo") | |
| 258 | + | } | |
| 230 | 259 | handle := func(m recvd) bool { | |
| 231 | 260 | if m.err != nil { | |
| 232 | 261 | if ctx.Err() == nil && !errors.Is(m.err, context.Canceled) { | |
| @@ -27,6 +27,7 @@ import ( | |||||
| 27 | // the HTML fragments the page shows, sent as Server-Sent Events: | 27 | // the HTML fragments the page shows, sent as Server-Sent Events: | ||
| 28 | // | 28 | // | ||
| 29 | // GET /-/events?topic=home | 29 | // GET /-/events?topic=home | ||
| 30 | + | // GET /-/events?topic=owner&view=inbox[&repo=<name>] (the signed-in owner only) | |||
| 30 | // GET /-/events?topic=repo:<name>&view=summary|refs | 31 | // GET /-/events?topic=repo:<name>&view=summary|refs | ||
| 31 | // GET /-/events?topic=repo:<name>&view=commits&ref=<branch>&head=<sha> | 32 | // GET /-/events?topic=repo:<name>&view=commits&ref=<branch>&head=<sha> | ||
| 32 | // GET /-/events?topic=repo:<name>&view=mrs | 33 | // GET /-/events?topic=repo:<name>&view=mrs | ||
| @@ -84,9 +85,14 @@ const ( | |||||
| 84 | retryAfter = 10 | 85 | retryAfter = 10 | ||
| 85 | ) | 86 | ) | ||
| 86 | 87 | ||||
| 87 | - | // parseTopic reads "home" or "repo:<name>"; repo is "" for home. | 88 | + | // ownerTopic is the stream of the inbox: the merge requests and issues of every |
| 89 | + | // repository, for the owner. | |||
| 90 | + | const ownerTopic = "owner" | |||
| 91 | + | ||||
| 92 | + | // parseTopic reads "home", "owner" or "repo:<name>"; repo is "" for home and | |||
| 93 | + | // owner. | |||
| 88 | func parseTopic(topic string) (repo string, ok bool) { | 94 | func parseTopic(topic string) (repo string, ok bool) { | ||
| 89 | - | if topic == "home" { | 95 | + | if topic == "home" || topic == ownerTopic { |
| 90 | return "", true | 96 | return "", true | ||
| 91 | } | 97 | } | ||
| 92 | if name, found := strings.CutPrefix(topic, "repo:"); found && name != "" { | 98 | if name, found := strings.CutPrefix(topic, "repo:"); found && name != "" { | ||
| @@ -95,6 +101,21 @@ func parseTopic(topic string) (repo string, ok bool) { | |||||
| 95 | return "", false | 101 | return "", false | ||
| 96 | } | 102 | } | ||
| 97 | 103 | ||||
| 104 | + | // ownerStreamOK tells whether the request may follow the owner topic: the | |||
| 105 | + | // signed-in owner, with the inbox view and a valid repository filter, on a | |||
| 106 | + | // server that has the inbox. | |||
| 107 | + | func (s *Server) ownerStreamOK(ctx context.Context, q url.Values) bool { | |||
| 108 | + | if s.cfg.Inbox == nil || !SignedIn(ctx) || q.Get("view") != "inbox" { | |||
| 109 | + | return false | |||
| 110 | + | } | |||
| 111 | + | if f := q.Get("repo"); f != "" { | |||
| 112 | + | if _, err := domain.ParseRepoName(f); err != nil { | |||
| 113 | + | return false | |||
| 114 | + | } | |||
| 115 | + | } | |||
| 116 | + | return true | |||
| 117 | + | } | |||
| 118 | + | ||||
| 98 | // events is GET /-/events. | 119 | // events is GET /-/events. | ||
| 99 | func (s *Server) events(w http.ResponseWriter, r *http.Request) { | 120 | func (s *Server) events(w http.ResponseWriter, r *http.Request) { | ||
| 100 | if s.cfg.Events == nil { | 121 | if s.cfg.Events == nil { | ||
| @@ -104,6 +125,11 @@ func (s *Server) events(w http.ResponseWriter, r *http.Request) { | |||||
| 104 | q := r.URL.Query() | 125 | q := r.URL.Query() | ||
| 105 | topic := q.Get("topic") | 126 | topic := q.Get("topic") | ||
| 106 | repo, ok := parseTopic(topic) | 127 | repo, ok := parseTopic(topic) | ||
| 128 | + | if topic == ownerTopic { | |||
| 129 | + | // Anyone but the signed-in owner gets the answer of an unknown topic. | |||
| 130 | + | ok = s.ownerStreamOK(r.Context(), q) | |||
| 131 | + | repo = "" | |||
| 132 | + | } | |||
| 107 | if !ok { | 133 | if !ok { | ||
| 108 | denyStream(w, http.StatusBadRequest, "topic must be home or repo:<name>") | 134 | denyStream(w, http.StatusBadRequest, "topic must be home or repo:<name>") | ||
| 109 | return | 135 | return | ||
| @@ -227,6 +253,9 @@ func (s *Server) events(w http.ResponseWriter, r *http.Request) { | |||||
| 227 | } | 253 | } | ||
| 228 | 254 | ||||
| 229 | st := &liveStream{s: s, repo: repo, view: q.Get("view"), ref: q.Get("ref"), head: q.Get("head"), n: q.Get("n"), job: q.Get("job"), sha: sha} | 255 | st := &liveStream{s: s, repo: repo, view: q.Get("view"), ref: q.Get("ref"), head: q.Get("head"), n: q.Get("n"), job: q.Get("job"), sha: sha} | ||
| 256 | + | if topic == ownerTopic { | |||
| 257 | + | st.filter = q.Get("repo") | |||
| 258 | + | } | |||
| 230 | handle := func(m recvd) bool { | 259 | handle := func(m recvd) bool { | ||
| 231 | if m.err != nil { | 260 | if m.err != nil { | ||
| 232 | if ctx.Err() == nil && !errors.Is(m.err, context.Canceled) { | 261 | if ctx.Err() == nil && !errors.Is(m.err, context.Canceled) { | ||
M internal/adapters/web/events_test.go +1 -1
| @@ -36,7 +36,7 @@ func TestFormatEvent(t *testing.T) { | |||
| 36 | 36 | ||
| 37 | 37 | func TestParseTopic(t *testing.T) { | |
| 38 | 38 | t.Parallel() | |
| 39 | - | for in, want := range map[string]string{"home": "", "repo:x": "x", "repo:a.b-c": "a.b-c"} { | |
| 39 | + | for in, want := range map[string]string{"home": "", "owner": "", "repo:x": "x", "repo:a.b-c": "a.b-c"} { | |
| 40 | 40 | repo, ok := parseTopic(in) | |
| 41 | 41 | assert.True(t, ok, in) | |
| 42 | 42 | assert.Equal(t, want, repo, in) | |
| @@ -36,7 +36,7 @@ func TestFormatEvent(t *testing.T) { | |||||
| 36 | 36 | ||||
| 37 | func TestParseTopic(t *testing.T) { | 37 | func TestParseTopic(t *testing.T) { | ||
| 38 | t.Parallel() | 38 | t.Parallel() | ||
| 39 | - | for in, want := range map[string]string{"home": "", "repo:x": "x", "repo:a.b-c": "a.b-c"} { | 39 | + | for in, want := range map[string]string{"home": "", "owner": "", "repo:x": "x", "repo:a.b-c": "a.b-c"} { |
| 40 | repo, ok := parseTopic(in) | 40 | repo, ok := parseTopic(in) | ||
| 41 | assert.True(t, ok, in) | 41 | assert.True(t, ok, in) | ||
| 42 | assert.Equal(t, want, repo, in) | 42 | assert.Equal(t, want, repo, in) | ||
M internal/adapters/web/fragments.go +10 -5
| @@ -21,11 +21,13 @@ import ( | |||
| 21 | 21 | type liveStream struct { | |
| 22 | 22 | s *Server | |
| 23 | 23 | repo string // "" on the home page | |
| 24 | - | view string // "summary", "refs" or "commits" | |
| 25 | - | ref string // commits: the branch listed | |
| 26 | - | head string // commits: the commit listed first | |
| 27 | - | n string // mr: the number of the merge request shown; run: the run id | |
| 28 | - | job string // job: the id of the job shown | |
| 24 | + | // filter is the repository the inbox is filtered on, "" for all. | |
| 25 | + | filter string | |
| 26 | + | view string // "summary", "refs" or "commits" | |
| 27 | + | ref string // commits: the branch listed | |
| 28 | + | head string // commits: the commit listed first | |
| 29 | + | n string // mr: the number of the merge request shown; run: the run id | |
| 30 | + | job string // job: the id of the job shown | |
| 29 | 31 | // sha is the commit of the run of the job shown, read once when the stream | |
| 30 | 32 | // is set up: the annotations link to files at it, and it never changes. | |
| 31 | 33 | sha string | |
| @@ -75,6 +77,9 @@ func (l *liveStream) render(ctx context.Context, we ports.WatchEvent) ([]fragmen | |||
| 75 | 77 | if we.Event == nil { | |
| 76 | 78 | return nil, nil | |
| 77 | 79 | } | |
| 80 | + | if l.view == "inbox" { | |
| 81 | + | return l.inbox(ctx, we) | |
| 82 | + | } | |
| 78 | 83 | if l.repo == "" { | |
| 79 | 84 | return l.home(ctx, we) | |
| 80 | 85 | } | |
| @@ -21,11 +21,13 @@ import ( | |||||
| 21 | type liveStream struct { | 21 | type liveStream struct { | ||
| 22 | s *Server | 22 | s *Server | ||
| 23 | repo string // "" on the home page | 23 | repo string // "" on the home page | ||
| 24 | - | view string // "summary", "refs" or "commits" | 24 | + | // filter is the repository the inbox is filtered on, "" for all. |
| 25 | - | ref string // commits: the branch listed | 25 | + | filter string |
| 26 | - | head string // commits: the commit listed first | 26 | + | view string // "summary", "refs" or "commits" |
| 27 | - | n string // mr: the number of the merge request shown; run: the run id | 27 | + | ref string // commits: the branch listed |
| 28 | - | job string // job: the id of the job shown | 28 | + | head string // commits: the commit listed first |
| 29 | + | n string // mr: the number of the merge request shown; run: the run id | |||
| 30 | + | job string // job: the id of the job shown | |||
| 29 | // sha is the commit of the run of the job shown, read once when the stream | 31 | // sha is the commit of the run of the job shown, read once when the stream | ||
| 30 | // is set up: the annotations link to files at it, and it never changes. | 32 | // is set up: the annotations link to files at it, and it never changes. | ||
| 31 | sha string | 33 | sha string | ||
| @@ -75,6 +77,9 @@ func (l *liveStream) render(ctx context.Context, we ports.WatchEvent) ([]fragmen | |||||
| 75 | if we.Event == nil { | 77 | if we.Event == nil { | ||
| 76 | return nil, nil | 78 | return nil, nil | ||
| 77 | } | 79 | } | ||
| 80 | + | if l.view == "inbox" { | |||
| 81 | + | return l.inbox(ctx, we) | |||
| 82 | + | } | |||
| 78 | if l.repo == "" { | 83 | if l.repo == "" { | ||
| 79 | return l.home(ctx, we) | 84 | return l.home(ctx, we) | ||
| 80 | } | 85 | } | ||
M internal/adapters/web/fragments.templ +1 -1
| @@ -102,7 +102,7 @@ templ Live(l Layout) { | |||
| 102 | 102 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | |
| 103 | 103 | htmx:sse:error -> ermiteLive.error(event.detail.status); | |
| 104 | 104 | htmx:sse:before:connection -> ermiteLive.gate(event); | |
| 105 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | |
| 105 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); | |
| 106 | 106 | gap -> ermiteLive.reload()" | |
| 107 | 107 | ></span> | |
| 108 | 108 | } | |
| @@ -102,7 +102,7 @@ templ Live(l Layout) { | |||||
| 102 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | 102 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | ||
| 103 | htmx:sse:error -> ermiteLive.error(event.detail.status); | 103 | htmx:sse:error -> ermiteLive.error(event.detail.status); | ||
| 104 | htmx:sse:before:connection -> ermiteLive.gate(event); | 104 | htmx:sse:before:connection -> ermiteLive.gate(event); | ||
| 105 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | 105 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); |
| 106 | gap -> ermiteLive.reload()" | 106 | gap -> ermiteLive.reload()" | ||
| 107 | ></span> | 107 | ></span> | ||
| 108 | } | 108 | } | ||
M internal/adapters/web/fragments_templ.go +1 -1 generated file: collapsed
M internal/adapters/web/home.go +3 -0
| @@ -121,6 +121,9 @@ func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, in | |||
| 121 | 121 | p.Sorts = append(p.Sorts, sl) | |
| 122 | 122 | } | |
| 123 | 123 | p.Rows = s.homeRows(ctx, repos, now) | |
| 124 | + | if n, show := s.inboxCount(ctx); show { | |
| 125 | + | p.Inbox = &InboxButton{Href: inboxPath, Count: n} | |
| 126 | + | } | |
| 124 | 127 | ||
| 125 | 128 | l := s.base() | |
| 126 | 129 | l.Title = s.instance | |
| @@ -121,6 +121,9 @@ func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, in | |||||
| 121 | p.Sorts = append(p.Sorts, sl) | 121 | p.Sorts = append(p.Sorts, sl) | ||
| 122 | } | 122 | } | ||
| 123 | p.Rows = s.homeRows(ctx, repos, now) | 123 | p.Rows = s.homeRows(ctx, repos, now) | ||
| 124 | + | if n, show := s.inboxCount(ctx); show { | |||
| 125 | + | p.Inbox = &InboxButton{Href: inboxPath, Count: n} | |||
| 126 | + | } | |||
| 124 | 127 | ||||
| 125 | l := s.base() | 128 | l := s.base() | ||
| 126 | l.Title = s.instance | 129 | l.Title = s.instance | ||
A internal/adapters/web/inbox.go +188 -0
| @@ -0,0 +1,188 @@ | |||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | + | ||
| 3 | + | package web | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "context" | |
| 7 | + | "net/http" | |
| 8 | + | "net/url" | |
| 9 | + | "strconv" | |
| 10 | + | "time" | |
| 11 | + | ||
| 12 | + | "github.com/a-h/templ" | |
| 13 | + | ||
| 14 | + | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 16 | + | ) | |
| 17 | + | ||
| 18 | + | // The owner's inbox (ADR 0031): GET /-/inbox lists the open merge requests and | |
| 19 | + | // issues of every repository, newest activity first, with a filter by | |
| 20 | + | // repository (?repo=<name>, a plain link, so it works without scripts). Only a | |
| 21 | + | // signed-in owner sees it: for anyone else the path is as missing as any other. | |
| 22 | + | // It follows the stream "owner" with view=inbox: each event of a merge request | |
| 23 | + | // or an issue sends the counters, the two lists and the filter again. | |
| 24 | + | ||
| 25 | + | // inboxPath is the page of the inbox. | |
| 26 | + | const inboxPath = "/-/inbox" | |
| 27 | + | ||
| 28 | + | // inboxEvent is the name of the live events of the inbox. | |
| 29 | + | const inboxEvent = "inbox" | |
| 30 | + | ||
| 31 | + | // InboxRow is one open item of the inbox. | |
| 32 | + | type InboxRow struct { | |
| 33 | + | Repo string | |
| 34 | + | RepoHref string | |
| 35 | + | Number string | |
| 36 | + | Href string | |
| 37 | + | Title string | |
| 38 | + | When string | |
| 39 | + | WhenAt string | |
| 40 | + | Cursor bool | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | // InboxRepoLink is an entry of the repository filter. | |
| 44 | + | type InboxRepoLink struct { | |
| 45 | + | Label string | |
| 46 | + | Href string | |
| 47 | + | Current bool | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // InboxPage is the inbox: the counters, the filter and the two lists. | |
| 51 | + | type InboxPage struct { | |
| 52 | + | // MergeRequests and Issues count every open item, whatever the filter. | |
| 53 | + | MergeRequests, Issues int | |
| 54 | + | Filter string // the repository filtered on, "" for all | |
| 55 | + | Repos []InboxRepoLink | |
| 56 | + | MRs []InboxRow | |
| 57 | + | IssueRows []InboxRow | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // inboxHref is the inbox page, filtered on repo when it is not "". | |
| 61 | + | func inboxHref(repo string) string { | |
| 62 | + | if repo == "" { | |
| 63 | + | return inboxPath | |
| 64 | + | } | |
| 65 | + | return inboxPath + "?repo=" + url.QueryEscape(repo) | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // inboxFilter reads ?repo=. A name that is not valid is a page that is not | |
| 69 | + | // there. | |
| 70 | + | func inboxFilter(r *http.Request) (domain.RepoName, error) { | |
| 71 | + | raw := r.URL.Query().Get("repo") | |
| 72 | + | if raw == "" { | |
| 73 | + | return domain.RepoName{}, nil | |
| 74 | + | } | |
| 75 | + | name, err := domain.ParseRepoName(raw) | |
| 76 | + | if err != nil { | |
| 77 | + | return domain.RepoName{}, errNotFound | |
| 78 | + | } | |
| 79 | + | return name, nil | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // inboxPage builds the page from the overview. | |
| 83 | + | func (s *Server) inboxPage(ov ports.InboxOverview, filter domain.RepoName) InboxPage { | |
| 84 | + | now := s.cfg.Now() | |
| 85 | + | p := InboxPage{MergeRequests: ov.Counts.MergeRequests, Issues: ov.Counts.Issues, Filter: filter.String()} | |
| 86 | + | row := func(repo domain.RepoName, n int64, href, title string, updated, created time.Time) InboxRow { | |
| 87 | + | ts := updated | |
| 88 | + | if ts.IsZero() { | |
| 89 | + | ts = created | |
| 90 | + | } | |
| 91 | + | r := InboxRow{ | |
| 92 | + | Repo: repo.String(), RepoHref: repoHref(repo.String()), | |
| 93 | + | Number: "#" + strconv.FormatInt(n, 10), Href: href, Title: visibleText(title), | |
| 94 | + | } | |
| 95 | + | r.When, r.WhenAt = whenOf(now, ts) | |
| 96 | + | return r | |
| 97 | + | } | |
| 98 | + | for _, m := range ov.MergeRequests { | |
| 99 | + | p.MRs = append(p.MRs, row(m.Repo, m.Number, mrHref(m.Repo.String(), m.Number), m.Title.String(), m.UpdatedAt, m.CreatedAt)) | |
| 100 | + | } | |
| 101 | + | for _, i := range ov.Issues { | |
| 102 | + | p.IssueRows = append(p.IssueRows, row(i.Repo, i.Number, issueHref(i.Repo.String(), i.Number), i.Title.String(), i.UpdatedAt, i.CreatedAt)) | |
| 103 | + | } | |
| 104 | + | switch { | |
| 105 | + | case len(p.MRs) > 0: | |
| 106 | + | p.MRs[0].Cursor = true | |
| 107 | + | case len(p.IssueRows) > 0: | |
| 108 | + | p.IssueRows[0].Cursor = true | |
| 109 | + | } | |
| 110 | + | p.Repos = append(p.Repos, InboxRepoLink{Label: "all", Href: inboxHref(""), Current: filter.IsZero()}) | |
| 111 | + | for _, r := range ov.Repos { | |
| 112 | + | p.Repos = append(p.Repos, InboxRepoLink{Label: r.String(), Href: inboxHref(r.String()), Current: r == filter}) | |
| 113 | + | } | |
| 114 | + | return p | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // inbox is GET /-/inbox. | |
| 118 | + | func (s *Server) inbox(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 119 | + | if !SignedIn(ctx) { | |
| 120 | + | return nil, 0, errNotFound | |
| 121 | + | } | |
| 122 | + | filter, err := inboxFilter(r) | |
| 123 | + | if err != nil { | |
| 124 | + | return nil, 0, err | |
| 125 | + | } | |
| 126 | + | ov, err := s.cfg.Inbox.Overview(ctx, principal(ctx), filter) | |
| 127 | + | if err != nil { | |
| 128 | + | return nil, 0, err | |
| 129 | + | } | |
| 130 | + | l := s.base() | |
| 131 | + | l.Title = "inbox · " + s.instance | |
| 132 | + | l.Crumbs = []Crumb{{Label: "inbox", Current: true}} | |
| 133 | + | l.Cmd = []CmdItem{{Kind: "go", Label: "home", Href: "/"}} | |
| 134 | + | if s.cfg.Events != nil { | |
| 135 | + | q := "view=inbox" | |
| 136 | + | if !filter.IsZero() { | |
| 137 | + | q += "&repo=" + url.QueryEscape(filter.String()) | |
| 138 | + | } | |
| 139 | + | l.Live, l.LiveURL = true, liveURL("owner", q) | |
| 140 | + | } | |
| 141 | + | return Inbox(l, s.inboxPage(ov, filter)), http.StatusOK, nil | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // inboxCount is the number of open items the home button shows, and whether | |
| 145 | + | // there is a button: only for the signed-in owner, and only when the inbox is | |
| 146 | + | // there. A failed read leaves the button without a number. | |
| 147 | + | func (s *Server) inboxCount(ctx context.Context) (n int, show bool) { | |
| 148 | + | if s.cfg.Inbox == nil || !SignedIn(ctx) { | |
| 149 | + | return 0, false | |
| 150 | + | } | |
| 151 | + | ov, err := s.cfg.Inbox.Overview(ctx, principal(ctx), domain.RepoName{}) | |
| 152 | + | if err != nil { | |
| 153 | + | return -1, true | |
| 154 | + | } | |
| 155 | + | return ov.Counts.MergeRequests + ov.Counts.Issues, true | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // inbox renders the fragments an event of a merge request or an issue changes | |
| 159 | + | // on the inbox page: the counters, the filter and the two lists. | |
| 160 | + | func (l *liveStream) inbox(ctx context.Context, we ports.WatchEvent) ([]fragment, error) { | |
| 161 | + | switch we.Event.(type) { | |
| 162 | + | case domain.MergeRequestOpened, domain.MergeRequestMerged, domain.MergeRequestClosed, domain.MergeRequestReady, domain.CommentAdded, | |
| 163 | + | domain.IssueOpened, domain.IssueClosed, domain.IssueReopened, domain.IssueCommented: | |
| 164 | + | default: | |
| 165 | + | return nil, nil | |
| 166 | + | } | |
| 167 | + | if l.s.cfg.Inbox == nil { | |
| 168 | + | return nil, nil | |
| 169 | + | } | |
| 170 | + | var filter domain.RepoName | |
| 171 | + | if l.filter != "" { | |
| 172 | + | filter, _ = domain.ParseRepoName(l.filter) | |
| 173 | + | } | |
| 174 | + | ov, err := l.s.cfg.Inbox.Overview(ctx, principal(ctx), filter) | |
| 175 | + | if err != nil { | |
| 176 | + | return nil, err | |
| 177 | + | } | |
| 178 | + | p := l.s.inboxPage(ov, filter) | |
| 179 | + | var out []fragment | |
| 180 | + | for _, c := range []templ.Component{InboxCounters(p), InboxRepos(p), InboxMRs(p), InboxIssues(p)} { | |
| 181 | + | f, err := renderFragment(ctx, inboxEvent, c) | |
| 182 | + | if err != nil { | |
| 183 | + | return nil, err | |
| 184 | + | } | |
| 185 | + | out = append(out, f) | |
| 186 | + | } | |
| 187 | + | return out, nil | |
| 188 | + | } | |
| @@ -0,0 +1,188 @@ | |||||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |||
| 2 | + | ||||
| 3 | + | package web | |||
| 4 | + | ||||
| 5 | + | import ( | |||
| 6 | + | "context" | |||
| 7 | + | "net/http" | |||
| 8 | + | "net/url" | |||
| 9 | + | "strconv" | |||
| 10 | + | "time" | |||
| 11 | + | ||||
| 12 | + | "github.com/a-h/templ" | |||
| 13 | + | ||||
| 14 | + | "bnema.dev/ermite/internal/domain" | |||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 16 | + | ) | |||
| 17 | + | ||||
| 18 | + | // The owner's inbox (ADR 0031): GET /-/inbox lists the open merge requests and | |||
| 19 | + | // issues of every repository, newest activity first, with a filter by | |||
| 20 | + | // repository (?repo=<name>, a plain link, so it works without scripts). Only a | |||
| 21 | + | // signed-in owner sees it: for anyone else the path is as missing as any other. | |||
| 22 | + | // It follows the stream "owner" with view=inbox: each event of a merge request | |||
| 23 | + | // or an issue sends the counters, the two lists and the filter again. | |||
| 24 | + | ||||
| 25 | + | // inboxPath is the page of the inbox. | |||
| 26 | + | const inboxPath = "/-/inbox" | |||
| 27 | + | ||||
| 28 | + | // inboxEvent is the name of the live events of the inbox. | |||
| 29 | + | const inboxEvent = "inbox" | |||
| 30 | + | ||||
| 31 | + | // InboxRow is one open item of the inbox. | |||
| 32 | + | type InboxRow struct { | |||
| 33 | + | Repo string | |||
| 34 | + | RepoHref string | |||
| 35 | + | Number string | |||
| 36 | + | Href string | |||
| 37 | + | Title string | |||
| 38 | + | When string | |||
| 39 | + | WhenAt string | |||
| 40 | + | Cursor bool | |||
| 41 | + | } | |||
| 42 | + | ||||
| 43 | + | // InboxRepoLink is an entry of the repository filter. | |||
| 44 | + | type InboxRepoLink struct { | |||
| 45 | + | Label string | |||
| 46 | + | Href string | |||
| 47 | + | Current bool | |||
| 48 | + | } | |||
| 49 | + | ||||
| 50 | + | // InboxPage is the inbox: the counters, the filter and the two lists. | |||
| 51 | + | type InboxPage struct { | |||
| 52 | + | // MergeRequests and Issues count every open item, whatever the filter. | |||
| 53 | + | MergeRequests, Issues int | |||
| 54 | + | Filter string // the repository filtered on, "" for all | |||
| 55 | + | Repos []InboxRepoLink | |||
| 56 | + | MRs []InboxRow | |||
| 57 | + | IssueRows []InboxRow | |||
| 58 | + | } | |||
| 59 | + | ||||
| 60 | + | // inboxHref is the inbox page, filtered on repo when it is not "". | |||
| 61 | + | func inboxHref(repo string) string { | |||
| 62 | + | if repo == "" { | |||
| 63 | + | return inboxPath | |||
| 64 | + | } | |||
| 65 | + | return inboxPath + "?repo=" + url.QueryEscape(repo) | |||
| 66 | + | } | |||
| 67 | + | ||||
| 68 | + | // inboxFilter reads ?repo=. A name that is not valid is a page that is not | |||
| 69 | + | // there. | |||
| 70 | + | func inboxFilter(r *http.Request) (domain.RepoName, error) { | |||
| 71 | + | raw := r.URL.Query().Get("repo") | |||
| 72 | + | if raw == "" { | |||
| 73 | + | return domain.RepoName{}, nil | |||
| 74 | + | } | |||
| 75 | + | name, err := domain.ParseRepoName(raw) | |||
| 76 | + | if err != nil { | |||
| 77 | + | return domain.RepoName{}, errNotFound | |||
| 78 | + | } | |||
| 79 | + | return name, nil | |||
| 80 | + | } | |||
| 81 | + | ||||
| 82 | + | // inboxPage builds the page from the overview. | |||
| 83 | + | func (s *Server) inboxPage(ov ports.InboxOverview, filter domain.RepoName) InboxPage { | |||
| 84 | + | now := s.cfg.Now() | |||
| 85 | + | p := InboxPage{MergeRequests: ov.Counts.MergeRequests, Issues: ov.Counts.Issues, Filter: filter.String()} | |||
| 86 | + | row := func(repo domain.RepoName, n int64, href, title string, updated, created time.Time) InboxRow { | |||
| 87 | + | ts := updated | |||
| 88 | + | if ts.IsZero() { | |||
| 89 | + | ts = created | |||
| 90 | + | } | |||
| 91 | + | r := InboxRow{ | |||
| 92 | + | Repo: repo.String(), RepoHref: repoHref(repo.String()), | |||
| 93 | + | Number: "#" + strconv.FormatInt(n, 10), Href: href, Title: visibleText(title), | |||
| 94 | + | } | |||
| 95 | + | r.When, r.WhenAt = whenOf(now, ts) | |||
| 96 | + | return r | |||
| 97 | + | } | |||
| 98 | + | for _, m := range ov.MergeRequests { | |||
| 99 | + | p.MRs = append(p.MRs, row(m.Repo, m.Number, mrHref(m.Repo.String(), m.Number), m.Title.String(), m.UpdatedAt, m.CreatedAt)) | |||
| 100 | + | } | |||
| 101 | + | for _, i := range ov.Issues { | |||
| 102 | + | p.IssueRows = append(p.IssueRows, row(i.Repo, i.Number, issueHref(i.Repo.String(), i.Number), i.Title.String(), i.UpdatedAt, i.CreatedAt)) | |||
| 103 | + | } | |||
| 104 | + | switch { | |||
| 105 | + | case len(p.MRs) > 0: | |||
| 106 | + | p.MRs[0].Cursor = true | |||
| 107 | + | case len(p.IssueRows) > 0: | |||
| 108 | + | p.IssueRows[0].Cursor = true | |||
| 109 | + | } | |||
| 110 | + | p.Repos = append(p.Repos, InboxRepoLink{Label: "all", Href: inboxHref(""), Current: filter.IsZero()}) | |||
| 111 | + | for _, r := range ov.Repos { | |||
| 112 | + | p.Repos = append(p.Repos, InboxRepoLink{Label: r.String(), Href: inboxHref(r.String()), Current: r == filter}) | |||
| 113 | + | } | |||
| 114 | + | return p | |||
| 115 | + | } | |||
| 116 | + | ||||
| 117 | + | // inbox is GET /-/inbox. | |||
| 118 | + | func (s *Server) inbox(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |||
| 119 | + | if !SignedIn(ctx) { | |||
| 120 | + | return nil, 0, errNotFound | |||
| 121 | + | } | |||
| 122 | + | filter, err := inboxFilter(r) | |||
| 123 | + | if err != nil { | |||
| 124 | + | return nil, 0, err | |||
| 125 | + | } | |||
| 126 | + | ov, err := s.cfg.Inbox.Overview(ctx, principal(ctx), filter) | |||
| 127 | + | if err != nil { | |||
| 128 | + | return nil, 0, err | |||
| 129 | + | } | |||
| 130 | + | l := s.base() | |||
| 131 | + | l.Title = "inbox · " + s.instance | |||
| 132 | + | l.Crumbs = []Crumb{{Label: "inbox", Current: true}} | |||
| 133 | + | l.Cmd = []CmdItem{{Kind: "go", Label: "home", Href: "/"}} | |||
| 134 | + | if s.cfg.Events != nil { | |||
| 135 | + | q := "view=inbox" | |||
| 136 | + | if !filter.IsZero() { | |||
| 137 | + | q += "&repo=" + url.QueryEscape(filter.String()) | |||
| 138 | + | } | |||
| 139 | + | l.Live, l.LiveURL = true, liveURL("owner", q) | |||
| 140 | + | } | |||
| 141 | + | return Inbox(l, s.inboxPage(ov, filter)), http.StatusOK, nil | |||
| 142 | + | } | |||
| 143 | + | ||||
| 144 | + | // inboxCount is the number of open items the home button shows, and whether | |||
| 145 | + | // there is a button: only for the signed-in owner, and only when the inbox is | |||
| 146 | + | // there. A failed read leaves the button without a number. | |||
| 147 | + | func (s *Server) inboxCount(ctx context.Context) (n int, show bool) { | |||
| 148 | + | if s.cfg.Inbox == nil || !SignedIn(ctx) { | |||
| 149 | + | return 0, false | |||
| 150 | + | } | |||
| 151 | + | ov, err := s.cfg.Inbox.Overview(ctx, principal(ctx), domain.RepoName{}) | |||
| 152 | + | if err != nil { | |||
| 153 | + | return -1, true | |||
| 154 | + | } | |||
| 155 | + | return ov.Counts.MergeRequests + ov.Counts.Issues, true | |||
| 156 | + | } | |||
| 157 | + | ||||
| 158 | + | // inbox renders the fragments an event of a merge request or an issue changes | |||
| 159 | + | // on the inbox page: the counters, the filter and the two lists. | |||
| 160 | + | func (l *liveStream) inbox(ctx context.Context, we ports.WatchEvent) ([]fragment, error) { | |||
| 161 | + | switch we.Event.(type) { | |||
| 162 | + | case domain.MergeRequestOpened, domain.MergeRequestMerged, domain.MergeRequestClosed, domain.MergeRequestReady, domain.CommentAdded, | |||
| 163 | + | domain.IssueOpened, domain.IssueClosed, domain.IssueReopened, domain.IssueCommented: | |||
| 164 | + | default: | |||
| 165 | + | return nil, nil | |||
| 166 | + | } | |||
| 167 | + | if l.s.cfg.Inbox == nil { | |||
| 168 | + | return nil, nil | |||
| 169 | + | } | |||
| 170 | + | var filter domain.RepoName | |||
| 171 | + | if l.filter != "" { | |||
| 172 | + | filter, _ = domain.ParseRepoName(l.filter) | |||
| 173 | + | } | |||
| 174 | + | ov, err := l.s.cfg.Inbox.Overview(ctx, principal(ctx), filter) | |||
| 175 | + | if err != nil { | |||
| 176 | + | return nil, err | |||
| 177 | + | } | |||
| 178 | + | p := l.s.inboxPage(ov, filter) | |||
| 179 | + | var out []fragment | |||
| 180 | + | for _, c := range []templ.Component{InboxCounters(p), InboxRepos(p), InboxMRs(p), InboxIssues(p)} { | |||
| 181 | + | f, err := renderFragment(ctx, inboxEvent, c) | |||
| 182 | + | if err != nil { | |||
| 183 | + | return nil, err | |||
| 184 | + | } | |||
| 185 | + | out = append(out, f) | |||
| 186 | + | } | |||
| 187 | + | return out, nil | |||
| 188 | + | } | |||
A internal/adapters/web/inbox.templ +77 -0
| @@ -0,0 +1,77 @@ | |||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | + | ||
| 3 | + | package web | |
| 4 | + | ||
| 5 | + | // Inbox is the owner's inbox: what is open across every repository. The | |
| 6 | + | // counters, the filter and the lists are fragments with an id that the live | |
| 7 | + | // stream replaces as a whole (ermiteLive.swap). | |
| 8 | + | templ Inbox(l Layout, p InboxPage) { | |
| 9 | + | @Shell(l, nil) { | |
| 10 | + | <h1 class="sr">Inbox</h1> | |
| 11 | + | <div class="inbox"> | |
| 12 | + | @InboxCounters(p) | |
| 13 | + | @InboxRepos(p) | |
| 14 | + | @InboxMRs(p) | |
| 15 | + | @InboxIssues(p) | |
| 16 | + | </div> | |
| 17 | + | } | |
| 18 | + | } | |
| 19 | + | ||
| 20 | + | templ InboxCounters(p InboxPage) { | |
| 21 | + | <p id="inbox-counts" class="inbox-counts"> | |
| 22 | + | <strong>{ itoa(p.MergeRequests) }</strong> merge requests · <strong>{ itoa(p.Issues) }</strong> issues | |
| 23 | + | </p> | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | templ InboxRepos(p InboxPage) { | |
| 27 | + | <nav id="inbox-repos" class="since" aria-label="Repository"> | |
| 28 | + | for _, r := range p.Repos { | |
| 29 | + | <a | |
| 30 | + | href={ templ.SafeURL(r.Href) } | |
| 31 | + | if r.Current { | |
| 32 | + | aria-current="page" | |
| 33 | + | } | |
| 34 | + | >{ r.Label }</a> | |
| 35 | + | } | |
| 36 | + | </nav> | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | templ InboxMRs(p InboxPage) { | |
| 40 | + | <section id="inbox-mrs" aria-labelledby="inbox-mrs-h"> | |
| 41 | + | <h2 id="inbox-mrs-h" class="rule-h"><span>Open merge requests</span><span class="count">{ itoa(len(p.MRs)) }</span></h2> | |
| 42 | + | @inboxRows(p.MRs, "Open merge requests") | |
| 43 | + | if len(p.MRs) == 0 { | |
| 44 | + | <p class="lede dim">no open merge requests.</p> | |
| 45 | + | } | |
| 46 | + | </section> | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | templ InboxIssues(p InboxPage) { | |
| 50 | + | <section id="inbox-issues" aria-labelledby="inbox-issues-h"> | |
| 51 | + | <h2 id="inbox-issues-h" class="rule-h"><span>Open issues</span><span class="count">{ itoa(len(p.IssueRows)) }</span></h2> | |
| 52 | + | @inboxRows(p.IssueRows, "Open issues") | |
| 53 | + | if len(p.IssueRows) == 0 { | |
| 54 | + | <p class="lede dim">no open issues.</p> | |
| 55 | + | } | |
| 56 | + | </section> | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | templ inboxRows(rows []InboxRow, label string) { | |
| 60 | + | if len(rows) > 0 { | |
| 61 | + | <table class="list mrs" aria-label={ label }> | |
| 62 | + | <tbody data-rows> | |
| 63 | + | for _, m := range rows { | |
| 64 | + | <tr data-cursor?={ m.Cursor } data-state="open"> | |
| 65 | + | <td class="c-n mute">{ m.Number }</td> | |
| 66 | + | <td class="c-subject"><a href={ templ.SafeURL(m.Href) }>{ m.Title }</a> <a class="mute" href={ templ.SafeURL(m.RepoHref) }>{ m.Repo }</a></td> | |
| 67 | + | <td class="c-when nowrap dim"> | |
| 68 | + | if m.WhenAt != "" { | |
| 69 | + | <time datetime={ m.WhenAt } title={ m.WhenAt }>{ m.When }</time> | |
| 70 | + | } | |
| 71 | + | </td> | |
| 72 | + | </tr> | |
| 73 | + | } | |
| 74 | + | </tbody> | |
| 75 | + | </table> | |
| 76 | + | } | |
| 77 | + | } | |
| @@ -0,0 +1,77 @@ | |||||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |||
| 2 | + | ||||
| 3 | + | package web | |||
| 4 | + | ||||
| 5 | + | // Inbox is the owner's inbox: what is open across every repository. The | |||
| 6 | + | // counters, the filter and the lists are fragments with an id that the live | |||
| 7 | + | // stream replaces as a whole (ermiteLive.swap). | |||
| 8 | + | templ Inbox(l Layout, p InboxPage) { | |||
| 9 | + | @Shell(l, nil) { | |||
| 10 | + | <h1 class="sr">Inbox</h1> | |||
| 11 | + | <div class="inbox"> | |||
| 12 | + | @InboxCounters(p) | |||
| 13 | + | @InboxRepos(p) | |||
| 14 | + | @InboxMRs(p) | |||
| 15 | + | @InboxIssues(p) | |||
| 16 | + | </div> | |||
| 17 | + | } | |||
| 18 | + | } | |||
| 19 | + | ||||
| 20 | + | templ InboxCounters(p InboxPage) { | |||
| 21 | + | <p id="inbox-counts" class="inbox-counts"> | |||
| 22 | + | <strong>{ itoa(p.MergeRequests) }</strong> merge requests · <strong>{ itoa(p.Issues) }</strong> issues | |||
| 23 | + | </p> | |||
| 24 | + | } | |||
| 25 | + | ||||
| 26 | + | templ InboxRepos(p InboxPage) { | |||
| 27 | + | <nav id="inbox-repos" class="since" aria-label="Repository"> | |||
| 28 | + | for _, r := range p.Repos { | |||
| 29 | + | <a | |||
| 30 | + | href={ templ.SafeURL(r.Href) } | |||
| 31 | + | if r.Current { | |||
| 32 | + | aria-current="page" | |||
| 33 | + | } | |||
| 34 | + | >{ r.Label }</a> | |||
| 35 | + | } | |||
| 36 | + | </nav> | |||
| 37 | + | } | |||
| 38 | + | ||||
| 39 | + | templ InboxMRs(p InboxPage) { | |||
| 40 | + | <section id="inbox-mrs" aria-labelledby="inbox-mrs-h"> | |||
| 41 | + | <h2 id="inbox-mrs-h" class="rule-h"><span>Open merge requests</span><span class="count">{ itoa(len(p.MRs)) }</span></h2> | |||
| 42 | + | @inboxRows(p.MRs, "Open merge requests") | |||
| 43 | + | if len(p.MRs) == 0 { | |||
| 44 | + | <p class="lede dim">no open merge requests.</p> | |||
| 45 | + | } | |||
| 46 | + | </section> | |||
| 47 | + | } | |||
| 48 | + | ||||
| 49 | + | templ InboxIssues(p InboxPage) { | |||
| 50 | + | <section id="inbox-issues" aria-labelledby="inbox-issues-h"> | |||
| 51 | + | <h2 id="inbox-issues-h" class="rule-h"><span>Open issues</span><span class="count">{ itoa(len(p.IssueRows)) }</span></h2> | |||
| 52 | + | @inboxRows(p.IssueRows, "Open issues") | |||
| 53 | + | if len(p.IssueRows) == 0 { | |||
| 54 | + | <p class="lede dim">no open issues.</p> | |||
| 55 | + | } | |||
| 56 | + | </section> | |||
| 57 | + | } | |||
| 58 | + | ||||
| 59 | + | templ inboxRows(rows []InboxRow, label string) { | |||
| 60 | + | if len(rows) > 0 { | |||
| 61 | + | <table class="list mrs" aria-label={ label }> | |||
| 62 | + | <tbody data-rows> | |||
| 63 | + | for _, m := range rows { | |||
| 64 | + | <tr data-cursor?={ m.Cursor } data-state="open"> | |||
| 65 | + | <td class="c-n mute">{ m.Number }</td> | |||
| 66 | + | <td class="c-subject"><a href={ templ.SafeURL(m.Href) }>{ m.Title }</a> <a class="mute" href={ templ.SafeURL(m.RepoHref) }>{ m.Repo }</a></td> | |||
| 67 | + | <td class="c-when nowrap dim"> | |||
| 68 | + | if m.WhenAt != "" { | |||
| 69 | + | <time datetime={ m.WhenAt } title={ m.WhenAt }>{ m.When }</time> | |||
| 70 | + | } | |||
| 71 | + | </td> | |||
| 72 | + | </tr> | |||
| 73 | + | } | |||
| 74 | + | </tbody> | |||
| 75 | + | </table> | |||
| 76 | + | } | |||
| 77 | + | } | |||
A internal/adapters/web/inbox_templ.go +503 -0 generated file: collapsed
A internal/adapters/web/inbox_test.go +195 -0
| @@ -0,0 +1,195 @@ | |||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | + | ||
| 3 | + | package web | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "context" | |
| 7 | + | "io" | |
| 8 | + | "net/http" | |
| 9 | + | "net/http/httptest" | |
| 10 | + | "testing" | |
| 11 | + | "time" | |
| 12 | + | ||
| 13 | + | "github.com/stretchr/testify/assert" | |
| 14 | + | "github.com/stretchr/testify/mock" | |
| 15 | + | "github.com/stretchr/testify/require" | |
| 16 | + | ||
| 17 | + | "bnema.dev/ermite/internal/domain" | |
| 18 | + | "bnema.dev/ermite/internal/ports" | |
| 19 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 20 | + | ) | |
| 21 | + | ||
| 22 | + | func inboxOverview(t testing.TB) ports.InboxOverview { | |
| 23 | + | t.Helper() | |
| 24 | + | mrTitle, err := domain.ParseMRTitle("fix <b>search</b>") | |
| 25 | + | require.NoError(t, err) | |
| 26 | + | isTitle, err := domain.ParseIssueTitle("crash on start") | |
| 27 | + | require.NoError(t, err) | |
| 28 | + | at := time.Now().Add(-2 * time.Hour) | |
| 29 | + | ov := ports.InboxOverview{ | |
| 30 | + | MergeRequests: []ports.InboxMergeRequest{{MergeRequest: domain.MergeRequest{ | |
| 31 | + | Repo: repoName(t, "alpha"), Number: 4, Title: mrTitle, State: domain.MRStateOpen, UpdatedAt: at, | |
| 32 | + | }}}, | |
| 33 | + | Issues: []domain.Issue{{Repo: repoName(t, "beta"), Number: 7, Title: isTitle, State: domain.IssueStateOpen, UpdatedAt: at}}, | |
| 34 | + | Repos: []domain.RepoName{repoName(t, "alpha"), repoName(t, "beta")}, | |
| 35 | + | } | |
| 36 | + | ov.Counts = ports.InboxCounts{MergeRequests: 1, Issues: 1} | |
| 37 | + | return ov | |
| 38 | + | } | |
| 39 | + | ||
| 40 | + | func inboxServer(t *testing.T, inbox ports.InboxService) *Server { | |
| 41 | + | t.Helper() | |
| 42 | + | return newTestServer(t, Config{ | |
| 43 | + | Repos: reposServing(t, publicRepo(t, "alpha")), Browse: homeBrowse(t), Inbox: inbox, | |
| 44 | + | Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}, | |
| 45 | + | }) | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | func inboxGet(srv *Server, path string, owner bool) *httptest.ResponseRecorder { | |
| 49 | + | req := httptest.NewRequest(http.MethodGet, path, nil) | |
| 50 | + | if owner { | |
| 51 | + | req.AddCookie(&http.Cookie{Name: CookieName, Value: "tok"}) | |
| 52 | + | } | |
| 53 | + | rec := httptest.NewRecorder() | |
| 54 | + | srv.ServeHTTP(rec, req) | |
| 55 | + | return rec | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | func TestInboxPageForTheOwner(t *testing.T) { | |
| 59 | + | t.Parallel() | |
| 60 | + | svc := mocks.NewInboxService(t) | |
| 61 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, domain.RepoName{}).Return(inboxOverview(t), nil) | |
| 62 | + | srv := inboxServer(t, svc) | |
| 63 | + | ||
| 64 | + | rec := inboxGet(srv, "/-/inbox", true) | |
| 65 | + | require.Equal(t, 200, rec.Code, rec.Body.String()) | |
| 66 | + | body := rec.Body.String() | |
| 67 | + | assert.Contains(t, body, "<strong>1</strong> merge requests · <strong>1</strong> issues") | |
| 68 | + | assert.Contains(t, body, "Open merge requests") | |
| 69 | + | assert.Contains(t, body, "Open issues") | |
| 70 | + | assert.Contains(t, body, `href="/alpha/merge-requests/4"`) | |
| 71 | + | assert.Contains(t, body, "fix <b>search</b>") | |
| 72 | + | assert.Contains(t, body, `href="/beta/issues/7"`) | |
| 73 | + | assert.Contains(t, body, "#7") | |
| 74 | + | assert.Contains(t, body, "2h ago") | |
| 75 | + | assert.Contains(t, body, `href="/-/inbox?repo=beta"`, "the filter") | |
| 76 | + | assert.Equal(t, "private, no-store", rec.Header().Get("Cache-Control")) | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | func TestInboxPageIsMissingForEveryoneElse(t *testing.T) { | |
| 80 | + | t.Parallel() | |
| 81 | + | svc := mocks.NewInboxService(t) // never asked | |
| 82 | + | srv := inboxServer(t, svc) | |
| 83 | + | missing := inboxGet(srv, "/-/nothing-here", false) | |
| 84 | + | require.Equal(t, 404, missing.Code) | |
| 85 | + | ||
| 86 | + | anon := inboxGet(srv, "/-/inbox", false) | |
| 87 | + | assert.Equal(t, 404, anon.Code) | |
| 88 | + | assert.Equal(t, missing.Body.String(), anon.Body.String(), "the same page as an unknown one") | |
| 89 | + | assert.NotContains(t, anon.Body.String(), "Open merge requests") | |
| 90 | + | ||
| 91 | + | // A bad cookie is anonymous as well. | |
| 92 | + | req := httptest.NewRequest(http.MethodGet, "/-/inbox", nil) | |
| 93 | + | req.AddCookie(&http.Cookie{Name: CookieName, Value: "other"}) | |
| 94 | + | rec := httptest.NewRecorder() | |
| 95 | + | srv.ServeHTTP(rec, req) | |
| 96 | + | assert.Equal(t, 404, rec.Code) | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | func TestInboxNotMountedWithoutTheService(t *testing.T) { | |
| 100 | + | t.Parallel() | |
| 101 | + | srv := newTestServer(t, Config{Repos: reposServing(t, publicRepo(t, "alpha")), Browse: homeBrowse(t), Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}}) | |
| 102 | + | assert.Equal(t, 404, inboxGet(srv, "/-/inbox", true).Code) | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | func TestInboxFilterAndEmptyStates(t *testing.T) { | |
| 106 | + | t.Parallel() | |
| 107 | + | svc := mocks.NewInboxService(t) | |
| 108 | + | ov := inboxOverview(t) | |
| 109 | + | filtered := ov | |
| 110 | + | filtered.MergeRequests, filtered.Issues = nil, nil | |
| 111 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, repoName(t, "gamma")).Return(filtered, nil) | |
| 112 | + | srv := inboxServer(t, svc) | |
| 113 | + | ||
| 114 | + | rec := inboxGet(srv, "/-/inbox?repo=gamma", true) | |
| 115 | + | require.Equal(t, 200, rec.Code) | |
| 116 | + | body := rec.Body.String() | |
| 117 | + | assert.Contains(t, body, "no open merge requests.") | |
| 118 | + | assert.Contains(t, body, "no open issues.") | |
| 119 | + | assert.Contains(t, body, `href="/-/inbox"`, "the link back to all") | |
| 120 | + | ||
| 121 | + | assert.Equal(t, 404, inboxGet(srv, "/-/inbox?repo=Bad%20Name", true).Code, "an invalid name is a missing page") | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | func TestInboxButtonOnHomeIsForTheOwnerOnly(t *testing.T) { | |
| 125 | + | t.Parallel() | |
| 126 | + | svc := mocks.NewInboxService(t) | |
| 127 | + | ov := inboxOverview(t) | |
| 128 | + | ov.Counts = ports.InboxCounts{MergeRequests: 3, Issues: 2} | |
| 129 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, domain.RepoName{}).Return(ov, nil).Once() // the owner's home only | |
| 130 | + | srv := inboxServer(t, svc) | |
| 131 | + | ||
| 132 | + | anon := inboxGet(srv, "/", false) | |
| 133 | + | require.Equal(t, 200, anon.Code) | |
| 134 | + | assert.NotContains(t, anon.Body.String(), "/-/inbox") | |
| 135 | + | assert.NotContains(t, anon.Body.String(), "Inbox") | |
| 136 | + | ||
| 137 | + | owner := inboxGet(srv, "/", true) | |
| 138 | + | require.Equal(t, 200, owner.Code) | |
| 139 | + | assert.Contains(t, owner.Body.String(), `href="/-/inbox"`) | |
| 140 | + | assert.Contains(t, owner.Body.String(), `<span class="count">5</span>`) | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | func TestInboxStreamIsTheOwnersAlone(t *testing.T) { | |
| 144 | + | t.Parallel() | |
| 145 | + | f := &watchProbe{release: make(chan struct{})} | |
| 146 | + | svc := mocks.NewInboxService(t) | |
| 147 | + | srv := newTestServer(t, Config{ | |
| 148 | + | Repos: reposServing(t, publicRepo(t, "x")), Browse: mocks.NewBrowseService(t), Events: f.service(t), Inbox: svc, | |
| 149 | + | Heartbeat: time.Hour, Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}, | |
| 150 | + | }) | |
| 151 | + | ts := httptest.NewServer(srv) | |
| 152 | + | t.Cleanup(ts.Close) | |
| 153 | + | ||
| 154 | + | unknown, _ := open(t, ts, "topic=nope&view=inbox", nil) | |
| 155 | + | want, _ := io.ReadAll(unknown.Body) | |
| 156 | + | for name, hdr := range map[string]map[string]string{ | |
| 157 | + | "anonymous": nil, | |
| 158 | + | "another token": {"Cookie": CookieName + "=other"}, | |
| 159 | + | } { | |
| 160 | + | resp, _ := open(t, ts, "topic=owner&view=inbox", hdr) | |
| 161 | + | body, _ := io.ReadAll(resp.Body) | |
| 162 | + | assert.Equal(t, unknown.StatusCode, resp.StatusCode, name) | |
| 163 | + | assert.Equal(t, string(want), string(body), name) | |
| 164 | + | assert.Equal(t, unknown.Header.Get("Cache-Control"), resp.Header.Get("Cache-Control"), name) | |
| 165 | + | } | |
| 166 | + | assert.Zero(t, f.opened.Load(), "no watch is opened for them") | |
| 167 | + | ||
| 168 | + | resp, _ := open(t, ts, "topic=owner&view=inbox", map[string]string{"Cookie": CookieName + "=tok"}) | |
| 169 | + | assert.Equal(t, http.StatusOK, resp.StatusCode) | |
| 170 | + | assert.Equal(t, "text/event-stream", resp.Header.Get("Content-Type")) | |
| 171 | + | } | |
| 172 | + | ||
| 173 | + | func TestInboxLiveFragments(t *testing.T) { | |
| 174 | + | t.Parallel() | |
| 175 | + | svc := mocks.NewInboxService(t) | |
| 176 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, domain.RepoName{}).Return(inboxOverview(t), nil) | |
| 177 | + | srv := inboxServer(t, svc) | |
| 178 | + | ls := &liveStream{s: srv, view: "inbox"} | |
| 179 | + | frags, err := ls.render(withOwner(t.Context()), ports.WatchEvent{ID: "b-1", Event: domain.IssueOpened{Issue: domain.Issue{Repo: repoName(t, "beta"), Number: 7}}}) | |
| 180 | + | require.NoError(t, err) | |
| 181 | + | require.Len(t, frags, 4) | |
| 182 | + | assert.Contains(t, frags[0].html, `id="inbox-counts"`) | |
| 183 | + | assert.Contains(t, frags[1].html, `id="inbox-repos"`) | |
| 184 | + | assert.Contains(t, frags[2].html, `id="inbox-mrs"`) | |
| 185 | + | assert.Contains(t, frags[3].html, `id="inbox-issues"`) | |
| 186 | + | ||
| 187 | + | none, err := ls.render(withOwner(t.Context()), ports.WatchEvent{Event: domain.PushEvent{Repo: repoName(t, "beta")}}) | |
| 188 | + | require.NoError(t, err) | |
| 189 | + | assert.Empty(t, none, "a push is not inbox news") | |
| 190 | + | } | |
| 191 | + | ||
| 192 | + | // withOwner is a context as the session middleware leaves it for the owner. | |
| 193 | + | func withOwner(ctx context.Context) context.Context { | |
| 194 | + | return domain.ContextWithPrincipal(context.WithValue(ctx, signedInKey{}, struct{}{}), domain.Owner()) | |
| 195 | + | } | |
| @@ -0,0 +1,195 @@ | |||||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |||
| 2 | + | ||||
| 3 | + | package web | |||
| 4 | + | ||||
| 5 | + | import ( | |||
| 6 | + | "context" | |||
| 7 | + | "io" | |||
| 8 | + | "net/http" | |||
| 9 | + | "net/http/httptest" | |||
| 10 | + | "testing" | |||
| 11 | + | "time" | |||
| 12 | + | ||||
| 13 | + | "github.com/stretchr/testify/assert" | |||
| 14 | + | "github.com/stretchr/testify/mock" | |||
| 15 | + | "github.com/stretchr/testify/require" | |||
| 16 | + | ||||
| 17 | + | "bnema.dev/ermite/internal/domain" | |||
| 18 | + | "bnema.dev/ermite/internal/ports" | |||
| 19 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 20 | + | ) | |||
| 21 | + | ||||
| 22 | + | func inboxOverview(t testing.TB) ports.InboxOverview { | |||
| 23 | + | t.Helper() | |||
| 24 | + | mrTitle, err := domain.ParseMRTitle("fix <b>search</b>") | |||
| 25 | + | require.NoError(t, err) | |||
| 26 | + | isTitle, err := domain.ParseIssueTitle("crash on start") | |||
| 27 | + | require.NoError(t, err) | |||
| 28 | + | at := time.Now().Add(-2 * time.Hour) | |||
| 29 | + | ov := ports.InboxOverview{ | |||
| 30 | + | MergeRequests: []ports.InboxMergeRequest{{MergeRequest: domain.MergeRequest{ | |||
| 31 | + | Repo: repoName(t, "alpha"), Number: 4, Title: mrTitle, State: domain.MRStateOpen, UpdatedAt: at, | |||
| 32 | + | }}}, | |||
| 33 | + | Issues: []domain.Issue{{Repo: repoName(t, "beta"), Number: 7, Title: isTitle, State: domain.IssueStateOpen, UpdatedAt: at}}, | |||
| 34 | + | Repos: []domain.RepoName{repoName(t, "alpha"), repoName(t, "beta")}, | |||
| 35 | + | } | |||
| 36 | + | ov.Counts = ports.InboxCounts{MergeRequests: 1, Issues: 1} | |||
| 37 | + | return ov | |||
| 38 | + | } | |||
| 39 | + | ||||
| 40 | + | func inboxServer(t *testing.T, inbox ports.InboxService) *Server { | |||
| 41 | + | t.Helper() | |||
| 42 | + | return newTestServer(t, Config{ | |||
| 43 | + | Repos: reposServing(t, publicRepo(t, "alpha")), Browse: homeBrowse(t), Inbox: inbox, | |||
| 44 | + | Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}, | |||
| 45 | + | }) | |||
| 46 | + | } | |||
| 47 | + | ||||
| 48 | + | func inboxGet(srv *Server, path string, owner bool) *httptest.ResponseRecorder { | |||
| 49 | + | req := httptest.NewRequest(http.MethodGet, path, nil) | |||
| 50 | + | if owner { | |||
| 51 | + | req.AddCookie(&http.Cookie{Name: CookieName, Value: "tok"}) | |||
| 52 | + | } | |||
| 53 | + | rec := httptest.NewRecorder() | |||
| 54 | + | srv.ServeHTTP(rec, req) | |||
| 55 | + | return rec | |||
| 56 | + | } | |||
| 57 | + | ||||
| 58 | + | func TestInboxPageForTheOwner(t *testing.T) { | |||
| 59 | + | t.Parallel() | |||
| 60 | + | svc := mocks.NewInboxService(t) | |||
| 61 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, domain.RepoName{}).Return(inboxOverview(t), nil) | |||
| 62 | + | srv := inboxServer(t, svc) | |||
| 63 | + | ||||
| 64 | + | rec := inboxGet(srv, "/-/inbox", true) | |||
| 65 | + | require.Equal(t, 200, rec.Code, rec.Body.String()) | |||
| 66 | + | body := rec.Body.String() | |||
| 67 | + | assert.Contains(t, body, "<strong>1</strong> merge requests · <strong>1</strong> issues") | |||
| 68 | + | assert.Contains(t, body, "Open merge requests") | |||
| 69 | + | assert.Contains(t, body, "Open issues") | |||
| 70 | + | assert.Contains(t, body, `href="/alpha/merge-requests/4"`) | |||
| 71 | + | assert.Contains(t, body, "fix <b>search</b>") | |||
| 72 | + | assert.Contains(t, body, `href="/beta/issues/7"`) | |||
| 73 | + | assert.Contains(t, body, "#7") | |||
| 74 | + | assert.Contains(t, body, "2h ago") | |||
| 75 | + | assert.Contains(t, body, `href="/-/inbox?repo=beta"`, "the filter") | |||
| 76 | + | assert.Equal(t, "private, no-store", rec.Header().Get("Cache-Control")) | |||
| 77 | + | } | |||
| 78 | + | ||||
| 79 | + | func TestInboxPageIsMissingForEveryoneElse(t *testing.T) { | |||
| 80 | + | t.Parallel() | |||
| 81 | + | svc := mocks.NewInboxService(t) // never asked | |||
| 82 | + | srv := inboxServer(t, svc) | |||
| 83 | + | missing := inboxGet(srv, "/-/nothing-here", false) | |||
| 84 | + | require.Equal(t, 404, missing.Code) | |||
| 85 | + | ||||
| 86 | + | anon := inboxGet(srv, "/-/inbox", false) | |||
| 87 | + | assert.Equal(t, 404, anon.Code) | |||
| 88 | + | assert.Equal(t, missing.Body.String(), anon.Body.String(), "the same page as an unknown one") | |||
| 89 | + | assert.NotContains(t, anon.Body.String(), "Open merge requests") | |||
| 90 | + | ||||
| 91 | + | // A bad cookie is anonymous as well. | |||
| 92 | + | req := httptest.NewRequest(http.MethodGet, "/-/inbox", nil) | |||
| 93 | + | req.AddCookie(&http.Cookie{Name: CookieName, Value: "other"}) | |||
| 94 | + | rec := httptest.NewRecorder() | |||
| 95 | + | srv.ServeHTTP(rec, req) | |||
| 96 | + | assert.Equal(t, 404, rec.Code) | |||
| 97 | + | } | |||
| 98 | + | ||||
| 99 | + | func TestInboxNotMountedWithoutTheService(t *testing.T) { | |||
| 100 | + | t.Parallel() | |||
| 101 | + | srv := newTestServer(t, Config{Repos: reposServing(t, publicRepo(t, "alpha")), Browse: homeBrowse(t), Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}}) | |||
| 102 | + | assert.Equal(t, 404, inboxGet(srv, "/-/inbox", true).Code) | |||
| 103 | + | } | |||
| 104 | + | ||||
| 105 | + | func TestInboxFilterAndEmptyStates(t *testing.T) { | |||
| 106 | + | t.Parallel() | |||
| 107 | + | svc := mocks.NewInboxService(t) | |||
| 108 | + | ov := inboxOverview(t) | |||
| 109 | + | filtered := ov | |||
| 110 | + | filtered.MergeRequests, filtered.Issues = nil, nil | |||
| 111 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, repoName(t, "gamma")).Return(filtered, nil) | |||
| 112 | + | srv := inboxServer(t, svc) | |||
| 113 | + | ||||
| 114 | + | rec := inboxGet(srv, "/-/inbox?repo=gamma", true) | |||
| 115 | + | require.Equal(t, 200, rec.Code) | |||
| 116 | + | body := rec.Body.String() | |||
| 117 | + | assert.Contains(t, body, "no open merge requests.") | |||
| 118 | + | assert.Contains(t, body, "no open issues.") | |||
| 119 | + | assert.Contains(t, body, `href="/-/inbox"`, "the link back to all") | |||
| 120 | + | ||||
| 121 | + | assert.Equal(t, 404, inboxGet(srv, "/-/inbox?repo=Bad%20Name", true).Code, "an invalid name is a missing page") | |||
| 122 | + | } | |||
| 123 | + | ||||
| 124 | + | func TestInboxButtonOnHomeIsForTheOwnerOnly(t *testing.T) { | |||
| 125 | + | t.Parallel() | |||
| 126 | + | svc := mocks.NewInboxService(t) | |||
| 127 | + | ov := inboxOverview(t) | |||
| 128 | + | ov.Counts = ports.InboxCounts{MergeRequests: 3, Issues: 2} | |||
| 129 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, domain.RepoName{}).Return(ov, nil).Once() // the owner's home only | |||
| 130 | + | srv := inboxServer(t, svc) | |||
| 131 | + | ||||
| 132 | + | anon := inboxGet(srv, "/", false) | |||
| 133 | + | require.Equal(t, 200, anon.Code) | |||
| 134 | + | assert.NotContains(t, anon.Body.String(), "/-/inbox") | |||
| 135 | + | assert.NotContains(t, anon.Body.String(), "Inbox") | |||
| 136 | + | ||||
| 137 | + | owner := inboxGet(srv, "/", true) | |||
| 138 | + | require.Equal(t, 200, owner.Code) | |||
| 139 | + | assert.Contains(t, owner.Body.String(), `href="/-/inbox"`) | |||
| 140 | + | assert.Contains(t, owner.Body.String(), `<span class="count">5</span>`) | |||
| 141 | + | } | |||
| 142 | + | ||||
| 143 | + | func TestInboxStreamIsTheOwnersAlone(t *testing.T) { | |||
| 144 | + | t.Parallel() | |||
| 145 | + | f := &watchProbe{release: make(chan struct{})} | |||
| 146 | + | svc := mocks.NewInboxService(t) | |||
| 147 | + | srv := newTestServer(t, Config{ | |||
| 148 | + | Repos: reposServing(t, publicRepo(t, "x")), Browse: mocks.NewBrowseService(t), Events: f.service(t), Inbox: svc, | |||
| 149 | + | Heartbeat: time.Hour, Sessions: newSessions(t, "tok"), Limiter: &countingLimiter{}, | |||
| 150 | + | }) | |||
| 151 | + | ts := httptest.NewServer(srv) | |||
| 152 | + | t.Cleanup(ts.Close) | |||
| 153 | + | ||||
| 154 | + | unknown, _ := open(t, ts, "topic=nope&view=inbox", nil) | |||
| 155 | + | want, _ := io.ReadAll(unknown.Body) | |||
| 156 | + | for name, hdr := range map[string]map[string]string{ | |||
| 157 | + | "anonymous": nil, | |||
| 158 | + | "another token": {"Cookie": CookieName + "=other"}, | |||
| 159 | + | } { | |||
| 160 | + | resp, _ := open(t, ts, "topic=owner&view=inbox", hdr) | |||
| 161 | + | body, _ := io.ReadAll(resp.Body) | |||
| 162 | + | assert.Equal(t, unknown.StatusCode, resp.StatusCode, name) | |||
| 163 | + | assert.Equal(t, string(want), string(body), name) | |||
| 164 | + | assert.Equal(t, unknown.Header.Get("Cache-Control"), resp.Header.Get("Cache-Control"), name) | |||
| 165 | + | } | |||
| 166 | + | assert.Zero(t, f.opened.Load(), "no watch is opened for them") | |||
| 167 | + | ||||
| 168 | + | resp, _ := open(t, ts, "topic=owner&view=inbox", map[string]string{"Cookie": CookieName + "=tok"}) | |||
| 169 | + | assert.Equal(t, http.StatusOK, resp.StatusCode) | |||
| 170 | + | assert.Equal(t, "text/event-stream", resp.Header.Get("Content-Type")) | |||
| 171 | + | } | |||
| 172 | + | ||||
| 173 | + | func TestInboxLiveFragments(t *testing.T) { | |||
| 174 | + | t.Parallel() | |||
| 175 | + | svc := mocks.NewInboxService(t) | |||
| 176 | + | svc.EXPECT().Overview(mock.Anything, mock.Anything, domain.RepoName{}).Return(inboxOverview(t), nil) | |||
| 177 | + | srv := inboxServer(t, svc) | |||
| 178 | + | ls := &liveStream{s: srv, view: "inbox"} | |||
| 179 | + | frags, err := ls.render(withOwner(t.Context()), ports.WatchEvent{ID: "b-1", Event: domain.IssueOpened{Issue: domain.Issue{Repo: repoName(t, "beta"), Number: 7}}}) | |||
| 180 | + | require.NoError(t, err) | |||
| 181 | + | require.Len(t, frags, 4) | |||
| 182 | + | assert.Contains(t, frags[0].html, `id="inbox-counts"`) | |||
| 183 | + | assert.Contains(t, frags[1].html, `id="inbox-repos"`) | |||
| 184 | + | assert.Contains(t, frags[2].html, `id="inbox-mrs"`) | |||
| 185 | + | assert.Contains(t, frags[3].html, `id="inbox-issues"`) | |||
| 186 | + | ||||
| 187 | + | none, err := ls.render(withOwner(t.Context()), ports.WatchEvent{Event: domain.PushEvent{Repo: repoName(t, "beta")}}) | |||
| 188 | + | require.NoError(t, err) | |||
| 189 | + | assert.Empty(t, none, "a push is not inbox news") | |||
| 190 | + | } | |||
| 191 | + | ||||
| 192 | + | // withOwner is a context as the session middleware leaves it for the owner. | |||
| 193 | + | func withOwner(ctx context.Context) context.Context { | |||
| 194 | + | return domain.ContextWithPrincipal(context.WithValue(ctx, signedInKey{}, struct{}{}), domain.Owner()) | |||
| 195 | + | } | |||
M internal/adapters/web/pages.templ +8 -0
| @@ -9,6 +9,14 @@ templ Home(l Layout, p HomePage) { | |||
| 9 | 9 | <div class="home" data-layout="cards"> | |
| 10 | 10 | <section class="home-repos" aria-label="Repositories"> | |
| 11 | 11 | <div class="home-bar"> | |
| 12 | + | if p.Inbox != nil { | |
| 13 | + | <a class="btn inbox-btn" href={ templ.SafeURL(p.Inbox.Href) } title="inbox"> | |
| 14 | + | Inbox | |
| 15 | + | if p.Inbox.Count >= 0 { | |
| 16 | + | <span class="count">{ itoa(p.Inbox.Count) }</span> | |
| 17 | + | } | |
| 18 | + | </a> | |
| 19 | + | } | |
| 12 | 20 | <div class="filter"> | |
| 13 | 21 | <label for="home-filter" class="sr">filter</label> | |
| 14 | 22 | <input | |
| @@ -9,6 +9,14 @@ templ Home(l Layout, p HomePage) { | |||||
| 9 | <div class="home" data-layout="cards"> | 9 | <div class="home" data-layout="cards"> | ||
| 10 | <section class="home-repos" aria-label="Repositories"> | 10 | <section class="home-repos" aria-label="Repositories"> | ||
| 11 | <div class="home-bar"> | 11 | <div class="home-bar"> | ||
| 12 | + | if p.Inbox != nil { | |||
| 13 | + | <a class="btn inbox-btn" href={ templ.SafeURL(p.Inbox.Href) } title="inbox"> | |||
| 14 | + | Inbox | |||
| 15 | + | if p.Inbox.Count >= 0 { | |||
| 16 | + | <span class="count">{ itoa(p.Inbox.Count) }</span> | |||
| 17 | + | } | |||
| 18 | + | </a> | |||
| 19 | + | } | |||
| 12 | <div class="filter"> | 20 | <div class="filter"> | ||
| 13 | <label for="home-filter" class="sr">filter</label> | 21 | <label for="home-filter" class="sr">filter</label> | ||
| 14 | <input | 22 | <input | ||
M internal/adapters/web/pages_templ.go +409 -363
| @@ -44,89 +44,135 @@ func Home(l Layout, p HomePage) templ.Component { | |||
| 44 | 44 | }() | |
| 45 | 45 | } | |
| 46 | 46 | ctx = templ.InitializeContext(ctx) | |
| 47 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<h1 class=\"sr\">Repositories</h1><div class=\"home\" data-layout=\"cards\"><section class=\"home-repos\" aria-label=\"Repositories\"><div class=\"home-bar\"><div class=\"filter\"><label for=\"home-filter\" class=\"sr\">filter</label> <input id=\"home-filter\" type=\"search\" data-filter=\"#repo-rows > li\" placeholder=\"Filter repositories…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><nav class=\"sort\" aria-label=\"Sort repositories\"><span class=\"mute\">sort</span> ") | |
| 47 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<h1 class=\"sr\">Repositories</h1><div class=\"home\" data-layout=\"cards\"><section class=\"home-repos\" aria-label=\"Repositories\"><div class=\"home-bar\">") | |
| 48 | 48 | if templ_7745c5c3_Err != nil { | |
| 49 | 49 | return templ_7745c5c3_Err | |
| 50 | 50 | } | |
| 51 | - | for _, s := range p.Sorts { | |
| 52 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<a href=\"") | |
| 51 | + | if p.Inbox != nil { | |
| 52 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<a class=\"btn inbox-btn\" href=\"") | |
| 53 | 53 | if templ_7745c5c3_Err != nil { | |
| 54 | 54 | return templ_7745c5c3_Err | |
| 55 | 55 | } | |
| 56 | 56 | var templ_7745c5c3_Var3 templ.SafeURL | |
| 57 | - | templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href)) | |
| 57 | + | templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Inbox.Href)) | |
| 58 | 58 | if templ_7745c5c3_Err != nil { | |
| 59 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 27, Col: 36} | |
| 59 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 13, Col: 65} | |
| 60 | 60 | } | |
| 61 | 61 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | |
| 62 | 62 | if templ_7745c5c3_Err != nil { | |
| 63 | 63 | return templ_7745c5c3_Err | |
| 64 | 64 | } | |
| 65 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"") | |
| 65 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" title=\"inbox\">Inbox ") | |
| 66 | + | if templ_7745c5c3_Err != nil { | |
| 67 | + | return templ_7745c5c3_Err | |
| 68 | + | } | |
| 69 | + | if p.Inbox.Count >= 0 { | |
| 70 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<span class=\"count\">") | |
| 71 | + | if templ_7745c5c3_Err != nil { | |
| 72 | + | return templ_7745c5c3_Err | |
| 73 | + | } | |
| 74 | + | var templ_7745c5c3_Var4 string | |
| 75 | + | templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Inbox.Count)) | |
| 76 | + | if templ_7745c5c3_Err != nil { | |
| 77 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 16, Col: 49} | |
| 78 | + | } | |
| 79 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) | |
| 80 | + | if templ_7745c5c3_Err != nil { | |
| 81 | + | return templ_7745c5c3_Err | |
| 82 | + | } | |
| 83 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</span>") | |
| 84 | + | if templ_7745c5c3_Err != nil { | |
| 85 | + | return templ_7745c5c3_Err | |
| 86 | + | } | |
| 87 | + | } | |
| 88 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a>") | |
| 89 | + | if templ_7745c5c3_Err != nil { | |
| 90 | + | return templ_7745c5c3_Err | |
| 91 | + | } | |
| 92 | + | } | |
| 93 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"filter\"><label for=\"home-filter\" class=\"sr\">filter</label> <input id=\"home-filter\" type=\"search\" data-filter=\"#repo-rows > li\" placeholder=\"Filter repositories…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><nav class=\"sort\" aria-label=\"Sort repositories\"><span class=\"mute\">sort</span> ") | |
| 94 | + | if templ_7745c5c3_Err != nil { | |
| 95 | + | return templ_7745c5c3_Err | |
| 96 | + | } | |
| 97 | + | for _, s := range p.Sorts { | |
| 98 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<a href=\"") | |
| 99 | + | if templ_7745c5c3_Err != nil { | |
| 100 | + | return templ_7745c5c3_Err | |
| 101 | + | } | |
| 102 | + | var templ_7745c5c3_Var5 templ.SafeURL | |
| 103 | + | templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href)) | |
| 104 | + | if templ_7745c5c3_Err != nil { | |
| 105 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 35, Col: 36} | |
| 106 | + | } | |
| 107 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) | |
| 108 | + | if templ_7745c5c3_Err != nil { | |
| 109 | + | return templ_7745c5c3_Err | |
| 110 | + | } | |
| 111 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\"") | |
| 66 | 112 | if templ_7745c5c3_Err != nil { | |
| 67 | 113 | return templ_7745c5c3_Err | |
| 68 | 114 | } | |
| 69 | 115 | if s.Mark != "" { | |
| 70 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " aria-current=\"true\"") | |
| 116 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " aria-current=\"true\"") | |
| 71 | 117 | if templ_7745c5c3_Err != nil { | |
| 72 | 118 | return templ_7745c5c3_Err | |
| 73 | 119 | } | |
| 74 | 120 | } | |
| 75 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, ">") | |
| 121 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, ">") | |
| 76 | 122 | if templ_7745c5c3_Err != nil { | |
| 77 | 123 | return templ_7745c5c3_Err | |
| 78 | 124 | } | |
| 79 | - | var templ_7745c5c3_Var4 string | |
| 80 | - | templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label) | |
| 125 | + | var templ_7745c5c3_Var6 string | |
| 126 | + | templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label) | |
| 81 | 127 | if templ_7745c5c3_Err != nil { | |
| 82 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 32, Col: 17} | |
| 128 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 40, Col: 17} | |
| 83 | 129 | } | |
| 84 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) | |
| 130 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) | |
| 85 | 131 | if templ_7745c5c3_Err != nil { | |
| 86 | 132 | return templ_7745c5c3_Err | |
| 87 | 133 | } | |
| 88 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") | |
| 134 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " ") | |
| 89 | 135 | if templ_7745c5c3_Err != nil { | |
| 90 | 136 | return templ_7745c5c3_Err | |
| 91 | 137 | } | |
| 92 | 138 | if s.Mark != "" { | |
| 93 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<span aria-hidden=\"true\">") | |
| 139 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<span aria-hidden=\"true\">") | |
| 94 | 140 | if templ_7745c5c3_Err != nil { | |
| 95 | 141 | return templ_7745c5c3_Err | |
| 96 | 142 | } | |
| 97 | - | var templ_7745c5c3_Var5 string | |
| 98 | - | templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(s.Mark) | |
| 143 | + | var templ_7745c5c3_Var7 string | |
| 144 | + | templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(s.Mark) | |
| 99 | 145 | if templ_7745c5c3_Err != nil { | |
| 100 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 34, Col: 42} | |
| 146 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 42, Col: 42} | |
| 101 | 147 | } | |
| 102 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) | |
| 148 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) | |
| 103 | 149 | if templ_7745c5c3_Err != nil { | |
| 104 | 150 | return templ_7745c5c3_Err | |
| 105 | 151 | } | |
| 106 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</span> <span class=\"sr\">") | |
| 152 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</span> <span class=\"sr\">") | |
| 107 | 153 | if templ_7745c5c3_Err != nil { | |
| 108 | 154 | return templ_7745c5c3_Err | |
| 109 | 155 | } | |
| 110 | - | var templ_7745c5c3_Var6 string | |
| 111 | - | templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(", " + s.State) | |
| 156 | + | var templ_7745c5c3_Var8 string | |
| 157 | + | templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(", " + s.State) | |
| 112 | 158 | if templ_7745c5c3_Err != nil { | |
| 113 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 35, Col: 42} | |
| 159 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 43, Col: 42} | |
| 114 | 160 | } | |
| 115 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) | |
| 161 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) | |
| 116 | 162 | if templ_7745c5c3_Err != nil { | |
| 117 | 163 | return templ_7745c5c3_Err | |
| 118 | 164 | } | |
| 119 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</span>") | |
| 165 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</span>") | |
| 120 | 166 | if templ_7745c5c3_Err != nil { | |
| 121 | 167 | return templ_7745c5c3_Err | |
| 122 | 168 | } | |
| 123 | 169 | } | |
| 124 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</a>") | |
| 170 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</a>") | |
| 125 | 171 | if templ_7745c5c3_Err != nil { | |
| 126 | 172 | return templ_7745c5c3_Err | |
| 127 | 173 | } | |
| 128 | 174 | } | |
| 129 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</nav><div class=\"layout-switch\" role=\"group\" aria-label=\"Layout\" data-js><button type=\"button\" class=\"btn icon\" data-set-layout=\"cards\" aria-pressed=\"true\" title=\"Cards\" aria-label=\"Cards\"><span class=\"ico i-cards\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"split\" aria-pressed=\"false\" title=\"Two columns\" aria-label=\"Two columns\"><span class=\"ico i-split\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"compact\" aria-pressed=\"false\" title=\"Compact list\" aria-label=\"Compact list\"><span class=\"ico i-compact\" aria-hidden=\"true\"></span></button></div></div><ul class=\"repos\" id=\"repo-rows\" data-rows>") | |
| 175 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</nav><div class=\"layout-switch\" role=\"group\" aria-label=\"Layout\" data-js><button type=\"button\" class=\"btn icon\" data-set-layout=\"cards\" aria-pressed=\"true\" title=\"Cards\" aria-label=\"Cards\"><span class=\"ico i-cards\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"split\" aria-pressed=\"false\" title=\"Two columns\" aria-label=\"Two columns\"><span class=\"ico i-split\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"compact\" aria-pressed=\"false\" title=\"Compact list\" aria-label=\"Compact list\"><span class=\"ico i-compact\" aria-hidden=\"true\"></span></button></div></div><ul class=\"repos\" id=\"repo-rows\" data-rows>") | |
| 130 | 176 | if templ_7745c5c3_Err != nil { | |
| 131 | 177 | return templ_7745c5c3_Err | |
| 132 | 178 | } | |
| @@ -136,17 +182,17 @@ func Home(l Layout, p HomePage) templ.Component { | |||
| 136 | 182 | return templ_7745c5c3_Err | |
| 137 | 183 | } | |
| 138 | 184 | } | |
| 139 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</ul>") | |
| 185 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</ul>") | |
| 140 | 186 | if templ_7745c5c3_Err != nil { | |
| 141 | 187 | return templ_7745c5c3_Err | |
| 142 | 188 | } | |
| 143 | 189 | if len(p.Rows) == 0 { | |
| 144 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<p class=\"lede dim\">no repositories yet.</p>") | |
| 190 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<p class=\"lede dim\">no repositories yet.</p>") | |
| 145 | 191 | if templ_7745c5c3_Err != nil { | |
| 146 | 192 | return templ_7745c5c3_Err | |
| 147 | 193 | } | |
| 148 | 194 | } | |
| 149 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</section></div>") | |
| 195 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</section></div>") | |
| 150 | 196 | if templ_7745c5c3_Err != nil { | |
| 151 | 197 | return templ_7745c5c3_Err | |
| 152 | 198 | } | |
| @@ -178,12 +224,12 @@ func Summary(l Layout, p SummaryPage) templ.Component { | |||
| 178 | 224 | }() | |
| 179 | 225 | } | |
| 180 | 226 | ctx = templ.InitializeContext(ctx) | |
| 181 | - | templ_7745c5c3_Var7 := templ.GetChildren(ctx) | |
| 182 | - | if templ_7745c5c3_Var7 == nil { | |
| 183 | - | templ_7745c5c3_Var7 = templ.NopComponent | |
| 227 | + | templ_7745c5c3_Var9 := templ.GetChildren(ctx) | |
| 228 | + | if templ_7745c5c3_Var9 == nil { | |
| 229 | + | templ_7745c5c3_Var9 = templ.NopComponent | |
| 184 | 230 | } | |
| 185 | 231 | ctx = templ.ClearChildren(ctx) | |
| 186 | - | templ_7745c5c3_Var8 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 232 | + | templ_7745c5c3_Var10 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 187 | 233 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | |
| 188 | 234 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | |
| 189 | 235 | if !templ_7745c5c3_IsBuffer { | |
| @@ -203,7 +249,7 @@ func Summary(l Layout, p SummaryPage) templ.Component { | |||
| 203 | 249 | } | |
| 204 | 250 | return nil | |
| 205 | 251 | }) | |
| 206 | - | templ_7745c5c3_Err = Shell(l, summaryRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var8), templ_7745c5c3_Buffer) | |
| 252 | + | templ_7745c5c3_Err = Shell(l, summaryRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var10), templ_7745c5c3_Buffer) | |
| 207 | 253 | if templ_7745c5c3_Err != nil { | |
| 208 | 254 | return templ_7745c5c3_Err | |
| 209 | 255 | } | |
| @@ -230,158 +276,158 @@ func latestTagFact(t LatestTag) templ.Component { | |||
| 230 | 276 | }() | |
| 231 | 277 | } | |
| 232 | 278 | ctx = templ.InitializeContext(ctx) | |
| 233 | - | templ_7745c5c3_Var9 := templ.GetChildren(ctx) | |
| 234 | - | if templ_7745c5c3_Var9 == nil { | |
| 235 | - | templ_7745c5c3_Var9 = templ.NopComponent | |
| 279 | + | templ_7745c5c3_Var11 := templ.GetChildren(ctx) | |
| 280 | + | if templ_7745c5c3_Var11 == nil { | |
| 281 | + | templ_7745c5c3_Var11 = templ.NopComponent | |
| 236 | 282 | } | |
| 237 | 283 | ctx = templ.ClearChildren(ctx) | |
| 238 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<dt>latest tag</dt><dd class=\"latest-tag\">") | |
| 284 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<dt>latest tag</dt><dd class=\"latest-tag\">") | |
| 239 | 285 | if templ_7745c5c3_Err != nil { | |
| 240 | 286 | return templ_7745c5c3_Err | |
| 241 | 287 | } | |
| 242 | 288 | if t.Name != "" { | |
| 243 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<a class=\"tag-name\" href=\"") | |
| 289 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<a class=\"tag-name\" href=\"") | |
| 244 | 290 | if templ_7745c5c3_Err != nil { | |
| 245 | 291 | return templ_7745c5c3_Err | |
| 246 | 292 | } | |
| 247 | - | var templ_7745c5c3_Var10 templ.SafeURL | |
| 248 | - | templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.Href)) | |
| 293 | + | var templ_7745c5c3_Var12 templ.SafeURL | |
| 294 | + | templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.Href)) | |
| 249 | 295 | if templ_7745c5c3_Err != nil { | |
| 250 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 82, Col: 51} | |
| 296 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 90, Col: 51} | |
| 251 | 297 | } | |
| 252 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) | |
| 298 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) | |
| 253 | 299 | if templ_7745c5c3_Err != nil { | |
| 254 | 300 | return templ_7745c5c3_Err | |
| 255 | 301 | } | |
| 256 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" title=\"") | |
| 302 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" title=\"") | |
| 257 | 303 | if templ_7745c5c3_Err != nil { | |
| 258 | 304 | return templ_7745c5c3_Err | |
| 259 | 305 | } | |
| 260 | - | var templ_7745c5c3_Var11 string | |
| 261 | - | templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.Subject) | |
| 306 | + | var templ_7745c5c3_Var13 string | |
| 307 | + | templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.Subject) | |
| 262 | 308 | if templ_7745c5c3_Err != nil { | |
| 263 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 82, Col: 71} | |
| 309 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 90, Col: 71} | |
| 264 | 310 | } | |
| 265 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11) | |
| 311 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var13) | |
| 266 | 312 | if templ_7745c5c3_Err != nil { | |
| 267 | 313 | return templ_7745c5c3_Err | |
| 268 | 314 | } | |
| 269 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">") | |
| 315 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\">") | |
| 270 | 316 | if templ_7745c5c3_Err != nil { | |
| 271 | 317 | return templ_7745c5c3_Err | |
| 272 | 318 | } | |
| 273 | - | var templ_7745c5c3_Var12 string | |
| 274 | - | templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(t.Name) | |
| 319 | + | var templ_7745c5c3_Var14 string | |
| 320 | + | templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(t.Name) | |
| 275 | 321 | if templ_7745c5c3_Err != nil { | |
| 276 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 82, Col: 82} | |
| 322 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 90, Col: 82} | |
| 277 | 323 | } | |
| 278 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) | |
| 324 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) | |
| 279 | 325 | if templ_7745c5c3_Err != nil { | |
| 280 | 326 | return templ_7745c5c3_Err | |
| 281 | 327 | } | |
| 282 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</a> ") | |
| 328 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</a> ") | |
| 283 | 329 | if templ_7745c5c3_Err != nil { | |
| 284 | 330 | return templ_7745c5c3_Err | |
| 285 | 331 | } | |
| 286 | 332 | if t.WhenAt != "" { | |
| 287 | - | var templ_7745c5c3_Var13 string | |
| 288 | - | templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") | |
| 333 | + | var templ_7745c5c3_Var15 string | |
| 334 | + | templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") | |
| 289 | 335 | if templ_7745c5c3_Err != nil { | |
| 290 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 12} | |
| 336 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 12} | |
| 291 | 337 | } | |
| 292 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) | |
| 338 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) | |
| 293 | 339 | if templ_7745c5c3_Err != nil { | |
| 294 | 340 | return templ_7745c5c3_Err | |
| 295 | 341 | } | |
| 296 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<time datetime=\"") | |
| 342 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<time datetime=\"") | |
| 297 | 343 | if templ_7745c5c3_Err != nil { | |
| 298 | 344 | return templ_7745c5c3_Err | |
| 299 | 345 | } | |
| 300 | - | var templ_7745c5c3_Var14 string | |
| 301 | - | templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) | |
| 346 | + | var templ_7745c5c3_Var16 string | |
| 347 | + | templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) | |
| 302 | 348 | if templ_7745c5c3_Err != nil { | |
| 303 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 39} | |
| 349 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 39} | |
| 304 | 350 | } | |
| 305 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var14) | |
| 351 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var16) | |
| 306 | 352 | if templ_7745c5c3_Err != nil { | |
| 307 | 353 | return templ_7745c5c3_Err | |
| 308 | 354 | } | |
| 309 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\" title=\"") | |
| 355 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" title=\"") | |
| 310 | 356 | if templ_7745c5c3_Err != nil { | |
| 311 | 357 | return templ_7745c5c3_Err | |
| 312 | 358 | } | |
| 313 | - | var templ_7745c5c3_Var15 string | |
| 314 | - | templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) | |
| 359 | + | var templ_7745c5c3_Var17 string | |
| 360 | + | templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) | |
| 315 | 361 | if templ_7745c5c3_Err != nil { | |
| 316 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 58} | |
| 362 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 58} | |
| 317 | 363 | } | |
| 318 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15) | |
| 364 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17) | |
| 319 | 365 | if templ_7745c5c3_Err != nil { | |
| 320 | 366 | return templ_7745c5c3_Err | |
| 321 | 367 | } | |
| 322 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">") | |
| 368 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\">") | |
| 323 | 369 | if templ_7745c5c3_Err != nil { | |
| 324 | 370 | return templ_7745c5c3_Err | |
| 325 | 371 | } | |
| 326 | - | var templ_7745c5c3_Var16 string | |
| 327 | - | templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(t.When) | |
| 372 | + | var templ_7745c5c3_Var18 string | |
| 373 | + | templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(t.When) | |
| 328 | 374 | if templ_7745c5c3_Err != nil { | |
| 329 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 69} | |
| 375 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 69} | |
| 330 | 376 | } | |
| 331 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) | |
| 377 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) | |
| 332 | 378 | if templ_7745c5c3_Err != nil { | |
| 333 | 379 | return templ_7745c5c3_Err | |
| 334 | 380 | } | |
| 335 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</time>") | |
| 381 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</time>") | |
| 336 | 382 | if templ_7745c5c3_Err != nil { | |
| 337 | 383 | return templ_7745c5c3_Err | |
| 338 | 384 | } | |
| 339 | 385 | } | |
| 340 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, " ") | |
| 386 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " ") | |
| 341 | 387 | if templ_7745c5c3_Err != nil { | |
| 342 | 388 | return templ_7745c5c3_Err | |
| 343 | 389 | } | |
| 344 | - | var templ_7745c5c3_Var17 string | |
| 345 | - | templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") | |
| 390 | + | var templ_7745c5c3_Var19 string | |
| 391 | + | templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") | |
| 346 | 392 | if templ_7745c5c3_Err != nil { | |
| 347 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 86, Col: 11} | |
| 393 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 94, Col: 11} | |
| 348 | 394 | } | |
| 349 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) | |
| 395 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) | |
| 350 | 396 | if templ_7745c5c3_Err != nil { | |
| 351 | 397 | return templ_7745c5c3_Err | |
| 352 | 398 | } | |
| 353 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " ") | |
| 399 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, " ") | |
| 354 | 400 | if templ_7745c5c3_Err != nil { | |
| 355 | 401 | return templ_7745c5c3_Err | |
| 356 | 402 | } | |
| 357 | 403 | } | |
| 358 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a class=\"all-tags\" href=\"") | |
| 404 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<a class=\"all-tags\" href=\"") | |
| 359 | 405 | if templ_7745c5c3_Err != nil { | |
| 360 | 406 | return templ_7745c5c3_Err | |
| 361 | 407 | } | |
| 362 | - | var templ_7745c5c3_Var18 templ.SafeURL | |
| 363 | - | templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.RefsHref)) | |
| 408 | + | var templ_7745c5c3_Var20 templ.SafeURL | |
| 409 | + | templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.RefsHref)) | |
| 364 | 410 | if templ_7745c5c3_Err != nil { | |
| 365 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 88, Col: 54} | |
| 411 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 96, Col: 54} | |
| 366 | 412 | } | |
| 367 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) | |
| 413 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) | |
| 368 | 414 | if templ_7745c5c3_Err != nil { | |
| 369 | 415 | return templ_7745c5c3_Err | |
| 370 | 416 | } | |
| 371 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">") | |
| 417 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "\">") | |
| 372 | 418 | if templ_7745c5c3_Err != nil { | |
| 373 | 419 | return templ_7745c5c3_Err | |
| 374 | 420 | } | |
| 375 | - | var templ_7745c5c3_Var19 string | |
| 376 | - | templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(plural(t.Count, "tag", "tags")) | |
| 421 | + | var templ_7745c5c3_Var21 string | |
| 422 | + | templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(plural(t.Count, "tag", "tags")) | |
| 377 | 423 | if templ_7745c5c3_Err != nil { | |
| 378 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 88, Col: 89} | |
| 424 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 96, Col: 89} | |
| 379 | 425 | } | |
| 380 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) | |
| 426 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) | |
| 381 | 427 | if templ_7745c5c3_Err != nil { | |
| 382 | 428 | return templ_7745c5c3_Err | |
| 383 | 429 | } | |
| 384 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a></dd>") | |
| 430 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</a></dd>") | |
| 385 | 431 | if templ_7745c5c3_Err != nil { | |
| 386 | 432 | return templ_7745c5c3_Err | |
| 387 | 433 | } | |
| @@ -405,12 +451,12 @@ func summaryRail(p SummaryPage) templ.Component { | |||
| 405 | 451 | }() | |
| 406 | 452 | } | |
| 407 | 453 | ctx = templ.InitializeContext(ctx) | |
| 408 | - | templ_7745c5c3_Var20 := templ.GetChildren(ctx) | |
| 409 | - | if templ_7745c5c3_Var20 == nil { | |
| 410 | - | templ_7745c5c3_Var20 = templ.NopComponent | |
| 454 | + | templ_7745c5c3_Var22 := templ.GetChildren(ctx) | |
| 455 | + | if templ_7745c5c3_Var22 == nil { | |
| 456 | + | templ_7745c5c3_Var22 = templ.NopComponent | |
| 411 | 457 | } | |
| 412 | 458 | ctx = templ.ClearChildren(ctx) | |
| 413 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<section aria-labelledby=\"r-clone\"><h2 id=\"r-clone\">Clone</h2>") | |
| 459 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<section aria-labelledby=\"r-clone\"><h2 id=\"r-clone\">Clone</h2>") | |
| 414 | 460 | if templ_7745c5c3_Err != nil { | |
| 415 | 461 | return templ_7745c5c3_Err | |
| 416 | 462 | } | |
| @@ -418,25 +464,25 @@ func summaryRail(p SummaryPage) templ.Component { | |||
| 418 | 464 | if templ_7745c5c3_Err != nil { | |
| 419 | 465 | return templ_7745c5c3_Err | |
| 420 | 466 | } | |
| 421 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</section><section aria-labelledby=\"r-facts\"><h2 id=\"r-facts\">About</h2><dl class=\"kv\">") | |
| 467 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</section><section aria-labelledby=\"r-facts\"><h2 id=\"r-facts\">About</h2><dl class=\"kv\">") | |
| 422 | 468 | if templ_7745c5c3_Err != nil { | |
| 423 | 469 | return templ_7745c5c3_Err | |
| 424 | 470 | } | |
| 425 | 471 | for _, f := range p.Facts { | |
| 426 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<dt>") | |
| 472 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<dt>") | |
| 427 | 473 | if templ_7745c5c3_Err != nil { | |
| 428 | 474 | return templ_7745c5c3_Err | |
| 429 | 475 | } | |
| 430 | - | var templ_7745c5c3_Var21 string | |
| 431 | - | templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(f.Key) | |
| 476 | + | var templ_7745c5c3_Var23 string | |
| 477 | + | templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(f.Key) | |
| 432 | 478 | if templ_7745c5c3_Err != nil { | |
| 433 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 99, Col: 15} | |
| 479 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 107, Col: 15} | |
| 434 | 480 | } | |
| 435 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) | |
| 481 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) | |
| 436 | 482 | if templ_7745c5c3_Err != nil { | |
| 437 | 483 | return templ_7745c5c3_Err | |
| 438 | 484 | } | |
| 439 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</dt>") | |
| 485 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</dt>") | |
| 440 | 486 | if templ_7745c5c3_Err != nil { | |
| 441 | 487 | return templ_7745c5c3_Err | |
| 442 | 488 | } | |
| @@ -451,25 +497,25 @@ func summaryRail(p SummaryPage) templ.Component { | |||
| 451 | 497 | return templ_7745c5c3_Err | |
| 452 | 498 | } | |
| 453 | 499 | } | |
| 454 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</dl></section>") | |
| 500 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</dl></section>") | |
| 455 | 501 | if templ_7745c5c3_Err != nil { | |
| 456 | 502 | return templ_7745c5c3_Err | |
| 457 | 503 | } | |
| 458 | 504 | if len(p.Recent) > 0 { | |
| 459 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<section aria-labelledby=\"r-recent\"><h2 id=\"r-recent\">Recent commits <a href=\"") | |
| 505 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "<section aria-labelledby=\"r-recent\"><h2 id=\"r-recent\">Recent commits <a href=\"") | |
| 460 | 506 | if templ_7745c5c3_Err != nil { | |
| 461 | 507 | return templ_7745c5c3_Err | |
| 462 | 508 | } | |
| 463 | - | var templ_7745c5c3_Var22 templ.SafeURL | |
| 464 | - | templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.AllHref)) | |
| 509 | + | var templ_7745c5c3_Var24 templ.SafeURL | |
| 510 | + | templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.AllHref)) | |
| 465 | 511 | if templ_7745c5c3_Err != nil { | |
| 466 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 108, Col: 105} | |
| 512 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 116, Col: 105} | |
| 467 | 513 | } | |
| 468 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) | |
| 514 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) | |
| 469 | 515 | if templ_7745c5c3_Err != nil { | |
| 470 | 516 | return templ_7745c5c3_Err | |
| 471 | 517 | } | |
| 472 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "\">View all</a></h2>") | |
| 518 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\">View all</a></h2>") | |
| 473 | 519 | if templ_7745c5c3_Err != nil { | |
| 474 | 520 | return templ_7745c5c3_Err | |
| 475 | 521 | } | |
| @@ -477,7 +523,7 @@ func summaryRail(p SummaryPage) templ.Component { | |||
| 477 | 523 | if templ_7745c5c3_Err != nil { | |
| 478 | 524 | return templ_7745c5c3_Err | |
| 479 | 525 | } | |
| 480 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</section>") | |
| 526 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "</section>") | |
| 481 | 527 | if templ_7745c5c3_Err != nil { | |
| 482 | 528 | return templ_7745c5c3_Err | |
| 483 | 529 | } | |
| @@ -489,7 +535,7 @@ func summaryRail(p SummaryPage) templ.Component { | |||
| 489 | 535 | } | |
| 490 | 536 | } | |
| 491 | 537 | if len(p.Outline) > 0 && p.Readme != nil { | |
| 492 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<section aria-labelledby=\"r-outline\"><h2 id=\"r-outline\">On this page</h2>") | |
| 538 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "<section aria-labelledby=\"r-outline\"><h2 id=\"r-outline\">On this page</h2>") | |
| 493 | 539 | if templ_7745c5c3_Err != nil { | |
| 494 | 540 | return templ_7745c5c3_Err | |
| 495 | 541 | } | |
| @@ -497,7 +543,7 @@ func summaryRail(p SummaryPage) templ.Component { | |||
| 497 | 543 | if templ_7745c5c3_Err != nil { | |
| 498 | 544 | return templ_7745c5c3_Err | |
| 499 | 545 | } | |
| 500 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</section>") | |
| 546 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</section>") | |
| 501 | 547 | if templ_7745c5c3_Err != nil { | |
| 502 | 548 | return templ_7745c5c3_Err | |
| 503 | 549 | } | |
| @@ -523,12 +569,12 @@ func Refs(l Layout, p RefsPage) templ.Component { | |||
| 523 | 569 | }() | |
| 524 | 570 | } | |
| 525 | 571 | ctx = templ.InitializeContext(ctx) | |
| 526 | - | templ_7745c5c3_Var23 := templ.GetChildren(ctx) | |
| 527 | - | if templ_7745c5c3_Var23 == nil { | |
| 528 | - | templ_7745c5c3_Var23 = templ.NopComponent | |
| 572 | + | templ_7745c5c3_Var25 := templ.GetChildren(ctx) | |
| 573 | + | if templ_7745c5c3_Var25 == nil { | |
| 574 | + | templ_7745c5c3_Var25 = templ.NopComponent | |
| 529 | 575 | } | |
| 530 | 576 | ctx = templ.ClearChildren(ctx) | |
| 531 | - | templ_7745c5c3_Var24 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 577 | + | templ_7745c5c3_Var26 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 532 | 578 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | |
| 533 | 579 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | |
| 534 | 580 | if !templ_7745c5c3_IsBuffer { | |
| @@ -540,7 +586,7 @@ func Refs(l Layout, p RefsPage) templ.Component { | |||
| 540 | 586 | }() | |
| 541 | 587 | } | |
| 542 | 588 | ctx = templ.InitializeContext(ctx) | |
| 543 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<div class=\"filter\"><label for=\"ref-filter\" class=\"sr\">filter</label> <input id=\"ref-filter\" type=\"search\" data-filter=\"#ref-rows > tr\" placeholder=\"Filter branches and tags…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><table class=\"list refs\" aria-label=\"Branches and tags\"><thead><tr><th class=\"c-kind\">kind</th><th class=\"c-name\">name</th><th class=\"c-sha\">commit</th><th class=\"c-sub\">subject</th><th class=\"c-when\">date</th></tr></thead>") | |
| 589 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<div class=\"filter\"><label for=\"ref-filter\" class=\"sr\">filter</label> <input id=\"ref-filter\" type=\"search\" data-filter=\"#ref-rows > tr\" placeholder=\"Filter branches and tags…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><table class=\"list refs\" aria-label=\"Branches and tags\"><thead><tr><th class=\"c-kind\">kind</th><th class=\"c-name\">name</th><th class=\"c-sha\">commit</th><th class=\"c-sub\">subject</th><th class=\"c-when\">date</th></tr></thead>") | |
| 544 | 590 | if templ_7745c5c3_Err != nil { | |
| 545 | 591 | return templ_7745c5c3_Err | |
| 546 | 592 | } | |
| @@ -548,32 +594,32 @@ func Refs(l Layout, p RefsPage) templ.Component { | |||
| 548 | 594 | if templ_7745c5c3_Err != nil { | |
| 549 | 595 | return templ_7745c5c3_Err | |
| 550 | 596 | } | |
| 551 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</table>") | |
| 597 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "</table>") | |
| 552 | 598 | if templ_7745c5c3_Err != nil { | |
| 553 | 599 | return templ_7745c5c3_Err | |
| 554 | 600 | } | |
| 555 | 601 | if p.Note != "" { | |
| 556 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<p class=\"note\">") | |
| 602 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "<p class=\"note\">") | |
| 557 | 603 | if templ_7745c5c3_Err != nil { | |
| 558 | 604 | return templ_7745c5c3_Err | |
| 559 | 605 | } | |
| 560 | - | var templ_7745c5c3_Var25 string | |
| 561 | - | templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note) | |
| 606 | + | var templ_7745c5c3_Var27 string | |
| 607 | + | templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note) | |
| 562 | 608 | if templ_7745c5c3_Err != nil { | |
| 563 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 141, Col: 27} | |
| 609 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 149, Col: 27} | |
| 564 | 610 | } | |
| 565 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) | |
| 611 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) | |
| 566 | 612 | if templ_7745c5c3_Err != nil { | |
| 567 | 613 | return templ_7745c5c3_Err | |
| 568 | 614 | } | |
| 569 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "</p>") | |
| 615 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "</p>") | |
| 570 | 616 | if templ_7745c5c3_Err != nil { | |
| 571 | 617 | return templ_7745c5c3_Err | |
| 572 | 618 | } | |
| 573 | 619 | } | |
| 574 | 620 | return nil | |
| 575 | 621 | }) | |
| 576 | - | templ_7745c5c3_Err = Shell(l, refsRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var24), templ_7745c5c3_Buffer) | |
| 622 | + | templ_7745c5c3_Err = Shell(l, refsRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var26), templ_7745c5c3_Buffer) | |
| 577 | 623 | if templ_7745c5c3_Err != nil { | |
| 578 | 624 | return templ_7745c5c3_Err | |
| 579 | 625 | } | |
| @@ -597,112 +643,112 @@ func refRow(kind string, r RefRow) templ.Component { | |||
| 597 | 643 | }() | |
| 598 | 644 | } | |
| 599 | 645 | ctx = templ.InitializeContext(ctx) | |
| 600 | - | templ_7745c5c3_Var26 := templ.GetChildren(ctx) | |
| 601 | - | if templ_7745c5c3_Var26 == nil { | |
| 602 | - | templ_7745c5c3_Var26 = templ.NopComponent | |
| 646 | + | templ_7745c5c3_Var28 := templ.GetChildren(ctx) | |
| 647 | + | if templ_7745c5c3_Var28 == nil { | |
| 648 | + | templ_7745c5c3_Var28 = templ.NopComponent | |
| 603 | 649 | } | |
| 604 | 650 | ctx = templ.ClearChildren(ctx) | |
| 605 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "<tr") | |
| 651 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "<tr") | |
| 606 | 652 | if templ_7745c5c3_Err != nil { | |
| 607 | 653 | return templ_7745c5c3_Err | |
| 608 | 654 | } | |
| 609 | 655 | if r.Cursor { | |
| 610 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, " data-cursor") | |
| 656 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, " data-cursor") | |
| 611 | 657 | if templ_7745c5c3_Err != nil { | |
| 612 | 658 | return templ_7745c5c3_Err | |
| 613 | 659 | } | |
| 614 | 660 | } | |
| 615 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "><td class=\"c-kind mute\">") | |
| 661 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "><td class=\"c-kind mute\">") | |
| 616 | 662 | if templ_7745c5c3_Err != nil { | |
| 617 | 663 | return templ_7745c5c3_Err | |
| 618 | 664 | } | |
| 619 | - | var templ_7745c5c3_Var27 string | |
| 620 | - | templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(kind) | |
| 665 | + | var templ_7745c5c3_Var29 string | |
| 666 | + | templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(kind) | |
| 621 | 667 | if templ_7745c5c3_Err != nil { | |
| 622 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 148, Col: 32} | |
| 668 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 156, Col: 32} | |
| 623 | 669 | } | |
| 624 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) | |
| 670 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) | |
| 625 | 671 | if templ_7745c5c3_Err != nil { | |
| 626 | 672 | return templ_7745c5c3_Err | |
| 627 | 673 | } | |
| 628 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "</td><td class=\"c-name\"><a href=\"") | |
| 674 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "</td><td class=\"c-name\"><a href=\"") | |
| 629 | 675 | if templ_7745c5c3_Err != nil { | |
| 630 | 676 | return templ_7745c5c3_Err | |
| 631 | 677 | } | |
| 632 | - | var templ_7745c5c3_Var28 templ.SafeURL | |
| 633 | - | templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Href)) | |
| 678 | + | var templ_7745c5c3_Var30 templ.SafeURL | |
| 679 | + | templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Href)) | |
| 634 | 680 | if templ_7745c5c3_Err != nil { | |
| 635 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 150, Col: 34} | |
| 681 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 158, Col: 34} | |
| 636 | 682 | } | |
| 637 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) | |
| 683 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) | |
| 638 | 684 | if templ_7745c5c3_Err != nil { | |
| 639 | 685 | return templ_7745c5c3_Err | |
| 640 | 686 | } | |
| 641 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\">") | |
| 687 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "\">") | |
| 642 | 688 | if templ_7745c5c3_Err != nil { | |
| 643 | 689 | return templ_7745c5c3_Err | |
| 644 | 690 | } | |
| 645 | - | var templ_7745c5c3_Var29 string | |
| 646 | - | templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) | |
| 691 | + | var templ_7745c5c3_Var31 string | |
| 692 | + | templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) | |
| 647 | 693 | if templ_7745c5c3_Err != nil { | |
| 648 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 150, Col: 45} | |
| 694 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 158, Col: 45} | |
| 649 | 695 | } | |
| 650 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) | |
| 696 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) | |
| 651 | 697 | if templ_7745c5c3_Err != nil { | |
| 652 | 698 | return templ_7745c5c3_Err | |
| 653 | 699 | } | |
| 654 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "</a> ") | |
| 700 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</a> ") | |
| 655 | 701 | if templ_7745c5c3_Err != nil { | |
| 656 | 702 | return templ_7745c5c3_Err | |
| 657 | 703 | } | |
| 658 | 704 | if r.Default { | |
| 659 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "<span class=\"pill\">default</span>") | |
| 705 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<span class=\"pill\">default</span>") | |
| 660 | 706 | if templ_7745c5c3_Err != nil { | |
| 661 | 707 | return templ_7745c5c3_Err | |
| 662 | 708 | } | |
| 663 | 709 | } | |
| 664 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</td><td class=\"c-sha\">") | |
| 710 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</td><td class=\"c-sha\">") | |
| 665 | 711 | if templ_7745c5c3_Err != nil { | |
| 666 | 712 | return templ_7745c5c3_Err | |
| 667 | 713 | } | |
| 668 | 714 | if r.CHref != "" { | |
| 669 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "<a href=\"") | |
| 715 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "<a href=\"") | |
| 670 | 716 | if templ_7745c5c3_Err != nil { | |
| 671 | 717 | return templ_7745c5c3_Err | |
| 672 | 718 | } | |
| 673 | - | var templ_7745c5c3_Var30 templ.SafeURL | |
| 674 | - | templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.CHref)) | |
| 719 | + | var templ_7745c5c3_Var32 templ.SafeURL | |
| 720 | + | templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.CHref)) | |
| 675 | 721 | if templ_7745c5c3_Err != nil { | |
| 676 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 157, Col: 36} | |
| 722 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 165, Col: 36} | |
| 677 | 723 | } | |
| 678 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) | |
| 724 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) | |
| 679 | 725 | if templ_7745c5c3_Err != nil { | |
| 680 | 726 | return templ_7745c5c3_Err | |
| 681 | 727 | } | |
| 682 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\">") | |
| 728 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\">") | |
| 683 | 729 | if templ_7745c5c3_Err != nil { | |
| 684 | 730 | return templ_7745c5c3_Err | |
| 685 | 731 | } | |
| 686 | - | var templ_7745c5c3_Var31 string | |
| 687 | - | templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) | |
| 732 | + | var templ_7745c5c3_Var33 string | |
| 733 | + | templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) | |
| 688 | 734 | if templ_7745c5c3_Err != nil { | |
| 689 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 157, Col: 48} | |
| 735 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 165, Col: 48} | |
| 690 | 736 | } | |
| 691 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) | |
| 737 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) | |
| 692 | 738 | if templ_7745c5c3_Err != nil { | |
| 693 | 739 | return templ_7745c5c3_Err | |
| 694 | 740 | } | |
| 695 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</a>") | |
| 741 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</a>") | |
| 696 | 742 | if templ_7745c5c3_Err != nil { | |
| 697 | 743 | return templ_7745c5c3_Err | |
| 698 | 744 | } | |
| 699 | 745 | } else { | |
| 700 | - | var templ_7745c5c3_Var32 string | |
| 701 | - | templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) | |
| 746 | + | var templ_7745c5c3_Var34 string | |
| 747 | + | templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) | |
| 702 | 748 | if templ_7745c5c3_Err != nil { | |
| 703 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 159, Col: 13} | |
| 749 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 167, Col: 13} | |
| 704 | 750 | } | |
| 705 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) | |
| 751 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) | |
| 706 | 752 | if templ_7745c5c3_Err != nil { | |
| 707 | 753 | return templ_7745c5c3_Err | |
| 708 | 754 | } | |
| @@ -711,69 +757,69 @@ func refRow(kind string, r RefRow) templ.Component { | |||
| 711 | 757 | if templ_7745c5c3_Err != nil { | |
| 712 | 758 | return templ_7745c5c3_Err | |
| 713 | 759 | } | |
| 714 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</td><td class=\"c-sub\">") | |
| 760 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "</td><td class=\"c-sub\">") | |
| 715 | 761 | if templ_7745c5c3_Err != nil { | |
| 716 | 762 | return templ_7745c5c3_Err | |
| 717 | 763 | } | |
| 718 | - | var templ_7745c5c3_Var33 string | |
| 719 | - | templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(r.Subject) | |
| 764 | + | var templ_7745c5c3_Var35 string | |
| 765 | + | templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(r.Subject) | |
| 720 | 766 | if templ_7745c5c3_Err != nil { | |
| 721 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 163, Col: 31} | |
| 767 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 171, Col: 31} | |
| 722 | 768 | } | |
| 723 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) | |
| 769 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) | |
| 724 | 770 | if templ_7745c5c3_Err != nil { | |
| 725 | 771 | return templ_7745c5c3_Err | |
| 726 | 772 | } | |
| 727 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "</td><td class=\"c-when dim\">") | |
| 773 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "</td><td class=\"c-when dim\">") | |
| 728 | 774 | if templ_7745c5c3_Err != nil { | |
| 729 | 775 | return templ_7745c5c3_Err | |
| 730 | 776 | } | |
| 731 | 777 | if r.WhenAt != "" { | |
| 732 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<time datetime=\"") | |
| 778 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "<time datetime=\"") | |
| 733 | 779 | if templ_7745c5c3_Err != nil { | |
| 734 | 780 | return templ_7745c5c3_Err | |
| 735 | 781 | } | |
| 736 | - | var templ_7745c5c3_Var34 string | |
| 737 | - | templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) | |
| 782 | + | var templ_7745c5c3_Var36 string | |
| 783 | + | templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) | |
| 738 | 784 | if templ_7745c5c3_Err != nil { | |
| 739 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 166, Col: 29} | |
| 785 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 174, Col: 29} | |
| 740 | 786 | } | |
| 741 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var34) | |
| 787 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var36) | |
| 742 | 788 | if templ_7745c5c3_Err != nil { | |
| 743 | 789 | return templ_7745c5c3_Err | |
| 744 | 790 | } | |
| 745 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" title=\"") | |
| 791 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\" title=\"") | |
| 746 | 792 | if templ_7745c5c3_Err != nil { | |
| 747 | 793 | return templ_7745c5c3_Err | |
| 748 | 794 | } | |
| 749 | - | var templ_7745c5c3_Var35 string | |
| 750 | - | templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) | |
| 795 | + | var templ_7745c5c3_Var37 string | |
| 796 | + | templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) | |
| 751 | 797 | if templ_7745c5c3_Err != nil { | |
| 752 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 166, Col: 48} | |
| 798 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 174, Col: 48} | |
| 753 | 799 | } | |
| 754 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var35) | |
| 800 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var37) | |
| 755 | 801 | if templ_7745c5c3_Err != nil { | |
| 756 | 802 | return templ_7745c5c3_Err | |
| 757 | 803 | } | |
| 758 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\">") | |
| 804 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "\">") | |
| 759 | 805 | if templ_7745c5c3_Err != nil { | |
| 760 | 806 | return templ_7745c5c3_Err | |
| 761 | 807 | } | |
| 762 | - | var templ_7745c5c3_Var36 string | |
| 763 | - | templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(r.When) | |
| 808 | + | var templ_7745c5c3_Var38 string | |
| 809 | + | templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(r.When) | |
| 764 | 810 | if templ_7745c5c3_Err != nil { | |
| 765 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 166, Col: 59} | |
| 811 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 174, Col: 59} | |
| 766 | 812 | } | |
| 767 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) | |
| 813 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38)) | |
| 768 | 814 | if templ_7745c5c3_Err != nil { | |
| 769 | 815 | return templ_7745c5c3_Err | |
| 770 | 816 | } | |
| 771 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</time>") | |
| 817 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "</time>") | |
| 772 | 818 | if templ_7745c5c3_Err != nil { | |
| 773 | 819 | return templ_7745c5c3_Err | |
| 774 | 820 | } | |
| 775 | 821 | } | |
| 776 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "</td></tr>") | |
| 822 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "</td></tr>") | |
| 777 | 823 | if templ_7745c5c3_Err != nil { | |
| 778 | 824 | return templ_7745c5c3_Err | |
| 779 | 825 | } | |
| @@ -797,12 +843,12 @@ func refsRail(p RefsPage) templ.Component { | |||
| 797 | 843 | }() | |
| 798 | 844 | } | |
| 799 | 845 | ctx = templ.InitializeContext(ctx) | |
| 800 | - | templ_7745c5c3_Var37 := templ.GetChildren(ctx) | |
| 801 | - | if templ_7745c5c3_Var37 == nil { | |
| 802 | - | templ_7745c5c3_Var37 = templ.NopComponent | |
| 846 | + | templ_7745c5c3_Var39 := templ.GetChildren(ctx) | |
| 847 | + | if templ_7745c5c3_Var39 == nil { | |
| 848 | + | templ_7745c5c3_Var39 = templ.NopComponent | |
| 803 | 849 | } | |
| 804 | 850 | ctx = templ.ClearChildren(ctx) | |
| 805 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "<section aria-labelledby=\"r-refs\"><h2 id=\"r-refs\">Overview</h2>") | |
| 851 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "<section aria-labelledby=\"r-refs\"><h2 id=\"r-refs\">Overview</h2>") | |
| 806 | 852 | if templ_7745c5c3_Err != nil { | |
| 807 | 853 | return templ_7745c5c3_Err | |
| 808 | 854 | } | |
| @@ -810,7 +856,7 @@ func refsRail(p RefsPage) templ.Component { | |||
| 810 | 856 | if templ_7745c5c3_Err != nil { | |
| 811 | 857 | return templ_7745c5c3_Err | |
| 812 | 858 | } | |
| 813 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "</section>") | |
| 859 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "</section>") | |
| 814 | 860 | if templ_7745c5c3_Err != nil { | |
| 815 | 861 | return templ_7745c5c3_Err | |
| 816 | 862 | } | |
| @@ -835,12 +881,12 @@ func State(l Layout, p StatePage) templ.Component { | |||
| 835 | 881 | }() | |
| 836 | 882 | } | |
| 837 | 883 | ctx = templ.InitializeContext(ctx) | |
| 838 | - | templ_7745c5c3_Var38 := templ.GetChildren(ctx) | |
| 839 | - | if templ_7745c5c3_Var38 == nil { | |
| 840 | - | templ_7745c5c3_Var38 = templ.NopComponent | |
| 884 | + | templ_7745c5c3_Var40 := templ.GetChildren(ctx) | |
| 885 | + | if templ_7745c5c3_Var40 == nil { | |
| 886 | + | templ_7745c5c3_Var40 = templ.NopComponent | |
| 841 | 887 | } | |
| 842 | 888 | ctx = templ.ClearChildren(ctx) | |
| 843 | - | templ_7745c5c3_Var39 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 889 | + | templ_7745c5c3_Var41 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 844 | 890 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | |
| 845 | 891 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | |
| 846 | 892 | if !templ_7745c5c3_IsBuffer { | |
| @@ -852,51 +898,51 @@ func State(l Layout, p StatePage) templ.Component { | |||
| 852 | 898 | }() | |
| 853 | 899 | } | |
| 854 | 900 | ctx = templ.InitializeContext(ctx) | |
| 855 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "<section class=\"state\" aria-labelledby=\"state-title\"><p class=\"eyebrow\">") | |
| 901 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "<section class=\"state\" aria-labelledby=\"state-title\"><p class=\"eyebrow\">") | |
| 856 | 902 | if templ_7745c5c3_Err != nil { | |
| 857 | 903 | return templ_7745c5c3_Err | |
| 858 | 904 | } | |
| 859 | - | var templ_7745c5c3_Var40 string | |
| 860 | - | templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(p.Code) | |
| 905 | + | var templ_7745c5c3_Var42 string | |
| 906 | + | templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Code) | |
| 861 | 907 | if templ_7745c5c3_Err != nil { | |
| 862 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 183, Col: 30} | |
| 908 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 191, Col: 30} | |
| 863 | 909 | } | |
| 864 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) | |
| 910 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) | |
| 865 | 911 | if templ_7745c5c3_Err != nil { | |
| 866 | 912 | return templ_7745c5c3_Err | |
| 867 | 913 | } | |
| 868 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "</p><h1 id=\"state-title\">") | |
| 914 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "</p><h1 id=\"state-title\">") | |
| 869 | 915 | if templ_7745c5c3_Err != nil { | |
| 870 | 916 | return templ_7745c5c3_Err | |
| 871 | 917 | } | |
| 872 | - | var templ_7745c5c3_Var41 string | |
| 873 | - | templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | |
| 918 | + | var templ_7745c5c3_Var43 string | |
| 919 | + | templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | |
| 874 | 920 | if templ_7745c5c3_Err != nil { | |
| 875 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 184, Col: 33} | |
| 921 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 192, Col: 33} | |
| 876 | 922 | } | |
| 877 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41)) | |
| 923 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) | |
| 878 | 924 | if templ_7745c5c3_Err != nil { | |
| 879 | 925 | return templ_7745c5c3_Err | |
| 880 | 926 | } | |
| 881 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "</h1>") | |
| 927 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</h1>") | |
| 882 | 928 | if templ_7745c5c3_Err != nil { | |
| 883 | 929 | return templ_7745c5c3_Err | |
| 884 | 930 | } | |
| 885 | 931 | for _, line := range p.Lines { | |
| 886 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "<p class=\"dim\">") | |
| 932 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "<p class=\"dim\">") | |
| 887 | 933 | if templ_7745c5c3_Err != nil { | |
| 888 | 934 | return templ_7745c5c3_Err | |
| 889 | 935 | } | |
| 890 | - | var templ_7745c5c3_Var42 string | |
| 891 | - | templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(line) | |
| 936 | + | var templ_7745c5c3_Var44 string | |
| 937 | + | templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(line) | |
| 892 | 938 | if templ_7745c5c3_Err != nil { | |
| 893 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 186, Col: 25} | |
| 939 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 194, Col: 25} | |
| 894 | 940 | } | |
| 895 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) | |
| 941 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44)) | |
| 896 | 942 | if templ_7745c5c3_Err != nil { | |
| 897 | 943 | return templ_7745c5c3_Err | |
| 898 | 944 | } | |
| 899 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "</p>") | |
| 945 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "</p>") | |
| 900 | 946 | if templ_7745c5c3_Err != nil { | |
| 901 | 947 | return templ_7745c5c3_Err | |
| 902 | 948 | } | |
| @@ -907,49 +953,49 @@ func State(l Layout, p StatePage) templ.Component { | |||
| 907 | 953 | return templ_7745c5c3_Err | |
| 908 | 954 | } | |
| 909 | 955 | } | |
| 910 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "<p class=\"state-back\">") | |
| 956 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "<p class=\"state-back\">") | |
| 911 | 957 | if templ_7745c5c3_Err != nil { | |
| 912 | 958 | return templ_7745c5c3_Err | |
| 913 | 959 | } | |
| 914 | 960 | for _, b := range p.Back { | |
| 915 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "<a href=\"") | |
| 961 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<a href=\"") | |
| 916 | 962 | if templ_7745c5c3_Err != nil { | |
| 917 | 963 | return templ_7745c5c3_Err | |
| 918 | 964 | } | |
| 919 | - | var templ_7745c5c3_Var43 templ.SafeURL | |
| 920 | - | templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(b.Href)) | |
| 965 | + | var templ_7745c5c3_Var45 templ.SafeURL | |
| 966 | + | templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(b.Href)) | |
| 921 | 967 | if templ_7745c5c3_Err != nil { | |
| 922 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 193, Col: 36} | |
| 968 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 201, Col: 36} | |
| 923 | 969 | } | |
| 924 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) | |
| 970 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45)) | |
| 925 | 971 | if templ_7745c5c3_Err != nil { | |
| 926 | 972 | return templ_7745c5c3_Err | |
| 927 | 973 | } | |
| 928 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "\">") | |
| 974 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "\">") | |
| 929 | 975 | if templ_7745c5c3_Err != nil { | |
| 930 | 976 | return templ_7745c5c3_Err | |
| 931 | 977 | } | |
| 932 | - | var templ_7745c5c3_Var44 string | |
| 933 | - | templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(b.Label) | |
| 978 | + | var templ_7745c5c3_Var46 string | |
| 979 | + | templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(b.Label) | |
| 934 | 980 | if templ_7745c5c3_Err != nil { | |
| 935 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 193, Col: 48} | |
| 981 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 201, Col: 48} | |
| 936 | 982 | } | |
| 937 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44)) | |
| 983 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46)) | |
| 938 | 984 | if templ_7745c5c3_Err != nil { | |
| 939 | 985 | return templ_7745c5c3_Err | |
| 940 | 986 | } | |
| 941 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</a>") | |
| 987 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "</a>") | |
| 942 | 988 | if templ_7745c5c3_Err != nil { | |
| 943 | 989 | return templ_7745c5c3_Err | |
| 944 | 990 | } | |
| 945 | 991 | } | |
| 946 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "</p></section>") | |
| 992 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</p></section>") | |
| 947 | 993 | if templ_7745c5c3_Err != nil { | |
| 948 | 994 | return templ_7745c5c3_Err | |
| 949 | 995 | } | |
| 950 | 996 | return nil | |
| 951 | 997 | }) | |
| 952 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var39), templ_7745c5c3_Buffer) | |
| 998 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var41), templ_7745c5c3_Buffer) | |
| 953 | 999 | if templ_7745c5c3_Err != nil { | |
| 954 | 1000 | return templ_7745c5c3_Err | |
| 955 | 1001 | } | |
| @@ -978,12 +1024,12 @@ func Login(l Layout, p LoginPage) templ.Component { | |||
| 978 | 1024 | }() | |
| 979 | 1025 | } | |
| 980 | 1026 | ctx = templ.InitializeContext(ctx) | |
| 981 | - | templ_7745c5c3_Var45 := templ.GetChildren(ctx) | |
| 982 | - | if templ_7745c5c3_Var45 == nil { | |
| 983 | - | templ_7745c5c3_Var45 = templ.NopComponent | |
| 1027 | + | templ_7745c5c3_Var47 := templ.GetChildren(ctx) | |
| 1028 | + | if templ_7745c5c3_Var47 == nil { | |
| 1029 | + | templ_7745c5c3_Var47 = templ.NopComponent | |
| 984 | 1030 | } | |
| 985 | 1031 | ctx = templ.ClearChildren(ctx) | |
| 986 | - | templ_7745c5c3_Var46 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 1032 | + | templ_7745c5c3_Var48 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 987 | 1033 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | |
| 988 | 1034 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | |
| 989 | 1035 | if !templ_7745c5c3_IsBuffer { | |
| @@ -995,75 +1041,75 @@ func Login(l Layout, p LoginPage) templ.Component { | |||
| 995 | 1041 | }() | |
| 996 | 1042 | } | |
| 997 | 1043 | ctx = templ.InitializeContext(ctx) | |
| 998 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") | |
| 1044 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") | |
| 999 | 1045 | if templ_7745c5c3_Err != nil { | |
| 1000 | 1046 | return templ_7745c5c3_Err | |
| 1001 | 1047 | } | |
| 1002 | - | var templ_7745c5c3_Var47 string | |
| 1003 | - | templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | |
| 1048 | + | var templ_7745c5c3_Var49 string | |
| 1049 | + | templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | |
| 1004 | 1050 | if templ_7745c5c3_Err != nil { | |
| 1005 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 208, Col: 33} | |
| 1051 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 216, Col: 33} | |
| 1006 | 1052 | } | |
| 1007 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47)) | |
| 1053 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49)) | |
| 1008 | 1054 | if templ_7745c5c3_Err != nil { | |
| 1009 | 1055 | return templ_7745c5c3_Err | |
| 1010 | 1056 | } | |
| 1011 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "</h1>") | |
| 1057 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "</h1>") | |
| 1012 | 1058 | if templ_7745c5c3_Err != nil { | |
| 1013 | 1059 | return templ_7745c5c3_Err | |
| 1014 | 1060 | } | |
| 1015 | 1061 | for _, line := range p.Lines { | |
| 1016 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<p class=\"dim\">") | |
| 1062 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "<p class=\"dim\">") | |
| 1017 | 1063 | if templ_7745c5c3_Err != nil { | |
| 1018 | 1064 | return templ_7745c5c3_Err | |
| 1019 | 1065 | } | |
| 1020 | - | var templ_7745c5c3_Var48 string | |
| 1021 | - | templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(line) | |
| 1066 | + | var templ_7745c5c3_Var50 string | |
| 1067 | + | templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(line) | |
| 1022 | 1068 | if templ_7745c5c3_Err != nil { | |
| 1023 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 210, Col: 25} | |
| 1069 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 218, Col: 25} | |
| 1024 | 1070 | } | |
| 1025 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48)) | |
| 1071 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50)) | |
| 1026 | 1072 | if templ_7745c5c3_Err != nil { | |
| 1027 | 1073 | return templ_7745c5c3_Err | |
| 1028 | 1074 | } | |
| 1029 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "</p>") | |
| 1075 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "</p>") | |
| 1030 | 1076 | if templ_7745c5c3_Err != nil { | |
| 1031 | 1077 | return templ_7745c5c3_Err | |
| 1032 | 1078 | } | |
| 1033 | 1079 | } | |
| 1034 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "<form class=\"state-act\" method=\"post\" action=\"") | |
| 1080 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "<form class=\"state-act\" method=\"post\" action=\"") | |
| 1035 | 1081 | if templ_7745c5c3_Err != nil { | |
| 1036 | 1082 | return templ_7745c5c3_Err | |
| 1037 | 1083 | } | |
| 1038 | - | var templ_7745c5c3_Var49 templ.SafeURL | |
| 1039 | - | templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Action)) | |
| 1084 | + | var templ_7745c5c3_Var51 templ.SafeURL | |
| 1085 | + | templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Action)) | |
| 1040 | 1086 | if templ_7745c5c3_Err != nil { | |
| 1041 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 212, Col: 73} | |
| 1087 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 220, Col: 73} | |
| 1042 | 1088 | } | |
| 1043 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49)) | |
| 1089 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51)) | |
| 1044 | 1090 | if templ_7745c5c3_Err != nil { | |
| 1045 | 1091 | return templ_7745c5c3_Err | |
| 1046 | 1092 | } | |
| 1047 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "\" data-autosubmit><button type=\"submit\" class=\"btn primary\">") | |
| 1093 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "\" data-autosubmit><button type=\"submit\" class=\"btn primary\">") | |
| 1048 | 1094 | if templ_7745c5c3_Err != nil { | |
| 1049 | 1095 | return templ_7745c5c3_Err | |
| 1050 | 1096 | } | |
| 1051 | - | var templ_7745c5c3_Var50 string | |
| 1052 | - | templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) | |
| 1097 | + | var templ_7745c5c3_Var52 string | |
| 1098 | + | templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) | |
| 1053 | 1099 | if templ_7745c5c3_Err != nil { | |
| 1054 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 213, Col: 56} | |
| 1100 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 221, Col: 56} | |
| 1055 | 1101 | } | |
| 1056 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50)) | |
| 1102 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52)) | |
| 1057 | 1103 | if templ_7745c5c3_Err != nil { | |
| 1058 | 1104 | return templ_7745c5c3_Err | |
| 1059 | 1105 | } | |
| 1060 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "</button></form><p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") | |
| 1106 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "</button></form><p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") | |
| 1061 | 1107 | if templ_7745c5c3_Err != nil { | |
| 1062 | 1108 | return templ_7745c5c3_Err | |
| 1063 | 1109 | } | |
| 1064 | 1110 | return nil | |
| 1065 | 1111 | }) | |
| 1066 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var46), templ_7745c5c3_Buffer) | |
| 1112 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var48), templ_7745c5c3_Buffer) | |
| 1067 | 1113 | if templ_7745c5c3_Err != nil { | |
| 1068 | 1114 | return templ_7745c5c3_Err | |
| 1069 | 1115 | } | |
| @@ -1089,12 +1135,12 @@ func PasskeyLogin(l Layout, p PasskeyLoginPage) templ.Component { | |||
| 1089 | 1135 | }() | |
| 1090 | 1136 | } | |
| 1091 | 1137 | ctx = templ.InitializeContext(ctx) | |
| 1092 | - | templ_7745c5c3_Var51 := templ.GetChildren(ctx) | |
| 1093 | - | if templ_7745c5c3_Var51 == nil { | |
| 1094 | - | templ_7745c5c3_Var51 = templ.NopComponent | |
| 1138 | + | templ_7745c5c3_Var53 := templ.GetChildren(ctx) | |
| 1139 | + | if templ_7745c5c3_Var53 == nil { | |
| 1140 | + | templ_7745c5c3_Var53 = templ.NopComponent | |
| 1095 | 1141 | } | |
| 1096 | 1142 | ctx = templ.ClearChildren(ctx) | |
| 1097 | - | templ_7745c5c3_Var52 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 1143 | + | templ_7745c5c3_Var54 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 1098 | 1144 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | |
| 1099 | 1145 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | |
| 1100 | 1146 | if !templ_7745c5c3_IsBuffer { | |
| @@ -1106,88 +1152,88 @@ func PasskeyLogin(l Layout, p PasskeyLoginPage) templ.Component { | |||
| 1106 | 1152 | }() | |
| 1107 | 1153 | } | |
| 1108 | 1154 | ctx = templ.InitializeContext(ctx) | |
| 1109 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") | |
| 1155 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") | |
| 1110 | 1156 | if templ_7745c5c3_Err != nil { | |
| 1111 | 1157 | return templ_7745c5c3_Err | |
| 1112 | 1158 | } | |
| 1113 | - | var templ_7745c5c3_Var53 string | |
| 1114 | - | templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | |
| 1159 | + | var templ_7745c5c3_Var55 string | |
| 1160 | + | templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | |
| 1115 | 1161 | if templ_7745c5c3_Err != nil { | |
| 1116 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 225, Col: 33} | |
| 1162 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 233, Col: 33} | |
| 1117 | 1163 | } | |
| 1118 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53)) | |
| 1164 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55)) | |
| 1119 | 1165 | if templ_7745c5c3_Err != nil { | |
| 1120 | 1166 | return templ_7745c5c3_Err | |
| 1121 | 1167 | } | |
| 1122 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "</h1><form class=\"state-act\" data-js data-passkey-form><button type=\"submit\" class=\"btn primary\" data-passkey=\"login\" data-begin=\"") | |
| 1168 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</h1><form class=\"state-act\" data-js data-passkey-form><button type=\"submit\" class=\"btn primary\" data-passkey=\"login\" data-begin=\"") | |
| 1123 | 1169 | if templ_7745c5c3_Err != nil { | |
| 1124 | 1170 | return templ_7745c5c3_Err | |
| 1125 | 1171 | } | |
| 1126 | - | var templ_7745c5c3_Var54 string | |
| 1127 | - | templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) | |
| 1172 | + | var templ_7745c5c3_Var56 string | |
| 1173 | + | templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) | |
| 1128 | 1174 | if templ_7745c5c3_Err != nil { | |
| 1129 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 227, Col: 87} | |
| 1175 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 235, Col: 87} | |
| 1130 | 1176 | } | |
| 1131 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var54) | |
| 1177 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var56) | |
| 1132 | 1178 | if templ_7745c5c3_Err != nil { | |
| 1133 | 1179 | return templ_7745c5c3_Err | |
| 1134 | 1180 | } | |
| 1135 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "\" data-finish=\"") | |
| 1181 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "\" data-finish=\"") | |
| 1136 | 1182 | if templ_7745c5c3_Err != nil { | |
| 1137 | 1183 | return templ_7745c5c3_Err | |
| 1138 | 1184 | } | |
| 1139 | - | var templ_7745c5c3_Var55 string | |
| 1140 | - | templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) | |
| 1185 | + | var templ_7745c5c3_Var57 string | |
| 1186 | + | templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) | |
| 1141 | 1187 | if templ_7745c5c3_Err != nil { | |
| 1142 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 227, Col: 112} | |
| 1188 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 235, Col: 112} | |
| 1143 | 1189 | } | |
| 1144 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var55) | |
| 1190 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var57) | |
| 1145 | 1191 | if templ_7745c5c3_Err != nil { | |
| 1146 | 1192 | return templ_7745c5c3_Err | |
| 1147 | 1193 | } | |
| 1148 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\">") | |
| 1194 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "\">") | |
| 1149 | 1195 | if templ_7745c5c3_Err != nil { | |
| 1150 | 1196 | return templ_7745c5c3_Err | |
| 1151 | 1197 | } | |
| 1152 | - | var templ_7745c5c3_Var56 string | |
| 1153 | - | templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) | |
| 1198 | + | var templ_7745c5c3_Var58 string | |
| 1199 | + | templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) | |
| 1154 | 1200 | if templ_7745c5c3_Err != nil { | |
| 1155 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 227, Col: 125} | |
| 1201 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 235, Col: 125} | |
| 1156 | 1202 | } | |
| 1157 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var56)) | |
| 1203 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58)) | |
| 1158 | 1204 | if templ_7745c5c3_Err != nil { | |
| 1159 | 1205 | return templ_7745c5c3_Err | |
| 1160 | 1206 | } | |
| 1161 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "</button></form><p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") | |
| 1207 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "</button></form><p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") | |
| 1162 | 1208 | if templ_7745c5c3_Err != nil { | |
| 1163 | 1209 | return templ_7745c5c3_Err | |
| 1164 | 1210 | } | |
| 1165 | 1211 | for _, line := range p.Lines { | |
| 1166 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<p class=\"dim\">") | |
| 1212 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "<p class=\"dim\">") | |
| 1167 | 1213 | if templ_7745c5c3_Err != nil { | |
| 1168 | 1214 | return templ_7745c5c3_Err | |
| 1169 | 1215 | } | |
| 1170 | - | var templ_7745c5c3_Var57 string | |
| 1171 | - | templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinStringErrs(line) | |
| 1216 | + | var templ_7745c5c3_Var59 string | |
| 1217 | + | templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(line) | |
| 1172 | 1218 | if templ_7745c5c3_Err != nil { | |
| 1173 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 231, Col: 25} | |
| 1219 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 239, Col: 25} | |
| 1174 | 1220 | } | |
| 1175 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57)) | |
| 1221 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59)) | |
| 1176 | 1222 | if templ_7745c5c3_Err != nil { | |
| 1177 | 1223 | return templ_7745c5c3_Err | |
| 1178 | 1224 | } | |
| 1179 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "</p>") | |
| 1225 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</p>") | |
| 1180 | 1226 | if templ_7745c5c3_Err != nil { | |
| 1181 | 1227 | return templ_7745c5c3_Err | |
| 1182 | 1228 | } | |
| 1183 | 1229 | } | |
| 1184 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "<p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") | |
| 1230 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "<p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") | |
| 1185 | 1231 | if templ_7745c5c3_Err != nil { | |
| 1186 | 1232 | return templ_7745c5c3_Err | |
| 1187 | 1233 | } | |
| 1188 | 1234 | return nil | |
| 1189 | 1235 | }) | |
| 1190 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var52), templ_7745c5c3_Buffer) | |
| 1236 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var54), templ_7745c5c3_Buffer) | |
| 1191 | 1237 | if templ_7745c5c3_Err != nil { | |
| 1192 | 1238 | return templ_7745c5c3_Err | |
| 1193 | 1239 | } | |
| @@ -1212,12 +1258,12 @@ func Passkeys(l Layout, p PasskeysPage) templ.Component { | |||
| 1212 | 1258 | }() | |
| 1213 | 1259 | } | |
| 1214 | 1260 | ctx = templ.InitializeContext(ctx) | |
| 1215 | - | templ_7745c5c3_Var58 := templ.GetChildren(ctx) | |
| 1216 | - | if templ_7745c5c3_Var58 == nil { | |
| 1217 | - | templ_7745c5c3_Var58 = templ.NopComponent | |
| 1261 | + | templ_7745c5c3_Var60 := templ.GetChildren(ctx) | |
| 1262 | + | if templ_7745c5c3_Var60 == nil { | |
| 1263 | + | templ_7745c5c3_Var60 = templ.NopComponent | |
| 1218 | 1264 | } | |
| 1219 | 1265 | ctx = templ.ClearChildren(ctx) | |
| 1220 | - | templ_7745c5c3_Var59 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 1266 | + | templ_7745c5c3_Var61 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | |
| 1221 | 1267 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | |
| 1222 | 1268 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | |
| 1223 | 1269 | if !templ_7745c5c3_IsBuffer { | |
| @@ -1229,231 +1275,231 @@ func Passkeys(l Layout, p PasskeysPage) templ.Component { | |||
| 1229 | 1275 | }() | |
| 1230 | 1276 | } | |
| 1231 | 1277 | ctx = templ.InitializeContext(ctx) | |
| 1232 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<h2 class=\"rule-h\"><span>Passkeys</span><span class=\"count\">") | |
| 1278 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "<h2 class=\"rule-h\"><span>Passkeys</span><span class=\"count\">") | |
| 1233 | 1279 | if templ_7745c5c3_Err != nil { | |
| 1234 | 1280 | return templ_7745c5c3_Err | |
| 1235 | 1281 | } | |
| 1236 | - | var templ_7745c5c3_Var60 string | |
| 1237 | - | templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Rows))) | |
| 1282 | + | var templ_7745c5c3_Var62 string | |
| 1283 | + | templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Rows))) | |
| 1238 | 1284 | if templ_7745c5c3_Err != nil { | |
| 1239 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 241, Col: 81} | |
| 1285 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 249, Col: 81} | |
| 1240 | 1286 | } | |
| 1241 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var60)) | |
| 1287 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62)) | |
| 1242 | 1288 | if templ_7745c5c3_Err != nil { | |
| 1243 | 1289 | return templ_7745c5c3_Err | |
| 1244 | 1290 | } | |
| 1245 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "</span></h2><p class=\"dim\">A passkey signs you in from this device or your phone, without a terminal. Removing one signs every browser out.</p>") | |
| 1291 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "</span></h2><p class=\"dim\">A passkey signs you in from this device or your phone, without a terminal. Removing one signs every browser out.</p>") | |
| 1246 | 1292 | if templ_7745c5c3_Err != nil { | |
| 1247 | 1293 | return templ_7745c5c3_Err | |
| 1248 | 1294 | } | |
| 1249 | 1295 | if len(p.Rows) > 0 { | |
| 1250 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "<table class=\"list passkeys\" aria-label=\"Passkeys\"><thead><tr><th class=\"c-name\">Name</th><th class=\"c-when\">Created</th><th class=\"c-when\">Last used</th><th class=\"c-sync\">Synced</th><th class=\"c-act\"><span class=\"sr\">Remove</span></th></tr></thead> <tbody>") | |
| 1296 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "<table class=\"list passkeys\" aria-label=\"Passkeys\"><thead><tr><th class=\"c-name\">Name</th><th class=\"c-when\">Created</th><th class=\"c-when\">Last used</th><th class=\"c-sync\">Synced</th><th class=\"c-act\"><span class=\"sr\">Remove</span></th></tr></thead> <tbody>") | |
| 1251 | 1297 | if templ_7745c5c3_Err != nil { | |
| 1252 | 1298 | return templ_7745c5c3_Err | |
| 1253 | 1299 | } | |
| 1254 | 1300 | for _, r := range p.Rows { | |
| 1255 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "<tr><td class=\"c-name\">") | |
| 1301 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "<tr><td class=\"c-name\">") | |
| 1256 | 1302 | if templ_7745c5c3_Err != nil { | |
| 1257 | 1303 | return templ_7745c5c3_Err | |
| 1258 | 1304 | } | |
| 1259 | - | var templ_7745c5c3_Var61 string | |
| 1260 | - | templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) | |
| 1305 | + | var templ_7745c5c3_Var63 string | |
| 1306 | + | templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) | |
| 1261 | 1307 | if templ_7745c5c3_Err != nil { | |
| 1262 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 257, Col: 34} | |
| 1308 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 265, Col: 34} | |
| 1263 | 1309 | } | |
| 1264 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61)) | |
| 1310 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63)) | |
| 1265 | 1311 | if templ_7745c5c3_Err != nil { | |
| 1266 | 1312 | return templ_7745c5c3_Err | |
| 1267 | 1313 | } | |
| 1268 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</td><td class=\"c-when nowrap\"><time") | |
| 1314 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "</td><td class=\"c-when nowrap\"><time") | |
| 1269 | 1315 | if templ_7745c5c3_Err != nil { | |
| 1270 | 1316 | return templ_7745c5c3_Err | |
| 1271 | 1317 | } | |
| 1272 | 1318 | if r.CreatedAt != "" { | |
| 1273 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, " datetime=\"") | |
| 1319 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, " datetime=\"") | |
| 1274 | 1320 | if templ_7745c5c3_Err != nil { | |
| 1275 | 1321 | return templ_7745c5c3_Err | |
| 1276 | 1322 | } | |
| 1277 | - | var templ_7745c5c3_Var62 string | |
| 1278 | - | templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.CreatedAt) | |
| 1323 | + | var templ_7745c5c3_Var64 string | |
| 1324 | + | templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.CreatedAt) | |
| 1279 | 1325 | if templ_7745c5c3_Err != nil { | |
| 1280 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 261, Col: 32} | |
| 1326 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 269, Col: 32} | |
| 1281 | 1327 | } | |
| 1282 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62) | |
| 1328 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64) | |
| 1283 | 1329 | if templ_7745c5c3_Err != nil { | |
| 1284 | 1330 | return templ_7745c5c3_Err | |
| 1285 | 1331 | } | |
| 1286 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "\"") | |
| 1332 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "\"") | |
| 1287 | 1333 | if templ_7745c5c3_Err != nil { | |
| 1288 | 1334 | return templ_7745c5c3_Err | |
| 1289 | 1335 | } | |
| 1290 | 1336 | } | |
| 1291 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, ">") | |
| 1337 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, ">") | |
| 1292 | 1338 | if templ_7745c5c3_Err != nil { | |
| 1293 | 1339 | return templ_7745c5c3_Err | |
| 1294 | 1340 | } | |
| 1295 | - | var templ_7745c5c3_Var63 string | |
| 1296 | - | templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(r.Created) | |
| 1341 | + | var templ_7745c5c3_Var65 string | |
| 1342 | + | templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(r.Created) | |
| 1297 | 1343 | if templ_7745c5c3_Err != nil { | |
| 1298 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 263, Col: 20} | |
| 1344 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 271, Col: 20} | |
| 1299 | 1345 | } | |
| 1300 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63)) | |
| 1346 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65)) | |
| 1301 | 1347 | if templ_7745c5c3_Err != nil { | |
| 1302 | 1348 | return templ_7745c5c3_Err | |
| 1303 | 1349 | } | |
| 1304 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "</time></td><td class=\"c-when nowrap\"><time") | |
| 1350 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "</time></td><td class=\"c-when nowrap\"><time") | |
| 1305 | 1351 | if templ_7745c5c3_Err != nil { | |
| 1306 | 1352 | return templ_7745c5c3_Err | |
| 1307 | 1353 | } | |
| 1308 | 1354 | if r.LastUsedAt != "" { | |
| 1309 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, " datetime=\"") | |
| 1355 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, " datetime=\"") | |
| 1310 | 1356 | if templ_7745c5c3_Err != nil { | |
| 1311 | 1357 | return templ_7745c5c3_Err | |
| 1312 | 1358 | } | |
| 1313 | - | var templ_7745c5c3_Var64 string | |
| 1314 | - | templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.LastUsedAt) | |
| 1359 | + | var templ_7745c5c3_Var66 string | |
| 1360 | + | templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.LastUsedAt) | |
| 1315 | 1361 | if templ_7745c5c3_Err != nil { | |
| 1316 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 268, Col: 33} | |
| 1362 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 276, Col: 33} | |
| 1317 | 1363 | } | |
| 1318 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64) | |
| 1364 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66) | |
| 1319 | 1365 | if templ_7745c5c3_Err != nil { | |
| 1320 | 1366 | return templ_7745c5c3_Err | |
| 1321 | 1367 | } | |
| 1322 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "\"") | |
| 1368 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\"") | |
| 1323 | 1369 | if templ_7745c5c3_Err != nil { | |
| 1324 | 1370 | return templ_7745c5c3_Err | |
| 1325 | 1371 | } | |
| 1326 | 1372 | } | |
| 1327 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, ">") | |
| 1373 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, ">") | |
| 1328 | 1374 | if templ_7745c5c3_Err != nil { | |
| 1329 | 1375 | return templ_7745c5c3_Err | |
| 1330 | 1376 | } | |
| 1331 | - | var templ_7745c5c3_Var65 string | |
| 1332 | - | templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(r.LastUsed) | |
| 1377 | + | var templ_7745c5c3_Var67 string | |
| 1378 | + | templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(r.LastUsed) | |
| 1333 | 1379 | if templ_7745c5c3_Err != nil { | |
| 1334 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 270, Col: 21} | |
| 1380 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 278, Col: 21} | |
| 1335 | 1381 | } | |
| 1336 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65)) | |
| 1382 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67)) | |
| 1337 | 1383 | if templ_7745c5c3_Err != nil { | |
| 1338 | 1384 | return templ_7745c5c3_Err | |
| 1339 | 1385 | } | |
| 1340 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "</time></td><td class=\"c-sync\">") | |
| 1386 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "</time></td><td class=\"c-sync\">") | |
| 1341 | 1387 | if templ_7745c5c3_Err != nil { | |
| 1342 | 1388 | return templ_7745c5c3_Err | |
| 1343 | 1389 | } | |
| 1344 | 1390 | if r.Synced { | |
| 1345 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "yes") | |
| 1391 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "yes") | |
| 1346 | 1392 | if templ_7745c5c3_Err != nil { | |
| 1347 | 1393 | return templ_7745c5c3_Err | |
| 1348 | 1394 | } | |
| 1349 | 1395 | } else { | |
| 1350 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "no") | |
| 1396 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "no") | |
| 1351 | 1397 | if templ_7745c5c3_Err != nil { | |
| 1352 | 1398 | return templ_7745c5c3_Err | |
| 1353 | 1399 | } | |
| 1354 | 1400 | } | |
| 1355 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, "</td><td class=\"c-act\"><form method=\"post\" action=\"") | |
| 1401 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "</td><td class=\"c-act\"><form method=\"post\" action=\"") | |
| 1356 | 1402 | if templ_7745c5c3_Err != nil { | |
| 1357 | 1403 | return templ_7745c5c3_Err | |
| 1358 | 1404 | } | |
| 1359 | - | var templ_7745c5c3_Var66 templ.SafeURL | |
| 1360 | - | templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Remove)) | |
| 1405 | + | var templ_7745c5c3_Var68 templ.SafeURL | |
| 1406 | + | templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Remove)) | |
| 1361 | 1407 | if templ_7745c5c3_Err != nil { | |
| 1362 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 280, Col: 60} | |
| 1408 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 288, Col: 60} | |
| 1363 | 1409 | } | |
| 1364 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66)) | |
| 1410 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68)) | |
| 1365 | 1411 | if templ_7745c5c3_Err != nil { | |
| 1366 | 1412 | return templ_7745c5c3_Err | |
| 1367 | 1413 | } | |
| 1368 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\"><button type=\"submit\" class=\"btn danger\" aria-label=\"") | |
| 1414 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "\"><button type=\"submit\" class=\"btn danger\" aria-label=\"") | |
| 1369 | 1415 | if templ_7745c5c3_Err != nil { | |
| 1370 | 1416 | return templ_7745c5c3_Err | |
| 1371 | 1417 | } | |
| 1372 | - | var templ_7745c5c3_Var67 string | |
| 1373 | - | templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue("Remove passkey " + r.Name) | |
| 1418 | + | var templ_7745c5c3_Var69 string | |
| 1419 | + | templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.ResolveAttributeValue("Remove passkey " + r.Name) | |
| 1374 | 1420 | if templ_7745c5c3_Err != nil { | |
| 1375 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 281, Col: 89} | |
| 1421 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 289, Col: 89} | |
| 1376 | 1422 | } | |
| 1377 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67) | |
| 1423 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var69) | |
| 1378 | 1424 | if templ_7745c5c3_Err != nil { | |
| 1379 | 1425 | return templ_7745c5c3_Err | |
| 1380 | 1426 | } | |
| 1381 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, "\">Remove</button></form></td></tr>") | |
| 1427 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "\">Remove</button></form></td></tr>") | |
| 1382 | 1428 | if templ_7745c5c3_Err != nil { | |
| 1383 | 1429 | return templ_7745c5c3_Err | |
| 1384 | 1430 | } | |
| 1385 | 1431 | } | |
| 1386 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "</tbody></table>") | |
| 1432 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "</tbody></table>") | |
| 1387 | 1433 | if templ_7745c5c3_Err != nil { | |
| 1388 | 1434 | return templ_7745c5c3_Err | |
| 1389 | 1435 | } | |
| 1390 | 1436 | } else { | |
| 1391 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "<p class=\"lede dim\">no passkeys yet.</p>") | |
| 1437 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "<p class=\"lede dim\">no passkeys yet.</p>") | |
| 1392 | 1438 | if templ_7745c5c3_Err != nil { | |
| 1393 | 1439 | return templ_7745c5c3_Err | |
| 1394 | 1440 | } | |
| 1395 | 1441 | } | |
| 1396 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, " ") | |
| 1442 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, " ") | |
| 1397 | 1443 | if templ_7745c5c3_Err != nil { | |
| 1398 | 1444 | return templ_7745c5c3_Err | |
| 1399 | 1445 | } | |
| 1400 | 1446 | if p.Full { | |
| 1401 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "<p class=\"dim\">") | |
| 1447 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 115, "<p class=\"dim\">") | |
| 1402 | 1448 | if templ_7745c5c3_Err != nil { | |
| 1403 | 1449 | return templ_7745c5c3_Err | |
| 1404 | 1450 | } | |
| 1405 | - | var templ_7745c5c3_Var68 string | |
| 1406 | - | templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Max)) | |
| 1451 | + | var templ_7745c5c3_Var70 string | |
| 1452 | + | templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Max)) | |
| 1407 | 1453 | if templ_7745c5c3_Err != nil { | |
| 1408 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 292, Col: 31} | |
| 1454 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 300, Col: 31} | |
| 1409 | 1455 | } | |
| 1410 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68)) | |
| 1456 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70)) | |
| 1411 | 1457 | if templ_7745c5c3_Err != nil { | |
| 1412 | 1458 | return templ_7745c5c3_Err | |
| 1413 | 1459 | } | |
| 1414 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, " passkeys are registered, the most there can be. Remove one to add another.</p>") | |
| 1460 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, " passkeys are registered, the most there can be. Remove one to add another.</p>") | |
| 1415 | 1461 | if templ_7745c5c3_Err != nil { | |
| 1416 | 1462 | return templ_7745c5c3_Err | |
| 1417 | 1463 | } | |
| 1418 | 1464 | } else { | |
| 1419 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "<form class=\"passkey-add\" data-js data-passkey-form><label for=\"passkey-name\" class=\"sr\">Name of the new passkey</label> <input id=\"passkey-name\" type=\"text\" placeholder=\"Name, for example Pixel 9\" autocomplete=\"off\" data-passkey-name> <button type=\"submit\" class=\"btn primary\" data-passkey=\"register\" data-begin=\"") | |
| 1465 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 117, "<form class=\"passkey-add\" data-js data-passkey-form><label for=\"passkey-name\" class=\"sr\">Name of the new passkey</label> <input id=\"passkey-name\" type=\"text\" placeholder=\"Name, for example Pixel 9\" autocomplete=\"off\" data-passkey-name> <button type=\"submit\" class=\"btn primary\" data-passkey=\"register\" data-begin=\"") | |
| 1420 | 1466 | if templ_7745c5c3_Err != nil { | |
| 1421 | 1467 | return templ_7745c5c3_Err | |
| 1422 | 1468 | } | |
| 1423 | - | var templ_7745c5c3_Var69 string | |
| 1424 | - | templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) | |
| 1469 | + | var templ_7745c5c3_Var71 string | |
| 1470 | + | templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) | |
| 1425 | 1471 | if templ_7745c5c3_Err != nil { | |
| 1426 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 297, Col: 90} | |
| 1472 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 305, Col: 90} | |
| 1427 | 1473 | } | |
| 1428 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var69) | |
| 1474 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71) | |
| 1429 | 1475 | if templ_7745c5c3_Err != nil { | |
| 1430 | 1476 | return templ_7745c5c3_Err | |
| 1431 | 1477 | } | |
| 1432 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "\" data-finish=\"") | |
| 1478 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, "\" data-finish=\"") | |
| 1433 | 1479 | if templ_7745c5c3_Err != nil { | |
| 1434 | 1480 | return templ_7745c5c3_Err | |
| 1435 | 1481 | } | |
| 1436 | - | var templ_7745c5c3_Var70 string | |
| 1437 | - | templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) | |
| 1482 | + | var templ_7745c5c3_Var72 string | |
| 1483 | + | templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) | |
| 1438 | 1484 | if templ_7745c5c3_Err != nil { | |
| 1439 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 297, Col: 115} | |
| 1485 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 305, Col: 115} | |
| 1440 | 1486 | } | |
| 1441 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var70) | |
| 1487 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72) | |
| 1442 | 1488 | if templ_7745c5c3_Err != nil { | |
| 1443 | 1489 | return templ_7745c5c3_Err | |
| 1444 | 1490 | } | |
| 1445 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "\">Add a passkey</button></form>") | |
| 1491 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "\">Add a passkey</button></form>") | |
| 1446 | 1492 | if templ_7745c5c3_Err != nil { | |
| 1447 | 1493 | return templ_7745c5c3_Err | |
| 1448 | 1494 | } | |
| 1449 | 1495 | } | |
| 1450 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, " <p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") | |
| 1496 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, " <p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") | |
| 1451 | 1497 | if templ_7745c5c3_Err != nil { | |
| 1452 | 1498 | return templ_7745c5c3_Err | |
| 1453 | 1499 | } | |
| 1454 | 1500 | return nil | |
| 1455 | 1501 | }) | |
| 1456 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var59), templ_7745c5c3_Buffer) | |
| 1502 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var61), templ_7745c5c3_Buffer) | |
| 1457 | 1503 | if templ_7745c5c3_Err != nil { | |
| 1458 | 1504 | return templ_7745c5c3_Err | |
| 1459 | 1505 | } | |
| @@ -44,89 +44,135 @@ func Home(l Layout, p HomePage) templ.Component { | |||||
| 44 | }() | 44 | }() | ||
| 45 | } | 45 | } | ||
| 46 | ctx = templ.InitializeContext(ctx) | 46 | ctx = templ.InitializeContext(ctx) | ||
| 47 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<h1 class=\"sr\">Repositories</h1><div class=\"home\" data-layout=\"cards\"><section class=\"home-repos\" aria-label=\"Repositories\"><div class=\"home-bar\"><div class=\"filter\"><label for=\"home-filter\" class=\"sr\">filter</label> <input id=\"home-filter\" type=\"search\" data-filter=\"#repo-rows > li\" placeholder=\"Filter repositories…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><nav class=\"sort\" aria-label=\"Sort repositories\"><span class=\"mute\">sort</span> ") | 47 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<h1 class=\"sr\">Repositories</h1><div class=\"home\" data-layout=\"cards\"><section class=\"home-repos\" aria-label=\"Repositories\"><div class=\"home-bar\">") |
| 48 | if templ_7745c5c3_Err != nil { | 48 | if templ_7745c5c3_Err != nil { | ||
| 49 | return templ_7745c5c3_Err | 49 | return templ_7745c5c3_Err | ||
| 50 | } | 50 | } | ||
| 51 | - | for _, s := range p.Sorts { | 51 | + | if p.Inbox != nil { |
| 52 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<a href=\"") | 52 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<a class=\"btn inbox-btn\" href=\"") |
| 53 | if templ_7745c5c3_Err != nil { | 53 | if templ_7745c5c3_Err != nil { | ||
| 54 | return templ_7745c5c3_Err | 54 | return templ_7745c5c3_Err | ||
| 55 | } | 55 | } | ||
| 56 | var templ_7745c5c3_Var3 templ.SafeURL | 56 | var templ_7745c5c3_Var3 templ.SafeURL | ||
| 57 | - | templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href)) | 57 | + | templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Inbox.Href)) |
| 58 | if templ_7745c5c3_Err != nil { | 58 | if templ_7745c5c3_Err != nil { | ||
| 59 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 27, Col: 36} | 59 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 13, Col: 65} |
| 60 | } | 60 | } | ||
| 61 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | 61 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) | ||
| 62 | if templ_7745c5c3_Err != nil { | 62 | if templ_7745c5c3_Err != nil { | ||
| 63 | return templ_7745c5c3_Err | 63 | return templ_7745c5c3_Err | ||
| 64 | } | 64 | } | ||
| 65 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"") | 65 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" title=\"inbox\">Inbox ") |
| 66 | + | if templ_7745c5c3_Err != nil { | |||
| 67 | + | return templ_7745c5c3_Err | |||
| 68 | + | } | |||
| 69 | + | if p.Inbox.Count >= 0 { | |||
| 70 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<span class=\"count\">") | |||
| 71 | + | if templ_7745c5c3_Err != nil { | |||
| 72 | + | return templ_7745c5c3_Err | |||
| 73 | + | } | |||
| 74 | + | var templ_7745c5c3_Var4 string | |||
| 75 | + | templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Inbox.Count)) | |||
| 76 | + | if templ_7745c5c3_Err != nil { | |||
| 77 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 16, Col: 49} | |||
| 78 | + | } | |||
| 79 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) | |||
| 80 | + | if templ_7745c5c3_Err != nil { | |||
| 81 | + | return templ_7745c5c3_Err | |||
| 82 | + | } | |||
| 83 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</span>") | |||
| 84 | + | if templ_7745c5c3_Err != nil { | |||
| 85 | + | return templ_7745c5c3_Err | |||
| 86 | + | } | |||
| 87 | + | } | |||
| 88 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a>") | |||
| 89 | + | if templ_7745c5c3_Err != nil { | |||
| 90 | + | return templ_7745c5c3_Err | |||
| 91 | + | } | |||
| 92 | + | } | |||
| 93 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"filter\"><label for=\"home-filter\" class=\"sr\">filter</label> <input id=\"home-filter\" type=\"search\" data-filter=\"#repo-rows > li\" placeholder=\"Filter repositories…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><nav class=\"sort\" aria-label=\"Sort repositories\"><span class=\"mute\">sort</span> ") | |||
| 94 | + | if templ_7745c5c3_Err != nil { | |||
| 95 | + | return templ_7745c5c3_Err | |||
| 96 | + | } | |||
| 97 | + | for _, s := range p.Sorts { | |||
| 98 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<a href=\"") | |||
| 99 | + | if templ_7745c5c3_Err != nil { | |||
| 100 | + | return templ_7745c5c3_Err | |||
| 101 | + | } | |||
| 102 | + | var templ_7745c5c3_Var5 templ.SafeURL | |||
| 103 | + | templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href)) | |||
| 104 | + | if templ_7745c5c3_Err != nil { | |||
| 105 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 35, Col: 36} | |||
| 106 | + | } | |||
| 107 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) | |||
| 108 | + | if templ_7745c5c3_Err != nil { | |||
| 109 | + | return templ_7745c5c3_Err | |||
| 110 | + | } | |||
| 111 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\"") | |||
| 66 | if templ_7745c5c3_Err != nil { | 112 | if templ_7745c5c3_Err != nil { | ||
| 67 | return templ_7745c5c3_Err | 113 | return templ_7745c5c3_Err | ||
| 68 | } | 114 | } | ||
| 69 | if s.Mark != "" { | 115 | if s.Mark != "" { | ||
| 70 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " aria-current=\"true\"") | 116 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " aria-current=\"true\"") |
| 71 | if templ_7745c5c3_Err != nil { | 117 | if templ_7745c5c3_Err != nil { | ||
| 72 | return templ_7745c5c3_Err | 118 | return templ_7745c5c3_Err | ||
| 73 | } | 119 | } | ||
| 74 | } | 120 | } | ||
| 75 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, ">") | 121 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, ">") |
| 76 | if templ_7745c5c3_Err != nil { | 122 | if templ_7745c5c3_Err != nil { | ||
| 77 | return templ_7745c5c3_Err | 123 | return templ_7745c5c3_Err | ||
| 78 | } | 124 | } | ||
| 79 | - | var templ_7745c5c3_Var4 string | 125 | + | var templ_7745c5c3_Var6 string |
| 80 | - | templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label) | 126 | + | templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label) |
| 81 | if templ_7745c5c3_Err != nil { | 127 | if templ_7745c5c3_Err != nil { | ||
| 82 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 32, Col: 17} | 128 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 40, Col: 17} |
| 83 | } | 129 | } | ||
| 84 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) | 130 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) |
| 85 | if templ_7745c5c3_Err != nil { | 131 | if templ_7745c5c3_Err != nil { | ||
| 86 | return templ_7745c5c3_Err | 132 | return templ_7745c5c3_Err | ||
| 87 | } | 133 | } | ||
| 88 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") | 134 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " ") |
| 89 | if templ_7745c5c3_Err != nil { | 135 | if templ_7745c5c3_Err != nil { | ||
| 90 | return templ_7745c5c3_Err | 136 | return templ_7745c5c3_Err | ||
| 91 | } | 137 | } | ||
| 92 | if s.Mark != "" { | 138 | if s.Mark != "" { | ||
| 93 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<span aria-hidden=\"true\">") | 139 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<span aria-hidden=\"true\">") |
| 94 | if templ_7745c5c3_Err != nil { | 140 | if templ_7745c5c3_Err != nil { | ||
| 95 | return templ_7745c5c3_Err | 141 | return templ_7745c5c3_Err | ||
| 96 | } | 142 | } | ||
| 97 | - | var templ_7745c5c3_Var5 string | 143 | + | var templ_7745c5c3_Var7 string |
| 98 | - | templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(s.Mark) | 144 | + | templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(s.Mark) |
| 99 | if templ_7745c5c3_Err != nil { | 145 | if templ_7745c5c3_Err != nil { | ||
| 100 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 34, Col: 42} | 146 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 42, Col: 42} |
| 101 | } | 147 | } | ||
| 102 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) | 148 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) |
| 103 | if templ_7745c5c3_Err != nil { | 149 | if templ_7745c5c3_Err != nil { | ||
| 104 | return templ_7745c5c3_Err | 150 | return templ_7745c5c3_Err | ||
| 105 | } | 151 | } | ||
| 106 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</span> <span class=\"sr\">") | 152 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</span> <span class=\"sr\">") |
| 107 | if templ_7745c5c3_Err != nil { | 153 | if templ_7745c5c3_Err != nil { | ||
| 108 | return templ_7745c5c3_Err | 154 | return templ_7745c5c3_Err | ||
| 109 | } | 155 | } | ||
| 110 | - | var templ_7745c5c3_Var6 string | 156 | + | var templ_7745c5c3_Var8 string |
| 111 | - | templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(", " + s.State) | 157 | + | templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(", " + s.State) |
| 112 | if templ_7745c5c3_Err != nil { | 158 | if templ_7745c5c3_Err != nil { | ||
| 113 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 35, Col: 42} | 159 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 43, Col: 42} |
| 114 | } | 160 | } | ||
| 115 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) | 161 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) |
| 116 | if templ_7745c5c3_Err != nil { | 162 | if templ_7745c5c3_Err != nil { | ||
| 117 | return templ_7745c5c3_Err | 163 | return templ_7745c5c3_Err | ||
| 118 | } | 164 | } | ||
| 119 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</span>") | 165 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</span>") |
| 120 | if templ_7745c5c3_Err != nil { | 166 | if templ_7745c5c3_Err != nil { | ||
| 121 | return templ_7745c5c3_Err | 167 | return templ_7745c5c3_Err | ||
| 122 | } | 168 | } | ||
| 123 | } | 169 | } | ||
| 124 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</a>") | 170 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</a>") |
| 125 | if templ_7745c5c3_Err != nil { | 171 | if templ_7745c5c3_Err != nil { | ||
| 126 | return templ_7745c5c3_Err | 172 | return templ_7745c5c3_Err | ||
| 127 | } | 173 | } | ||
| 128 | } | 174 | } | ||
| 129 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</nav><div class=\"layout-switch\" role=\"group\" aria-label=\"Layout\" data-js><button type=\"button\" class=\"btn icon\" data-set-layout=\"cards\" aria-pressed=\"true\" title=\"Cards\" aria-label=\"Cards\"><span class=\"ico i-cards\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"split\" aria-pressed=\"false\" title=\"Two columns\" aria-label=\"Two columns\"><span class=\"ico i-split\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"compact\" aria-pressed=\"false\" title=\"Compact list\" aria-label=\"Compact list\"><span class=\"ico i-compact\" aria-hidden=\"true\"></span></button></div></div><ul class=\"repos\" id=\"repo-rows\" data-rows>") | 175 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</nav><div class=\"layout-switch\" role=\"group\" aria-label=\"Layout\" data-js><button type=\"button\" class=\"btn icon\" data-set-layout=\"cards\" aria-pressed=\"true\" title=\"Cards\" aria-label=\"Cards\"><span class=\"ico i-cards\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"split\" aria-pressed=\"false\" title=\"Two columns\" aria-label=\"Two columns\"><span class=\"ico i-split\" aria-hidden=\"true\"></span></button> <button type=\"button\" class=\"btn icon\" data-set-layout=\"compact\" aria-pressed=\"false\" title=\"Compact list\" aria-label=\"Compact list\"><span class=\"ico i-compact\" aria-hidden=\"true\"></span></button></div></div><ul class=\"repos\" id=\"repo-rows\" data-rows>") |
| 130 | if templ_7745c5c3_Err != nil { | 176 | if templ_7745c5c3_Err != nil { | ||
| 131 | return templ_7745c5c3_Err | 177 | return templ_7745c5c3_Err | ||
| 132 | } | 178 | } | ||
| @@ -136,17 +182,17 @@ func Home(l Layout, p HomePage) templ.Component { | |||||
| 136 | return templ_7745c5c3_Err | 182 | return templ_7745c5c3_Err | ||
| 137 | } | 183 | } | ||
| 138 | } | 184 | } | ||
| 139 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</ul>") | 185 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</ul>") |
| 140 | if templ_7745c5c3_Err != nil { | 186 | if templ_7745c5c3_Err != nil { | ||
| 141 | return templ_7745c5c3_Err | 187 | return templ_7745c5c3_Err | ||
| 142 | } | 188 | } | ||
| 143 | if len(p.Rows) == 0 { | 189 | if len(p.Rows) == 0 { | ||
| 144 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<p class=\"lede dim\">no repositories yet.</p>") | 190 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<p class=\"lede dim\">no repositories yet.</p>") |
| 145 | if templ_7745c5c3_Err != nil { | 191 | if templ_7745c5c3_Err != nil { | ||
| 146 | return templ_7745c5c3_Err | 192 | return templ_7745c5c3_Err | ||
| 147 | } | 193 | } | ||
| 148 | } | 194 | } | ||
| 149 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</section></div>") | 195 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</section></div>") |
| 150 | if templ_7745c5c3_Err != nil { | 196 | if templ_7745c5c3_Err != nil { | ||
| 151 | return templ_7745c5c3_Err | 197 | return templ_7745c5c3_Err | ||
| 152 | } | 198 | } | ||
| @@ -178,12 +224,12 @@ func Summary(l Layout, p SummaryPage) templ.Component { | |||||
| 178 | }() | 224 | }() | ||
| 179 | } | 225 | } | ||
| 180 | ctx = templ.InitializeContext(ctx) | 226 | ctx = templ.InitializeContext(ctx) | ||
| 181 | - | templ_7745c5c3_Var7 := templ.GetChildren(ctx) | 227 | + | templ_7745c5c3_Var9 := templ.GetChildren(ctx) |
| 182 | - | if templ_7745c5c3_Var7 == nil { | 228 | + | if templ_7745c5c3_Var9 == nil { |
| 183 | - | templ_7745c5c3_Var7 = templ.NopComponent | 229 | + | templ_7745c5c3_Var9 = templ.NopComponent |
| 184 | } | 230 | } | ||
| 185 | ctx = templ.ClearChildren(ctx) | 231 | ctx = templ.ClearChildren(ctx) | ||
| 186 | - | templ_7745c5c3_Var8 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 232 | + | templ_7745c5c3_Var10 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
| 187 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | 233 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||
| 188 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 234 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||
| 189 | if !templ_7745c5c3_IsBuffer { | 235 | if !templ_7745c5c3_IsBuffer { | ||
| @@ -203,7 +249,7 @@ func Summary(l Layout, p SummaryPage) templ.Component { | |||||
| 203 | } | 249 | } | ||
| 204 | return nil | 250 | return nil | ||
| 205 | }) | 251 | }) | ||
| 206 | - | templ_7745c5c3_Err = Shell(l, summaryRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var8), templ_7745c5c3_Buffer) | 252 | + | templ_7745c5c3_Err = Shell(l, summaryRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var10), templ_7745c5c3_Buffer) |
| 207 | if templ_7745c5c3_Err != nil { | 253 | if templ_7745c5c3_Err != nil { | ||
| 208 | return templ_7745c5c3_Err | 254 | return templ_7745c5c3_Err | ||
| 209 | } | 255 | } | ||
| @@ -230,158 +276,158 @@ func latestTagFact(t LatestTag) templ.Component { | |||||
| 230 | }() | 276 | }() | ||
| 231 | } | 277 | } | ||
| 232 | ctx = templ.InitializeContext(ctx) | 278 | ctx = templ.InitializeContext(ctx) | ||
| 233 | - | templ_7745c5c3_Var9 := templ.GetChildren(ctx) | 279 | + | templ_7745c5c3_Var11 := templ.GetChildren(ctx) |
| 234 | - | if templ_7745c5c3_Var9 == nil { | 280 | + | if templ_7745c5c3_Var11 == nil { |
| 235 | - | templ_7745c5c3_Var9 = templ.NopComponent | 281 | + | templ_7745c5c3_Var11 = templ.NopComponent |
| 236 | } | 282 | } | ||
| 237 | ctx = templ.ClearChildren(ctx) | 283 | ctx = templ.ClearChildren(ctx) | ||
| 238 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<dt>latest tag</dt><dd class=\"latest-tag\">") | 284 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<dt>latest tag</dt><dd class=\"latest-tag\">") |
| 239 | if templ_7745c5c3_Err != nil { | 285 | if templ_7745c5c3_Err != nil { | ||
| 240 | return templ_7745c5c3_Err | 286 | return templ_7745c5c3_Err | ||
| 241 | } | 287 | } | ||
| 242 | if t.Name != "" { | 288 | if t.Name != "" { | ||
| 243 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<a class=\"tag-name\" href=\"") | 289 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<a class=\"tag-name\" href=\"") |
| 244 | if templ_7745c5c3_Err != nil { | 290 | if templ_7745c5c3_Err != nil { | ||
| 245 | return templ_7745c5c3_Err | 291 | return templ_7745c5c3_Err | ||
| 246 | } | 292 | } | ||
| 247 | - | var templ_7745c5c3_Var10 templ.SafeURL | 293 | + | var templ_7745c5c3_Var12 templ.SafeURL |
| 248 | - | templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.Href)) | 294 | + | templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.Href)) |
| 249 | if templ_7745c5c3_Err != nil { | 295 | if templ_7745c5c3_Err != nil { | ||
| 250 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 82, Col: 51} | 296 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 90, Col: 51} |
| 251 | } | 297 | } | ||
| 252 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) | 298 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) |
| 253 | if templ_7745c5c3_Err != nil { | 299 | if templ_7745c5c3_Err != nil { | ||
| 254 | return templ_7745c5c3_Err | 300 | return templ_7745c5c3_Err | ||
| 255 | } | 301 | } | ||
| 256 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" title=\"") | 302 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" title=\"") |
| 257 | if templ_7745c5c3_Err != nil { | 303 | if templ_7745c5c3_Err != nil { | ||
| 258 | return templ_7745c5c3_Err | 304 | return templ_7745c5c3_Err | ||
| 259 | } | 305 | } | ||
| 260 | - | var templ_7745c5c3_Var11 string | 306 | + | var templ_7745c5c3_Var13 string |
| 261 | - | templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.Subject) | 307 | + | templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.Subject) |
| 262 | if templ_7745c5c3_Err != nil { | 308 | if templ_7745c5c3_Err != nil { | ||
| 263 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 82, Col: 71} | 309 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 90, Col: 71} |
| 264 | } | 310 | } | ||
| 265 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11) | 311 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var13) |
| 266 | if templ_7745c5c3_Err != nil { | 312 | if templ_7745c5c3_Err != nil { | ||
| 267 | return templ_7745c5c3_Err | 313 | return templ_7745c5c3_Err | ||
| 268 | } | 314 | } | ||
| 269 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">") | 315 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\">") |
| 270 | if templ_7745c5c3_Err != nil { | 316 | if templ_7745c5c3_Err != nil { | ||
| 271 | return templ_7745c5c3_Err | 317 | return templ_7745c5c3_Err | ||
| 272 | } | 318 | } | ||
| 273 | - | var templ_7745c5c3_Var12 string | 319 | + | var templ_7745c5c3_Var14 string |
| 274 | - | templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(t.Name) | 320 | + | templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(t.Name) |
| 275 | if templ_7745c5c3_Err != nil { | 321 | if templ_7745c5c3_Err != nil { | ||
| 276 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 82, Col: 82} | 322 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 90, Col: 82} |
| 277 | } | 323 | } | ||
| 278 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) | 324 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) |
| 279 | if templ_7745c5c3_Err != nil { | 325 | if templ_7745c5c3_Err != nil { | ||
| 280 | return templ_7745c5c3_Err | 326 | return templ_7745c5c3_Err | ||
| 281 | } | 327 | } | ||
| 282 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</a> ") | 328 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</a> ") |
| 283 | if templ_7745c5c3_Err != nil { | 329 | if templ_7745c5c3_Err != nil { | ||
| 284 | return templ_7745c5c3_Err | 330 | return templ_7745c5c3_Err | ||
| 285 | } | 331 | } | ||
| 286 | if t.WhenAt != "" { | 332 | if t.WhenAt != "" { | ||
| 287 | - | var templ_7745c5c3_Var13 string | 333 | + | var templ_7745c5c3_Var15 string |
| 288 | - | templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") | 334 | + | templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") |
| 289 | if templ_7745c5c3_Err != nil { | 335 | if templ_7745c5c3_Err != nil { | ||
| 290 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 12} | 336 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 12} |
| 291 | } | 337 | } | ||
| 292 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) | 338 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) |
| 293 | if templ_7745c5c3_Err != nil { | 339 | if templ_7745c5c3_Err != nil { | ||
| 294 | return templ_7745c5c3_Err | 340 | return templ_7745c5c3_Err | ||
| 295 | } | 341 | } | ||
| 296 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<time datetime=\"") | 342 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<time datetime=\"") |
| 297 | if templ_7745c5c3_Err != nil { | 343 | if templ_7745c5c3_Err != nil { | ||
| 298 | return templ_7745c5c3_Err | 344 | return templ_7745c5c3_Err | ||
| 299 | } | 345 | } | ||
| 300 | - | var templ_7745c5c3_Var14 string | 346 | + | var templ_7745c5c3_Var16 string |
| 301 | - | templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) | 347 | + | templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) |
| 302 | if templ_7745c5c3_Err != nil { | 348 | if templ_7745c5c3_Err != nil { | ||
| 303 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 39} | 349 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 39} |
| 304 | } | 350 | } | ||
| 305 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var14) | 351 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var16) |
| 306 | if templ_7745c5c3_Err != nil { | 352 | if templ_7745c5c3_Err != nil { | ||
| 307 | return templ_7745c5c3_Err | 353 | return templ_7745c5c3_Err | ||
| 308 | } | 354 | } | ||
| 309 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\" title=\"") | 355 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" title=\"") |
| 310 | if templ_7745c5c3_Err != nil { | 356 | if templ_7745c5c3_Err != nil { | ||
| 311 | return templ_7745c5c3_Err | 357 | return templ_7745c5c3_Err | ||
| 312 | } | 358 | } | ||
| 313 | - | var templ_7745c5c3_Var15 string | 359 | + | var templ_7745c5c3_Var17 string |
| 314 | - | templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) | 360 | + | templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.ResolveAttributeValue(t.WhenAt) |
| 315 | if templ_7745c5c3_Err != nil { | 361 | if templ_7745c5c3_Err != nil { | ||
| 316 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 58} | 362 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 58} |
| 317 | } | 363 | } | ||
| 318 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15) | 364 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17) |
| 319 | if templ_7745c5c3_Err != nil { | 365 | if templ_7745c5c3_Err != nil { | ||
| 320 | return templ_7745c5c3_Err | 366 | return templ_7745c5c3_Err | ||
| 321 | } | 367 | } | ||
| 322 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">") | 368 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\">") |
| 323 | if templ_7745c5c3_Err != nil { | 369 | if templ_7745c5c3_Err != nil { | ||
| 324 | return templ_7745c5c3_Err | 370 | return templ_7745c5c3_Err | ||
| 325 | } | 371 | } | ||
| 326 | - | var templ_7745c5c3_Var16 string | 372 | + | var templ_7745c5c3_Var18 string |
| 327 | - | templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(t.When) | 373 | + | templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(t.When) |
| 328 | if templ_7745c5c3_Err != nil { | 374 | if templ_7745c5c3_Err != nil { | ||
| 329 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 84, Col: 69} | 375 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 92, Col: 69} |
| 330 | } | 376 | } | ||
| 331 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) | 377 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) |
| 332 | if templ_7745c5c3_Err != nil { | 378 | if templ_7745c5c3_Err != nil { | ||
| 333 | return templ_7745c5c3_Err | 379 | return templ_7745c5c3_Err | ||
| 334 | } | 380 | } | ||
| 335 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</time>") | 381 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</time>") |
| 336 | if templ_7745c5c3_Err != nil { | 382 | if templ_7745c5c3_Err != nil { | ||
| 337 | return templ_7745c5c3_Err | 383 | return templ_7745c5c3_Err | ||
| 338 | } | 384 | } | ||
| 339 | } | 385 | } | ||
| 340 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, " ") | 386 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " ") |
| 341 | if templ_7745c5c3_Err != nil { | 387 | if templ_7745c5c3_Err != nil { | ||
| 342 | return templ_7745c5c3_Err | 388 | return templ_7745c5c3_Err | ||
| 343 | } | 389 | } | ||
| 344 | - | var templ_7745c5c3_Var17 string | 390 | + | var templ_7745c5c3_Var19 string |
| 345 | - | templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") | 391 | + | templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(" · ") |
| 346 | if templ_7745c5c3_Err != nil { | 392 | if templ_7745c5c3_Err != nil { | ||
| 347 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 86, Col: 11} | 393 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 94, Col: 11} |
| 348 | } | 394 | } | ||
| 349 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) | 395 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) |
| 350 | if templ_7745c5c3_Err != nil { | 396 | if templ_7745c5c3_Err != nil { | ||
| 351 | return templ_7745c5c3_Err | 397 | return templ_7745c5c3_Err | ||
| 352 | } | 398 | } | ||
| 353 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " ") | 399 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, " ") |
| 354 | if templ_7745c5c3_Err != nil { | 400 | if templ_7745c5c3_Err != nil { | ||
| 355 | return templ_7745c5c3_Err | 401 | return templ_7745c5c3_Err | ||
| 356 | } | 402 | } | ||
| 357 | } | 403 | } | ||
| 358 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a class=\"all-tags\" href=\"") | 404 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<a class=\"all-tags\" href=\"") |
| 359 | if templ_7745c5c3_Err != nil { | 405 | if templ_7745c5c3_Err != nil { | ||
| 360 | return templ_7745c5c3_Err | 406 | return templ_7745c5c3_Err | ||
| 361 | } | 407 | } | ||
| 362 | - | var templ_7745c5c3_Var18 templ.SafeURL | 408 | + | var templ_7745c5c3_Var20 templ.SafeURL |
| 363 | - | templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.RefsHref)) | 409 | + | templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(t.RefsHref)) |
| 364 | if templ_7745c5c3_Err != nil { | 410 | if templ_7745c5c3_Err != nil { | ||
| 365 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 88, Col: 54} | 411 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 96, Col: 54} |
| 366 | } | 412 | } | ||
| 367 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) | 413 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) |
| 368 | if templ_7745c5c3_Err != nil { | 414 | if templ_7745c5c3_Err != nil { | ||
| 369 | return templ_7745c5c3_Err | 415 | return templ_7745c5c3_Err | ||
| 370 | } | 416 | } | ||
| 371 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">") | 417 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "\">") |
| 372 | if templ_7745c5c3_Err != nil { | 418 | if templ_7745c5c3_Err != nil { | ||
| 373 | return templ_7745c5c3_Err | 419 | return templ_7745c5c3_Err | ||
| 374 | } | 420 | } | ||
| 375 | - | var templ_7745c5c3_Var19 string | 421 | + | var templ_7745c5c3_Var21 string |
| 376 | - | templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(plural(t.Count, "tag", "tags")) | 422 | + | templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(plural(t.Count, "tag", "tags")) |
| 377 | if templ_7745c5c3_Err != nil { | 423 | if templ_7745c5c3_Err != nil { | ||
| 378 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 88, Col: 89} | 424 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 96, Col: 89} |
| 379 | } | 425 | } | ||
| 380 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) | 426 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) |
| 381 | if templ_7745c5c3_Err != nil { | 427 | if templ_7745c5c3_Err != nil { | ||
| 382 | return templ_7745c5c3_Err | 428 | return templ_7745c5c3_Err | ||
| 383 | } | 429 | } | ||
| 384 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a></dd>") | 430 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</a></dd>") |
| 385 | if templ_7745c5c3_Err != nil { | 431 | if templ_7745c5c3_Err != nil { | ||
| 386 | return templ_7745c5c3_Err | 432 | return templ_7745c5c3_Err | ||
| 387 | } | 433 | } | ||
| @@ -405,12 +451,12 @@ func summaryRail(p SummaryPage) templ.Component { | |||||
| 405 | }() | 451 | }() | ||
| 406 | } | 452 | } | ||
| 407 | ctx = templ.InitializeContext(ctx) | 453 | ctx = templ.InitializeContext(ctx) | ||
| 408 | - | templ_7745c5c3_Var20 := templ.GetChildren(ctx) | 454 | + | templ_7745c5c3_Var22 := templ.GetChildren(ctx) |
| 409 | - | if templ_7745c5c3_Var20 == nil { | 455 | + | if templ_7745c5c3_Var22 == nil { |
| 410 | - | templ_7745c5c3_Var20 = templ.NopComponent | 456 | + | templ_7745c5c3_Var22 = templ.NopComponent |
| 411 | } | 457 | } | ||
| 412 | ctx = templ.ClearChildren(ctx) | 458 | ctx = templ.ClearChildren(ctx) | ||
| 413 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<section aria-labelledby=\"r-clone\"><h2 id=\"r-clone\">Clone</h2>") | 459 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<section aria-labelledby=\"r-clone\"><h2 id=\"r-clone\">Clone</h2>") |
| 414 | if templ_7745c5c3_Err != nil { | 460 | if templ_7745c5c3_Err != nil { | ||
| 415 | return templ_7745c5c3_Err | 461 | return templ_7745c5c3_Err | ||
| 416 | } | 462 | } | ||
| @@ -418,25 +464,25 @@ func summaryRail(p SummaryPage) templ.Component { | |||||
| 418 | if templ_7745c5c3_Err != nil { | 464 | if templ_7745c5c3_Err != nil { | ||
| 419 | return templ_7745c5c3_Err | 465 | return templ_7745c5c3_Err | ||
| 420 | } | 466 | } | ||
| 421 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</section><section aria-labelledby=\"r-facts\"><h2 id=\"r-facts\">About</h2><dl class=\"kv\">") | 467 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</section><section aria-labelledby=\"r-facts\"><h2 id=\"r-facts\">About</h2><dl class=\"kv\">") |
| 422 | if templ_7745c5c3_Err != nil { | 468 | if templ_7745c5c3_Err != nil { | ||
| 423 | return templ_7745c5c3_Err | 469 | return templ_7745c5c3_Err | ||
| 424 | } | 470 | } | ||
| 425 | for _, f := range p.Facts { | 471 | for _, f := range p.Facts { | ||
| 426 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<dt>") | 472 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<dt>") |
| 427 | if templ_7745c5c3_Err != nil { | 473 | if templ_7745c5c3_Err != nil { | ||
| 428 | return templ_7745c5c3_Err | 474 | return templ_7745c5c3_Err | ||
| 429 | } | 475 | } | ||
| 430 | - | var templ_7745c5c3_Var21 string | 476 | + | var templ_7745c5c3_Var23 string |
| 431 | - | templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(f.Key) | 477 | + | templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(f.Key) |
| 432 | if templ_7745c5c3_Err != nil { | 478 | if templ_7745c5c3_Err != nil { | ||
| 433 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 99, Col: 15} | 479 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 107, Col: 15} |
| 434 | } | 480 | } | ||
| 435 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) | 481 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) |
| 436 | if templ_7745c5c3_Err != nil { | 482 | if templ_7745c5c3_Err != nil { | ||
| 437 | return templ_7745c5c3_Err | 483 | return templ_7745c5c3_Err | ||
| 438 | } | 484 | } | ||
| 439 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</dt>") | 485 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</dt>") |
| 440 | if templ_7745c5c3_Err != nil { | 486 | if templ_7745c5c3_Err != nil { | ||
| 441 | return templ_7745c5c3_Err | 487 | return templ_7745c5c3_Err | ||
| 442 | } | 488 | } | ||
| @@ -451,25 +497,25 @@ func summaryRail(p SummaryPage) templ.Component { | |||||
| 451 | return templ_7745c5c3_Err | 497 | return templ_7745c5c3_Err | ||
| 452 | } | 498 | } | ||
| 453 | } | 499 | } | ||
| 454 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</dl></section>") | 500 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</dl></section>") |
| 455 | if templ_7745c5c3_Err != nil { | 501 | if templ_7745c5c3_Err != nil { | ||
| 456 | return templ_7745c5c3_Err | 502 | return templ_7745c5c3_Err | ||
| 457 | } | 503 | } | ||
| 458 | if len(p.Recent) > 0 { | 504 | if len(p.Recent) > 0 { | ||
| 459 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<section aria-labelledby=\"r-recent\"><h2 id=\"r-recent\">Recent commits <a href=\"") | 505 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "<section aria-labelledby=\"r-recent\"><h2 id=\"r-recent\">Recent commits <a href=\"") |
| 460 | if templ_7745c5c3_Err != nil { | 506 | if templ_7745c5c3_Err != nil { | ||
| 461 | return templ_7745c5c3_Err | 507 | return templ_7745c5c3_Err | ||
| 462 | } | 508 | } | ||
| 463 | - | var templ_7745c5c3_Var22 templ.SafeURL | 509 | + | var templ_7745c5c3_Var24 templ.SafeURL |
| 464 | - | templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.AllHref)) | 510 | + | templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.AllHref)) |
| 465 | if templ_7745c5c3_Err != nil { | 511 | if templ_7745c5c3_Err != nil { | ||
| 466 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 108, Col: 105} | 512 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 116, Col: 105} |
| 467 | } | 513 | } | ||
| 468 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) | 514 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) |
| 469 | if templ_7745c5c3_Err != nil { | 515 | if templ_7745c5c3_Err != nil { | ||
| 470 | return templ_7745c5c3_Err | 516 | return templ_7745c5c3_Err | ||
| 471 | } | 517 | } | ||
| 472 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "\">View all</a></h2>") | 518 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\">View all</a></h2>") |
| 473 | if templ_7745c5c3_Err != nil { | 519 | if templ_7745c5c3_Err != nil { | ||
| 474 | return templ_7745c5c3_Err | 520 | return templ_7745c5c3_Err | ||
| 475 | } | 521 | } | ||
| @@ -477,7 +523,7 @@ func summaryRail(p SummaryPage) templ.Component { | |||||
| 477 | if templ_7745c5c3_Err != nil { | 523 | if templ_7745c5c3_Err != nil { | ||
| 478 | return templ_7745c5c3_Err | 524 | return templ_7745c5c3_Err | ||
| 479 | } | 525 | } | ||
| 480 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</section>") | 526 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "</section>") |
| 481 | if templ_7745c5c3_Err != nil { | 527 | if templ_7745c5c3_Err != nil { | ||
| 482 | return templ_7745c5c3_Err | 528 | return templ_7745c5c3_Err | ||
| 483 | } | 529 | } | ||
| @@ -489,7 +535,7 @@ func summaryRail(p SummaryPage) templ.Component { | |||||
| 489 | } | 535 | } | ||
| 490 | } | 536 | } | ||
| 491 | if len(p.Outline) > 0 && p.Readme != nil { | 537 | if len(p.Outline) > 0 && p.Readme != nil { | ||
| 492 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<section aria-labelledby=\"r-outline\"><h2 id=\"r-outline\">On this page</h2>") | 538 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "<section aria-labelledby=\"r-outline\"><h2 id=\"r-outline\">On this page</h2>") |
| 493 | if templ_7745c5c3_Err != nil { | 539 | if templ_7745c5c3_Err != nil { | ||
| 494 | return templ_7745c5c3_Err | 540 | return templ_7745c5c3_Err | ||
| 495 | } | 541 | } | ||
| @@ -497,7 +543,7 @@ func summaryRail(p SummaryPage) templ.Component { | |||||
| 497 | if templ_7745c5c3_Err != nil { | 543 | if templ_7745c5c3_Err != nil { | ||
| 498 | return templ_7745c5c3_Err | 544 | return templ_7745c5c3_Err | ||
| 499 | } | 545 | } | ||
| 500 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</section>") | 546 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</section>") |
| 501 | if templ_7745c5c3_Err != nil { | 547 | if templ_7745c5c3_Err != nil { | ||
| 502 | return templ_7745c5c3_Err | 548 | return templ_7745c5c3_Err | ||
| 503 | } | 549 | } | ||
| @@ -523,12 +569,12 @@ func Refs(l Layout, p RefsPage) templ.Component { | |||||
| 523 | }() | 569 | }() | ||
| 524 | } | 570 | } | ||
| 525 | ctx = templ.InitializeContext(ctx) | 571 | ctx = templ.InitializeContext(ctx) | ||
| 526 | - | templ_7745c5c3_Var23 := templ.GetChildren(ctx) | 572 | + | templ_7745c5c3_Var25 := templ.GetChildren(ctx) |
| 527 | - | if templ_7745c5c3_Var23 == nil { | 573 | + | if templ_7745c5c3_Var25 == nil { |
| 528 | - | templ_7745c5c3_Var23 = templ.NopComponent | 574 | + | templ_7745c5c3_Var25 = templ.NopComponent |
| 529 | } | 575 | } | ||
| 530 | ctx = templ.ClearChildren(ctx) | 576 | ctx = templ.ClearChildren(ctx) | ||
| 531 | - | templ_7745c5c3_Var24 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 577 | + | templ_7745c5c3_Var26 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
| 532 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | 578 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||
| 533 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 579 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||
| 534 | if !templ_7745c5c3_IsBuffer { | 580 | if !templ_7745c5c3_IsBuffer { | ||
| @@ -540,7 +586,7 @@ func Refs(l Layout, p RefsPage) templ.Component { | |||||
| 540 | }() | 586 | }() | ||
| 541 | } | 587 | } | ||
| 542 | ctx = templ.InitializeContext(ctx) | 588 | ctx = templ.InitializeContext(ctx) | ||
| 543 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<div class=\"filter\"><label for=\"ref-filter\" class=\"sr\">filter</label> <input id=\"ref-filter\" type=\"search\" data-filter=\"#ref-rows > tr\" placeholder=\"Filter branches and tags…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><table class=\"list refs\" aria-label=\"Branches and tags\"><thead><tr><th class=\"c-kind\">kind</th><th class=\"c-name\">name</th><th class=\"c-sha\">commit</th><th class=\"c-sub\">subject</th><th class=\"c-when\">date</th></tr></thead>") | 589 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<div class=\"filter\"><label for=\"ref-filter\" class=\"sr\">filter</label> <input id=\"ref-filter\" type=\"search\" data-filter=\"#ref-rows > tr\" placeholder=\"Filter branches and tags…\" autocomplete=\"off\" hx-on:input=\"ermite.filter(this)\"></div><table class=\"list refs\" aria-label=\"Branches and tags\"><thead><tr><th class=\"c-kind\">kind</th><th class=\"c-name\">name</th><th class=\"c-sha\">commit</th><th class=\"c-sub\">subject</th><th class=\"c-when\">date</th></tr></thead>") |
| 544 | if templ_7745c5c3_Err != nil { | 590 | if templ_7745c5c3_Err != nil { | ||
| 545 | return templ_7745c5c3_Err | 591 | return templ_7745c5c3_Err | ||
| 546 | } | 592 | } | ||
| @@ -548,32 +594,32 @@ func Refs(l Layout, p RefsPage) templ.Component { | |||||
| 548 | if templ_7745c5c3_Err != nil { | 594 | if templ_7745c5c3_Err != nil { | ||
| 549 | return templ_7745c5c3_Err | 595 | return templ_7745c5c3_Err | ||
| 550 | } | 596 | } | ||
| 551 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</table>") | 597 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "</table>") |
| 552 | if templ_7745c5c3_Err != nil { | 598 | if templ_7745c5c3_Err != nil { | ||
| 553 | return templ_7745c5c3_Err | 599 | return templ_7745c5c3_Err | ||
| 554 | } | 600 | } | ||
| 555 | if p.Note != "" { | 601 | if p.Note != "" { | ||
| 556 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<p class=\"note\">") | 602 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "<p class=\"note\">") |
| 557 | if templ_7745c5c3_Err != nil { | 603 | if templ_7745c5c3_Err != nil { | ||
| 558 | return templ_7745c5c3_Err | 604 | return templ_7745c5c3_Err | ||
| 559 | } | 605 | } | ||
| 560 | - | var templ_7745c5c3_Var25 string | 606 | + | var templ_7745c5c3_Var27 string |
| 561 | - | templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note) | 607 | + | templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note) |
| 562 | if templ_7745c5c3_Err != nil { | 608 | if templ_7745c5c3_Err != nil { | ||
| 563 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 141, Col: 27} | 609 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 149, Col: 27} |
| 564 | } | 610 | } | ||
| 565 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) | 611 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) |
| 566 | if templ_7745c5c3_Err != nil { | 612 | if templ_7745c5c3_Err != nil { | ||
| 567 | return templ_7745c5c3_Err | 613 | return templ_7745c5c3_Err | ||
| 568 | } | 614 | } | ||
| 569 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "</p>") | 615 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "</p>") |
| 570 | if templ_7745c5c3_Err != nil { | 616 | if templ_7745c5c3_Err != nil { | ||
| 571 | return templ_7745c5c3_Err | 617 | return templ_7745c5c3_Err | ||
| 572 | } | 618 | } | ||
| 573 | } | 619 | } | ||
| 574 | return nil | 620 | return nil | ||
| 575 | }) | 621 | }) | ||
| 576 | - | templ_7745c5c3_Err = Shell(l, refsRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var24), templ_7745c5c3_Buffer) | 622 | + | templ_7745c5c3_Err = Shell(l, refsRail(p)).Render(templ.WithChildren(ctx, templ_7745c5c3_Var26), templ_7745c5c3_Buffer) |
| 577 | if templ_7745c5c3_Err != nil { | 623 | if templ_7745c5c3_Err != nil { | ||
| 578 | return templ_7745c5c3_Err | 624 | return templ_7745c5c3_Err | ||
| 579 | } | 625 | } | ||
| @@ -597,112 +643,112 @@ func refRow(kind string, r RefRow) templ.Component { | |||||
| 597 | }() | 643 | }() | ||
| 598 | } | 644 | } | ||
| 599 | ctx = templ.InitializeContext(ctx) | 645 | ctx = templ.InitializeContext(ctx) | ||
| 600 | - | templ_7745c5c3_Var26 := templ.GetChildren(ctx) | 646 | + | templ_7745c5c3_Var28 := templ.GetChildren(ctx) |
| 601 | - | if templ_7745c5c3_Var26 == nil { | 647 | + | if templ_7745c5c3_Var28 == nil { |
| 602 | - | templ_7745c5c3_Var26 = templ.NopComponent | 648 | + | templ_7745c5c3_Var28 = templ.NopComponent |
| 603 | } | 649 | } | ||
| 604 | ctx = templ.ClearChildren(ctx) | 650 | ctx = templ.ClearChildren(ctx) | ||
| 605 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "<tr") | 651 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "<tr") |
| 606 | if templ_7745c5c3_Err != nil { | 652 | if templ_7745c5c3_Err != nil { | ||
| 607 | return templ_7745c5c3_Err | 653 | return templ_7745c5c3_Err | ||
| 608 | } | 654 | } | ||
| 609 | if r.Cursor { | 655 | if r.Cursor { | ||
| 610 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, " data-cursor") | 656 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, " data-cursor") |
| 611 | if templ_7745c5c3_Err != nil { | 657 | if templ_7745c5c3_Err != nil { | ||
| 612 | return templ_7745c5c3_Err | 658 | return templ_7745c5c3_Err | ||
| 613 | } | 659 | } | ||
| 614 | } | 660 | } | ||
| 615 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "><td class=\"c-kind mute\">") | 661 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "><td class=\"c-kind mute\">") |
| 616 | if templ_7745c5c3_Err != nil { | 662 | if templ_7745c5c3_Err != nil { | ||
| 617 | return templ_7745c5c3_Err | 663 | return templ_7745c5c3_Err | ||
| 618 | } | 664 | } | ||
| 619 | - | var templ_7745c5c3_Var27 string | 665 | + | var templ_7745c5c3_Var29 string |
| 620 | - | templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(kind) | 666 | + | templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(kind) |
| 621 | if templ_7745c5c3_Err != nil { | 667 | if templ_7745c5c3_Err != nil { | ||
| 622 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 148, Col: 32} | 668 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 156, Col: 32} |
| 623 | } | 669 | } | ||
| 624 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) | 670 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) |
| 625 | if templ_7745c5c3_Err != nil { | 671 | if templ_7745c5c3_Err != nil { | ||
| 626 | return templ_7745c5c3_Err | 672 | return templ_7745c5c3_Err | ||
| 627 | } | 673 | } | ||
| 628 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "</td><td class=\"c-name\"><a href=\"") | 674 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "</td><td class=\"c-name\"><a href=\"") |
| 629 | if templ_7745c5c3_Err != nil { | 675 | if templ_7745c5c3_Err != nil { | ||
| 630 | return templ_7745c5c3_Err | 676 | return templ_7745c5c3_Err | ||
| 631 | } | 677 | } | ||
| 632 | - | var templ_7745c5c3_Var28 templ.SafeURL | 678 | + | var templ_7745c5c3_Var30 templ.SafeURL |
| 633 | - | templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Href)) | 679 | + | templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Href)) |
| 634 | if templ_7745c5c3_Err != nil { | 680 | if templ_7745c5c3_Err != nil { | ||
| 635 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 150, Col: 34} | 681 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 158, Col: 34} |
| 636 | } | 682 | } | ||
| 637 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) | 683 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) |
| 638 | if templ_7745c5c3_Err != nil { | 684 | if templ_7745c5c3_Err != nil { | ||
| 639 | return templ_7745c5c3_Err | 685 | return templ_7745c5c3_Err | ||
| 640 | } | 686 | } | ||
| 641 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\">") | 687 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "\">") |
| 642 | if templ_7745c5c3_Err != nil { | 688 | if templ_7745c5c3_Err != nil { | ||
| 643 | return templ_7745c5c3_Err | 689 | return templ_7745c5c3_Err | ||
| 644 | } | 690 | } | ||
| 645 | - | var templ_7745c5c3_Var29 string | 691 | + | var templ_7745c5c3_Var31 string |
| 646 | - | templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) | 692 | + | templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) |
| 647 | if templ_7745c5c3_Err != nil { | 693 | if templ_7745c5c3_Err != nil { | ||
| 648 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 150, Col: 45} | 694 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 158, Col: 45} |
| 649 | } | 695 | } | ||
| 650 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) | 696 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) |
| 651 | if templ_7745c5c3_Err != nil { | 697 | if templ_7745c5c3_Err != nil { | ||
| 652 | return templ_7745c5c3_Err | 698 | return templ_7745c5c3_Err | ||
| 653 | } | 699 | } | ||
| 654 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "</a> ") | 700 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</a> ") |
| 655 | if templ_7745c5c3_Err != nil { | 701 | if templ_7745c5c3_Err != nil { | ||
| 656 | return templ_7745c5c3_Err | 702 | return templ_7745c5c3_Err | ||
| 657 | } | 703 | } | ||
| 658 | if r.Default { | 704 | if r.Default { | ||
| 659 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "<span class=\"pill\">default</span>") | 705 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<span class=\"pill\">default</span>") |
| 660 | if templ_7745c5c3_Err != nil { | 706 | if templ_7745c5c3_Err != nil { | ||
| 661 | return templ_7745c5c3_Err | 707 | return templ_7745c5c3_Err | ||
| 662 | } | 708 | } | ||
| 663 | } | 709 | } | ||
| 664 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</td><td class=\"c-sha\">") | 710 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</td><td class=\"c-sha\">") |
| 665 | if templ_7745c5c3_Err != nil { | 711 | if templ_7745c5c3_Err != nil { | ||
| 666 | return templ_7745c5c3_Err | 712 | return templ_7745c5c3_Err | ||
| 667 | } | 713 | } | ||
| 668 | if r.CHref != "" { | 714 | if r.CHref != "" { | ||
| 669 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "<a href=\"") | 715 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "<a href=\"") |
| 670 | if templ_7745c5c3_Err != nil { | 716 | if templ_7745c5c3_Err != nil { | ||
| 671 | return templ_7745c5c3_Err | 717 | return templ_7745c5c3_Err | ||
| 672 | } | 718 | } | ||
| 673 | - | var templ_7745c5c3_Var30 templ.SafeURL | 719 | + | var templ_7745c5c3_Var32 templ.SafeURL |
| 674 | - | templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.CHref)) | 720 | + | templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.CHref)) |
| 675 | if templ_7745c5c3_Err != nil { | 721 | if templ_7745c5c3_Err != nil { | ||
| 676 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 157, Col: 36} | 722 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 165, Col: 36} |
| 677 | } | 723 | } | ||
| 678 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) | 724 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) |
| 679 | if templ_7745c5c3_Err != nil { | 725 | if templ_7745c5c3_Err != nil { | ||
| 680 | return templ_7745c5c3_Err | 726 | return templ_7745c5c3_Err | ||
| 681 | } | 727 | } | ||
| 682 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\">") | 728 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\">") |
| 683 | if templ_7745c5c3_Err != nil { | 729 | if templ_7745c5c3_Err != nil { | ||
| 684 | return templ_7745c5c3_Err | 730 | return templ_7745c5c3_Err | ||
| 685 | } | 731 | } | ||
| 686 | - | var templ_7745c5c3_Var31 string | 732 | + | var templ_7745c5c3_Var33 string |
| 687 | - | templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) | 733 | + | templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) |
| 688 | if templ_7745c5c3_Err != nil { | 734 | if templ_7745c5c3_Err != nil { | ||
| 689 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 157, Col: 48} | 735 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 165, Col: 48} |
| 690 | } | 736 | } | ||
| 691 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) | 737 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) |
| 692 | if templ_7745c5c3_Err != nil { | 738 | if templ_7745c5c3_Err != nil { | ||
| 693 | return templ_7745c5c3_Err | 739 | return templ_7745c5c3_Err | ||
| 694 | } | 740 | } | ||
| 695 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</a>") | 741 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</a>") |
| 696 | if templ_7745c5c3_Err != nil { | 742 | if templ_7745c5c3_Err != nil { | ||
| 697 | return templ_7745c5c3_Err | 743 | return templ_7745c5c3_Err | ||
| 698 | } | 744 | } | ||
| 699 | } else { | 745 | } else { | ||
| 700 | - | var templ_7745c5c3_Var32 string | 746 | + | var templ_7745c5c3_Var34 string |
| 701 | - | templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) | 747 | + | templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(r.Short) |
| 702 | if templ_7745c5c3_Err != nil { | 748 | if templ_7745c5c3_Err != nil { | ||
| 703 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 159, Col: 13} | 749 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 167, Col: 13} |
| 704 | } | 750 | } | ||
| 705 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) | 751 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) |
| 706 | if templ_7745c5c3_Err != nil { | 752 | if templ_7745c5c3_Err != nil { | ||
| 707 | return templ_7745c5c3_Err | 753 | return templ_7745c5c3_Err | ||
| 708 | } | 754 | } | ||
| @@ -711,69 +757,69 @@ func refRow(kind string, r RefRow) templ.Component { | |||||
| 711 | if templ_7745c5c3_Err != nil { | 757 | if templ_7745c5c3_Err != nil { | ||
| 712 | return templ_7745c5c3_Err | 758 | return templ_7745c5c3_Err | ||
| 713 | } | 759 | } | ||
| 714 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</td><td class=\"c-sub\">") | 760 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "</td><td class=\"c-sub\">") |
| 715 | if templ_7745c5c3_Err != nil { | 761 | if templ_7745c5c3_Err != nil { | ||
| 716 | return templ_7745c5c3_Err | 762 | return templ_7745c5c3_Err | ||
| 717 | } | 763 | } | ||
| 718 | - | var templ_7745c5c3_Var33 string | 764 | + | var templ_7745c5c3_Var35 string |
| 719 | - | templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(r.Subject) | 765 | + | templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(r.Subject) |
| 720 | if templ_7745c5c3_Err != nil { | 766 | if templ_7745c5c3_Err != nil { | ||
| 721 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 163, Col: 31} | 767 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 171, Col: 31} |
| 722 | } | 768 | } | ||
| 723 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) | 769 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) |
| 724 | if templ_7745c5c3_Err != nil { | 770 | if templ_7745c5c3_Err != nil { | ||
| 725 | return templ_7745c5c3_Err | 771 | return templ_7745c5c3_Err | ||
| 726 | } | 772 | } | ||
| 727 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "</td><td class=\"c-when dim\">") | 773 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "</td><td class=\"c-when dim\">") |
| 728 | if templ_7745c5c3_Err != nil { | 774 | if templ_7745c5c3_Err != nil { | ||
| 729 | return templ_7745c5c3_Err | 775 | return templ_7745c5c3_Err | ||
| 730 | } | 776 | } | ||
| 731 | if r.WhenAt != "" { | 777 | if r.WhenAt != "" { | ||
| 732 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<time datetime=\"") | 778 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "<time datetime=\"") |
| 733 | if templ_7745c5c3_Err != nil { | 779 | if templ_7745c5c3_Err != nil { | ||
| 734 | return templ_7745c5c3_Err | 780 | return templ_7745c5c3_Err | ||
| 735 | } | 781 | } | ||
| 736 | - | var templ_7745c5c3_Var34 string | 782 | + | var templ_7745c5c3_Var36 string |
| 737 | - | templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) | 783 | + | templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) |
| 738 | if templ_7745c5c3_Err != nil { | 784 | if templ_7745c5c3_Err != nil { | ||
| 739 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 166, Col: 29} | 785 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 174, Col: 29} |
| 740 | } | 786 | } | ||
| 741 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var34) | 787 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var36) |
| 742 | if templ_7745c5c3_Err != nil { | 788 | if templ_7745c5c3_Err != nil { | ||
| 743 | return templ_7745c5c3_Err | 789 | return templ_7745c5c3_Err | ||
| 744 | } | 790 | } | ||
| 745 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" title=\"") | 791 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\" title=\"") |
| 746 | if templ_7745c5c3_Err != nil { | 792 | if templ_7745c5c3_Err != nil { | ||
| 747 | return templ_7745c5c3_Err | 793 | return templ_7745c5c3_Err | ||
| 748 | } | 794 | } | ||
| 749 | - | var templ_7745c5c3_Var35 string | 795 | + | var templ_7745c5c3_Var37 string |
| 750 | - | templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) | 796 | + | templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.WhenAt) |
| 751 | if templ_7745c5c3_Err != nil { | 797 | if templ_7745c5c3_Err != nil { | ||
| 752 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 166, Col: 48} | 798 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 174, Col: 48} |
| 753 | } | 799 | } | ||
| 754 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var35) | 800 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var37) |
| 755 | if templ_7745c5c3_Err != nil { | 801 | if templ_7745c5c3_Err != nil { | ||
| 756 | return templ_7745c5c3_Err | 802 | return templ_7745c5c3_Err | ||
| 757 | } | 803 | } | ||
| 758 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\">") | 804 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "\">") |
| 759 | if templ_7745c5c3_Err != nil { | 805 | if templ_7745c5c3_Err != nil { | ||
| 760 | return templ_7745c5c3_Err | 806 | return templ_7745c5c3_Err | ||
| 761 | } | 807 | } | ||
| 762 | - | var templ_7745c5c3_Var36 string | 808 | + | var templ_7745c5c3_Var38 string |
| 763 | - | templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(r.When) | 809 | + | templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(r.When) |
| 764 | if templ_7745c5c3_Err != nil { | 810 | if templ_7745c5c3_Err != nil { | ||
| 765 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 166, Col: 59} | 811 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 174, Col: 59} |
| 766 | } | 812 | } | ||
| 767 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) | 813 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38)) |
| 768 | if templ_7745c5c3_Err != nil { | 814 | if templ_7745c5c3_Err != nil { | ||
| 769 | return templ_7745c5c3_Err | 815 | return templ_7745c5c3_Err | ||
| 770 | } | 816 | } | ||
| 771 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</time>") | 817 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "</time>") |
| 772 | if templ_7745c5c3_Err != nil { | 818 | if templ_7745c5c3_Err != nil { | ||
| 773 | return templ_7745c5c3_Err | 819 | return templ_7745c5c3_Err | ||
| 774 | } | 820 | } | ||
| 775 | } | 821 | } | ||
| 776 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "</td></tr>") | 822 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "</td></tr>") |
| 777 | if templ_7745c5c3_Err != nil { | 823 | if templ_7745c5c3_Err != nil { | ||
| 778 | return templ_7745c5c3_Err | 824 | return templ_7745c5c3_Err | ||
| 779 | } | 825 | } | ||
| @@ -797,12 +843,12 @@ func refsRail(p RefsPage) templ.Component { | |||||
| 797 | }() | 843 | }() | ||
| 798 | } | 844 | } | ||
| 799 | ctx = templ.InitializeContext(ctx) | 845 | ctx = templ.InitializeContext(ctx) | ||
| 800 | - | templ_7745c5c3_Var37 := templ.GetChildren(ctx) | 846 | + | templ_7745c5c3_Var39 := templ.GetChildren(ctx) |
| 801 | - | if templ_7745c5c3_Var37 == nil { | 847 | + | if templ_7745c5c3_Var39 == nil { |
| 802 | - | templ_7745c5c3_Var37 = templ.NopComponent | 848 | + | templ_7745c5c3_Var39 = templ.NopComponent |
| 803 | } | 849 | } | ||
| 804 | ctx = templ.ClearChildren(ctx) | 850 | ctx = templ.ClearChildren(ctx) | ||
| 805 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "<section aria-labelledby=\"r-refs\"><h2 id=\"r-refs\">Overview</h2>") | 851 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "<section aria-labelledby=\"r-refs\"><h2 id=\"r-refs\">Overview</h2>") |
| 806 | if templ_7745c5c3_Err != nil { | 852 | if templ_7745c5c3_Err != nil { | ||
| 807 | return templ_7745c5c3_Err | 853 | return templ_7745c5c3_Err | ||
| 808 | } | 854 | } | ||
| @@ -810,7 +856,7 @@ func refsRail(p RefsPage) templ.Component { | |||||
| 810 | if templ_7745c5c3_Err != nil { | 856 | if templ_7745c5c3_Err != nil { | ||
| 811 | return templ_7745c5c3_Err | 857 | return templ_7745c5c3_Err | ||
| 812 | } | 858 | } | ||
| 813 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "</section>") | 859 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "</section>") |
| 814 | if templ_7745c5c3_Err != nil { | 860 | if templ_7745c5c3_Err != nil { | ||
| 815 | return templ_7745c5c3_Err | 861 | return templ_7745c5c3_Err | ||
| 816 | } | 862 | } | ||
| @@ -835,12 +881,12 @@ func State(l Layout, p StatePage) templ.Component { | |||||
| 835 | }() | 881 | }() | ||
| 836 | } | 882 | } | ||
| 837 | ctx = templ.InitializeContext(ctx) | 883 | ctx = templ.InitializeContext(ctx) | ||
| 838 | - | templ_7745c5c3_Var38 := templ.GetChildren(ctx) | 884 | + | templ_7745c5c3_Var40 := templ.GetChildren(ctx) |
| 839 | - | if templ_7745c5c3_Var38 == nil { | 885 | + | if templ_7745c5c3_Var40 == nil { |
| 840 | - | templ_7745c5c3_Var38 = templ.NopComponent | 886 | + | templ_7745c5c3_Var40 = templ.NopComponent |
| 841 | } | 887 | } | ||
| 842 | ctx = templ.ClearChildren(ctx) | 888 | ctx = templ.ClearChildren(ctx) | ||
| 843 | - | templ_7745c5c3_Var39 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 889 | + | templ_7745c5c3_Var41 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
| 844 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | 890 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||
| 845 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 891 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||
| 846 | if !templ_7745c5c3_IsBuffer { | 892 | if !templ_7745c5c3_IsBuffer { | ||
| @@ -852,51 +898,51 @@ func State(l Layout, p StatePage) templ.Component { | |||||
| 852 | }() | 898 | }() | ||
| 853 | } | 899 | } | ||
| 854 | ctx = templ.InitializeContext(ctx) | 900 | ctx = templ.InitializeContext(ctx) | ||
| 855 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "<section class=\"state\" aria-labelledby=\"state-title\"><p class=\"eyebrow\">") | 901 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "<section class=\"state\" aria-labelledby=\"state-title\"><p class=\"eyebrow\">") |
| 856 | if templ_7745c5c3_Err != nil { | 902 | if templ_7745c5c3_Err != nil { | ||
| 857 | return templ_7745c5c3_Err | 903 | return templ_7745c5c3_Err | ||
| 858 | } | 904 | } | ||
| 859 | - | var templ_7745c5c3_Var40 string | 905 | + | var templ_7745c5c3_Var42 string |
| 860 | - | templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(p.Code) | 906 | + | templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Code) |
| 861 | if templ_7745c5c3_Err != nil { | 907 | if templ_7745c5c3_Err != nil { | ||
| 862 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 183, Col: 30} | 908 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 191, Col: 30} |
| 863 | } | 909 | } | ||
| 864 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) | 910 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) |
| 865 | if templ_7745c5c3_Err != nil { | 911 | if templ_7745c5c3_Err != nil { | ||
| 866 | return templ_7745c5c3_Err | 912 | return templ_7745c5c3_Err | ||
| 867 | } | 913 | } | ||
| 868 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "</p><h1 id=\"state-title\">") | 914 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "</p><h1 id=\"state-title\">") |
| 869 | if templ_7745c5c3_Err != nil { | 915 | if templ_7745c5c3_Err != nil { | ||
| 870 | return templ_7745c5c3_Err | 916 | return templ_7745c5c3_Err | ||
| 871 | } | 917 | } | ||
| 872 | - | var templ_7745c5c3_Var41 string | 918 | + | var templ_7745c5c3_Var43 string |
| 873 | - | templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | 919 | + | templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) |
| 874 | if templ_7745c5c3_Err != nil { | 920 | if templ_7745c5c3_Err != nil { | ||
| 875 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 184, Col: 33} | 921 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 192, Col: 33} |
| 876 | } | 922 | } | ||
| 877 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41)) | 923 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) |
| 878 | if templ_7745c5c3_Err != nil { | 924 | if templ_7745c5c3_Err != nil { | ||
| 879 | return templ_7745c5c3_Err | 925 | return templ_7745c5c3_Err | ||
| 880 | } | 926 | } | ||
| 881 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "</h1>") | 927 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</h1>") |
| 882 | if templ_7745c5c3_Err != nil { | 928 | if templ_7745c5c3_Err != nil { | ||
| 883 | return templ_7745c5c3_Err | 929 | return templ_7745c5c3_Err | ||
| 884 | } | 930 | } | ||
| 885 | for _, line := range p.Lines { | 931 | for _, line := range p.Lines { | ||
| 886 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "<p class=\"dim\">") | 932 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "<p class=\"dim\">") |
| 887 | if templ_7745c5c3_Err != nil { | 933 | if templ_7745c5c3_Err != nil { | ||
| 888 | return templ_7745c5c3_Err | 934 | return templ_7745c5c3_Err | ||
| 889 | } | 935 | } | ||
| 890 | - | var templ_7745c5c3_Var42 string | 936 | + | var templ_7745c5c3_Var44 string |
| 891 | - | templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(line) | 937 | + | templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(line) |
| 892 | if templ_7745c5c3_Err != nil { | 938 | if templ_7745c5c3_Err != nil { | ||
| 893 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 186, Col: 25} | 939 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 194, Col: 25} |
| 894 | } | 940 | } | ||
| 895 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) | 941 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44)) |
| 896 | if templ_7745c5c3_Err != nil { | 942 | if templ_7745c5c3_Err != nil { | ||
| 897 | return templ_7745c5c3_Err | 943 | return templ_7745c5c3_Err | ||
| 898 | } | 944 | } | ||
| 899 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "</p>") | 945 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "</p>") |
| 900 | if templ_7745c5c3_Err != nil { | 946 | if templ_7745c5c3_Err != nil { | ||
| 901 | return templ_7745c5c3_Err | 947 | return templ_7745c5c3_Err | ||
| 902 | } | 948 | } | ||
| @@ -907,49 +953,49 @@ func State(l Layout, p StatePage) templ.Component { | |||||
| 907 | return templ_7745c5c3_Err | 953 | return templ_7745c5c3_Err | ||
| 908 | } | 954 | } | ||
| 909 | } | 955 | } | ||
| 910 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "<p class=\"state-back\">") | 956 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "<p class=\"state-back\">") |
| 911 | if templ_7745c5c3_Err != nil { | 957 | if templ_7745c5c3_Err != nil { | ||
| 912 | return templ_7745c5c3_Err | 958 | return templ_7745c5c3_Err | ||
| 913 | } | 959 | } | ||
| 914 | for _, b := range p.Back { | 960 | for _, b := range p.Back { | ||
| 915 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "<a href=\"") | 961 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<a href=\"") |
| 916 | if templ_7745c5c3_Err != nil { | 962 | if templ_7745c5c3_Err != nil { | ||
| 917 | return templ_7745c5c3_Err | 963 | return templ_7745c5c3_Err | ||
| 918 | } | 964 | } | ||
| 919 | - | var templ_7745c5c3_Var43 templ.SafeURL | 965 | + | var templ_7745c5c3_Var45 templ.SafeURL |
| 920 | - | templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(b.Href)) | 966 | + | templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(b.Href)) |
| 921 | if templ_7745c5c3_Err != nil { | 967 | if templ_7745c5c3_Err != nil { | ||
| 922 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 193, Col: 36} | 968 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 201, Col: 36} |
| 923 | } | 969 | } | ||
| 924 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) | 970 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45)) |
| 925 | if templ_7745c5c3_Err != nil { | 971 | if templ_7745c5c3_Err != nil { | ||
| 926 | return templ_7745c5c3_Err | 972 | return templ_7745c5c3_Err | ||
| 927 | } | 973 | } | ||
| 928 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "\">") | 974 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "\">") |
| 929 | if templ_7745c5c3_Err != nil { | 975 | if templ_7745c5c3_Err != nil { | ||
| 930 | return templ_7745c5c3_Err | 976 | return templ_7745c5c3_Err | ||
| 931 | } | 977 | } | ||
| 932 | - | var templ_7745c5c3_Var44 string | 978 | + | var templ_7745c5c3_Var46 string |
| 933 | - | templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(b.Label) | 979 | + | templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(b.Label) |
| 934 | if templ_7745c5c3_Err != nil { | 980 | if templ_7745c5c3_Err != nil { | ||
| 935 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 193, Col: 48} | 981 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 201, Col: 48} |
| 936 | } | 982 | } | ||
| 937 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44)) | 983 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46)) |
| 938 | if templ_7745c5c3_Err != nil { | 984 | if templ_7745c5c3_Err != nil { | ||
| 939 | return templ_7745c5c3_Err | 985 | return templ_7745c5c3_Err | ||
| 940 | } | 986 | } | ||
| 941 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</a>") | 987 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "</a>") |
| 942 | if templ_7745c5c3_Err != nil { | 988 | if templ_7745c5c3_Err != nil { | ||
| 943 | return templ_7745c5c3_Err | 989 | return templ_7745c5c3_Err | ||
| 944 | } | 990 | } | ||
| 945 | } | 991 | } | ||
| 946 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "</p></section>") | 992 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</p></section>") |
| 947 | if templ_7745c5c3_Err != nil { | 993 | if templ_7745c5c3_Err != nil { | ||
| 948 | return templ_7745c5c3_Err | 994 | return templ_7745c5c3_Err | ||
| 949 | } | 995 | } | ||
| 950 | return nil | 996 | return nil | ||
| 951 | }) | 997 | }) | ||
| 952 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var39), templ_7745c5c3_Buffer) | 998 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var41), templ_7745c5c3_Buffer) |
| 953 | if templ_7745c5c3_Err != nil { | 999 | if templ_7745c5c3_Err != nil { | ||
| 954 | return templ_7745c5c3_Err | 1000 | return templ_7745c5c3_Err | ||
| 955 | } | 1001 | } | ||
| @@ -978,12 +1024,12 @@ func Login(l Layout, p LoginPage) templ.Component { | |||||
| 978 | }() | 1024 | }() | ||
| 979 | } | 1025 | } | ||
| 980 | ctx = templ.InitializeContext(ctx) | 1026 | ctx = templ.InitializeContext(ctx) | ||
| 981 | - | templ_7745c5c3_Var45 := templ.GetChildren(ctx) | 1027 | + | templ_7745c5c3_Var47 := templ.GetChildren(ctx) |
| 982 | - | if templ_7745c5c3_Var45 == nil { | 1028 | + | if templ_7745c5c3_Var47 == nil { |
| 983 | - | templ_7745c5c3_Var45 = templ.NopComponent | 1029 | + | templ_7745c5c3_Var47 = templ.NopComponent |
| 984 | } | 1030 | } | ||
| 985 | ctx = templ.ClearChildren(ctx) | 1031 | ctx = templ.ClearChildren(ctx) | ||
| 986 | - | templ_7745c5c3_Var46 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 1032 | + | templ_7745c5c3_Var48 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
| 987 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | 1033 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||
| 988 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 1034 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||
| 989 | if !templ_7745c5c3_IsBuffer { | 1035 | if !templ_7745c5c3_IsBuffer { | ||
| @@ -995,75 +1041,75 @@ func Login(l Layout, p LoginPage) templ.Component { | |||||
| 995 | }() | 1041 | }() | ||
| 996 | } | 1042 | } | ||
| 997 | ctx = templ.InitializeContext(ctx) | 1043 | ctx = templ.InitializeContext(ctx) | ||
| 998 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") | 1044 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") |
| 999 | if templ_7745c5c3_Err != nil { | 1045 | if templ_7745c5c3_Err != nil { | ||
| 1000 | return templ_7745c5c3_Err | 1046 | return templ_7745c5c3_Err | ||
| 1001 | } | 1047 | } | ||
| 1002 | - | var templ_7745c5c3_Var47 string | 1048 | + | var templ_7745c5c3_Var49 string |
| 1003 | - | templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | 1049 | + | templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) |
| 1004 | if templ_7745c5c3_Err != nil { | 1050 | if templ_7745c5c3_Err != nil { | ||
| 1005 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 208, Col: 33} | 1051 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 216, Col: 33} |
| 1006 | } | 1052 | } | ||
| 1007 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47)) | 1053 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49)) |
| 1008 | if templ_7745c5c3_Err != nil { | 1054 | if templ_7745c5c3_Err != nil { | ||
| 1009 | return templ_7745c5c3_Err | 1055 | return templ_7745c5c3_Err | ||
| 1010 | } | 1056 | } | ||
| 1011 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "</h1>") | 1057 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "</h1>") |
| 1012 | if templ_7745c5c3_Err != nil { | 1058 | if templ_7745c5c3_Err != nil { | ||
| 1013 | return templ_7745c5c3_Err | 1059 | return templ_7745c5c3_Err | ||
| 1014 | } | 1060 | } | ||
| 1015 | for _, line := range p.Lines { | 1061 | for _, line := range p.Lines { | ||
| 1016 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<p class=\"dim\">") | 1062 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "<p class=\"dim\">") |
| 1017 | if templ_7745c5c3_Err != nil { | 1063 | if templ_7745c5c3_Err != nil { | ||
| 1018 | return templ_7745c5c3_Err | 1064 | return templ_7745c5c3_Err | ||
| 1019 | } | 1065 | } | ||
| 1020 | - | var templ_7745c5c3_Var48 string | 1066 | + | var templ_7745c5c3_Var50 string |
| 1021 | - | templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(line) | 1067 | + | templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(line) |
| 1022 | if templ_7745c5c3_Err != nil { | 1068 | if templ_7745c5c3_Err != nil { | ||
| 1023 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 210, Col: 25} | 1069 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 218, Col: 25} |
| 1024 | } | 1070 | } | ||
| 1025 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48)) | 1071 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50)) |
| 1026 | if templ_7745c5c3_Err != nil { | 1072 | if templ_7745c5c3_Err != nil { | ||
| 1027 | return templ_7745c5c3_Err | 1073 | return templ_7745c5c3_Err | ||
| 1028 | } | 1074 | } | ||
| 1029 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "</p>") | 1075 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "</p>") |
| 1030 | if templ_7745c5c3_Err != nil { | 1076 | if templ_7745c5c3_Err != nil { | ||
| 1031 | return templ_7745c5c3_Err | 1077 | return templ_7745c5c3_Err | ||
| 1032 | } | 1078 | } | ||
| 1033 | } | 1079 | } | ||
| 1034 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "<form class=\"state-act\" method=\"post\" action=\"") | 1080 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "<form class=\"state-act\" method=\"post\" action=\"") |
| 1035 | if templ_7745c5c3_Err != nil { | 1081 | if templ_7745c5c3_Err != nil { | ||
| 1036 | return templ_7745c5c3_Err | 1082 | return templ_7745c5c3_Err | ||
| 1037 | } | 1083 | } | ||
| 1038 | - | var templ_7745c5c3_Var49 templ.SafeURL | 1084 | + | var templ_7745c5c3_Var51 templ.SafeURL |
| 1039 | - | templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Action)) | 1085 | + | templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Action)) |
| 1040 | if templ_7745c5c3_Err != nil { | 1086 | if templ_7745c5c3_Err != nil { | ||
| 1041 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 212, Col: 73} | 1087 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 220, Col: 73} |
| 1042 | } | 1088 | } | ||
| 1043 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49)) | 1089 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51)) |
| 1044 | if templ_7745c5c3_Err != nil { | 1090 | if templ_7745c5c3_Err != nil { | ||
| 1045 | return templ_7745c5c3_Err | 1091 | return templ_7745c5c3_Err | ||
| 1046 | } | 1092 | } | ||
| 1047 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "\" data-autosubmit><button type=\"submit\" class=\"btn primary\">") | 1093 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "\" data-autosubmit><button type=\"submit\" class=\"btn primary\">") |
| 1048 | if templ_7745c5c3_Err != nil { | 1094 | if templ_7745c5c3_Err != nil { | ||
| 1049 | return templ_7745c5c3_Err | 1095 | return templ_7745c5c3_Err | ||
| 1050 | } | 1096 | } | ||
| 1051 | - | var templ_7745c5c3_Var50 string | 1097 | + | var templ_7745c5c3_Var52 string |
| 1052 | - | templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) | 1098 | + | templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) |
| 1053 | if templ_7745c5c3_Err != nil { | 1099 | if templ_7745c5c3_Err != nil { | ||
| 1054 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 213, Col: 56} | 1100 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 221, Col: 56} |
| 1055 | } | 1101 | } | ||
| 1056 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50)) | 1102 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52)) |
| 1057 | if templ_7745c5c3_Err != nil { | 1103 | if templ_7745c5c3_Err != nil { | ||
| 1058 | return templ_7745c5c3_Err | 1104 | return templ_7745c5c3_Err | ||
| 1059 | } | 1105 | } | ||
| 1060 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "</button></form><p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") | 1106 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "</button></form><p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") |
| 1061 | if templ_7745c5c3_Err != nil { | 1107 | if templ_7745c5c3_Err != nil { | ||
| 1062 | return templ_7745c5c3_Err | 1108 | return templ_7745c5c3_Err | ||
| 1063 | } | 1109 | } | ||
| 1064 | return nil | 1110 | return nil | ||
| 1065 | }) | 1111 | }) | ||
| 1066 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var46), templ_7745c5c3_Buffer) | 1112 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var48), templ_7745c5c3_Buffer) |
| 1067 | if templ_7745c5c3_Err != nil { | 1113 | if templ_7745c5c3_Err != nil { | ||
| 1068 | return templ_7745c5c3_Err | 1114 | return templ_7745c5c3_Err | ||
| 1069 | } | 1115 | } | ||
| @@ -1089,12 +1135,12 @@ func PasskeyLogin(l Layout, p PasskeyLoginPage) templ.Component { | |||||
| 1089 | }() | 1135 | }() | ||
| 1090 | } | 1136 | } | ||
| 1091 | ctx = templ.InitializeContext(ctx) | 1137 | ctx = templ.InitializeContext(ctx) | ||
| 1092 | - | templ_7745c5c3_Var51 := templ.GetChildren(ctx) | 1138 | + | templ_7745c5c3_Var53 := templ.GetChildren(ctx) |
| 1093 | - | if templ_7745c5c3_Var51 == nil { | 1139 | + | if templ_7745c5c3_Var53 == nil { |
| 1094 | - | templ_7745c5c3_Var51 = templ.NopComponent | 1140 | + | templ_7745c5c3_Var53 = templ.NopComponent |
| 1095 | } | 1141 | } | ||
| 1096 | ctx = templ.ClearChildren(ctx) | 1142 | ctx = templ.ClearChildren(ctx) | ||
| 1097 | - | templ_7745c5c3_Var52 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 1143 | + | templ_7745c5c3_Var54 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
| 1098 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | 1144 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||
| 1099 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 1145 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||
| 1100 | if !templ_7745c5c3_IsBuffer { | 1146 | if !templ_7745c5c3_IsBuffer { | ||
| @@ -1106,88 +1152,88 @@ func PasskeyLogin(l Layout, p PasskeyLoginPage) templ.Component { | |||||
| 1106 | }() | 1152 | }() | ||
| 1107 | } | 1153 | } | ||
| 1108 | ctx = templ.InitializeContext(ctx) | 1154 | ctx = templ.InitializeContext(ctx) | ||
| 1109 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") | 1155 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "<section class=\"state\" aria-labelledby=\"state-title\"><h1 id=\"state-title\">") |
| 1110 | if templ_7745c5c3_Err != nil { | 1156 | if templ_7745c5c3_Err != nil { | ||
| 1111 | return templ_7745c5c3_Err | 1157 | return templ_7745c5c3_Err | ||
| 1112 | } | 1158 | } | ||
| 1113 | - | var templ_7745c5c3_Var53 string | 1159 | + | var templ_7745c5c3_Var55 string |
| 1114 | - | templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) | 1160 | + | templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title) |
| 1115 | if templ_7745c5c3_Err != nil { | 1161 | if templ_7745c5c3_Err != nil { | ||
| 1116 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 225, Col: 33} | 1162 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 233, Col: 33} |
| 1117 | } | 1163 | } | ||
| 1118 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53)) | 1164 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55)) |
| 1119 | if templ_7745c5c3_Err != nil { | 1165 | if templ_7745c5c3_Err != nil { | ||
| 1120 | return templ_7745c5c3_Err | 1166 | return templ_7745c5c3_Err | ||
| 1121 | } | 1167 | } | ||
| 1122 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "</h1><form class=\"state-act\" data-js data-passkey-form><button type=\"submit\" class=\"btn primary\" data-passkey=\"login\" data-begin=\"") | 1168 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</h1><form class=\"state-act\" data-js data-passkey-form><button type=\"submit\" class=\"btn primary\" data-passkey=\"login\" data-begin=\"") |
| 1123 | if templ_7745c5c3_Err != nil { | 1169 | if templ_7745c5c3_Err != nil { | ||
| 1124 | return templ_7745c5c3_Err | 1170 | return templ_7745c5c3_Err | ||
| 1125 | } | 1171 | } | ||
| 1126 | - | var templ_7745c5c3_Var54 string | 1172 | + | var templ_7745c5c3_Var56 string |
| 1127 | - | templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) | 1173 | + | templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) |
| 1128 | if templ_7745c5c3_Err != nil { | 1174 | if templ_7745c5c3_Err != nil { | ||
| 1129 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 227, Col: 87} | 1175 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 235, Col: 87} |
| 1130 | } | 1176 | } | ||
| 1131 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var54) | 1177 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var56) |
| 1132 | if templ_7745c5c3_Err != nil { | 1178 | if templ_7745c5c3_Err != nil { | ||
| 1133 | return templ_7745c5c3_Err | 1179 | return templ_7745c5c3_Err | ||
| 1134 | } | 1180 | } | ||
| 1135 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "\" data-finish=\"") | 1181 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "\" data-finish=\"") |
| 1136 | if templ_7745c5c3_Err != nil { | 1182 | if templ_7745c5c3_Err != nil { | ||
| 1137 | return templ_7745c5c3_Err | 1183 | return templ_7745c5c3_Err | ||
| 1138 | } | 1184 | } | ||
| 1139 | - | var templ_7745c5c3_Var55 string | 1185 | + | var templ_7745c5c3_Var57 string |
| 1140 | - | templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) | 1186 | + | templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) |
| 1141 | if templ_7745c5c3_Err != nil { | 1187 | if templ_7745c5c3_Err != nil { | ||
| 1142 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 227, Col: 112} | 1188 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 235, Col: 112} |
| 1143 | } | 1189 | } | ||
| 1144 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var55) | 1190 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var57) |
| 1145 | if templ_7745c5c3_Err != nil { | 1191 | if templ_7745c5c3_Err != nil { | ||
| 1146 | return templ_7745c5c3_Err | 1192 | return templ_7745c5c3_Err | ||
| 1147 | } | 1193 | } | ||
| 1148 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\">") | 1194 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "\">") |
| 1149 | if templ_7745c5c3_Err != nil { | 1195 | if templ_7745c5c3_Err != nil { | ||
| 1150 | return templ_7745c5c3_Err | 1196 | return templ_7745c5c3_Err | ||
| 1151 | } | 1197 | } | ||
| 1152 | - | var templ_7745c5c3_Var56 string | 1198 | + | var templ_7745c5c3_Var58 string |
| 1153 | - | templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) | 1199 | + | templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(p.Button) |
| 1154 | if templ_7745c5c3_Err != nil { | 1200 | if templ_7745c5c3_Err != nil { | ||
| 1155 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 227, Col: 125} | 1201 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 235, Col: 125} |
| 1156 | } | 1202 | } | ||
| 1157 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var56)) | 1203 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58)) |
| 1158 | if templ_7745c5c3_Err != nil { | 1204 | if templ_7745c5c3_Err != nil { | ||
| 1159 | return templ_7745c5c3_Err | 1205 | return templ_7745c5c3_Err | ||
| 1160 | } | 1206 | } | ||
| 1161 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "</button></form><p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") | 1207 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "</button></form><p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") |
| 1162 | if templ_7745c5c3_Err != nil { | 1208 | if templ_7745c5c3_Err != nil { | ||
| 1163 | return templ_7745c5c3_Err | 1209 | return templ_7745c5c3_Err | ||
| 1164 | } | 1210 | } | ||
| 1165 | for _, line := range p.Lines { | 1211 | for _, line := range p.Lines { | ||
| 1166 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<p class=\"dim\">") | 1212 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "<p class=\"dim\">") |
| 1167 | if templ_7745c5c3_Err != nil { | 1213 | if templ_7745c5c3_Err != nil { | ||
| 1168 | return templ_7745c5c3_Err | 1214 | return templ_7745c5c3_Err | ||
| 1169 | } | 1215 | } | ||
| 1170 | - | var templ_7745c5c3_Var57 string | 1216 | + | var templ_7745c5c3_Var59 string |
| 1171 | - | templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinStringErrs(line) | 1217 | + | templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(line) |
| 1172 | if templ_7745c5c3_Err != nil { | 1218 | if templ_7745c5c3_Err != nil { | ||
| 1173 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 231, Col: 25} | 1219 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 239, Col: 25} |
| 1174 | } | 1220 | } | ||
| 1175 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57)) | 1221 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59)) |
| 1176 | if templ_7745c5c3_Err != nil { | 1222 | if templ_7745c5c3_Err != nil { | ||
| 1177 | return templ_7745c5c3_Err | 1223 | return templ_7745c5c3_Err | ||
| 1178 | } | 1224 | } | ||
| 1179 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "</p>") | 1225 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</p>") |
| 1180 | if templ_7745c5c3_Err != nil { | 1226 | if templ_7745c5c3_Err != nil { | ||
| 1181 | return templ_7745c5c3_Err | 1227 | return templ_7745c5c3_Err | ||
| 1182 | } | 1228 | } | ||
| 1183 | } | 1229 | } | ||
| 1184 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "<p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") | 1230 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "<p class=\"state-back\"><a href=\"/\">Back to home</a></p></section>") |
| 1185 | if templ_7745c5c3_Err != nil { | 1231 | if templ_7745c5c3_Err != nil { | ||
| 1186 | return templ_7745c5c3_Err | 1232 | return templ_7745c5c3_Err | ||
| 1187 | } | 1233 | } | ||
| 1188 | return nil | 1234 | return nil | ||
| 1189 | }) | 1235 | }) | ||
| 1190 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var52), templ_7745c5c3_Buffer) | 1236 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var54), templ_7745c5c3_Buffer) |
| 1191 | if templ_7745c5c3_Err != nil { | 1237 | if templ_7745c5c3_Err != nil { | ||
| 1192 | return templ_7745c5c3_Err | 1238 | return templ_7745c5c3_Err | ||
| 1193 | } | 1239 | } | ||
| @@ -1212,12 +1258,12 @@ func Passkeys(l Layout, p PasskeysPage) templ.Component { | |||||
| 1212 | }() | 1258 | }() | ||
| 1213 | } | 1259 | } | ||
| 1214 | ctx = templ.InitializeContext(ctx) | 1260 | ctx = templ.InitializeContext(ctx) | ||
| 1215 | - | templ_7745c5c3_Var58 := templ.GetChildren(ctx) | 1261 | + | templ_7745c5c3_Var60 := templ.GetChildren(ctx) |
| 1216 | - | if templ_7745c5c3_Var58 == nil { | 1262 | + | if templ_7745c5c3_Var60 == nil { |
| 1217 | - | templ_7745c5c3_Var58 = templ.NopComponent | 1263 | + | templ_7745c5c3_Var60 = templ.NopComponent |
| 1218 | } | 1264 | } | ||
| 1219 | ctx = templ.ClearChildren(ctx) | 1265 | ctx = templ.ClearChildren(ctx) | ||
| 1220 | - | templ_7745c5c3_Var59 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { | 1266 | + | templ_7745c5c3_Var61 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
| 1221 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | 1267 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context | ||
| 1222 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | 1268 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) | ||
| 1223 | if !templ_7745c5c3_IsBuffer { | 1269 | if !templ_7745c5c3_IsBuffer { | ||
| @@ -1229,231 +1275,231 @@ func Passkeys(l Layout, p PasskeysPage) templ.Component { | |||||
| 1229 | }() | 1275 | }() | ||
| 1230 | } | 1276 | } | ||
| 1231 | ctx = templ.InitializeContext(ctx) | 1277 | ctx = templ.InitializeContext(ctx) | ||
| 1232 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<h2 class=\"rule-h\"><span>Passkeys</span><span class=\"count\">") | 1278 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "<h2 class=\"rule-h\"><span>Passkeys</span><span class=\"count\">") |
| 1233 | if templ_7745c5c3_Err != nil { | 1279 | if templ_7745c5c3_Err != nil { | ||
| 1234 | return templ_7745c5c3_Err | 1280 | return templ_7745c5c3_Err | ||
| 1235 | } | 1281 | } | ||
| 1236 | - | var templ_7745c5c3_Var60 string | 1282 | + | var templ_7745c5c3_Var62 string |
| 1237 | - | templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Rows))) | 1283 | + | templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Rows))) |
| 1238 | if templ_7745c5c3_Err != nil { | 1284 | if templ_7745c5c3_Err != nil { | ||
| 1239 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 241, Col: 81} | 1285 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 249, Col: 81} |
| 1240 | } | 1286 | } | ||
| 1241 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var60)) | 1287 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62)) |
| 1242 | if templ_7745c5c3_Err != nil { | 1288 | if templ_7745c5c3_Err != nil { | ||
| 1243 | return templ_7745c5c3_Err | 1289 | return templ_7745c5c3_Err | ||
| 1244 | } | 1290 | } | ||
| 1245 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "</span></h2><p class=\"dim\">A passkey signs you in from this device or your phone, without a terminal. Removing one signs every browser out.</p>") | 1291 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "</span></h2><p class=\"dim\">A passkey signs you in from this device or your phone, without a terminal. Removing one signs every browser out.</p>") |
| 1246 | if templ_7745c5c3_Err != nil { | 1292 | if templ_7745c5c3_Err != nil { | ||
| 1247 | return templ_7745c5c3_Err | 1293 | return templ_7745c5c3_Err | ||
| 1248 | } | 1294 | } | ||
| 1249 | if len(p.Rows) > 0 { | 1295 | if len(p.Rows) > 0 { | ||
| 1250 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "<table class=\"list passkeys\" aria-label=\"Passkeys\"><thead><tr><th class=\"c-name\">Name</th><th class=\"c-when\">Created</th><th class=\"c-when\">Last used</th><th class=\"c-sync\">Synced</th><th class=\"c-act\"><span class=\"sr\">Remove</span></th></tr></thead> <tbody>") | 1296 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "<table class=\"list passkeys\" aria-label=\"Passkeys\"><thead><tr><th class=\"c-name\">Name</th><th class=\"c-when\">Created</th><th class=\"c-when\">Last used</th><th class=\"c-sync\">Synced</th><th class=\"c-act\"><span class=\"sr\">Remove</span></th></tr></thead> <tbody>") |
| 1251 | if templ_7745c5c3_Err != nil { | 1297 | if templ_7745c5c3_Err != nil { | ||
| 1252 | return templ_7745c5c3_Err | 1298 | return templ_7745c5c3_Err | ||
| 1253 | } | 1299 | } | ||
| 1254 | for _, r := range p.Rows { | 1300 | for _, r := range p.Rows { | ||
| 1255 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "<tr><td class=\"c-name\">") | 1301 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "<tr><td class=\"c-name\">") |
| 1256 | if templ_7745c5c3_Err != nil { | 1302 | if templ_7745c5c3_Err != nil { | ||
| 1257 | return templ_7745c5c3_Err | 1303 | return templ_7745c5c3_Err | ||
| 1258 | } | 1304 | } | ||
| 1259 | - | var templ_7745c5c3_Var61 string | 1305 | + | var templ_7745c5c3_Var63 string |
| 1260 | - | templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) | 1306 | + | templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name) |
| 1261 | if templ_7745c5c3_Err != nil { | 1307 | if templ_7745c5c3_Err != nil { | ||
| 1262 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 257, Col: 34} | 1308 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 265, Col: 34} |
| 1263 | } | 1309 | } | ||
| 1264 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61)) | 1310 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63)) |
| 1265 | if templ_7745c5c3_Err != nil { | 1311 | if templ_7745c5c3_Err != nil { | ||
| 1266 | return templ_7745c5c3_Err | 1312 | return templ_7745c5c3_Err | ||
| 1267 | } | 1313 | } | ||
| 1268 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</td><td class=\"c-when nowrap\"><time") | 1314 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "</td><td class=\"c-when nowrap\"><time") |
| 1269 | if templ_7745c5c3_Err != nil { | 1315 | if templ_7745c5c3_Err != nil { | ||
| 1270 | return templ_7745c5c3_Err | 1316 | return templ_7745c5c3_Err | ||
| 1271 | } | 1317 | } | ||
| 1272 | if r.CreatedAt != "" { | 1318 | if r.CreatedAt != "" { | ||
| 1273 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, " datetime=\"") | 1319 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, " datetime=\"") |
| 1274 | if templ_7745c5c3_Err != nil { | 1320 | if templ_7745c5c3_Err != nil { | ||
| 1275 | return templ_7745c5c3_Err | 1321 | return templ_7745c5c3_Err | ||
| 1276 | } | 1322 | } | ||
| 1277 | - | var templ_7745c5c3_Var62 string | 1323 | + | var templ_7745c5c3_Var64 string |
| 1278 | - | templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.CreatedAt) | 1324 | + | templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.CreatedAt) |
| 1279 | if templ_7745c5c3_Err != nil { | 1325 | if templ_7745c5c3_Err != nil { | ||
| 1280 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 261, Col: 32} | 1326 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 269, Col: 32} |
| 1281 | } | 1327 | } | ||
| 1282 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62) | 1328 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64) |
| 1283 | if templ_7745c5c3_Err != nil { | 1329 | if templ_7745c5c3_Err != nil { | ||
| 1284 | return templ_7745c5c3_Err | 1330 | return templ_7745c5c3_Err | ||
| 1285 | } | 1331 | } | ||
| 1286 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "\"") | 1332 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "\"") |
| 1287 | if templ_7745c5c3_Err != nil { | 1333 | if templ_7745c5c3_Err != nil { | ||
| 1288 | return templ_7745c5c3_Err | 1334 | return templ_7745c5c3_Err | ||
| 1289 | } | 1335 | } | ||
| 1290 | } | 1336 | } | ||
| 1291 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, ">") | 1337 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, ">") |
| 1292 | if templ_7745c5c3_Err != nil { | 1338 | if templ_7745c5c3_Err != nil { | ||
| 1293 | return templ_7745c5c3_Err | 1339 | return templ_7745c5c3_Err | ||
| 1294 | } | 1340 | } | ||
| 1295 | - | var templ_7745c5c3_Var63 string | 1341 | + | var templ_7745c5c3_Var65 string |
| 1296 | - | templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(r.Created) | 1342 | + | templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(r.Created) |
| 1297 | if templ_7745c5c3_Err != nil { | 1343 | if templ_7745c5c3_Err != nil { | ||
| 1298 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 263, Col: 20} | 1344 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 271, Col: 20} |
| 1299 | } | 1345 | } | ||
| 1300 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63)) | 1346 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65)) |
| 1301 | if templ_7745c5c3_Err != nil { | 1347 | if templ_7745c5c3_Err != nil { | ||
| 1302 | return templ_7745c5c3_Err | 1348 | return templ_7745c5c3_Err | ||
| 1303 | } | 1349 | } | ||
| 1304 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "</time></td><td class=\"c-when nowrap\"><time") | 1350 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "</time></td><td class=\"c-when nowrap\"><time") |
| 1305 | if templ_7745c5c3_Err != nil { | 1351 | if templ_7745c5c3_Err != nil { | ||
| 1306 | return templ_7745c5c3_Err | 1352 | return templ_7745c5c3_Err | ||
| 1307 | } | 1353 | } | ||
| 1308 | if r.LastUsedAt != "" { | 1354 | if r.LastUsedAt != "" { | ||
| 1309 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, " datetime=\"") | 1355 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, " datetime=\"") |
| 1310 | if templ_7745c5c3_Err != nil { | 1356 | if templ_7745c5c3_Err != nil { | ||
| 1311 | return templ_7745c5c3_Err | 1357 | return templ_7745c5c3_Err | ||
| 1312 | } | 1358 | } | ||
| 1313 | - | var templ_7745c5c3_Var64 string | 1359 | + | var templ_7745c5c3_Var66 string |
| 1314 | - | templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.LastUsedAt) | 1360 | + | templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(r.LastUsedAt) |
| 1315 | if templ_7745c5c3_Err != nil { | 1361 | if templ_7745c5c3_Err != nil { | ||
| 1316 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 268, Col: 33} | 1362 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 276, Col: 33} |
| 1317 | } | 1363 | } | ||
| 1318 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64) | 1364 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66) |
| 1319 | if templ_7745c5c3_Err != nil { | 1365 | if templ_7745c5c3_Err != nil { | ||
| 1320 | return templ_7745c5c3_Err | 1366 | return templ_7745c5c3_Err | ||
| 1321 | } | 1367 | } | ||
| 1322 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "\"") | 1368 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\"") |
| 1323 | if templ_7745c5c3_Err != nil { | 1369 | if templ_7745c5c3_Err != nil { | ||
| 1324 | return templ_7745c5c3_Err | 1370 | return templ_7745c5c3_Err | ||
| 1325 | } | 1371 | } | ||
| 1326 | } | 1372 | } | ||
| 1327 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, ">") | 1373 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, ">") |
| 1328 | if templ_7745c5c3_Err != nil { | 1374 | if templ_7745c5c3_Err != nil { | ||
| 1329 | return templ_7745c5c3_Err | 1375 | return templ_7745c5c3_Err | ||
| 1330 | } | 1376 | } | ||
| 1331 | - | var templ_7745c5c3_Var65 string | 1377 | + | var templ_7745c5c3_Var67 string |
| 1332 | - | templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(r.LastUsed) | 1378 | + | templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(r.LastUsed) |
| 1333 | if templ_7745c5c3_Err != nil { | 1379 | if templ_7745c5c3_Err != nil { | ||
| 1334 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 270, Col: 21} | 1380 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 278, Col: 21} |
| 1335 | } | 1381 | } | ||
| 1336 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65)) | 1382 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67)) |
| 1337 | if templ_7745c5c3_Err != nil { | 1383 | if templ_7745c5c3_Err != nil { | ||
| 1338 | return templ_7745c5c3_Err | 1384 | return templ_7745c5c3_Err | ||
| 1339 | } | 1385 | } | ||
| 1340 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "</time></td><td class=\"c-sync\">") | 1386 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "</time></td><td class=\"c-sync\">") |
| 1341 | if templ_7745c5c3_Err != nil { | 1387 | if templ_7745c5c3_Err != nil { | ||
| 1342 | return templ_7745c5c3_Err | 1388 | return templ_7745c5c3_Err | ||
| 1343 | } | 1389 | } | ||
| 1344 | if r.Synced { | 1390 | if r.Synced { | ||
| 1345 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "yes") | 1391 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "yes") |
| 1346 | if templ_7745c5c3_Err != nil { | 1392 | if templ_7745c5c3_Err != nil { | ||
| 1347 | return templ_7745c5c3_Err | 1393 | return templ_7745c5c3_Err | ||
| 1348 | } | 1394 | } | ||
| 1349 | } else { | 1395 | } else { | ||
| 1350 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "no") | 1396 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "no") |
| 1351 | if templ_7745c5c3_Err != nil { | 1397 | if templ_7745c5c3_Err != nil { | ||
| 1352 | return templ_7745c5c3_Err | 1398 | return templ_7745c5c3_Err | ||
| 1353 | } | 1399 | } | ||
| 1354 | } | 1400 | } | ||
| 1355 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, "</td><td class=\"c-act\"><form method=\"post\" action=\"") | 1401 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "</td><td class=\"c-act\"><form method=\"post\" action=\"") |
| 1356 | if templ_7745c5c3_Err != nil { | 1402 | if templ_7745c5c3_Err != nil { | ||
| 1357 | return templ_7745c5c3_Err | 1403 | return templ_7745c5c3_Err | ||
| 1358 | } | 1404 | } | ||
| 1359 | - | var templ_7745c5c3_Var66 templ.SafeURL | 1405 | + | var templ_7745c5c3_Var68 templ.SafeURL |
| 1360 | - | templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Remove)) | 1406 | + | templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(r.Remove)) |
| 1361 | if templ_7745c5c3_Err != nil { | 1407 | if templ_7745c5c3_Err != nil { | ||
| 1362 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 280, Col: 60} | 1408 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 288, Col: 60} |
| 1363 | } | 1409 | } | ||
| 1364 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66)) | 1410 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68)) |
| 1365 | if templ_7745c5c3_Err != nil { | 1411 | if templ_7745c5c3_Err != nil { | ||
| 1366 | return templ_7745c5c3_Err | 1412 | return templ_7745c5c3_Err | ||
| 1367 | } | 1413 | } | ||
| 1368 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\"><button type=\"submit\" class=\"btn danger\" aria-label=\"") | 1414 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "\"><button type=\"submit\" class=\"btn danger\" aria-label=\"") |
| 1369 | if templ_7745c5c3_Err != nil { | 1415 | if templ_7745c5c3_Err != nil { | ||
| 1370 | return templ_7745c5c3_Err | 1416 | return templ_7745c5c3_Err | ||
| 1371 | } | 1417 | } | ||
| 1372 | - | var templ_7745c5c3_Var67 string | 1418 | + | var templ_7745c5c3_Var69 string |
| 1373 | - | templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue("Remove passkey " + r.Name) | 1419 | + | templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.ResolveAttributeValue("Remove passkey " + r.Name) |
| 1374 | if templ_7745c5c3_Err != nil { | 1420 | if templ_7745c5c3_Err != nil { | ||
| 1375 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 281, Col: 89} | 1421 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 289, Col: 89} |
| 1376 | } | 1422 | } | ||
| 1377 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67) | 1423 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var69) |
| 1378 | if templ_7745c5c3_Err != nil { | 1424 | if templ_7745c5c3_Err != nil { | ||
| 1379 | return templ_7745c5c3_Err | 1425 | return templ_7745c5c3_Err | ||
| 1380 | } | 1426 | } | ||
| 1381 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, "\">Remove</button></form></td></tr>") | 1427 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "\">Remove</button></form></td></tr>") |
| 1382 | if templ_7745c5c3_Err != nil { | 1428 | if templ_7745c5c3_Err != nil { | ||
| 1383 | return templ_7745c5c3_Err | 1429 | return templ_7745c5c3_Err | ||
| 1384 | } | 1430 | } | ||
| 1385 | } | 1431 | } | ||
| 1386 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "</tbody></table>") | 1432 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "</tbody></table>") |
| 1387 | if templ_7745c5c3_Err != nil { | 1433 | if templ_7745c5c3_Err != nil { | ||
| 1388 | return templ_7745c5c3_Err | 1434 | return templ_7745c5c3_Err | ||
| 1389 | } | 1435 | } | ||
| 1390 | } else { | 1436 | } else { | ||
| 1391 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "<p class=\"lede dim\">no passkeys yet.</p>") | 1437 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "<p class=\"lede dim\">no passkeys yet.</p>") |
| 1392 | if templ_7745c5c3_Err != nil { | 1438 | if templ_7745c5c3_Err != nil { | ||
| 1393 | return templ_7745c5c3_Err | 1439 | return templ_7745c5c3_Err | ||
| 1394 | } | 1440 | } | ||
| 1395 | } | 1441 | } | ||
| 1396 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, " ") | 1442 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, " ") |
| 1397 | if templ_7745c5c3_Err != nil { | 1443 | if templ_7745c5c3_Err != nil { | ||
| 1398 | return templ_7745c5c3_Err | 1444 | return templ_7745c5c3_Err | ||
| 1399 | } | 1445 | } | ||
| 1400 | if p.Full { | 1446 | if p.Full { | ||
| 1401 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "<p class=\"dim\">") | 1447 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 115, "<p class=\"dim\">") |
| 1402 | if templ_7745c5c3_Err != nil { | 1448 | if templ_7745c5c3_Err != nil { | ||
| 1403 | return templ_7745c5c3_Err | 1449 | return templ_7745c5c3_Err | ||
| 1404 | } | 1450 | } | ||
| 1405 | - | var templ_7745c5c3_Var68 string | 1451 | + | var templ_7745c5c3_Var70 string |
| 1406 | - | templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Max)) | 1452 | + | templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Max)) |
| 1407 | if templ_7745c5c3_Err != nil { | 1453 | if templ_7745c5c3_Err != nil { | ||
| 1408 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 292, Col: 31} | 1454 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 300, Col: 31} |
| 1409 | } | 1455 | } | ||
| 1410 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68)) | 1456 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70)) |
| 1411 | if templ_7745c5c3_Err != nil { | 1457 | if templ_7745c5c3_Err != nil { | ||
| 1412 | return templ_7745c5c3_Err | 1458 | return templ_7745c5c3_Err | ||
| 1413 | } | 1459 | } | ||
| 1414 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, " passkeys are registered, the most there can be. Remove one to add another.</p>") | 1460 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, " passkeys are registered, the most there can be. Remove one to add another.</p>") |
| 1415 | if templ_7745c5c3_Err != nil { | 1461 | if templ_7745c5c3_Err != nil { | ||
| 1416 | return templ_7745c5c3_Err | 1462 | return templ_7745c5c3_Err | ||
| 1417 | } | 1463 | } | ||
| 1418 | } else { | 1464 | } else { | ||
| 1419 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "<form class=\"passkey-add\" data-js data-passkey-form><label for=\"passkey-name\" class=\"sr\">Name of the new passkey</label> <input id=\"passkey-name\" type=\"text\" placeholder=\"Name, for example Pixel 9\" autocomplete=\"off\" data-passkey-name> <button type=\"submit\" class=\"btn primary\" data-passkey=\"register\" data-begin=\"") | 1465 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 117, "<form class=\"passkey-add\" data-js data-passkey-form><label for=\"passkey-name\" class=\"sr\">Name of the new passkey</label> <input id=\"passkey-name\" type=\"text\" placeholder=\"Name, for example Pixel 9\" autocomplete=\"off\" data-passkey-name> <button type=\"submit\" class=\"btn primary\" data-passkey=\"register\" data-begin=\"") |
| 1420 | if templ_7745c5c3_Err != nil { | 1466 | if templ_7745c5c3_Err != nil { | ||
| 1421 | return templ_7745c5c3_Err | 1467 | return templ_7745c5c3_Err | ||
| 1422 | } | 1468 | } | ||
| 1423 | - | var templ_7745c5c3_Var69 string | 1469 | + | var templ_7745c5c3_Var71 string |
| 1424 | - | templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) | 1470 | + | templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Begin) |
| 1425 | if templ_7745c5c3_Err != nil { | 1471 | if templ_7745c5c3_Err != nil { | ||
| 1426 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 297, Col: 90} | 1472 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 305, Col: 90} |
| 1427 | } | 1473 | } | ||
| 1428 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var69) | 1474 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71) |
| 1429 | if templ_7745c5c3_Err != nil { | 1475 | if templ_7745c5c3_Err != nil { | ||
| 1430 | return templ_7745c5c3_Err | 1476 | return templ_7745c5c3_Err | ||
| 1431 | } | 1477 | } | ||
| 1432 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "\" data-finish=\"") | 1478 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, "\" data-finish=\"") |
| 1433 | if templ_7745c5c3_Err != nil { | 1479 | if templ_7745c5c3_Err != nil { | ||
| 1434 | return templ_7745c5c3_Err | 1480 | return templ_7745c5c3_Err | ||
| 1435 | } | 1481 | } | ||
| 1436 | - | var templ_7745c5c3_Var70 string | 1482 | + | var templ_7745c5c3_Var72 string |
| 1437 | - | templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) | 1483 | + | templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Finish) |
| 1438 | if templ_7745c5c3_Err != nil { | 1484 | if templ_7745c5c3_Err != nil { | ||
| 1439 | - | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 297, Col: 115} | 1485 | + | return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/pages.templ`, Line: 305, Col: 115} |
| 1440 | } | 1486 | } | ||
| 1441 | - | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var70) | 1487 | + | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72) |
| 1442 | if templ_7745c5c3_Err != nil { | 1488 | if templ_7745c5c3_Err != nil { | ||
| 1443 | return templ_7745c5c3_Err | 1489 | return templ_7745c5c3_Err | ||
| 1444 | } | 1490 | } | ||
| 1445 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "\">Add a passkey</button></form>") | 1491 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "\">Add a passkey</button></form>") |
| 1446 | if templ_7745c5c3_Err != nil { | 1492 | if templ_7745c5c3_Err != nil { | ||
| 1447 | return templ_7745c5c3_Err | 1493 | return templ_7745c5c3_Err | ||
| 1448 | } | 1494 | } | ||
| 1449 | } | 1495 | } | ||
| 1450 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, " <p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") | 1496 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, " <p class=\"dim\" role=\"status\" aria-live=\"polite\" data-passkey-status></p>") |
| 1451 | if templ_7745c5c3_Err != nil { | 1497 | if templ_7745c5c3_Err != nil { | ||
| 1452 | return templ_7745c5c3_Err | 1498 | return templ_7745c5c3_Err | ||
| 1453 | } | 1499 | } | ||
| 1454 | return nil | 1500 | return nil | ||
| 1455 | }) | 1501 | }) | ||
| 1456 | - | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var59), templ_7745c5c3_Buffer) | 1502 | + | templ_7745c5c3_Err = Shell(l, nil).Render(templ.WithChildren(ctx, templ_7745c5c3_Var61), templ_7745c5c3_Buffer) |
| 1457 | if templ_7745c5c3_Err != nil { | 1503 | if templ_7745c5c3_Err != nil { | ||
| 1458 | return templ_7745c5c3_Err | 1504 | return templ_7745c5c3_Err | ||
| 1459 | } | 1505 | } | ||
M internal/adapters/web/static/css/60-mr.css +9 -0
| @@ -186,6 +186,15 @@ | |||
| 186 | 186 | } | |
| 187 | 187 | #mr-notice:empty { display: none; } | |
| 188 | 188 | ||
| 189 | + | /* the owner's inbox: counters, repository filter, then the two lists */ | |
| 190 | + | .inbox { | |
| 191 | + | display: flex; flex-direction: column; gap: var(--s4); | |
| 192 | + | & .inbox-counts { font-size: var(--fs-l, var(--fs)); color: var(--ink-dim); } | |
| 193 | + | & .inbox-counts strong { color: var(--ink-hi); font-family: var(--mono); } | |
| 194 | + | & .since { align-self: flex-start; max-width: 100%; } | |
| 195 | + | } | |
| 196 | + | .inbox-btn { gap: var(--s2); } | |
| 197 | + | ||
| 189 | 198 | @media (max-width: 700px) { | |
| 190 | 199 | .list.mrs .c-who { display: none; } | |
| 191 | 200 | } | |
| @@ -186,6 +186,15 @@ | |||||
| 186 | } | 186 | } | ||
| 187 | #mr-notice:empty { display: none; } | 187 | #mr-notice:empty { display: none; } | ||
| 188 | 188 | ||||
| 189 | + | /* the owner's inbox: counters, repository filter, then the two lists */ | |||
| 190 | + | .inbox { | |||
| 191 | + | display: flex; flex-direction: column; gap: var(--s4); | |||
| 192 | + | & .inbox-counts { font-size: var(--fs-l, var(--fs)); color: var(--ink-dim); } | |||
| 193 | + | & .inbox-counts strong { color: var(--ink-hi); font-family: var(--mono); } | |||
| 194 | + | & .since { align-self: flex-start; max-width: 100%; } | |||
| 195 | + | } | |||
| 196 | + | .inbox-btn { gap: var(--s2); } | |||
| 197 | + | ||||
| 189 | @media (max-width: 700px) { | 198 | @media (max-width: 700px) { | ||
| 190 | .list.mrs .c-who { display: none; } | 199 | .list.mrs .c-who { display: none; } | ||
| 191 | } | 200 | } | ||
M internal/adapters/web/view.go +10 -0
| @@ -135,6 +135,16 @@ type SortLink struct { | |||
| 135 | 135 | type HomePage struct { | |
| 136 | 136 | Sorts []SortLink | |
| 137 | 137 | Rows []HomeRow | |
| 138 | + | // Inbox is the button to the owner's inbox; nil unless the owner is signed | |
| 139 | + | // in. | |
| 140 | + | Inbox *InboxButton | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | // InboxButton is the link to the inbox with the number of open items; Count is | |
| 144 | + | // negative when it could not be read. | |
| 145 | + | type InboxButton struct { | |
| 146 | + | Href string | |
| 147 | + | Count int | |
| 138 | 148 | } | |
| 139 | 149 | ||
| 140 | 150 | // Fact is one key/value row of the facts block. | |
| @@ -135,6 +135,16 @@ type SortLink struct { | |||||
| 135 | type HomePage struct { | 135 | type HomePage struct { | ||
| 136 | Sorts []SortLink | 136 | Sorts []SortLink | ||
| 137 | Rows []HomeRow | 137 | Rows []HomeRow | ||
| 138 | + | // Inbox is the button to the owner's inbox; nil unless the owner is signed | |||
| 139 | + | // in. | |||
| 140 | + | Inbox *InboxButton | |||
| 141 | + | } | |||
| 142 | + | ||||
| 143 | + | // InboxButton is the link to the inbox with the number of open items; Count is | |||
| 144 | + | // negative when it could not be read. | |||
| 145 | + | type InboxButton struct { | |||
| 146 | + | Href string | |||
| 147 | + | Count int | |||
| 138 | } | 148 | } | ||
| 139 | 149 | ||||
| 140 | // Fact is one key/value row of the facts block. | 150 | // Fact is one key/value row of the facts block. | ||
M internal/adapters/web/web.go +7 -0
| @@ -63,6 +63,10 @@ type Config struct { | |||
| 63 | 63 | // it there is no such redirect. Leave it unset rather than assigning a | |
| 64 | 64 | // typed nil pointer. | |
| 65 | 65 | IssueNumbers ports.IssueNumberResolver | |
| 66 | + | // Inbox serves the owner's inbox page (/-/inbox) and the button that | |
| 67 | + | // leads to it. Without it there is neither. Leave it unset rather than | |
| 68 | + | // assigning a typed nil pointer. | |
| 69 | + | Inbox ports.InboxService | |
| 66 | 70 | // Runs serves the CI pages (/<repo>/actions) and the checks shown next to | |
| 67 | 71 | // commits and merge requests. Without it there are no such pages. Leave it | |
| 68 | 72 | // unset rather than assigning a typed nil pointer. | |
| @@ -175,6 +179,9 @@ func (s *Server) routes() *http.ServeMux { | |||
| 175 | 179 | if s.passkeysOn() { | |
| 176 | 180 | s.passkeyRoutes(mux) | |
| 177 | 181 | } | |
| 182 | + | if s.cfg.Inbox != nil { | |
| 183 | + | mux.HandleFunc("GET "+inboxPath, s.page(s.inbox)) | |
| 184 | + | } | |
| 178 | 185 | mux.HandleFunc("GET /{$}", s.page(s.home)) | |
| 179 | 186 | mux.HandleFunc("GET /{repo}", s.page(s.summary)) | |
| 180 | 187 | mux.HandleFunc("GET /{repo}/{$}", s.page(s.summary)) | |
| @@ -63,6 +63,10 @@ type Config struct { | |||||
| 63 | // it there is no such redirect. Leave it unset rather than assigning a | 63 | // it there is no such redirect. Leave it unset rather than assigning a | ||
| 64 | // typed nil pointer. | 64 | // typed nil pointer. | ||
| 65 | IssueNumbers ports.IssueNumberResolver | 65 | IssueNumbers ports.IssueNumberResolver | ||
| 66 | + | // Inbox serves the owner's inbox page (/-/inbox) and the button that | |||
| 67 | + | // leads to it. Without it there is neither. Leave it unset rather than | |||
| 68 | + | // assigning a typed nil pointer. | |||
| 69 | + | Inbox ports.InboxService | |||
| 66 | // Runs serves the CI pages (/<repo>/actions) and the checks shown next to | 70 | // Runs serves the CI pages (/<repo>/actions) and the checks shown next to | ||
| 67 | // commits and merge requests. Without it there are no such pages. Leave it | 71 | // commits and merge requests. Without it there are no such pages. Leave it | ||
| 68 | // unset rather than assigning a typed nil pointer. | 72 | // unset rather than assigning a typed nil pointer. | ||
| @@ -175,6 +179,9 @@ func (s *Server) routes() *http.ServeMux { | |||||
| 175 | if s.passkeysOn() { | 179 | if s.passkeysOn() { | ||
| 176 | s.passkeyRoutes(mux) | 180 | s.passkeyRoutes(mux) | ||
| 177 | } | 181 | } | ||
| 182 | + | if s.cfg.Inbox != nil { | |||
| 183 | + | mux.HandleFunc("GET "+inboxPath, s.page(s.inbox)) | |||
| 184 | + | } | |||
| 178 | mux.HandleFunc("GET /{$}", s.page(s.home)) | 185 | mux.HandleFunc("GET /{$}", s.page(s.home)) | ||
| 179 | mux.HandleFunc("GET /{repo}", s.page(s.summary)) | 186 | mux.HandleFunc("GET /{repo}", s.page(s.summary)) | ||
| 180 | mux.HandleFunc("GET /{repo}/{$}", s.page(s.summary)) | 187 | mux.HandleFunc("GET /{repo}/{$}", s.page(s.summary)) | ||
M internal/app/testdata/web/commits-root.html +1 -1
| @@ -972,7 +972,7 @@ | |||
| 972 | 972 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | |
| 973 | 973 | htmx:sse:error -> ermiteLive.error(event.detail.status); | |
| 974 | 974 | htmx:sse:before:connection -> ermiteLive.gate(event); | |
| 975 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | |
| 975 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); | |
| 976 | 976 | gap -> ermiteLive.reload()"> | |
| 977 | 977 | </span> | |
| 978 | 978 | </div> | |
| @@ -972,7 +972,7 @@ | |||||
| 972 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | 972 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | ||
| 973 | htmx:sse:error -> ermiteLive.error(event.detail.status); | 973 | htmx:sse:error -> ermiteLive.error(event.detail.status); | ||
| 974 | htmx:sse:before:connection -> ermiteLive.gate(event); | 974 | htmx:sse:before:connection -> ermiteLive.gate(event); | ||
| 975 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | 975 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); |
| 976 | gap -> ermiteLive.reload()"> | 976 | gap -> ermiteLive.reload()"> | ||
| 977 | </span> | 977 | </span> | ||
| 978 | </div> | 978 | </div> | ||
M internal/app/testdata/web/commits-small.html +1 -1
| @@ -317,7 +317,7 @@ | |||
| 317 | 317 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | |
| 318 | 318 | htmx:sse:error -> ermiteLive.error(event.detail.status); | |
| 319 | 319 | htmx:sse:before:connection -> ermiteLive.gate(event); | |
| 320 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | |
| 320 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); | |
| 321 | 321 | gap -> ermiteLive.reload()"> | |
| 322 | 322 | </span> | |
| 323 | 323 | </div> | |
| @@ -317,7 +317,7 @@ | |||||
| 317 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | 317 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | ||
| 318 | htmx:sse:error -> ermiteLive.error(event.detail.status); | 318 | htmx:sse:error -> ermiteLive.error(event.detail.status); | ||
| 319 | htmx:sse:before:connection -> ermiteLive.gate(event); | 319 | htmx:sse:before:connection -> ermiteLive.gate(event); | ||
| 320 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | 320 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); |
| 321 | gap -> ermiteLive.reload()"> | 321 | gap -> ermiteLive.reload()"> | ||
| 322 | </span> | 322 | </span> | ||
| 323 | </div> | 323 | </div> | ||
M internal/app/testdata/web/home.html +1 -1
| @@ -191,7 +191,7 @@ | |||
| 191 | 191 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | |
| 192 | 192 | htmx:sse:error -> ermiteLive.error(event.detail.status); | |
| 193 | 193 | htmx:sse:before:connection -> ermiteLive.gate(event); | |
| 194 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | |
| 194 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); | |
| 195 | 195 | gap -> ermiteLive.reload()"> | |
| 196 | 196 | </span> | |
| 197 | 197 | </div> | |
| @@ -191,7 +191,7 @@ | |||||
| 191 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | 191 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | ||
| 192 | htmx:sse:error -> ermiteLive.error(event.detail.status); | 192 | htmx:sse:error -> ermiteLive.error(event.detail.status); | ||
| 193 | htmx:sse:before:connection -> ermiteLive.gate(event); | 193 | htmx:sse:before:connection -> ermiteLive.gate(event); | ||
| 194 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | 194 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); |
| 195 | gap -> ermiteLive.reload()"> | 195 | gap -> ermiteLive.reload()"> | ||
| 196 | </span> | 196 | </span> | ||
| 197 | </div> | 197 | </div> | ||
M internal/app/testdata/web/refs.html +1 -1
| @@ -199,7 +199,7 @@ | |||
| 199 | 199 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | |
| 200 | 200 | htmx:sse:error -> ermiteLive.error(event.detail.status); | |
| 201 | 201 | htmx:sse:before:connection -> ermiteLive.gate(event); | |
| 202 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | |
| 202 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); | |
| 203 | 203 | gap -> ermiteLive.reload()"> | |
| 204 | 204 | </span> | |
| 205 | 205 | </div> | |
| @@ -199,7 +199,7 @@ | |||||
| 199 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | 199 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | ||
| 200 | htmx:sse:error -> ermiteLive.error(event.detail.status); | 200 | htmx:sse:error -> ermiteLive.error(event.detail.status); | ||
| 201 | htmx:sse:before:connection -> ermiteLive.gate(event); | 201 | htmx:sse:before:connection -> ermiteLive.gate(event); | ||
| 202 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | 202 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); |
| 203 | gap -> ermiteLive.reload()"> | 203 | gap -> ermiteLive.reload()"> | ||
| 204 | </span> | 204 | </span> | ||
| 205 | </div> | 205 | </div> | ||
M internal/app/testdata/web/summary.html +1 -1
| @@ -225,7 +225,7 @@ | |||
| 225 | 225 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | |
| 226 | 226 | htmx:sse:error -> ermiteLive.error(event.detail.status); | |
| 227 | 227 | htmx:sse:before:connection -> ermiteLive.gate(event); | |
| 228 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | |
| 228 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); | |
| 229 | 229 | gap -> ermiteLive.reload()"> | |
| 230 | 230 | </span> | |
| 231 | 231 | </div> | |
| @@ -225,7 +225,7 @@ | |||||
| 225 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | 225 | htmx:sse:close, htmx:sse:error -> ermiteLive.lost(); | ||
| 226 | htmx:sse:error -> ermiteLive.error(event.detail.status); | 226 | htmx:sse:error -> ermiteLive.error(event.detail.status); | ||
| 227 | htmx:sse:before:connection -> ermiteLive.gate(event); | 227 | htmx:sse:before:connection -> ermiteLive.gate(event); | ||
| 228 | - | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job -> ermiteLive.swap(event.detail.data); | 228 | + | home-list, repo-last-push, refs-list, commits-head, mr-notice, ci-run, ci-job, inbox -> ermiteLive.swap(event.detail.data); |
| 229 | gap -> ermiteLive.reload()"> | 229 | gap -> ermiteLive.reload()"> | ||
| 230 | </span> | 230 | </span> | ||
| 231 | </div> | 231 | </div> | ||
M internal/app/web.go +1 -0
| @@ -47,6 +47,7 @@ func newWeb(cfg config.Config, f *forge, limiter *clientlimit.Limiter) (http.Han | |||
| 47 | 47 | MergeRequests: f.MergeRequests, | |
| 48 | 48 | Issues: f.Issues, | |
| 49 | 49 | IssueNumbers: f.Issues, | |
| 50 | + | Inbox: f.Inbox, | |
| 50 | 51 | Runs: f.CI, | |
| 51 | 52 | Artifacts: artifacts, | |
| 52 | 53 | Events: f.EventLog, | |
| @@ -47,6 +47,7 @@ func newWeb(cfg config.Config, f *forge, limiter *clientlimit.Limiter) (http.Han | |||||
| 47 | MergeRequests: f.MergeRequests, | 47 | MergeRequests: f.MergeRequests, | ||
| 48 | Issues: f.Issues, | 48 | Issues: f.Issues, | ||
| 49 | IssueNumbers: f.Issues, | 49 | IssueNumbers: f.Issues, | ||
| 50 | + | Inbox: f.Inbox, | |||
| 50 | Runs: f.CI, | 51 | Runs: f.CI, | ||
| 51 | Artifacts: artifacts, | 52 | Artifacts: artifacts, | ||
| 52 | Events: f.EventLog, | 53 | Events: f.EventLog, | ||
A internal/app/web_inbox_test.go +152 -0
| @@ -0,0 +1,152 @@ | |||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | + | ||
| 3 | + | package app | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "bufio" | |
| 7 | + | "context" | |
| 8 | + | "net/http" | |
| 9 | + | "strings" | |
| 10 | + | "testing" | |
| 11 | + | ||
| 12 | + | "github.com/stretchr/testify/assert" | |
| 13 | + | "github.com/stretchr/testify/require" | |
| 14 | + | ||
| 15 | + | "bnema.dev/ermite/internal/domain" | |
| 16 | + | "bnema.dev/ermite/internal/ports" | |
| 17 | + | ) | |
| 18 | + | ||
| 19 | + | // The owner's inbox end to end: two repositories with open merge requests and | |
| 20 | + | // issues, the filter, the home button, the owner stream, and a 404 for | |
| 21 | + | // everyone who is not the signed-in owner. | |
| 22 | + | func TestWebInboxEndToEnd(t *testing.T) { | |
| 23 | + | r := newMRRepo(t, domain.VisibilityPublic) | |
| 24 | + | b := browser{r.harness} | |
| 25 | + | token := r.signIn(t) | |
| 26 | + | ||
| 27 | + | _, err := r.forge.Repos.Create(r.ctx, domain.Root(), createParams(r.harness, "other", domain.VisibilityPrivate)) | |
| 28 | + | require.NoError(t, err) | |
| 29 | + | otherURL := r.urlAuth(adminToken, "/other.git") | |
| 30 | + | r.mustGit(r.wt, "push", "-q", otherURL, "main") | |
| 31 | + | r.mustGit(r.wt, "push", "-q", otherURL, "feat/search") | |
| 32 | + | ||
| 33 | + | owner := domain.IssuesOwner | |
| 34 | + | for _, n := range []string{"proj", "other"} { | |
| 35 | + | _, err := r.forge.Repos.Update(r.ctx, domain.Root(), r.name(n), ports.UpdateRepoParams{Issues: &owner}) | |
| 36 | + | require.NoError(t, err) | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | // Nothing is open yet. | |
| 40 | + | empty := b.get("/-/inbox", as(token)) | |
| 41 | + | require.Equal(t, 200, empty.status, empty.body) | |
| 42 | + | assert.Contains(t, empty.body, "no open merge requests.") | |
| 43 | + | assert.Contains(t, empty.body, "no open issues.") | |
| 44 | + | ||
| 45 | + | // The owner stream sees both repositories. | |
| 46 | + | stream := ownerStream(t, r.harness, token) | |
| 47 | + | ||
| 48 | + | root := domain.Root() | |
| 49 | + | _, err = r.forge.MergeRequests.Create(r.ctx, root, r.name("proj"), ports.CreateMergeRequestParams{Title: "add search", Source: "feat/search", Target: "main"}) | |
| 50 | + | require.NoError(t, err) | |
| 51 | + | ev := stream.next(t, watchWait) | |
| 52 | + | assert.Equal(t, "inbox", ev.name) | |
| 53 | + | assert.Contains(t, ev.data, `id="inbox-counts"`) | |
| 54 | + | for range 3 { // the other fragments of this event | |
| 55 | + | stream.next(t, watchWait) | |
| 56 | + | } | |
| 57 | + | _, err = r.forge.Issues.Create(r.ctx, root, r.name("other"), ports.CreateIssueParams{Title: "search is slow"}) | |
| 58 | + | require.NoError(t, err) | |
| 59 | + | var seen strings.Builder | |
| 60 | + | for range 4 { // the four fragments of this event | |
| 61 | + | seen.WriteString(stream.next(t, watchWait).data) | |
| 62 | + | } | |
| 63 | + | assert.Contains(t, seen.String(), "search is slow", "an event of the second repository") | |
| 64 | + | _, err = r.forge.MergeRequests.Create(r.ctx, root, r.name("other"), ports.CreateMergeRequestParams{Title: "other work", Source: "feat/search", Target: "main"}) | |
| 65 | + | require.NoError(t, err) | |
| 66 | + | _, err = r.forge.Issues.Create(r.ctx, root, r.name("proj"), ports.CreateIssueParams{Title: "proj bug"}) | |
| 67 | + | require.NoError(t, err) | |
| 68 | + | ||
| 69 | + | all := b.get("/-/inbox", as(token)) | |
| 70 | + | require.Equal(t, 200, all.status, all.body) | |
| 71 | + | assert.Equal(t, "private, no-store", all.hdr.Get("Cache-Control")) | |
| 72 | + | assert.Contains(t, all.body, "<strong>2</strong> merge requests · <strong>2</strong> issues") | |
| 73 | + | for _, want := range []string{"add search", "other work", "search is slow", "proj bug", `href="/other/issues/`, `href="/proj/merge-requests/`} { | |
| 74 | + | assert.Contains(t, all.body, want) | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | only := b.get("/-/inbox?repo=other", as(token)) | |
| 78 | + | require.Equal(t, 200, only.status) | |
| 79 | + | assert.Contains(t, only.body, "<strong>2</strong> merge requests · <strong>2</strong> issues", "the counters ignore the filter") | |
| 80 | + | assert.Contains(t, only.body, "other work") | |
| 81 | + | assert.Contains(t, only.body, "search is slow") | |
| 82 | + | assert.NotContains(t, only.body, "add search") | |
| 83 | + | assert.NotContains(t, only.body, "proj bug") | |
| 84 | + | ||
| 85 | + | // Issues off: that repository's issues leave the inbox, its merge requests stay. | |
| 86 | + | off := domain.IssuesOff | |
| 87 | + | _, err = r.forge.Repos.Update(r.ctx, root, r.name("other"), ports.UpdateRepoParams{Issues: &off}) | |
| 88 | + | require.NoError(t, err) | |
| 89 | + | hidden := b.get("/-/inbox", as(token)) | |
| 90 | + | assert.Contains(t, hidden.body, "<strong>2</strong> merge requests · <strong>1</strong> issues") | |
| 91 | + | assert.NotContains(t, hidden.body, "search is slow") | |
| 92 | + | ||
| 93 | + | // The home button, for the owner only. | |
| 94 | + | assert.Contains(t, b.get("/", as(token)).body, `href="/-/inbox"`) | |
| 95 | + | anonHome := b.get("/", nil) | |
| 96 | + | assert.NotContains(t, anonHome.body, "/-/inbox") | |
| 97 | + | assert.NotContains(t, anonHome.body, "Inbox") | |
| 98 | + | ||
| 99 | + | // Anyone else: the 404 of an unknown page, and no stream. | |
| 100 | + | missing := b.get("/-/no-such-page", nil) | |
| 101 | + | anon := b.get("/-/inbox", nil) | |
| 102 | + | assert.Equal(t, 404, anon.status) | |
| 103 | + | assert.Equal(t, missing.body, anon.body) | |
| 104 | + | assert.Equal(t, 404, b.get("/-/inbox", map[string]string{"Authorization": "Bearer " + adminToken}).status, "a token is not a session") | |
| 105 | + | unknown := b.get("/-/events?topic=nope&view=inbox", nil) | |
| 106 | + | ownerAnon := b.get("/-/events?topic=owner&view=inbox", nil) | |
| 107 | + | assert.Equal(t, unknown.status, ownerAnon.status, "the answer to an unknown topic") | |
| 108 | + | assert.Equal(t, strings.ReplaceAll(unknown.body, "nope", "owner"), ownerAnon.body) | |
| 109 | + | assert.Equal(t, unknown.status, b.get("/-/events?topic=owner&view=inbox", map[string]string{"Authorization": "Bearer " + adminToken}).status) | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // ownerStream opens the owner topic with the session cookie. | |
| 113 | + | func ownerStream(t *testing.T, h *harness, token string) *sseStream { | |
| 114 | + | t.Helper() | |
| 115 | + | ctx, cancel := context.WithCancel(h.ctx) | |
| 116 | + | t.Cleanup(cancel) | |
| 117 | + | req, err := http.NewRequestWithContext(ctx, http.MethodGet, h.url("/-/events?topic=owner&view=inbox"), nil) | |
| 118 | + | require.NoError(t, err) | |
| 119 | + | req.Header.Set("Cookie", sessionCookie+"="+token) | |
| 120 | + | resp, err := http.DefaultClient.Do(req) | |
| 121 | + | require.NoError(t, err) | |
| 122 | + | t.Cleanup(func() { _ = resp.Body.Close() }) | |
| 123 | + | require.Equal(t, http.StatusOK, resp.StatusCode) | |
| 124 | + | s := &sseStream{resp: resp, events: make(chan sseEvent, 256), cancel: cancel} | |
| 125 | + | go func() { | |
| 126 | + | defer close(s.events) | |
| 127 | + | sc := bufio.NewScanner(resp.Body) | |
| 128 | + | sc.Buffer(make([]byte, 0, 64<<10), 1<<20) | |
| 129 | + | var cur sseEvent | |
| 130 | + | var data []string | |
| 131 | + | for sc.Scan() { | |
| 132 | + | line := sc.Text() | |
| 133 | + | switch { | |
| 134 | + | case line == "": | |
| 135 | + | if cur.id != "" || cur.name != "" || len(data) > 0 { | |
| 136 | + | cur.data = strings.Join(data, "\n") | |
| 137 | + | s.events <- cur | |
| 138 | + | } | |
| 139 | + | cur, data = sseEvent{}, nil | |
| 140 | + | case strings.HasPrefix(line, ":"): | |
| 141 | + | cur.comment = true | |
| 142 | + | case strings.HasPrefix(line, "event: "): | |
| 143 | + | cur.name = strings.TrimPrefix(line, "event: ") | |
| 144 | + | case strings.HasPrefix(line, "id: "): | |
| 145 | + | cur.id = strings.TrimPrefix(line, "id: ") | |
| 146 | + | case strings.HasPrefix(line, "data: "): | |
| 147 | + | data = append(data, strings.TrimPrefix(line, "data: ")) | |
| 148 | + | } | |
| 149 | + | } | |
| 150 | + | }() | |
| 151 | + | return s | |
| 152 | + | } | |
| @@ -0,0 +1,152 @@ | |||||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |||
| 2 | + | ||||
| 3 | + | package app | |||
| 4 | + | ||||
| 5 | + | import ( | |||
| 6 | + | "bufio" | |||
| 7 | + | "context" | |||
| 8 | + | "net/http" | |||
| 9 | + | "strings" | |||
| 10 | + | "testing" | |||
| 11 | + | ||||
| 12 | + | "github.com/stretchr/testify/assert" | |||
| 13 | + | "github.com/stretchr/testify/require" | |||
| 14 | + | ||||
| 15 | + | "bnema.dev/ermite/internal/domain" | |||
| 16 | + | "bnema.dev/ermite/internal/ports" | |||
| 17 | + | ) | |||
| 18 | + | ||||
| 19 | + | // The owner's inbox end to end: two repositories with open merge requests and | |||
| 20 | + | // issues, the filter, the home button, the owner stream, and a 404 for | |||
| 21 | + | // everyone who is not the signed-in owner. | |||
| 22 | + | func TestWebInboxEndToEnd(t *testing.T) { | |||
| 23 | + | r := newMRRepo(t, domain.VisibilityPublic) | |||
| 24 | + | b := browser{r.harness} | |||
| 25 | + | token := r.signIn(t) | |||
| 26 | + | ||||
| 27 | + | _, err := r.forge.Repos.Create(r.ctx, domain.Root(), createParams(r.harness, "other", domain.VisibilityPrivate)) | |||
| 28 | + | require.NoError(t, err) | |||
| 29 | + | otherURL := r.urlAuth(adminToken, "/other.git") | |||
| 30 | + | r.mustGit(r.wt, "push", "-q", otherURL, "main") | |||
| 31 | + | r.mustGit(r.wt, "push", "-q", otherURL, "feat/search") | |||
| 32 | + | ||||
| 33 | + | owner := domain.IssuesOwner | |||
| 34 | + | for _, n := range []string{"proj", "other"} { | |||
| 35 | + | _, err := r.forge.Repos.Update(r.ctx, domain.Root(), r.name(n), ports.UpdateRepoParams{Issues: &owner}) | |||
| 36 | + | require.NoError(t, err) | |||
| 37 | + | } | |||
| 38 | + | ||||
| 39 | + | // Nothing is open yet. | |||
| 40 | + | empty := b.get("/-/inbox", as(token)) | |||
| 41 | + | require.Equal(t, 200, empty.status, empty.body) | |||
| 42 | + | assert.Contains(t, empty.body, "no open merge requests.") | |||
| 43 | + | assert.Contains(t, empty.body, "no open issues.") | |||
| 44 | + | ||||
| 45 | + | // The owner stream sees both repositories. | |||
| 46 | + | stream := ownerStream(t, r.harness, token) | |||
| 47 | + | ||||
| 48 | + | root := domain.Root() | |||
| 49 | + | _, err = r.forge.MergeRequests.Create(r.ctx, root, r.name("proj"), ports.CreateMergeRequestParams{Title: "add search", Source: "feat/search", Target: "main"}) | |||
| 50 | + | require.NoError(t, err) | |||
| 51 | + | ev := stream.next(t, watchWait) | |||
| 52 | + | assert.Equal(t, "inbox", ev.name) | |||
| 53 | + | assert.Contains(t, ev.data, `id="inbox-counts"`) | |||
| 54 | + | for range 3 { // the other fragments of this event | |||
| 55 | + | stream.next(t, watchWait) | |||
| 56 | + | } | |||
| 57 | + | _, err = r.forge.Issues.Create(r.ctx, root, r.name("other"), ports.CreateIssueParams{Title: "search is slow"}) | |||
| 58 | + | require.NoError(t, err) | |||
| 59 | + | var seen strings.Builder | |||
| 60 | + | for range 4 { // the four fragments of this event | |||
| 61 | + | seen.WriteString(stream.next(t, watchWait).data) | |||
| 62 | + | } | |||
| 63 | + | assert.Contains(t, seen.String(), "search is slow", "an event of the second repository") | |||
| 64 | + | _, err = r.forge.MergeRequests.Create(r.ctx, root, r.name("other"), ports.CreateMergeRequestParams{Title: "other work", Source: "feat/search", Target: "main"}) | |||
| 65 | + | require.NoError(t, err) | |||
| 66 | + | _, err = r.forge.Issues.Create(r.ctx, root, r.name("proj"), ports.CreateIssueParams{Title: "proj bug"}) | |||
| 67 | + | require.NoError(t, err) | |||
| 68 | + | ||||
| 69 | + | all := b.get("/-/inbox", as(token)) | |||
| 70 | + | require.Equal(t, 200, all.status, all.body) | |||
| 71 | + | assert.Equal(t, "private, no-store", all.hdr.Get("Cache-Control")) | |||
| 72 | + | assert.Contains(t, all.body, "<strong>2</strong> merge requests · <strong>2</strong> issues") | |||
| 73 | + | for _, want := range []string{"add search", "other work", "search is slow", "proj bug", `href="/other/issues/`, `href="/proj/merge-requests/`} { | |||
| 74 | + | assert.Contains(t, all.body, want) | |||
| 75 | + | } | |||
| 76 | + | ||||
| 77 | + | only := b.get("/-/inbox?repo=other", as(token)) | |||
| 78 | + | require.Equal(t, 200, only.status) | |||
| 79 | + | assert.Contains(t, only.body, "<strong>2</strong> merge requests · <strong>2</strong> issues", "the counters ignore the filter") | |||
| 80 | + | assert.Contains(t, only.body, "other work") | |||
| 81 | + | assert.Contains(t, only.body, "search is slow") | |||
| 82 | + | assert.NotContains(t, only.body, "add search") | |||
| 83 | + | assert.NotContains(t, only.body, "proj bug") | |||
| 84 | + | ||||
| 85 | + | // Issues off: that repository's issues leave the inbox, its merge requests stay. | |||
| 86 | + | off := domain.IssuesOff | |||
| 87 | + | _, err = r.forge.Repos.Update(r.ctx, root, r.name("other"), ports.UpdateRepoParams{Issues: &off}) | |||
| 88 | + | require.NoError(t, err) | |||
| 89 | + | hidden := b.get("/-/inbox", as(token)) | |||
| 90 | + | assert.Contains(t, hidden.body, "<strong>2</strong> merge requests · <strong>1</strong> issues") | |||
| 91 | + | assert.NotContains(t, hidden.body, "search is slow") | |||
| 92 | + | ||||
| 93 | + | // The home button, for the owner only. | |||
| 94 | + | assert.Contains(t, b.get("/", as(token)).body, `href="/-/inbox"`) | |||
| 95 | + | anonHome := b.get("/", nil) | |||
| 96 | + | assert.NotContains(t, anonHome.body, "/-/inbox") | |||
| 97 | + | assert.NotContains(t, anonHome.body, "Inbox") | |||
| 98 | + | ||||
| 99 | + | // Anyone else: the 404 of an unknown page, and no stream. | |||
| 100 | + | missing := b.get("/-/no-such-page", nil) | |||
| 101 | + | anon := b.get("/-/inbox", nil) | |||
| 102 | + | assert.Equal(t, 404, anon.status) | |||
| 103 | + | assert.Equal(t, missing.body, anon.body) | |||
| 104 | + | assert.Equal(t, 404, b.get("/-/inbox", map[string]string{"Authorization": "Bearer " + adminToken}).status, "a token is not a session") | |||
| 105 | + | unknown := b.get("/-/events?topic=nope&view=inbox", nil) | |||
| 106 | + | ownerAnon := b.get("/-/events?topic=owner&view=inbox", nil) | |||
| 107 | + | assert.Equal(t, unknown.status, ownerAnon.status, "the answer to an unknown topic") | |||
| 108 | + | assert.Equal(t, strings.ReplaceAll(unknown.body, "nope", "owner"), ownerAnon.body) | |||
| 109 | + | assert.Equal(t, unknown.status, b.get("/-/events?topic=owner&view=inbox", map[string]string{"Authorization": "Bearer " + adminToken}).status) | |||
| 110 | + | } | |||
| 111 | + | ||||
| 112 | + | // ownerStream opens the owner topic with the session cookie. | |||
| 113 | + | func ownerStream(t *testing.T, h *harness, token string) *sseStream { | |||
| 114 | + | t.Helper() | |||
| 115 | + | ctx, cancel := context.WithCancel(h.ctx) | |||
| 116 | + | t.Cleanup(cancel) | |||
| 117 | + | req, err := http.NewRequestWithContext(ctx, http.MethodGet, h.url("/-/events?topic=owner&view=inbox"), nil) | |||
| 118 | + | require.NoError(t, err) | |||
| 119 | + | req.Header.Set("Cookie", sessionCookie+"="+token) | |||
| 120 | + | resp, err := http.DefaultClient.Do(req) | |||
| 121 | + | require.NoError(t, err) | |||
| 122 | + | t.Cleanup(func() { _ = resp.Body.Close() }) | |||
| 123 | + | require.Equal(t, http.StatusOK, resp.StatusCode) | |||
| 124 | + | s := &sseStream{resp: resp, events: make(chan sseEvent, 256), cancel: cancel} | |||
| 125 | + | go func() { | |||
| 126 | + | defer close(s.events) | |||
| 127 | + | sc := bufio.NewScanner(resp.Body) | |||
| 128 | + | sc.Buffer(make([]byte, 0, 64<<10), 1<<20) | |||
| 129 | + | var cur sseEvent | |||
| 130 | + | var data []string | |||
| 131 | + | for sc.Scan() { | |||
| 132 | + | line := sc.Text() | |||
| 133 | + | switch { | |||
| 134 | + | case line == "": | |||
| 135 | + | if cur.id != "" || cur.name != "" || len(data) > 0 { | |||
| 136 | + | cur.data = strings.Join(data, "\n") | |||
| 137 | + | s.events <- cur | |||
| 138 | + | } | |||
| 139 | + | cur, data = sseEvent{}, nil | |||
| 140 | + | case strings.HasPrefix(line, ":"): | |||
| 141 | + | cur.comment = true | |||
| 142 | + | case strings.HasPrefix(line, "event: "): | |||
| 143 | + | cur.name = strings.TrimPrefix(line, "event: ") | |||
| 144 | + | case strings.HasPrefix(line, "id: "): | |||
| 145 | + | cur.id = strings.TrimPrefix(line, "id: ") | |||
| 146 | + | case strings.HasPrefix(line, "data: "): | |||
| 147 | + | data = append(data, strings.TrimPrefix(line, "data: ")) | |||
| 148 | + | } | |||
| 149 | + | } | |||
| 150 | + | }() | |||
| 151 | + | return s | |||
| 152 | + | } | |||