From c1b621532c9f283173eeea3a90c399d49c5546d9 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Thu, 30 Oct 2025 12:04:16 +0000 Subject: [PATCH] appview/pages: show live updating counters for steps Change-Id: lstutzylzylkyyppvpxymrwqnrozwyvq spindles can now give us detailed logs for start and end of steps. the appview can ingest these logs to indicate live durations for steps. it is implemented like so: - the logs handler keeps track of start and end times for each step - whenever we recieve a start or end time, we update the html to add a `data-start` or `data-end` attribute - using some javascript, we print a live updating timer for each step: * if only `data-start` is present: then use Now - Start and update each second * if both `data-start` and `data-end` are present, then use End - Start Signed-off-by: oppiliappan --- appview/pages/pages.go | 12 ++++++ .../templates/fragments/workflow-timers.html | 36 ++++++++++++++++++ .../repo/pipelines/fragments/logBlock.html | 13 ++++--- .../repo/pipelines/fragments/logBlockEnd.html | 9 +++++ .../templates/repo/pipelines/workflow.html | 1 + appview/pipelines/pipelines.go | 38 ++++++++++++------- 6 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 appview/pages/templates/fragments/workflow-timers.html create mode 100644 appview/pages/templates/repo/pipelines/fragments/logBlockEnd.html diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 9608ff2e..4ffb73c8 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -15,6 +15,7 @@ import ( "path/filepath" "strings" "sync" + "time" "tangled.org/core/api/tangled" "tangled.org/core/appview/commitverify" @@ -1360,12 +1361,23 @@ type LogBlockParams struct { Name string Command string Collapsed bool + StartTime time.Time } func (p *Pages) LogBlock(w io.Writer, params LogBlockParams) error { return p.executePlain("repo/pipelines/fragments/logBlock", w, params) } +type LogBlockEndParams struct { + Id int + StartTime time.Time + EndTime time.Time +} + +func (p *Pages) LogBlockEnd(w io.Writer, params LogBlockEndParams) error { + return p.executePlain("repo/pipelines/fragments/logBlockEnd", w, params) +} + type LogLineParams struct { Id int Content string diff --git a/appview/pages/templates/fragments/workflow-timers.html b/appview/pages/templates/fragments/workflow-timers.html new file mode 100644 index 00000000..0fdae0a9 --- /dev/null +++ b/appview/pages/templates/fragments/workflow-timers.html @@ -0,0 +1,36 @@ +{{ define "fragments/workflow-timers" }} + +{{ end }} diff --git a/appview/pages/templates/repo/pipelines/fragments/logBlock.html b/appview/pages/templates/repo/pipelines/fragments/logBlock.html index 3e1b56df..7e118bb5 100644 --- a/appview/pages/templates/repo/pipelines/fragments/logBlock.html +++ b/appview/pages/templates/repo/pipelines/fragments/logBlock.html @@ -2,14 +2,15 @@
-
- {{ i "chevron-right" "w-4 h-4" }} {{ .Name }} -
- +
{{ template "stepHeader" . }}
+
{{ .Command }}
{{ end }} + +{{ define "stepHeader" }} + {{ i "chevron-right" "w-4 h-4" }} {{ .Name }} + +{{ end }} diff --git a/appview/pages/templates/repo/pipelines/fragments/logBlockEnd.html b/appview/pages/templates/repo/pipelines/fragments/logBlockEnd.html new file mode 100644 index 00000000..d4cce5e3 --- /dev/null +++ b/appview/pages/templates/repo/pipelines/fragments/logBlockEnd.html @@ -0,0 +1,9 @@ +{{ define "repo/pipelines/fragments/logBlockEnd" }} + +{{ end }} + diff --git a/appview/pages/templates/repo/pipelines/workflow.html b/appview/pages/templates/repo/pipelines/workflow.html index 7cf7cc90..ca72a897 100644 --- a/appview/pages/templates/repo/pipelines/workflow.html +++ b/appview/pages/templates/repo/pipelines/workflow.html @@ -15,6 +15,7 @@ {{ block "logs" . }} {{ end }} +{{ template "fragments/workflow-timers" }} {{ end }} {{ define "sidebar" }} diff --git a/appview/pipelines/pipelines.go b/appview/pipelines/pipelines.go index 397c6631..402708b2 100644 --- a/appview/pipelines/pipelines.go +++ b/appview/pipelines/pipelines.go @@ -227,7 +227,7 @@ func (p *Pipelines) Logs(w http.ResponseWriter, r *http.Request) { // start a goroutine to read from spindle go readLogs(spindleConn, evChan) - stepIdx := 0 + stepStartTimes := make(map[int]time.Time) var fragment bytes.Buffer for { select { @@ -259,22 +259,34 @@ func (p *Pipelines) Logs(w http.ResponseWriter, r *http.Request) { switch logLine.Kind { case spindlemodel.LogKindControl: - // control messages create a new step block - stepIdx++ - collapsed := false - if logLine.StepKind == spindlemodel.StepKindSystem { - collapsed = true + switch logLine.StepStatus { + case spindlemodel.StepStatusStart: + stepStartTimes[logLine.StepId] = logLine.Time + collapsed := false + if logLine.StepKind == spindlemodel.StepKindSystem { + collapsed = true + } + err = p.pages.LogBlock(&fragment, pages.LogBlockParams{ + Id: logLine.StepId, + Name: logLine.Content, + Command: logLine.StepCommand, + Collapsed: collapsed, + StartTime: logLine.Time, + }) + case spindlemodel.StepStatusEnd: + startTime := stepStartTimes[logLine.StepId] + endTime := logLine.Time + err = p.pages.LogBlockEnd(&fragment, pages.LogBlockEndParams{ + Id: logLine.StepId, + StartTime: startTime, + EndTime: endTime, + }) } - err = p.pages.LogBlock(&fragment, pages.LogBlockParams{ - Id: stepIdx, - Name: logLine.Content, - Command: logLine.StepCommand, - Collapsed: collapsed, - }) + case spindlemodel.LogKindData: // data messages simply insert new log lines into current step err = p.pages.LogLine(&fragment, pages.LogLineParams{ - Id: stepIdx, + Id: logLine.StepId, Content: logLine.Content, }) } -- 2.43.0