From e62ba3c1b668eed1828bf939fdd2de0a619ae87c Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Tue, 14 Feb 2023 16:42:26 +0100 Subject: dashboard: display the list of applied filters Currently it's non obvious whether and what filters are applied to a bug list. Display the list to the user and enable them to drop individual filters. --- dashboard/app/main.go | 45 +++++++++++++++++++++++++++++++++++--------- dashboard/app/main.html | 5 ++++- dashboard/app/main_test.go | 26 +++++++++++++++++++++++++ dashboard/app/templates.html | 17 +++++++++++++++++ dashboard/app/terminal.html | 1 + pkg/html/html.go | 6 +++++- 6 files changed, 89 insertions(+), 11 deletions(-) diff --git a/dashboard/app/main.go b/dashboard/app/main.go index 51e876705..9435aa456 100644 --- a/dashboard/app/main.go +++ b/dashboard/app/main.go @@ -71,9 +71,25 @@ type uiMainPage struct { Now time.Time Decommissioned bool Managers *uiManagerList + BugFilter *uiBugFilter Groups []*uiBugGroup } +type uiBugFilter struct { + Filter *userBugFilter + DropURL func(string) string +} + +func makeUIBugFilter(c context.Context, filter *userBugFilter) *uiBugFilter { + url := getCurrentURL(c) + return &uiBugFilter{ + Filter: filter, + DropURL: func(name string) string { + return html.AmendURL(url, name, "") + }, + } +} + type uiManagerList struct { RepoLink string List []*uiManager @@ -87,10 +103,11 @@ func makeManagerList(managers []*uiManager, ns string) *uiManagerList { } type uiTerminalPage struct { - Header *uiHeader - Now time.Time - Bugs *uiBugGroup - Stats *uiBugStats + Header *uiHeader + Now time.Time + Bugs *uiBugGroup + Stats *uiBugStats + BugFilter *uiBugFilter } type uiBugStats struct { @@ -314,7 +331,8 @@ func MakeBugFilter(r *http.Request) *userBugFilter { } func (filter *userBugFilter) MatchManagerName(name string) bool { - return filter == nil || filter.Manager == name || filter.OnlyManager == name + target := filter.ManagerName() + return target == "" || target == name } func (filter *userBugFilter) ManagerName() string { @@ -343,6 +361,13 @@ func (filter *userBugFilter) MatchBug(bug *Bug) bool { return true } +func (filter *userBugFilter) Any() bool { + if filter == nil { + return false + } + return filter.Subsystem != "" || filter.OnlyManager != "" || filter.Manager != "" +} + // handleMain serves main page. func handleMain(c context.Context, w http.ResponseWriter, r *http.Request) error { hdr, err := commonHeader(c, r, w, "") @@ -368,6 +393,7 @@ func handleMain(c context.Context, w http.ResponseWriter, r *http.Request) error Now: timeNow(c), Groups: groups, Managers: makeManagerList(managers, hdr.Namespace), + BugFilter: makeUIBugFilter(c, filter), } return serveTemplate(w, "main.html", data) } @@ -438,10 +464,11 @@ func handleTerminalBugList(c context.Context, w http.ResponseWriter, r *http.Req stats = nil } data := &uiTerminalPage{ - Header: hdr, - Now: timeNow(c), - Bugs: bugs, - Stats: stats, + Header: hdr, + Now: timeNow(c), + Bugs: bugs, + Stats: stats, + BugFilter: makeUIBugFilter(c, typ.Filter), } return serveTemplate(w, "terminal.html", data) } diff --git a/dashboard/app/main.html b/dashboard/app/main.html index 89f273fae..a0ed079ea 100644 --- a/dashboard/app/main.html +++ b/dashboard/app/main.html @@ -14,7 +14,10 @@ Main page. {{template "header" .Header}} {{if $.Decommissioned}}

This kernel is DECOMMISSIONED

{{end}} - {{template "manager_list" $.Managers}} + {{if not $.BugFilter.Filter.Any}} + {{template "manager_list" $.Managers}} + {{end}} + {{template "bug_filter" $.BugFilter}} {{range $group := $.Groups}} {{template "bug_list" $group}} {{end}} diff --git a/dashboard/app/main_test.go b/dashboard/app/main_test.go index d344f4ce2..84ee49d70 100644 --- a/dashboard/app/main_test.go +++ b/dashboard/app/main_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/google/syzkaller/dashboard/dashapi" + "github.com/stretchr/testify/assert" ) func TestOnlyManagerFilter(t *testing.T) { @@ -156,3 +157,28 @@ func TestSubsystemFilterTerminal(t *testing.T) { t.Fatalf("%#v is not contained on the invalid bugs page", crash2.Title) } } + +func TestMainBugFilters(t *testing.T) { + c := NewCtx(t) + defer c.Close() + + client := c.client + build1 := testBuild(1) + build1.Manager = "manager-name-123" + client.UploadBuild(build1) + + crash1 := testCrash(build1, 1) + client.ReportCrash(crash1) + client.pollBugs(1) + + // The normal main page. + reply, err := c.AuthGET(AccessAdmin, "/test1") + c.expectOK(err) + assert.Contains(t, string(reply), build1.Manager) + assert.NotContains(t, string(reply), "Applied filters") + + reply, err = c.AuthGET(AccessAdmin, "/test1?subsystem=abcd") + c.expectOK(err) + 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 +} diff --git a/dashboard/app/templates.html b/dashboard/app/templates.html index 01055dd5c..0420aef25 100644 --- a/dashboard/app/templates.html +++ b/dashboard/app/templates.html @@ -79,6 +79,23 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
{{end}} +{{/* List of enabled filters, invoked with *uiBugFilter */}} +{{define "bug_filter"}} +{{if .Filter.Any}} + Applied filters: + {{if .Filter.Manager}} + Manager={{.Filter.Manager}} ({{link (call .DropURL "manager") "drop"}}) + {{end}} + {{if .Filter.OnlyManager}} + Only Manager={{.Filter.OnlyManager}} ({{link (call .DropURL "only_manager") "drop"}}) + {{end}} + {{if .Filter.Subsystem}} + Subsystem={{.Filter.Subsystem}} ({{link (call .DropURL "subsystem") "drop"}}) + {{end}} +
+{{end}} +{{end}} + {{/* List of bugs, invoked with *uiBugGroup */}} {{define "bug_list"}} {{if .}} diff --git a/dashboard/app/terminal.html b/dashboard/app/terminal.html index cc0da050c..43d539f4c 100644 --- a/dashboard/app/terminal.html +++ b/dashboard/app/terminal.html @@ -21,6 +21,7 @@ Out of {{.Total}} bugs, {{.AutoObsoleted}} were automatically obso {{end}} {{end}} + {{template "bug_filter" $.BugFilter}} {{template "bug_list" .Bugs}} diff --git a/pkg/html/html.go b/pkg/html/html.go index c89c42fbb..046a35b4c 100644 --- a/pkg/html/html.go +++ b/pkg/html/html.go @@ -202,7 +202,11 @@ func AmendURL(baseURL, key, value string) string { return "" } values := parsed.Query() - values.Set(key, value) + if value == "" { + values.Del(key) + } else { + values.Set(key, value) + } parsed.RawQuery = values.Encode() return parsed.String() } -- cgit mrf-deployment