Skip to content

Commit

Permalink
internal/relui: improve task result formatting
Browse files Browse the repository at this point in the history
Format most result types, somewhat. This implementation should be
reusable when formatting workflow outputs in the future.

For golang/go#53382

Change-Id: I4734cdefff85a37cb1047a6689411139f2ebfbc1
Reviewed-on: https://go-review.googlesource.com/c/build/+/412677
Reviewed-by: Dmitri Shuralyov <[email protected]>
Run-TryBot: Alex Rakoczy <[email protected]>
Reviewed-by: Dmitri Shuralyov <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
toothrot committed Jun 21, 2022
1 parent 651a84e commit bcadfe3
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 5 deletions.
46 changes: 46 additions & 0 deletions internal/relui/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ h6 {
font-size: 0.8125rem;
margin: 0;
padding: 1rem 0;
vertical-align: top;
}
.TaskList-itemLogLine {
font-family: monospace;
Expand All @@ -235,6 +236,51 @@ h6 {
font-size: 0.8125rem;
font-weight: bold;
}
.TaskList-itemActions {
width: 12.8125rem;
}
.TaskList-itemResult {
width: 5rem;
}
.TaskList-itemResultDetail {
border: 0.0625rem solid #ccc;
border-top: 0;
max-width: 17.8125rem;
vertical-align: top;
width: 17.8125rem;
}
.TaskList-itemResultDetailList {
margin: 0;
}
.TaskList-itemResultTerm {
background: #fafafa;
border-top: 0.0625rem solid #ccc;
font-size: 0.75rem;
padding: 0.1875rem 0.25rem 0;
}
.TaskList-itemResultTerm:nth-of-type(even) {
background: #f8f8f8;
}
.TaskList-itemResultDefinition {
background: #fafafa;
font-size: 0.875rem;
margin: 0;
min-height: 1.875rem;
padding: 0.5rem 0.375rem;
}
.TaskList-itemResultDefinition:nth-of-type(even) {
background: #f8f8f8;
}
.TaskList-itemResultDefinition--string {
display: block;
-webkit-line-clamp: 3;
max-height: 7.5rem;
overflow: hidden;
text-overflow: ellipsis;
}
.TaskList-itemResultArtifactSize {
float: right;
}
.Button {
background: #375eab;
border: none;
Expand Down
71 changes: 68 additions & 3 deletions internal/relui/templates/task_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
</tr>
</thead>
{{range $task := .Tasks}}
{{ $resultDetail := unmarshalResultDetail $task.Result.String }}
<tbody>
<tr class="TaskList-item TaskList-itemSummary TaskList-expandableItem">
<td class="TaskList-itemCol TaskList-itemExpand">
Expand Down Expand Up @@ -53,7 +54,7 @@
{{$task.UpdatedAt.UTC.Format "Mon Jan _2 2006 15:04:05"}}
</td>
<td class="TaskList-itemCol TaskList-itemResult">
{{$task.Result.String}}
{{ $resultDetail.Kind }}
</td>
<td class="TaskList-itemCol TaskList-itemAction">
{{if $task.Error.Valid}}
Expand All @@ -75,20 +76,84 @@
</td>
</tr>
<tr class="TaskList-itemLogsRow">
<td class="TaskList-itemLogs" colspan="7">
<td class="TaskList-itemLogs" colspan="5">
{{if $task.Error.Valid}}
<div class="TaskList-itemLogLine TaskList-itemLogLineError">
{{- $task.Error.Value -}}
</div>
{{end}}
{{range $log := index $.TaskLogs $task.Name}}
<div class="TaskList-itemLogLine">
{{- $log.CreatedAt.UTC.Format "2006/01/02 15:04:05"}} {{$log.Body -}}
{{- printf "%s %s" ($log.CreatedAt.UTC.Format "2006/01/02 15:04:05") $log.Body -}}
</div>
{{end}}
{{if $task.Result.Valid}}
<div class="TaskList-itemLogLine">
{{- $task.Result.String -}}
</div>
{{end}}
</td>
<td class="TaskList-itemResultDetail" colspan="2">
{{template "itemResult" $resultDetail}}
</td>
</tr>
</tbody>
{{end}}
</table>
{{end}}

{{define "itemResult"}}
{{$resultDetail := .}}
{{if eq $resultDetail.Kind "Artifact"}}
<dl class="TaskList-itemResultDetailList">
<dt class="TaskList-itemResultTerm">Name</dt>
<dd class="TaskList-itemResultDefinition">
{{$resultDetail.Artifact.Target.Name}}
</dd>
<dt class="TaskList-itemResultTerm">Filename</dt>
<dd class="TaskList-itemResultDefinition">
{{$resultDetail.Artifact.Filename}}
</dd>
<dt class="TaskList-itemResultTerm">ScratchPath</dt>
<dd class="TaskList-itemResultDefinition">
{{$resultDetail.Artifact.ScratchPath}}
</dd>
<dt class="TaskList-itemResultTerm">StagingPath</dt>
<dd class="TaskList-itemResultDefinition">
{{$resultDetail.Artifact.StagingPath}}
</dd>
</dl>
{{else if eq $resultDetail.Kind "Artifacts"}}
<dt class="TaskList-itemResultTerm">Filenames</dt>
<dd class="TaskList-itemResultDefinition">
{{range $artifact := $resultDetail.Artifacts}}
{{$artifact.Filename}} <span class="TaskList-itemResultArtifactSize">{{prettySize $artifact.Size}}</span>
{{end}}
</dd>
{{else if eq $resultDetail.Kind "Outputs"}}
{{range $key, $value := $resultDetail.Outputs}}
<dt class="TaskList-itemResultTerm">
{{$key}}
</dt>
<dd class="TaskList-itemResultDefinition">
{{template "itemResult" $value}}
</dd>
{{end}}
{{else if eq $resultDetail.Kind "JSON"}}
{{range $key, $value := $resultDetail.JSON}}
<dt class="TaskList-itemResultTerm">
{{$key}}
</dt>
<dd class="TaskList-itemResultDefinition">
{{$value}}
</dd>
{{end}}
{{else if eq $resultDetail.Kind "String"}}
<dt class="TaskList-itemResultTerm">
String
</dt>
<dd class="TaskList-itemResultDefinition TaskList-itemResultDefinition--string">
{{$resultDetail.String}}
</dd>
{{end}}
{{end}}
70 changes: 68 additions & 2 deletions internal/relui/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"net/http"
"net/url"
"path"
"reflect"
"strings"
"time"

Expand Down Expand Up @@ -77,8 +78,10 @@ func NewServer(p *pgxpool.Pool, w *Worker, baseURL *url.URL, header SiteHeader)
header: header,
}
helpers := map[string]interface{}{
"baseLink": s.BaseLink,
"hasPrefix": strings.HasPrefix,
"baseLink": s.BaseLink,
"hasPrefix": strings.HasPrefix,
"prettySize": prettySize,
"unmarshalResultDetail": unmarshalResultDetail,
}
s.templates = template.Must(template.New("").Funcs(helpers).ParseFS(templates, "templates/*.html"))
s.homeTmpl = s.mustLookup("home.html")
Expand Down Expand Up @@ -353,3 +356,66 @@ func (s *Server) stopWorkflowHandler(w http.ResponseWriter, r *http.Request, par
}
http.Redirect(w, r, s.BaseLink("/"), http.StatusSeeOther)
}

// resultDetail contains unmarshalled results from a workflow task, or
// workflow output. Only one field is expected to be populated.
//
// The UI implementation uses Kind to determine which result type to
// render.
type resultDetail struct {
Artifact artifact
Artifacts []artifact
Outputs map[string]*resultDetail
JSON map[string]interface{}
String string
Unknown interface{}
}

func (r *resultDetail) Kind() string {
v := reflect.ValueOf(r)
if v.IsZero() {
return ""
}
v = v.Elem()
for i := 0; i < v.NumField(); i++ {
if v.Field(i).IsZero() {
continue
}
return v.Type().Field(i).Name
}
return ""
}

func (r *resultDetail) UnmarshalJSON(result []byte) error {
v := reflect.ValueOf(r).Elem()
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if err := json.Unmarshal(result, f.Addr().Interface()); err == nil {
if f.IsZero() {
continue
}
return nil
}
}
return errors.New("unknown result type")
}

func unmarshalResultDetail(result string) *resultDetail {
ret := new(resultDetail)
if err := json.Unmarshal([]byte(result), &ret); err != nil {
ret.String = err.Error()
}
return ret
}

func prettySize(size int) string {
const mb = 1 << 20
if size == 0 {
return ""
}
if size < mb {
// All Go releases are >1mb, but handle this case anyway.
return fmt.Sprintf("%v bytes", size)
}
return fmt.Sprintf("%.0fMiB", float64(size)/mb)
}
57 changes: 57 additions & 0 deletions internal/relui/web_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -753,3 +753,60 @@ func TestServerStopWorkflow(t *testing.T) {
})
}
}

func TestResultDetail(t *testing.T) {
cases := []struct {
desc string
input string
want *resultDetail
wantKind string
}{
{
desc: "string",
input: `"hello"`,
want: &resultDetail{String: "hello"},
wantKind: "String",
},
{
desc: "nested json string",
input: `{"SomeOutput": "hello"}`,
want: &resultDetail{Outputs: map[string]*resultDetail{"SomeOutput": {String: "hello"}}},
wantKind: "Outputs",
},
{
desc: "nested json complex",
input: `{"SomeOutput": {"Filename": "go.exe"}}`,
want: &resultDetail{Outputs: map[string]*resultDetail{"SomeOutput": {Artifact: artifact{Filename: "go.exe"}}}},
wantKind: "Outputs",
},
{
desc: "nested json slice",
input: `{"SomeOutput": [{"Filename": "go.exe"}]}`,
want: &resultDetail{Outputs: map[string]*resultDetail{"SomeOutput": {Artifacts: []artifact{{Filename: "go.exe"}}}}},
wantKind: "Outputs",
},
{
desc: "nested json output",
input: `{"SomeOutput": {"OtherOutput": "go.exe"}}`,
want: &resultDetail{Outputs: map[string]*resultDetail{"SomeOutput": {Outputs: map[string]*resultDetail{"OtherOutput": {String: "go.exe"}}}}},
wantKind: "Outputs",
},
{
desc: "null json",
input: `null`,
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := unmarshalResultDetail(c.input)

if got.Kind() != c.wantKind {
t.Errorf("got.Kind() = %q, wanted %q", got.Kind(), c.wantKind)
}
if diff := cmp.Diff(c.want, got); diff != "" {
t.Errorf("unmarshalResultDetail mismatch (-want +got):\n%s", diff)
}
})
}

}

0 comments on commit bcadfe3

Please sign in to comment.