فهرست منبع

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
James Read 2 سال پیش
والد
کامیت
f15235d120
5فایلهای تغییر یافته به همراه85 افزوده شده و 6 حذف شده
  1. 1 0
      OliveTin.proto
  2. 28 4
      internal/grpcapi/grpcApi.go
  3. 8 2
      internal/grpcapi/grpcApiDashboard.go
  4. 47 0
      webui.dev/js/marshaller.js
  5. 1 0
      webui.dev/style.css

+ 1 - 0
OliveTin.proto

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

+ 28 - 4
internal/grpcapi/grpcApi.go

@@ -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) {
 	res := &pb.ExecutionStatusResponse{}
 
-	logEntry, ok := api.executor.Logs[req.ExecutionTrackingId]
+	var ile *executor.InternalLogEntry
 
-	if !ok {
-		return res, nil
+	if req.ExecutionTrackingId != "" {
+		ile = getExecutionStatusByTrackingID(api, req.ExecutionTrackingId)
+	} else {
+		ile = getMostRecentExecutionStatusById(api, req.ActionId)
 	}
 
-	res.LogEntry = internalLogEntryToPb(logEntry)
+	res.LogEntry = internalLogEntryToPb(ile)
 
 	return res, nil
 }

+ 8 - 2
internal/grpcapi/grpcApiDashboard.go

@@ -3,6 +3,7 @@ package grpcapi
 import (
 	pb "github.com/OliveTin/OliveTin/gen/grpc"
 	config "github.com/OliveTin/OliveTin/internal/config"
+	"golang.org/x/exp/slices"
 )
 
 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 {
+	allowedTypes := []string{
+		"stdout-most-recent-execution",
+		"display",
+	}
+
 	if len(item.Contents) > 0 {
 		if item.Type != "fieldset" {
 			return "directory"
 		}
 
 		return "fieldset"
-	} else if item.Type == "display" {
-		return "display"
+	} else if slices.Contains(allowedTypes, item.Type) {
+		return item.Type
 	}
 
 	return "link"

+ 47 - 0
webui.dev/js/marshaller.js

@@ -199,6 +199,50 @@ function marshalLink (item, fieldset) {
   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) {
   for (const item of json.contents) {
     switch (item.type) {
@@ -212,6 +256,9 @@ function marshalContainerContents (json, section, fieldset, parentDashboard) {
       case 'display':
         marshalDisplay(item, fieldset)
         break
+      case 'stdout-most-recent-execution':
+        marshalMreOutput(item, fieldset)
+        break
       case 'link':
         marshalLink(item, fieldset)
         break

+ 1 - 0
webui.dev/style.css

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