diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index 5df2d869..a4e68653 100644 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -1606,7 +1606,7 @@ class AppBase: appendresult += char actionname_lower = "exec" - elif actionname_lower.startswith("shuffle_cache "): + elif actionname_lower.startswith("shuffle_cache ") or actionname_lower.startswith("shuffle_db "): actionname_lower = "shuffle_cache" actionname_lower = actionname_lower.replace(" ", "_", -1) diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index ddbb3ce7..282af25c 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -412,7 +412,7 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) { } //log.Printf("Actionresult unmarshal: %s", string(body)) - log.Printf("[DEBUG] Got workflow result from %s of length %d. \n\nBody: %s\n\n", request.RemoteAddr, len(body), string(body)) + log.Printf("[DEBUG] Got workflow result from %s of length %d.", request.RemoteAddr, len(body)) err = shuffle.ValidateNewWorkerExecution(body) if err == nil { resp.WriteHeader(200) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index ab5ba534..3fdfd8a2 100644 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -1000,6 +1000,7 @@ const ParsedAction = (props) => { color="secondary" style={{justifyContent: "flex-start", textAlign: "left", textTransform: "none", width: "100%",}} fullWidth + disabled={selectedAction.description === undefined || selectedAction.description === null || selectedAction.description.length === 0} onClick={() => { setHiddenDescription(!hiddenDescription) }} @@ -2654,7 +2655,7 @@ const ParsedAction = (props) => { option === undefined || option === null || option.name === undefined || - option.name === undefined + option.name === null ) { return null; } diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 315849b2..ed2a4781 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useLayoutEffect } from "react"; import { useInterval } from "react-powerhooks"; -import { useTheme } from "@material-ui/core/styles"; +import { makeStyles, useTheme } from "@material-ui/core/styles"; import { v4 as uuidv4 } from "uuid"; import { Link } from "react-router-dom"; @@ -80,6 +80,7 @@ import { AddComment as AddCommentIcon, } from "@material-ui/icons"; +import Autocomplete from "@material-ui/lab/Autocomplete"; import * as cytoscape from "cytoscape"; import * as edgehandles from "cytoscape-edgehandles"; import * as clipboard from "cytoscape-clipboard"; @@ -178,6 +179,32 @@ function removeParam(key, sourceURL) { return rtn; } +const useStyles = makeStyles({ + notchedOutline: { + borderColor: "#f85a3e !important", + }, + root: { + "& .MuiAutocomplete-listbox": { + border: "2px solid #f85a3e", + color: "white", + fontSize: 18, + "& li:nth-child(even)": { + backgroundColor: "#CCC", + }, + "& li:nth-child(odd)": { + backgroundColor: "#FFF", + }, + }, + }, + inputRoot: { + color: "white", + // This matches the specificity of the default styles at https://github.com/mui-org/material-ui/blob/v4.11.3/packages/material-ui-lab/src/Autocomplete/Autocomplete.js#L90 + "&:hover .MuiOutlinedInput-notchedOutline": { + borderColor: "#f86a3e", + }, + }, +}); + const splitter = "|~|"; const svgSize = 24; //const referenceUrl = "https://shuffler.io/functions/webhooks/" @@ -320,6 +347,7 @@ const AngularWorkflow = (props) => { const appBarSize = isCloud ? 75 : 60; const triggerEnvironments = isCloud ? ["cloud"] : ["onprem", "cloud"]; const unloadText = "Are you sure you want to leave without saving (CTRL+S)?"; + const classes = useStyles(); const [elements, setElements] = useState([]); @@ -5617,7 +5645,7 @@ const AngularWorkflow = (props) => { actionlist.push({ type: "Shuffle DB", name: "Shuffle DB", - value: "shuffle_cache", + value: "$shuffle_cache", highlight: "shuffle_cache", autocomplete: "shuffle_cache", example: "tmp", @@ -7119,6 +7147,14 @@ const AngularWorkflow = (props) => { autocomplete: "exec", example: "hello", }) + actionlist.push({ + type: "Shuffle Database", + name: "Shuffle Database", + value: "$shuffle_cache", + highlight: "shuffle_db", + autocomplete: "shuffle_cache", + example: "hello", + }) if ( workflow.workflow_variables !== null && workflow.workflow_variables !== undefined && @@ -7537,6 +7573,9 @@ const AngularWorkflow = (props) => { value: "false", }; + /* + // API-key has been replaced by auth key for the execution. + // Parents can now automatically execute children without auth from a user, as long as the subflow in question is owned by the same org and the subflow is actually referencing it during checkin. console.log("SETTINGS: ", userSettings); if ( userSettings !== undefined && @@ -7550,8 +7589,120 @@ const AngularWorkflow = (props) => { value: userSettings.apikey, }; } + */ } + const handleSubflowStartnodeSelection = (e) => { + setSubworkflowStartnode(e.target.value); + + const branchId = uuidv4(); + const newbranch = { + source_id: workflow.triggers[selectedTriggerIndex].id, + destination_id: e.target.value.id, + source: workflow.triggers[selectedTriggerIndex].id, + target: e.target.value.id, + has_errors: false, + id: branchId, + _id: branchId, + label: "Subflow", + decorator: true, + }; + + if (workflow.visual_branches !== undefined) { + if (workflow.visual_branches === null) { + workflow.visual_branches = [newbranch]; + } else if (workflow.visual_branches.length === 0) { + workflow.visual_branches.push(newbranch); + } else { + const foundIndex = workflow.visual_branches.findIndex( + (branch) => branch.source_id === newbranch.source_id + ); + if (foundIndex !== -1) { + const currentEdge = cy.getElementById( + workflow.visual_branches[foundIndex].id + ); + if ( + currentEdge !== undefined && + currentEdge !== null + ) { + currentEdge.remove(); + } + } + + workflow.visual_branches.splice(foundIndex, 1); + workflow.visual_branches.push(newbranch); + } + } + + if (workflow.id === subworkflow.id) { + const cybranch = { + group: "edges", + source: newbranch.source_id, + target: newbranch.destination_id, + id: branchId, + data: newbranch, + }; + + cy.add(cybranch); + } + + console.log("Value to be set: ", e.target.value); + try { + workflow.triggers[ + selectedTriggerIndex + ].parameters[3].value = e.target.value.id; + } catch { + workflow.triggers[selectedTriggerIndex].parameters[3] = + { + name: "startnode", + value: e.target.value.id, + }; + } + + setWorkflow(workflow); + } + + const handleWorkflowSelectionUpdate = (e) => { + setUpdate(Math.random()); + workflow.triggers[ + selectedTriggerIndex + ].parameters[0].value = e.target.value.id; + setSubworkflow(e.target.value); + + // Sets the startnode + if (e.target.value.id !== workflow.id) { + console.log("WORKFLOW: ", e.target.value); + + const startnode = e.target.value.actions.find( + (action) => action.id === e.target.value.start + ); + if (startnode !== undefined && startnode !== null) { + console.log("STARTNODE: ", startnode); + setSubworkflowStartnode(startnode); + + try { + workflow.triggers[ + selectedTriggerIndex + ].parameters[3].value = startnode.id; + } catch { + workflow.triggers[ + selectedTriggerIndex + ].parameters[3] = { + name: "startnode", + value: startnode.id, + }; + } + + setWorkflow(workflow); + } + console.log("STARTNODE: ", startnode); + } else { + console.log("WORKFLOW: ", workflow); + } + + setWorkflow(workflow); + } + return (
{ display: "flex", }} > -
Select a workflow to execute
- {workflows === undefined || - workflows === null || - workflows.length === 0 ? null : ( - + //key={index} + return ( + + {data.name} + + ) + }} + renderInput={(params) => { + return ( + + ); + }} + /> )} {workflow.triggers[selectedTriggerIndex].parameters[0].value .length === 0 ? null : workflow.triggers[selectedTriggerIndex] @@ -7773,113 +7910,63 @@ const AngularWorkflow = (props) => { display: "flex", }} > -
Select the Startnode
- + }} + renderInput={(params) => { + return ( + + ); + }} + /> )}
{ display: "flex", }} > -
Execution Argument
{ data={workflow.triggers[selectedTriggerIndex]} /> ) : null} + {/*
{ display: "flex", }} > -
API-key
{ setWorkflow(workflow); }} /> + */}
diff --git a/functions/onprem/orborus/docker-compose.yml b/functions/onprem/orborus/docker-compose.yml new file mode 100644 index 00000000..ef6132e2 --- /dev/null +++ b/functions/onprem/orborus/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3' +services: + orborus: + image: ghcr.io/frikky/shuffle-orborus:nightly + container_name: shuffle-orborus + hostname: shuffle-orborus + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - SHUFFLE_APP_SDK_VERSION=nightly + - SHUFFLE_WORKER_VERSION=nightly + - ORG_ID=Shuffle + - ENVIRONMENT_NAME=Shuffle + - BASE_URL=http://192.168.86.39:5001 + - DOCKER_API_VERSION=1.40 + - SHUFFLE_SCALE_REPLICAS=5 + - SHUFFLE_SWARM_CONFIG=run + restart: unless-stopped + networks: + - shuffle-executions +networks: + shuffle-executions: + driver: overlay + external: true + diff --git a/functions/onprem/worker/worker.go b/functions/onprem/worker/worker.go index a242b0b6..a2965adf 100644 --- a/functions/onprem/worker/worker.go +++ b/functions/onprem/worker/worker.go @@ -557,6 +557,11 @@ func handleSubworkflowExecution(client *http.Client, workflowExecution shuffle.W } } + if apikey == "" { + log.Printf("[DEBUG][%s] Replacing apikey with parent auth", workflowExecution.ExecutionId) + apikey = workflowExecution.Authorization + } + //handleSubworkflowExecution(workflowExecution, action) status := "SUCCESS" baseResult := `{"success": true}`