From 82a2649e8d7d7a5cc81051c0a3520368a98cfbb2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 14 Jan 2026 15:48:51 +0100 Subject: dashboard/app: improve AI UI A bag of minor assorted improvements to data formatting. + show job results in the jobs table --- dashboard/app/ai.go | 44 +++++++++++++++++++++------------- dashboard/app/main.go | 2 +- dashboard/app/templates/ai_job.html | 12 +++++++--- dashboard/app/templates/templates.html | 18 ++++++++++---- 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. +
{{end}} - {{range $res := .Results}} -
{{$res.Name}}:
-
{{$res.Value}}

+ {{range $res := .Job.Results}} + {{if $res.IsBool}} + {{$res.Name}}: + {{if $res.Value}}✅{{else}}❌{{end}}    + {{else}} +

{{$res.Name}}: +
{{$res.Value}}
+ {{end}} {{end}} 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 + - + @@ -695,15 +696,22 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the {{range $job := .}} - + - - + + + - + {{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 { -- cgit mrf-deployment
ID WorkflowResult CorrectDescriptionBug Created Started Finished
{{link $job.Link $job.ID}}{{link $job.Link $job.ID}} {{$job.Workflow}}{{$job.Correct}}{{link $job.DescriptionLink $job.Description}} + {{range $res := $job.Results}} + {{if $res.IsBool}} + {{$res.Name}}: {{if $res.Value}}✅{{else}}❌{{end}}  + {{end}} + {{end}} + {{$job.Correct}}{{link $job.DescriptionLink $job.Description}} {{formatTime $job.Created}} {{formatTime $job.Started}} {{formatTime $job.Finished}} {{$job.LLMModel}}{{link $job.CodeRevisionLink $job.CodeRevision}}{{link $job.CodeRevisionLink $job.CodeRevision}} {{$job.Error}}