Msot recent execution output on the dashboard. (#238)

* feature: Support for most recent action output on dashboard

* feature: Support for most recent action output on dashboard
This commit is contained in:
James Read 2024-03-04 23:33:50 +00:00 committed by GitHub
parent 471d5726f6
commit f15235d120
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 85 additions and 6 deletions

View File

@ -137,6 +137,7 @@ message WatchExecutionUpdate {
message ExecutionStatusRequest { message ExecutionStatusRequest {
string execution_tracking_id = 1; string execution_tracking_id = 1;
string action_id = 2;
} }
message ExecutionStatusResponse { message ExecutionStatusResponse {

View File

@ -142,16 +142,40 @@ func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *pb.LogEntry {
} }
} }
func getExecutionStatusByTrackingID(api *oliveTinAPI, executionTrackingId string) *executor.InternalLogEntry {
logEntry, ok := api.executor.Logs[executionTrackingId]
if !ok {
return nil
}
return logEntry
}
func getMostRecentExecutionStatusById(api *oliveTinAPI, actionId string) *executor.InternalLogEntry {
var ile *executor.InternalLogEntry
for _, candidateLe := range api.executor.Logs {
if actionId == candidateLe.ActionId {
ile = candidateLe
}
}
return ile
}
func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *pb.ExecutionStatusRequest) (*pb.ExecutionStatusResponse, error) { func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *pb.ExecutionStatusRequest) (*pb.ExecutionStatusResponse, error) {
res := &pb.ExecutionStatusResponse{} res := &pb.ExecutionStatusResponse{}
logEntry, ok := api.executor.Logs[req.ExecutionTrackingId] var ile *executor.InternalLogEntry
if !ok { if req.ExecutionTrackingId != "" {
return res, nil ile = getExecutionStatusByTrackingID(api, req.ExecutionTrackingId)
} else {
ile = getMostRecentExecutionStatusById(api, req.ActionId)
} }
res.LogEntry = internalLogEntryToPb(logEntry) res.LogEntry = internalLogEntryToPb(ile)
return res, nil return res, nil
} }

View File

@ -3,6 +3,7 @@ package grpcapi
import ( import (
pb "github.com/OliveTin/OliveTin/gen/grpc" pb "github.com/OliveTin/OliveTin/gen/grpc"
config "github.com/OliveTin/OliveTin/internal/config" config "github.com/OliveTin/OliveTin/internal/config"
"golang.org/x/exp/slices"
) )
func dashboardCfgToPb(res *pb.GetDashboardComponentsResponse, dashboards []*config.DashboardComponent) { func dashboardCfgToPb(res *pb.GetDashboardComponentsResponse, dashboards []*config.DashboardComponent) {
@ -37,14 +38,19 @@ func getDashboardComponentContents(dashboard *config.DashboardComponent) []*pb.D
} }
func getDashboardComponentType(item *config.DashboardComponent) string { func getDashboardComponentType(item *config.DashboardComponent) string {
allowedTypes := []string{
"stdout-most-recent-execution",
"display",
}
if len(item.Contents) > 0 { if len(item.Contents) > 0 {
if item.Type != "fieldset" { if item.Type != "fieldset" {
return "directory" return "directory"
} }
return "fieldset" return "fieldset"
} else if item.Type == "display" { } else if slices.Contains(allowedTypes, item.Type) {
return "display" return item.Type
} }
return "link" return "link"

View File

@ -199,6 +199,50 @@ function marshalLink (item, fieldset) {
fieldset.appendChild(btn) fieldset.appendChild(btn)
} }
function marshalMreOutput (dashboardComponent, fieldset) {
const pre = document.createElement('pre')
pre.classList.add('mre-output')
pre.innerHTML = 'Waiting...'
const executionStatus = {
actionId: dashboardComponent.title
}
window.fetch(window.restBaseUrl + 'ExecutionStatus', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(executionStatus)
}).then((res) => {
if (res.ok) {
return res.json()
} else {
pre.innerHTML = 'error'
throw new Error(res.statusText)
}
}).then((json) => {
updateMre(pre, json.logEntry)
})
const updateMre = (pre, json) => {
pre.innerHTML = json.stdout
}
window.addEventListener('ExecutionFinished', (e) => {
// The dashboard component "title" field is used for lots of things
// and in this context for MreOutput it's just to refer an an actionId.
//
// So this is not a typo.
if (e.payload.actionId === dashboardComponent.title) {
updateMre(pre, e.payload)
}
})
fieldset.appendChild(pre)
}
function marshalContainerContents (json, section, fieldset, parentDashboard) { function marshalContainerContents (json, section, fieldset, parentDashboard) {
for (const item of json.contents) { for (const item of json.contents) {
switch (item.type) { switch (item.type) {
@ -212,6 +256,9 @@ function marshalContainerContents (json, section, fieldset, parentDashboard) {
case 'display': case 'display':
marshalDisplay(item, fieldset) marshalDisplay(item, fieldset)
break break
case 'stdout-most-recent-execution':
marshalMreOutput(item, fieldset)
break
case 'link': case 'link':
marshalLink(item, fieldset) marshalLink(item, fieldset)
break break

View File

@ -429,6 +429,7 @@ pre {
padding: 1em; padding: 1em;
min-height: 1em; min-height: 1em;
overflow: auto; overflow: auto;
text-align: left;
} }
td.exit-code { td.exit-code {