Skip to content

feat: display human-friendly timestamps in locks and jobs tables #5542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions server/controllers/web_templates/templates/index.html.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<span>Project</span>
<span>Workspace</span>
<span>Locked By</span>
<span>Date/Time</span>
<span>Lock Age</span>
<span>Status</span>
</div>
{{ range .Locks }}
Expand All @@ -79,7 +79,7 @@
<span class="lock-username">{{.LockedBy}}</span>
</a>
<a class="lock-link" tabindex="-1" href="{{ $basePath }}{{.LockPath}}">
<span class="lock-datetime">{{.TimeFormatted}}</span>
<span class="lock-datetime" title="{{.TimeFormatted }}">{{ .LockAge }}</span>
</a>
<a class="lock-link" tabindex="-1" href="{{ $basePath }}{{.LockPath}}">
<span><code>Locked</code></span>
Expand All @@ -102,7 +102,7 @@
<span>Repository</span>
<span>Project</span>
<span>Workspace</span>
<span>Date/Time</span>
<span>Job Age</span>
<span>Step</span>
<span>Description</span>
</div>
Expand All @@ -113,7 +113,7 @@
<span class="pulls-element">{{ if .Pull.Workspace }}<code>{{ .Pull.Workspace }}</code>{{ end }}</span>
<span class="pulls-element">
{{ range .JobIDInfos }}
<div><span class="lock-datetime">{{ .TimeFormatted }}</span></div>
<div><span class="lock-datetime" title="{{ .TimeFormatted }}">{{ .JobAge }}</span></div>
{{ end }}
</span>
<span class="pulls-element">
Expand Down
2 changes: 2 additions & 0 deletions server/controllers/web_templates/web_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type LockIndexData struct {
LockedBy string
Time time.Time
TimeFormatted string
LockAge string
}

// ApplyLockData holds the fields to display in the index view
Expand Down Expand Up @@ -96,6 +97,7 @@ type LockDetailData struct {
// not using a path-based proxy, this will be an empty string. Never ends
// in a '/' (hence "cleaned").
CleanedBasePath string
LockAge string
}

var LockTemplate = templates.Lookup(templateFileNames["lock"])
Expand Down
3 changes: 2 additions & 1 deletion server/controllers/web_templates/web_templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestIndexTemplate(t *testing.T) {
Workspace: "workspace",
Time: time.Now(),
TimeFormatted: "2006-01-02 15:04:05",
LockAge: "just now",
},
},
ApplyLock: ApplyLockData{
Expand All @@ -40,7 +41,7 @@ func TestIndexTemplate(t *testing.T) {
Workspace: "workspace",
},
JobIDInfos: []jobs.JobIDInfo{
{JobID: "job id", JobIDUrl: "job id url", JobDescription: "job description", Time: time.Now(), TimeFormatted: "02-01-2006 15:04:05", JobStep: "job step"},
{JobID: "job id", JobIDUrl: "job id url", JobDescription: "job description", Time: time.Now(), TimeFormatted: "02-01-2006 15:04:05", JobStep: "job step", "JobAge": "just now"},
},
},
},
Expand Down
1 change: 1 addition & 0 deletions server/jobs/project_command_output_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type JobIDInfo struct {
Time time.Time
TimeFormatted string
JobStep string
JobAge string
}

type PullInfoWithJobIDs struct {
Expand Down
36 changes: 36 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,35 @@ func (s *Server) waitForDrain() {
}
}

func HumanReadableDuration(d time.Duration) string {
if d < time.Minute {
return "just now"
}
if d < time.Hour {
mins := int(d.Minutes())
return fmt.Sprintf("%d minute%s ago", mins, PluralIfNeeded(mins))
}
if d < 24*time.Hour {
hours := int(d.Hours())
return fmt.Sprintf("%d hour%s ago", hours, PluralIfNeeded(hours))
}

days := int(d.Hours()) / 24
hours := int(d.Hours()) % 24

if hours == 0 {
return fmt.Sprintf("%d day%s ago", days, PluralIfNeeded(days))
}
return fmt.Sprintf("%d day%s, %d hour%s ago", days, PluralIfNeeded(days), hours, PluralIfNeeded(hours))
}

func PluralIfNeeded(n int) string {
if n == 1 {
return ""
}
return "s"
}

// Index is the / route.
func (s *Server) Index(w http.ResponseWriter, _ *http.Request) {
locks, err := s.Locker.List()
Expand All @@ -1155,6 +1184,8 @@ func (s *Server) Index(w http.ResponseWriter, _ *http.Request) {
var lockResults []web_templates.LockIndexData
for id, v := range locks {
lockURL, _ := s.Router.Get(LockViewRouteName).URL("id", url.QueryEscape(id))
lockDuration := time.Since(v.Time)
lockAge := HumanReadableDuration(lockDuration)
lockResults = append(lockResults, web_templates.LockIndexData{
// NOTE: must use .String() instead of .Path because we need the
// query params as part of the lock URL.
Expand All @@ -1166,6 +1197,7 @@ func (s *Server) Index(w http.ResponseWriter, _ *http.Request) {
Workspace: v.Workspace,
Time: v.Time,
TimeFormatted: v.Time.Format("2006-01-02 15:04:05"),
LockAge: lockAge,
})
}

Expand Down Expand Up @@ -1204,9 +1236,13 @@ func preparePullToJobMappings(s *Server) []jobs.PullInfoWithJobIDs {

for i := range pullToJobMappings {
for j := range pullToJobMappings[i].JobIDInfos {
jobDuration := time.Since(pullToJobMappings[i].JobIDInfos[j].Time)
jobAge := HumanReadableDuration(jobDuration)
jobUrl, _ := s.Router.Get(ProjectJobsViewRouteName).URL("job-id", pullToJobMappings[i].JobIDInfos[j].JobID)

pullToJobMappings[i].JobIDInfos[j].JobIDUrl = jobUrl.String()
pullToJobMappings[i].JobIDInfos[j].TimeFormatted = pullToJobMappings[i].JobIDInfos[j].Time.Format("2006-01-02 15:04:05")
pullToJobMappings[i].JobIDInfos[j].JobAge = jobAge
}

//Sort by date - newest to oldest.
Expand Down