diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2026-01-14 15:48:51 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2026-01-15 10:08:05 +0000 |
| commit | 82a2649e8d7d7a5cc81051c0a3520368a98cfbb2 (patch) | |
| tree | 92e1ff210804f948e3e0140f0a96d00a127e35f0 | |
| parent | 3b7a3359989abfb9ee0c821fdc0a8be33f7e996d (diff) | |
dashboard/app: improve AI UI
A bag of minor assorted improvements to data formatting.
+ show job results in the jobs table
| -rw-r--r-- | dashboard/app/ai.go | 44 | ||||
| -rw-r--r-- | dashboard/app/main.go | 2 | ||||
| -rw-r--r-- | dashboard/app/templates/ai_job.html | 12 | ||||
| -rw-r--r-- | dashboard/app/templates/templates.html | 18 | ||||
| -rw-r--r-- | pkg/html/pages/style.css | 8 |
5 files changed, 58 insertions, 26 deletions
diff --git a/dashboard/app/ai.go b/dashboard/app/ai.go index 2912addea..511865da3 100644 --- a/dashboard/app/ai.go +++ b/dashboard/app/ai.go @@ -34,17 +34,15 @@ type uiAIJobPage struct { Job *uiAIJob // The slice contains the same single Job, just for HTML templates convenience. Jobs []*uiAIJob - Results []*uiAIResult Trajectory []*uiAITrajectorySpan } type uiAIJob struct { - ID string - Link string - Workflow string - Description string - DescriptionLink string - + ID string + Link string + Workflow string + Description string + DescriptionLink string Created time.Time Started time.Time Finished time.Time @@ -53,11 +51,13 @@ type uiAIJob struct { CodeRevisionLink string Error string Correct string + Results []*uiAIResult } type uiAIResult struct { - Name string - Value any + Name string + IsBool bool + Value any } type uiAITrajectorySpan struct { @@ -138,21 +138,32 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request Jobs: []*uiAIJob{uiJob}, Trajectory: makeUIAITrajectory(trajectory), } + return serveTemplate(w, "ai_job.html", page) +} + +func makeUIAIJob(job *aidb.Job) *uiAIJob { + var results []*uiAIResult if m, ok := job.Results.Value.(map[string]any); ok && job.Results.Valid { for name, value := range m { - page.Results = append(page.Results, &uiAIResult{ - Name: name, - Value: value, + _, isBool := value.(bool) + results = append(results, &uiAIResult{ + Name: name, + IsBool: isBool, + Value: value, }) } } - slices.SortFunc(page.Results, func(a, b *uiAIResult) int { + slices.SortFunc(results, func(a, b *uiAIResult) int { + // Pop up bool flags to the top. + if a.IsBool != b.IsBool { + if a.IsBool { + return -1 + } + return 1 + } return strings.Compare(a.Name, b.Name) }) - return serveTemplate(w, "ai_job.html", page) -} -func makeUIAIJob(job *aidb.Job) *uiAIJob { correct := aiCorrectnessIncorrect if !job.Finished.Valid { correct = aiCorrectnessPending @@ -177,6 +188,7 @@ func makeUIAIJob(job *aidb.Job) *uiAIJob { CodeRevisionLink: vcs.LogLink(vcs.SyzkallerRepo, job.CodeRevision), Error: job.Error, Correct: correct, + Results: results, } } diff --git a/dashboard/app/main.go b/dashboard/app/main.go index 30a30eb84..e9a1cf106 100644 --- a/dashboard/app/main.go +++ b/dashboard/app/main.go @@ -84,7 +84,7 @@ func initHTTPHandlers() { http.Handle("/"+ns+"/backports", handlerWrapper(handleBackports)) http.Handle("/"+ns+"/s/", handlerWrapper(handleSubsystemPage)) http.Handle("/"+ns+"/manager/", handlerWrapper(handleManagerPage)) - http.Handle("/"+ns+"/ai/", handlerWrapper(handleAIJobsPage)) + http.Handle("/"+ns+"/ai", handlerWrapper(handleAIJobsPage)) } http.HandleFunc("/cron/cache_update", cacheUpdate) http.HandleFunc("/cron/minute_cache_update", handleMinuteCacheUpdate) diff --git a/dashboard/app/templates/ai_job.html b/dashboard/app/templates/ai_job.html index 5a45654f8..34c7d39e8 100644 --- a/dashboard/app/templates/ai_job.html +++ b/dashboard/app/templates/ai_job.html @@ -28,11 +28,17 @@ Detailed info on a single AI job execution. <button type="submit">Set</button> </fieldset> </form> + <br> {{end}} - {{range $res := .Results}} - <br><b>{{$res.Name}}:</b><br> - <div id="ai_result_div"><pre>{{$res.Value}}</pre></div><br> + {{range $res := .Job.Results}} + {{if $res.IsBool}} + <b>{{$res.Name}}:</b> + {{if $res.Value}}✅{{else}}❌{{end}} + {{else}} + <br><br><b>{{$res.Name}}:</b> + <br><div id="ai_result_div"><pre>{{$res.Value}}</pre></div> + {{end}} {{end}} <table class="list_table"> diff --git a/dashboard/app/templates/templates.html b/dashboard/app/templates/templates.html index 15f50a287..dee2d1300 100644 --- a/dashboard/app/templates/templates.html +++ b/dashboard/app/templates/templates.html @@ -683,8 +683,9 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the <thead><tr> <th><a onclick="return sortTable(this, 'ID', textSort)" href="#">ID</a></th> <th><a onclick="return sortTable(this, 'Workflow', textSort)" href="#">Workflow</a></th> + <th><a onclick="return sortTable(this, 'Result', textSort)" href="#">Result</a></th> <th><a onclick="return sortTable(this, 'Correct', textSort)" href="#">Correct</a></th> - <th><a onclick="return sortTable(this, 'Description', textSort)" href="#">Description</a></th> + <th><a onclick="return sortTable(this, 'Bug', textSort)" href="#">Bug</a></th> <th><a onclick="return sortTable(this, 'Created', textSort)" href="#">Created</a></th> <th><a onclick="return sortTable(this, 'Started', textSort)" href="#">Started</a></th> <th><a onclick="return sortTable(this, 'Finished', textSort)" href="#">Finished</a></th> @@ -695,15 +696,22 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the <tbody> {{range $job := .}} <tr> - <td>{{link $job.Link $job.ID}}</td> + <td class="tag">{{link $job.Link $job.ID}}</td> <td>{{$job.Workflow}}</td> - <td>{{$job.Correct}}</td> - <td>{{link $job.DescriptionLink $job.Description}}</td> + <td> + {{range $res := $job.Results}} + {{if $res.IsBool}} + {{$res.Name}}: {{if $res.Value}}✅{{else}}❌{{end}} + {{end}} + {{end}} + </td> + <td class="ai_correct">{{$job.Correct}}</td> + <td class="title">{{link $job.DescriptionLink $job.Description}}</td> <td>{{formatTime $job.Created}}</td> <td>{{formatTime $job.Started}}</td> <td>{{formatTime $job.Finished}}</td> <td>{{$job.LLMModel}}</td> - <td>{{link $job.CodeRevisionLink $job.CodeRevision}}</td> + <td class="tag">{{link $job.CodeRevisionLink $job.CodeRevision}}</td> <td>{{$job.Error}}</td> </tr> {{end}} diff --git a/pkg/html/pages/style.css b/pkg/html/pages/style.css index 8bc461882..cb1766df6 100644 --- a/pkg/html/pages/style.css +++ b/pkg/html/pages/style.css @@ -244,6 +244,10 @@ table td, table th { font-size: 75%; } +.list_table .ai_correct { + text-align: center; +} + .list_table .status-crashed { background-color: #FF8674; } @@ -388,7 +392,6 @@ aside { #ai_result_div { align: left; - width: 90%; margin: 0 0; overflow: scroll; border: 1px solid #777; @@ -399,6 +402,9 @@ aside { #ai_result_div pre { margin: 1px; font-family: 'Courier New', Courier, monospace; + max-width: 120ch; + white-space: pre-wrap; + overflow-wrap: break-word; } #ai_details_div pre { |
