internal/relui: format task results on home
Render the workflow task results as a table using a css grid layout,
rather than a table, to allow for us to expand rows to show logs and
eventually other results without using javascript.
For golang/go#47401
Change-Id: I1ab1bb3a1b87d2e864b769eeb232336af98a306d
Reviewed-on: https://go-review.googlesource.com/c/build/+/353349
Trust: Alexander Rakoczy <alex@golang.org>
Run-TryBot: Alexander Rakoczy <alex@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/internal/relui/static/styles.css b/internal/relui/static/styles.css
index 0a2ba88..0f2c51c 100644
--- a/internal/relui/static/styles.css
+++ b/internal/relui/static/styles.css
@@ -69,48 +69,94 @@
padding: 0;
}
.WorkflowList-title {
+ font-weight: normal;
+ margin: 0.875rem 0 0.5rem 0;
+}
+.WorkflowList-params {
+ border: none;
+ border-spacing: 0;
+}
+.WorkflowList-titleTime {
+ font-size: 1rem;
+}
+.WorkflowList-paramData:first-child {
+ text-transform: capitalize;
+}
+.WorkflowList-paramData {
+ font-size: 0.875rem;
}
.WorkflowList-sectionTitle {
font-weight: normal;
- margin-bottom: 0.5rem;
+ letter-spacing: normal;
+ margin: 1rem 0 0.5rem 0;
}
.WorkflowList-item {
background: #fff;
- margin-top: 1rem;
- padding: 0 0.5rem;
border: 0.0625rem solid #d6d6d6;
border-radius: 0.0625rem;
+ margin-top: 1rem;
+ padding: 0 0.5rem;
}
.TaskList {
+ align-items: center;
border-bottom: 0.0625rem solid #d6d6d6;
- border-top: 0.0625rem solid #d6d6d6;
+ display: grid;
+ grid-auto-rows: minmax(1.5rem, auto);
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
margin-bottom: 1rem;
}
-.TaskList-item + .TaskList-item {
+.TaskList-itemCol {
border-top: 0.0625rem solid #d6d6d6;
+ overflow: hidden;
+ padding: 0.25rem 0;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
.TaskList-itemSummary {
align-items: center;
cursor: pointer;
- justify-content: space-between;
+ display: contents;
+ font-size: 0.8125rem;
padding: 0.5rem;
}
.TaskList-itemSummary:hover {
background-color: #fafafa;
}
+.TaskList-itemSummary:hover > .TaskList-itemCol {
+ background-color: #fafafa;
+}
+.TaskList-itemDetails {
+ display: contents;
+}
+.TaskList-itemDetails .TaskList-itemStatus::before {
+ content: "▸";
+}
+.TaskList-itemDetails[open] .TaskList-itemStatus::before {
+ content: "▾";
+}
.TaskList-itemLogs {
background-color: #f5f5f5;
box-shadow: inset 0 6px 6px -8px #888;
- font-size: 0.875rem;
+ font-size: 0.8125rem;
+ grid-column: 1/6;
margin: 0;
padding: 1rem 0;
}
.TaskList-itemLogLine {
+ grid-row: 6;
padding: 0 1rem;
}
.TaskList-itemLogLine:nth-child(even) {
background-color: #fafafa;
}
+.TaskList-item {
+ display: contents;
+}
+.TaskList-itemHeader {
+ align-items: center;
+ font-size: 0.8125rem;
+ font-weight: bold;
+}
.Button {
background: #375eab;
border-radius: 0.1875rem;
diff --git a/internal/relui/templates/home.html b/internal/relui/templates/home.html
index 60e17a8..cd8f73c 100644
--- a/internal/relui/templates/home.html
+++ b/internal/relui/templates/home.html
@@ -13,24 +13,55 @@
{{range $workflow := .Workflows}}
<li class="WorkflowList-item">
<h3 class="WorkflowList-title">
- {{$workflow.Name.String}} -
- {{index $workflow.ID}}
+ {{$workflow.Name.String}}
+ <span class="WorkflowList-titleTime">
+ {{$workflow.CreatedAt.UTC.Format "2006/01/02 15:04 MST"}}
+ </span>
</h3>
+ <table class="WorkflowList-params">
+ <tbody>
+ {{range $name, $value := $.WorkflowParams $workflow}}
+ <tr>
+ <td class="WorkflowList-paramData">{{$name}}:</td>
+ <td class="WorkflowList-paramData">{{$value}}</td>
+ </tr>
+ {{end}}
+ </tbody>
+ </table>
<h4 class="WorkflowList-sectionTitle">Tasks</h4>
<ul class="TaskList">
+ <li class="TaskList-item TaskList-itemHeader">
+ <span class="TaskList-itemStatus">Status</span>
+ <span class="TaskList-itemName">Name</span>
+ <span class="TaskList-itemCreated">Started</span>
+ <span class="TaskList-itemUpdated">Updated</span>
+ <span class="TaskList-itemResult">Result</span>
+ </li>
{{$tasks := index $.WorkflowTasks $workflow.ID}}
{{range $task := $tasks}}
<li class="TaskList-item">
<details class="TaskList-itemDetails">
<summary class="TaskList-itemSummary">
- <span class="TaskList-itemTitle">{{$task.Name}}</span>
- Finished: {{$task.Finished}} Result: {{$task.Result.String}} Name:
- {{$task.Name}}
+ <span class="TaskList-itemCol TaskList-itemStatus">
+ {{$task.Finished}}
+ </span>
+ <span class="TaskList-itemCol TaskList-itemName">
+ {{$task.Name}}
+ </span>
+ <span class="TaskList-itemCol TaskList-itemCreated">
+ {{$task.CreatedAt.UTC.Format "Mon Jan _2 2006 15:04:05"}}
+ </span>
+ <span class="TaskList-itemCol TaskList-itemUpdated">
+ {{$task.UpdatedAt.UTC.Format "Mon Jan _2 2006 15:04:05"}}
+ </span>
+ <span class="TaskList-itemCol TaskList-itemResult">
+ {{$task.Result}}
+ </span>
</summary>
<div class="TaskList-itemLogs">
{{range $log := $.Logs $workflow.ID $task.Name}}
<div class="TaskList-itemLogLine">
- {{$log.CreatedAt.Format "2006/01/02 15:04:05"}}
+ {{$log.CreatedAt.UTC.Format "2006/01/02 15:04:05"}}
{{$log.Body}}
</div>
{{end}}
diff --git a/internal/relui/web.go b/internal/relui/web.go
index 584ca29..e64a77a 100644
--- a/internal/relui/web.go
+++ b/internal/relui/web.go
@@ -87,6 +87,12 @@
return t[task]
}
+func (h *homeResponse) WorkflowParams(wf db.Workflow) map[string]string {
+ params := make(map[string]string)
+ json.Unmarshal([]byte(wf.Params.String), ¶ms)
+ return params
+}
+
// homeHandler renders the homepage.
func (s *Server) homeHandler(w http.ResponseWriter, r *http.Request) {
resp, err := s.buildHomeResponse(r.Context())
diff --git a/internal/workflow/workflow.go b/internal/workflow/workflow.go
index 11727ed..ff50cd7 100644
--- a/internal/workflow/workflow.go
+++ b/internal/workflow/workflow.go
@@ -339,7 +339,7 @@
// will be restarted, but tasks that finished in errors will not be retried.
//
// The host must create the WorkflowState. TaskStates should be saved from
-// listener callbacks, but for ease of stoage, their Result field does not
+// listener callbacks, but for ease of storage, their Result field does not
// need to be populated.
func Resume(def *Definition, state *WorkflowState, taskStates map[string]*TaskState) (*Workflow, error) {
w := &Workflow{