#71: Started adding sub-result control
This commit is contained in:
@@ -328,7 +328,7 @@ class AppBase:
|
|||||||
print("BEFORE VARIABLES!")
|
print("BEFORE VARIABLES!")
|
||||||
if len(baseresult) == 0:
|
if len(baseresult) == 0:
|
||||||
try:
|
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"]:
|
for variable in execution_data["workflow"]["workflow_variables"]:
|
||||||
variablename = variable["name"].replace(" ", "_", -1).lower()
|
variablename = variable["name"].replace(" ", "_", -1).lower()
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ class AppBase:
|
|||||||
print("BEFORE EXECUTION VAR")
|
print("BEFORE EXECUTION VAR")
|
||||||
if len(baseresult) == 0:
|
if len(baseresult) == 0:
|
||||||
try:
|
try:
|
||||||
print("Execution Variables: %s" % execution_data["execution_variables"])
|
#print("Execution Variables: %s" % execution_data["execution_variables"])
|
||||||
for variable in execution_data["execution_variables"]:
|
for variable in execution_data["execution_variables"]:
|
||||||
variablename = variable["name"].replace(" ", "_", -1).lower()
|
variablename = variable["name"].replace(" ", "_", -1).lower()
|
||||||
if variablename.lower() == actionname_lower:
|
if variablename.lower() == actionname_lower:
|
||||||
|
|||||||
+104
-40
@@ -250,21 +250,24 @@ type Schedule struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Workflow struct {
|
type Workflow struct {
|
||||||
Actions []Action `json:"actions" datastore:"actions,noindex"`
|
Actions []Action `json:"actions" datastore:"actions,noindex"`
|
||||||
Branches []Branch `json:"branches" datastore:"branches,noindex"`
|
Branches []Branch `json:"branches" datastore:"branches,noindex"`
|
||||||
Triggers []Trigger `json:"triggers" datastore:"triggers,noindex"`
|
Triggers []Trigger `json:"triggers" datastore:"triggers,noindex"`
|
||||||
Schedules []Schedule `json:"schedules" datastore:"schedules,noindex"`
|
Schedules []Schedule `json:"schedules" datastore:"schedules,noindex"`
|
||||||
Errors []string `json:"errors,omitempty" datastore:"errors"`
|
Configuration struct {
|
||||||
Tags []string `json:"tags,omitempty" datastore:"tags"`
|
ExitOnError bool `json:"exit_on_error" datastore:"exit_on_error"`
|
||||||
ID string `json:"id" datastore:"id"`
|
} `json:"configuration,omitempty" datastore:"configuration"`
|
||||||
IsValid bool `json:"is_valid" datastore:"is_valid"`
|
Errors []string `json:"errors,omitempty" datastore:"errors"`
|
||||||
Name string `json:"name" datastore:"name"`
|
Tags []string `json:"tags,omitempty" datastore:"tags"`
|
||||||
Description string `json:"description" datastore:"description"`
|
ID string `json:"id" datastore:"id"`
|
||||||
Start string `json:"start" datastore:"start"`
|
IsValid bool `json:"is_valid" datastore:"is_valid"`
|
||||||
Owner string `json:"owner" datastore:"owner"`
|
Name string `json:"name" datastore:"name"`
|
||||||
Sharing string `json:"sharing" datastore:"sharing"`
|
Description string `json:"description" datastore:"description"`
|
||||||
Org []Org `json:"org,omitempty" datastore:"org"`
|
Start string `json:"start" datastore:"start"`
|
||||||
ExecutingOrg Org `json:"execution_org,omitempty" datastore:"execution_org"`
|
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 {
|
WorkflowVariables []struct {
|
||||||
Description string `json:"description" datastore:"description"`
|
Description string `json:"description" datastore:"description"`
|
||||||
ID string `json:"id" datastore:"id"`
|
ID string `json:"id" datastore:"id"`
|
||||||
@@ -276,7 +279,7 @@ type Workflow struct {
|
|||||||
ID string `json:"id" datastore:"id"`
|
ID string `json:"id" datastore:"id"`
|
||||||
Name string `json:"name" datastore:"name"`
|
Name string `json:"name" datastore:"name"`
|
||||||
Value string `json:"value" datastore:"value"`
|
Value string `json:"value" datastore:"value"`
|
||||||
} `json:"execution_variables,omitempty" datastore:"execution_variables,omitempty"`
|
} `json:"execution_variables,omitempty" datastore:"execution_variables"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionResult struct {
|
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) {
|
func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
@@ -732,20 +753,65 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// FIXME - remove comment
|
// FIXME - remove comment
|
||||||
if workflowExecution.Status == "ABORTED" || workflowExecution.Status == "FAILURE" {
|
if workflowExecution.Status == "ABORTED" || workflowExecution.Status == "FAILURE" {
|
||||||
|
|
||||||
log.Printf("Workflowexecution is already aborted. No further action can be taken")
|
if workflowExecution.Workflow.Configuration.ExitOnError {
|
||||||
resp.WriteHeader(401)
|
log.Printf("Workflowexecution already has status %s. No further action can be taken", workflowExecution.Status)
|
||||||
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)))
|
resp.WriteHeader(401)
|
||||||
return
|
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" {
|
if actionResult.Status == "ABORTED" || actionResult.Status == "FAILURE" {
|
||||||
log.Printf("Actionresult is %s. Should set workflowExecution and exit all running functions", actionResult.Status)
|
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
|
// Cleans up aborted, and always gives a result
|
||||||
lastResult := ""
|
lastResult := ""
|
||||||
newResults := []ActionResult{}
|
|
||||||
// type ActionResult struct {
|
// type ActionResult struct {
|
||||||
for _, result := range workflowExecution.Results {
|
for _, result := range workflowExecution.Results {
|
||||||
if result.Status == "EXECUTING" {
|
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
|
// FIXME rebuild to be like this or something
|
||||||
// workflowExecution/ExecutionId/Nodes/NodeId
|
// workflowExecution/ExecutionId/Nodes/NodeId
|
||||||
// Find the appropriate action
|
// 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)
|
//log.Printf("Checking results %d vs %d", len(workflowExecution.Results), len(workflowExecution.Workflow.Actions)+extraInputs)
|
||||||
if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extraInputs {
|
if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extraInputs {
|
||||||
finished := true
|
finished := true
|
||||||
lastResult := ""
|
lastResult := ""
|
||||||
|
|
||||||
|
// Doesn't have to be SUCCESS and FINISHED everywhere anymore.
|
||||||
|
skippedNodes := false
|
||||||
for _, result := range workflowExecution.Results {
|
for _, result := range workflowExecution.Results {
|
||||||
if result.Status != "SUCCESS" && result.Status != "FINISHED" {
|
if result.Status == "EXECUTING" {
|
||||||
finished = false
|
finished = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result.Status == "SKIPPED" {
|
||||||
|
skippedNodes = true
|
||||||
|
}
|
||||||
|
|
||||||
lastResult = result.Result
|
lastResult = result.Result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Handle skip nodes - change status?
|
||||||
|
_ = skippedNodes
|
||||||
|
|
||||||
if finished {
|
if finished {
|
||||||
log.Printf("Execution of %s finished.", workflowExecution.ExecutionId)
|
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.")
|
//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.Actions = newActions
|
||||||
workflow.IsValid = true
|
workflow.IsValid = true
|
||||||
|
workflow.Configuration.ExitOnError = true
|
||||||
|
|
||||||
workflowjson, err := json.Marshal(workflow)
|
workflowjson, err := json.Marshal(workflow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1431,7 +1495,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
"0ca8887e-b4af-4e3e-887c-87e9d3bc3d3e",
|
"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
|
builtin := false
|
||||||
for _, id := range reservedApps {
|
for _, id := range reservedApps {
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
frontend:
|
frontend:
|
||||||
#build: ./frontend
|
build: ./frontend
|
||||||
image: frikky/shuffle:frontend
|
image: frikky/shuffle:frontend
|
||||||
container_name: shuffle-frontend
|
container_name: shuffle-frontend
|
||||||
hostname: shuffle-frontend
|
hostname: shuffle-frontend
|
||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
backend:
|
backend:
|
||||||
#build: ./backend
|
build: ./backend
|
||||||
image: frikky/shuffle:backend
|
image: frikky/shuffle:backend
|
||||||
container_name: shuffle-backend
|
container_name: shuffle-backend
|
||||||
hostname: ${BACKEND_HOSTNAME}
|
hostname: ${BACKEND_HOSTNAME}
|
||||||
|
|||||||
@@ -1455,7 +1455,7 @@ const AngularWorkflow = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div style={appViewStyle}>
|
<div style={appViewStyle}>
|
||||||
<div style={variableScrollStyle}>
|
<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 ?
|
{workflow.workflow_variables === null ?
|
||||||
null : workflow.workflow_variables.map(variable=> {
|
null : workflow.workflow_variables.map(variable=> {
|
||||||
return (
|
return (
|
||||||
|
|||||||
+3
-1
@@ -39,8 +39,10 @@ import { positions, Provider } from "react-alert";
|
|||||||
|
|
||||||
// Production - backend proxy forwarding in nginx
|
// Production - backend proxy forwarding in nginx
|
||||||
var globalUrl = window.location.origin
|
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") {
|
if (window.location.protocol == "http:" && window.location.port === "3000") {
|
||||||
globalUrl = "http://192.168.3.6:5001"
|
globalUrl = "http://localhost:5001"
|
||||||
}
|
}
|
||||||
|
|
||||||
const surfaceColor = "#27292D"
|
const surfaceColor = "#27292D"
|
||||||
|
|||||||
@@ -189,10 +189,10 @@ const Docs = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Heading(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 (
|
return (
|
||||||
<span>
|
<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}
|
{element}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user