aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2023-04-06 18:39:39 +0200
committerAleksandr Nogikh <wp32pw@gmail.com>2023-04-07 09:55:58 +0200
commitf7ba566df7167369062324a989c8c848e12433ab (patch)
tree813d7d9d614541da0b5dc628d0cdd04ed23d05e2
parent132eb7c803ad81798b4c6f36326e43cd0ba18b17 (diff)
dashboard: display collapsible info sections on the bug page
Instead of showing tons of extra information to the user, only show the collapsed titles with counts and let user toggle the sections they need.
-rw-r--r--dashboard/app/bug.html24
-rw-r--r--dashboard/app/main.go94
-rw-r--r--dashboard/app/templates.html5
-rw-r--r--pkg/html/pages/common.js14
-rw-r--r--pkg/html/pages/style.css29
5 files changed, 127 insertions, 39 deletions
diff --git a/dashboard/app/bug.html b/dashboard/app/bug.html
index 252b33ebd..23f2c6689 100644
--- a/dashboard/app/bug.html
+++ b/dashboard/app/bug.html
@@ -39,21 +39,27 @@ Page with details about a single bug.
<div class="bug-bisection-stop"></div>
</div>
- {{template "discussions_list" .Discussions}}
- {{template "bug_list" .DupOf}}
- {{template "bug_list" .Dups}}
- {{template "bug_list" .Similar}}
- {{template "job_list" .TestPatchJobs}}
+ {{range $item := .Sections}}
+ <div class="collapsible {{if $item.Show}}collapsible-show{{else}}collapsible-hide{{end}}">
+ <div class="head">
+ <span class="show-icon">&#9654;</span>
+ <span class="hide-icon">&#9650;</span>
+ <span>{{$item.Title}}</span>
+ </div>
+ <div class="content">
+ {{if eq $item.Type "bug_list"}}{{template "bug_list" $item.Value}}{{end}}
+ {{if eq $item.Type "job_list"}}{{template "job_list" $item.Value}}{{end}}
+ {{if eq $item.Type "crash_list"}}{{template "crash_list" $item.Value}}{{end}}
+ {{if eq $item.Type "discussion_list"}}{{template "discussion_list" $item.Value}}{{end}}
+ </div>
+ </div>
+ {{end}}
{{if .SampleReport}}
<br><b>Sample crash report:</b><br>
<div id="crash_div"><pre>{{.SampleReport}}</pre></div><br>
{{end}}
- {{if .FixBisections}}
- {{template "crash_list" .FixBisections}}
- {{end}}
-
{{template "crash_list" .Crashes}}
</body>
</html>
diff --git a/dashboard/app/main.go b/dashboard/app/main.go
index b86c3ea23..97babdf55 100644
--- a/dashboard/app/main.go
+++ b/dashboard/app/main.go
@@ -242,15 +242,25 @@ type uiBugPage struct {
Bug *uiBug
BisectCause *uiJob
BisectFix *uiJob
- DupOf *uiBugGroup
- Dups *uiBugGroup
- Similar *uiBugGroup
+ Sections []*uiCollapsible
SampleReport template.HTML
Crashes *uiCrashTable
- FixBisections *uiCrashTable
TestPatchJobs *uiJobList
Subsystems []*uiBugSubsystem
- Discussions []*uiBugDiscussion
+}
+
+const (
+ sectionBugList = "bug_list"
+ sectionJobList = "job_list"
+ sectionCrashList = "crash_list"
+ sectionDiscussionList = "discussion_list"
+)
+
+type uiCollapsible struct {
+ Title string
+ Show bool // By default it's collapsed.
+ Type string // Template system understands it.
+ Value interface{}
}
type uiBugGroup struct {
@@ -644,6 +654,7 @@ func handleAdmin(c context.Context, w http.ResponseWriter, r *http.Request) erro
}
// handleBug serves page about a single bug (which is passed in id argument).
+// nolint: funlen, gocyclo
func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error {
bug, err := findBugByID(c, r)
if err != nil {
@@ -665,18 +676,22 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
if err != nil {
return err
}
- var dupOf *uiBugGroup
+ sections := []*uiCollapsible{}
if bug.DupOf != "" {
dup := new(Bug)
if err := db.Get(c, db.NewKey(c, "Bug", bug.DupOf, 0, nil), dup); err != nil {
return err
}
if accessLevel >= dup.sanitizeAccess(accessLevel) {
- dupOf = &uiBugGroup{
- Now: timeNow(c),
- Caption: "Duplicate of",
- Bugs: []*uiBug{createUIBug(c, dup, state, managers)},
- }
+ sections = append(sections, &uiCollapsible{
+ Title: "Duplicate of",
+ Show: true,
+ Type: sectionBugList,
+ Value: &uiBugGroup{
+ Now: timeNow(c),
+ Bugs: []*uiBug{createUIBug(c, dup, state, managers)},
+ },
+ })
}
}
uiBug := createUIBug(c, bug, state, managers)
@@ -692,10 +707,25 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
if err != nil {
return err
}
+ if len(dups.Bugs) > 0 {
+ sections = append(sections, &uiCollapsible{
+ Title: fmt.Sprintf("Duplicate bugs (%d)", len(dups.Bugs)),
+ Type: sectionBugList,
+ Value: dups,
+ })
+ }
similar, err := loadSimilarBugsUI(c, r, bug, state)
if err != nil {
return err
}
+ if len(similar.Bugs) > 0 {
+ sections = append(sections, &uiCollapsible{
+ Title: fmt.Sprintf("Similar bugs (%d)", len(similar.Bugs)),
+ Type: sectionBugList,
+ Value: similar,
+ })
+ }
+
var bisectCause *uiJob
if bug.BisectCause > BisectPending {
bisectCause, err = getUIJob(c, bug, JobBisectCause)
@@ -710,31 +740,41 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
return err
}
}
- testPatchJobs, err := loadTestPatchJobs(c, bug)
+ discussions, err := getBugDiscussionsUI(c, bug)
if err != nil {
return err
}
- discussions, err := getBugDiscussionsUI(c, bug)
+ if len(discussions) > 0 {
+ sections = append(sections, &uiCollapsible{
+ Title: fmt.Sprintf("Discussions (%d)", len(discussions)),
+ Show: true,
+ Type: sectionDiscussionList,
+ Value: discussions,
+ })
+ }
+ testPatchJobs, err := loadTestPatchJobs(c, bug)
if err != nil {
return err
}
+ if len(testPatchJobs) > 0 {
+ sections = append(sections, &uiCollapsible{
+ Title: fmt.Sprintf("Last patch testing requests (%d)", len(testPatchJobs)),
+ Type: sectionJobList,
+ Value: &uiJobList{
+ PerBug: true,
+ Jobs: testPatchJobs,
+ },
+ })
+ }
data := &uiBugPage{
Header: hdr,
Now: timeNow(c),
Bug: uiBug,
BisectCause: bisectCause,
BisectFix: bisectFix,
- DupOf: dupOf,
- Dups: dups,
- Similar: similar,
+ Sections: sections,
SampleReport: sampleReport,
Crashes: crashesTable,
- TestPatchJobs: &uiJobList{
- Title: "Last patch testing requests:",
- PerBug: true,
- Jobs: testPatchJobs,
- },
- Discussions: discussions,
}
for _, entry := range bug.Tags.Subsystems {
data.Subsystems = append(data.Subsystems, makeBugSubsystemUI(c, bug, entry))
@@ -748,10 +788,11 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
return err
}
if len(fixBisections) != 0 {
- data.FixBisections = &uiCrashTable{
- Crashes: fixBisections,
- Caption: "Fix bisection attempts",
- }
+ data.Sections = append(data.Sections, &uiCollapsible{
+ Title: fmt.Sprintf("Fix bisection attempts (%d)", len(fixBisections)),
+ Type: sectionCrashList,
+ Value: &uiCrashTable{Crashes: fixBisections},
+ })
}
}
@@ -1331,7 +1372,6 @@ func loadSimilarBugsUI(c context.Context, r *http.Request, bug *Bug, state *Repo
}
group := &uiBugGroup{
Now: timeNow(c),
- Caption: "similar bugs",
ShowNamespace: true,
ShowPatched: true,
ShowStatus: true,
diff --git a/dashboard/app/templates.html b/dashboard/app/templates.html
index 840f8073e..62f37b5cd 100644
--- a/dashboard/app/templates.html
+++ b/dashboard/app/templates.html
@@ -356,7 +356,7 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
{{define "crash_list"}}
{{if .}}
<table class="list_table">
- <caption>{{.Caption}}:</caption>
+ {{if .Caption}}<caption>{{.Caption}}:</caption>{{end}}
<thead>
<tr>
<th><a onclick="return sortTable(this, 'Time', textSort, true)" href="#">Time</a></th>
@@ -506,10 +506,9 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
{{end}}
{{/* List of discussions, invoked with []*uiBugDiscussion */}}
-{{define "discussions_list"}}
+{{define "discussion_list"}}
{{if .}}
<table class="list_table">
- <caption id="managers">Discussions:</caption>
<thead>
<tr>
<th>Title</th>
diff --git a/pkg/html/pages/common.js b/pkg/html/pages/common.js
index 95e6c8f61..80db71c8f 100644
--- a/pkg/html/pages/common.js
+++ b/pkg/html/pages/common.js
@@ -99,3 +99,17 @@ function addInputGroup(node) {
values.insertBefore(newGroup, lastGroup.nextSibling)
return false
}
+
+document.addEventListener("DOMContentLoaded", function() {
+ document.addEventListener('click', function(event) {
+ const collapsible = event.target.closest('.collapsible')
+ if (!collapsible) {
+ return
+ }
+ const toggle = event.target.closest('.collapsible .head');
+ if (toggle) {
+ collapsible.classList.toggle("collapsible-hide");
+ collapsible.classList.toggle("collapsible-show");
+ }
+ })
+})
diff --git a/pkg/html/pages/style.css b/pkg/html/pages/style.css
index 09bcc90a0..5e19eebef 100644
--- a/pkg/html/pages/style.css
+++ b/pkg/html/pages/style.css
@@ -342,3 +342,32 @@ aside {
clear: both;
margin-bottom: 10px;
}
+
+.collapsible {
+ border: 1px solid lightgrey;
+ margin-bottom: 15px;
+}
+
+.collapsible .content {
+ overflow-x: auto;
+}
+
+.collapsible .head {
+ max-width: 100%;
+ background-color: lightgrey;
+ padding: 5pt;
+ vertical-align: middle;
+ cursor: pointer;
+}
+
+.collapsible-hide .content {
+ display: none;
+}
+
+.collapsible-hide .hide-icon {
+ display: none;
+}
+
+.collapsible-show .show-icon {
+ display: none;
+}