feature: Kill support in the UI (#297)

* feature: Kill command API (wip)

* feature: Kill support in the UI
This commit is contained in:
James Read
2024-04-27 22:51:45 +01:00
committed by GitHub
parent a783fc8cd4
commit dc6f6c2896
7 changed files with 87 additions and 8 deletions

View File

@@ -189,6 +189,17 @@ message EventExecutionFinished {
LogEntry log_entry = 1;
}
message KillActionRequest {
string execution_tracking_id = 1;
}
message KillActionResponse {
string execution_tracking_id = 1;
bool killed = 2;
bool already_completed = 3;
bool found = 4;
}
service OliveTinApiService {
rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) {
option (google.api.http) = {
@@ -222,6 +233,13 @@ service OliveTinApiService {
};
}
rpc KillAction(KillActionRequest) returns (KillActionResponse) {
option (google.api.http) = {
post: "/api/KillAction"
body: "*"
};
}
rpc ExecutionStatus(ExecutionStatusRequest) returns (ExecutionStatusResponse) {
option (google.api.http) = {
post: "/api/ExecutionStatus"

View File

@@ -74,6 +74,7 @@ type InternalLogEntry struct {
ExecutionStarted bool
ExecutionFinished bool
ExecutionTrackingID string
Process *os.Process
/*
The following 3 properties are obviously on Action normally, but it's useful
@@ -382,6 +383,8 @@ func stepExec(req *ExecutionRequest) bool {
runerr := cmd.Start()
req.logEntry.Process = cmd.Process
waiterr := cmd.Wait()
req.logEntry.ExitCode = int32(cmd.ProcessState.ExitCode())

View File

@@ -30,6 +30,28 @@ type oliveTinAPI struct {
executor *executor.Executor
}
func (api *oliveTinAPI) KillAction(ctx ctx.Context, req *pb.KillActionRequest) (*pb.KillActionResponse, error) {
ret := &pb.KillActionResponse{
ExecutionTrackingId: req.ExecutionTrackingId,
}
execReq, found := api.executor.Logs[req.ExecutionTrackingId]
ret.Found = found
if found {
err := execReq.Process.Kill()
if err == nil {
ret.AlreadyCompleted = true
} else {
ret.Killed = true
}
}
return ret, nil
}
func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) (*pb.StartActionResponse, error) {
args := make(map[string]string)

View File

@@ -125,11 +125,13 @@
</details>
</div>
<form method = "dialog">
<div class = "buttons">
<button name = "kill" title = "Kill" id = "execution-dialog-kill-action">Kill</button>
<form method = "dialog">
<button name = "Cancel" title = "Close">Close</button>
</div>
</form>
</div>
</dialog>
<template id = "tplArgumentForm">

View File

@@ -146,6 +146,7 @@ class ActionButton extends ExecutionFeedbackButton {
window.executionDialog.hideEverythingApartFromOutput()
}
window.executionDialog.executionTrackingId = executionTrackingId
window.executionDialog.show(this)
}

View File

@@ -14,6 +14,8 @@ export class ExecutionDialog {
this.toggleSize()
}
this.domBtnKill = document.getElementById('execution-dialog-kill-action')
this.domDatetimeStarted = document.getElementById('execution-dialog-datetime-started')
this.domDatetimeFinished = document.getElementById('execution-dialog-datetime-finished')
this.domExitCode = document.getElementById('execution-dialog-exit-code')
@@ -36,6 +38,7 @@ export class ExecutionDialog {
reset () {
this.executionSeconds = 0
this.executionTrackingId = 'notset'
this.dlg.classList.remove('big')
this.dlg.style.maxWidth = 'calc(100vw - 2em)'
@@ -54,6 +57,9 @@ export class ExecutionDialog {
this.domStdout.innerText = ''
this.domStderr.innerText = ''
this.domBtnKill.disabled = true
this.domBtnKill.onclick = () => {}
this.hideDetailsOnResult = false
this.domExecutionBasics.hidden = false
@@ -68,6 +74,11 @@ export class ExecutionDialog {
this.domIcon.innerText = actionButton.domIcon.innerText
}
this.domBtnKill.disabled = false
this.domBtnKill.onclick = () => {
this.killAction()
}
clearInterval(window.executionDialogTicker)
this.executionSeconds = 0
this.executionTick()
@@ -82,6 +93,24 @@ export class ExecutionDialog {
this.dlg.showModal()
}
killAction () {
const killActionArgs = {
executionTrackingId: this.executionTrackingId
}
window.fetch(window.restBaseUrl + 'KillAction', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(killActionArgs)
}).then((res) => {
console.log(res)
}).catch(err => {
throw err
})
}
executionTick () {
this.executionSeconds++
@@ -93,8 +122,8 @@ export class ExecutionDialog {
this.domExecutionBasics.hidden = true
}
fetchExecutionResult (uuid) {
this.executionTrackingId = uuid
fetchExecutionResult (executionTrackingId) {
this.executionTrackingId = executionTrackingId
const executionStatusArgs = {
executionTrackingId: this.executionTrackingId
@@ -133,6 +162,8 @@ export class ExecutionDialog {
this.executionTrackingId = res.logEntry.executionTrackingId
this.domBtnKill.disabled = res.logEntry.executionFinished
if (res.logEntry.executionFinished) {
this.domStatus.innerText = 'Completed'
this.domStatus.classList.add('action-success')

View File

@@ -424,8 +424,10 @@ p.argument-wrapper {
display: flex;
}
form div.buttons {
text-align: right;
div.buttons {
display: flex;
justify-content: end;
gap: 1em;
}
pre {