diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index cd7fc992..f607e452 100644 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -428,7 +428,7 @@ class AppBase: except KeyError as e: print("Lower keyerror: %s" % e) - return "KeyError: %s" % e + return "KeyError: Couldn't find key: %s" % e return basejson @@ -795,7 +795,7 @@ class AppBase: result += "Failed autocasting. Can't handle %s type from function. Must be string" % type(newres) print("Can't handle type %s value from function" % (type(newres))) else: - print("APP_SDK DONE: Starting multi execution with", multi_parameters) + print("APP_SDK DONE: Starting MULTI execution with", multi_parameters) # 1. Use number of executions based on longest array # 2. Find the right value from the parsed multi_params @@ -848,10 +848,11 @@ class AppBase: self.logger.debug(f"Executed {action['label']}-{action['id']} with result: {result}") self.logger.debug(f"Data: %s" % action_result) except TypeError as e: + print("TypeError issue: %s" % e) action_result["status"] = "FAILURE" action_result["result"] = "TypeError: %s" % str(e) else: - print("Not callable?") + print("Function %s doesn't exist?" % action["name"]) self.logger.error(f"App {self.__class__.__name__}.{action['name']} is not callable") action_result["status"] = "FAILURE" action_result["result"] = "Function %s is not callable." % actionname diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index e05ff1df..5aa2aa45 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -1250,7 +1250,7 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) { workflow.Actions = newActions workflow.IsValid = true - workflow.Configuration.ExitOnError = true + workflow.Configuration.ExitOnError = false workflowjson, err := json.Marshal(workflow) if err != nil { @@ -1573,6 +1573,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) { // doesn't check sharing=true // Have to do it like this to add the user's apps log.Println("Apps set starting") + log.Printf("EXIT ON ERROR: %#v", workflow.Configuration.ExitOnError) workflowApps := []WorkflowApp{} //memcacheName = "all_apps" //if item, err := memcache.Get(ctx, memcacheName); err == memcache.ErrCacheMiss { diff --git a/frontend/src/AngularWorkflow.js b/frontend/src/AngularWorkflow.js index 45814704..db735647 100644 --- a/frontend/src/AngularWorkflow.js +++ b/frontend/src/AngularWorkflow.js @@ -50,6 +50,7 @@ import SaveIcon from '@material-ui/icons/Save'; import KeyboardArrowLeftIcon from '@material-ui/icons/KeyboardArrowLeft'; import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import SettingsIcon from '@material-ui/icons/Settings'; import * as cytoscape from 'cytoscape'; import * as edgehandles from 'cytoscape-edgehandles'; @@ -4202,7 +4203,7 @@ const AngularWorkflow = (props) => { return null } - const cytoscapeViewWidths = 650 + const cytoscapeViewWidths = 700 const bottomBarStyle = { position: "fixed", right: 20, @@ -4260,8 +4261,67 @@ const AngularWorkflow = (props) => { return null } + const WorkflowMenu = () => { + const [newAnchor, setNewAnchor] = React.useState(null); + const [showShuffleMenu, setShowShuffleMenu] = React.useState(false) + + { /*const [showShuffleMenu, setShowShuffleMenu] = React.useState(true) */} + return ( +
+ { + setShowShuffleMenu(false) + }} + > +
+

This menu is used to control the workflow itself.

+ + Exit on Error
+ control={ + { + workflow.configuration.exit_on_error = !workflow.configuration.exit_on_error + setWorkflow(workflow) + setUpdate("exit_on_error_"+workflow.configuration.exit_on_error ? "true" : "false") + setShowShuffleMenu(false) + }} /> + } + /> + Start from top
+ control={ + { + workflow.configuration.start_from_top = !workflow.configuration.start_from_top + setWorkflow(workflow) + setUpdate("start_from_top_"+workflow.configuration.start_from_top ? "true" : "false") + setShowShuffleMenu(false) + }} /> + } + /> + + + + + + + ) + } const BottomCytoscapeBar = () => { + const [anchorEl, setAnchorEl] = React.useState(null); + const boxSize = 100 const executionButton = executionRunning ? @@ -4328,6 +4388,7 @@ const AngularWorkflow = (props) => { + ) @@ -4461,9 +4522,9 @@ const AngularWorkflow = (props) => { const getExecutionSourceImage = (execution) => { + // This is the playbutton at 150x150 const defaultImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACOCAMAAADkWgEmAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAWlBMVEX4Wj69TDgmKCvkVTwlJyskJiokJikkJSkjJSn4Ykf+6+f5h3L////8xLr5alH/9fT7nYz4Wz/919H5cVn/+vr8qpv4XUL94d35e2X//v38t6v4YUbkVDy8SzcVIzHLAAAAAWJLR0QMgbNRYwAAAAlwSFlzAAARsAAAEbAByCf1VAAAAAd0SU1FB+QGGgsvBZ/GkmwAAAFKSURBVHja7dlrTgMxDEXhFgpTiukL2vLc/zbZQH5N7MmReu4KPmlGN4m9WgGzfhgtaOZxM1rQztNoQDvPowHtTKMB7WxHA2TJkiVLlixIZMmSRYgsWbIIkSVLFiGyZMkiRNZirBcma/eKZEW87ZGsOBxPRFbE+R3Jio/LlciKuH0iWfH1/UNkRSR3RRYruSvyWKldkcjK7IpUVl5X5LLSuiKbldQV6aycrihgZXRFCau/K2pY3V1RxersijJWX1cUsnq6opLV0RW1rNldUc2a2RXlrHldsQBrTlfcLwv5EZm/PLIgkHXKPHyQRzXzYoO8BjIvzcgnBvJBxny+Ih/7zNEIcpDEHLshh5TIkS5zAI5cFzCXK8hVFHNxh1xzQpfC0BV6XWTJkkWILFmyCJElSxYhsmTJIkSWLFmEyJIlixBZsmQB8stk/U3/Yb49pVcDMg4AAAAldEVYdGRhdGU6Y3JlYXRlADIwMjAtMDYtMjZUMTE6NDc6MDUrMDI6MDD8QCPmAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIwLTA2LTI2VDExOjQ3OjA1KzAyOjAwjR2bWgAAAABJRU5ErkJggg==" const size = 40 - console.log("EXECUTION SOURCE: ", execution.execution_source) if (execution.execution_source === undefined || execution.execution_source === null || execution.execution_source.length === 0) { return default } @@ -4560,7 +4621,7 @@ const AngularWorkflow = (props) => {

Executing Workflow

Show skipped actions + label=
Show failed / skipped actions
control={ {setShowSkippedActions(!showSkippedActions)}} /> } @@ -4603,7 +4664,7 @@ const AngularWorkflow = (props) => { : executionData.results.map(data => { - if (!showSkippedActions && data.status === "SKIPPED") { + if (!showSkippedActions && (data.status === "SKIPPED" || data.status === "FAILURE")) { return null }