web: check status and a path filter on the log, visible focus in the rail !80
merged
merged by cmc on 2026-08-26 05:14 UTC
· krz/gitbay:log-polish into main
Conversation
Commits 1
Files changed 4
4 files changed, +63 −3
Layout: unified · split
internal/httpd/web.go
+3 −1
@@ -1183,12 +1183,14 @@ func (s *Server) log(w http.ResponseWriter, r *http.Request) {
1183 type row struct {
1183 type row struct {
1184 SHA , ShortSHA , Subject , AuthorName , AuthorEmail , AuthorUser , Date string
1184 SHA , ShortSHA , Subject , AuthorName , AuthorEmail , AuthorUser , Date string
1185 Sig sigView
1185 Sig sigView
1186 Check string // combined status, "" when none ran
1186 }
1187 }
1187 names := s . authorNames ( )
1188 names := s . authorNames ( )
1189 checks , _ := s . st . CombinedStatusFor ( p . Repo . ID , shas )
1188 var rows [ ] row
1190 var rows [ ] row
1189 for _ , sha := range shas {
1191 for _ , sha := range shas {
1190 v , parsed := s . sigFor ( p . Repo , p . Dir , sha )
1192 v , parsed := s . sigFor ( p . Repo , p . Dir , sha )
1191 rw := row { SHA : sha , ShortSHA : sha [ : 10 ] , Sig : v }
1193 rw := row { SHA : sha , ShortSHA : sha [ : 10 ] , Sig : v , Check : checks [ sha ] }
1192 if parsed != nil {
1194 if parsed != nil {
1193 rw . Subject = parsed . Subject
1195 rw . Subject = parsed . Subject
1194 rw . AuthorName = names . name ( parsed . AuthorEmail , parsed . AuthorName )
1196 rw . AuthorName = names . name ( parsed . AuthorEmail , parsed . AuthorName )
internal/store/statuses.go
+41
@@ -1,5 +1,7 @@
1 package store
1 package store
2
2
3 import "strings"
4
3 type CommitStatus struct {
5 type CommitStatus struct {
4 Context string
6 Context string
5 State string // pending | success | failure | error
7 State string // pending | success | failure | error
@@ -50,6 +52,45 @@ func (s *Store) ListCommitStatuses(repoID int64, sha string) ([]CommitStatus, er
50
52
51 // CombinedStatus reduces per-context states to one: error/failure dominate,
53 // CombinedStatus reduces per-context states to one: error/failure dominate,
52 // then pending, then success; "" when no statuses exist.
54 // then pending, then success; "" when no statuses exist.
55 // CombinedStatusFor returns the combined state for each of several commits
56 // in one query. The log lists fifty commits at a time; asking per commit
57 // turns one page into fifty round trips.
58 func ( s * Store ) CombinedStatusFor ( repoID int64 , shas [ ] string ) ( map [ string ] string , error ) {
59 out := map [ string ] string { }
60 if len ( shas ) == 0 {
61 return out , nil
62 }
63 args := make ( [ ] any , 0 , len ( shas ) + 1 )
64 args = append ( args , repoID )
65 for _ , sha := range shas {
66 args = append ( args , sha )
67 }
68 q := ` SELECT commit_sha, state FROM commit_statuses WHERE repo_id = ? AND commit_sha IN (? ` +
69 strings . Repeat ( ",?" , len ( shas ) - 1 ) + ` ) `
70 rows , err := s . DB . Query ( q , args ... )
71 if err != nil {
72 return nil , err
73 }
74 defer rows . Close ( )
75 for rows . Next ( ) {
76 var sha , state string
77 if err := rows . Scan ( & sha , & state ) ; err != nil {
78 return nil , err
79 }
80 // Same precedence as CombinedStatus, folded in as rows arrive.
81 switch {
82 case out [ sha ] == "failure" :
83 case state == "error" || state == "failure" :
84 out [ sha ] = "failure"
85 case state == "pending" :
86 out [ sha ] = "pending"
87 case out [ sha ] == "" :
88 out [ sha ] = "success"
89 }
90 }
91 return out , rows . Err ( )
92 }
93
53 func CombinedStatus ( statuses [ ] CommitStatus ) string {
94 func CombinedStatus ( statuses [ ] CommitStatus ) string {
54 if len ( statuses ) == 0 {
95 if len ( statuses ) == 0 {
55 return ""
96 return ""
internal/web/static/style.css
+10
@@ -144,6 +144,10 @@ a:hover { text-decoration: underline; }
144 outline-offset : 2px ;
144 outline-offset : 2px ;
145 border-radius : 1px ;
145 border-radius : 1px ;
146 }
146 }
147 /* the shell is black in both schemes, and --accent is a dark blue in the
148 light one — a ring nobody could see. The shell's own mark clears 7:1 on
149 black either way. */
150 . rail : focus-visible { outline-color : var ( - - shell - mark ) ; }
147
151
148 /* visually hidden, still read aloud: for headings a sighted reader gets
152 /* visually hidden, still read aloud: for headings a sighted reader gets
149 from the layout but a screen reader would otherwise miss */
153 from the layout but a screen reader would otherwise miss */
@@ -800,6 +804,12 @@ pre.message {
800 . teambody { padding : var ( - - sp -3 ) ; background : var ( - - bg ) ; }
804 . teambody { padding : var ( - - sp -3 ) ; background : var ( - - bg ) ; }
801 . teambody . memberchip { margin-right : var ( - - sp -2 ) ; }
805 . teambody . memberchip { margin-right : var ( - - sp -2 ) ; }
802
806
807 form . logfilter {
808 display : flex ; align-items : center ; gap : var ( - - sp -2 ) ;
809 margin : 0 0 var ( - - sp -4 ) ; flex-wrap : wrap ;
810 }
811 form . logfilter input { flex : 1 ; min-width : 12 rem ; max-width : 28 rem ; }
812
803 /* account settings */
813 /* account settings */
804 table . keys td { padding : var ( - - sp -2 ) var ( - - sp -4 ) var ( - - sp -2 ) 0 ; }
814 table . keys td { padding : var ( - - sp -2 ) var ( - - sp -4 ) var ( - - sp -2 ) 0 ; }
805 table . keys td . mono , . mono { font-family : var ( - - mono ) ; font-size : var ( - - fs -1 ) ; overflow-wrap : anywhere ; }
815 table . keys td . mono , . mono { font-family : var ( - - mono ) ; font-size : var ( - - fs -1 ) ; overflow-wrap : anywhere ; }
internal/web/templates/log.html
+9 −2
@@ -1,14 +1,21 @@
1 {{define "title"}}log · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}}
1 {{define "title"}}log · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}}
2 {{define "content"}}
2 {{define "content"}}
3 {{if .FilePath}}< p class = "meta" > history of < a href = "/{{.Repo.OwnerName}}/{{.Repo.Name}}/blob/{{.Ref}}/{{.FilePath}}" > < code > {{.FilePath}}< / code > < / a > · < a href = "/{{.Repo.OwnerName}}/{{.Repo.Name}}/log" > full log< / a > < / p > {{end}}
4 < h1 class = "vh" > Commits< / h1 >
3 < h1 class = "vh" > Commits< / h1 >
4 < form method = "get" class = "logfilter" action = "/{{.Repo.OwnerName}}/{{.Repo.Name}}/log/{{.Ref}}" >
5 < label for = "path" > Path< / label >
6 < input type = "text" id = "path" name = "path" value = "{{.FilePath}}" placeholder = "filter to a file or directory" >
7 < button type = "submit" > Filter< / button >
8 {{if .FilePath}}< a class = "act" href = "/{{.Repo.OwnerName}}/{{.Repo.Name}}/log/{{.Ref}}" > Clear< / a > {{end}}
9 < / form >
10 {{if .FilePath}}< p class = "meta" > history of < a href = "/{{.Repo.OwnerName}}/{{.Repo.Name}}/blob/{{.Ref}}/{{.FilePath}}" > < code > {{.FilePath}}< / code > < / a > < / p > {{end}}
5 < ul class = "loglist" >
11 < ul class = "loglist" >
6 {{range .Commits}}< li >
12 {{range .Commits}}{{$c := .}}< li >
7 < div class = "commitmain" >
13 < div class = "commitmain" >
8 < p class = "subject" > < a href = "/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}" > {{.Subject}}< / a > < / p >
14 < p class = "subject" > < a href = "/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}" > {{.Subject}}< / a > < / p >
9 < p class = "meta" > {{template "authorname" dict "Name" .AuthorName "User" .AuthorUser "Email" .AuthorEmail}} · {{.Date}}< / p >
15 < p class = "meta" > {{template "authorname" dict "Name" .AuthorName "User" .AuthorUser "Email" .AuthorEmail}} · {{.Date}}< / p >
10 < / div >
16 < / div >
11 < div class = "commitside" >
17 < div class = "commitside" >
18 {{with .Check}}< a class = "badge badge-{{.}}" href = "/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{$c.SHA}}" title = "checks: {{.}}" > {{.}}< / a > {{end}}
12 {{template "sigbadge" .Sig}}
19 {{template "sigbadge" .Sig}}
13 < code > < a href = "/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}" > {{.ShortSHA}}< / a > < / code >
20 < code > < a href = "/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}" > {{.ShortSHA}}< / a > < / code >
14 < / div >
21 < / div >
Checks
success
ci/build success 2026-08-26 05:14 UTC · 9s
Revisions
1. 73c8e291f7 2026-09-04 18:53 UTC
Source and target
krz/gitbay:log-polish into main
merged at 73c8e291f7 · base fa1784cbc9 · branch deleted