From 90f33d95b586bd48047a7eeaefe5518b82cf7246 Mon Sep 17 00:00:00 2001 From: frikky Date: Sat, 26 Sep 2020 21:04:46 +0200 Subject: [PATCH] #164: Made autocompleter better --- frontend/package-lock.json | 5 + frontend/package.json | 1 + frontend/src/views/AngularWorkflow.jsx | 332 +++++++++++++++++-------- frontend/src/views/Apps.jsx | 4 + 4 files changed, 234 insertions(+), 108 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1daf4734..bd6df28b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12177,6 +12177,11 @@ "prop-types": "^15.6.1" } }, + "material-ui-nested-menu-item": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/material-ui-nested-menu-item/-/material-ui-nested-menu-item-1.0.2.tgz", + "integrity": "sha512-LZb8xI0FrAI/A3P2vT3CB9bmSoOFWOK0dikTc1t9VvEpp1a8hZkbVUz7VhETnoLUYu3NXCkgulmXcl3zitqI9A==" + }, "material-ui-pickers": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/material-ui-pickers/-/material-ui-pickers-2.2.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 117587fc..a4c40596 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,6 +28,7 @@ "material-icons": "^0.3.1", "material-icons-react": "^1.0.4", "material-ui-chip-input": "^2.0.0-beta.2", + "material-ui-nested-menu-item": "^1.0.2", "md5-file": "^4.0.0", "mdbreact": "^4.21.1", "moment": "~2.20.1", diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index ae8216e2..81ccc578 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -36,6 +36,7 @@ import CircularProgress from '@material-ui/core/CircularProgress'; import Switch from '@material-ui/core/Switch'; import ReactJson from 'react-json-view' import { useBeforeunload } from 'react-beforeunload'; +import NestedMenuItem from "material-ui-nested-menu-item"; import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward'; import CachedIcon from '@material-ui/icons/Cached'; @@ -1395,7 +1396,6 @@ const AngularWorkflow = (props) => { example = action.example } - console.log("EXAMPLE: ", example) node.data.example = example return node; @@ -2438,6 +2438,7 @@ const AngularWorkflow = (props) => { const [actionlist, setActionlist] = React.useState([]) const [jsonList, setJsonList] = React.useState([]) const [showAutocomplete, setShowAutocomplete] = React.useState(false) + const [menuPosition, setMenuPosition] = useState(null) useEffect(() => { if (selectedActionParameters !== null && selectedActionParameters.length === 0) { @@ -2469,6 +2470,7 @@ const AngularWorkflow = (props) => { } } + // Loops parent nodes' old results to fix autocomplete var parents = getParents(selectedAction) if (parents.length > 1) { for (var key in parents) { @@ -2477,8 +2479,39 @@ const AngularWorkflow = (props) => { continue } + var exampledata = item.example === undefined ? "" : item.example + // Find previous execution and their variables + if (exampledata === "" && workflowExecutions.length > 0) { + // Look for the ID + const found = false + for (var key in workflowExecutions) { + const foundResult = workflowExecutions[key].results.find(result => result.action.id === item.id) + if (foundResult === undefined) { + continue + } + + var jsonvalid = true + try { + const tmp = String(JSON.parse(foundResult.result)) + if (!tmp.includes("{") && !tmp.includes("[")) { + jsonvalid = false + } + } catch (e) { + jsonvalid = false + } + + // Finds the FIRST json only + if (jsonvalid) { + exampledata = JSON.parse(foundResult.result) + break + } else { + console.log("Invalid JSON: ", foundResult.result) + } + } + } + // 1. Take - const actionvalue = {"type": "action", "id": item.id, "name": item.label, "autocomplete": `${item.label.split(" ").join("_")}`, "example": item.example === undefined ? "" : item.example} + const actionvalue = {"type": "action", "id": item.id, "name": item.label, "autocomplete": `${item.label.split(" ").join("_")}`, "example": exampledata} actionlist.push(actionvalue) } } @@ -2502,12 +2535,18 @@ const AngularWorkflow = (props) => { // bad detection mechanism probably if (event.target.value[event.target.value.length-1] === "." && actionlist.length > 0) { - - console.log("GET THE LAST ARGUMENT FOR !") - //const [jsonList, getJsonList] = React.useState([]) + console.log("GET THE LAST ARGUMENT FOR NODE!") + // THIS IS AN EXAMPLE OF SHOWING IT + /* const inputdata = {"data": "1.2.3.4", "dataType": "4.5.6.6"} - const returnJson = GetParsedPaths(inputdata, "") + setJsonList(GetParsedPaths(inputdata, "")) + if (!showDropdown) { + setShowAutocomplete(false) + setShowDropdown(true) + setShowDropdownNumber(count) + } console.log(jsonList) + */ // Search for the item backwards // 1. Reverse search backwards from . -> $ @@ -2693,7 +2732,11 @@ const AngularWorkflow = (props) => { endAdornment: ( - { + { + setMenuPosition({ + top: event.pageY, + left: event.pageX, + }) setShowDropdownNumber(count) setShowDropdown(true) setShowAutocomplete(true) @@ -2862,7 +2905,180 @@ const AngularWorkflow = (props) => { )) : null} } + } + // Shows nested list of nodes > their JSON lists + const ActionlistWrapper = (props) => { + + const handleMenuClose = () => { + setShowAutocomplete(false) + + if (!selectedActionParameters[count].value[selectedActionParameters[count].value.length-1] === "$") { + setShowDropdown(false) + } + + setUpdate(Math.random()) + setMenuPosition(null) + } + + const handleItemClick = (values) => { + if (values === undefined || values === null || values.length === 0) { + return + } + + var toComplete = selectedActionParameters[count].value.trim().endsWith("$") ? values[0].autocomplete : "$"+values[0].autocomplete + for (var key in values) { + if (key == 0 || values[key].autocomplete.length === 0) { + continue + } + + toComplete += values[key].autocomplete + } + + selectedActionParameters[count].value += toComplete + selectedAction.parameters[count].value = selectedActionParameters[count].value + console.log("TARGET: ", selectedActionParameters) + setSelectedAction(selectedAction) + setUpdate(Math.random()) + + setShowDropdown(false) + setMenuPosition(null) + } + + const iconStyle = { + marginRight: 15, + } + + return ( +
+ { + handleMenuClose() + }} + open={!!menuPosition} + style={{ + border: `2px solid #f85a3e`, + color: "white", + marginTop: 2, + }} + > + {actionlist.map(innerdata => { + const icon = innerdata.type === "action" ? : innerdata.type === "workflow_variable" || innerdata.type === "execution_variable" ? : + + const handleExecArgumentHover = (inside) => { + var exec_text_field = document.getElementById("execution_argument_input_field") + if (exec_text_field !== null) { + if (inside) { + exec_text_field.style.border = "2px solid #f85a3e" + } else { + exec_text_field.style.border = "" + } + } + + // Also doing arguments + if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length > 0) { + for (var key in workflow.triggers) { + const item = workflow.triggers[key] + + var node = cy.getElementById(item.id) + if (node.length > 0) { + if (inside) { + node.addClass('shuffle-hover-highlight') + } else { + node.removeClass('shuffle-hover-highlight') + } + } + + } + } + } + + const handleActionHover = (inside, actionId) => { + var node = cy.getElementById(actionId) + if (node.length > 0) { + if (inside) { + node.addClass('shuffle-hover-highlight') + } else { + node.removeClass('shuffle-hover-highlight') + } + } + } + + const handleMouseover = () => { + if (innerdata.type === "Execution Argument") { + handleExecArgumentHover(true) + } else if (innerdata.type === "action") { + handleActionHover(true, innerdata.id) + } + } + + const handleMouseOut = () => { + if (innerdata.type === "Execution Argument") { + handleExecArgumentHover(false) + } else if (innerdata.type === "action") { + handleActionHover(false, innerdata.id) + } + } + + var parsedPaths = [] + if (typeof(innerdata.example) === "object") { + parsedPaths = GetParsedPaths(innerdata.example, "") + } + + return ( + parsedPaths.length > 0 ? + + {icon} {innerdata.name} +
+ } + parentMenuOpen={!!menuPosition} + style={{backgroundColor: inputColor, color: "white"}} + onClick={() => { + handleItemClick([innerdata]) + }} + > + {parsedPaths.map((pathdata, index) => { + // FIXME: Should be recursive in here + const icon = pathdata.type === "value" ? : pathdata.type === "list" ? : + return ( + {}} + onClick={() => { + handleItemClick([innerdata, pathdata]) + }} + > + +
+ {icon} {pathdata.name} +
+
+
+ ) + + })} + + : + handleMouseover()} onMouseOut={() => {handleMouseOut()}} + onClick={() => { + handleItemClick([innerdata]) + }} + > + +
+ {icon} {innerdata.name} +
+
+
+ + ) + })} + + + ) } var itemColor = "#f85a3e" @@ -2942,7 +3158,6 @@ const AngularWorkflow = (props) => { selectedActionParameters[count].value += e.target.value.autocomplete selectedAction.parameters[count].value = selectedActionParameters[count].value - console.log("TARGET: ", selectedActionParameters) setSelectedAction(selectedAction) setUpdate(Math.random()) @@ -2969,106 +3184,7 @@ const AngularWorkflow = (props) => { : null} {showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length === 0 ? - - Autocomplete - - + : null} diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index f6ae675d..6fc4f596 100644 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -45,6 +45,10 @@ const inputColor = "#383B40" export const GetParsedPaths = (inputdata, basekey) => { const splitkey = " => " var parsedValues = [] + if (typeof(inputdata) !== "object") { + return parsedValues + } + for (const [key, value] of Object.entries(inputdata)) { // Check if loop or JSON