From 5281abcb509dccb2f6b597068c4a090e5cca1e3e 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 6f32e5a8..c46691b0 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" @@ -1361,12 +1362,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 d936360d..3cf562c4 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 963bd240..c1cfb429 100644 --- a/appview/pipelines/pipelines.go +++ b/appview/pipelines/pipelines.go @@ -236,7 +236,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 { @@ -268,22 +268,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