#71: Started adding sub-result control
This commit is contained in:
@@ -328,7 +328,7 @@ class AppBase:
|
||||
print("BEFORE VARIABLES!")
|
||||
if len(baseresult) == 0:
|
||||
try:
|
||||
print("WF Variables: %s" % execution_data["workflow"]["workflow_variables"])
|
||||
#print("WF Variables: %s" % execution_data["workflow"]["workflow_variables"])
|
||||
for variable in execution_data["workflow"]["workflow_variables"]:
|
||||
variablename = variable["name"].replace(" ", "_", -1).lower()
|
||||
|
||||
@@ -345,7 +345,7 @@ class AppBase:
|
||||
print("BEFORE EXECUTION VAR")
|
||||
if len(baseresult) == 0:
|
||||
try:
|
||||
print("Execution Variables: %s" % execution_data["execution_variables"])
|
||||
#print("Execution Variables: %s" % execution_data["execution_variables"])
|
||||
for variable in execution_data["execution_variables"]:
|
||||
variablename = variable["name"].replace(" ", "_", -1).lower()
|
||||
if variablename.lower() == actionname_lower:
|
||||
|
||||
+104
-40
@@ -250,21 +250,24 @@ type Schedule struct {
|
||||
}
|
||||
|
||||
type Workflow struct {
|
||||
Actions []Action `json:"actions" datastore:"actions,noindex"`
|
||||
Branches []Branch `json:"branches" datastore:"branches,noindex"`
|
||||
Triggers []Trigger `json:"triggers" datastore:"triggers,noindex"`
|
||||
Schedules []Schedule `json:"schedules" datastore:"schedules,noindex"`
|
||||
Errors []string `json:"errors,omitempty" datastore:"errors"`
|
||||
Tags []string `json:"tags,omitempty" datastore:"tags"`
|
||||
ID string `json:"id" datastore:"id"`
|
||||
IsValid bool `json:"is_valid" datastore:"is_valid"`
|
||||
Name string `json:"name" datastore:"name"`
|
||||
Description string `json:"description" datastore:"description"`
|
||||
Start string `json:"start" datastore:"start"`
|
||||
Owner string `json:"owner" datastore:"owner"`
|
||||
Sharing string `json:"sharing" datastore:"sharing"`
|
||||
Org []Org `json:"org,omitempty" datastore:"org"`
|
||||
ExecutingOrg Org `json:"execution_org,omitempty" datastore:"execution_org"`
|
||||
Actions []Action `json:"actions" datastore:"actions,noindex"`
|
||||
Branches []Branch `json:"branches" datastore:"branches,noindex"`
|
||||
Triggers []Trigger `json:"triggers" datastore:"triggers,noindex"`
|
||||
Schedules []Schedule `json:"schedules" datastore:"schedules,noindex"`
|
||||
Configuration struct {
|
||||
ExitOnError bool `json:"exit_on_error" datastore:"exit_on_error"`
|
||||
} `json:"configuration,omitempty" datastore:"configuration"`
|
||||
Errors []string `json:"errors,omitempty" datastore:"errors"`
|
||||
Tags []string `json:"tags,omitempty" datastore:"tags"`
|
||||
ID string `json:"id" datastore:"id"`
|
||||
IsValid bool `json:"is_valid" datastore:"is_valid"`
|
||||
Name string `json:"name" datastore:"name"`
|
||||
Description string `json:"description" datastore:"description"`
|
||||
Start string `json:"start" datastore:"start"`
|
||||
Owner string `json:"owner" datastore:"owner"`
|
||||
Sharing string `json:"sharing" datastore:"sharing"`
|
||||
Org []Org `json:"org,omitempty" datastore:"org"`
|
||||
ExecutingOrg Org `json:"execution_org,omitempty" datastore:"execution_org"`
|
||||
WorkflowVariables []struct {
|
||||
Description string `json:"description" datastore:"description"`
|
||||
ID string `json:"id" datastore:"id"`
|
||||
@@ -276,7 +279,7 @@ type Workflow struct {
|
||||
ID string `json:"id" datastore:"id"`
|
||||
Name string `json:"name" datastore:"name"`
|
||||
Value string `json:"value" datastore:"value"`
|
||||
} `json:"execution_variables,omitempty" datastore:"execution_variables,omitempty"`
|
||||
} `json:"execution_variables,omitempty" datastore:"execution_variables"`
|
||||
}
|
||||
|
||||
type ActionResult struct {
|
||||
@@ -675,6 +678,24 @@ func handleGetStreamResults(resp http.ResponseWriter, request *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
// Finds the child nodes of a node in execution and returns them
|
||||
// Used if e.g. a node in a branch is exited, and all children have to be stopped
|
||||
func findChildNodes(workflowExecution WorkflowExecution, nodeId string) []string {
|
||||
log.Printf("\nNODE TO FIX: %s\n\n", nodeId)
|
||||
allChildren := []string{nodeId}
|
||||
|
||||
// 1. Find children of this specific node
|
||||
// 2. Find the children of those nodes etc.
|
||||
for _, branch := range workflowExecution.Workflow.Branches {
|
||||
if branch.SourceID == nodeId {
|
||||
log.Printf("Children: %s", branch.DestinationID)
|
||||
allChildren = append(allChildren, branch.DestinationID)
|
||||
}
|
||||
}
|
||||
|
||||
return allChildren
|
||||
}
|
||||
|
||||
func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
cors := handleCors(resp, request)
|
||||
if cors {
|
||||
@@ -732,20 +753,65 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
// FIXME - remove comment
|
||||
if workflowExecution.Status == "ABORTED" || workflowExecution.Status == "FAILURE" {
|
||||
|
||||
log.Printf("Workflowexecution is already aborted. No further action can be taken")
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Workflowexecution is aborted because of %s with result %s and status %s"}`, workflowExecution.LastNode, workflowExecution.Result, workflowExecution.Status)))
|
||||
return
|
||||
if workflowExecution.Workflow.Configuration.ExitOnError {
|
||||
log.Printf("Workflowexecution already has status %s. No further action can be taken", workflowExecution.Status)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Workflowexecution is aborted because of %s with result %s and status %s"}`, workflowExecution.LastNode, workflowExecution.Result, workflowExecution.Status)))
|
||||
return
|
||||
} else {
|
||||
log.Printf("Continuing even though it's aborted.")
|
||||
}
|
||||
}
|
||||
|
||||
if actionResult.Status == "ABORTED" || actionResult.Status == "FAILURE" {
|
||||
log.Printf("Actionresult is %s. Should set workflowExecution and exit all running functions", actionResult.Status)
|
||||
workflowExecution.Status = actionResult.Status
|
||||
workflowExecution.LastNode = actionResult.Action.ID
|
||||
|
||||
newResults := []ActionResult{}
|
||||
childNodes := []string{}
|
||||
if workflowExecution.Workflow.Configuration.ExitOnError {
|
||||
workflowExecution.Status = actionResult.Status
|
||||
workflowExecution.LastNode = actionResult.Action.ID
|
||||
// Find underlying nodes and add them
|
||||
} else {
|
||||
// Finds childnodes to set them to SKIPPED
|
||||
childNodes = findChildNodes(*workflowExecution, actionResult.Action.ID)
|
||||
for _, nodeId := range childNodes {
|
||||
if nodeId == actionResult.Action.ID {
|
||||
continue
|
||||
}
|
||||
|
||||
// 1. Find the action itself
|
||||
// 2. Create an actionresult
|
||||
curAction := Action{ID: ""}
|
||||
for _, action := range workflowExecution.Workflow.Actions {
|
||||
if action.ID == nodeId {
|
||||
curAction = action
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(curAction.ID) == 0 {
|
||||
log.Printf("Couldn't find subnode %s", nodeId)
|
||||
continue
|
||||
}
|
||||
|
||||
newResult := ActionResult{
|
||||
Action: curAction,
|
||||
ExecutionId: actionResult.ExecutionId,
|
||||
Authorization: actionResult.Authorization,
|
||||
Result: "Skipped because of previous node",
|
||||
StartedAt: 0,
|
||||
CompletedAt: 0,
|
||||
Status: "SKIPPED",
|
||||
}
|
||||
|
||||
newResults = append(newResults, newResult)
|
||||
increaseStatisticsField(ctx, "workflow_execution_actions_skipped", workflowExecution.Workflow.ID, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans up aborted, and always gives a result
|
||||
lastResult := ""
|
||||
newResults := []ActionResult{}
|
||||
// type ActionResult struct {
|
||||
for _, result := range workflowExecution.Results {
|
||||
if result.Status == "EXECUTING" {
|
||||
@@ -776,21 +842,6 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// This means it should continue I think :)
|
||||
if actionResult.Status == "SKIPPED" {
|
||||
// How the fuck do I do this tho
|
||||
// Parse _all_ children of the skipped and add them to "finished"
|
||||
//
|
||||
log.Printf("Find out how to handle skipped items, as there might be more branches to continue anyway")
|
||||
// FIXME - simulate that every subnode is skipped
|
||||
// Check worker, as it contains this code
|
||||
// Children of children of children...
|
||||
// Recurse, woo
|
||||
//for _, item := range children {
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
// FIXME rebuild to be like this or something
|
||||
// workflowExecution/ExecutionId/Nodes/NodeId
|
||||
// Find the appropriate action
|
||||
@@ -840,19 +891,31 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("LENGTH: %d - %d", len(workflowExecution.Results), len(workflowExecution.Workflow.Actions))
|
||||
|
||||
//log.Printf("Checking results %d vs %d", len(workflowExecution.Results), len(workflowExecution.Workflow.Actions)+extraInputs)
|
||||
if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extraInputs {
|
||||
finished := true
|
||||
lastResult := ""
|
||||
|
||||
// Doesn't have to be SUCCESS and FINISHED everywhere anymore.
|
||||
skippedNodes := false
|
||||
for _, result := range workflowExecution.Results {
|
||||
if result.Status != "SUCCESS" && result.Status != "FINISHED" {
|
||||
if result.Status == "EXECUTING" {
|
||||
finished = false
|
||||
break
|
||||
}
|
||||
|
||||
if result.Status == "SKIPPED" {
|
||||
skippedNodes = true
|
||||
}
|
||||
|
||||
lastResult = result.Result
|
||||
}
|
||||
|
||||
// FIXME: Handle skip nodes - change status?
|
||||
_ = skippedNodes
|
||||
|
||||
if finished {
|
||||
log.Printf("Execution of %s finished.", workflowExecution.ExecutionId)
|
||||
//log.Println("Might be finished based on length of results and everything being SUCCESS or FINISHED - VERIFY THIS. Setting status to finished.")
|
||||
@@ -1070,6 +1133,7 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
|
||||
workflow.Actions = newActions
|
||||
workflow.IsValid = true
|
||||
workflow.Configuration.ExitOnError = true
|
||||
|
||||
workflowjson, err := json.Marshal(workflow)
|
||||
if err != nil {
|
||||
@@ -1431,7 +1495,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
"0ca8887e-b4af-4e3e-887c-87e9d3bc3d3e",
|
||||
}
|
||||
|
||||
log.Printf("%s Action execution var: %s", action.Label, action.ExecutionVariable.Name)
|
||||
//log.Printf("%s Action execution var: %s", action.Label, action.ExecutionVariable.Name)
|
||||
|
||||
builtin := false
|
||||
for _, id := range reservedApps {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
version: '3'
|
||||
services:
|
||||
frontend:
|
||||
#build: ./frontend
|
||||
build: ./frontend
|
||||
image: frikky/shuffle:frontend
|
||||
container_name: shuffle-frontend
|
||||
hostname: shuffle-frontend
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
depends_on:
|
||||
- backend
|
||||
backend:
|
||||
#build: ./backend
|
||||
build: ./backend
|
||||
image: frikky/shuffle:backend
|
||||
container_name: shuffle-backend
|
||||
hostname: ${BACKEND_HOSTNAME}
|
||||
|
||||
@@ -1455,7 +1455,7 @@ const AngularWorkflow = (props) => {
|
||||
return (
|
||||
<div style={appViewStyle}>
|
||||
<div style={variableScrollStyle}>
|
||||
What are <a href="https://shuffler.io/docs/workflows#variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>WORKFLOW variables?</a>
|
||||
What are <a href="https://shuffler.io/docs/workflows#workflow_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>WORKFLOW variables?</a>
|
||||
{workflow.workflow_variables === null ?
|
||||
null : workflow.workflow_variables.map(variable=> {
|
||||
return (
|
||||
|
||||
+3
-1
@@ -39,8 +39,10 @@ import { positions, Provider } from "react-alert";
|
||||
|
||||
// Production - backend proxy forwarding in nginx
|
||||
var globalUrl = window.location.origin
|
||||
|
||||
// CORS used for testing purposes. Should only happen with specific port and http
|
||||
if (window.location.protocol == "http:" && window.location.port === "3000") {
|
||||
globalUrl = "http://192.168.3.6:5001"
|
||||
globalUrl = "http://localhost:5001"
|
||||
}
|
||||
|
||||
const surfaceColor = "#27292D"
|
||||
|
||||
@@ -189,10 +189,10 @@ const Docs = (props) => {
|
||||
}
|
||||
|
||||
function Heading(props) {
|
||||
const element = React.createElement(`h${props.level}`, {style: {marginTop: 25}}, props.children)
|
||||
const element = React.createElement(`h${props.level}`, {style: {marginTop: 40}}, props.children)
|
||||
return (
|
||||
<span>
|
||||
{props.level !== 1 ? <Divider style={{width: "90%", marginTop: 25, backgroundColor: inputColor}} /> : null}
|
||||
{props.level !== 1 ? <Divider style={{width: "90%", marginTop: 40, backgroundColor: inputColor}} /> : null}
|
||||
{element}
|
||||
</span>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user