Browse Source

feature: Logs table creates an entry as soon as the execution is started (#464)

James Read 1 year ago
parent
commit
1bfb7c4b28

+ 4 - 0
OliveTin.proto

@@ -199,6 +199,10 @@ message EventExecutionFinished {
 	LogEntry log_entry = 1;
 	LogEntry log_entry = 1;
 }
 }
 
 
+message EventExecutionStarted {
+  LogEntry log_entry = 1;
+}
+
 message KillActionRequest {
 message KillActionRequest {
 	string execution_tracking_id = 1;
 	string execution_tracking_id = 1;
 }
 }

+ 11 - 3
internal/executor/executor.go

@@ -125,7 +125,7 @@ func DefaultExecutor(cfg *config.Config) *Executor {
 }
 }
 
 
 type listener interface {
 type listener interface {
-	OnExecutionStarted(actionTitle string)
+	OnExecutionStarted(logEntry *InternalLogEntry)
 	OnExecutionFinished(logEntry *InternalLogEntry)
 	OnExecutionFinished(logEntry *InternalLogEntry)
 	OnOutputChunk(o []byte, executionTrackingId string)
 	OnOutputChunk(o []byte, executionTrackingId string)
 	OnActionMapRebuilt()
 	OnActionMapRebuilt()
@@ -233,7 +233,7 @@ func (e *Executor) execChain(req *ExecutionRequest) {
 
 
 	// This isn't a step, because we want to notify all listeners, irrespective
 	// This isn't a step, because we want to notify all listeners, irrespective
 	// of how many steps were actually executed.
 	// of how many steps were actually executed.
-	notifyListeners(req)
+	notifyListenersFinished(req)
 }
 }
 
 
 func getConcurrentCount(req *ExecutionRequest) int {
 func getConcurrentCount(req *ExecutionRequest) int {
@@ -400,6 +400,8 @@ func stepRequestAction(req *ExecutionRequest) bool {
 		"tags":        req.Tags,
 		"tags":        req.Tags,
 	}).Infof("Action requested")
 	}).Infof("Action requested")
 
 
+	notifyListenersStarted(req)
+
 	return true
 	return true
 }
 }
 
 
@@ -425,12 +427,18 @@ func stepLogFinish(req *ExecutionRequest) bool {
 	return true
 	return true
 }
 }
 
 
-func notifyListeners(req *ExecutionRequest) {
+func notifyListenersFinished(req *ExecutionRequest) {
 	for _, listener := range req.executor.listeners {
 	for _, listener := range req.executor.listeners {
 		listener.OnExecutionFinished(req.logEntry)
 		listener.OnExecutionFinished(req.logEntry)
 	}
 	}
 }
 }
 
 
+func notifyListenersStarted(req *ExecutionRequest) {
+	for _, listener := range req.executor.listeners {
+		listener.OnExecutionStarted(req.logEntry)
+	}
+}
+
 func appendErrorToStderr(err error, logEntry *InternalLogEntry) {
 func appendErrorToStderr(err error, logEntry *InternalLogEntry) {
 	if err != nil {
 	if err != nil {
 		logEntry.Output = err.Error() + "\n\n" + logEntry.Output
 		logEntry.Output = err.Error() + "\n\n" + logEntry.Output

+ 25 - 23
internal/websocket/websocket.go

@@ -35,13 +35,10 @@ var ExecutionListener WebsocketExecutionListener
 
 
 type WebsocketExecutionListener struct{}
 type WebsocketExecutionListener struct{}
 
 
-func (WebsocketExecutionListener) OnExecutionStarted(title string) {
-	/*
-		broadcast(ExecutionStarted{
-			Type: "ExecutionStarted",
-			Action: title,
-		});
-	*/
+func (WebsocketExecutionListener) OnExecutionStarted(ile *executor.InternalLogEntry) {
+	broadcast(&pb.EventExecutionStarted{
+		LogEntry: internalLogEntryToPb(ile),
+	});
 }
 }
 
 
 func OnEntityChanged() {
 func OnEntityChanged() {
@@ -82,22 +79,7 @@ func (WebsocketExecutionListener) OnOutputChunk(chunk []byte, executionTrackingI
 
 
 func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.InternalLogEntry) {
 func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.InternalLogEntry) {
 	evt := &pb.EventExecutionFinished{
 	evt := &pb.EventExecutionFinished{
-		LogEntry: &pb.LogEntry{
-			ActionTitle:         logEntry.ActionTitle,
-			ActionIcon:          logEntry.ActionIcon,
-			ActionId:            logEntry.ActionId,
-			DatetimeStarted:     logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
-			DatetimeFinished:    logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
-			Output:              logEntry.Output,
-			TimedOut:            logEntry.TimedOut,
-			Blocked:             logEntry.Blocked,
-			ExitCode:            logEntry.ExitCode,
-			Tags:                logEntry.Tags,
-			ExecutionTrackingId: logEntry.ExecutionTrackingID,
-			ExecutionStarted:    logEntry.ExecutionStarted,
-			ExecutionFinished:   logEntry.ExecutionFinished,
-			User:                logEntry.Username,
-		},
+		LogEntry: internalLogEntryToPb(logEntry),
 	}
 	}
 
 
 	log.Infof("Execution finished: %v+v", evt.LogEntry)
 	log.Infof("Execution finished: %v+v", evt.LogEntry)
@@ -178,3 +160,23 @@ func HandleWebsocket(w http.ResponseWriter, r *http.Request) bool {
 
 
 	return true
 	return true
 }
 }
+
+func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *pb.LogEntry {
+	return &pb.LogEntry{
+		ActionTitle:         logEntry.ActionTitle,
+		ActionIcon:          logEntry.ActionIcon,
+		ActionId:            logEntry.ActionId,
+		DatetimeStarted:     logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
+		DatetimeFinished:    logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
+		Output:              logEntry.Output,
+		TimedOut:            logEntry.TimedOut,
+		Blocked:             logEntry.Blocked,
+		ExitCode:            logEntry.ExitCode,
+		Tags:                logEntry.Tags,
+		ExecutionTrackingId: logEntry.ExecutionTrackingID,
+		ExecutionStarted:    logEntry.ExecutionStarted,
+		ExecutionFinished:   logEntry.ExecutionFinished,
+		User:                logEntry.Username,
+	}
+}
+

+ 37 - 21
webui.dev/js/marshaller.js

@@ -54,12 +54,13 @@ export function initMarshaller () {
 
 
   window.executionDialog = new ExecutionDialog()
   window.executionDialog = new ExecutionDialog()
 
 
-  window.logEntries = {}
+  window.logEntries = new Map()
   window.registeredPaths = new Map()
   window.registeredPaths = new Map()
   window.breadcrumbNavigation = []
   window.breadcrumbNavigation = []
 
 
   window.currentPath = ''
   window.currentPath = ''
 
 
+  window.addEventListener('EventExecutionStarted', onExecutionStarted)
   window.addEventListener('EventExecutionFinished', onExecutionFinished)
   window.addEventListener('EventExecutionFinished', onExecutionFinished)
   window.addEventListener('EventOutputChunk', onOutputChunk)
   window.addEventListener('EventOutputChunk', onOutputChunk)
 }
 }
@@ -125,6 +126,14 @@ function onOutputChunk (evt) {
   }
   }
 }
 }
 
 
+function onExecutionStarted (evt) {
+  const logEntry = evt.payload.logEntry
+
+  marshalLogsJsonToHtml({
+    logs: [logEntry]
+  })
+}
+
 function onExecutionFinished (evt) {
 function onExecutionFinished (evt) {
   const logEntry = evt.payload.logEntry
   const logEntry = evt.payload.logEntry
 
 
@@ -136,7 +145,9 @@ function onExecutionFinished (evt) {
 
 
   switch (actionButton.popupOnStart) {
   switch (actionButton.popupOnStart) {
     case 'execution-button':
     case 'execution-button':
-      document.querySelector('execution-button#execution-' + logEntry.executionTrackingId).onExecutionFinished(logEntry)
+      if (document.querySelector('execution-button#execution-' + logEntry.executionTrackingId) !== null) { // If the button was created in our instance
+        document.querySelector('execution-button#execution-' + logEntry.executionTrackingId).onExecutionFinished(logEntry)
+      }
       break
       break
     case 'execution-dialog-stdout-only':
     case 'execution-dialog-stdout-only':
     case 'execution-dialog':
     case 'execution-dialog':
@@ -617,41 +628,46 @@ function marshalDirectory (item, section) {
 
 
 export function marshalLogsJsonToHtml (json) {
 export function marshalLogsJsonToHtml (json) {
   for (const logEntry of json.logs) {
   for (const logEntry of json.logs) {
-    const existing = window.logEntries[logEntry.executionTrackingId]
+    let row
 
 
-    if (existing !== undefined) {
-      continue
-    }
+    if (window.logEntries.has(logEntry.executionTrackingId)) {
+      row = window.logEntries.get(logEntry.executionTrackingId).dom
+    } else {
+      const tpl = document.getElementById('tplLogRow')
+      row = tpl.content.querySelector('tr').cloneNode(true)
+
+      row.querySelector('.content').onclick = () => {
+        window.executionDialog.reset()
+        window.executionDialog.show()
+        window.executionDialog.renderExecutionResult({
+          logEntry: window.logEntries.get(logEntry.executionTrackingId)
+        })
+        pushNewNavigationPath('/logs/' + logEntry.executionTrackingId)
+      }
 
 
-    window.logEntries[logEntry.executionTrackingId] = logEntry
+      row.exitCodeDisplay = new ActionStatusDisplay(row.querySelector('.exit-code'))
 
 
-    const tpl = document.getElementById('tplLogRow')
-    const row = tpl.content.querySelector('tr').cloneNode(true)
+      logEntry.dom = row
+
+      window.logEntries.set(logEntry.executionTrackingId, logEntry)
+
+      document.querySelector('#logTableBody').prepend(row)
+    }
 
 
     row.querySelector('.timestamp').innerText = logEntry.datetimeStarted
     row.querySelector('.timestamp').innerText = logEntry.datetimeStarted
     row.querySelector('.content').innerText = logEntry.actionTitle
     row.querySelector('.content').innerText = logEntry.actionTitle
     row.querySelector('.icon').innerHTML = logEntry.actionIcon
     row.querySelector('.icon').innerHTML = logEntry.actionIcon
     row.setAttribute('title', logEntry.actionTitle)
     row.setAttribute('title', logEntry.actionTitle)
 
 
-    const exitCodeDisplay = new ActionStatusDisplay(row.querySelector('.exit-code'))
-    exitCodeDisplay.update(logEntry)
+    row.exitCodeDisplay.update(logEntry)
 
 
-    row.querySelector('.content').onclick = () => {
-      window.executionDialog.reset()
-      window.executionDialog.show()
-      window.executionDialog.renderExecutionResult({
-        logEntry: window.logEntries[logEntry.executionTrackingId]
-      })
-      pushNewNavigationPath('/logs/' + logEntry.executionTrackingId)
-    }
+    row.querySelector('.tags').innerHTML = ''
 
 
     for (const tag of logEntry.tags) {
     for (const tag of logEntry.tags) {
       row.querySelector('.tags').append(createTag(tag))
       row.querySelector('.tags').append(createTag(tag))
     }
     }
 
 
     row.querySelector('.tags').append(createAnnotation('user', logEntry.user))
     row.querySelector('.tags').append(createAnnotation('user', logEntry.user))
-
-    document.querySelector('#logTableBody').prepend(row)
   }
   }
 }
 }
 
 

+ 1 - 0
webui.dev/js/websocket.js

@@ -54,6 +54,7 @@ function websocketOnMessage (msg) {
     case 'EventOutputChunk':
     case 'EventOutputChunk':
     case 'EventConfigChanged':
     case 'EventConfigChanged':
     case 'EventExecutionFinished':
     case 'EventExecutionFinished':
+    case 'EventExecutionStarted':
     case 'EventEntityChanged':
     case 'EventEntityChanged':
       window.dispatchEvent(e)
       window.dispatchEvent(e)
       break
       break