diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2023-02-16 18:37:12 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2023-02-17 12:00:36 +0100 |
| commit | bc63aac79a4640f951b050c537ba040bb231449b (patch) | |
| tree | 45c308692b866132b65cb219c16742657808b868 | |
| parent | 5fe5301b69de36dc64cf350d6924cb3e7b54b9ba (diff) | |
dashboard: display the subsystem list
Take the counts from the cache, include links to the filtered bug views.
| -rw-r--r-- | dashboard/app/handler.go | 2 | ||||
| -rw-r--r-- | dashboard/app/main.go | 64 | ||||
| -rw-r--r-- | dashboard/app/main_test.go | 27 | ||||
| -rw-r--r-- | dashboard/app/subsystems.html | 41 | ||||
| -rw-r--r-- | dashboard/app/templates.html | 4 | ||||
| -rw-r--r-- | pkg/html/pages/style.css | 4 | ||||
| -rw-r--r-- | pkg/subsystem/service.go | 8 |
7 files changed, 148 insertions, 2 deletions
diff --git a/dashboard/app/handler.go b/dashboard/app/handler.go index cb998a516..333d7847d 100644 --- a/dashboard/app/handler.go +++ b/dashboard/app/handler.go @@ -129,6 +129,7 @@ type uiHeader struct { Namespace string BugCounts *CachedBugStats Namespaces []uiNamespace + ShowSubsystems bool } type uiNamespace struct { @@ -203,6 +204,7 @@ func commonHeader(c context.Context, r *http.Request, w http.ResponseWriter, ns } if ns != adminPage { h.Namespace = ns + h.ShowSubsystems = getSubsystemService(c, ns) != nil cookie.Namespace = ns encodeCookie(w, cookie) cached, err := CacheGet(c, r, ns) diff --git a/dashboard/app/main.go b/dashboard/app/main.go index 661d7e992..fa31a7ab2 100644 --- a/dashboard/app/main.go +++ b/dashboard/app/main.go @@ -60,6 +60,7 @@ func initHTTPHandlers() { http.Handle("/"+ns+"/graph/crashes", handlerWrapper(handleGraphCrashes)) http.Handle("/"+ns+"/repos", handlerWrapper(handleRepos)) http.Handle("/"+ns+"/bug-stats", handlerWrapper(handleBugStats)) + http.Handle("/"+ns+"/subsystems", handlerWrapper(handleSubsystemsList)) } http.HandleFunc("/cron/cache_update", cacheUpdate) http.HandleFunc("/cron/deprecate_assets", handleDeprecateAssets) @@ -144,6 +145,25 @@ type uiRepo struct { Alias string } +type uiSubsystemsPage struct { + Header *uiHeader + List []*uiSubsystem +} + +type uiSubsystem struct { + Name string + Lists string + Maintainers string + Open uiSubsystemStats + Fixed uiSubsystemStats + Invalid uiSubsystemStats +} + +type uiSubsystemStats struct { + Count int + Link string +} + type uiAdminPage struct { Header *uiHeader Log []byte @@ -770,6 +790,50 @@ func getUIJob(c context.Context, bug *Bug, jobType JobType) (*uiJob, error) { return makeUIJob(job, jobKey, bug, crash, build), nil } +func handleSubsystemsList(c context.Context, w http.ResponseWriter, r *http.Request) error { + hdr, err := commonHeader(c, r, w, "") + if err != nil { + return err + } + cached, err := CacheGet(c, r, hdr.Namespace) + if err != nil { + return err + } + service := getSubsystemService(c, hdr.Namespace) + if service == nil { + return fmt.Errorf("the namespace does not have subsystems") + } + list := []*uiSubsystem{} + for _, item := range service.List() { + stats := cached.Subsystems[item.Name] + list = append(list, &uiSubsystem{ + Name: item.Name, + Lists: strings.Join(item.Lists, ", "), + Maintainers: strings.Join(item.Maintainers, ", "), + Open: uiSubsystemStats{ + Count: stats.Open, + Link: html.AmendURL("/"+hdr.Namespace, + "subsystem", item.Name), + }, + Fixed: uiSubsystemStats{ + Count: stats.Fixed, + Link: html.AmendURL("/"+hdr.Namespace+"/fixed", + "subsystem", item.Name), + }, + Invalid: uiSubsystemStats{ + Count: stats.Invalid, + Link: html.AmendURL("/"+hdr.Namespace+"/invalid", + "subsystem", item.Name), + }, + }) + } + sort.Slice(list, func(i, j int) bool { return list[i].Name < list[j].Name }) + return serveTemplate(w, "subsystems.html", &uiSubsystemsPage{ + Header: hdr, + List: list, + }) +} + // handleText serves plain text blobs (crash logs, reports, reproducers, etc). func handleTextImpl(c context.Context, w http.ResponseWriter, r *http.Request, tag string) error { var id int64 diff --git a/dashboard/app/main_test.go b/dashboard/app/main_test.go index 88cb0dcf5..e69dd0275 100644 --- a/dashboard/app/main_test.go +++ b/dashboard/app/main_test.go @@ -183,3 +183,30 @@ func TestMainBugFilters(t *testing.T) { assert.NotContains(t, string(reply), build1.Manager) // managers are hidden assert.Contains(t, string(reply), "Applied filters") // we're seeing a prompt to disable the filter } + +func TestSubsystemsList(t *testing.T) { + c := NewCtx(t) + defer c.Close() + + client := c.client + build := testBuild(1) + client.UploadBuild(build) + + crash1 := testCrash(build, 1) + crash1.GuiltyFiles = []string{"a.c"} + client.ReportCrash(crash1) + client.pollBug() + + crash2 := testCrash(build, 2) + crash2.GuiltyFiles = []string{"b.c"} + client.ReportCrash(crash2) + client.updateBug(client.pollBug().ID, dashapi.BugStatusInvalid, "") + + _, err := c.AuthGET(AccessUser, "/cron/refresh_subsystems") + c.expectOK(err) + + reply, err := c.AuthGET(AccessAdmin, "/test1/subsystems") + c.expectOK(err) + assert.Contains(t, string(reply), "subsystemA") + assert.Contains(t, string(reply), "subsystemB") +} diff --git a/dashboard/app/subsystems.html b/dashboard/app/subsystems.html new file mode 100644 index 000000000..254a113fe --- /dev/null +++ b/dashboard/app/subsystems.html @@ -0,0 +1,41 @@ +{{/* +Copyright 2023 syzkaller project authors. All rights reserved. +Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +The list of polled trees. +*/}} + +<!doctype html> +<html> +<head> + {{template "head" .Header}} + <title>syzbot</title> +</head> +<body> + {{template "header" .Header}} + <h2>The list of subsystems</h2><br> + <i>(*) Note that the numbers below do not represent the latest data. They are updated once an hour.</i><br> + <i>(**) If you have any ideas/suggestions on how to improve this list, feel free to contact us at <a href="mailto:syzkaller@googlegroups.com">syzkaller@googlegroups.com</a>.</i> + <table class="list_table"> + <caption>Subsystems list</caption> + <tr> + <th>Name</th> + <th>Lists</th> + <th>Maintainers</th> + <th>Open bugs</th> + <th>Fixed</th> + <th>Invalid</th> + </tr> + {{range $item := .List}} + <tr> + <td>{{$item.Name}}</td> + <td>{{$item.Lists}}</td> + <td class="maintainers">{{$item.Maintainers}}</td> + <td>{{link $item.Open.Link (printf "%d" $item.Open.Count)}}</td> + <td>{{link $item.Fixed.Link (printf "%d" $item.Fixed.Count)}}</td> + <td>{{link $item.Invalid.Link (printf "%d" $item.Invalid.Count)}}</td> + </tr> + {{end}} + </table> +</body> +</html> diff --git a/dashboard/app/templates.html b/dashboard/app/templates.html index 2b7ef61c1..f40361f85 100644 --- a/dashboard/app/templates.html +++ b/dashboard/app/templates.html @@ -63,6 +63,10 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the <span style="color:ForestGreen;">🐞</span> Fixed [{{$.BugCounts.Fixed}}]</a> <a class="navigation_tab{{if eq .URLPath (printf "/%v/invalid" $.Namespace)}}_selected{{end}}" href='/{{$.Namespace}}/invalid'> <span style="color:RoyalBlue;">🐞</span> Invalid [{{$.BugCounts.Invalid}}]</a> + {{if .ShowSubsystems}} + <a class="navigation_tab{{if eq .URLPath (printf "/%v/subsystems" $.Namespace)}}_selected{{end}}" href='/{{$.Namespace}}/subsystems'> + <span style="color:DeepPink;">≡</span> Subsystems</a> + {{end}} <a class="navigation_tab{{if eq .URLPath (printf "/%v/graph/bugs" $.Namespace)}}_selected{{end}}" href='/{{$.Namespace}}/graph/bugs'> <span style="color:DarkOrange;">📈</span> Kernel Health</a> <a class="navigation_tab{{if eq .URLPath (printf "/%v/graph/lifetimes" $.Namespace)}}_selected{{end}}" href='/{{$.Namespace}}/graph/lifetimes'> diff --git a/pkg/html/pages/style.css b/pkg/html/pages/style.css index aecde7554..ebeb7d012 100644 --- a/pkg/html/pages/style.css +++ b/pkg/html/pages/style.css @@ -140,8 +140,8 @@ table td, table th { } .list_table .maintainers { - width: 150pt; - max-width: 150pt; + max-width: 300pt; + white-space: normal; } .list_table .result { diff --git a/pkg/subsystem/service.go b/pkg/subsystem/service.go index b27200c30..d8c144cc4 100644 --- a/pkg/subsystem/service.go +++ b/pkg/subsystem/service.go @@ -45,3 +45,11 @@ func MakeService(list []*Subsystem) (*Service, error) { func (s *Service) ByName(name string) *Subsystem { return s.perName[name] } + +func (s *Service) List() []*Subsystem { + ret := []*Subsystem{} + for _, item := range s.perName { + ret = append(ret, item) + } + return ret +} |
