From 47b02dec898d34d5cc226a6e931ddf068af50409 Mon Sep 17 00:00:00 2001 From: frikky Date: Wed, 24 Nov 2021 17:40:59 +0100 Subject: [PATCH] Fixed bugs and visuals in angularworkflow --- backend/app_sdk/app_base.py | 12 +- backend/go-app/go.mod | 2 +- backend/go-app/main.go | 1 + docker-compose.yml | 2 +- frontend/src/components/ConfigureWorkflow.jsx | 73 +-- frontend/src/components/ParsedAction.jsx | 5 +- frontend/src/views/AngularWorkflow.jsx | 470 ++++++++++-------- frontend/src/views/Workflows.jsx | 76 +-- 8 files changed, 363 insertions(+), 278 deletions(-) diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index 132b3fe9..190d983a 100644 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -587,10 +587,13 @@ class AppBase: try: e = sys.exc_info()[1] except: - self.logger.info("Exc check fail: %s" % e) + self.logger.info("Exec check fail: %s" % e) pass - tmp = "An error occured during execution: %s" % e + tmp = json.dumps({ + "success": False, + "reason": f"An error occured during execution: {e}", + }) # An attempt at decomposing coroutine results @@ -2156,7 +2159,10 @@ class AppBase: if func == None: self.logger.debug(f"[DEBUG] Failed executing {actionname} because func is None (no function specified).") self.action_result["status"] = "FAILURE" - self.action_result["result"] = "Function %s doesn't exist." % actionname + self.action_result["result"] = json.dumps({ + "success": False, + "reason": f"Function {actionname} doesn't exist.", + }) elif callable(func): try: if len(action["parameters"]) < 1: diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 627332b2..c08245ed 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -22,7 +22,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/h2non/filetype v1.1.1 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.1.43 + github.com/shuffle/shuffle-shared v0.1.44 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 88cfe1a4..444f3ba3 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -5811,6 +5811,7 @@ func initHandlers() { // App specific // From here down isnt checked for org specific + r.HandleFunc("/api/v1/apps/{appId}/activate", shuffle.ActivateWorkflowApp).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/apps/{appId}", shuffle.UpdateWorkflowAppConfig).Methods("PATCH", "OPTIONS") r.HandleFunc("/api/v1/apps/{appId}", shuffle.DeleteWorkflowApp).Methods("DELETE", "OPTIONS") r.HandleFunc("/api/v1/apps/{appId}/config", shuffle.GetWorkflowAppConfig).Methods("GET", "OPTIONS") diff --git a/docker-compose.yml b/docker-compose.yml index 8a8ba025..b03ecd3f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,7 @@ services: depends_on: - backend backend: - #build: ./backend + build: ./backend image: ghcr.io/frikky/shuffle-backend:nightly container_name: shuffle-backend hostname: ${BACKEND_HOSTNAME} diff --git a/frontend/src/components/ConfigureWorkflow.jsx b/frontend/src/components/ConfigureWorkflow.jsx index 460ca8cf..b66ed310 100644 --- a/frontend/src/components/ConfigureWorkflow.jsx +++ b/frontend/src/components/ConfigureWorkflow.jsx @@ -456,6 +456,44 @@ const ConfigureWorkflow = (props) => { ); }; + const activateApp = (app_id, app_name, app_version) => { + fetch( + `${globalUrl}/api/v1/apps/${app_id}/activate?app_name=${app_name}&app_version=${app_version}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + } + ) + .then((response) => { + if (response.status !== 200) { + //window.location.pathname = "/search" + //alert.error("Failed to find this app. Is it public?") + } + + return response.json(); + }) + .then((responseJson) => { + if (responseJson.success === false) { + if (responseJson.reason !== undefined) { + alert.error("Failed to activate the app: "+responseJson.reason); + } else { + alert.error("Failed to activate the app"); + } + } else { + alert.success("App activated for your organization!"); + } + }) + .catch((error) => { + alert.error(error.toString()); + }); + }; + + + const AppSection = (props) => { const { action } = props; @@ -517,7 +555,8 @@ const ConfigureWorkflow = (props) => { color="primary" variant="outlined" onClick={() => { - activateApp(action.app_id, action.app_name, action.app_version); + console.log("ACTION: ", action) + activateApp(action.action.app_id, action.app_name, action.app_version); setItemChanged(true); }} > @@ -557,38 +596,6 @@ const ConfigureWorkflow = (props) => { ); }; - const activateApp = (app_id, app_name, app_version) => { - fetch( - `${globalUrl}/api/v1/apps/app_id/activate?app_name=${app_name}&app_version=${app_version}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - credentials: "include", - } - ) - .then((response) => { - if (response.status !== 200) { - //window.location.pathname = "/search" - //alert.error("Failed to find this app. Is it public?") - } - - return response.json(); - }) - .then((responseJson) => { - if (responseJson.success === false) { - alert.error("Failed to activate the app"); - } else { - alert.success("App activated for your organization!"); - } - }) - .catch((error) => { - alert.error(error.toString()); - }); - }; - return (
{workflow.name} diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 0ff8120d..b0cc7e74 100644 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -965,7 +965,7 @@ const ParsedAction = (props) => { } var helperText = "" - console.log("DATA: ", name, value) + //console.log("DATA: ", name, value) if (name.includes("url")) { if (value.includes("localhost") || value.includes("127.0.0.1")) { helperText = "Can't use localhost. Please change to an external IP or hostname." @@ -1545,8 +1545,7 @@ const ParsedAction = (props) => { console.log("AUTOCOMPLETE1: ", values); - var toComplete = selectedActionParameters[count].value - .trim() + var toComplete = selectedActionParameters[count].value.trim() .endsWith("$") ? values[0].autocomplete : "$" + values[0].autocomplete; diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index de3c5617..2643c0ec 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -12,6 +12,7 @@ import ReactMarkdown from "react-markdown"; import { useAlert } from "react-alert"; import { + Zoom, Popover, TextField, Drawer, @@ -1614,6 +1615,7 @@ const AngularWorkflow = (props) => { setSelectedAction({}); setSelectedApp({}); setSelectedTrigger({}); + setSelectedComment({}) //setSelectedEdge({}) // setSelectedTriggerIndex(-1) @@ -1967,6 +1969,8 @@ const AngularWorkflow = (props) => { if (parentNode !== null && parentNode !== undefined) { parentNode.remove(); } + + return } else if ( data.buttonType === "set_startnode" && data.type !== "TRIGGER" @@ -1990,6 +1994,9 @@ const AngularWorkflow = (props) => { setLastSaved(false); parentNode.data("isStartNode", true); } + + //event.target.unselect(); + return } else if (data.buttonType === "copy") { console.log("COPY!"); // 1. Find parent @@ -2088,10 +2095,12 @@ const AngularWorkflow = (props) => { data: newbranch, }); } + + //event.target.unselect(); + return } } - event.target.unselect(); return; } else if (data.isDescriptor) { console.log("Can't select descriptor"); @@ -2244,10 +2253,32 @@ const AngularWorkflow = (props) => { setSelectedActionEnvironment(env); } } else if (data.type === "TRIGGER") { - const trigger_index = workflow.triggers.findIndex( + if (workflow.triggers === null) { + workflow.triggers = [] + } + + var trigger_index = workflow.triggers.findIndex( (a) => a.id === data.id ); + console.log("Trigger: ", data, trigger_index) + if (trigger_index === -1) { + workflow.triggers.push(data) + trigger_index = workflow.triggers.length-1 + setWorkflow(workflow) + } + + console.log("Trigger2: ", data, trigger_index) + //if (data.id !== undefined && data.app_name !== undefined) { + // //newapps.push(data) + // workflow.actions.push(data) + // curaction = data + //} else { + // alert.error("Action not found. Please remake it."); + // event.target.remove(); + // return; + //} + if (data.app_name === "Shuffle Workflow") { getAvailableWorkflows(trigger_index); getSettings(); @@ -4782,6 +4813,9 @@ const AngularWorkflow = (props) => { ) ); + var delay = -75 + var runDelay = false + const ParsedAppPaper = (props) => { const app = props.app; const [hover, setHover] = React.useState(false); @@ -4977,7 +5011,25 @@ const AngularWorkflow = (props) => { return null; } - return ; + var extraMessage = "" + if (index == 2) { + extraMessage =
+ } + + delay += 75 + return ( + runDelay ? + +
+ +
+
+ : +
+ {extraMessage} + +
+ ) })}
) : apps.length > 0 ? ( @@ -6420,11 +6472,15 @@ const AngularWorkflow = (props) => { color="primary" onClick={() => { console.log("HOST: ", window.location.host); + console.log("HOST: ", window.location); const redirectUri = isCloud ? window.location.host === "localhost:3002" ? "http%3A%2F%2Flocalhost:5002%2Fapi%2Fv1%2Ftriggers%2Fgmail%2Fregister" : "https%3A%2F%2Fshuffler.io%2Fapi%2Fv1%2Ftriggers%2Fgmail%2Fregister" - : "http%3A%2F%2Flocalhost:5001%2Fapi%2Fv1%2Ftriggers%2Fgmail%2Fregister"; + : window.location.protocol === "http:" ? + `http%3A%2F%2F${window.location.host}%2Fapi%2Fv1%2Ftriggers%2Fgmail%2Fregister` + : + `https%3A%2F%2F${window.location.host}%2Fapi%2Fv1%2Ftriggers%2Fgmail%2Fregister` const client_id = "253565968129-c0a35knic7q1pdk6i6qk9gdkvr07ci49.apps.googleusercontent.com"; @@ -6510,13 +6566,15 @@ const AngularWorkflow = (props) => { }} color="primary" onClick={() => { - //const redirectUri = isCloud ? "https%3A%2F%2Fshuffler.io%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" : "http%3A%2F%2Flocalhost:5001%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" - //const redirectUri = isCloud ? "http%3A%2F%2Flocalhost:5002%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" : "http%3A%2F%2Flocalhost:5001%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" + console.log(window.location) const redirectUri = isCloud ? window.location.host === "localhost:3002" ? "http%3A%2F%2Flocalhost:5002%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" : "https%3A%2F%2Fshuffler.io%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" - : "http%3A%2F%2Flocalhost:5001%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister"; + : window.location.protocol === "http:" ? + `http%3A%2F%2F${window.location.host}%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister` + : + `https%3A%2F%2F${window.location.host}%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister` //const client_id = "fd55c175-aa30-4fa6-b303-09a29fb3f750" const client_id = "bb4bff85-0d0b-4f5d-8a69-3cee8029b11a"; @@ -9806,7 +9864,8 @@ const AngularWorkflow = (props) => { "action": { "label": "Execution Argument", "name": "Execution Argument", - "large_image": "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==", + "large_image": theme.palette.defaultImage, + "image": theme.palette.defaultImage, }, "result": validate.valid ? JSON.stringify(validate.result) : validate.result, "status": "SUCCESS" @@ -9823,10 +9882,6 @@ const AngularWorkflow = (props) => { - {/* - - */} - { base = JSON.stringify(base) } + if (base_node_name === "execution_argument") { + base_node_name = "exec" + } + console.log("COPY: ", copy); var newitem = JSON.parse(base); to_be_copied = "$" + base_node_name.toLowerCase().replaceAll(" ", "_"); @@ -10156,6 +10215,7 @@ const AngularWorkflow = (props) => { ) } + var executionDelay = -75 const executionModal = ( { {workflowExecutions.length > 0 ? (
{workflowExecutions.map((data, index) => { + executionDelay += 75 + const statusColor = data.status === "FINISHED" ? green @@ -10244,106 +10306,110 @@ const AngularWorkflow = (props) => { } return ( - - {}} - onMouseOut={() => {}} - onClick={() => { - if ( - (data.result === undefined || - data.result === null || - data.result.length === 0) && - data.status !== "FINISHED" && - data.status !== "ABORTED" - ) { - start(); - setExecutionRunning(true); - setExecutionRequestStarted(false); - } + +
+ + {}} + onMouseOut={() => {}} + onClick={() => { + if ( + (data.result === undefined || + data.result === null || + data.result.length === 0) && + data.status !== "FINISHED" && + data.status !== "ABORTED" + ) { + start(); + setExecutionRunning(true); + setExecutionRequestStarted(false); + } - const cur_execution = { - execution_id: data.execution_id, - authorization: data.authorization, - }; - setExecutionRequest(cur_execution); - setExecutionModalView(1); - setExecutionData(data); - handleUpdateResults(data, cur_execution); - }} - > -
-
-
- {getExecutionSourceImage(data)} -
-
- {timestamp} -
- {data.workflow.actions !== null ? ( - -
- {resultsLength}/{calculatedResult} -
-
- ) : null} -
- - {lastExecution === data.execution_id ? ( - - ) : ( - - )} - - - + const cur_execution = { + execution_id: data.execution_id, + authorization: data.authorization, + }; + setExecutionRequest(cur_execution); + setExecutionModalView(1); + setExecutionData(data); + handleUpdateResults(data, cur_execution); + }} + > +
+
+
+ {getExecutionSourceImage(data)} +
+
+ {timestamp} +
+ {data.workflow.actions !== null ? ( + +
+ {resultsLength}/{calculatedResult} +
+
+ ) : null} +
+ + {lastExecution === data.execution_id ? ( + + ) : ( + + )} + + + +
+ ); })}
@@ -10833,10 +10899,6 @@ const AngularWorkflow = (props) => {
{validate.valid ? ( - {/* - - */} - { {curapp === null ? null : ( {selectedResult.app_name} { const newView = (
-
- {leftView} - {workflow.id === undefined || - workflow.id === null || - apps.length === 0 ? ( -
- - - Loading Workflow - -
- ) : ( - { - // FIXME: There's something specific loading when - // you do the first hover of a node. Why is this different? - //console.log("CY: ", incy) - setCy(incy); - }} - /> - )} -
- {executionModal} - - - +
+ {leftView} + {workflow.id === undefined || + workflow.id === null || + apps.length === 0 ? ( +
+ + + Loading Workflow + +
+ ) : ( + + { + // FIXME: There's something specific loading when + // you do the first hover of a node. Why is this different? + //console.log("CY: ", incy) + setCy(incy); + }} + /> + + )} +
+ {executionModal} + + +
); diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index de86d8c9..1bd9abf1 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -26,6 +26,7 @@ import { DialogActions, DialogContent, } from "@material-ui/core"; + import { GridOn as GridOnIcon, List as ListIcon, @@ -425,7 +426,6 @@ const Workflows = (props) => { const [workflows, setWorkflows] = React.useState([]); const [filteredWorkflows, setFilteredWorkflows] = React.useState([]); const [selectedWorkflow, setSelectedWorkflow] = React.useState({}); - const [firstrequest, setFirstrequest] = React.useState(true); const [workflowDone, setWorkflowDone] = React.useState(false); const [selectedWorkflowId, setSelectedWorkflowId] = React.useState(""); @@ -854,16 +854,16 @@ const Workflows = (props) => { // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => { - if (workflows.length <= 0 && firstrequest) { + if (workflows.length <= 0) { const tmpView = localStorage.getItem("view"); if (tmpView !== undefined && tmpView !== null) { setView(tmpView); } - setFirstrequest(false); + //setFirstrequest(false); getAvailableWorkflows(); } - }); + }, []) const viewStyle = { color: "#ffffff", @@ -1459,7 +1459,7 @@ const Workflows = (props) => { } return ( - +
{ }) : null} - {data.actions !== undefined && data.actions !== null ? ( - - - - - - {workflowMenuButtons} - - +
+ + + + {workflowMenuButtons} +
) : null} - - - ); - }; + + +
+ ) + } // Can create and set workflows const setNewWorkflow = ( @@ -2140,7 +2131,8 @@ const Workflows = (props) => { }; return obj; - }); + }) + workflowData = ( { ); } + var workflowDelay = -150 + var appDelay = -75 return (
@@ -2587,7 +2581,10 @@ const Workflows = (props) => { data.large_image = theme.palette.defaultImage; } + appDelay += 75 + return ( + { + ); })}
) : null} {view === "grid" ? ( - + + + {filteredWorkflows.map((data, index) => { - return ; + workflowDelay += 75 + + return ( + + + + + + ) })} ) : (