From fe6be7107634993d7d91b28baf091f76c5561dd8 Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 6 Feb 2023 22:53:04 +0100 Subject: [PATCH] Re-fixed looping issues in #1012 and bugs from the issue that the initial fix caused --- frontend/src/components/AppFramework.jsx | 12 +- frontend/src/components/ConfigureWorkflow.jsx | 20 +- frontend/src/components/ParsedAction.jsx | 75 +- frontend/src/components/WelcomeForm2.jsx | 2 +- frontend/src/views/Admin.jsx | 2 +- frontend/src/views/AngularWorkflow.jsx | 1011 +++++++++-------- frontend/src/views/AppCreator.jsx | 345 +++--- frontend/src/views/Workflows.jsx | 10 +- 8 files changed, 810 insertions(+), 667 deletions(-) diff --git a/frontend/src/components/AppFramework.jsx b/frontend/src/components/AppFramework.jsx index 39547697..aaabc2de 100644 --- a/frontend/src/components/AppFramework.jsx +++ b/frontend/src/components/AppFramework.jsx @@ -564,6 +564,7 @@ const AppFramework = (props) => { const alert = useAlert() + const handleLoadNextSuggestion = (frameworkData) => { console.log("Should check for next apps to load from App suggestion model") //fetch(globalUrl + "/api/v1/workflows/usecases", { @@ -623,7 +624,6 @@ const AppFramework = (props) => { suggestions.push(value.slice(0,1)) } - console.log("SUGG: ", suggestions) setInjectedApps(suggestions) }) .catch((error) => { @@ -909,6 +909,10 @@ const AppFramework = (props) => { }) } + useEffect(() => { + handleLoadNextSuggestion(frameworkData) + }, []) + useEffect(() => { console.log("New selected app: ", newSelectedApp, discoveryData) if (newSelectedApp.objectID === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID.length === 0) { @@ -1931,10 +1935,11 @@ const AppFramework = (props) => { return (
- {apps.map((app) => { + {apps.map((app, appIndex) => { return ( } + key={app.id} label={""} variant="contained" style={{}} @@ -2089,6 +2094,9 @@ const AppFramework = (props) => { setSelectionOpen(true) setDefaultSearch("") + + //handleLoadNextSuggestion(frameworkData) + setInjectedApps([]) const foundelement = cy.getElementById(discoveryData.id) if (foundelement !== undefined && foundelement !== null) { diff --git a/frontend/src/components/ConfigureWorkflow.jsx b/frontend/src/components/ConfigureWorkflow.jsx index dc35d902..b032befe 100644 --- a/frontend/src/components/ConfigureWorkflow.jsx +++ b/frontend/src/components/ConfigureWorkflow.jsx @@ -129,7 +129,7 @@ const ConfigureWorkflow = (props) => { setFirstLoad(workflow.id) const newactions = []; - for (let [key, keyval] in workflow.actions.entries()) { + for (let [key, keyval] in Object.entries(workflow.actions)) { const action = workflow.actions[key]; var newaction = { large_image: action.large_image, @@ -175,7 +175,7 @@ const ConfigureWorkflow = (props) => { ) { // Check if configuration is filled or not var filled = true; - for (let [key,keyval] in action.parameters.entries()) { + for (let [key,keyval] in Object.entries(action.parameters)) { if (action.parameters[key].configuration) { //console.log("Found config: ", action.parameters[key]) if ( @@ -216,7 +216,7 @@ const ConfigureWorkflow = (props) => { if (newaction.must_authenticate) { var authenticationOptions = []; - for (let [key,keyval] in appAuthentication.entries()) { + for (let [key,keyval] in Object.entries(appAuthentication)) { const auth = appAuthentication[key]; if (auth.app.name === app.name && auth.active) { //console.log("Found auth: ", auth) @@ -265,7 +265,7 @@ const ConfigureWorkflow = (props) => { } if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length !== 0) { - for (let [key,keyval] in workflow.workflow_variables.entries()) { + for (let [key,keyval] in Object.entries(workflow.workflow_variables)) { const variable = workflow.workflow_variables[key]; if ( variable.value === undefined || @@ -280,7 +280,7 @@ const ConfigureWorkflow = (props) => { } if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length !== 0) { - for (let [key,keyval] in workflow.triggers.entries()) { + for (let [key,keyval] in Object.entries(workflow.triggers)) { var trigger = workflow.triggers[key]; trigger.index = key; @@ -302,7 +302,7 @@ const ConfigureWorkflow = (props) => { } ] - for (let [subkey,subkeyval] in tmpsteps.entries()) { + for (let [subkey,subkeyval] in Object.entries(tmpsteps)) { newactions[foundindex].steps.push(tmpsteps[subkey]) } @@ -344,13 +344,13 @@ const ConfigureWorkflow = (props) => { setRequiredActions(newactions); } - if (appAuthentication.length !== previousAuth.length) { + if (appAuthentication !== undefined && previousAuth !== undefined && appAuthentication.length !== previousAuth.length) { var newactions = [] - for (let [actionkey, actionkeyval] in requiredActions.entries()) { + for (let [actionkey, actionkeyval] in Object.entries(requiredActions)) { var newaction = requiredActions[actionkey]; const app = newaction.app; - for (let [key,keyval] in appAuthentication.entries()) { + for (let [key,keyval] in Object.entries(appAuthentication)) { const auth = appAuthentication[key]; // Does this account for all the different ones of the same? @@ -694,7 +694,7 @@ const ConfigureWorkflow = (props) => { if (workflow.actions !== null) { //console.log(workflow.actions) alert.info("Setting action to version "+action.update_version) - for (let [key,keyval] in workflow.actions.entries()) { + for (let [key,keyval] in Object.entries(workflow.actions)) { if (workflow.actions[key].app_name === action.app_name && workflow.actions[key].app_version === action.app_version) { workflow.actions[key].app_version = action.update_version diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index ede8d900..982375da 100644 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -277,7 +277,7 @@ const ParsedAction = (props) => { console.log("FOUNDACTION: ", foundAction); if (foundAction !== null && foundAction !== undefined) { var foundparams = []; - for (let [paramkey,paramkeyval] in foundAction.parameters.entries()) { + for (let [paramkey,paramkeyval] in Object.entries(foundAction.parameters)) { const param = foundAction.parameters[paramkey]; const foundParam = selectedAction.parameters.find( @@ -401,7 +401,7 @@ const ParsedAction = (props) => { if (actionlist.length === 0) { // FIXME: Have previous execution values in here if (workflowExecutions.length > 0) { - for (let [key,keyval] in workflowExecutions.entries()) { + for (let [key,keyval] in Object.entries(workflowExecutions)) { if ( workflowExecutions[key].execution_argument === undefined || workflowExecutions[key].execution_argument === null || @@ -451,7 +451,7 @@ const ParsedAction = (props) => { workflow.workflow_variables !== undefined && workflow.workflow_variables.length > 0 ) { - for (let [key,keyval] in workflow.workflow_variables.entries()) { + for (let [key,keyval] in Object.entries(workflow.workflow_variables)) { const item = workflow.workflow_variables[key]; actionlist.push({ type: "workflow_variable", @@ -470,7 +470,7 @@ const ParsedAction = (props) => { workflow.execution_variables !== undefined && workflow.execution_variables.length > 0 ) { - for (let [key,keyval] in workflow.execution_variables.entries()) { + for (let [key,keyval] in Object.entries(workflow.execution_variables)) { const item = workflow.execution_variables[key]; actionlist.push({ type: "execution_variable", @@ -488,7 +488,7 @@ const ParsedAction = (props) => { var parents = getParents(selectedAction); if (parents.length > 1) { - for (let [key,keyval] in parents.entries()) { + for (let [key,keyval] in Object.entries(parents)) { const item = parents[key]; if (item.label === "Execution Argument") { continue; @@ -500,7 +500,7 @@ const ParsedAction = (props) => { if (workflowExecutions.length > 0) { // Look for the ID const found = false; - for (let [key,keyval] in workflowExecutions.entries()) { + for (let [key,keyval] in Object.entries(workflowExecutions)) { if ( workflowExecutions[key].results === undefined || workflowExecutions[key].results === null @@ -566,13 +566,12 @@ const ParsedAction = (props) => { if (found !== null && found !== undefined) { var new_occurences = [] - for (let [key,keyval] in found.entries()) { + for (let [key,keyval] in Object.entries(found)) { if (found[key][0] !== "\\") { new_occurences.push(found[key]) } } - console.log("New found: ", new_occurences) found = new_occurences.valueOf() } @@ -627,9 +626,8 @@ const ParsedAction = (props) => { //console.log("Action change: ", selectedAction, data) if (data.name.startsWith("${") && data.name.endsWith("}")) { // PARAM FIX - Gonna use the ID field, even though it's a hack - const paramcheck = selectedAction.parameters.find( - (param) => param.name === "body" - ); + const paramcheck = selectedAction.parameters.find((param) => param.name === "body"); + if (paramcheck !== undefined) { // Escapes all double quotes var toReplace = event.target.value.trim() @@ -730,7 +728,7 @@ const ParsedAction = (props) => { var curstring = ""; var record = false; - for (let [key,keyval] in selectedActionParameters[count].value.entries()) { + for (let [key,keyval] in Object.entries(selectedActionParameters[count].value)) { const item = selectedActionParameters[count].value[key]; if (record) { curstring += item; @@ -911,7 +909,7 @@ const ParsedAction = (props) => { var curstring = "" var record = false - for (let [key,keyval] in selectedActionParameters[count].value.entries()) { + for (let [key,keyval] in Object.entries(selectedActionParameters[count].value)) { const item = selectedActionParameters[count].value[key] if (record) { curstring += item @@ -1187,7 +1185,7 @@ const ParsedAction = (props) => { renderInput={(params) => { if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) { const prefixes = ["Post", "Put", "Patch"] - for (let [key,keyval] in prefixes.entries()) { + for (let [key,keyval] in Object.entries(prefixes)) { if (params.inputProps.value.startsWith(prefixes[key])) { params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1) if (params.inputProps.value.length > 1) { @@ -1346,9 +1344,8 @@ const ParsedAction = (props) => { } if (data.name.startsWith("${") && data.name.endsWith("}")) { - const paramcheck = selectedAction.parameters.find( - (param) => param.name === "body" - ); + const paramcheck = selectedAction.parameters.find((param) => param.name === "body"); + if (paramcheck !== undefined && paramcheck !== null) { if ( @@ -1426,8 +1423,8 @@ const ParsedAction = (props) => { setHideBody(!hideBody); - for (let [key,keyval] in selectedActionParameters.entries()) { - var currentItem = selectedActionParameters[key]; + for (let paramkey in Object.entries(selectedActionParameters)) { + var currentItem = selectedActionParameters[paramkey]; if (currentItem.name === "ssl_verify") { } @@ -1472,10 +1469,11 @@ const ParsedAction = (props) => { openApiHelperText = "OpenAPI spec: fill the following fields."; //console.log("SHOULD ADD TO selectedActionParameters!: ", found, selectedActionParameters) var changed = false; - for (let [specKey,specKeyVal] in found.entries()) { + for (let specKey in found) { const tmpitem = found[specKey]; var skip = false; - for (let [innerkey,innerkeyval] in selectedActionParameters.entries()) { + + for (let innerkey in selectedActionParameters) { if (selectedActionParameters[innerkey].name === tmpitem) { skip = true; break; @@ -1707,7 +1705,7 @@ const ParsedAction = (props) => { var foundnewline = false var allValues = [] - for (let [key,keyval] in splitdata.entries()) { + for (let [key,keyval] in Object.entries(splitdata)) { const line = splitdata[key] if (line === "") { foundnewline = true @@ -1777,7 +1775,7 @@ const ParsedAction = (props) => { const tmpsplit = selectedActionParameters[count].value.split("\n") var valsplit = [] var add_empty = false - for (let [key,keyval] in tmpsplit.entries()) { + for (let [key,keyval] in Object.entries(tmpsplit)) { if (tmpsplit[key] === "") { add_empty = true continue @@ -1792,7 +1790,7 @@ const ParsedAction = (props) => { console.log("Split: ", valsplit) var newarr = [] - for (let [key,keyval] in valsplit.entries()) { + for (let [key,keyval] in Object.entries(valsplit)) { var line = valsplit[key] if (key == index) { @@ -1832,7 +1830,7 @@ const ParsedAction = (props) => { var tmpsplit = selectedActionParameters[count].value.split("\n") var valsplit = [] var add_empty = false - for (let [key,keyval] in tmpsplit.entries()) { + for (let [key,keyval] in Object.entries(tmpsplit)) { if (tmpsplit[key] === "") { add_empty = true continue @@ -1847,7 +1845,7 @@ const ParsedAction = (props) => { console.log("Split: ", valsplit) var newarr = [] - for (let [key,keyval] in valsplit.entries()) { + for (let [key,keyval] in Object.entries(valsplit)) { var line = valsplit[key] if (key == index) { @@ -2094,7 +2092,7 @@ const ParsedAction = (props) => { : "$" + values[0].autocomplete; toComplete = toComplete.toLowerCase().replaceAll(" ", "_"); - for (let [key,keyval] in values.entries()) { + for (let [key,keyval] in Object.entries(values)) { if (key == 0 || values[key].autocomplete.length === 0) { continue; } @@ -2205,7 +2203,7 @@ const ParsedAction = (props) => { workflow.triggers !== null && workflow.triggers.length > 0 ) { - for (let [key,keyval] in workflow.triggers.entries()) { + for (let [key,keyval] in Object.entries(workflow.triggers)) { const item = workflow.triggers[key]; if (cy !== undefined) { @@ -2727,7 +2725,7 @@ const ParsedAction = (props) => { if (workflowExecutions.length > 0) { // Look for the ID const found = false; - for (let [key,keyval] in workflowExecutions.entries()) { + for (let [key,keyval] in Object.entries(workflowExecutions)) { if ( workflowExecutions[key].results === undefined || workflowExecutions[key].results === null @@ -2735,6 +2733,11 @@ const ParsedAction = (props) => { continue; } + // Enforces it to show at least one + //if (workflowExecutions[key].execution_argument.includes("too large") && key !== workflowExecutions.length - 1) { + // continue + //} + var foundResult = workflowExecutions[key].results.find( (result) => result.action.id === selectedAction.id ) @@ -2971,8 +2974,8 @@ const ParsedAction = (props) => { // // Should make it a function lol if (workflow.branches !== undefined && workflow.branches !== null) { - for (let [key,keyval] in workflow.branches.entries()) { - for (let [subkey,subkeyval] in workflow.branches[key].conditions.entries()) { + for (let [key,keyval] in Object.entries(workflow.branches)) { + for (let [subkey,subkeyval] in Object.entries(workflow.branches[key].conditions)) { const condition = workflow.branches[key].conditions[subkey] const sourceparam = condition.source const destinationparam = condition.destination @@ -3080,12 +3083,12 @@ const ParsedAction = (props) => { } } - for (let [key,keyval] in workflow.actions.entries()) { + for (let [key,keyval] in Object.entries(workflow.actions)) { if (workflow.actions[key].id === selectedAction.id) { continue } - for (let [subkey, subkeyval] in workflow.actions[key].parameters.entries()) { + for (let [subkey, subkeyval] in Object.entries(workflow.actions[key].parameters)) { const param = workflow.actions[key].parameters[subkey]; if (!param.value.includes("$")) { continue @@ -3251,7 +3254,7 @@ const ParsedAction = (props) => { selectedAction.selectedAuthentication = {}; selectedAction.authentication_id = ""; - for (let [key,keyval] in selectedAction.parameters.entries()) { + for (let [key,keyval] in Object.entries(selectedAction.parameters)) { //console.log(selectedAction.parameters[key]) if (selectedAction.parameters[key].configuration) { selectedAction.parameters[key].value = ""; @@ -3568,7 +3571,7 @@ const ParsedAction = (props) => { if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) { var extraUrl = "" const descSplit = data.description.split("\n") - for (let [line,lineval] in descSplit.entries()) { + for (let [line,lineval] in Object.entries(descSplit)) { if (descSplit[line].includes("http") && descSplit[line].includes("://")) { const urlsplit = descSplit[line].split("/") try { @@ -3629,7 +3632,7 @@ const ParsedAction = (props) => { renderInput={(params) => { if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) { const prefixes = ["Post", "Put", "Patch"] - for (let [key,keyval] in prefixes.entries()) { + for (let [key,keyval] in Object.entries(prefixes)) { if (params.inputProps.value.startsWith(prefixes[key])) { params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1) if (params.inputProps.value.length > 1) { diff --git a/frontend/src/components/WelcomeForm2.jsx b/frontend/src/components/WelcomeForm2.jsx index 5c7a2163..79a89f06 100644 --- a/frontend/src/components/WelcomeForm2.jsx +++ b/frontend/src/components/WelcomeForm2.jsx @@ -594,7 +594,7 @@ const WelcomeForm = (props) => {
- Use the buttons below to find your apps, and we will help you connect them later. + Apps for each category are shown based on your activity and can be changed by clicking their icon. We will help you connect them later. {/*The app framework helps us access and authenticate the most important APIs for you. */} diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index b6b6fb6e..59cd69d8 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -5162,7 +5162,7 @@ const Admin = (props) => { index={6} value={6} label= - Organizations + Tenants /> {/*window.location.protocol == "http:" && window.location.port === "3000" ? Hybrid/> : null*/} diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 3e4097ab..a821a0f3 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -305,7 +305,7 @@ const AngularWorkflow = (defaultprops) => { const [historyIndex, setHistoryIndex] = React.useState(history.length); const [variableInfo, setVariableInfo] = React.useState({}) - const [appAuthentication, setAppAuthentication] = React.useState([]); + const [appAuthentication, setAppAuthentication] = React.useState(undefined); const [variablesModalOpen, setVariablesModalOpen] = React.useState(false); const [executionVariablesModalOpen, setExecutionVariablesModalOpen] = React.useState(false); @@ -316,7 +316,6 @@ const AngularWorkflow = (defaultprops) => { const [workflowDone, setWorkflowDone] = React.useState(false); - const [authLoaded, setAuthLoaded] = React.useState(false); const [localFirstrequest, setLocalFirstrequest] = React.useState(true); const [requiresAuthentication, setRequiresAuthentication] = React.useState(false); @@ -410,14 +409,13 @@ const AngularWorkflow = (defaultprops) => { const [bodyWidth, bodyHeight] = useWindowSize() //console.log("Mobile: ", isMobile, bodyWidth, bodyHeight) const cytoscapeWidth = isMobile ? bodyWidth - leftBarSize : bodyWidth - leftBarSize - 25 - - + const [elements, setElements] = useState([]); // No point going as fast, as the nodes aren't realtime anymore, but bulk updated. // Set it from 2500 to 6000 to reduce overall load const { start, stop } = useInterval({ duration: 3000, - startImmediate: false, + startImmediate: true, callback: () => { fetchUpdates(); }, @@ -496,8 +494,8 @@ const AngularWorkflow = (defaultprops) => { var baseSubflow = {} const trigger = workflow.triggers[trigger_index]; if (trigger.parameters.length >= 3) { - for (let [key,keyval] in trigger.parameters.entries()) { - const param = trigger.parameters[key]; + for (let paramkey in trigger.parameters) { + const param = trigger.parameters[paramkey]; if (param.name === "workflow") { if (param.value === workflow.id) { @@ -727,21 +725,25 @@ const AngularWorkflow = (defaultprops) => { var tmpView = new URLSearchParams(cursearch).get("execution_id"); if ( - execution_id !== undefined && - execution_id !== null && - execution_id.length > 0 && - (tmpView === undefined || tmpView === null || tmpView.length === 0) + execution_id !== undefined && execution_id !== null && + execution_id.length > 0 && (tmpView === undefined || tmpView === null || tmpView.length === 0) ) { tmpView = execution_id; } if (tmpView !== undefined && tmpView !== null && tmpView.length > 0) { - const execution = responseJson.find( - (data) => data.execution_id === tmpView - ); + const execution = responseJson.find((data) => data.execution_id === tmpView); if (execution !== null && execution !== undefined) { - setExecutionData(execution); + + if (execution.execution_argument.includes("too large")) { + setExecutionData({}); + setExecutionRunning(true); + setExecutionRequestStarted(false); + } else { + setExecutionData(execution); + } + setExecutionModalView(1); start(); @@ -841,6 +843,141 @@ const AngularWorkflow = (defaultprops) => { }); }; + const handleColoring = (actionId, status, label) => { + if (cy === undefined) { + return + } + + var currentnode = cy.getElementById(actionId); + if (currentnode.length === 0) { + return + //continue; + } + + currentnode = currentnode[0]; + const outgoingEdges = currentnode.outgoers("edge"); + const incomingEdges = currentnode.incomers("edge"); + + switch (status) { + case "EXECUTING": + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("success-highlight"); + currentnode.removeClass("failure-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.removeClass("awaiting-data-highlight"); + incomingEdges.addClass("success-highlight"); + currentnode.addClass("executing-highlight"); + break; + case "SKIPPED": + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("success-highlight"); + currentnode.removeClass("failure-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.removeClass("awaiting-data-highlight"); + currentnode.removeClass("executing-highlight"); + currentnode.addClass("skipped-highlight"); + break; + case "WAITING": + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("success-highlight"); + currentnode.removeClass("failure-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.removeClass("awaiting-data-highlight"); + currentnode.addClass("executing-highlight"); + + if (!visited.includes(label)) { + if (executionRunning) { + visited.push(label); + setVisited(visited); + } + } + + // FIXME - add outgoing nodes to executing + //const outgoingNodes = outgoingEdges.find().data().target + if (outgoingEdges.length > 0) { + outgoingEdges.addClass("success-highlight"); + } + break; + case "SUCCESS": + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("executing-highlight"); + currentnode.removeClass("failure-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.removeClass("awaiting-data-highlight"); + currentnode.addClass("success-highlight"); + incomingEdges.addClass("success-highlight"); + outgoingEdges.addClass("success-highlight"); + + if (visited !== undefined && visited !== null && !visited.includes(label)) { + if (executionRunning) { + visited.push(label); + setVisited(visited); + } + } + + // FIXME - add outgoing nodes to executing + //const outgoingNodes = outgoingEdges.find().data().target + if (outgoingEdges.length > 0) { + for (let i = 0; i < outgoingEdges.length; i++) { + const edge = outgoingEdges[i]; + const targetnode = cy.getElementById(edge.data().target); + if ( + targetnode !== undefined && + !targetnode.classes().includes("success-highlight") && + !targetnode.classes().includes("failure-highlight") + ) { + targetnode.removeClass("not-executing-highlight"); + targetnode.removeClass("success-highlight"); + targetnode.removeClass("shuffle-hover-highlight"); + targetnode.removeClass("failure-highlight"); + targetnode.removeClass("awaiting-data-highlight"); + targetnode.addClass("executing-highlight"); + } + } + } + break; + case "FAILURE": + //When status comes as failure, allow user to start workflow execution + if (executionRunning) { + setExecutionRunning(false); + } + + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("executing-highlight"); + currentnode.removeClass("success-highlight"); + currentnode.removeClass("awaiting-data-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.addClass("failure-highlight"); + + if (!visited.includes(label)) { + //if (item.action.result !== undefined && item.action.result !== null && !item.action.result.includes("failed condition")) { + // alert.error("Error for " + item.action.label + " with result " + item.result); + //} + visited.push(label); + setVisited(visited); + } + break; + case "AWAITING_DATA": + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("executing-highlight"); + currentnode.removeClass("success-highlight"); + currentnode.removeClass("failure-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.addClass("awaiting-data-highlight"); + break; + default: + currentnode.removeClass("not-executing-highlight"); + currentnode.removeClass("executing-highlight"); + currentnode.removeClass("success-highlight"); + currentnode.removeClass("failure-highlight"); + currentnode.removeClass("shuffle-hover-highlight"); + currentnode.removeClass("awaiting-data-highlight"); + currentnode.addClass("not-executing-highlight"); + //console.log("DEFAULT -> Clearing!"); + break; + } + } + // Controls the colors and direction of execution results. // Style is in defaultCytoscapeStyle.js const handleUpdateResults = (responseJson, executionRequest) => { @@ -852,176 +989,40 @@ const AngularWorkflow = (defaultprops) => { if (JSON.stringify(responseJson) !== JSON.stringify(executionData)) { // FIXME: If another is selected, don't edit.. // Doesn't work because this is some async garbage - if ( - executionData.execution_id === undefined || - (responseJson.execution_id === executionData.execution_id && - responseJson.results !== undefined && - responseJson.results !== null) - ) { - if ( - executionData.status !== responseJson.status || - executionData.result !== responseJson.result || - executionData.results.length !== responseJson.results.length - ) { - setExecutionData(responseJson); + if (executionData.execution_id === undefined || (responseJson.execution_id === executionData.execution_id && responseJson.results !== undefined && responseJson.results !== null)) { + if (executionData.status !== responseJson.status || executionData.result !== responseJson.result || (executionData.results !== undefined && responseJson.results !== null && executionData.results.length !== responseJson.results.length)) { + console.log("Updating data!") + setExecutionData(responseJson) } else { - //console.log("NOT updating state."); + console.log("NOT updating executiondata state."); } } } if (responseJson.execution_id !== executionRequest.execution_id) { - cy.elements().removeClass( - "success-highlight failure-highlight executing-highlight" - ); + cy.elements().removeClass("success-highlight failure-highlight executing-highlight"); return; } if (responseJson.results !== null && responseJson.results.length > 0) { - for (let [key,keyval] in responseJson.results.entries()) { - var item = responseJson.results[key]; - var currentnode = cy.getElementById(item.action.id); - if (currentnode.length === 0) { - continue; - } + // First clear current nodes + if (responseJson.workflow.actions !== undefined && responseJson.workflow.actions !== null) { + // In clearing of actions + for (let actionKey in responseJson.workflow.actions) { + var item = responseJson.workflow.actions[actionKey]; - currentnode = currentnode[0]; - const outgoingEdges = currentnode.outgoers("edge"); - const incomingEdges = currentnode.incomers("edge"); + handleColoring(item.id, "", item.label) + } + } - switch (item.status) { - case "EXECUTING": - currentnode.removeClass("not-executing-highlight"); - currentnode.removeClass("success-highlight"); - currentnode.removeClass("failure-highlight"); - currentnode.removeClass("shuffle-hover-highlight"); - currentnode.removeClass("awaiting-data-highlight"); - incomingEdges.addClass("success-highlight"); - currentnode.addClass("executing-highlight"); - break; - case "SKIPPED": - currentnode.removeClass("not-executing-highlight"); - currentnode.removeClass("success-highlight"); - currentnode.removeClass("failure-highlight"); - currentnode.removeClass("shuffle-hover-highlight"); - currentnode.removeClass("awaiting-data-highlight"); - currentnode.removeClass("executing-highlight"); - currentnode.addClass("skipped-highlight"); - break; - case "WAITING": - currentnode.removeClass("not-executing-highlight"); - currentnode.removeClass("success-highlight"); - currentnode.removeClass("failure-highlight"); - currentnode.removeClass("shuffle-hover-highlight"); - currentnode.removeClass("awaiting-data-highlight"); - currentnode.addClass("executing-highlight"); + for (let resultKey in responseJson.results) { + var item = responseJson.results[resultKey]; - if (!visited.includes(item.action.label)) { - if (executionRunning) { - visited.push(item.action.label); - setVisited(visited); - } - } - - // FIXME - add outgoing nodes to executing - //const outgoingNodes = outgoingEdges.find().data().target - if (outgoingEdges.length > 0) { - outgoingEdges.addClass("success-highlight"); - } - break; - case "SUCCESS": - currentnode.removeClass("not-executing-highlight"); - currentnode.removeClass("executing-highlight"); - currentnode.removeClass("failure-highlight"); - currentnode.removeClass("shuffle-hover-highlight"); - currentnode.removeClass("awaiting-data-highlight"); - currentnode.addClass("success-highlight"); - incomingEdges.addClass("success-highlight"); - outgoingEdges.addClass("success-highlight"); - - if ( - visited !== undefined && - visited !== null && - !visited.includes(item.action.label) - ) { - if (executionRunning) { - visited.push(item.action.label); - setVisited(visited); - } - } - - // FIXME - add outgoing nodes to executing - //const outgoingNodes = outgoingEdges.find().data().target - if (outgoingEdges.length > 0) { - for (let i = 0; i < outgoingEdges.length; i++) { - const edge = outgoingEdges[i]; - const targetnode = cy.getElementById(edge.data().target); - if ( - targetnode !== undefined && - !targetnode.classes().includes("success-highlight") && - !targetnode.classes().includes("failure-highlight") - ) { - targetnode.removeClass("not-executing-highlight"); - targetnode.removeClass("success-highlight"); - targetnode.removeClass("shuffle-hover-highlight"); - targetnode.removeClass("failure-highlight"); - targetnode.removeClass("awaiting-data-highlight"); - targetnode.addClass("executing-highlight"); - } - } - } - break; - case "FAILURE": - //When status comes as failure, allow user to start workflow execution - if (executionRunning) { - setExecutionRunning(false); - } - - currentnode.removeClass("not-executing-highlight"); - currentnode.removeClass("executing-highlight"); - currentnode.removeClass("success-highlight"); - currentnode.removeClass("awaiting-data-highlight"); - currentnode.removeClass("shuffle-hover-highlight"); - currentnode.addClass("failure-highlight"); - - if (!visited.includes(item.action.label)) { - if ( - item.action.result !== undefined && - item.action.result !== null && - !item.action.result.includes("failed condition") - ) { - alert.error( - "Error for " + - item.action.label + - " with result " + - item.result - ); - } - visited.push(item.action.label); - setVisited(visited); - } - break; - case "AWAITING_DATA": - currentnode.removeClass("not-executing-highlight"); - currentnode.removeClass("executing-highlight"); - currentnode.removeClass("success-highlight"); - currentnode.removeClass("failure-highlight"); - currentnode.removeClass("shuffle-hover-highlight"); - currentnode.addClass("awaiting-data-highlight"); - break; - default: - console.log("DEFAULT?"); - break; - } + handleColoring(item.action.id, item.status, item.action.label) } } - if ( - responseJson.status === "ABORTED" || - responseJson.status === "STOPPED" || - responseJson.status === "FAILURE" || - responseJson.status === "WAITING" - ) { + if (responseJson.status === "ABORTED" || responseJson.status === "STOPPED" || responseJson.status === "FAILURE" || responseJson.status === "WAITING") { stop(); if (executionRunning) { @@ -1341,16 +1342,12 @@ const AngularWorkflow = (defaultprops) => { cyelements[i].data().errors = []; } - for (let [key,keyval] in workflow.actions.entries()) { - workflow.actions[key].is_valid = true; - workflow.actions[key].errors = []; + for (let actionkey in workflow.actions) { + workflow.actions[actionkey].is_valid = true; + workflow.actions[actionkey].errors = []; } } - for (let [key,keyval] in workflow.errors.entries()) { - //alert.info(workflow.errors[key]); - } - setWorkflow(workflow); } @@ -1373,11 +1370,11 @@ const AngularWorkflow = (defaultprops) => { var firstnode = cy.getElementById(workflow.start); if (firstnode.length === 0) { var found = false; - for (let [key,keyval] in workflow.actions.entries()) { - if (workflow.actions[key].isStartNode) { + for (let actionkey in workflow.actions) { + if (workflow.actions[actionkey].isStartNode) { console.log("Updating startnode"); - workflow.start = workflow.actions[key].id; - firstnode = cy.getElementById(workflow.actions[key].id); + workflow.start = workflow.actions[actionkey].id; + firstnode = cy.getElementById(workflow.actions[actionkey].id); found = true; break; } @@ -1520,15 +1517,16 @@ const AngularWorkflow = (defaultprops) => { .then((responseJson) => { if (responseJson.success) { var newauth = []; - console.log("App auth: ", responseJson.data); - for (let [key,keyval] in responseJson.data.entries()) { - if (responseJson.data[key].defined === false) { + for (let authkey in responseJson.data) { + if (responseJson.data[authkey].defined === false) { continue; } - newauth.push(responseJson.data[key]); + newauth.push(responseJson.data[authkey]); } + setAppAuthentication(newauth); + if (cy !== undefined) { // Remove the old listener for select, run with new one cy.removeListener("select"); @@ -1536,24 +1534,20 @@ const AngularWorkflow = (defaultprops) => { cy.on("select", "edge", (e) => onEdgeSelect(e)); } - setAppAuthentication(newauth); - setAuthLoaded(true); - if (updateAction === true) { if (selectedApp.authentication.required) { // Setup auth here :) var appUpdates = false; const authenticationOptions = []; - var tmpAuth = JSON.parse(JSON.stringify(responseJson.data)); + var tmpAuth = JSON.parse(JSON.stringify(newauth)); var latest = 0; - for (let [key,keyval] in tmpAuth.entries()) { - var item = tmpAuth[key]; + for (let authkey in tmpAuth) { + var item = tmpAuth[authkey]; const newfields = {}; - for (let [filterkey, filterkeyval] in item.fields.entries()) { - newfields[item.fields[filterkey].key] = - item.fields[filterkey].value; + for (let filterkey in item.fields) { + newfields[item.fields[filterkey].key] = item.fields[filterkey].value; } item.fields = newfields; @@ -1565,10 +1559,10 @@ const AngularWorkflow = (defaultprops) => { latest = item.edited; selectedAction.selectedAuthentication = item; - for (let [key,keyval] in workflow.actions.entries()) { - if (workflow.actions[key].app_name === selectedApp.name) { - workflow.actions[key].selectedAuthentication = item; - workflow.actions[key].authentication_id = item.id; + for (let actionkey in workflow.actions) { + if (workflow.actions[actionkey].app_name === selectedApp.name) { + workflow.actions[actionkey].selectedAuthentication = item; + workflow.actions[actionkey].authentication_id = item.id; appUpdates = true; } } @@ -1603,11 +1597,11 @@ const AngularWorkflow = (defaultprops) => { } } } else { - setAuthLoaded(true); + setAppAuthentication([]); } }) .catch((error) => { - setAuthLoaded(true); + setAppAuthentication([]); //alert.error("Auth loading error: " + error.toString()); console.log("AppAuth error: " + error.toString()); }); @@ -1807,7 +1801,7 @@ const AngularWorkflow = (defaultprops) => { if (responseJson.public) { //alert.info("This workflow is public. Save the workflow to use it in your organization."); - setAuthLoaded(true) + setAppAuthentication([]) console.log("RESP: ", responseJson) if (Object.getOwnPropertyNames(creatorProfile).length === 0) { //getUserProfile("frikky") @@ -1817,8 +1811,8 @@ const AngularWorkflow = (defaultprops) => { //{appGroup.map((data, index) => { //const [appGroup, setAppGroup] = React.useState([]); var appsFound = [] - for (let [key,keyval] in responseJson.actions.entries()) { - const parsedAction = responseJson.actions[key] + for (let actionkey in responseJson.actions) { + const parsedAction = responseJson.actions[actionkey] if (parsedAction.large_image === undefined || parsedAction.large_image === null || parsedAction.large_image === "") { continue } @@ -1830,8 +1824,8 @@ const AngularWorkflow = (defaultprops) => { setAppGroup(appsFound) appsFound = [] - for (let [key,keyval] in responseJson.triggers.entries()) { - const parsedAction = responseJson.triggers[key] + for (let triggerkey in responseJson.triggers) { + const parsedAction = responseJson.triggers[triggerkey] if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0){ appsFound.push(parsedAction) } @@ -2008,6 +2002,7 @@ const AngularWorkflow = (defaultprops) => { responseJson.errors !== // what responseJson.errors.length > 0 ) { + console.log("Setting configure Modal to open") setConfigureWorkflowModalOpen(true); } } @@ -2092,10 +2087,6 @@ const AngularWorkflow = (defaultprops) => { } */ - //cy.removeListener("select"); - //cy.on("select", "node", (e) => onNodeSelect(e, appAuthentication)); - //cy.on("select", "edge", (e) => onEdgeSelect(e)); - // FIXME - check if they have value before overriding like this for no reason. // Would save a lot of time (400~ ms -> 30ms) @@ -2239,26 +2230,26 @@ const AngularWorkflow = (defaultprops) => { const connected = event.target.connectedEdges().jsons() if (connected.length > 0 && connected !== undefined) { - for (let [key,keyval] in connected.entries()) { - const edge = connected[key] - //console.log("EDGE:", edge) + for (let connectkey in connected) { + const edge = connected[connectkey] + //console.log("EDGE:", edge) - //const edge = edgeBase.json() + //const edge = edgeBase.json() - const sourcenode = cy.getElementById(edge.data.source) - const destinationnode = cy.getElementById(edge.data.target) - if (sourcenode === undefined || sourcenode === null || destinationnode === undefined || destinationnode === null) { - continue - } + const sourcenode = cy.getElementById(edge.data.source) + const destinationnode = cy.getElementById(edge.data.target) + if (sourcenode === undefined || sourcenode === null || destinationnode === undefined || destinationnode === null) { + continue + } - const edgeCurve = calculateEdgeCurve(sourcenode.position(), destinationnode.position()) - const currentedge = cy.getElementById(edge.data.id) - if (currentedge !== undefined && currentedge !== null) { - currentedge.style('control-point-distance', edgeCurve.distance) - currentedge.style('control-point-weight', edgeCurve.weight) + const edgeCurve = calculateEdgeCurve(sourcenode.position(), destinationnode.position()) + const currentedge = cy.getElementById(edge.data.id) + if (currentedge !== undefined && currentedge !== null) { + currentedge.style('control-point-distance', edgeCurve.distance) + currentedge.style('control-point-weight', edgeCurve.weight) + } } } - } if (styledElements.length === 1) { console.log( @@ -2337,8 +2328,8 @@ const AngularWorkflow = (defaultprops) => { ) { const allNodes = cy.nodes().jsons(); var found = false; - for (let [key,keyval] in allNodes.entries()) { - const currentNode = allNodes[key]; + for (let nodekey in allNodes) { + const currentNode = allNodes[nodekey]; if ( currentNode.data.attachedTo === nodedata.id && currentNode.data.isDescriptor @@ -2404,8 +2395,8 @@ const AngularWorkflow = (defaultprops) => { if (nodedata.app_name !== undefined) { const allNodes = cy.nodes().jsons(); - for (var key_ in allNodes) { - const currentNode = allNodes[key_]; + for (var nodekey in allNodes) { + const currentNode = allNodes[nodekey]; if (currentNode.data.attachedTo === nodedata.id) { cy.getElementById(currentNode.data.id).remove(); } @@ -2535,7 +2526,9 @@ const AngularWorkflow = (defaultprops) => { // https://stackoverflow.com/questions/16677856/cy-onselect-callback-only-once // onNodeClick const onNodeSelect = (event, newAppAuth) => { - // Otherwise everything is SUPER slow + console.log("App auth in select: ", newAppAuth) + // Forces all states to update at the same time, + // Otherwise everything is SUPER slow ReactDOM.unstable_batchedUpdates(() => { const data = event.target.data(); if (data.isButton) { @@ -2691,7 +2684,6 @@ const AngularWorkflow = (defaultprops) => { //event.target.data() var curaction = workflow.actions.find((a) => a.id === data.id) if (!curaction || curaction === undefined) { - console.log("NOT FOUND DATA: ", event.target.data()) if (data.id !== undefined && data.app_name !== undefined) { workflow.actions.push(data) setWorkflow(workflow) @@ -2805,18 +2797,35 @@ const AngularWorkflow = (defaultprops) => { } const tmpAuth = JSON.parse(JSON.stringify(newAppAuth)); - //var tmpAuth = newAppAuth + console.log("FOUND AUTH OPTIONS: ", tmpAuth) - for (var tmpAuthKey in tmpAuth) { + const curappName = curapp.name.toLowerCase() + for (let tmpAuthKey in tmpAuth) { var item = tmpAuth[tmpAuthKey]; const newfields = {}; - for (var fieldFilterKey in item.fields) { - newfields[item.fields[fieldFilterKey].key] = item.fields[fieldFilterKey].value; + if (item.app.name.toLowerCase() !== curappName) { + continue + } + + // Makes list into key:value object + for (let fieldkey in item.fields) { + if (item.fields[fieldkey] === undefined) { + console.log("Problem with filterkey in Node select", fieldkey) + continue + } + + const filterkey = item.fields[fieldkey]["key"] + if (filterkey === null || filterkey === undefined) { + console.log("Problem with filterkey 2. Null or undefined 3") + continue + } + + newfields[filterkey] = item.fields[fieldkey]["value"]; } item.fields = newfields; - if (item.app.name === curapp.name) { + if (item.app.name.toLowerCase() === curappName) { authenticationOptions.push(item); if (item.id === findAuthId) { curaction.selectedAuthentication = item; @@ -2824,6 +2833,8 @@ const AngularWorkflow = (defaultprops) => { } } + console.log("Options: ", authenticationOptions) + curaction.authentication = authenticationOptions; if ( curaction.selectedAuthentication === null || @@ -2855,7 +2866,7 @@ const AngularWorkflow = (defaultprops) => { } } else { console.log("Should check APP if it has the same params as ACTION") - for (var actionKey in curapp.actions) { + for (let actionKey in curapp.actions) { const tmpaction = curapp.actions[actionKey] if (tmpaction.name === curaction.name) { console.log("Found action - needs change?", tmpaction) @@ -2867,7 +2878,24 @@ const AngularWorkflow = (defaultprops) => { } } + //curaction["authentication"] = [] + //curaction["authentication_id"] = "" + // Fix parameters that are... Not ideal + //var paramnames = [] + //var newparams = [] + //for (let paramKey in curaction.parameters) { + // console.log("Name: ", curaction.parameters[paramKey].name) + // if (paramnames.includes(curaction.parameters[paramKey].name)) { + // continue + // } + + // paramnames.push(curaction.parameters[paramKey].name) + // newparams.push(curaction.parameters[paramKey]) + //} + + //curaction.parameters = newparams console.log("ACTION CLICK: ", curaction) + setSelectedApp(curapp); setSelectedAction(curaction); @@ -2931,7 +2959,6 @@ const AngularWorkflow = (defaultprops) => { } } - console.log("DATA: ", data) setSelectedTriggerIndex(trigger_index); setSelectedTrigger(data); setSelectedActionEnvironment(data.env); @@ -3003,10 +3030,10 @@ const AngularWorkflow = (defaultprops) => { var exampledata = item.example === undefined ? "" : item.example; if (workflowExecutions.length > 0) { // Look for the ID - for (let [key,keyval] in workflowExecutions.entries()) { + for (let execkey in workflowExecutions) { if ( - workflowExecutions[key].results === undefined || - workflowExecutions[key].results === null + workflowExecutions[execkey].results === undefined || + workflowExecutions[execkey].results === null ) { continue; } @@ -3014,16 +3041,16 @@ const AngularWorkflow = (defaultprops) => { var foundResult = { result: "" }; if (item.id === "exec") { if ( - workflowExecutions[key].execution_argument !== undefined && - workflowExecutions[key].execution_argument !== null && - workflowExecutions[key].execution_argument.length > 0 + workflowExecutions[execkey].execution_argument !== undefined && + workflowExecutions[execkey].execution_argument !== null && + workflowExecutions[execkey].execution_argument.length > 0 ) { - foundResult.result = workflowExecutions[key].execution_argument; + foundResult.result = workflowExecutions[execkey].execution_argument; } else { continue; } } else { - foundResult = workflowExecutions[key].results.find( + foundResult = workflowExecutions[execkey].results.find( (result) => result.action.id === item.id ); if (foundResult === undefined) { @@ -3150,7 +3177,7 @@ const AngularWorkflow = (defaultprops) => { selectedkey = `.${key}`; } - for (let [subitem,subitemval] in value.entries()) { + for (let [subitem,subitemval] in Object.entries(value)) { toreturn = GetParamMatch( paramname, value[subitem], @@ -3226,8 +3253,8 @@ const AngularWorkflow = (defaultprops) => { var parents = getParents(dstdata); if (parents.length > 1) { - for (let [key,keyval] in parents.entries()) { - const item = parents[key]; + for (let parentkey in parents) { + const item = parents[parentkey]; if (item.label === "Execution Argument") { continue; } @@ -3236,33 +3263,36 @@ const AngularWorkflow = (defaultprops) => { item.label === undefined ? "" : item.label.toLowerCase().trim().replaceAll(" ", "_"); + exampledata = GetExampleResult(item); - for (let [paramkey,paramkeyval] in dstdata.parameters.entries()) { - const param = dstdata.parameters[paramkey]; - // Skip authentication params - if (param.configuration) { - continue - } + if (dstdata.parameters !== undefined && dstdata.parameters !== null) { + for (let [paramkey,paramkeyval] in Object.entries(dstdata.parameters)) { + const param = dstdata.parameters[paramkey]; + // Skip authentication params + if (param.configuration) { + continue + } - if (param.options !== undefined && param.options !== null && param.options.length > 0) { - continue - } + if (param.options !== undefined && param.options !== null && param.options.length > 0) { + continue + } - const paramname = param.name - .toLowerCase() - .trim() - .replaceAll("_", " "); + const paramname = param.name + .toLowerCase() + .trim() + .replaceAll("_", " "); - const foundresult = GetParamMatch(paramname, exampledata, ""); - if (foundresult.length > 0) { - if (dstdata.parameters[paramkey].value.length === 0) { - dstdata.parameters[paramkey].value = `$${parentlabel}${foundresult}`; - dstdata.parameters[paramkey].autocompleted = true - } else { - //dstdata.parameters[paramkey].value = `$${parentlabel}${foundresult}`; - } - } - } + const foundresult = GetParamMatch(paramname, exampledata, ""); + if (foundresult.length > 0) { + if (dstdata.parameters[paramkey].value.length === 0) { + dstdata.parameters[paramkey].value = `$${parentlabel}${foundresult}`; + dstdata.parameters[paramkey].autocompleted = true + } else { + //dstdata.parameters[paramkey].value = `$${parentlabel}${foundresult}`; + } + } + } + } // Check agains every param } } @@ -3387,18 +3417,18 @@ const AngularWorkflow = (defaultprops) => { // dest == dest && source == source // backend: check all children? to stop recursion var found = false; - for (let [key,keyval] in workflow.branches.entries()) { + for (let branchkey in workflow.branches) { if ( - workflow.branches[key].destination_id === edge.source && - workflow.branches[key].source_id === edge.target + workflow.branches[branchkey].destination_id === edge.source && + workflow.branches[branchkey].source_id === edge.target ) { alert.error("A branch in the opposite direction already exists"); event.target.remove(); found = true; break; } else if ( - workflow.branches[key].destination_id === edge.target && - workflow.branches[key].source_id === edge.source + workflow.branches[branchkey].destination_id === edge.target && + workflow.branches[branchkey].source_id === edge.source ) { console.log(edge.source); alert.error("That branch already exists"); @@ -3418,7 +3448,7 @@ const AngularWorkflow = (defaultprops) => { found = true; } - } else if (edge.source === workflow.branches[key].source_id) { + } else if (edge.source === workflow.branches[branchkey].source_id) { // FIXME: Verify multi-target for triggers // 1. Check if destination exists // 2. Check if source is a trigger @@ -3495,9 +3525,9 @@ const AngularWorkflow = (defaultprops) => { const node = event.target; const nodedata = event.target.data(); - if (Object.keys(nodedata).length === 1) { - console.log("Check if another node actually exists before adding") - } + //if (Object.keys(nodedata).length === 1) { + // console.log("Check if another node actually exists before adding") + //} if (nodedata.finished === false || (nodedata.id !== undefined && nodedata.is_valid === undefined) ) { @@ -3522,8 +3552,8 @@ const AngularWorkflow = (defaultprops) => { } // Remove bad startnode - for (let [key,keyval] in workflow.actions.entries()) { - const action = workflow.actions[key]; + for (let actionkey in workflow.actions) { + const action = workflow.actions[actionkey]; if (action.isStartNode && workflow.start !== action.id) { action.isStartNode = false; } @@ -3586,7 +3616,7 @@ const AngularWorkflow = (defaultprops) => { ) { var newparameters = []; - for (let [subkey,subkeyval] in nodedata.parameters.entries()) { + for (let [subkey,subkeyval] in Object.entries(nodedata.parameters)) { var newparam = JSON.parse( JSON.stringify(nodedata.parameters[subkey]) ); @@ -3679,8 +3709,8 @@ const AngularWorkflow = (defaultprops) => { // Check if the source is trigger and can start console.log("Removed: ", edge.data()) const allNodes = cy.nodes().jsons() - for (let [key,keyval] in allNodes.entries()) { - const curnode = allNodes[key] + for (let nodekey in allNodes) { + const curnode = allNodes[nodekey] if (curnode.data.type !== "TRIGGER") { continue } @@ -3951,8 +3981,8 @@ const AngularWorkflow = (defaultprops) => { const parsedjson = JSON.parse(clipboard); //console.log("Parsed: ", parsedjson) - for (let [key,keyval] in parsedjson.entries()) { - const item = parsedjson[key]; + for (let jsonkey in parsedjson) { + const item = parsedjson[jsonkey]; console.log("Adding: ", item); item.data.id = uuidv4() @@ -3999,13 +4029,13 @@ const AngularWorkflow = (defaultprops) => { .then((responseJson) => { var found = false; var showEnvCnt = 0; - for (let [key,keyval] in responseJson.entries()) { - if (responseJson[key].default && !found) { - setDefaultEnvironmentIndex(key); + for (let jsonkey in responseJson) { + if (responseJson[jsonkey].default && !found) { + setDefaultEnvironmentIndex(jsonkey); found = true; } - if (responseJson[key].archived === false) { + if (responseJson[jsonkey].archived === false) { showEnvCnt += 1; } } @@ -4015,9 +4045,9 @@ const AngularWorkflow = (defaultprops) => { } if (!found) { - for (let [key,keyval] in responseJson.entries()) { - if (!responseJson[key].archived) { - setDefaultEnvironmentIndex(key); + for (let jsonkey in responseJson) { + if (!responseJson[jsonkey].archived) { + setDefaultEnvironmentIndex(jsonkey); break; } } @@ -4846,6 +4876,7 @@ const AngularWorkflow = (defaultprops) => { const triggerindex = workflow.triggers.findIndex( (data) => data.id === selectedNode.data().id ); + setSelectedTriggerIndex(triggerindex); if (selectedNode.data().trigger_type === "SCHEDULE") { setSelectedTrigger(selectedNode.data()); @@ -4869,7 +4900,12 @@ const AngularWorkflow = (defaultprops) => { if (selectedNode.data().decorator === true && selectedNode.data("type") !== "COMMENT") { alert.info("This node can't be deleted."); } else { + console.log("Deleted.") selectedNode.remove(); + + setSelectedTrigger({}) + setSelectedEdge({}) + setSelectedAction({}) } // An attempt at NOT unselecting when removing @@ -4984,8 +5020,7 @@ const AngularWorkflow = (defaultprops) => { console.log("In graph setup") // 2nd load - configures cytoscape - } else if (!established && cy !== undefined && ((apps !== null && apps !== undefined && apps.length > 0) || workflow.public === true) && Object.getOwnPropertyNames(workflow).length > 0 && authLoaded) { - + } else if (!established && cy !== undefined && ((apps !== null && apps !== undefined && apps.length > 0) || workflow.public === true) && Object.getOwnPropertyNames(workflow).length > 0 && appAuthentication !== undefined) { console.log("In POST graph setup!") @@ -5022,11 +5057,8 @@ const AngularWorkflow = (defaultprops) => { } if (cy.edgehandles !== undefined) { - console.log("Inside edgehandles") cy.edgehandles({ handleNodes: (el) => { - console.log("in handlenodes") - if (el.isNode() && !el.data("isButton") && !el.data("isDescriptor") && @@ -5155,8 +5187,8 @@ const AngularWorkflow = (defaultprops) => { var mappedStartnode = "" const alledges = cy.edges().jsons() if (alledges !== undefined && alledges !== null && alledges.length > 0) { - for (let [key,keyval] in alledges.entries()) { - const tmp = alledges[key] + for (let edgekey in alledges) { + const tmp = alledges[edgekey] console.log("TMP: ", tmp, tmp.data.source) if (tmp.data.source === trigger.id) { mappedStartnode = tmp.data.target @@ -5934,13 +5966,27 @@ const AngularWorkflow = (defaultprops) => { } const tmpAuth = JSON.parse(JSON.stringify(appAuthentication)); - for (let [key,keyval] in tmpAuth.entries()) { - var item = tmpAuth[key]; + for (let authkey in tmpAuth) { + if (authkey === undefined) { + continue + } + var item = tmpAuth[authkey]; const newfields = {}; - for (let [filterkey,filterkeyval] in item.fields.entries()) { - newfields[item.fields[filterkey].key] = item.fields[filterkey].value; - } + for (let fieldkey in item.fields) { + if (item.fields[fieldkey] === undefined) { + console.log("Problem with filterkey in Node select", fieldkey) + continue + } + + const filterkey = item.fields[fieldkey]["key"] + if (filterkey === null || filterkey === undefined) { + console.log("Problem with filterkey 2. Null or undefined 3") + continue + } + + newfields[filterkey] = item.fields[fieldkey]["value"]; + } item.fields = newfields; if (item.app.id === app.id || item.app.name === app.name) { @@ -5964,8 +6010,8 @@ const AngularWorkflow = (defaultprops) => { authenticationOptions !== null && authenticationOptions.length > 0 ) { - for (let [key,keyval] in authenticationOptions.entries()) { - const option = authenticationOptions[key]; + for (let authkey in authenticationOptions) { + const option = authenticationOptions[authkey]; if (option.active && newAppData.authentication_id === "") { newAppData.selectedAuthentication = option; @@ -6046,6 +6092,7 @@ const AngularWorkflow = (defaultprops) => { newNodeId = uuidv4(); const actionType = "ACTION"; const actionLabel = getNextActionName(app.name); + console.log("Next action name: ", actionLabel) var parameters = null; var example = ""; var description = "" @@ -6085,6 +6132,8 @@ const AngularWorkflow = (defaultprops) => { // activated: app.generated === true ? app.activated === false ? false : true : true, const newAppData = { + name: app.actions[0].name, + label: actionLabel, app_name: app.name, app_version: app.app_version, app_id: app.id, @@ -6098,9 +6147,7 @@ const AngularWorkflow = (defaultprops) => { _id_: newNodeId, id: newNodeId, is_valid: true, - label: actionLabel, type: actionType, - name: app.actions[0].name, parameters: parameters, isStartNode: false, large_image: app.large_image, @@ -6376,12 +6423,14 @@ const AngularWorkflow = (defaultprops) => { if (newApps.length === 0) { const searchvalue = value.trim().toLowerCase(); newApps = allApps.filter((app) => { - for (let [key,keyval] in app.actions.entries()) { - const inneraction = app.actions[key]; - if (inneraction.name.toLowerCase().includes(searchvalue)) { - return true; - } - } + if (app.actions !== undefined && app.actions !== null) { + for (let actionkey in app.actions) { + const inneraction = app.actions[actionkey]; + if (inneraction.name.toLowerCase().includes(searchvalue)) { + return true; + } + } + } return false; }); @@ -6405,7 +6454,6 @@ const AngularWorkflow = (defaultprops) => { if (document !== undefined) { const appsearchValue = document.getElementById("appsearch") if (appsearchValue !== undefined && appsearchValue !== null) { - console.log("Value2: ", appsearchValue.value) if (appsearchValue.value !== undefined && appsearchValue.value !== null && appsearchValue.value.length > 0) { refine(appsearchValue.value) } @@ -6741,25 +6789,29 @@ const AngularWorkflow = (defaultprops) => { var highest = ""; const allitems = workflow.actions.concat(workflow.triggers); - for (let [key,keyval] in allitems.entries()) { - const item = allitems[key]; - if ( - item.app_name === appName && - item.label !== undefined && - item.label !== null - ) { - var number = item.label.split("_"); - if ( - isNaN(number[-1]) && - parseInt(number[number.length - 1]) > highest - ) { - highest = number[number.length - 1]; - } - } - } + if (allitems !== undefined && allitems !== null) { + for (let itemkey in allitems) { + const item = allitems[itemkey]; + if ( + item.app_name === appName && + item.label !== undefined && + item.label !== null + ) { + var number = item.label.split("_"); + if ( + isNaN(number[-1]) && + parseInt(number[number.length - 1]) > highest + ) { + highest = number[number.length - 1]; + } + } + } + } appName = appName.replaceAll(" ", "_") + console.log("Highest:", highest) + if (highest) { return appName + "_" + (parseInt(highest) + 1); } else { @@ -6799,10 +6851,11 @@ const AngularWorkflow = (defaultprops) => { newSelectedAction.is_valid = true; //console.log(newSelectedAction) + // Simmple action swap autocompleter - if (oldaction.parameters !== undefined && newSelectedAction.parameters !== undefined && oldaction.id === newSelectedAction.id) { + if (oldaction.parameters !== undefined && oldaction.parameters !== null && newSelectedAction.parameters !== undefined && oldaction.id === newSelectedAction.id) { var fileid_found = false - for (let [paramkey,paramkeyval] in oldaction.parameters.entries()) { + for (let [paramkey,paramkeyval] in Object.entries(oldaction.parameters)) { const param = oldaction.parameters[paramkey]; if (param.name === "file_id") { @@ -6916,24 +6969,26 @@ const AngularWorkflow = (defaultprops) => { // FIXME - should change icon-node (descriptor) as well const allNodes = cy.nodes().jsons(); - for (let [key,keyval] in allNodes.entries()) { - const currentNode = allNodes[key]; - if ( - currentNode.data.attachedTo === oldaction.id && - currentNode.data.isDescriptor - ) { - const foundnode = cy.getElementById(currentNode.data.id); - if (foundnode !== null && foundnode !== undefined) { - const iconInfo = GetIconInfo(newaction); - const svg_pin = ``; - const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin); - foundnode.data("image", svgpin_Url); - foundnode.data("imageColor", iconInfo.iconBackgroundColor); - } + if (allNodes !== undefined && allNodes !== null) { + for (let nodekey in allNodes) { + const currentNode = allNodes[nodekey]; + if ( + currentNode.data.attachedTo === oldaction.id && + currentNode.data.isDescriptor + ) { + const foundnode = cy.getElementById(currentNode.data.id); + if (foundnode !== null && foundnode !== undefined) { + const iconInfo = GetIconInfo(newaction); + const svg_pin = ``; + const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin); + foundnode.data("image", svgpin_Url); + foundnode.data("imageColor", iconInfo.iconBackgroundColor); + } - break; - } - } + break; + } + } + } }; // APPSELECT at top @@ -7008,15 +7063,15 @@ const AngularWorkflow = (defaultprops) => { var iterations = 0; var maxiter = 10; while (true) { - for (let [key,keyval] in allkeys.entries()) { - var currentnode = cy.getElementById(allkeys[key]); + for (let parentkey in allkeys) { + var currentnode = cy.getElementById(allkeys[parentkey]); if (currentnode === undefined || currentnode === null) { continue; } if (currentnode.data() === undefined) { - handled.push(allkeys[key]); - results.push({ id: allkeys[key], type: "TRIGGER" }); + handled.push(allkeys[parentkey]); + results.push({ id: allkeys[parentkey], type: "TRIGGER" }); } else { if (handled.includes(currentnode.data().id)) { continue; @@ -7255,8 +7310,8 @@ const AngularWorkflow = (defaultprops) => { workflow.workflow_variables !== undefined && workflow.workflow_variables.length > 0 ) { - for (let [key,keyval] in workflow.workflow_variables.entries()) { - const item = workflow.workflow_variables[key]; + for (let varkey in workflow.workflow_variables) { + const item = workflow.workflow_variables[varkey]; actionlist.push({ type: "workflow_variable", name: item.name, @@ -7274,8 +7329,8 @@ const AngularWorkflow = (defaultprops) => { workflow.execution_variables !== undefined && workflow.execution_variables.length > 0 ) { - for (let [key,keyval] in workflow.execution_variables.entries()) { - const item = workflow.execution_variables[key]; + for (let varkey in workflow.execution_variables) { + const item = workflow.execution_variables[varkey]; actionlist.push({ type: "execution_variable", name: item.name, @@ -7290,8 +7345,8 @@ const AngularWorkflow = (defaultprops) => { const destAction = cy.getElementById(selectedEdge.target); var parents = getParents(destAction.data()); if (parents.length > 1) { - for (let [key,keyval] in parents.entries()) { - const item = parents[key]; + for (let parentkey in parents) { + const item = parents[parentkey]; if (item.label === "Execution Argument") { continue; } @@ -7466,8 +7521,8 @@ const AngularWorkflow = (defaultprops) => { workflow.triggers !== null && workflow.triggers.length > 0 ) { - for (let [key,keyval] in workflow.triggers.entries()) { - const item = workflow.triggers[key]; + for (let triggerkey in workflow.triggers) { + const item = workflow.triggers[triggerkey]; var node = cy.getElementById(item.id); if (node.length > 0) { @@ -8812,8 +8867,8 @@ const AngularWorkflow = (defaultprops) => { workflow.workflow_variables !== undefined && workflow.workflow_variables.length > 0 ) { - for (let [key,keyval] in workflow.workflow_variables.entries()) { - const item = workflow.workflow_variables[key]; + for (let varkey in workflow.workflow_variables) { + const item = workflow.workflow_variables[varkey]; actionlist.push({ type: "workflow_variable", name: item.name, @@ -8831,8 +8886,8 @@ const AngularWorkflow = (defaultprops) => { workflow.execution_variables !== undefined && workflow.execution_variables.length > 0 ) { - for (let [key,keyval] in workflow.execution_variables.entries()) { - const item = workflow.execution_variables[key]; + for (let varkey in workflow.execution_variables) { + const item = workflow.execution_variables[varkey]; actionlist.push({ type: "execution_variable", name: item.name, @@ -8846,8 +8901,8 @@ const AngularWorkflow = (defaultprops) => { var parents = getParents(selectedTrigger); if (parents.length > 1) { - for (let [key,keyval] in parents.entries()) { - const item = parents[key]; + for (let parentkey in parents) { + const item = parents[parentkey]; if (item.label === "Execution Argument") { continue; } @@ -8856,15 +8911,15 @@ const AngularWorkflow = (defaultprops) => { // Find previous execution and their variables if (workflowExecutions.length > 0) { // Look for the ID - for (let [key,keyval] in workflowExecutions.entries()) { + for (let execkey in workflowExecutions) { if ( - workflowExecutions[key].results === undefined || - workflowExecutions[key].results === null + workflowExecutions[execkey].results === undefined || + workflowExecutions[execkey].results === null ) { continue; } - var foundResult = workflowExecutions[key].results.find( + var foundResult = workflowExecutions[execkey].results.find( (result) => result.action.id === item.id ); if (foundResult === undefined) { @@ -8985,8 +9040,8 @@ const AngularWorkflow = (defaultprops) => { workflow.triggers !== null && workflow.triggers.length > 0 ) { - for (let [key,keyval] in workflow.triggers.entries()) { - const item = workflow.triggers[key]; + for (let triggerkey in workflow.triggers) { + const item = workflow.triggers[triggerkey]; if (cy !== undefined) { var node = cy.getElementById(item.id); @@ -9704,7 +9759,6 @@ const AngularWorkflow = (defaultprops) => { workflow.triggers[selectedTriggerIndex].parameters[1].value } onBlur={(e) => { - console.log("DATA: ", e.target.value); workflow.triggers[selectedTriggerIndex].parameters[1].value = e.target.value; setWorkflow(workflow); @@ -10570,8 +10624,8 @@ const AngularWorkflow = (defaultprops) => { ) console.log("Starting mail sub: ", workflow.triggers[selectedTriggerIndex].parameters[0].value, splitItem); - for (let [key,keyval] in splitItem.entries()) { - const item = splitItem[key]; + for (let splitkey in splitItem) { + const item = splitItem[splitkey]; const curfolder = triggerFolders.find((a) => a.displayName === item); if (curfolder === undefined) { alert.error("Something went wrong with folder selection: " + item); @@ -10761,7 +10815,7 @@ const AngularWorkflow = (defaultprops) => { }) .catch((error) => { //alert.error(error.toString()); - alert.error("Delete webhook error: ", error.toString()); + alert.error("Delete webhook error. Contact support or check logs if this persists.") }); }; @@ -12725,17 +12779,17 @@ const AngularWorkflow = (defaultprops) => { } to_be_copied = "$" + base_node_name.toLowerCase().replaceAll(" ", "_"); - for (let [key,keyval] in copy.namespace.entries()) { - if (copy.namespace[key].includes("Results for")) { + for (let copykey in copy.namespace) { + if (copy.namespace[copykey].includes("Results for")) { continue; } if (newitem !== undefined && newitem !== null) { - newitem = newitem[copy.namespace[key]]; - if (!isNaN(copy.namespace[key])) { + newitem = newitem[copy.namespace[copykey]]; + if (!isNaN(copy.namespace[copykey])) { to_be_copied += ".#"; } else { - to_be_copied += "." + copy.namespace[key]; + to_be_copied += "." + copy.namespace[copykey]; } } } @@ -12943,7 +12997,7 @@ const AngularWorkflow = (defaultprops) => { : null} {executionModalView === 0 ? ( -
+
{ const statusColor = data.status === "FINISHED" - ? green - : data.status === "ABORTED" || data.status === "FAILED" + ? green : data.status === "ABORTED" || data.status === "FAILED" ? "red" : yellow; const resultsLength = @@ -13000,17 +13053,20 @@ const AngularWorkflow = (defaultprops) => { data.workflow.actions !== null ? data.workflow.actions.length : 0; - for (let [key,keyval] in data.workflow.triggers.entries()) { - const trigger = data.workflow.triggers[key]; - if ( - (trigger.app_name === "User Input" && - trigger.trigger_type === "USERINPUT") || - (trigger.app_name === "Shuffle Workflow" && - trigger.trigger_type === "SUBFLOW") - ) { - calculatedResult += 1; - } - } + + if (data.workflow.triggers !== undefined && data.workflow.triggers !== null) { + for (let triggerkey in data.workflow.triggers) { + const trigger = data.workflow.triggers[triggerkey]; + if ( + (trigger.app_name === "User Input" && + trigger.trigger_type === "USERINPUT") || + (trigger.app_name === "Shuffle Workflow" && + trigger.trigger_type === "SUBFLOW") + ) { + calculatedResult += 1; + } + } + } return ( @@ -13041,6 +13097,7 @@ const AngularWorkflow = (defaultprops) => { setExecutionRequestStarted(false); } + // Ensuring we have the latest version of the result. // Especially important IF the result is > 1 Mb in cloud var checkStarted = false @@ -13053,21 +13110,23 @@ const AngularWorkflow = (defaultprops) => { setExecutionRunning(true); setExecutionRequestStarted(false); } else { - for (let [key,keyval] in data.results.entries()) { - if (data.results[key].status !== "SUCCESS") { - continue - } + if (data.results !== undefined && data.results !== null) { + for (let resultkey in data.results) { + if (data.results[resultkey].status !== "SUCCESS") { + continue + } - if (data.results[key].result.includes("too large")) { - setExecutionData({}); - checkStarted = true - start(); - setExecutionRunning(true); - setExecutionRequestStarted(false); - break - } - } - } + if (data.results[resultkey].result.includes("too large")) { + setExecutionData({}); + checkStarted = true + start(); + setExecutionRunning(true); + setExecutionRequestStarted(false); + break + } + } + } + } } const cur_execution = { @@ -13079,6 +13138,24 @@ const AngularWorkflow = (defaultprops) => { if (!checkStarted) { handleUpdateResults(data, cur_execution); + + console.log("Clearing colors during click for: !", data) + + if (cy !== undefined && cy !== null) { + cy.elements().removeClass("success-highlight failure-highlight executing-highlight"); + for (let actionKey in data.workflow.actions) { + var actionitem = data.workflow.actions[actionKey]; + + handleColoring(actionitem.id, "", actionitem.label) + } + + for (let resultKey in data.results) { + var item = data.results[resultKey]; + + handleColoring(item.action.id, item.status, item.action.label) + } + } + setExecutionData(data); } }} @@ -13153,7 +13230,7 @@ const AngularWorkflow = (defaultprops) => { })}
) : ( -
There are no executions yet
+
There are no executions yet, or they are not loaded.
)}
) : ( @@ -13536,10 +13613,12 @@ const AngularWorkflow = (defaultprops) => { if (data.similar_actions !== undefined && data.similar_actions !== null) { var minimumMatch = 85 var matching_executions = [] - for (let [k,kval] in data.similar_actions.entries()){ - if (data.similar_actions.hasOwnProperty(k)) { - if (data.similar_actions[k].similarity > minimumMatch) { - matching_executions.push(data.similar_actions[k].execution_id) + if (data.similar_actions !== undefined && data.similar_actions !== null) { + for (let [k,kval] in Object.entries(data.similar_actions)){ + if (data.similar_actions.hasOwnProperty(k)) { + if (data.similar_actions[k].similarity > minimumMatch) { + matching_executions.push(data.similar_actions[k].execution_id) + } } } } @@ -13882,28 +13961,31 @@ const AngularWorkflow = (defaultprops) => { }} onClick={(e) => { e.preventDefault(); - for (let [key,keyval] in workflowExecutions.entries()) { - const execution = workflowExecutions[key]; - const result = execution.results.find( - (data) => - data.status === "SUCCESS" && - data.action.id === selectedResult.action.id - ); - if (result !== undefined) { - const oldstartnode = cy.getElementById(selectedResult.action.id); - if (oldstartnode !== undefined && oldstartnode !== null) { - const foundname = oldstartnode.data("label") - if (foundname !== undefined && foundname !== null) { - result.action.label = foundname - } - } + if (workflowExecutions !== null) { + for (let execkey in workflowExecutions) { + const execution = workflowExecutions[execkey]; + if (execution.execution_argument.includes("too large")) { + continue + } - setSelectedResult(result); - setUpdate(Math.random()); - break; - } - } + const result = execution.results.find((data) => data.status === "SUCCESS" && data.action.id === selectedResult.action.id) + + if (result !== undefined) { + const oldstartnode = cy.getElementById(selectedResult.action.id); + if (oldstartnode !== undefined && oldstartnode !== null) { + const foundname = oldstartnode.data("label") + if (foundname !== undefined && foundname !== null) { + result.action.label = foundname + } + } + + setSelectedResult(result); + setUpdate(Math.random()); + break; + } + } + } }} > @@ -13923,8 +14005,8 @@ const AngularWorkflow = (defaultprops) => { }} onClick={(e) => { e.preventDefault(); - for (let [key,keyval] in workflowExecutions.entries()) { - const execution = workflowExecutions[key]; + for (let execkey in workflowExecutions) { + const execution = workflowExecutions[execkey]; const result = execution.results.find( (data) => data.action.id === selectedResult.action.id && @@ -13961,13 +14043,21 @@ const AngularWorkflow = (defaultprops) => { style={{ zIndex: 5000, position: "absolute", top: 34, right: 98 }} onClick={(e) => { e.preventDefault(); - const executionIndex = workflowExecutions.findIndex( - (data) => data.execution_id === selectedResult.execution_id - ); + const executionIndex = workflowExecutions.findIndex((data) => data.execution_id === selectedResult.execution_id); + if (executionIndex !== -1) { setExecutionModalOpen(true); setExecutionModalView(1); - setExecutionData(workflowExecutions[executionIndex]); + + if (workflowExecutions[executionIndex] !== undefined && workflowExecutions[executionIndex] !== null && workflowExecutions[executionIndex].execution_argument.includes("too large")) { + //checkStarted = true + setExecutionData({}); + start(); + setExecutionRunning(true); + setExecutionRequestStarted(false); + } else { + setExecutionData(workflowExecutions[executionIndex]); + } } }} > @@ -14597,14 +14687,14 @@ const AngularWorkflow = (defaultprops) => { authenticationOption.app.actions = []; - for (let [key,keyval] in selectedApp.authentication.parameters.entries()) { + for (let paramkey in selectedApp.authentication.parameters) { if ( authenticationOption.fields[ - selectedApp.authentication.parameters[key].name + selectedApp.authentication.parameters[paramkey].name ] === undefined ) { authenticationOption.fields[ - selectedApp.authentication.parameters[key].name + selectedApp.authentication.parameters[paramkey].name ] = ""; } } @@ -14616,31 +14706,31 @@ const AngularWorkflow = (defaultprops) => { // Automatically mapping fields that already exist (predefined). // Warning if fields are NOT filled - for (let [key,keyval] in selectedApp.authentication.parameters.entries()) { + for (let paramkey in selectedApp.authentication.parameters) { if ( authenticationOption.fields[ - selectedApp.authentication.parameters[key].name + selectedApp.authentication.parameters[paramkey].name ].length === 0 ) { if ( - selectedApp.authentication.parameters[key].value !== undefined && - selectedApp.authentication.parameters[key].value !== null && - selectedApp.authentication.parameters[key].value.length > 0 + selectedApp.authentication.parameters[paramkey].value !== undefined && + selectedApp.authentication.parameters[paramkey].value !== null && + selectedApp.authentication.parameters[paramkey].value.length > 0 ) { authenticationOption.fields[ - selectedApp.authentication.parameters[key].name - ] = selectedApp.authentication.parameters[key].value; + selectedApp.authentication.parameters[paramkey].name + ] = selectedApp.authentication.parameters[paramkey].value; } else { if ( - selectedApp.authentication.parameters[key].schema.type === "bool" + selectedApp.authentication.parameters[paramkey].schema.type === "bool" ) { authenticationOption.fields[ - selectedApp.authentication.parameters[key].name + selectedApp.authentication.parameters[paramkey].name ] = "false"; } else { alert.info( "Field " + - selectedApp.authentication.parameters[key].name + + selectedApp.authentication.parameters[paramkey].name + " can't be empty" ); return; @@ -14665,11 +14755,12 @@ const AngularWorkflow = (defaultprops) => { var newAuthOption = JSON.parse(JSON.stringify(authenticationOption)); var newFields = []; - for (let [key,keyval] in newAuthOption.fields.entries()) { - const value = newAuthOption.fields[key]; + console.log("Fields: ", newAuthOption.fields) + for (let authkey in newAuthOption.fields) { + const value = newAuthOption.fields[authkey]; newFields.push({ - key: key, - value: value, + "key": authkey, + "value": value, }); } diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index a8da7482..16087936 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -299,6 +299,60 @@ const AppCreator = (defaultprops) => { const [selectedAction, setSelectedAction] = useState({}); const [authLoaded, setAuthLoaded] = useState(false); + // From 2023: Example to handle action labels + // Goal: Make this dynamically load from the backend + // and make categories + labels modifyable. + // + // Categories are the main categories in the App Framework + const [categories, setCategories] = useState([ + { + "name": "Communication", + "color": "#FFC107", + "icon": "communication", + "action_labels": [], + }, { + "name": "SIEM", + "color": "#FFC107", + "icon": "siem", + "action_labels": ["Get alerts", "Search", "Create detection",], + }, { + "name": "Eradication", + "color": "#FFC107", + "icon": "eradication", + "action_labels": ["List tickets", "Update ticket", "Block hash", "Isolate host"], + }, { + "name": "Cases", + "color": "#FFC107", + "icon": "cases", + "action_labels": ["List tickets", "Get ticket", "Create ticket", "Update ticket",], + }, { + "name": "Assets", + "color": "#FFC107", + "icon": "assets", + "action_labels": [], + }, { + "name": "Intel", + "color": "#FFC107", + "icon": "intel", + "action_labels": [], + }, { + "name": "IAM", + "color": "#FFC107", + "icon": "iam", + "action_labels": [], + }, { + "name": "Network", + "color": "#FFC107", + "icon": "network", + "action_labels": ["Block IP",], + }, { + "name": "Other", + "color": "#FFC107", + "icon": "other", + "action_labels": [], + } + ]); + //const [actions, setActions] = useState([{ // "name": "Get workflows", // "description": "Get workflows", @@ -337,6 +391,7 @@ const AppCreator = (defaultprops) => { body: "", errors: [], example_response: "", + action_label: "No Label", method: actionNonBodyRequest[0], }); @@ -456,8 +511,8 @@ const AppCreator = (defaultprops) => { } var newitem = data; - for (let [key,keyval] in paramsplit.entries()) { - var tmpparam = paramsplit[key]; + for (let paramkey in paramsplit) { + var tmpparam = paramsplit[paramkey]; if (tmpparam === "#") { continue; } @@ -579,16 +634,14 @@ const AppCreator = (defaultprops) => { console.log("Tags: ", data.tags) if (data.tags !== undefined && data.tags.length > 0) { var newtags = []; - for (let [key,keyval] in data.tags.entries()) { - if (data.tags[key].name.length > 50) { - console.log( - "Skipping tag because it's too long: ", - data.tags[key].name.length - ); + for (let tagkey in data.tags) { + if (data.tags[tagkey].name.length > 50) { + console.log("Skipping tag because it's too long: ",data.tags[tagkey].name.length); + continue; } - newtags.push(data.tags[key].name); + newtags.push(data.tags[tagkey].name); } if (newtags.length > 10) { @@ -625,6 +678,7 @@ const AppCreator = (defaultprops) => { console.log("Paths: ", data.paths) if (data.paths !== null && data.paths !== undefined) { for (let [path, pathvalue] of Object.entries(data.paths)) { + for (let [method, methodvalue] of Object.entries(pathvalue)) { if (methodvalue === null) { alert.info("Skipped method (null)" + method); @@ -685,24 +739,24 @@ const AppCreator = (defaultprops) => { const pathsplit = path.split("/"); var categoryindex = -1; // Stupid way of finding a category/grouping - for (let [key,keyval] in pathsplit.entries()) { - if (pathsplit[key].includes("_shuffle_replace_")) { + for (let splitkey in pathsplit) { + if (pathsplit[splitkey].includes("_shuffle_replace_")) { const regex = /_shuffle_replace_\d/i; //console.log("NEW: ", - pathsplit[key] = pathsplit[key].replaceAll(new RegExp(regex, 'g'), "") + pathsplit[splitkey] = pathsplit[splitkey].replaceAll(new RegExp(regex, 'g'), "") } if ( - pathsplit[key].length > 0 && - pathsplit[key] !== "v1" && - pathsplit[key] !== "v2" && - pathsplit[key] !== "api" && - pathsplit[key] !== "1.0" && - pathsplit[key] !== "apis" + pathsplit[splitkey].length > 0 && + pathsplit[splitkey] !== "v1" && + pathsplit[splitkey] !== "v2" && + pathsplit[splitkey] !== "api" && + pathsplit[splitkey] !== "1.0" && + pathsplit[splitkey] !== "apis" ) { - newaction["category"] = pathsplit[key]; - if (!all_categories.includes(pathsplit[key])) { - all_categories.push(pathsplit[key]); + newaction["category"] = pathsplit[splitkey]; + if (!all_categories.includes(pathsplit[splitkey])) { + all_categories.push(pathsplit[splitkey]); } break; } @@ -743,16 +797,14 @@ const AppCreator = (defaultprops) => { console.log("Schema: ", methodvalue["requestBody"]["content"]["application/json"]["schema"]) if (methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"] !== undefined) { var tmpobject = {}; - for (let [prop, propvalue] of Object.entries( - methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"] - )) { + for (let prop of methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"]) { tmpobject[prop] = `\$\{${prop}\}`; } //console.log("Data: ", data) - for (let [subkey,subkeyval] in methodvalue["requestBody"]["content"][ - "application/json" - ]["schema"]["required"].entries()) { + for (let subkey in methodvalue["requestBody"]["content"]["application/json"]["schema"]["required"]) { + + const tmpitem = methodvalue["requestBody"]["content"][ "application/json" @@ -771,7 +823,7 @@ const AppCreator = (defaultprops) => { ); var newbody = {}; // Can handle default, required, description and type - for (let [propkey,propkeyval] in retRef.properties.entries()) { + for (let propkey in retRef.properties) { console.log("replace: ", propkey) const parsedkey = propkey.replaceAll(" ", "_").toLowerCase(); @@ -802,17 +854,12 @@ const AppCreator = (defaultprops) => { ]["properties"] !== undefined ) { var tmpobject = {}; - for (let [prop, propvalue] of Object.entries( - methodvalue["requestBody"]["content"]["application/xml"][ - "schema" - ]["properties"] - )) { + for (let [prop, propvalue] of Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["properties"])) { + tmpobject[prop] = `\$\{${prop}\}`; } - for (let [subkey,subkeyval] in methodvalue["requestBody"]["content"][ - "application/xml" - ]["schema"]["required"].entries()) { + for (let [subkey,subkeyval] in Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["required"])) { const tmpitem = methodvalue["requestBody"]["content"][ "application/xml" @@ -854,11 +901,7 @@ const AppCreator = (defaultprops) => { "multipart/form-data" ]["schema"] !== null ) { - if ( - methodvalue["requestBody"]["content"][ - "multipart/form-data" - ]["schema"]["type"] === "object" - ) { + if (methodvalue["requestBody"]["content"]["multipart/form-data"]["schema"]["type"] === "object") { const fieldname = methodvalue["requestBody"]["content"][ "multipart/form-data" @@ -912,12 +955,11 @@ const AppCreator = (defaultprops) => { if (schemas.length === 1) { const parameter = handleGetRef({ $ref: schemas[0] }, data); - if ( - parameter.properties !== undefined && - parameter["type"] === "object" - ) { + console.log("Reading type from parameter: ", parameter) + if (parameter.properties !== undefined && parameter["type"] === "object") { + var newbody = {}; - for (let [propkey,propkeyval] in parameter.properties.entries()) { + for (let propkey in parameter.properties) { console.log("propkey2: ", propkey) const parsedkey = propkey.replaceAll(" ", "_").toLowerCase(); if (parameter.properties[propkey].type === undefined) { @@ -987,7 +1029,6 @@ const AppCreator = (defaultprops) => { methodvalue.responses.default.content["text/plain"] !== undefined ) { - console.log("RESP: ", path, methodvalue.responses.default.content["text/plain"]) if ( methodvalue.responses.default.content["text/plain"][ "schema" @@ -1039,19 +1080,15 @@ const AppCreator = (defaultprops) => { ], data ); - //console.log("GOT REF RETURN AS EXAMPLE: ", parameter) - if ( - parameter.properties !== undefined && - parameter["type"] === "object" - ) { + console.log("Reading parameter type 2", parameter) + if (parameter.properties !== undefined && parameter["type"] === "object") { var newbody = {}; - for (let [propkey,propkeyval] in parameter.properties.entries()) { + for (let propkey in parameter.properties) { console.log("propkey3: ", propkey) + const parsedkey = propkey.replaceAll(" ", "_").toLowerCase(); - if ( - parameter.properties[propkey].type === undefined - ) { + if (parameter.properties[propkey].type === undefined) { console.log( "Skipping (1): ", parameter.properties[propkey] @@ -1130,12 +1167,11 @@ const AppCreator = (defaultprops) => { selectedComponent, data ); - if ( - parameter.properties !== undefined && - parameter["type"] === "object" - ) { + + console.log("Reading parameter type 3!") + if (parameter.properties !== undefined && parameter["type"] === "object") { var newbody = {}; - for (let [propkey,propkeyval] in parameter.properties.entries()) { + for (let propkey in parameter.properties) { console.log("propkey4: ", propkey) const parsedkey = propkey.replaceAll(" ", "_").toLowerCase(); if ( @@ -1214,12 +1250,11 @@ const AppCreator = (defaultprops) => { ]["properties"]["data"], data ); - if ( - parameter.properties !== undefined && - parameter["type"] === "object" - ) { + + console.log("Reading type 3: ", parameter) + if (parameter.properties !== undefined && parameter["type"] === "object") { var newbody = {}; - for (let [propkey,keyval] in parameter.properties.entries()) { + for (let propkey in parameter.properties) { console.log("propkey5: ", propkey) const parsedkey = propkey .replaceAll(" ", "_") @@ -1287,8 +1322,8 @@ const AppCreator = (defaultprops) => { } } - for (let [key,keyval] in methodvalue.parameters.entries()) { - const parameter = handleGetRef(methodvalue.parameters[key], data); + for (let paramkey in methodvalue.parameters) { + const parameter = handleGetRef(methodvalue.parameters[paramkey], data); if (parameter.in === "query") { var tmpaction = { description: parameter.description, @@ -1334,8 +1369,9 @@ const AppCreator = (defaultprops) => { if (Object.getOwnPropertyNames(wordlist).length === 0) { for (let [newpath, pathvalue] of Object.entries(data.paths)) { const newpathsplit = newpath.split("/"); - for (let [key,keyval] in newpathsplit.entries()) { - const pathitem = newpathsplit[key].toLowerCase(); + + for (let splitkey in newpathsplit) { + const pathitem = newpathsplit[splitkey].toLowerCase(); if (wordlist[pathitem] === undefined) { wordlist[pathitem] = 1; } else { @@ -1351,8 +1387,8 @@ const AppCreator = (defaultprops) => { const urlsplit = path.split("/"); if (urlsplit.length > 0) { var curname = ""; - for (let [key,keyval] in urlsplit.entries()) { - var subpath = urlsplit[key]; + for (let urlkey in urlsplit) { + var subpath = urlsplit[urlkey]; if (wordlist[subpath] > 2 || subpath.length < 1) { continue; } @@ -1396,8 +1432,7 @@ const AppCreator = (defaultprops) => { } } - - + newaction.action_label = "No Label" newActions.push(newaction); } } @@ -1413,11 +1448,11 @@ const AppCreator = (defaultprops) => { const regex = /{\w+}/g; const found = firstUrl.match(regex); if (found !== null) { - for (let [key,keyval] in found.entries()) { - const item = found[key].slice(1, found[key].length - 1); + for (let foundkey in found) { + const item = found[foundkey].slice(1, found[foundkey].length - 1); const foundVar = data.servers[0].variables[item]; if (foundVar["default"] !== undefined) { - firstUrl = firstUrl.replace(found[key], foundVar["default"]); + firstUrl = firstUrl.replace(found[foundkey], foundVar["default"]); } } } @@ -1436,7 +1471,6 @@ const AppCreator = (defaultprops) => { console.log("NEWAUTH: ", securitySchemes) // FIXME: Should add Oauth2 (Microsoft) and JWT (Wazuh) //console.log("SECURITY: ", securitySchemes) - //if (Object.entries(securitySchemes) > 1 && var newauth = []; try { var optionset = false @@ -1558,9 +1592,7 @@ const AppCreator = (defaultprops) => { setOauth2Scopes(value[flowkey][basekey].scopes); } else { var newscopes = []; - for (let [scopekey, scopevalue] of Object.entries( - value[flowkey][basekey].scopes - )) { + for (let [scopekey, scopevalue] of Object.entries(value[flowkey][basekey].scopes)) { if (scopekey.startsWith("http")) { const scopekeysplit = scopekey.split("/"); if (scopekeysplit.length < 5) { @@ -1683,8 +1715,8 @@ const AppCreator = (defaultprops) => { if (newWorkflowTags.length > 0) { var newtags = []; - for (let [key,keyval] in newWorkflowTags.entries()) { - newtags.push({ name: newWorkflowTags[key] }); + for (let tagkey in newWorkflowTags) { + newtags.push({ name: newWorkflowTags[tagkey] }); } data["tags"] = newtags; @@ -1696,8 +1728,8 @@ const AppCreator = (defaultprops) => { // Handles actions var handledPaths = [] - for (let [key,keyval] in actions.entries()) { - var item = JSON.parse(JSON.stringify(actions[key])) + for (let actionkey in actions) { + var item = JSON.parse(JSON.stringify(actions[actionkey])) if (item.errors.length > 0) { alert.error("Saving with error in action " + item.name); } @@ -1822,7 +1854,7 @@ const AppCreator = (defaultprops) => { if (item.queries.length > 0) { var skipped = false; var querynames = [] - for (let [querykey,querykeyval] in item.queries.entries()) { + for (let querykey in item.queries) { const queryitem = item.queries[querykey]; if (queryitem === undefined || queryitem === null || queryitem.name === undefined || queryitem.name === null || queryitem.name === "") { @@ -1923,7 +1955,7 @@ const AppCreator = (defaultprops) => { //data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem) if (item.paths.length > 0) { - for (let [querykey,querykeyval] in item.paths.entries()) { + for (let querykey in item.paths) { const queryitem = item.paths[querykey]; if (queryitem.toLowerCase() == "url") { @@ -1948,9 +1980,7 @@ const AppCreator = (defaultprops) => { newitem.description = queryitem.description; } - data.paths[item.url][item.method.toLowerCase()].parameters.push( - newitem - ); + data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem); //console.log(queryitem) } } else { @@ -1958,7 +1988,7 @@ const AppCreator = (defaultprops) => { const values = getCurrentPaths(item.url); const paths = values[0]; - for (let [querykey,querykeyval] in paths.entries()) { + for (let querykey in paths) { const queryitem = paths[querykey]; newitem = { in: "path", @@ -1996,25 +2026,25 @@ const AppCreator = (defaultprops) => { // but it's the only way we can properly support e.g. GraphQL // with good examples var newbody = "" - for (let [key,keyval] in item.body.entries()) { - if (item.body[key] === "$") { - if (key > 0) { - //console.log("Found: ", item.body[key-1]) - const newkey = parseInt(key, 10) + for (let bodykey in item.body) { + if (item.body[bodykey] === "$") { + if (bodykey > 0) { + + const newkey = parseInt(bodykey, 10) if (item.body[newkey-1] !== "\\") { if (item.body[newkey+1] !== "\{") { newbody += "\\" } } - newbody += item.body[key] + newbody += item.body[bodykey] } else { newbody += "\\" - newbody += item.body[key] + newbody += item.body[bodykey] } - //newbody += item.body[key] + } else { - newbody += item.body[key] + newbody += item.body[bodykey] } } @@ -2118,42 +2148,43 @@ const AppCreator = (defaultprops) => { const required = false; const headersSplit = item.headers.split("\n"); - for (let [key,keyval] in headersSplit.entries()) { - const header = headersSplit[key]; - // var key = ""; + for (let headerkey in headersSplit) { + const header = headersSplit[headerkey]; + + var innerkey = "" var value = ""; if (header.length > 0 && header.includes("= ")) { const headersplit = header.split("= "); - key = headersplit[0]; + innerkey = headersplit[0]; value = headersplit[1]; } else if (header.length > 0 && header.includes(" =")) { const headersplit = header.split(" ="); - key = headersplit[0]; + innerkey = headersplit[0]; value = headersplit[1]; } else if (header.length > 0 && header.includes("=")) { const headersplit = header.split("="); - key = headersplit[0]; + innerkey = headersplit[0]; value = headersplit[1]; } else if (header.length > 0 && header.includes(": ")) { const headersplit = header.split(": "); - key = headersplit[0]; + innerkey = headersplit[0]; value = headersplit[1]; } else if (header.length > 0 && header.includes(" :")) { const headersplit = header.split(" :"); - key = headersplit[0]; + innerkey = headersplit[0]; value = headersplit[1]; } else if (header.length > 0 && header.includes(":")) { const headersplit = header.split(":"); - key = headersplit[0]; + innerkey = headersplit[0]; value = headersplit[1]; } else { continue; } - if (key.length > 0 && value.length > 0) { + if (innerkey.length > 0 && value.length > 0) { newitem = { in: "header", - name: key, + name: innerkey, multiline: false, description: "Header generated by shuffler.io OpenAPI", required: false, @@ -2235,8 +2266,8 @@ const AppCreator = (defaultprops) => { } if (setExtraAuth.length > 0) { - for (var key in extraAuth) { - const curauth = extraAuth[key]; + for (let authkey in extraAuth) { + const curauth = extraAuth[authkey]; if (curauth.name.toLowerCase() == "url") { alert.error("Can't add extra auth with Name URL"); @@ -2327,30 +2358,6 @@ const AppCreator = (defaultprops) => {
) : null; - // API key - //const verifyBaseUrl = () => { - // if (baseUrl.startsWith("http://") || baseUrl.startsWith("https://")) { - // return true - // } - - // if (baseUrl.endsWith("/")) { - // return true - // } - // - // return false - //} - - //const verifyApiParameter = () => { - // const notAllowed = ["!","#","$","%","&","'","^","+","-",".","_","~","|","]","+","$",] - // for (var key in notAllowed) { - // if (parameterName.includes(notAllowed[key])) { - // return false - // } - // } - - // return true - //} - const testAction = (index) => { console.log("Should test action at index " + index); console.log(actions[index]); @@ -3021,6 +3028,9 @@ const AppCreator = (defaultprops) => {
); + const foundCategory = newWorkflowCategories !== undefined && newWorkflowCategories !== null && newWorkflowCategories.length > 0 ? categories.find((x) => x.name === newWorkflowCategories[0]) : undefined + const actionLabels = foundCategory !== undefined && foundCategory !== null && foundCategory.action_labels.length > 0 ? ["No Label"].concat(foundCategory.action_labels) : [] + const loopActions = actions.length === 0 ? null : (
@@ -3157,6 +3167,48 @@ const AppCreator = (defaultprops) => {
*/} + + {/* From 2023: Example of handling action labels */} + {/*actionLabels.length > 0 && newWorkflowCategories !== undefined && newWorkflowCategories !== null && newWorkflowCategories.length > 0 && categories.length > 0 ? + ( + + ) + : null*/} + { ); - const categories = [ - "Communication", - "Cases", - "SIEM", - "Assets", - "Intel", - "IAM", - "Network", - "Eradication", - "Other", - ]; const tagView = (
@@ -4094,7 +4135,7 @@ const AppCreator = (defaultprops) => { }} /> */} -

Categories

+

Choose a Category