mirror of
https://github.com/OliveTin/OliveTin
synced 2025-12-12 09:05:39 +00:00
feature: Kill support in the UI (#297)
* feature: Kill command API (wip) * feature: Kill support in the UI
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -146,6 +146,7 @@ class ActionButton extends ExecutionFeedbackButton {
|
||||
window.executionDialog.hideEverythingApartFromOutput()
|
||||
}
|
||||
|
||||
window.executionDialog.executionTrackingId = executionTrackingId
|
||||
window.executionDialog.show(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user