From 5964f914b962ae41a629dea5ce016106ad2c1cbe Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Wed, 29 May 2024 17:05:23 +0530 Subject: [PATCH 01/22] Fixed the Re-rendering issue of Apps/Actions & Triggers --- frontend/src/components/ParsedAction.jsx | 2455 +++++++++++----------- frontend/src/views/AngularWorkflow.jsx | 811 ++++--- 2 files changed, 1586 insertions(+), 1680 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 0190a6bd..c90e7747 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -182,7 +182,14 @@ const ParsedAction = (props) => { const [hiddenDescription, setHiddenDescription] = React.useState(true); const [autoCompleting, setAutocompleting] = React.useState(false); - + const [selectedActionParameters, setSelectedActionParameters] = React.useState([]); + const [selectedVariableParameter, setSelectedVariableParameter] = React.useState(""); + const [actionlist, setActionlist] = React.useState([]); + const [jsonList, setJsonList] = React.useState([]); + const [showDropdown, setShowDropdown] = React.useState(false); + const [showDropdownNumber, setShowDropdownNumber] = React.useState(0); + const [showAutocomplete, setShowAutocomplete] = React.useState(false); + const [menuPosition, setMenuPosition] = useState(null); const isIntegration = selectedAction.app_id === "integration" useEffect(() => { @@ -372,15 +379,6 @@ const ParsedAction = (props) => { //setStartNode(selectedAction.id) }; - const AppActionArguments = (props) => { - const [selectedActionParameters, setSelectedActionParameters] = React.useState([]); - const [selectedVariableParameter, setSelectedVariableParameter] = React.useState(""); - const [actionlist, setActionlist] = React.useState([]); - const [jsonList, setJsonList] = React.useState([]); - const [showDropdown, setShowDropdown] = React.useState(false); - const [showDropdownNumber, setShowDropdownNumber] = React.useState(0); - const [showAutocomplete, setShowAutocomplete] = React.useState(false); - const [menuPosition, setMenuPosition] = useState(null); useEffect(() => { if (selectedActionParameters !== undefined && selectedActionParameters !== null && selectedActionParameters.length === 0 @@ -1185,7 +1183,6 @@ const ParsedAction = (props) => { } // FIXME: Issue #40 - selectedActionParameters not reset - if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0) { var wrapperapp = { "id": "", @@ -1217,8 +1214,1198 @@ const ParsedAction = (props) => { // Check the actual value and if it's the same noAppSelected = true } - return ( -
+ + + const ActionSelectOption = (actionprops) => { + const { data, newActionname, newActiondescription, useIcon, extraDescription, } = actionprops; + const [hover, setHover] = React.useState(false); + + return ( + +
setHover(true)} onMouseLeave={() => setHover(false)} + onClick={() => { + //setSelectedAction(actionprops) + //setShowActionList(false) + //setUpdate(Math.random()) + // + if (data !== undefined && data !== null) { + setNewSelectedAction({ + target: { + value: data.name + } + }); + } + }} + > +
+ + {useIcon} + + {newActionname} +
+ {extraDescription.length > 0 ? + + {extraDescription} + + : null} +
+
+ ) + } + + const sortByCategoryLabel = (a, b) => { + const aHasCategoryLabel = a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0 + const bHasCategoryLabel = b.category_label !== undefined && b.category_label !== null && b.category_label.length > 0 + + // Sort by existence and length of "category_label" + if (aHasCategoryLabel && !bHasCategoryLabel) { + return -1 + } else if (!aHasCategoryLabel && bHasCategoryLabel) { + return 1 + } else { + return 0 + } + } + + // Function to deduplicate based on the "name" field + const deduplicateByName = (array) => { + const uniqueNames = {}; + return array.filter(item => { + if (!item.hasOwnProperty('name') || !item.name.length) { + return true + } + if (!uniqueNames[item.name]) { + uniqueNames[item.name] = true + return true + } + return false + }) + } + + // Gets the most important actions first + const renderedActionOptions = deduplicateByName(( + selectedApp.actions === undefined || selectedApp.actions === null ? [] : + selectedApp.actions.filter((a) => + a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label")) + ).sort(sortByCategoryLabel)) + + + const selectedAppIcon = selectedAction.large_image + var baselabel = selectedAction.label + return ( +
+ + {hideExtraTypes === true ? null : ( + +
+
+
{ + //window.open("/apps/${selectedAction.app_id}", "_blank") + }} + > + + + +

+ {( + selectedAction.app_name.charAt(0).toUpperCase() + + selectedAction.app_name.substring(1) + ).replaceAll("_", " ")} +

+
+
+ { + if (workflowExecutions.length > 0) { + // Look for the ID + var found = false; + for (let [key,keyval] in Object.entries(workflowExecutions)) { + if (workflowExecutions[key].results === undefined || workflowExecutions[key].results === null) { + continue; + } + + var foundResult = workflowExecutions[key].results.find( + (result) => result.action.id === selectedAction.id + ) + + if (foundResult === undefined || foundResult === null) { + continue; + } + + const oldstartnode = cy.getElementById(selectedAction.id); + if (oldstartnode !== undefined && oldstartnode !== null) { + const foundname = oldstartnode.data("label") + if (foundname !== undefined && foundname !== null) { + foundResult.action.label = foundname + } + } + + setSelectedResult(foundResult); + if (setCodeModalOpen !== undefined) { + setCodeModalOpen(true); + + found = true + } + + break; + } + + if (!found) { + toast("No result for this action yet. Please run the workflow first.") + } + } + }} + > + + + + + { + setAuthenticationModalOpen(true) + }} + > + + + + + {/* + {}} + > + + + + + + + */} + {/* + { + //setAuthenticationModalOpen(true); + console.log("Should enable/disable magic!") + console.log("Action: ", selectedAction) + if (selectedAction.run_magic_output === undefined) { + selectedAction.run_magic_output = true + } else { + if (selectedAction.run_magic_output === true) { + selectedAction.run_magic_output = false + } else { + selectedAction.run_magic_output = true + } + } + + setSelectedAction(selectedAction) + setUpdate(Math.random()); + }} + > + + + + + */} + {/* + { + }} + > + + + + + + + */} + { + //if (setAiQueryModalOpen !== undefined) { + // setAiQueryModalOpen(true) + //} else { + aiSubmit("Fill based on previous values", undefined, undefined, selectedAction) + //} + setAutocompleting(true) + }} + > + + {autoCompleting ? + + : + + } + + +
+
+
+ {/*selectedAction.id === workflow.start ? null : + + + + + */} + {selectedApp.versions !== null && + selectedApp.versions !== undefined && + selectedApp.versions.length > 1 ? ( + + ) : null} +
+
+
+
+ Name + { + // Copy the name value + const name = e.target.value + const parsedBaseLabel = "$"+baselabel.toLowerCase().replaceAll(" ", "_") + const newname = "$"+name.toLowerCase().replaceAll(" ", "_") + + // Check if it's the same as the current name in use + //if (name === selectedAction.label) { + // console.log("Returning from name thing") + // return + //} + + // Change in actions, triggers & conditions + // Highlight the changes somehow with a glow? + if (workflow.branches !== undefined && workflow.branches !== null) { + for (let [key,keyval] in Object.entries(workflow.branches)) { + if (workflow.branches[key].conditions !== undefined && workflow.branches[key].conditions !== null) { + 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 + + // Should have a smarter way of discovering node names + // Finding index(es) and replacing at the location + if (sourceparam.value.includes("$")) { + try { + var cnt = -1 + var previous = 0 + while (true) { + cnt += 1 + // Need to make sure e.g. changing the first here doesn't change the 2nd + // $change_me + // $change_me_2 + + const foundindex = sourceparam.value.toLowerCase().indexOf(parsedBaseLabel, previous) + if (foundindex === previous && foundindex !== 0) { + break + } + + if (foundindex >= 0) { + previous = foundindex+newname.length + // Need to add diff of length to word + + // Check location: + // If it's a-zA-Z_ then don't replace + if (sourceparam.value.length > foundindex+parsedBaseLabel.length) { + const regex = /[a-zA-Z0-9_]/g; + const match = sourceparam.value[foundindex+parsedBaseLabel.length].match(regex); + if (match !== null) { + continue + } + } + + console.log("Old found: ", workflow.branches[key].conditions[subkey].source.value) + const extralength = newname.length-parsedBaseLabel.length + sourceparam.value = sourceparam.value.substring(0, foundindex) + newname + sourceparam.value.substring(foundindex-extralength+newname.length, sourceparam.value.length) + + console.log("New: ", workflow.branches[key].conditions[subkey].source.value) + } else { + break + } + + // Break no matter what after 5 replaces. May need to increase + if (cnt >= 5) { + break + } + + } + } catch (e) { + console.log("Failed value replacement based on index: ", e) + } + } + + if (destinationparam.value.includes("$")) { + try { + var cnt = -1 + var previous = 0 + while (true) { + cnt += 1 + // Need to make sure e.g. changing the first here doesn't change the 2nd + // $change_me + // $change_me_2 + + const foundindex = destinationparam.value.toLowerCase().indexOf(parsedBaseLabel, previous) + if (foundindex === previous && foundindex !== 0) { + break + } + + if (foundindex >= 0) { + previous = foundindex+newname.length + // Need to add diff of length to word + + // Check location: + // If it's a-zA-Z_ then don't replace + if (destinationparam.value.length > foundindex+parsedBaseLabel.length) { + const regex = /[a-zA-Z0-9_]/g; + const match = destinationparam.value[foundindex+parsedBaseLabel.length].match(regex); + if (match !== null) { + continue + } + } + + console.log("Old found: ", workflow.branches[key].conditions[subkey].destination.value) + const extralength = newname.length-parsedBaseLabel.length + destinationparam.value = destinationparam.value.substring(0, foundindex) + newname + destinationparam.value.substring(foundindex-extralength+newname.length, destinationparam.value.length) + + console.log("New: ", workflow.branches[key].conditions[subkey].destination.value) + } else { + break + } + + // Break no matter what after 5 replaces. May need to increase + if (cnt >= 5) { + break + } + + } + } catch (e) { + console.log("Failed value replacement based on index: ", e) + } + } + } + } + } + } + + for (let [key,keyval] in Object.entries(workflow.actions)) { + if (workflow.actions[key].id === selectedAction.id) { + continue + } + + const params = workflow.actions[key].parameters + console.log(params) + if (params === null || params === undefined) { + continue + } + + for (let [subkey, subkeyval] in Object.entries(params)) { + const param = workflow.actions[key].parameters[subkey]; + if (!param.value.includes("$")) { + continue + } + + // Should have a smarter way of discovering node names + // Do regex? + // Finding index(es) and replacing at the location + // + + try { + var cnt = -1 + var previous = 0 + while (true) { + cnt += 1 + // Need to make sure e.g. changing the first here doesn't change the 2nd + // $change_me + // $change_me_2 + + const foundindex = param.value.toLowerCase().indexOf(parsedBaseLabel, previous) + if (foundindex === previous && foundindex !== 0) { + break + } + + if (foundindex >= 0) { + previous = foundindex+newname.length + // Need to add diff of length to word + + // Check location: + // If it's a-zA-Z_ then don't replace + if (param.value.length > foundindex+parsedBaseLabel.length) { + const regex = /[a-zA-Z0-9_]/g; + const match = param.value[foundindex+parsedBaseLabel.length].match(regex); + if (match !== null) { + continue + } + } + + console.log("Old found: ", workflow.actions[key].parameters[subkey].value) + const extralength = newname.length-parsedBaseLabel.length + param.value = param.value.substring(0, foundindex) + newname + param.value.substring(foundindex-extralength+newname.length, param.value.length) + + console.log("New: ", workflow.actions[key].parameters[subkey].value) + } else { + break + } + + // Break no matter what after 5 replaces. May need to increase + if (cnt >= 5) { + break + } + + } + } catch (e) { + console.log("Failed value replacement based on index: ", e) + } + } + } + + setWorkflow(workflow); + setUpdate(Math.random()); + baselabel = name + }} + /> +
+ {/*!isCloud ? null :*/} +
+ + + Delay + { + if (actionDelayChange !== undefined) { + actionDelayChange(event) + } + }} + /> + + +
+ {/**/} +
+
+ )} + {selectedApp.name !== undefined && + selectedAction.authentication !== null && + selectedAction.authentication !== undefined && + selectedAction.authentication.length === 0 && + requiresAuthentication ? ( +
+ + + + + +
+ ) : null} + + {selectedAction.authentication !== undefined && + selectedAction.authentication !== null && + selectedAction.authentication.length > 0 ? ( +
+ Authentication +
+ + + {/* + + + curaction.authentication = authenticationOptions + if (curaction.selectedAuthentication === null || curaction.selectedAuthentication === undefined || curaction.selectedAuthentication.length === "") + */} + + { + setAuthenticationModalOpen(true); + }} + > + + + +
+
+ ) : null} + + {showEnvironment !== undefined && showEnvironment && environments.length > 1 && !isIntegration ? ( +
+ Environment + +
+ ) : null} + + {workflow.execution_variables !== undefined && + workflow.execution_variables !== null && + workflow.execution_variables.length > 0 ? ( +
+ Execution variable (optional) + +
+ ) : null} + + +
+ {/*hideExtraTypes ? null : +
+ Actions +
+ */} + + {setNewSelectedAction !== undefined ? ( + { + // Most popular + // Is categorized + // Uncategorized + return option.category_label !== undefined && option.category_label !== null && option.category_label.length > 0 ? "Most used" : "All Actions"; + }} + renderGroup={(params) => { + + return ( +
  • + {params.group} + {params.children} +
  • + ) + }} + options={renderedActionOptions} + ListboxProps={{ + style: { + backgroundColor: theme.palette.surfaceColor, + color: "white", + }, + }} + filterOptions={(options, { inputValue }) => { + //console.log("Option contains?: ", inputValue, options) + const lowercaseValue = inputValue.toLowerCase() + options = options.filter(x => x.name.replaceAll("_", " ").toLowerCase().includes(lowercaseValue) || x.description.toLowerCase().includes(lowercaseValue)) + + return options + }} + getOptionLabel={(option) => { + if (option === undefined || option === null || option.name === undefined || option.name === null ) { + return null; + } + + const newname = ( + option.name.charAt(0).toUpperCase() + option.name.substring(1) + ).replaceAll("_", " "); + + return newname; + }} + fullWidth + style={{ + backgroundColor: theme.palette.inputColor, + height: 50, + borderRadius: theme.palette.borderRadius, + }} + onChange={(event, newValue) => { + // Workaround with event lol + if (newValue !== undefined && newValue !== null) { + setNewSelectedAction({ + target: { + value: newValue.name + } + }); + } + }} + renderOption={(props, data, state) => { + var newActionname = data.name; + if (data.label !== undefined && data.label !== null && data.label.length > 0) { + newActionname = data.label; + } + + var newActiondescription = data.description; + //console.log("DESC: ", newActiondescription) + if (data.description === undefined || data.description === null) { + newActiondescription = "Description: No description defined for this action" + } else { + newActiondescription = "Description: "+newActiondescription + } + + const iconInfo = GetIconInfo({ name: data.name }); + const useIcon = iconInfo.originalIcon; + + if (newActionname === undefined || newActionname === null) { + newActionname = "No name" + data.name = "No name" + data.label = "No name" + } + + newActionname = (newActionname.charAt(0).toUpperCase() + newActionname.substring(1)).replaceAll("_", " "); + + var method = "" + var extraDescription = "" + if (data.name.includes("get_")) { + method = "GET" + } else if (data.name.includes("post_")) { + method = "POST" + } else if (data.name.includes("put_")) { + method = "PUT" + } else if (data.name.includes("patch_")) { + method = "PATCH" + } else if (data.name.includes("delete_")) { + method = "DELETE" + } else if (data.name.includes("options_")) { + method = "OPTIONS" + } else if (data.name.includes("connect_")) { + method = "CONNECT" + } + + // FIXME: Should it require a base URL? + if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) { + var extraUrl = "" + const descSplit = data.description.split("\n") + // Last line of descSplit + if (descSplit.length > 0) { + extraUrl = descSplit[descSplit.length-1] + } + + //for (let [line,lineval] in Object.entries(descSplit)) { + // if (descSplit[line].includes("http") && descSplit[line].includes("://")) { + // const urlsplit = descSplit[line].split("/") + // try { + // extraUrl = "/"+urlsplit.slice(3, urlsplit.length).join("/") + // } catch (e) { + // //console.log("Failed - running with -1") + // extraUrl = "/"+urlsplit.slice(3, urlsplit.length-1).join("/") + // } + + + // //console.log("NO BASEURL TOO!! Why missing last one in certain scenarios (sevco)?", extraUrl, urlsplit, descSplit[line]) + // //break + // } + //} + + if (extraUrl.length > 0) { + if (extraUrl.includes(" ")) { + extraUrl = extraUrl.split(" ")[0] + } + + if (extraUrl.includes("#")) { + extraUrl = extraUrl.split("#")[0] + } + + extraDescription = `${method} ${extraUrl}` + } else { + //console.log("No url found. Check again :)") + } + } + + return ( + + ); + }} + 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 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) { + params.inputProps.value = params.inputProps.value.charAt(0).toUpperCase()+params.inputProps.value.substring(1) + } + break + } + } + + // Check if it starts with "Get List" and method is "Get" + if (params.inputProps.value.startsWith("Get List")) { + console.log("Get List") + } + } + + return ( + + ); + }} + /> + ) : null} + + {/*setNewSelectedAction !== undefined ? + + : null*/} + +
    { + Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0 ? +
    {isIntegration ? apps !== undefined && apps !== null && apps.length > 0 ?
    @@ -2984,1247 +4171,9 @@ const ParsedAction = (props) => { ); })}
    - ); - } - return null; - }; - - - const ActionSelectOption = (actionprops) => { - const { data, newActionname, newActiondescription, useIcon, extraDescription, } = actionprops; - const [hover, setHover] = React.useState(false); - - return ( - -
    setHover(true)} onMouseLeave={() => setHover(false)} - onClick={() => { - //setSelectedAction(actionprops) - //setShowActionList(false) - //setUpdate(Math.random()) - // - if (data !== undefined && data !== null) { - setNewSelectedAction({ - target: { - value: data.name - } - }); - } - }} - > -
    - - {useIcon} - - {newActionname} -
    - {extraDescription.length > 0 ? - - {extraDescription} - - : null} -
    -
    - ) - } - - const sortByCategoryLabel = (a, b) => { - const aHasCategoryLabel = a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0 - const bHasCategoryLabel = b.category_label !== undefined && b.category_label !== null && b.category_label.length > 0 - - // Sort by existence and length of "category_label" - if (aHasCategoryLabel && !bHasCategoryLabel) { - return -1 - } else if (!aHasCategoryLabel && bHasCategoryLabel) { - return 1 - } else { - return 0 - } - } - - // Function to deduplicate based on the "name" field - const deduplicateByName = (array) => { - const uniqueNames = {}; - return array.filter(item => { - if (!item.hasOwnProperty('name') || !item.name.length) { - return true + : null } - if (!uniqueNames[item.name]) { - uniqueNames[item.name] = true - return true - } - return false - }) - } - - // Gets the most important actions first - const renderedActionOptions = deduplicateByName(( - selectedApp.actions === undefined || selectedApp.actions === null ? [] : - selectedApp.actions.filter((a) => - a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label")) - ).sort(sortByCategoryLabel)) - - const selectedAppIcon = selectedAction.large_image - var baselabel = selectedAction.label - return ( -
    - - {hideExtraTypes === true ? null : ( - -
    -
    -
    { - //window.open("/apps/${selectedAction.app_id}", "_blank") - }} - > - - - -

    - {( - selectedAction.app_name.charAt(0).toUpperCase() + - selectedAction.app_name.substring(1) - ).replaceAll("_", " ")} -

    -
    -
    - { - if (workflowExecutions.length > 0) { - // Look for the ID - var found = false; - for (let [key,keyval] in Object.entries(workflowExecutions)) { - if (workflowExecutions[key].results === undefined || workflowExecutions[key].results === null) { - continue; - } - - var foundResult = workflowExecutions[key].results.find( - (result) => result.action.id === selectedAction.id - ) - - if (foundResult === undefined || foundResult === null) { - continue; - } - - const oldstartnode = cy.getElementById(selectedAction.id); - if (oldstartnode !== undefined && oldstartnode !== null) { - const foundname = oldstartnode.data("label") - if (foundname !== undefined && foundname !== null) { - foundResult.action.label = foundname - } - } - - setSelectedResult(foundResult); - if (setCodeModalOpen !== undefined) { - setCodeModalOpen(true); - - found = true - } - - break; - } - - if (!found) { - toast.info("No result for this action yet. Please run the workflow first.") - } - } else { - toast.info("No workflow runs to search through. Run the workflow first.") - } - }} - > - - - - - { - setAuthenticationModalOpen(true) - }} - > - - - - - {/* - {}} - > - - - - - - - */} - {/* - { - //setAuthenticationModalOpen(true); - console.log("Should enable/disable magic!") - console.log("Action: ", selectedAction) - if (selectedAction.run_magic_output === undefined) { - selectedAction.run_magic_output = true - } else { - if (selectedAction.run_magic_output === true) { - selectedAction.run_magic_output = false - } else { - selectedAction.run_magic_output = true - } - } - - setSelectedAction(selectedAction) - setUpdate(Math.random()); - }} - > - - - - - */} - {/* - { - }} - > - - - - - - - */} - { - //if (setAiQueryModalOpen !== undefined) { - // setAiQueryModalOpen(true) - //} else { - aiSubmit("Fill based on previous values", undefined, undefined, selectedAction) - //} - setAutocompleting(true) - }} - > - - {autoCompleting ? - - : - - } - - -
    -
    -
    - {/*selectedAction.id === workflow.start ? null : - - - - - */} - {selectedApp.versions !== null && - selectedApp.versions !== undefined && - selectedApp.versions.length > 1 ? ( - - ) : null} -
    -
    -
    -
    - Name - { - // Copy the name value - const name = e.target.value - const parsedBaseLabel = "$"+baselabel.toLowerCase().replaceAll(" ", "_") - const newname = "$"+name.toLowerCase().replaceAll(" ", "_") - - // Check if it's the same as the current name in use - //if (name === selectedAction.label) { - // console.log("Returning from name thing") - // return - //} - - // Change in actions, triggers & conditions - // Highlight the changes somehow with a glow? - if (workflow.branches !== undefined && workflow.branches !== null) { - for (let [key,keyval] in Object.entries(workflow.branches)) { - if (workflow.branches[key].conditions !== undefined && workflow.branches[key].conditions !== null) { - 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 - - // Should have a smarter way of discovering node names - // Finding index(es) and replacing at the location - if (sourceparam.value.includes("$")) { - try { - var cnt = -1 - var previous = 0 - while (true) { - cnt += 1 - // Need to make sure e.g. changing the first here doesn't change the 2nd - // $change_me - // $change_me_2 - - const foundindex = sourceparam.value.toLowerCase().indexOf(parsedBaseLabel, previous) - if (foundindex === previous && foundindex !== 0) { - break - } - - if (foundindex >= 0) { - previous = foundindex+newname.length - // Need to add diff of length to word - - // Check location: - // If it's a-zA-Z_ then don't replace - if (sourceparam.value.length > foundindex+parsedBaseLabel.length) { - const regex = /[a-zA-Z0-9_]/g; - const match = sourceparam.value[foundindex+parsedBaseLabel.length].match(regex); - if (match !== null) { - continue - } - } - - console.log("Old found: ", workflow.branches[key].conditions[subkey].source.value) - const extralength = newname.length-parsedBaseLabel.length - sourceparam.value = sourceparam.value.substring(0, foundindex) + newname + sourceparam.value.substring(foundindex-extralength+newname.length, sourceparam.value.length) - - console.log("New: ", workflow.branches[key].conditions[subkey].source.value) - } else { - break - } - - // Break no matter what after 5 replaces. May need to increase - if (cnt >= 5) { - break - } - - } - } catch (e) { - console.log("Failed value replacement based on index: ", e) - } - } - - if (destinationparam.value.includes("$")) { - try { - var cnt = -1 - var previous = 0 - while (true) { - cnt += 1 - // Need to make sure e.g. changing the first here doesn't change the 2nd - // $change_me - // $change_me_2 - - const foundindex = destinationparam.value.toLowerCase().indexOf(parsedBaseLabel, previous) - if (foundindex === previous && foundindex !== 0) { - break - } - - if (foundindex >= 0) { - previous = foundindex+newname.length - // Need to add diff of length to word - - // Check location: - // If it's a-zA-Z_ then don't replace - if (destinationparam.value.length > foundindex+parsedBaseLabel.length) { - const regex = /[a-zA-Z0-9_]/g; - const match = destinationparam.value[foundindex+parsedBaseLabel.length].match(regex); - if (match !== null) { - continue - } - } - - console.log("Old found: ", workflow.branches[key].conditions[subkey].destination.value) - const extralength = newname.length-parsedBaseLabel.length - destinationparam.value = destinationparam.value.substring(0, foundindex) + newname + destinationparam.value.substring(foundindex-extralength+newname.length, destinationparam.value.length) - - console.log("New: ", workflow.branches[key].conditions[subkey].destination.value) - } else { - break - } - - // Break no matter what after 5 replaces. May need to increase - if (cnt >= 5) { - break - } - - } - } catch (e) { - console.log("Failed value replacement based on index: ", e) - } - } - } - } - } - } - - for (let [key,keyval] in Object.entries(workflow.actions)) { - if (workflow.actions[key].id === selectedAction.id) { - continue - } - - const params = workflow.actions[key].parameters - console.log(params) - if (params === null || params === undefined) { - continue - } - - for (let [subkey, subkeyval] in Object.entries(params)) { - const param = workflow.actions[key].parameters[subkey]; - if (!param.value.includes("$")) { - continue - } - - // Should have a smarter way of discovering node names - // Do regex? - // Finding index(es) and replacing at the location - // - - try { - var cnt = -1 - var previous = 0 - while (true) { - cnt += 1 - // Need to make sure e.g. changing the first here doesn't change the 2nd - // $change_me - // $change_me_2 - - const foundindex = param.value.toLowerCase().indexOf(parsedBaseLabel, previous) - if (foundindex === previous && foundindex !== 0) { - break - } - - if (foundindex >= 0) { - previous = foundindex+newname.length - // Need to add diff of length to word - - // Check location: - // If it's a-zA-Z_ then don't replace - if (param.value.length > foundindex+parsedBaseLabel.length) { - const regex = /[a-zA-Z0-9_]/g; - const match = param.value[foundindex+parsedBaseLabel.length].match(regex); - if (match !== null) { - continue - } - } - - console.log("Old found: ", workflow.actions[key].parameters[subkey].value) - const extralength = newname.length-parsedBaseLabel.length - param.value = param.value.substring(0, foundindex) + newname + param.value.substring(foundindex-extralength+newname.length, param.value.length) - - console.log("New: ", workflow.actions[key].parameters[subkey].value) - } else { - break - } - - // Break no matter what after 5 replaces. May need to increase - if (cnt >= 5) { - break - } - - } - } catch (e) { - console.log("Failed value replacement based on index: ", e) - } - } - } - - setWorkflow(workflow); - setUpdate(Math.random()); - baselabel = name - }} - /> -
    - {/*!isCloud ? null :*/} -
    - - - Delay - { - if (actionDelayChange !== undefined) { - actionDelayChange(event) - } - }} - /> - - -
    - {/**/} -
    -
    - )} - {selectedApp.name !== undefined && - selectedAction.authentication !== null && - selectedAction.authentication !== undefined && - selectedAction.authentication.length === 0 && - requiresAuthentication ? ( -
    - - - - - -
    - ) : null} - - {selectedAction.authentication !== undefined && - selectedAction.authentication !== null && - selectedAction.authentication.length > 0 ? ( -
    - Authentication -
    - - - {/* - - - curaction.authentication = authenticationOptions - if (curaction.selectedAuthentication === null || curaction.selectedAuthentication === undefined || curaction.selectedAuthentication.length === "") - */} - - { - setAuthenticationModalOpen(true); - }} - > - - - -
    -
    - ) : null} - - - {showEnvironment !== undefined && showEnvironment && environments.length > 1 && !isIntegration ? ( -
    - Environment - -
    - ) : null} - - {workflow.execution_variables !== undefined && - workflow.execution_variables !== null && - workflow.execution_variables.length > 0 ? ( -
    - Execution variable (optional) - -
    - ) : null} - - -
    - {/*hideExtraTypes ? null : -
    - Actions -
    - */} - - {setNewSelectedAction !== undefined ? ( - { - // Most popular - // Is categorized - // Uncategorized - return option.category_label !== undefined && option.category_label !== null && option.category_label.length > 0 ? "Most used" : "All Actions"; - }} - renderGroup={(params) => { - - return ( -
  • - {params.group} - {params.children} -
  • - ) - }} - options={renderedActionOptions} - ListboxProps={{ - style: { - backgroundColor: theme.palette.surfaceColor, - color: "white", - }, - }} - filterOptions={(options, { inputValue }) => { - //console.log("Option contains?: ", inputValue, options) - const lowercaseValue = inputValue.toLowerCase() - options = options.filter(x => x.name.replaceAll("_", " ").toLowerCase().includes(lowercaseValue) || x.description.toLowerCase().includes(lowercaseValue)) - - return options - }} - getOptionLabel={(option) => { - if (option === undefined || option === null || option.name === undefined || option.name === null ) { - return null; - } - - const newname = ( - option.name.charAt(0).toUpperCase() + option.name.substring(1) - ).replaceAll("_", " "); - - return newname; - }} - fullWidth - style={{ - backgroundColor: theme.palette.inputColor, - height: 50, - borderRadius: theme.palette.borderRadius, - }} - onChange={(event, newValue) => { - // Workaround with event lol - if (newValue !== undefined && newValue !== null) { - setNewSelectedAction({ - target: { - value: newValue.name - } - }); - } - }} - renderOption={(props, data, state) => { - var newActionname = data.name; - if (data.label !== undefined && data.label !== null && data.label.length > 0) { - newActionname = data.label; - } - - var newActiondescription = data.description; - //console.log("DESC: ", newActiondescription) - if (data.description === undefined || data.description === null) { - newActiondescription = "Description: No description defined for this action" - } else { - newActiondescription = "Description: "+newActiondescription - } - - const iconInfo = GetIconInfo({ name: data.name }); - const useIcon = iconInfo.originalIcon; - - if (newActionname === undefined || newActionname === null) { - newActionname = "No name" - data.name = "No name" - data.label = "No name" - } - - newActionname = (newActionname.charAt(0).toUpperCase() + newActionname.substring(1)).replaceAll("_", " "); - - var method = "" - var extraDescription = "" - if (data.name.includes("get_")) { - method = "GET" - } else if (data.name.includes("post_")) { - method = "POST" - } else if (data.name.includes("put_")) { - method = "PUT" - } else if (data.name.includes("patch_")) { - method = "PATCH" - } else if (data.name.includes("delete_")) { - method = "DELETE" - } else if (data.name.includes("options_")) { - method = "OPTIONS" - } else if (data.name.includes("connect_")) { - method = "CONNECT" - } - - // FIXME: Should it require a base URL? - if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) { - var extraUrl = "" - const descSplit = data.description.split("\n") - // Last line of descSplit - if (descSplit.length > 0) { - extraUrl = descSplit[descSplit.length-1] - } - - //for (let [line,lineval] in Object.entries(descSplit)) { - // if (descSplit[line].includes("http") && descSplit[line].includes("://")) { - // const urlsplit = descSplit[line].split("/") - // try { - // extraUrl = "/"+urlsplit.slice(3, urlsplit.length).join("/") - // } catch (e) { - // //console.log("Failed - running with -1") - // extraUrl = "/"+urlsplit.slice(3, urlsplit.length-1).join("/") - // } - - - // //console.log("NO BASEURL TOO!! Why missing last one in certain scenarios (sevco)?", extraUrl, urlsplit, descSplit[line]) - // //break - // } - //} - - if (extraUrl.length > 0) { - if (extraUrl.includes(" ")) { - extraUrl = extraUrl.split(" ")[0] - } - - if (extraUrl.includes("#")) { - extraUrl = extraUrl.split("#")[0] - } - - extraDescription = `${method} ${extraUrl}` - } else { - //console.log("No url found. Check again :)") - } - } - - return ( - - ); - }} - 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 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) { - params.inputProps.value = params.inputProps.value.charAt(0).toUpperCase()+params.inputProps.value.substring(1) - } - break - } - } - - // Check if it starts with "Get List" and method is "Get" - if (params.inputProps.value.startsWith("Get List")) { - console.log("Get List") - } - } - - return ( - - ); - }} - /> - ) : null} - - {/*setNewSelectedAction !== undefined ? - - : null*/} - -
    - +
    diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 021cc0d6..cfd65edd 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -4225,6 +4225,283 @@ const AngularWorkflow = (defaultprops) => { } }) + // Should get AI autocompletes + const aiSubmit = (value, setResponseMsg, setSuggestionLoading, inputAction) => { + if (setResponseMsg !== undefined) { + setResponseMsg("") + } + + if (value === undefined || value === "") { + console.log("No value input!") + return + } + + if (setSuggestionLoading !== undefined) { + setSuggestionLoading(true) + } + + console.log("Submit conversation with value: ", value); + + // This is to find sample response and parse it as string + + var AppContext = [] + if (inputAction !== undefined && inputAction !== null) { + const parents = getParents(inputAction) + + console.log("Parents: ", parents) + var actionlist = [] + if (parents.length > 1) { + for (let [key,keyval] in Object.entries(parents)) { + const item = parents[key]; + if (item.label === "Execution Argument") { + continue; + } + + var exampledata = item.example === undefined || item.example === null ? "" : item.example; + // Find previous execution and their variables + //exampledata === "" && + if (workflowExecutions.length > 0) { + // Look for the ID + const found = false; + for (let [key,keyval] in Object.entries(workflowExecutions)) { + if (workflowExecutions[key].results === undefined || workflowExecutions[key].results === null) { + continue; + } + + var foundResult = workflowExecutions[key].results.find((result) => result.action.id === item.id); + if (foundResult === undefined || foundResult === null) { + continue; + } + + if (foundResult.result !== undefined && foundResult.result !== null) { + foundResult = foundResult.result + } + + const valid = validateJson(foundResult, true) + if (valid.valid) { + if (valid.result.success === false) { + //console.log("Skipping success false autocomplete") + } else { + exampledata = valid.result; + break; + } + } else { + exampledata = foundResult; + } + } + } + + // 1. Take + const itemlabelComplete = item.label === null || item.label === undefined ? "" : item.label.split(" ").join("_"); + + const actionvalue = { + app_name: item.app_name, + action_name: item.name, + label: item.label, + + type: "action", + id: item.id, + name: item.label, + autocomplete: itemlabelComplete, + example: exampledata, + }; + + actionlist.push(actionvalue); + } + } + + var fixedResults = [] + for (var i = 0; i < actionlist.length; i++) { + const item = actionlist[i]; + const responseFix = SetJsonDotnotation(item.example, "") + + // Check if json + const validated = validateJson(responseFix) + var exampledata = responseFix; + if (validated.valid) { + exampledata = JSON.stringify(validated.result) + } + + AppContext.push({ + "app_name": item.app_name, + "action_name": item.action_name, + "label": item.label, + "example": exampledata, + "example_response": exampledata, + }) + } + } + + var conversationData = { + "query": value, + "output_format": "action", + "app_context": AppContext, + + "workflow_id": workflow.id, + } + + if (inputAction !== undefined) { + console.log("Add app context! This should them get parameters directly") + conversationData.output_format = "action_parameters" + + conversationData.app_id = inputAction.app_id + conversationData.app_name = inputAction.app_name + conversationData.action_name = inputAction.name + conversationData.parameters = inputAction.parameters + + if (!value.includes(inputAction.label)) { + conversationData.query = inputAction.label.replaceAll("_", " ") + } + } + + // Onprem not available yet (April 2023) + // Should: Make OpenAI work for them with their own key + //fetch("https://shuffler.io/api/v1/conversation", { + fetch(`${globalUrl}/api/v1/conversation`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify(conversationData), + credentials: "include", + }) + .then((response) => { + if (setSuggestionLoading !== undefined) { + setSuggestionLoading(false) + } + + if (response.status !== 200) { + console.log("Status not 200 for stream results :O!"); + } + + return response.json(); + }) + .then((responseJson) => { + console.log("Conversation response: ", responseJson) + if (responseJson.success === false) { + if (responseJson.reason !== undefined) { + if (setResponseMsg !== undefined) { + setResponseMsg(responseJson.reason) + } + } + + return + } + + if (inputAction !== undefined) { + console.log("In input action! Should check params if they match, and add suggestions") + + if (responseJson.parameters === undefined || responseJson.parameters.length === 0) { + return + } + + var changed = false + + for (let paramkey in inputAction.parameters) { + const actionParam = inputAction.parameters[paramkey] + + if (actionParam.autocompleted === true) { + continue + } + + if (actionParam.configuration === true && actionParam.name !== "url") { + continue + } + + if (actionParam.value !== "" && actionParam.value !== actionParam.example) { + console.log("Skipping: ", actionParam) + continue + } + + for (let respParam of responseJson.parameters) { + if (respParam.name === actionParam.name) { + console.log("Found match for param: ", respParam) + + if (respParam.value === "") { + break + } + + changed = true + + inputAction.parameters[paramkey].autocompleted = true + inputAction.parameters[paramkey].value = respParam.value + break + } + } + } + + if (changed === true) { + console.log("Setting action! Force update pls :)") + setUpdate(Math.random()) + setSelectedAction(inputAction) + } + + return + } + + console.log("Suggestionbox location: ", suggestionBox) + + // Add action + if (responseJson.app_name !== undefined && responseJson.app_name !== null) { + // Always added to 0, 0 + // Should use suggestionBox.position.x, suggestionBox.position.y + var newitem = { + "data": responseJson, + "position": { + "x": suggestionBox.node_position.x !== undefined ? suggestionBox.node_position.x : 0, + "y": suggestionBox.node_position.y !== undefined ? suggestionBox.node_position.y + 100 : 0, + }, + "group": "nodes", + } + + newitem.type = "ACTION" + newitem.isStartNode = false + newitem.data.id = uuidv4() + newitem.data.type = "ACTION" + newitem.data.isStartNode = false + + newitem.data.is_valid = true + newitem.data.isValid = true + + cy.add({ + group: newitem.group, + data: newitem.data, + position: newitem.position, + }); + + // Add edge + const newId = uuidv4() + cy.add({ + group: "edges", + data: { + id: newId, + _id: newId, + source: suggestionBox.attachedTo, + target: newitem.data.id, + } + }) + //label: "Generated", + + setSuggestionBox({ + "position": { + "top": 500, + "left": 500, + }, + "open": false, + "attachedTo": "", + }); + } + }) + .catch((error) => { + if (setSuggestionLoading !== undefined) { + setSuggestionLoading(false) + } + + console.log("Conv response error: ", error); + }); + } + // Nodeselectbatching: // https://stackoverflow.com/questions/16677856/cy-onselect-callback-only-once // onNodeClick @@ -13647,7 +13924,48 @@ const AngularWorkflow = (defaultprops) => { workflow.triggers[selectedTriggerIndex].parameters.length > 2 ? workflow.triggers[selectedTriggerIndex].parameters[2].value : ""; - } + }else if( + selectedTrigger.trigger_type === "USERINPUT" + ){ + if ( + workflow.triggers[selectedTriggerIndex].parameters === undefined || + workflow.triggers[selectedTriggerIndex].parameters === null || + workflow.triggers[selectedTriggerIndex].parameters.length === 0 + ) { + workflow.triggers[selectedTriggerIndex].parameters = []; + workflow.triggers[selectedTriggerIndex].parameters[0] = { + name: "alertinfo", + value: "Do you want to continue the workflow? Start parameters: $exec", + }; + + // boolean, + workflow.triggers[selectedTriggerIndex].parameters[1] = { + name: "options", + value: "boolean", + }; + + // email,sms,app ... + workflow.triggers[selectedTriggerIndex].parameters[2] = { + name: "type", + value: "subflow", + }; + + workflow.triggers[selectedTriggerIndex].parameters[3] = { + name: "email", + value: "test@test.com", + }; + workflow.triggers[selectedTriggerIndex].parameters[4] = { + name: "sms", + value: "0000000", + }; + workflow.triggers[selectedTriggerIndex].parameters[5] = { + name: "subflow", + value: "", + }; + + setWorkflow(workflow); + } + } } const WebhookSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined || selectedTrigger.trigger_type !== "WEBHOOK" ? null : @@ -14442,48 +14760,7 @@ const AngularWorkflow = (defaultprops) => { }) } - const UserinputSidebar = () => { - if (Object.getOwnPropertyNames(selectedTrigger).length > 0 && workflow.triggers[selectedTriggerIndex] !== undefined) { - if ( - workflow.triggers[selectedTriggerIndex].parameters === undefined || - workflow.triggers[selectedTriggerIndex].parameters === null || - workflow.triggers[selectedTriggerIndex].parameters.length === 0 - ) { - workflow.triggers[selectedTriggerIndex].parameters = []; - workflow.triggers[selectedTriggerIndex].parameters[0] = { - name: "alertinfo", - value: "Do you want to continue the workflow? Start parameters: $exec", - }; - - // boolean, - workflow.triggers[selectedTriggerIndex].parameters[1] = { - name: "options", - value: "boolean", - }; - - // email,sms,app ... - workflow.triggers[selectedTriggerIndex].parameters[2] = { - name: "type", - value: "subflow", - }; - - workflow.triggers[selectedTriggerIndex].parameters[3] = { - name: "email", - value: "test@test.com", - }; - workflow.triggers[selectedTriggerIndex].parameters[4] = { - name: "sms", - value: "0000000", - }; - workflow.triggers[selectedTriggerIndex].parameters[5] = { - name: "subflow", - value: "", - }; - - setWorkflow(workflow); - } - - return ( + const UserinputSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined || selectedTrigger.trigger_type !== "USERINPUT" ? null :

    {selectedTrigger.app_name} @@ -14820,11 +15097,6 @@ const AngularWorkflow = (defaultprops) => {

    - ) - } - - return null - } const PipelineSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined && selectedTrigger.trigger_type !== "SCHEDULE" ? null :
    @@ -16677,115 +16949,17 @@ const AngularWorkflow = (defaultprops) => { }; const RightSideBar = (props) => { - const { - //workflow, - //setWorkflow, - //setSelectedAction, - //setUpdate, - //selectedApp, - //workflowExecutions, - //setSelectedResult, - //selectedAction, - //setSelectedApp, - //setSelectedTrigger, - //setSelectedEdge, - //setCurrentView, - //cy, - //setAuthenticationModalOpen, - //setVariablesModalOpen, - //setCodeModalOpen, - //selectedNameChange, - //rightsidebarStyle, - //showEnvironment, - //selectedActionEnvironment, - //environments, - //setNewSelectedAction, - //appApiViewStyle, - //globalUrl, - //setSelectedActionEnvironment, - //requiresAuthentication, - //scrollConfig, - //setScrollConfig, - } = props; - if (!rightSideBarOpen) { - return null; - } var defaultReturn = null - if (Object.getOwnPropertyNames(selectedAction).length > 0) { - if (Object.getOwnPropertyNames(selectedAction).length === 0) { - return null; - } - - defaultReturn = - - } else if (Object.getOwnPropertyNames(selectedComment).length > 0) { + + if (Object.getOwnPropertyNames(selectedComment).length > 0) { defaultReturn = } else if (Object.getOwnPropertyNames(selectedTrigger).length > 0) { - if (selectedTrigger.trigger_type === "SCHEDULE") { - // Handled elsewhere as an experiment - defaultReturn = null - } else if (selectedTrigger.trigger_type === "WEBHOOK") { - defaultReturn = null - } else if (selectedTrigger.trigger_type === "SUBFLOW") { + if (selectedTrigger.trigger_type === "SUBFLOW") { defaultReturn = } else if (selectedTrigger.trigger_type === "EMAIL") { defaultReturn = - } else if (selectedTrigger.trigger_type === "USERINPUT") { - defaultReturn = } else if (selectedTrigger.trigger_type === undefined) { //defaultReturn = return null; @@ -19646,12 +19820,68 @@ const AngularWorkflow = (defaultprops) => {
    {executionModal} - - + + { + rightSideBarOpen && Object.getOwnPropertyNames(selectedAction).length > 0 ? +
    + +
    : null + } {/* Looks for triggers" */} {/* Only fixed the ones that require scrolling on a small screen */} {/* Most important: Actions. But these are a lot more complex */} - {rightSideBarOpen && (selectedTrigger.trigger_type === "SCHEDULE" || selectedTrigger.trigger_type === "WEBHOOK" || selectedTrigger.trigger_type === "PIPELINE") ? + {rightSideBarOpen && (selectedTrigger.trigger_type === "SCHEDULE" || selectedTrigger.trigger_type === "WEBHOOK" || selectedTrigger.trigger_type === "PIPELINE" || selectedTrigger.trigger_type === "USERINPUT") ?
    {Object.getOwnPropertyNames(selectedTrigger).length > 0 ? selectedTrigger.trigger_type === "SCHEDULE" ? @@ -19660,6 +19890,8 @@ const AngularWorkflow = (defaultprops) => { PipelineSidebar : selectedTrigger.trigger_type === "WEBHOOK" ? WebhookSidebar + : selectedTrigger.trigger_type === "USERINPUT" ? + UserinputSidebar : null : null}
    @@ -20914,282 +21146,7 @@ const AngularWorkflow = (defaultprops) => { ) : null; - // Should get AI autocompletes - const aiSubmit = (value, setResponseMsg, setSuggestionLoading, inputAction) => { - if (setResponseMsg !== undefined) { - setResponseMsg("") - } - if (value === undefined || value === "") { - console.log("No value input!") - return - } - - if (setSuggestionLoading !== undefined) { - setSuggestionLoading(true) - } - - console.log("Submit conversation with value: ", value); - - // This is to find sample response and parse it as string - - var AppContext = [] - if (inputAction !== undefined && inputAction !== null) { - const parents = getParents(inputAction) - - console.log("Parents: ", parents) - var actionlist = [] - if (parents.length > 1) { - for (let [key,keyval] in Object.entries(parents)) { - const item = parents[key]; - if (item.label === "Execution Argument") { - continue; - } - - var exampledata = item.example === undefined || item.example === null ? "" : item.example; - // Find previous execution and their variables - //exampledata === "" && - if (workflowExecutions.length > 0) { - // Look for the ID - const found = false; - for (let [key,keyval] in Object.entries(workflowExecutions)) { - if (workflowExecutions[key].results === undefined || workflowExecutions[key].results === null) { - continue; - } - - var foundResult = workflowExecutions[key].results.find((result) => result.action.id === item.id); - if (foundResult === undefined || foundResult === null) { - continue; - } - - if (foundResult.result !== undefined && foundResult.result !== null) { - foundResult = foundResult.result - } - - const valid = validateJson(foundResult, true) - if (valid.valid) { - if (valid.result.success === false) { - //console.log("Skipping success false autocomplete") - } else { - exampledata = valid.result; - break; - } - } else { - exampledata = foundResult; - } - } - } - - // 1. Take - const itemlabelComplete = item.label === null || item.label === undefined ? "" : item.label.split(" ").join("_"); - - const actionvalue = { - app_name: item.app_name, - action_name: item.name, - label: item.label, - - type: "action", - id: item.id, - name: item.label, - autocomplete: itemlabelComplete, - example: exampledata, - }; - - actionlist.push(actionvalue); - } - } - - var fixedResults = [] - for (var i = 0; i < actionlist.length; i++) { - const item = actionlist[i]; - const responseFix = SetJsonDotnotation(item.example, "") - - // Check if json - const validated = validateJson(responseFix) - var exampledata = responseFix; - if (validated.valid) { - exampledata = JSON.stringify(validated.result) - } - - AppContext.push({ - "app_name": item.app_name, - "action_name": item.action_name, - "label": item.label, - "example": exampledata, - "example_response": exampledata, - }) - } - } - - var conversationData = { - "query": value, - "output_format": "action", - "app_context": AppContext, - - "workflow_id": workflow.id, - } - - if (inputAction !== undefined) { - console.log("Add app context! This should them get parameters directly") - conversationData.output_format = "action_parameters" - - conversationData.app_id = inputAction.app_id - conversationData.app_name = inputAction.app_name - conversationData.action_name = inputAction.name - conversationData.parameters = inputAction.parameters - - if (!value.includes(inputAction.label)) { - conversationData.query = inputAction.label.replaceAll("_", " ") - } - } - - // Onprem not available yet (April 2023) - // Should: Make OpenAI work for them with their own key - //fetch("https://shuffler.io/api/v1/conversation", { - fetch(`${globalUrl}/api/v1/conversation`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify(conversationData), - credentials: "include", - }) - .then((response) => { - if (setSuggestionLoading !== undefined) { - setSuggestionLoading(false) - } - - if (response.status !== 200) { - console.log("Status not 200 for stream results :O!"); - } - - return response.json(); - }) - .then((responseJson) => { - console.log("Conversation response: ", responseJson) - if (responseJson.success === false) { - if (responseJson.reason !== undefined) { - if (setResponseMsg !== undefined) { - setResponseMsg(responseJson.reason) - } - } - - return - } - - if (inputAction !== undefined) { - console.log("In input action! Should check params if they match, and add suggestions") - - if (responseJson.parameters === undefined || responseJson.parameters.length === 0) { - return - } - - var changed = false - - for (let paramkey in inputAction.parameters) { - const actionParam = inputAction.parameters[paramkey] - - if (actionParam.autocompleted === true) { - continue - } - - if (actionParam.configuration === true && actionParam.name !== "url") { - continue - } - - if (actionParam.value !== "" && actionParam.value !== actionParam.example) { - console.log("Skipping: ", actionParam) - continue - } - - for (let respParam of responseJson.parameters) { - if (respParam.name === actionParam.name) { - console.log("Found match for param: ", respParam) - - if (respParam.value === "") { - break - } - - changed = true - - inputAction.parameters[paramkey].autocompleted = true - inputAction.parameters[paramkey].value = respParam.value - break - } - } - } - - if (changed === true) { - console.log("Setting action! Force update pls :)") - setUpdate(Math.random()) - setSelectedAction(inputAction) - } - - return - } - - console.log("Suggestionbox location: ", suggestionBox) - - // Add action - if (responseJson.app_name !== undefined && responseJson.app_name !== null) { - // Always added to 0, 0 - // Should use suggestionBox.position.x, suggestionBox.position.y - var newitem = { - "data": responseJson, - "position": { - "x": suggestionBox.node_position.x !== undefined ? suggestionBox.node_position.x : 0, - "y": suggestionBox.node_position.y !== undefined ? suggestionBox.node_position.y + 100 : 0, - }, - "group": "nodes", - } - - newitem.type = "ACTION" - newitem.isStartNode = false - newitem.data.id = uuidv4() - newitem.data.type = "ACTION" - newitem.data.isStartNode = false - - newitem.data.is_valid = true - newitem.data.isValid = true - - cy.add({ - group: newitem.group, - data: newitem.data, - position: newitem.position, - }); - - // Add edge - const newId = uuidv4() - cy.add({ - group: "edges", - data: { - id: newId, - _id: newId, - source: suggestionBox.attachedTo, - target: newitem.data.id, - } - }) - //label: "Generated", - - setSuggestionBox({ - "position": { - "top": 500, - "left": 500, - }, - "open": false, - "attachedTo": "", - }); - } - }) - .catch((error) => { - if (setSuggestionLoading !== undefined) { - setSuggestionLoading(false) - } - - console.log("Conv response error: ", error); - }); - } const SuggestionBoxUi = () => { const [suggestionValue, setSuggestionValue] = useState(""); From 3600502f94197afe3b3a828f9d81715a44f55039 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Thu, 30 May 2024 00:46:58 +0530 Subject: [PATCH 02/22] Fixed the action parameter bug --- frontend/src/components/ParsedAction.jsx | 12 ++++++------ frontend/src/views/AngularWorkflow.jsx | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index c90e7747..937b0557 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -381,13 +381,12 @@ const ParsedAction = (props) => { useEffect(() => { - if (selectedActionParameters !== undefined && selectedActionParameters !== null && selectedActionParameters.length === 0 + if (selectedActionParameters !== undefined && selectedActionParameters !== null ) { if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { setSelectedActionParameters(selectedAction.parameters); } } - if ((selectedVariableParameter === null || selectedVariableParameter === undefined) && workflow.workflow_variables !== null && workflow.workflow_variables.length > 0) { // FIXME - this is the bad thing @@ -613,7 +612,8 @@ const ParsedAction = (props) => { setActionlist(actionlist); } } - }); + }, + [selectedAction, selectedVariableParameter, workflowExecutions, listCache]); const calculateHelpertext = (input_data) => { @@ -1307,6 +1307,8 @@ const ParsedAction = (props) => { const selectedAppIcon = selectedAction.large_image + console.log("Selected action: ", selectedAction) + console.log("Selected action paramaters: ", selectedAction.parameters) var baselabel = selectedAction.label return (
    @@ -2075,7 +2077,6 @@ const ParsedAction = (props) => {
    ) : null} - {workflow.execution_variables !== undefined && workflow.execution_variables !== null && workflow.execution_variables.length > 0 ? ( @@ -2395,7 +2396,6 @@ const ParsedAction = (props) => { })} : null*/} -
    { placeholder = data.example; - if (data.name === "url" && data.value !== undefined && data.value !== null && data.value.length === 0) { + if (data.name === "url" && data.value !== undefined && data.value !== null && data.value.length > 0) { data.value = data.example; } // In case of data.example diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index cfd65edd..32054a69 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -4584,6 +4584,7 @@ const AngularWorkflow = (defaultprops) => { workflow.actions[foundindex].name = curaction.name setWorkflow(workflow) + console.log(workflow) } break } From 73b5d1a30d54daefc069579766144135d36f7116 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Fri, 31 May 2024 12:58:56 +0530 Subject: [PATCH 03/22] Bug fixes --- frontend/src/components/ParsedAction.jsx | 16 ++++++++-------- frontend/src/views/AngularWorkflow.jsx | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 937b0557..3ce989fe 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -380,12 +380,13 @@ const ParsedAction = (props) => { }; - useEffect(() => { - if (selectedActionParameters !== undefined && selectedActionParameters !== null - ) { + useEffect( + () => { + // if (selectedActionParameters !== undefined && selectedActionParameters !== null + // ) { if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { setSelectedActionParameters(selectedAction.parameters); - } + // } } if ((selectedVariableParameter === null || selectedVariableParameter === undefined) && workflow.workflow_variables !== null && workflow.workflow_variables.length > 0) { @@ -2054,7 +2055,6 @@ const ParsedAction = (props) => { return ( { placeholder = data.example; - if (data.name === "url" && data.value !== undefined && data.value !== null && data.value.length > 0) { + if (data.name === "url") { data.value = data.example; } // In case of data.example @@ -3149,8 +3149,8 @@ const ParsedAction = (props) => { id={clickedFieldId} rows={data.name.startsWith("${") && data.name.endsWith("}") ? 2 : rows} color="primary" - defaultValue={data.value} - //value={data.value} + // defaultValue={data.value} + value={data.value} //options={{ // theme: 'gruvbox-dark', // keyMap: 'sublime', diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 32054a69..b3711b81 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -16953,7 +16953,6 @@ const AngularWorkflow = (defaultprops) => { var defaultReturn = null - if (Object.getOwnPropertyNames(selectedComment).length > 0) { defaultReturn = } else if (Object.getOwnPropertyNames(selectedTrigger).length > 0) { @@ -17811,7 +17810,7 @@ const AngularWorkflow = (defaultprops) => { console.log("IN useeffectt (2)" + collapsed) return; } - }) + },[]) /* componentWillUpdate = (nextProps, nextState) => { console.log(nextProps, nextState) From af734f7fb407db628d085ff695834b78bf0a9f6e Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Sun, 2 Jun 2024 15:30:10 +0530 Subject: [PATCH 04/22] Bug fix --- frontend/src/components/ParsedAction.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 3ce989fe..1db53973 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -3149,8 +3149,8 @@ const ParsedAction = (props) => { id={clickedFieldId} rows={data.name.startsWith("${") && data.name.endsWith("}") ? 2 : rows} color="primary" - // defaultValue={data.value} - value={data.value} + defaultValue={data.value} + // value={data.value} //options={{ // theme: 'gruvbox-dark', // keyMap: 'sublime', From 4f1bfc2313b002887993b4560db1d38bb9bb8beb Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Thu, 6 Jun 2024 12:56:01 +0530 Subject: [PATCH 05/22] Done with find action dropdown --- frontend/src/components/ParsedAction.jsx | 75 +- frontend/src/views/AngularWorkflow.jsx | 1027 +++++++++++----------- 2 files changed, 550 insertions(+), 552 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 1db53973..95a9ad4e 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -180,9 +180,8 @@ const ParsedAction = (props) => { const [fieldCount, setFieldCount] = React.useState(0); const [hiddenDescription, setHiddenDescription] = React.useState(true); - const [autoCompleting, setAutocompleting] = React.useState(false); - const [selectedActionParameters, setSelectedActionParameters] = React.useState([]); + const [selectedActionParameters, setSelectedActionParameters] = React.useState(selectedAction.parameters); const [selectedVariableParameter, setSelectedVariableParameter] = React.useState(""); const [actionlist, setActionlist] = React.useState([]); const [jsonList, setJsonList] = React.useState([]); @@ -382,9 +381,12 @@ const ParsedAction = (props) => { useEffect( () => { + console.log("UseEffect Rendered!") + console.log("Workflow", workflow) // if (selectedActionParameters !== undefined && selectedActionParameters !== null // ) { if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { + console.log("Setting action parameters!!") setSelectedActionParameters(selectedAction.parameters); // } } @@ -614,9 +616,13 @@ const ParsedAction = (props) => { } } }, - [selectedAction, selectedVariableParameter, workflowExecutions, listCache]); - - + [selectedAction,selectedApp,setNewSelectedAction] + ); + console.log("selectedActionParameters: ", selectedActionParameters) + console.log("selectedApp:", selectedApp) + console.log("selectedAction: ", selectedAction) + console.log("ACTIONLIST: ", actionlist) + console.log("selectedVariableParameter", selectedVariableParameter) const calculateHelpertext = (input_data) => { var helperText = "" var looperText = "" @@ -1184,7 +1190,7 @@ const ParsedAction = (props) => { } // FIXME: Issue #40 - selectedActionParameters not reset - + if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0) { var wrapperapp = { "id": "", "name": "noapp", @@ -1210,15 +1216,16 @@ const ParsedAction = (props) => { var authWritten = false; var noAppSelected = false - const paramIndex = selectedAction.parameters.findIndex((param) => param.name === "app_name") + var paramIndex = selectedAction.parameters.findIndex((param) => param.name === "app_name") if (paramIndex === -1 || selectedAction.parameters[paramIndex].value === "" || selectedAction.parameters[paramIndex].value === "noapp") { // Check the actual value and if it's the same noAppSelected = true } + } const ActionSelectOption = (actionprops) => { - const { data, newActionname, newActiondescription, useIcon, extraDescription, } = actionprops; + const { option, newActionname, newActiondescription, useIcon, extraDescription, } = actionprops; const [hover, setHover] = React.useState(false); return ( @@ -1234,18 +1241,20 @@ const ParsedAction = (props) => { paddingBottom: 4, backgroundColor: hover ? theme.palette.surfaceColor : theme.palette.inputColor, }} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} - onClick={() => { + onClick={(event) => { + // event.preventDefault() //setSelectedAction(actionprops) //setShowActionList(false) //setUpdate(Math.random()) // - if (data !== undefined && data !== null) { + if (option !== undefined && option !== null) { setNewSelectedAction({ target: { - value: data.name + value: option.name } }); } + document.activeElement.blur(); }} >
    @@ -1308,7 +1317,7 @@ const ParsedAction = (props) => { const selectedAppIcon = selectedAction.large_image - console.log("Selected action: ", selectedAction) +// console.log("Selected action: ", selectedAction) console.log("Selected action paramaters: ", selectedAction.parameters) var baselabel = selectedAction.label return ( @@ -2220,54 +2229,55 @@ const ParsedAction = (props) => { } }); } - }} - renderOption={(props, data, state) => { - var newActionname = data.name; - if (data.label !== undefined && data.label !== null && data.label.length > 0) { - newActionname = data.label; + event.target.blur(); + }} + renderOption={(props, option, state) => { + var newActionname = option.name; + if (option.label !== undefined && option.label !== null && option.label.length > 0) { + newActionname = option.label; } - var newActiondescription = data.description; + var newActiondescription = option.description; //console.log("DESC: ", newActiondescription) - if (data.description === undefined || data.description === null) { + if (option.description === undefined || option.description === null) { newActiondescription = "Description: No description defined for this action" } else { newActiondescription = "Description: "+newActiondescription } - const iconInfo = GetIconInfo({ name: data.name }); + const iconInfo = GetIconInfo({ name: option.name }); const useIcon = iconInfo.originalIcon; if (newActionname === undefined || newActionname === null) { newActionname = "No name" - data.name = "No name" - data.label = "No name" + option.name = "No name" + option.label = "No name" } newActionname = (newActionname.charAt(0).toUpperCase() + newActionname.substring(1)).replaceAll("_", " "); var method = "" var extraDescription = "" - if (data.name.includes("get_")) { + if (option.name.includes("get_")) { method = "GET" - } else if (data.name.includes("post_")) { + } else if (option.name.includes("post_")) { method = "POST" - } else if (data.name.includes("put_")) { + } else if (option.name.includes("put_")) { method = "PUT" - } else if (data.name.includes("patch_")) { + } else if (option.name.includes("patch_")) { method = "PATCH" - } else if (data.name.includes("delete_")) { + } else if (option.name.includes("delete_")) { method = "DELETE" - } else if (data.name.includes("options_")) { + } else if (option.name.includes("options_")) { method = "OPTIONS" - } else if (data.name.includes("connect_")) { + } else if (option.name.includes("connect_")) { method = "CONNECT" } // FIXME: Should it require a base URL? - if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) { + if (method.length > 0 && option.description !== undefined && option.description !== null && option.description.includes("http")) { var extraUrl = "" - const descSplit = data.description.split("\n") + const descSplit = option.description.split("\n") // Last line of descSplit if (descSplit.length > 0) { extraUrl = descSplit[descSplit.length-1] @@ -2306,7 +2316,8 @@ const ParsedAction = (props) => { return ( { //const data = JSON.parse(JSON.stringify(event.target.data())) const data = event.target.data() - + console.log("===============================Node selected=============================") console.log("NODE SELECT: ", data) if (data.app_name === "Shuffle Workflow") { @@ -8567,11 +8567,15 @@ const AngularWorkflow = (defaultprops) => { ); }; - const handleSetTab = (event, newValue) => { - setCurrentView(newValue); - }; + const HandleLeftView = () => { + // console.log("HandleLeftView Rendered!") + + const handleSetTab = (event, newValue) => { + setCurrentView(newValue); + }; + // Defaults to apps. var thisview = ( { ) } - - - const TriggersView = () => { - const triggersViewStyle = { - marginLeft: 10, - marginRight: 10, - display: "flex", - flexDirection: "column", - } - - // Predefined hurr - return ( -
    -
    - {triggers.map((trigger, index) => { - - /* - if (trigger.trigger_type === "PIPELINE") { - if (userdata.support !== true) { - return null - } - } - */ - - // Hiding since March 2024 - if (trigger.trigger_type === "EMAIL") { - return null - } - - const imagesize = isMobile ? 40 : trigger.large_image.includes("svg") ? 50 : 50 - var imageline = trigger.large_image.length === 0 ? - : - - - const title = trigger.trigger_type === "WEBHOOK" ? "Workflow starters" : trigger.trigger_type === "SUBFLOW" ? "Mid-Workflow" : "" - - const color = trigger.is_valid ? green : yellow; - return ( - - {title.length > 0 ? - - {title} - - : null} - - { - handleTriggerDrag(e, trigger); - }} - onStop={(e) => { - handleDragStop(e); - }} - dragging={false} - position={{ - x: 0, - y: 0, - }} - > - { }}> -
    - - - {imageline} - - {isMobile ? null : - - - - {trigger.name} - - - - - {trigger.description} - - - - } - -
    -
    -
    - ); - })} -
    -
    - ); - }; - - var newNodeId = ""; - var parsedApp = {}; - const handleTriggerDrag = (e, data) => { - const cycontainer = cy.container(); - // Chrome lol - if ( - e.pageX > cycontainer.offsetLeft && - e.pageX < cycontainer.offsetLeft + cycontainer.offsetWidth && - e.pageY > cycontainer.offsetTop && - e.pageY < cycontainer.offsetTop + cycontainer.offsetHeight - ) { - if (newNodeId.length > 0) { - var currentnode = cy.getElementById(newNodeId); - if (currentnode.length === 0) { - return; - } - - currentnode[0].renderedPosition("x", e.pageX - cycontainer.offsetLeft); - currentnode[0].renderedPosition("y", e.pageY - cycontainer.offsetTop); - } else { - if (workflow.start === "" || workflow.start === undefined) { - toast("Define a starting action first."); - return; - } - - const triggerLabel = getNextActionName(data.name); - - newNodeId = uuidv4(); - const newposition = { - x: e.pageX - cycontainer.offsetLeft, - y: e.pageY - cycontainer.offsetTop, - }; - - const newAppData = { - app_name: data.name, - app_version: "1.0.0", - environment: isCloud ? "cloud" : data.environment, - description: data.description, - long_description: data.long_description, - errors: [], - id_: newNodeId, - _id_: newNodeId, - id: newNodeId, - finished: false, - label: triggerLabel, - type: data.type, - is_valid: true, - trigger_type: data.trigger_type, - large_image: data.large_image, - status: "uninitialized", - name: data.name, - isStartNode: false, - position: newposition, - }; - - // Can all the data be in here? hmm - const nodeToBeAdded = { - group: "nodes", - data: newAppData, - renderedPosition: newposition, - }; - - cy.add(nodeToBeAdded); - parsedApp = nodeToBeAdded; - return; - } - } - }; - - const handleDragStop = (e, app) => { - var currentnode = cy.getElementById(newNodeId); - if ( - currentnode === undefined || - currentnode === null || - currentnode.length === 0 - ) { - return; - } - - // Using remove & replace, as this triggers the function - // onNodeAdded() with this node after it's added - - currentnode.remove(); - parsedApp.data.finished = true; - parsedApp.data.position = currentnode.renderedPosition(); - parsedApp.position = currentnode.renderedPosition(); - parsedApp.renderedPosition = currentnode.renderedPosition(); - - var newAppData = parsedApp.data; - if (newAppData.type === "ACTION") { - - //const activateApp = (appid) => { - if (newAppData.activated === false) { - activateApp(newAppData.app_id, false) - } - - // AUTHENTICATION - if (app.authentication !== undefined && app.authentication !== null && app.authentication.required === true) { - - // Setup auth here :) - const authenticationOptions = []; - var findAuthId = ""; - if ( - newAppData.authentication_id !== null && - newAppData.authentication_id !== undefined && - newAppData.authentication_id.length > 0 - ) { - findAuthId = newAppData.authentication_id; - } - - const tmpAuth = JSON.parse(JSON.stringify(appAuthentication)); - for (let authkey in tmpAuth) { - if (authkey === undefined) { - continue - } - - var item = tmpAuth[authkey]; - const newfields = {}; - 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) { - authenticationOptions.push(item); - - if (item.id === findAuthId) { - newAppData.selectedAuthentication = item - newAppData.authentication_id = item.id - - } else if (findAuthId === "") { - // Will always be set to the last one if one isn't found. - // Last = timestamp too - newAppData.selectedAuthentication = item - newAppData.authentication_id = item.id - } - } - } - - if ( - authenticationOptions !== undefined && - authenticationOptions !== null && - authenticationOptions.length > 0 - ) { - for (let authkey in authenticationOptions) { - const option = authenticationOptions[authkey]; - - if (option.active && newAppData.authentication_id === "") { - newAppData.selectedAuthentication = option; - newAppData.authentication_id = option.id; - break; - } - } - } - } else { - newAppData.authentication = []; - newAppData.authentication_id = ""; - newAppData.selectedAuthentication = {}; - } - - parsedApp.data = newAppData; - cy.add(parsedApp); - } else if (newAppData.type === "TRIGGER") { - cy.add(parsedApp); - } - - newNodeId = ""; - parsedApp = {}; - }; - - const barHeight = bodyHeight - appBarSize - 50; - const appScrollStyle = { - overflow: "scroll", - maxHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight, - minHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight, - marginTop: 1, - overflowY: "auto", - overflowX: "hidden", - } - - const handleAppDrag = (e, app) => { - const cycontainer = cy.container(); - - - if (app.type === "TRIGGER") { - handleTriggerDrag(e, app) - return - } - - //console.log("e: ", e) - //console.log("Offset: ", cycontainer) - - // Chrome lol - if ( - e.pageX > cycontainer.offsetLeft && - e.pageX < cycontainer.offsetLeft + cycontainer.offsetWidth && - e.pageY > cycontainer.offsetTop && - e.pageY < cycontainer.offsetTop + cycontainer.offsetHeight - ) { - if (newNodeId.length > 0) { - var currentnode = cy.getElementById(newNodeId); - if ( - currentnode === undefined || - currentnode === null || - currentnode.length === 0 - ) { - return; - } - - currentnode[0].renderedPosition("x", e.pageX - cycontainer.offsetLeft) - currentnode[0].renderedPosition("y", e.pageY - cycontainer.offsetTop) - } else { - if (workflow.public) { - console.log("workflow is public - not adding") - return; - } - - if (app.actions === undefined || app.actions === null) { - app.actions = [] - } - - /* - if (app.actions === undefined || app.actions === null || app.actions.length === 0) { - toast("App " + app.name + " currently has no actions to perform. Please go to https://shuffler.io/apps to edit it.") - - return - } - */ - - newNodeId = uuidv4(); - const actionType = "ACTION"; - const actionLabel = getNextActionName(app.name); - //console.log("Next action name: ", actionLabel) - var parameters = null; - var example = ""; - var description = "" - - const startIndex = app.actions.findIndex((action) => action.category_label !== undefined && action.category_label !== null && action.category_label.length > 0) - const actionIndex = startIndex < 0 ? 0 : startIndex - - // Make the first action the most relevant one for them based on previous use - if ( - app.actions[actionIndex].parameters !== undefined && - app.actions[actionIndex].parameters !== null && - app.actions[actionIndex].parameters.length > 0 - ) { - parameters = app.actions[actionIndex].parameters; - for (let paramkey in parameters) { - // Check if parameter.name == "headers" and if it includes "=undefined". If it does, set the value to example if it exists, otherwise empty - if (parameters[paramkey].name === "headers" && parameters[paramkey].value.includes("=undefined")) { - if (parameters[paramkey].example !== undefined && parameters[paramkey].example !== null && parameters[paramkey].example.length > 0) { - parameters[paramkey].value = parameters[paramkey].example - } else { - parameters[paramkey].value = "" - } - } - } - - //parameters = app.actions[0].parameters; - } - - if ( - app.actions[actionIndex].returns !== undefined && - app.actions[actionIndex].returns !== null && - app.actions[actionIndex].returns.example !== undefined && - app.actions[actionIndex].returns.example !== null && - app.actions[actionIndex].returns.example.length > 0 - ) { - example = app.actions[actionIndex].returns.example; - } - - if ( - app.actions[actionIndex].description !== undefined && - app.actions[actionIndex].description !== null && - app.actions[actionIndex].description.length > 0 - ) { - description = app.actions[actionIndex].description - } - - var parsedEnvironments = - environments === null || environments === [] - ? "cloud" - : environments[defaultEnvironmentIndex] === undefined - ? "cloud" - : environments[defaultEnvironmentIndex].Name - - // Basic automatic auth mapping - var authId = "" - if (appAuthentication !== undefined && appAuthentication !== null && appAuthentication.length > 0) { - const appname = app.name.toLowerCase().replace(" ", "_") - for (var key in appAuthentication) { - const authKey = appAuthentication[key] - if (authKey.app.id === app.id) { - authId = authKey.id - break - } - - const appauthname = authKey.app.name.toLowerCase().replace(" ", "_") - if (appauthname === appname) { - authId = authKey.id - } - } - } - - // List other nodes in the workflow and see if they have an environment set. If they do, use that as the default - if (cy !== undefined && cy !== null) { - const foundnodes = cy.nodes().jsons() - if (foundnodes !== undefined && foundnodes !== null && foundnodes.length > 0) { - // As they should all be the same, this is just an override - for (let nodekey in foundnodes) { - const curnode = foundnodes[nodekey] - if (curnode.data.environment !== undefined && curnode.data.environment !== null && curnode.data.environment.length > 0) { - parsedEnvironments = curnode.data.environment - break - } - } - } - } - - const newAppData = { - name: app.actions[actionIndex].name, - label: actionLabel, - app_name: app.name, - app_version: app.app_version, - app_id: app.id, - sharing: app.sharing, - private_id: app.private_id, - description: description, - environment: parsedEnvironments, - errors: [], - finished: false, - id_: newNodeId, - _id_: newNodeId, - id: newNodeId, - is_valid: true, - type: actionType, - parameters: parameters, - isStartNode: false, - large_image: app.large_image, - run_magic_output: false, - authentication: [], - execution_variable: undefined, - example: example, - required_body_fields: app.actions[actionIndex].required_body_fields, - category: - app.categories !== null && - app.categories !== undefined && - app.categories.length > 0 - ? app.categories[0] - : "", - authentication_id: authId, - finished: false, - template: app.template === true ? true : false, - }; - - // FIXME: overwrite category if the ACTION chosen has a different category - // - - if (!isCloud && (!app.is_valid || (!app.activated && app.generated))) { - console.log("NOT VALID: Activate!") - - activateApp(app.id, false) - } - - // const image = "url("+app.large_image+")" - // FIXME - find the cytoscape offset position - // Can this be done with zoom calculations? - const nodeToBeAdded = { - group: "nodes", - data: newAppData, - renderedPosition: { - x: e.pageX - cycontainer.offsetLeft, - y: e.pageY - cycontainer.offsetTop, - }, - }; - - parsedApp = nodeToBeAdded; - cy.add(nodeToBeAdded); - return; - } - } - }; - const AppView = (props) => { const { allApps, prioritizedApps, filteredApps, extraApps } = props; - + // console.log("AppView Rendered!") //extraApps, const [visibleApps, setVisibleApps] = React.useState( Array.prototype.concat.apply( @@ -9833,8 +9323,505 @@ const AngularWorkflow = (defaultprops) => {
    ); +} + + const TriggersView = () => { + console.log("TriggerView Rendered!") + const triggersViewStyle = { + marginLeft: 10, + marginRight: 10, + display: "flex", + flexDirection: "column", + } + + // Predefined hurr + return ( +
    +
    + {triggers.map((trigger, index) => { + + /* + if (trigger.trigger_type === "PIPELINE") { + if (userdata.support !== true) { + return null + } + } + */ + + // Hiding since March 2024 + if (trigger.trigger_type === "EMAIL") { + return null + } + + const imagesize = isMobile ? 40 : trigger.large_image.includes("svg") ? 50 : 50 + var imageline = trigger.large_image.length === 0 ? + : + + + const title = trigger.trigger_type === "WEBHOOK" ? "Workflow starters" : trigger.trigger_type === "SUBFLOW" ? "Mid-Workflow" : "" + + const color = trigger.is_valid ? green : yellow; + return ( + + {title.length > 0 ? + + {title} + + : null} + + { + handleTriggerDrag(e, trigger); + }} + onStop={(e) => { + handleDragStop(e); + }} + dragging={false} + position={{ + x: 0, + y: 0, + }} + > + { }}> +
    + + + {imageline} + + {isMobile ? null : + + + + {trigger.name} + + + + + {trigger.description} + + + + } + +
    +
    +
    + ); + })} +
    +
    + ); + } + + var newNodeId = ""; + var parsedApp = {}; + const handleTriggerDrag = (e, data) => { + const cycontainer = cy.container(); + // Chrome lol + if ( + e.pageX > cycontainer.offsetLeft && + e.pageX < cycontainer.offsetLeft + cycontainer.offsetWidth && + e.pageY > cycontainer.offsetTop && + e.pageY < cycontainer.offsetTop + cycontainer.offsetHeight + ) { + if (newNodeId.length > 0) { + var currentnode = cy.getElementById(newNodeId); + if (currentnode.length === 0) { + return; + } + + currentnode[0].renderedPosition("x", e.pageX - cycontainer.offsetLeft); + currentnode[0].renderedPosition("y", e.pageY - cycontainer.offsetTop); + } else { + if (workflow.start === "" || workflow.start === undefined) { + toast("Define a starting action first."); + return; + } + + const triggerLabel = getNextActionName(data.name); + + newNodeId = uuidv4(); + const newposition = { + x: e.pageX - cycontainer.offsetLeft, + y: e.pageY - cycontainer.offsetTop, + }; + + const newAppData = { + app_name: data.name, + app_version: "1.0.0", + environment: isCloud ? "cloud" : data.environment, + description: data.description, + long_description: data.long_description, + errors: [], + id_: newNodeId, + _id_: newNodeId, + id: newNodeId, + finished: false, + label: triggerLabel, + type: data.type, + is_valid: true, + trigger_type: data.trigger_type, + large_image: data.large_image, + status: "uninitialized", + name: data.name, + isStartNode: false, + position: newposition, + }; + + // Can all the data be in here? hmm + const nodeToBeAdded = { + group: "nodes", + data: newAppData, + renderedPosition: newposition, + }; + + cy.add(nodeToBeAdded); + parsedApp = nodeToBeAdded; + return; + } + } }; + const handleDragStop = (e, app) => { + var currentnode = cy.getElementById(newNodeId); + if ( + currentnode === undefined || + currentnode === null || + currentnode.length === 0 + ) { + return; + } + + // Using remove & replace, as this triggers the function + // onNodeAdded() with this node after it's added + + currentnode.remove(); + parsedApp.data.finished = true; + parsedApp.data.position = currentnode.renderedPosition(); + parsedApp.position = currentnode.renderedPosition(); + parsedApp.renderedPosition = currentnode.renderedPosition(); + + var newAppData = parsedApp.data; + if (newAppData.type === "ACTION") { + + //const activateApp = (appid) => { + if (newAppData.activated === false) { + activateApp(newAppData.app_id, false) + } + + // AUTHENTICATION + if (app.authentication !== undefined && app.authentication !== null && app.authentication.required === true) { + + // Setup auth here :) + const authenticationOptions = []; + var findAuthId = ""; + if ( + newAppData.authentication_id !== null && + newAppData.authentication_id !== undefined && + newAppData.authentication_id.length > 0 + ) { + findAuthId = newAppData.authentication_id; + } + + const tmpAuth = JSON.parse(JSON.stringify(appAuthentication)); + for (let authkey in tmpAuth) { + if (authkey === undefined) { + continue + } + + var item = tmpAuth[authkey]; + const newfields = {}; + 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) { + authenticationOptions.push(item); + + if (item.id === findAuthId) { + newAppData.selectedAuthentication = item + newAppData.authentication_id = item.id + + } else if (findAuthId === "") { + // Will always be set to the last one if one isn't found. + // Last = timestamp too + newAppData.selectedAuthentication = item + newAppData.authentication_id = item.id + } + } + } + + if ( + authenticationOptions !== undefined && + authenticationOptions !== null && + authenticationOptions.length > 0 + ) { + for (let authkey in authenticationOptions) { + const option = authenticationOptions[authkey]; + + if (option.active && newAppData.authentication_id === "") { + newAppData.selectedAuthentication = option; + newAppData.authentication_id = option.id; + break; + } + } + } + } else { + newAppData.authentication = []; + newAppData.authentication_id = ""; + newAppData.selectedAuthentication = {}; + } + + parsedApp.data = newAppData; + cy.add(parsedApp); + } else if (newAppData.type === "TRIGGER") { + cy.add(parsedApp); + } + + newNodeId = ""; + parsedApp = {}; + }; + + const barHeight = bodyHeight - appBarSize - 50; + const appScrollStyle = { + overflow: "scroll", + maxHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight, + minHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight, + marginTop: 1, + overflowY: "auto", + overflowX: "hidden", + } + + const handleAppDrag = (e, app) => { + const cycontainer = cy.container(); + + + if (app.type === "TRIGGER") { + handleTriggerDrag(e, app) + return + } + + //console.log("e: ", e) + //console.log("Offset: ", cycontainer) + + // Chrome lol + if ( + e.pageX > cycontainer.offsetLeft && + e.pageX < cycontainer.offsetLeft + cycontainer.offsetWidth && + e.pageY > cycontainer.offsetTop && + e.pageY < cycontainer.offsetTop + cycontainer.offsetHeight + ) { + if (newNodeId.length > 0) { + var currentnode = cy.getElementById(newNodeId); + if ( + currentnode === undefined || + currentnode === null || + currentnode.length === 0 + ) { + return; + } + + currentnode[0].renderedPosition("x", e.pageX - cycontainer.offsetLeft) + currentnode[0].renderedPosition("y", e.pageY - cycontainer.offsetTop) + } else { + if (workflow.public) { + console.log("workflow is public - not adding") + return; + } + + if (app.actions === undefined || app.actions === null) { + app.actions = [] + } + + /* + if (app.actions === undefined || app.actions === null || app.actions.length === 0) { + toast("App " + app.name + " currently has no actions to perform. Please go to https://shuffler.io/apps to edit it.") + + return + } + */ + + newNodeId = uuidv4(); + const actionType = "ACTION"; + const actionLabel = getNextActionName(app.name); + //console.log("Next action name: ", actionLabel) + var parameters = null; + var example = ""; + var description = "" + + const startIndex = app.actions.findIndex((action) => action.category_label !== undefined && action.category_label !== null && action.category_label.length > 0) + const actionIndex = startIndex < 0 ? 0 : startIndex + + // Make the first action the most relevant one for them based on previous use + if ( + app.actions[actionIndex].parameters !== undefined && + app.actions[actionIndex].parameters !== null && + app.actions[actionIndex].parameters.length > 0 + ) { + parameters = app.actions[actionIndex].parameters; + for (let paramkey in parameters) { + // Check if parameter.name == "headers" and if it includes "=undefined". If it does, set the value to example if it exists, otherwise empty + if (parameters[paramkey].name === "headers" && parameters[paramkey].value.includes("=undefined")) { + if (parameters[paramkey].example !== undefined && parameters[paramkey].example !== null && parameters[paramkey].example.length > 0) { + parameters[paramkey].value = parameters[paramkey].example + } else { + parameters[paramkey].value = "" + } + } + } + + //parameters = app.actions[0].parameters; + } + + if ( + app.actions[actionIndex].returns !== undefined && + app.actions[actionIndex].returns !== null && + app.actions[actionIndex].returns.example !== undefined && + app.actions[actionIndex].returns.example !== null && + app.actions[actionIndex].returns.example.length > 0 + ) { + example = app.actions[actionIndex].returns.example; + } + + if ( + app.actions[actionIndex].description !== undefined && + app.actions[actionIndex].description !== null && + app.actions[actionIndex].description.length > 0 + ) { + description = app.actions[actionIndex].description + } + + var parsedEnvironments = + environments === null || environments === [] + ? "cloud" + : environments[defaultEnvironmentIndex] === undefined + ? "cloud" + : environments[defaultEnvironmentIndex].Name; + + // List other nodes in the workflow and see if they have an environment set. If they do, use that as the default + if (cy !== undefined && cy !== null) { + const foundnodes = cy.nodes().jsons() + if (foundnodes !== undefined && foundnodes !== null && foundnodes.length > 0) { + // As they should all be the same, this is just an override + for (let nodekey in foundnodes) { + const curnode = foundnodes[nodekey] + if (curnode.data.environment !== undefined && curnode.data.environment !== null && curnode.data.environment.length > 0) { + parsedEnvironments = curnode.data.environment + break + } + } + } + } + + const newAppData = { + name: app.actions[actionIndex].name, + label: actionLabel, + app_name: app.name, + app_version: app.app_version, + app_id: app.id, + sharing: app.sharing, + private_id: app.private_id, + description: description, + environment: parsedEnvironments, + errors: [], + finished: false, + id_: newNodeId, + _id_: newNodeId, + id: newNodeId, + is_valid: true, + type: actionType, + parameters: parameters, + isStartNode: false, + large_image: app.large_image, + run_magic_output: false, + authentication: [], + execution_variable: undefined, + example: example, + required_body_fields: app.actions[actionIndex].required_body_fields, + category: + app.categories !== null && + app.categories !== undefined && + app.categories.length > 0 + ? app.categories[0] + : "", + authentication_id: "", + finished: false, + template: app.template === true ? true : false, + }; + + // FIXME: overwrite category if the ACTION chosen has a different category + // + + if (!isCloud && (!app.is_valid || (!app.activated && app.generated))) { + console.log("NOT VALID: Activate!") + + activateApp(app.id, false) + } + + // const image = "url("+app.large_image+")" + // FIXME - find the cytoscape offset position + // Can this be done with zoom calculations? + const nodeToBeAdded = { + group: "nodes", + data: newAppData, + renderedPosition: { + x: e.pageX - cycontainer.offsetLeft, + y: e.pageY - cycontainer.offsetTop, + }, + }; + + parsedApp = nodeToBeAdded; + cy.add(nodeToBeAdded); + return; + } + } + }; + + const getNextActionName = (appName) => { var highest = ""; From 355466a9a28ae03f8255dec188bf102b93804ea6 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Thu, 6 Jun 2024 17:44:15 +0530 Subject: [PATCH 06/22] Done with delay --- frontend/src/components/ParsedAction.jsx | 31 +++++++++--- frontend/src/views/AngularWorkflow.jsx | 64 ++++++++++++------------ 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 95a9ad4e..7b308d71 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -177,7 +177,8 @@ const ParsedAction = (props) => { const classes = useStyles(); const [hideBody, setHideBody] = React.useState(true); const [activateHidingBodyButton, setActivateHidingBodyButton] = React.useState(false); - + const [appActionName, setAppActionName] = React.useState(selectedAction.label); + const [delay, setDelay] = React.useState(selectedAction?.execution_delay); const [fieldCount, setFieldCount] = React.useState(0); const [hiddenDescription, setHiddenDescription] = React.useState(true); const [autoCompleting, setAutocompleting] = React.useState(false); @@ -197,6 +198,7 @@ const ParsedAction = (props) => { } }, [expansionModalOpen]) + useEffect(() => { if (selectedAction.parameters === null || selectedAction.parameters === undefined) { return @@ -383,6 +385,9 @@ const ParsedAction = (props) => { () => { console.log("UseEffect Rendered!") console.log("Workflow", workflow) + setAppActionName(selectedAction.label) + setDelay(selectedAction.execution_delay) + // if (selectedActionParameters !== undefined && selectedActionParameters !== null // ) { if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { @@ -618,6 +623,12 @@ const ParsedAction = (props) => { }, [selectedAction,selectedApp,setNewSelectedAction] ); + + useEffect(() => { + selectedNameChange(appActionName) + actionDelayChange(delay) + },[appActionName,delay]) + console.log("selectedActionParameters: ", selectedActionParameters) console.log("selectedApp:", selectedApp) console.log("selectedAction: ", selectedAction) @@ -1628,11 +1639,17 @@ const ParsedAction = (props) => { fullWidth color="primary" placeholder={selectedAction.label} - defaultValue={selectedAction.label} - onChange={selectedNameChange} + value={appActionName} + onChange={ + (event) => { + let newValue = event.target.value + newValue = newValue.replaceAll(" ", "_") + setAppActionName(newValue) + } + } onBlur={(e) => { // Copy the name value - const name = e.target.value + const name = appActionName const parsedBaseLabel = "$"+baselabel.toLowerCase().replaceAll(" ", "_") const newname = "$"+name.toLowerCase().replaceAll(" ", "_") @@ -1848,11 +1865,9 @@ const ParsedAction = (props) => { disableUnderline: true, }} placeholder={selectedAction.execution_delay} - defaultValue={selectedAction.execution_delay} + value={delay} onChange={(event) => { - if (actionDelayChange !== undefined) { - actionDelayChange(event) - } + setDelay(event.target.value) }} /> diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 7e173716..bece66c2 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -22,7 +22,6 @@ import { CodeHandler, Img, OuterLink, } from "../views/Docs.jsx"; import { InstantSearch, Configure, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom'; import algoliasearch from 'algoliasearch/lite'; - import { Zoom, Fade, @@ -10067,44 +10066,43 @@ const AngularWorkflow = (defaultprops) => { // appname & version // description // ACTION select - const selectedNameChange = (event) => { - event.target.value = event.target.value.replaceAll("(", ""); - event.target.value = event.target.value.replaceAll(")", ""); - event.target.value = event.target.value.replaceAll("]", ""); - event.target.value = event.target.value.replaceAll("[", ""); - event.target.value = event.target.value.replaceAll("{", ""); - event.target.value = event.target.value.replaceAll("}", ""); - event.target.value = event.target.value.replaceAll("*", ""); - event.target.value = event.target.value.replaceAll("!", ""); - event.target.value = event.target.value.replaceAll("@", ""); - event.target.value = event.target.value.replaceAll("#", ""); - event.target.value = event.target.value.replaceAll("$", ""); - event.target.value = event.target.value.replaceAll("%", ""); - event.target.value = event.target.value.replaceAll("&", ""); - event.target.value = event.target.value.replaceAll("#", ""); - event.target.value = event.target.value.replaceAll(".", ""); - event.target.value = event.target.value.replaceAll(",", ""); - event.target.value = event.target.value.replaceAll(" ", "_"); - event.target.value = event.target.value.replaceAll("^", "_"); - event.target.value = event.target.value.replaceAll("'", "_"); - event.target.value = event.target.value.replaceAll("\"", "_"); - event.target.value = event.target.value.replaceAll("\"", "_"); - event.target.value = event.target.value.replaceAll(":", "_"); - event.target.value = event.target.value.replaceAll(";", "_"); - event.target.value = event.target.value.replaceAll("=", "_"); - event.target.value = event.target.value.replaceAll("+", "_"); - - selectedAction.label = event.target.value; + const selectedNameChange = (appActionName) => { + appActionName = appActionName.replaceAll("(", ""); + appActionName = appActionName.replaceAll(")", ""); + appActionName = appActionName.replaceAll("]", ""); + appActionName = appActionName.replaceAll("[", ""); + appActionName = appActionName.replaceAll("{", ""); + appActionName = appActionName.replaceAll("}", ""); + appActionName = appActionName.replaceAll("*", ""); + appActionName = appActionName.replaceAll("!", ""); + appActionName = appActionName.replaceAll("@", ""); + appActionName = appActionName.replaceAll("#", ""); + appActionName = appActionName.replaceAll("$", ""); + appActionName = appActionName.replaceAll("%", ""); + appActionName = appActionName.replaceAll("&", ""); + appActionName = appActionName.replaceAll("#", ""); + appActionName = appActionName.replaceAll(".", ""); + appActionName = appActionName.replaceAll(",", ""); + appActionName = appActionName.replaceAll(" ", "_"); + appActionName = appActionName.replaceAll("^", "_"); + appActionName = appActionName.replaceAll("'", "_"); + appActionName = appActionName.replaceAll("\"", "_"); + appActionName = appActionName.replaceAll("\"", "_"); + appActionName = appActionName.replaceAll(":", "_"); + appActionName = appActionName.replaceAll(";", "_"); + appActionName = appActionName.replaceAll("=", "_"); + appActionName = appActionName.replaceAll("+", "_"); + selectedAction.label = appActionName; setSelectedAction(selectedAction); }; - const actionDelayChange = (event) => { - if (isNaN(event.target.value)) { - console.log("NAN: ", event.target.value) + const actionDelayChange = (delay) => { + if (isNaN(delay)) { + console.log("NAN: ", delay) return } - const parsedNumber = parseInt(event.target.value) + const parsedNumber = parseInt(delay) if (parsedNumber > 86400) { console.log("Max number is 1 day (86400)") return From 03a1e62e4ede84a7becf60b7cc2a349635d24cf5 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Fri, 7 Jun 2024 17:10:54 +0530 Subject: [PATCH 07/22] Fixed the parameter value change dynamically --- frontend/src/components/ParsedAction.jsx | 58 +++++++++++++++--------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 7b308d71..2d428ca8 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -178,12 +178,16 @@ const ParsedAction = (props) => { const [hideBody, setHideBody] = React.useState(true); const [activateHidingBodyButton, setActivateHidingBodyButton] = React.useState(false); const [appActionName, setAppActionName] = React.useState(selectedAction.label); - const [delay, setDelay] = React.useState(selectedAction?.execution_delay); + const [delay, setDelay] = React.useState(selectedAction?.execution_delay || 0); + const [fieldCount, setFieldCount] = React.useState(0); const [hiddenDescription, setHiddenDescription] = React.useState(true); const [autoCompleting, setAutocompleting] = React.useState(false); const [selectedActionParameters, setSelectedActionParameters] = React.useState(selectedAction.parameters); const [selectedVariableParameter, setSelectedVariableParameter] = React.useState(""); + const [paramValues, setParamValues] = React.useState( + selectedAction.parameters.map((param) => param.value) || [] + ); const [actionlist, setActionlist] = React.useState([]); const [jsonList, setJsonList] = React.useState([]); const [showDropdown, setShowDropdown] = React.useState(false); @@ -386,8 +390,9 @@ const ParsedAction = (props) => { console.log("UseEffect Rendered!") console.log("Workflow", workflow) setAppActionName(selectedAction.label) - setDelay(selectedAction.execution_delay) + setDelay(selectedAction?.execution_delay) + setParamValues(selectedAction.parameters.map((param) => param.value) || []) // if (selectedActionParameters !== undefined && selectedActionParameters !== null // ) { if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { @@ -634,6 +639,16 @@ const ParsedAction = (props) => { console.log("selectedAction: ", selectedAction) console.log("ACTIONLIST: ", actionlist) console.log("selectedVariableParameter", selectedVariableParameter) + + const handleParamChange = (event, count,data) => { + setParamValues((prev) => { + const newValues = [...prev]; + newValues[count] = event.target.value; + return newValues; + } + ); + changeActionParameter(event, count, data) + } const calculateHelpertext = (input_data) => { var helperText = "" var looperText = "" @@ -1574,7 +1589,7 @@ const ParsedAction = (props) => { MenuProps={{ disableScrollLock: true, }} - defaultValue={selectedAction.app_version} + value={selectedAction.app_version} onChange={(event) => { const newversion = selectedApp.versions.find( (tmpApp) => tmpApp.version == event.target.value @@ -2340,22 +2355,23 @@ 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 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) { - params.inputProps.value = params.inputProps.value.charAt(0).toUpperCase()+params.inputProps.value.substring(1) + renderInput={(params) => { + if (params.inputProps?.value) { + const prefixes = ["Post", "Put", "Patch"]; + for (let prefix of prefixes) { + if (params.inputProps.value.startsWith(prefix)) { + let newValue = params.inputProps.value.replace(prefix + " ", ""); + if (newValue.length > 1) { + newValue = newValue.charAt(0).toUpperCase() + newValue.substring(1); } - break + // Set the new value without mutating inputProps + params = { ...params, inputProps: { ...params.inputProps, value: newValue } }; + break; } } - // Check if it starts with "Get List" and method is "Get" if (params.inputProps.value.startsWith("Get List")) { - console.log("Get List") + console.log("Get List"); } } @@ -2802,9 +2818,9 @@ const ParsedAction = (props) => { placeholder = data.example; - if (data.name === "url") { - data.value = data.example; - } + // if (data.name === "url") { + // data.value = data.example; + // } // In case of data.example if (data.value === undefined || data.value === null) { data.value = "" @@ -3046,7 +3062,6 @@ const ParsedAction = (props) => { } } //selectedActionParameters - if (changed) { // Sort selectedActionParameters based on selectedActionParameters.required //selectedActionParameters.sort((a, b) => (a.required < b.required) ? 1 : -1) @@ -3175,8 +3190,8 @@ const ParsedAction = (props) => { id={clickedFieldId} rows={data.name.startsWith("${") && data.name.endsWith("}") ? 2 : rows} color="primary" - defaultValue={data.value} - // value={data.value} + // defaultValue={data.value} + value={paramValues[count] !== undefined ? paramValues[count] : data.value} //options={{ // theme: 'gruvbox-dark', // keyMap: 'sublime', @@ -3196,7 +3211,8 @@ const ParsedAction = (props) => { placeholder={placeholder} onChange={(event) => { //changeActionParameterCodemirror(event, count, data) - changeActionParameter(event, count, data); + // changeActionParameter(event, count, data); + handleParamChange(event, count, data) }} helperText={returnHelperText(data.name, data.value)} onBlur={(event) => { From a56b5ed8bf35fca0469368eb2eebbd4fca26b8ae Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Mon, 10 Jun 2024 15:18:48 +0530 Subject: [PATCH 08/22] Fixed the delay issue --- frontend/src/components/ParsedAction.jsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 2d428ca8..70a5970a 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -390,16 +390,15 @@ const ParsedAction = (props) => { console.log("UseEffect Rendered!") console.log("Workflow", workflow) setAppActionName(selectedAction.label) - setDelay(selectedAction?.execution_delay) - + setDelay(selectedAction?.execution_delay || 0) + if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { + console.log("Setting action parameters!!") + setSelectedActionParameters(selectedAction.parameters); + // } + } setParamValues(selectedAction.parameters.map((param) => param.value) || []) // if (selectedActionParameters !== undefined && selectedActionParameters !== null // ) { - if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { - console.log("Setting action parameters!!") - setSelectedActionParameters(selectedAction.parameters); - // } - } if ((selectedVariableParameter === null || selectedVariableParameter === undefined) && workflow.workflow_variables !== null && workflow.workflow_variables.length > 0) { // FIXME - this is the bad thing From 5b48e290d723eaf9221602b4c02954a272b1e9c3 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Tue, 11 Jun 2024 16:09:01 +0530 Subject: [PATCH 09/22] Fixed the bug with param value change --- frontend/src/components/ParsedAction.jsx | 39 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 70a5970a..af509c51 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -183,11 +183,16 @@ const ParsedAction = (props) => { const [fieldCount, setFieldCount] = React.useState(0); const [hiddenDescription, setHiddenDescription] = React.useState(true); const [autoCompleting, setAutocompleting] = React.useState(false); - const [selectedActionParameters, setSelectedActionParameters] = React.useState(selectedAction.parameters); + const [selectedActionParameters, setSelectedActionParameters] = React.useState(selectedAction?.parameters || []); const [selectedVariableParameter, setSelectedVariableParameter] = React.useState(""); const [paramValues, setParamValues] = React.useState( - selectedAction.parameters.map((param) => param.value) || [] - ); + selectedAction?.parameters.map((param) => { + return { + name: param.name, + value: param.value, + } + }) + ); const [actionlist, setActionlist] = React.useState([]); const [jsonList, setJsonList] = React.useState([]); const [showDropdown, setShowDropdown] = React.useState(false); @@ -201,8 +206,17 @@ const ParsedAction = (props) => { setLastSaved(false) } }, [expansionModalOpen]) + useEffect(() => { + setParamValues(selectedAction.parameters.map((param) => { + return { + name: param.name, + value: param.value, + } + })) + },[ + selectedAction, selectedApp,setNewSelectedAction + ]) - useEffect(() => { if (selectedAction.parameters === null || selectedAction.parameters === undefined) { return @@ -396,7 +410,6 @@ const ParsedAction = (props) => { setSelectedActionParameters(selectedAction.parameters); // } } - setParamValues(selectedAction.parameters.map((param) => param.value) || []) // if (selectedActionParameters !== undefined && selectedActionParameters !== null // ) { if ((selectedVariableParameter === null || selectedVariableParameter === undefined) && workflow.workflow_variables !== null && workflow.workflow_variables.length > 0) { @@ -638,14 +651,14 @@ const ParsedAction = (props) => { console.log("selectedAction: ", selectedAction) console.log("ACTIONLIST: ", actionlist) console.log("selectedVariableParameter", selectedVariableParameter) - const handleParamChange = (event, count,data) => { - setParamValues((prev) => { - const newValues = [...prev]; - newValues[count] = event.target.value; - return newValues; - } - ); + const newParams = [...paramValues]; + newParams.map((param) => { + if (param.name === data.name) { + param.value = event.target.value; + } + }) + setParamValues(newParams); changeActionParameter(event, count, data) } const calculateHelpertext = (input_data) => { @@ -3190,7 +3203,7 @@ const ParsedAction = (props) => { rows={data.name.startsWith("${") && data.name.endsWith("}") ? 2 : rows} color="primary" // defaultValue={data.value} - value={paramValues[count] !== undefined ? paramValues[count] : data.value} + value={data.value} //options={{ // theme: 'gruvbox-dark', // keyMap: 'sublime', From 70a313d40a11cc567f2ef8f0c865ef31fe7fde3b Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Tue, 11 Jun 2024 16:23:31 +0530 Subject: [PATCH 10/22] Fixed the autoComplete issue:Closecase in Hive --- frontend/src/components/ParsedAction.jsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index af509c51..12f81ad8 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -885,10 +885,12 @@ const ParsedAction = (props) => { } //console.log("CHANGING ACTION COUNT !") - selectedActionParameters[count].autocompleted = false - selectedAction.parameters[count].autocompleted = false - selectedActionParameters[count].value = event.target.value; - selectedAction.parameters[count].value = event.target.value; + setTimeout(() => { + // selectedActionParameters[count].autocompleted = false + selectedAction.parameters[count].autocompleted = false + // selectedActionParameters[count].value = event.target.value; + selectedAction.parameters[count].value = event.target.value; + },100) var forceUpdate = false if (isCloud && (selectedAction.app_name === "Shuffle Tools" || selectedAction.app_name === "email") && (selectedAction.name === "send_email_shuffle" || selectedAction.name === "send_sms_shuffle") && data.name === "apikey") { @@ -3994,7 +3996,7 @@ const ParsedAction = (props) => { } const buttonTitle = `Authenticate ${selectedApp.name.replaceAll("_", " ")}` - const hasAutocomplete = data.autocompleted === true + const hasAutocomplete = data?.autocompleted === true return (
    {hideBodyButton} From df8493ae69eb2cc9722cd6c5b4f884381d0d6e45 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Tue, 11 Jun 2024 16:32:01 +0530 Subject: [PATCH 11/22] Solved the param change issue --- frontend/src/components/ParsedAction.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 12f81ad8..5f7edc20 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -3205,7 +3205,11 @@ const ParsedAction = (props) => { rows={data.name.startsWith("${") && data.name.endsWith("}") ? 2 : rows} color="primary" // defaultValue={data.value} - value={data.value} + value={ + paramValues.find((param) => param.name === data.name) !== undefined + ? paramValues.find((param) => param.name === data.name).value + : data.value + } //options={{ // theme: 'gruvbox-dark', // keyMap: 'sublime', From bcda8c6143d26ead65960486a7dee7c760cf1631 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Tue, 11 Jun 2024 17:11:55 +0530 Subject: [PATCH 12/22] Fixed the dropdown bug in UserInputSidebar --- frontend/src/views/AngularWorkflow.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index bece66c2..be234c12 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -14944,6 +14944,7 @@ const AngularWorkflow = (defaultprops) => { onChange={(event, newValue) => { console.log("Changed autocomplete!") handleWorkflowSelectionUpdate({ target: { value: newValue } }, true) + event.target.blur(); }} renderOption={(props, data, state) => { if (data.id === workflow.id) { @@ -14972,6 +14973,7 @@ const AngularWorkflow = (defaultprops) => { value: data, }}, true) + document.activeElement.blur(); }} > From e87b112ff6fc521e78477d6a1bee71d41ce5b936 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Wed, 12 Jun 2024 12:59:09 +0530 Subject: [PATCH 13/22] Fixed the bug --- frontend/src/components/ParsedAction.jsx | 390 +++++++++-------------- 1 file changed, 154 insertions(+), 236 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 5f7edc20..c02afb09 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -401,244 +401,160 @@ const ParsedAction = (props) => { useEffect( () => { - console.log("UseEffect Rendered!") - console.log("Workflow", workflow) - setAppActionName(selectedAction.label) - setDelay(selectedAction?.execution_delay || 0) - if (selectedAction.parameters !== undefined && selectedAction.parameters !== null && selectedAction.parameters.length > 0) { - console.log("Setting action parameters!!") - setSelectedActionParameters(selectedAction.parameters); - // } - } - // if (selectedActionParameters !== undefined && selectedActionParameters !== null - // ) { - if ((selectedVariableParameter === null || selectedVariableParameter === undefined) && workflow.workflow_variables !== null && workflow.workflow_variables.length > 0) { - - // FIXME - this is the bad thing - setSelectedVariableParameter(workflow.workflow_variables[0].name); - } - - if (actionlist.length === 0) { - // FIXME: Have previous execution values in here - if (workflowExecutions.length > 0) { - for (let [key,keyval] in Object.entries(workflowExecutions)) { - if ( - workflowExecutions[key].execution_argument === undefined || - workflowExecutions[key].execution_argument === null || - workflowExecutions[key].execution_argument.length === 0 - ) { - continue; - } - - const valid = validateJson(workflowExecutions[key].execution_argument) - if (valid.valid) { - actionlist.push({ - type: "Execution Argument", - name: "Execution Argument", - value: "$exec", - highlight: "exec", - autocomplete: "exec", - example: valid.result, - }) - break - } - } - + console.log("UseEffect Rendered!"); + console.log("Workflow", workflow); + + // Only set app action name if it has changed + if (selectedAction.label !== appActionName) { + setAppActionName(selectedAction.label); } - + + // Only set delay if it has changed + const newDelay = selectedAction?.execution_delay || 0; + if (newDelay !== delay) { + setDelay(newDelay); + } + + // Only set selected action parameters if they have changed + if (selectedAction.parameters && selectedAction.parameters.length > 0) { + console.log("Setting action parameters!!"); + setSelectedActionParameters(selectedAction.parameters); + } + + // Only set selected variable parameter if it is null or undefined + if (!selectedVariableParameter && workflow.workflow_variables?.length > 0) { + setSelectedVariableParameter(workflow.workflow_variables[0].name); + } + + // Initialize action list if it is empty if (actionlist.length === 0) { - actionlist.push({ - type: "Execution Argument", - name: "Execution Argument", - value: "$exec", - highlight: "exec", - autocomplete: "exec", - example: "", - }) - } - - /* - actionlist.push({ - type: "Shuffle DB", - name: "Shuffle DB", - value: "$shuffle_cache", - highlight: "shuffle_cache", - autocomplete: "shuffle_cache", - example: { - "what": "", - "unique gmail ids new": "", - }, - }) - */ - - var cachekey = { - type: "Shuffle DB", - name: "Shuffle DB", - value: "$shuffle_cache", - highlight: "shuffle_cache", - autocomplete: "shuffle_cache", - example: "", - } - - if (listCache !== undefined && listCache !== null && listCache.keys !== undefined && listCache.keys !== null && listCache.keys.length > 0) { - cachekey.example = {} - - for (var i in listCache.keys) { - const item = listCache.keys[i] - if (item.key === undefined || item.key === null || item.key.length === 0) { - continue - } - - var itemvalue = item.value === undefined || item.value === null ? "" : item.value - try{ - if (itemvalue.length > 10000) { - itemvalue = "" - } - - } catch (e) { - itemvalue = "" - } - - var itemkey = item.key.split(" ").join("_") - cachekey.example[itemkey] = { - "value": itemvalue, - } - } - } else { - } - - actionlist.push(cachekey) - - if (workflow.workflow_variables !== null && workflow.workflow_variables !== undefined && workflow.workflow_variables.length > 0) { - for (let [key,keyval] in Object.entries(workflow.workflow_variables)) { - const item = workflow.workflow_variables[key]; - actionlist.push({ - type: "workflow_variable", - name: item.name, - value: item.value, - id: item.id, - autocomplete: `${item.name.split(" ").join("_")}`, - example: item.value, - }); - } - } - - if (workflow.execution_variables !== null && workflow.execution_variables !== undefined && workflow.execution_variables.length > 0) { - for (let [key,keyval] in Object.entries(workflow.execution_variables)) { - const item = workflow.execution_variables[key] - - var exampleoutput = "" - for (let execkey in workflowExecutions) { - const exec = workflowExecutions[execkey] - if (exec["execution_variables"] === undefined || exec["execution_variables"] === null) { - continue - } - - const foundExec = exec.execution_variables.find((exvar) => exvar.name === item.name) - if (!foundExec) { - continue - } - - if (foundExec.value !== undefined && foundExec.value !== null && foundExec.value.length > 0) { - exampleoutput = foundExec.value - break - } - } - - actionlist.push({ - type: "execution_variable", - name: item.name, - value: item.value, - id: item.id, - autocomplete: `${item.name.split(" ").join("_")}`, - example: exampleoutput, - }); - } - } - - // Loops parent nodes' old results to fix autocomplete - if (getParents !== undefined) { - var parents = getParents(selectedAction) - - if (parents.length > 1) { - var labels = [] - //for (let [parentkey, parentkeyval] in Object.entries(parents)) { - for (let parentkey in parents) { - const parentNode = parents[parentkey] - if (parentNode.label === "Execution Argument") { - continue - } - - //if (labels.includes(item.label)) { - // continue - //} - - labels.push(parentNode.label) - - var exampledata = parentNode.example === undefined || parentNode.example === null ? "" : parentNode.example - // Find previous execution and their variables - //exampledata === "" && - if (workflowExecutions.length > 0) { - // Look for the ID - const found = false; - for (let wfkey in workflowExecutions) { - if (workflowExecutions[wfkey].results === undefined || workflowExecutions[wfkey].results === null) { - - continue; - } - - var foundResult = workflowExecutions[wfkey].results.find((result) => result.action.id === parentNode.id) - - if (foundResult === undefined || foundResult === null) { - continue - } - - if (foundResult.result !== undefined && foundResult.result !== null) { - foundResult = foundResult.result - } - - const valid = validateJson(foundResult) - if (valid.valid) { - if (valid.result.success === false) { - //console.log("Skipping success false autocomplete") - } else { - - // FIXME: Have a merge system to allow to use kind of any key from that node in the last 10-20 execs - //if (exampledata.length > 0) { - // exampledata = valid.result - //} else { - // exampledata = valid.result - //} - - exampledata = valid.result - break + if (workflowExecutions.length > 0) { + for (let [key, keyval] of Object.entries(workflowExecutions)) { + const execArg = workflowExecutions[key].execution_argument; + if (execArg && execArg.length > 0) { + const valid = validateJson(execArg); + if (valid.valid) { + actionlist.push({ + type: "Execution Argument", + name: "Execution Argument", + value: "$exec", + highlight: "exec", + autocomplete: "exec", + example: valid.result, + }); + break; + } } - } else { - exampledata = foundResult } - } - } - - // 1. Take - const itemlabelComplete = parentNode.label === null || parentNode.label === undefined ? "" : parentNode.label.split(" ").join("_"); - - const actionvalue = { - type: "action", - id: parentNode.id, - name: parentNode.label, - autocomplete: itemlabelComplete, - example: exampledata, - } - - actionlist.push(actionvalue) - } - } - - setActionlist(actionlist); - } - } - }, - [selectedAction,selectedApp,setNewSelectedAction] + } + + if (actionlist.length === 0) { + actionlist.push({ + type: "Execution Argument", + name: "Execution Argument", + value: "$exec", + highlight: "exec", + autocomplete: "exec", + example: "", + }); + } + + let cacheKey = { + type: "Shuffle DB", + name: "Shuffle DB", + value: "$shuffle_cache", + highlight: "shuffle_cache", + autocomplete: "shuffle_cache", + example: "", + }; + + if (listCache?.keys?.length > 0) { + cacheKey.example = {}; + for (let item of listCache.keys) { + if (item.key) { + let itemValue = item.value ?? ""; + if (itemValue.length > 10000) { + itemValue = ""; + } + cacheKey.example[item.key.split(" ").join("_")] = { value: itemValue }; + } + } + } + + actionlist.push(cacheKey); + + if (workflow.workflow_variables?.length > 0) { + for (let [key, keyval] of Object.entries(workflow.workflow_variables)) { + const item = workflow.workflow_variables[key]; + actionlist.push({ + type: "workflow_variable", + name: item.name, + value: item.value, + id: item.id, + autocomplete: item.name.split(" ").join("_"), + example: item.value, + }); + } + } + + if (workflow.execution_variables?.length > 0) { + for (let [key, keyval] of Object.entries(workflow.execution_variables)) { + const item = workflow.execution_variables[key]; + let exampleOutput = ""; + for (let exec of workflowExecutions) { + const foundExec = exec.execution_variables?.find(exvar => exvar.name === item.name); + if (foundExec?.value) { + exampleOutput = foundExec.value; + break; + } + } + actionlist.push({ + type: "execution_variable", + name: item.name, + value: item.value, + id: item.id, + autocomplete: item.name.split(" ").join("_"), + example: exampleOutput, + }); + } + } + + if (getParents) { + const parents = getParents(selectedAction); + if (parents.length > 1) { + const labels = []; + for (let parentNode of parents) { + if (parentNode.label !== "Execution Argument" && !labels.includes(parentNode.label)) { + labels.push(parentNode.label); + let exampleData = parentNode.example ?? ""; + if (!exampleData && workflowExecutions.length > 0) { + for (let exec of workflowExecutions) { + const foundResult = exec.results?.find(result => result.action.id === parentNode.id); + if (foundResult) { + const valid = validateJson(foundResult.result); + if (valid.valid && valid.result.success !== false) { + exampleData = valid.result; + break; + } + } + } + } + actionlist.push({ + type: "action", + id: parentNode.id, + name: parentNode.label, + autocomplete: parentNode.label.split(" ").join("_"), + example: exampleData, + }); + } + } + } + } + + setActionlist(actionlist); + } + }, + [selectedAction,selectedApp,setNewSelectedAction,workflow, workflowExecutions, listCache, getParents, actionlist] ); useEffect(() => { @@ -886,9 +802,9 @@ const ParsedAction = (props) => { //console.log("CHANGING ACTION COUNT !") setTimeout(() => { - // selectedActionParameters[count].autocompleted = false + selectedActionParameters[count].autocompleted = false selectedAction.parameters[count].autocompleted = false - // selectedActionParameters[count].value = event.target.value; + selectedActionParameters[count].value = event.target.value; selectedAction.parameters[count].value = event.target.value; },100) @@ -1060,10 +976,12 @@ const ParsedAction = (props) => { } } + setTimeout(() => { selectedActionParameters[count].autocompleted = false selectedAction.parameters[count].autocompleted = false selectedActionParameters[count].value = data selectedAction.parameters[count].value = data + }, 100); setSelectedAction(selectedAction) //setUpdate(Math.random()) //setUpdate(event.target.value) From da4e25f6c9c97c1058a6dad089ab5e10c6999b74 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Wed, 12 Jun 2024 23:38:52 +0530 Subject: [PATCH 14/22] Fixes in ParsedAction --- frontend/src/components/ParsedAction.jsx | 33 ++++++++++++++---------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index c02afb09..60e87f22 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -206,16 +206,16 @@ const ParsedAction = (props) => { setLastSaved(false) } }, [expansionModalOpen]) - useEffect(() => { - setParamValues(selectedAction.parameters.map((param) => { - return { - name: param.name, - value: param.value, - } - })) - },[ - selectedAction, selectedApp,setNewSelectedAction - ]) +// useEffect(() => { +// setParamValues(selectedAction.parameters.map((param) => { +// return { +// name: param.name, +// value: param.value, +// } +// })) +// },[ +// selectedAction, selectedApp,setNewSelectedAction +// ]) useEffect(() => { if (selectedAction.parameters === null || selectedAction.parameters === undefined) { @@ -404,6 +404,12 @@ const ParsedAction = (props) => { console.log("UseEffect Rendered!"); console.log("Workflow", workflow); + setParamValues(selectedAction.parameters.map((param) => { + return { + name: param.name, + value: param.value, + } + })) // Only set app action name if it has changed if (selectedAction.label !== appActionName) { setAppActionName(selectedAction.label); @@ -554,14 +560,13 @@ const ParsedAction = (props) => { setActionlist(actionlist); } }, - [selectedAction,selectedApp,setNewSelectedAction,workflow, workflowExecutions, listCache, getParents, actionlist] + [selectedAction,selectedApp,setNewSelectedAction,workflow, workflowExecutions, getParents] ); - useEffect(() => { selectedNameChange(appActionName) actionDelayChange(delay) },[appActionName,delay]) - + console.log("selectedActionParameters: ", selectedActionParameters) console.log("selectedApp:", selectedApp) console.log("selectedAction: ", selectedAction) @@ -3126,7 +3131,7 @@ const ParsedAction = (props) => { value={ paramValues.find((param) => param.name === data.name) !== undefined ? paramValues.find((param) => param.name === data.name).value - : data.value + : "" } //options={{ // theme: 'gruvbox-dark', From 50dcf618a0f1fcc668a1e914b2c9ca02066d5f11 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Thu, 13 Jun 2024 00:04:33 +0530 Subject: [PATCH 15/22] Changes --- frontend/src/views/AngularWorkflow.jsx | 546 +++++++------------------ 1 file changed, 144 insertions(+), 402 deletions(-) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index be234c12..2f9a123d 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -553,7 +553,7 @@ const AngularWorkflow = (defaultprops) => { }, [editWorkflowModalOpen]) // New for generated stuff - const releaseToConnectLabel = "Release to Connect" +const releaseToConnectLabel = "Release to Connect" const integrationApps = [{ "id": "integration", "name": "Integration Framework", @@ -1446,18 +1446,18 @@ const AngularWorkflow = (defaultprops) => { trigger.parameters = [] - const topic = document.getElementById('topic')?.value - const bootstrapServers = document.getElementById('bootstrap_servers')?.value - const groupId = document.getElementById('group_id')?.value + const topic = document.getElementById('topic')?.value; + const bootstrapServers = document.getElementById('bootstrap_servers')?.value; + const groupId = document.getElementById('group_id')?.value; //const autoOffsetReset = document.getElementById('auto_offset_reset')?.value; if(topic) { trigger.parameters.push({ name: "topic", value: topic - }) + }); } else { - toast("Please enter the topic name"); + toast("please enter the topic name"); return; } @@ -3283,19 +3283,12 @@ const AngularWorkflow = (defaultprops) => { // don't redirect if it exists const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search; var execFound = new URLSearchParams(cursearch).get("execution_id"); - var sessionToken = new URLSearchParams(cursearch).get("session_token"); - if (execFound === null && sessionToken === null) { - toast(`You don't have access to this workflow or loading failed. Redirecting to workflows in a few seconds..`) - setTimeout(() => { - window.location.pathname = "/workflows"; - }, 2000); - } else if (sessionToken !== null && workflow_id === "3abdfb21-b40f-4e50-b855-ac0d62f83cbe") { - toast(`Injecting session token and reloading workflow..`) - setTimeout(() => { - setCookie("session_token", sessionToken, { path: "/" }); - window.location.href = "https://shuffler.io/workflows/3abdfb21-b40f-4e50-b855-ac0d62f83cbe"; - }, 2000); - } + if (execFound === null) { + toast(`You don't access to this workflow or loading failed. Redirecting to workflows in a few seconds..`) + setTimeout(() => { + window.location.pathname = "/workflows"; + }, 2000); + } } } @@ -3776,28 +3769,20 @@ const AngularWorkflow = (defaultprops) => { const onNodeDragStop = (event, selectedAction) => { const nodedata = event.target.data(); if (nodedata.id === selectedAction.id) { - //console.log("Same node, return") - return + return; } if (nodedata.finished === false) { - //console.log("Node is not finished, return") - return + return; } const connected = event.target.connectedEdges().jsons() if (connected.length > 0 && connected !== undefined) { for (let connectkey in connected) { const edge = connected[connectkey] - if (edge.data.decorator && edge.data.label === releaseToConnectLabel) { - // Transform to normal edge - const currentedge = cy.getElementById(edge.data.id) - if (currentedge !== undefined && currentedge !== null) { - currentedge.data("decorator", false) - currentedge.data("label", "") - } - continue - } + //console.log("EDGE:", edge) + + //const edge = edgeBase.json() const sourcenode = cy.getElementById(edge.data.source) const destinationnode = cy.getElementById(edge.data.target) @@ -4012,141 +3997,26 @@ const AngularWorkflow = (defaultprops) => { } if (nodedata.id === selectedAction.id) { - return + return; } - - if ((nodedata.trigger_type === "SUBFLOW" || nodedata.trigger_type === "USERINPUT" || nodedata.type === "ACTION") && !nodedata.isStartNode) { - // Check if it already has any non-decorator branches attached to it - const branches = cy.elements('edge').jsons() - var branchFound = false - var decoratorIds = [] - for (var branchkey in branches) { - if (branches[branchkey].data.source === nodedata.id || branches[branchkey].data.target === nodedata.id) { - - if (branches[branchkey].data.decorator === true) { - - // Add the source/destination - if (branches[branchkey].data.source === nodedata.id) { - decoratorIds.push(branches[branchkey].data.target) - } else { - decoratorIds.push(branches[branchkey].data.source) - } - - continue - } - - branchFound = true - break - } - } - - if (!branchFound) { - //console.log("Found action during drag. Checking closest nodes as it doesn't have a valid branch") - var closestNode = null - var minDistance = 300 - - const draggedNode = event.target - const allnodes = cy.nodes().jsons() - for (var nodekey in allnodes) { - const node = allnodes[nodekey] - if (node.data.id === nodedata.id) { - continue - } - - // Decorators - if (node.data.attachedTo !== undefined) { - continue - } - - if (node.position === undefined || node.position === null || node.position.x === undefined || node.position.y === undefined) { - continue - } - - if (node.data.type !== "ACTION" && node.data.type !== "TRIGGER") { - continue - } - - const distance = Math.sqrt( - Math.pow(draggedNode.position('x') - node.position.x, 2) + - Math.pow(draggedNode.position('y') - node.position.y, 2) - ) - - if (decoratorIds.includes(node.data.id)) { - //console.log("Found existing decorator for: ", node.data.app_name, "Distance: ", distance) - - if (distance > 300) { - // Remove the branch - const edgeToRemove = cy.getElementById(branches[branchkey].data.id) - if (edgeToRemove !== null && edgeToRemove !== undefined) { - //console.log("Removing edge: ", edgeToRemove) - edgeToRemove.remove() - //decoratorIds.splice(decoratorIds.indexOf(node.data.id), 1) - break - } - } - } - if (distance < minDistance) { - minDistance = distance - closestNode = node - } - } + /* + // Tried looking for the closest node by position. aStar path not working entirely. + console.log("NODE: ", event.target) + const closestNode = cy.elements().aStar({ + root: nodedata.id, + goal: 'node', + directed: false, + }) - if (closestNode !== null && closestNode !== undefined) { - //console.log("Closest node app: ", closestNode.data.app_name, "Distance: ", minDistance) - - /* - if (decoratorIds.length > 0) { - console.log("Decorators already exists. If within distance of 15 add to existing, otherwise remove old and add new: ", decoratorIds) - for (var decoratorkey in decoratorIds) { - const decoratorEdge = cy.getElementById(decoratorIds[decoratorkey]) - if (decoratorEdge === null || decoratorEdge === undefined) { - continue - } - - const sourceNode = cy.getElementById(decoratorEdge.data.source) - const targetNode = cy.getElementById(decoratorEdge.data.target) - - const distance = Math.sqrt( - Math.pow(draggedNode.position('x') - sourceNode.position('x'), 2) + - Math.pow(draggedNode.position('y') - sourceNode.position('y'), 2) - ) - - // Check plus minus 15 in distance from mindistance - if (distance > minDistance - 15 && distance < minDistance + 15) { - console.log("Within distance of 15, add to existing edge") - } else { - console.log("Outside distance of 15, remove old edge and add new") - } - - } - } - */ - - if (decoratorIds.length === 0) { - //const edgeCurve = calculateEdgeCurve(draggedNode.position(), closestNode.position) - //currentedge.style('control-point-distance', edgeCurve.distance) - //currentedge.style('control-point-weight', edgeCurve.weight) - - const newId = uuidv4() - cy.add({ - group: "edges", - data: { - decorator: true, - id: newId, - _id: newId, - source: closestNode.data.id, - target: nodedata.id, - label: releaseToConnectLabel, - conditions: [], - } - }) - } - } - } - } + if (closestNode.found) { + console.log("No closest node found for: ", nodedata.id) + } else { + console.log("Closest: ", closestNode) + } + */ if ( originalLocation.x === 0 && @@ -4205,11 +4075,11 @@ const AngularWorkflow = (defaultprops) => { } // Ensure it only happens once - document.removeEventListener("mousemove", onMouseUpdate, false) - } + document.removeEventListener("mousemove", onMouseUpdate, false); + }; - document.addEventListener("mousemove", onMouseUpdate, false) - } + document.addEventListener("mousemove", onMouseUpdate, false); + }; useBeforeunload(() => { @@ -4222,7 +4092,7 @@ const AngularWorkflow = (defaultprops) => { document.removeEventListener("paste", handlePaste, true); } } - }) + }); // Should get AI autocompletes const aiSubmit = (value, setResponseMsg, setSuggestionLoading, inputAction) => { @@ -5624,10 +5494,11 @@ const AngularWorkflow = (defaultprops) => { // Checks for errors in edges when they're added const onEdgeAdded = (event) => { - const edge = event.target.data() - //console.log("EDGE ADDED!: ", edge) + setLastSaved(false); + const edge = event.target.data(); + + //console.log("edge added: ", edge) if (edge.source === undefined && edge.target === undefined) { - console.log("Edge source and target is undefined") return } @@ -5641,7 +5512,6 @@ const AngularWorkflow = (defaultprops) => { const sourcenode = cy.getElementById(edge.source) const destinationnode = cy.getElementById(edge.target) if (sourcenode === undefined || sourcenode === null || destinationnode === undefined || destinationnode === null) { - console.log("Source or destination node is undefined") } else { //console.log("Edge added: Is it a trigger? If so, check if it already has a branch and remove it: ", sourcenode.data()) if (sourcenode.data("type") === "TRIGGER") { @@ -5654,10 +5524,10 @@ const AngularWorkflow = (defaultprops) => { console.log("Node: ", targetedge) if (targetedge !== -1) { + event.target.remove() //console.log("Found branch already!") toast.error("Triggers can have exactly one target node") - event.target.remove() return @@ -5678,10 +5548,6 @@ const AngularWorkflow = (defaultprops) => { } } - if (edge.decorator === true) { - console.log("Doing nothing to branch because decorator") - return - } var targetnode = workflow.triggers.findIndex( (data) => data.id === edge.target @@ -5721,14 +5587,15 @@ const AngularWorkflow = (defaultprops) => { } } - if (eventTarget.data("isDescriptor") === true || eventTarget.data("type") === "COMMENT") { + if ( + eventTarget.data("isDescriptor") === true || + eventTarget.data("type") === "COMMENT" + ) { console.log("Removing because of descriptor or comment") - event.target.remove() - return + event.target.remove(); + return; } - - setLastSaved(false) targetnode = -1; // Check if: @@ -5736,51 +5603,38 @@ const AngularWorkflow = (defaultprops) => { // dest == dest && source == source // backend: check all children? to stop recursion var found = false; - const branches = cy.edges().jsons() - - const startNode = cy.nodes().jsons().find((node) => node.data.isStartNode === true) - var startnodeId = workflow.start - if (startNode !== undefined && startNode !== null) { - startnodeId = startNode.data.id - } - - //for (let branchkey in workflow.branches) { - for (let branchkey in branches) { - const branch = branches[branchkey].data - - //if (workflow.branches[branchkey].destination_id === edge.source && workflow.branches[branchkey].source_id === edge.target) { - if (branch.target === edge.source && branch.source === edge.target) { - toast("A branch in the opposite direction already exists") - event.target.remove() - found = true - break - - //} else if (workflow.branches[branchkey].destination_id === edge.target && workflow.branches[branchkey].source_id === edge.source) { - } else if (branch.target === edge.target && branch.source === edge.source) { - - if (branch.conditions === undefined) { - // Edgehandles - } else { - console.log("Removing because the same branch already exists") - event.target.remove() - - found = true - break - } - } else if (edge.target === startnodeId) { - targetnode = workflow.triggers.findIndex((data) => data.id === edge.source) + for (let branchkey in workflow.branches) { + if ( + workflow.branches[branchkey].destination_id === edge.source && + workflow.branches[branchkey].source_id === edge.target + ) { + toast("A branch in the opposite direction already exists"); + event.target.remove(); + found = true; + break; + } else if ( + workflow.branches[branchkey].destination_id === edge.target && + workflow.branches[branchkey].source_id === edge.source + ) { + //toast("That branch already exists"); + event.target.remove(); + found = true; + break; + } else if (edge.target === workflow.start) { + targetnode = workflow.triggers.findIndex( + (data) => data.id === edge.source + ); if (targetnode === -1) { if (targetnode.type !== "TRIGGER") { - toast("Can't make arrow to starting node") - event.target.remove() - break + toast("Can't make arrow to starting node"); + event.target.remove(); + break; } found = true; } - //} else if (edge.source === workflow.branches[branchkey].source_id) { - } else if (edge.source === branch.source) { + } 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 @@ -5824,6 +5678,7 @@ const AngularWorkflow = (defaultprops) => { newdst !== null ) { const dstdata = RunAutocompleter(newdst.data()); + //console.log("DST Autocompleter: ", dstdata); } var newbranch = { @@ -11538,101 +11393,11 @@ const AngularWorkflow = (defaultprops) => { {/* Check if dest is the same as start */} - {conditionsDisabled ? - - Conditions are unavailable between triggers and the startnode. - - : null} - -
    - {/* - - - - */} - -
    + {conditionsDisabled ? + + Conditions are unavailable between triggers and the startnode. + + : null}
    ); }; @@ -12396,7 +12161,7 @@ const AngularWorkflow = (defaultprops) => { return transformedData; - } + }; const AppAuthSelector = ({ appAuthData }) => { const [selectedAuth, setSelectedAuth] = useState(""); @@ -12409,7 +12174,6 @@ const AngularWorkflow = (defaultprops) => { const handleShowingValue = (appName) => { let mappingWithName = {} let listWithValues = workflow.triggers[selectedTriggerIndex].parameters[5]?.value.split(";").filter(e => e).map(e => e.split("=")) - console.log("LIST WITH VALUES: ", listWithValues) for (let i = 0; i < listWithValues.length; i++) { mappingWithName[listWithValues[i][0]] = listWithValues[i][1] @@ -13092,7 +12856,7 @@ const AngularWorkflow = (defaultprops) => { data: newbranch, }; - cy.add(cybranch) + cy.add(cybranch); } console.log("Value to be set: ", e.target.value); @@ -13636,27 +13400,25 @@ const AngularWorkflow = (defaultprops) => {
    - {/*
    -
    -
    -
    - Auth Override -
    -
    +
    +
    +
    + Auth Override +
    +
    -
    -
    - -
    -
    -
    +
    +
    + +
    +
    +
    - */}
    - ) + ); } return null; @@ -15610,8 +15372,12 @@ const AngularWorkflow = (defaultprops) => { right: 0, left: isMobile ? 20 : leftBarSize + 20, top: isMobile ? 30 : appBarSize + 20, + pointerEvents: "none", } + + + const TopCytoscapeBar = (props) => { if (workflow.public === true) { return null @@ -15627,7 +15393,7 @@ const AngularWorkflow = (defaultprops) => {
    {

    {workflow.name}

    @@ -16376,8 +16143,6 @@ const AngularWorkflow = (defaultprops) => { } } - /* - // Infinitely annoying. Need a new bind if (( event.ctrlKey || event.metaKey ) && event.shiftKey) { console.log("Shift key pressed") if (!workflow.public && executionModalOpen) { @@ -16389,8 +16154,7 @@ const AngularWorkflow = (defaultprops) => { setExecutionModalView(0); } } - */ - } + }; document.addEventListener('keydown', handleKeyDown); @@ -18260,7 +18024,7 @@ const AngularWorkflow = (defaultprops) => {
    {foundnotifications > 0 ? - + { @@ -19319,11 +19083,10 @@ const AngularWorkflow = (defaultprops) => { return "The queries or data sent to the API is most likely wrong (400). Check the body of the result for more information." } - /* if (result.status === 200 || result.status === 201 || result.status === 204) { return "It looks like the result was successful! If it didn't work, make sure to check if the body you are sending was correct." } - */ + // Validate and check for newlines if (result.success !== false) { @@ -21012,9 +20775,8 @@ const AngularWorkflow = (defaultprops) => {
    Configuration options for {selectedOption}
    - - {selectedOption === "Kafka Queue" ? -
    + {selectedOption === "Kafka Queue" && ( + <> Topic { placeholder={"earliest"} defaultValue={(selectedTrigger?.parameters?.find(param => param.name === "auto_offset_reset")?.value) || ''} /> */} -
    - : null} - - param.name === "bootstrap_servers")?.value) || ''} - /> - + + )}
    + } + parentMenuOpen={!!menuPosition} + style={{ + color: "white", + minWidth: 250, + maxWidth: 250, + maxHeight: 50, + overflow: "hidden", + }} + onClick={() => { + console.log("CLICKED: ", innerdata); + console.log(innerdata.example) + handleItemClick([innerdata]); + }} + > + + + { + //console.log("HOVER: ", pathdata); + }} + onClick={() => { + handleItemClick([innerdata]); + }} + > + + {innerdata.name} + + + + {parsedPaths.map((pathdata, index) => { + // FIXME: Should be recursive in here + // + const icon = + pathdata.type === "value" ? ( + + ) : pathdata.type === "list" ? ( + + ) : ( + + ); + // + + const indentation_count = (pathdata.name.match(/\./g) || []).length+1 + const baseIndent =
    + //const boxPadding = pathdata.type === "object" ? "10px 0px 0px 0px" : 0 + const boxPadding = 0 + const namesplit = pathdata.name.split(".") + const newname = namesplit[namesplit.length-1] + return ( + { + //console.log("HOVER: ", pathdata); + }} + onClick={() => { + handleItemClick([innerdata, pathdata]); + }} + > + +
    + {Array(indentation_count).fill().map((subdata, subindex) => { + return ( + baseIndent + ) + })} + {icon} {newname} + {pathdata.type === "list" ? { + + }} /> : null} +
    +
    +
    + ); + })} + + + + ) : ( + handleMouseover()} + onMouseOut={() => { + handleMouseOut(); + }} + onClick={() => { + handleItemClick([innerdata]); + }} + > + +
    + {icon} {innerdata.name} +
    +
    +
    + ); + })} + } {/*
    0) { defaultReturn = } else if (Object.getOwnPropertyNames(selectedTrigger).length > 0) { - if (selectedTrigger.trigger_type === "SUBFLOW") { - defaultReturn = - } else if (selectedTrigger.trigger_type === "EMAIL") { + if (selectedTrigger.trigger_type === "EMAIL") { defaultReturn = } else if (selectedTrigger.trigger_type === undefined) { //defaultReturn = @@ -19648,6 +19636,13 @@ const releaseToConnectLabel = "Release to Connect" : null}
    : null} + + { + rightSideBarOpen && selectedTrigger.trigger_type === "SUBFLOW"&& Object.getOwnPropertyNames(selectedTrigger).length > 0 ? +
    + +
    : null + } {/* Date: Mon, 17 Jun 2024 11:42:15 +0530 Subject: [PATCH 19/22] Made paramValues separate --- frontend/src/components/ParsedAction.jsx | 27 ++++++++++-------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 9bf06710..a9b0c955 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -206,16 +206,16 @@ const ParsedAction = (props) => { setLastSaved(false) } }, [expansionModalOpen]) -// useEffect(() => { -// setParamValues(selectedAction.parameters.map((param) => { -// return { -// name: param.name, -// value: param.value, -// } -// })) -// },[ -// selectedAction, selectedApp,setNewSelectedAction -// ]) + useEffect(() => { + setParamValues(selectedAction.parameters.map((param) => { + return { + name: param.name, + value: param.value, + } + })) + },[ + selectedAction, selectedApp,setNewSelectedAction, setUpdate, showDropdown, showAutocomplete, selectedActionParameters + ]) // useEffect(() => { // if (selectedAction.parameters === null || selectedAction.parameters === undefined) { @@ -404,12 +404,7 @@ const ParsedAction = (props) => { console.log("UseEffect Rendered!"); console.log("Workflow", workflow); - setParamValues(selectedAction.parameters.map((param) => { - return { - name: param.name, - value: param.value, - } - })) + // Only set app action name if it has changed if (selectedAction.label !== appActionName) { setAppActionName(selectedAction.label); From 1570f852b43fb1bc1ce98d03adb7cff70defa9c1 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Mon, 17 Jun 2024 16:52:43 +0530 Subject: [PATCH 20/22] Fixed the exec args issue --- frontend/src/components/ParsedAction.jsx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index a9b0c955..5761da74 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -214,9 +214,24 @@ const ParsedAction = (props) => { } })) },[ - selectedAction, selectedApp,setNewSelectedAction, setUpdate, showDropdown, showAutocomplete, selectedActionParameters + selectedAction, selectedApp,setNewSelectedAction, workflow, ]) +// useEffect(() => { +// if(!showAutocomplete){ +// paramValueChange(); +// } +// },[menuPosition,showAutocomplete]) + +// const paramValueChange = () => { +// setParamValues(selectedAction.parameters.map((param) => { +// return { +// name: param.name, +// value: param.value, +// } +// })) +// } + // useEffect(() => { // if (selectedAction.parameters === null || selectedAction.parameters === undefined) { // return @@ -801,12 +816,10 @@ const ParsedAction = (props) => { } //console.log("CHANGING ACTION COUNT !") - setTimeout(() => { selectedActionParameters[count].autocompleted = false selectedAction.parameters[count].autocompleted = false selectedActionParameters[count].value = event.target.value; selectedAction.parameters[count].value = event.target.value; - },100) var forceUpdate = false if (isCloud && (selectedAction.app_name === "Shuffle Tools" || selectedAction.app_name === "email") && (selectedAction.name === "send_email_shuffle" || selectedAction.name === "send_sms_shuffle") && data.name === "apikey") { @@ -3608,7 +3621,7 @@ const ParsedAction = (props) => { //selectedAction.parameters[count].value = selectedActionParameters[count].value; //setSelectedAction(selectedAction); //setUpdate(Math.random()); - + setShowDropdown(false); setMenuPosition(null); }; From 1a4b673bc8208baa6ee7e3bf2d6496b0bb8c2726 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Mon, 17 Jun 2024 17:00:23 +0530 Subject: [PATCH 21/22] Fixed the webhook associated app dropdown issue --- frontend/src/components/ParsedAction.jsx | 1 - frontend/src/views/AngularWorkflow.jsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 5761da74..9d8a4988 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -2204,7 +2204,6 @@ const ParsedAction = (props) => { } }); } - event.target.blur(); }} renderOption={(props, option, state) => { var newActionname = option.name; diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 65e7abff..f7d6227d 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -13829,6 +13829,7 @@ const releaseToConnectLabel = "Release to Connect" setUpdate(Math.random()); } + document.activeElement.blur(); }} >
    From 34e5913bfa83d80c3f23a434c97935e0eb9f6f81 Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Tue, 18 Jun 2024 21:00:07 +0530 Subject: [PATCH 22/22] Fixed the actionlist exec arg issue --- frontend/src/components/ParsedAction.jsx | 262 ++++++++++++----------- 1 file changed, 135 insertions(+), 127 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 9d8a4988..318ee546 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -442,136 +442,144 @@ const ParsedAction = (props) => { setSelectedVariableParameter(workflow.workflow_variables[0].name); } - // Initialize action list if it is empty - if (actionlist.length === 0) { - if (workflowExecutions.length > 0) { - for (let [key, keyval] of Object.entries(workflowExecutions)) { - const execArg = workflowExecutions[key].execution_argument; - if (execArg && execArg.length > 0) { - const valid = validateJson(execArg); - if (valid.valid) { - actionlist.push({ - type: "Execution Argument", - name: "Execution Argument", - value: "$exec", - highlight: "exec", - autocomplete: "exec", - example: valid.result, - }); - break; - } - } - } - } - - if (actionlist.length === 0) { - actionlist.push({ - type: "Execution Argument", - name: "Execution Argument", - value: "$exec", - highlight: "exec", - autocomplete: "exec", - example: "", - }); - } - - let cacheKey = { - type: "Shuffle DB", - name: "Shuffle DB", - value: "$shuffle_cache", - highlight: "shuffle_cache", - autocomplete: "shuffle_cache", - example: "", - }; - - if (listCache?.keys?.length > 0) { - cacheKey.example = {}; - for (let item of listCache.keys) { - if (item.key) { - let itemValue = item.value ?? ""; - if (itemValue.length > 10000) { - itemValue = ""; - } - cacheKey.example[item.key.split(" ").join("_")] = { value: itemValue }; - } - } - } - - actionlist.push(cacheKey); - - if (workflow.workflow_variables?.length > 0) { - for (let [key, keyval] of Object.entries(workflow.workflow_variables)) { - const item = workflow.workflow_variables[key]; - actionlist.push({ - type: "workflow_variable", - name: item.name, - value: item.value, - id: item.id, - autocomplete: item.name.split(" ").join("_"), - example: item.value, - }); - } - } - - if (workflow.execution_variables?.length > 0) { - for (let [key, keyval] of Object.entries(workflow.execution_variables)) { - const item = workflow.execution_variables[key]; - let exampleOutput = ""; - for (let exec of workflowExecutions) { - const foundExec = exec.execution_variables?.find(exvar => exvar.name === item.name); - if (foundExec?.value) { - exampleOutput = foundExec.value; - break; - } - } - actionlist.push({ - type: "execution_variable", - name: item.name, - value: item.value, - id: item.id, - autocomplete: item.name.split(" ").join("_"), - example: exampleOutput, - }); - } - } - - if (getParents) { - const parents = getParents(selectedAction); - if (parents.length > 1) { - const labels = []; - for (let parentNode of parents) { - if (parentNode.label !== "Execution Argument" && !labels.includes(parentNode.label)) { - labels.push(parentNode.label); - let exampleData = parentNode.example ?? ""; - if (!exampleData && workflowExecutions.length > 0) { - for (let exec of workflowExecutions) { - const foundResult = exec.results?.find(result => result.action.id === parentNode.id); - if (foundResult) { - const valid = validateJson(foundResult.result); - if (valid.valid && valid.result.success !== false) { - exampleData = valid.result; - break; - } - } - } - } - actionlist.push({ - type: "action", - id: parentNode.id, - name: parentNode.label, - autocomplete: parentNode.label.split(" ").join("_"), - example: exampleData, - }); - } - } - } - } - - setActionlist(actionlist); - } + }, [selectedAction,selectedApp,setNewSelectedAction,workflow, workflowExecutions, getParents] ); + + useEffect(() => { + const newActionList = []; + + // Process workflowExecutions + if (workflowExecutions.length > 0) { + for (let execution of workflowExecutions) { + const execArg = execution.execution_argument; + if (execArg && execArg.length > 0) { + const valid = validateJson(execArg); + if (valid.valid) { + newActionList.push({ + type: "Execution Argument", + name: "Execution Argument", + value: "$exec", + highlight: "exec", + autocomplete: "exec", + example: valid.result, + }); + break; + } + } + } + } + + // Add default Execution Argument if none were added + if (newActionList.length === 0) { + newActionList.push({ + type: "Execution Argument", + name: "Execution Argument", + value: "$exec", + highlight: "exec", + autocomplete: "exec", + example: "", + }); + + let cacheKey = { + type: "Shuffle DB", + name: "Shuffle DB", + value: "$shuffle_cache", + highlight: "shuffle_cache", + autocomplete: "shuffle_cache", + example: "", + }; + + if (listCache?.keys?.length > 0) { + cacheKey.example = {}; + for (let item of listCache.keys) { + if (item.key) { + let itemValue = item.value ?? ""; + if (itemValue.length > 10000) { + itemValue = ""; + } + cacheKey.example[item.key.split(" ").join("_")] = { value: itemValue }; + } + } + } + + newActionList.push(cacheKey); + } + + // Process workflow variables + if (workflow.workflow_variables?.length > 0) { + for (let variable of workflow.workflow_variables) { + newActionList.push({ + type: "workflow_variable", + name: variable.name, + value: variable.value, + id: variable.id, + autocomplete: variable.name.split(" ").join("_"), + example: variable.value, + }); + } + } + + // Process execution variables + if (workflow.execution_variables?.length > 0) { + for (let variable of workflow.execution_variables) { + let exampleOutput = ""; + for (let exec of workflowExecutions) { + const foundExec = exec.execution_variables?.find(exvar => exvar.name === variable.name); + if (foundExec?.value) { + exampleOutput = foundExec.value; + break; + } + } + newActionList.push({ + type: "execution_variable", + name: variable.name, + value: variable.value, + id: variable.id, + autocomplete: variable.name.split(" ").join("_"), + example: exampleOutput, + }); + } + } + + // Process parent actions if getParents is provided + if (getParents) { + const parents = getParents(selectedAction); + if (parents.length > 1) { + const labels = []; + for (let parentNode of parents) { + if (parentNode.label !== "Execution Argument" && !labels.includes(parentNode.label)) { + labels.push(parentNode.label); + let exampleData = parentNode.example ?? ""; + if (!exampleData && workflowExecutions.length > 0) { + for (let exec of workflowExecutions) { + const foundResult = exec.results?.find(result => result.action.id === parentNode.id); + if (foundResult) { + const valid = validateJson(foundResult.result); + if (valid.valid && valid.result.success !== false) { + exampleData = valid.result; + break; + } + } + } + } + newActionList.push({ + type: "action", + id: parentNode.id, + name: parentNode.label, + autocomplete: parentNode.label.split(" ").join("_"), + example: exampleData, + }); + } + } + } + } + + // Update the actionlist state + setActionlist(newActionList); + }, [workflow.execution_variables, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents]); + useEffect(() => { selectedNameChange(appActionName) actionDelayChange(delay)