#71: Added control options to the workflow
This commit is contained in:
@@ -428,7 +428,7 @@ class AppBase:
|
|||||||
|
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print("Lower keyerror: %s" % e)
|
print("Lower keyerror: %s" % e)
|
||||||
return "KeyError: %s" % e
|
return "KeyError: Couldn't find key: %s" % e
|
||||||
|
|
||||||
return basejson
|
return basejson
|
||||||
|
|
||||||
@@ -795,7 +795,7 @@ class AppBase:
|
|||||||
result += "Failed autocasting. Can't handle %s type from function. Must be string" % type(newres)
|
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)))
|
print("Can't handle type %s value from function" % (type(newres)))
|
||||||
else:
|
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
|
# 1. Use number of executions based on longest array
|
||||||
# 2. Find the right value from the parsed multi_params
|
# 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"Executed {action['label']}-{action['id']} with result: {result}")
|
||||||
self.logger.debug(f"Data: %s" % action_result)
|
self.logger.debug(f"Data: %s" % action_result)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
|
print("TypeError issue: %s" % e)
|
||||||
action_result["status"] = "FAILURE"
|
action_result["status"] = "FAILURE"
|
||||||
action_result["result"] = "TypeError: %s" % str(e)
|
action_result["result"] = "TypeError: %s" % str(e)
|
||||||
else:
|
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")
|
self.logger.error(f"App {self.__class__.__name__}.{action['name']} is not callable")
|
||||||
action_result["status"] = "FAILURE"
|
action_result["status"] = "FAILURE"
|
||||||
action_result["result"] = "Function %s is not callable." % actionname
|
action_result["result"] = "Function %s is not callable." % actionname
|
||||||
|
|||||||
@@ -1250,7 +1250,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
|
workflow.Configuration.ExitOnError = false
|
||||||
|
|
||||||
workflowjson, err := json.Marshal(workflow)
|
workflowjson, err := json.Marshal(workflow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1573,6 +1573,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// doesn't check sharing=true
|
// doesn't check sharing=true
|
||||||
// Have to do it like this to add the user's apps
|
// Have to do it like this to add the user's apps
|
||||||
log.Println("Apps set starting")
|
log.Println("Apps set starting")
|
||||||
|
log.Printf("EXIT ON ERROR: %#v", workflow.Configuration.ExitOnError)
|
||||||
workflowApps := []WorkflowApp{}
|
workflowApps := []WorkflowApp{}
|
||||||
//memcacheName = "all_apps"
|
//memcacheName = "all_apps"
|
||||||
//if item, err := memcache.Get(ctx, memcacheName); err == memcache.ErrCacheMiss {
|
//if item, err := memcache.Get(ctx, memcacheName); err == memcache.ErrCacheMiss {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import SaveIcon from '@material-ui/icons/Save';
|
|||||||
import KeyboardArrowLeftIcon from '@material-ui/icons/KeyboardArrowLeft';
|
import KeyboardArrowLeftIcon from '@material-ui/icons/KeyboardArrowLeft';
|
||||||
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
|
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
|
||||||
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
|
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
|
||||||
|
import SettingsIcon from '@material-ui/icons/Settings';
|
||||||
|
|
||||||
import * as cytoscape from 'cytoscape';
|
import * as cytoscape from 'cytoscape';
|
||||||
import * as edgehandles from 'cytoscape-edgehandles';
|
import * as edgehandles from 'cytoscape-edgehandles';
|
||||||
@@ -4202,7 +4203,7 @@ const AngularWorkflow = (props) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const cytoscapeViewWidths = 650
|
const cytoscapeViewWidths = 700
|
||||||
const bottomBarStyle = {
|
const bottomBarStyle = {
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
right: 20,
|
right: 20,
|
||||||
@@ -4260,8 +4261,67 @@ const AngularWorkflow = (props) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const WorkflowMenu = () => {
|
||||||
|
const [newAnchor, setNewAnchor] = React.useState(null);
|
||||||
|
const [showShuffleMenu, setShowShuffleMenu] = React.useState(false)
|
||||||
|
|
||||||
|
{ /*const [showShuffleMenu, setShowShuffleMenu] = React.useState(true) */}
|
||||||
|
return (
|
||||||
|
<div style={{"display": "inline-block"}}>
|
||||||
|
<Menu
|
||||||
|
id="long-menu"
|
||||||
|
anchorEl={newAnchor}
|
||||||
|
open={showShuffleMenu}
|
||||||
|
onClose={() => {
|
||||||
|
setShowShuffleMenu(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{margin: 15, color: "white", maxWidth: 250, minWidth: 250, }}>
|
||||||
|
<h4>This menu is used to control the workflow itself.</h4>
|
||||||
|
<Divider style={{backgroundColor: "white", marginTop: 10, marginBottom: 10,}}/>
|
||||||
|
<FormControlLabel
|
||||||
|
style={{marginBottom: 15, color: "white",}}
|
||||||
|
label=<div style={{color: "white"}}>Exit on Error</div>
|
||||||
|
control={
|
||||||
|
<Switch checked={workflow.configuration.exit_on_error} onChange={() => {
|
||||||
|
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)
|
||||||
|
}} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<FormControlLabel
|
||||||
|
style={{marginBottom: 15, color: "white",}}
|
||||||
|
label=<div style={{color: "white"}}>Start from top</div>
|
||||||
|
control={
|
||||||
|
<Switch checked={workflow.configuration.start_from_top} onChange={() => {
|
||||||
|
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)
|
||||||
|
}} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Menu>
|
||||||
|
<Tooltip color="secondary" title="Show settings" placement="top-start">
|
||||||
|
<Button color="primary" style={{height: 50, marginLeft: 10, }} variant="outlined" onClick={(event) => {
|
||||||
|
setShowShuffleMenu(!showShuffleMenu)
|
||||||
|
console.log("EVENT: ", event)
|
||||||
|
console.log("EVENT: ", event.currentTarget)
|
||||||
|
setNewAnchor(event.currentTarget)
|
||||||
|
}}>
|
||||||
|
<SettingsIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const BottomCytoscapeBar = () => {
|
const BottomCytoscapeBar = () => {
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||||
|
|
||||||
const boxSize = 100
|
const boxSize = 100
|
||||||
const executionButton = executionRunning ?
|
const executionButton = executionRunning ?
|
||||||
<Tooltip color="primary" title="Stop execution" placement="top">
|
<Tooltip color="primary" title="Stop execution" placement="top">
|
||||||
@@ -4328,6 +4388,7 @@ const AngularWorkflow = (props) => {
|
|||||||
<DirectionsRunIcon />
|
<DirectionsRunIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<WorkflowMenu />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -4461,9 +4522,9 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
|
|
||||||
const getExecutionSourceImage = (execution) => {
|
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 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
|
const size = 40
|
||||||
console.log("EXECUTION SOURCE: ", execution.execution_source)
|
|
||||||
if (execution.execution_source === undefined || execution.execution_source === null || execution.execution_source.length === 0) {
|
if (execution.execution_source === undefined || execution.execution_source === null || execution.execution_source.length === 0) {
|
||||||
return <img alt="default" src={defaultImage} style={{width: size, height: size}} />
|
return <img alt="default" src={defaultImage} style={{width: size, height: size}} />
|
||||||
}
|
}
|
||||||
@@ -4560,7 +4621,7 @@ const AngularWorkflow = (props) => {
|
|||||||
<h2>Executing Workflow</h2>
|
<h2>Executing Workflow</h2>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
style={{color: "white", marginBottom: "0px", marginTop: "10px"}}
|
style={{color: "white", marginBottom: "0px", marginTop: "10px"}}
|
||||||
label=<div style={{color: "white"}}>Show skipped actions</div>
|
label=<div style={{color: "white"}}>Show failed / skipped actions</div>
|
||||||
control={
|
control={
|
||||||
<Switch checked={showSkippedActions} onChange={() => {setShowSkippedActions(!showSkippedActions)}} />
|
<Switch checked={showSkippedActions} onChange={() => {setShowSkippedActions(!showSkippedActions)}} />
|
||||||
}
|
}
|
||||||
@@ -4603,7 +4664,7 @@ const AngularWorkflow = (props) => {
|
|||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
:
|
:
|
||||||
executionData.results.map(data => {
|
executionData.results.map(data => {
|
||||||
if (!showSkippedActions && data.status === "SKIPPED") {
|
if (!showSkippedActions && (data.status === "SKIPPED" || data.status === "FAILURE")) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user