#164: Made autocompleter better
This commit is contained in:
Generated
+5
@@ -12177,6 +12177,11 @@
|
|||||||
"prop-types": "^15.6.1"
|
"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": {
|
"material-ui-pickers": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/material-ui-pickers/-/material-ui-pickers-2.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/material-ui-pickers/-/material-ui-pickers-2.2.4.tgz",
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
"material-icons": "^0.3.1",
|
"material-icons": "^0.3.1",
|
||||||
"material-icons-react": "^1.0.4",
|
"material-icons-react": "^1.0.4",
|
||||||
"material-ui-chip-input": "^2.0.0-beta.2",
|
"material-ui-chip-input": "^2.0.0-beta.2",
|
||||||
|
"material-ui-nested-menu-item": "^1.0.2",
|
||||||
"md5-file": "^4.0.0",
|
"md5-file": "^4.0.0",
|
||||||
"mdbreact": "^4.21.1",
|
"mdbreact": "^4.21.1",
|
||||||
"moment": "~2.20.1",
|
"moment": "~2.20.1",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import CircularProgress from '@material-ui/core/CircularProgress';
|
|||||||
import Switch from '@material-ui/core/Switch';
|
import Switch from '@material-ui/core/Switch';
|
||||||
import ReactJson from 'react-json-view'
|
import ReactJson from 'react-json-view'
|
||||||
import { useBeforeunload } from 'react-beforeunload';
|
import { useBeforeunload } from 'react-beforeunload';
|
||||||
|
import NestedMenuItem from "material-ui-nested-menu-item";
|
||||||
|
|
||||||
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
|
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
|
||||||
import CachedIcon from '@material-ui/icons/Cached';
|
import CachedIcon from '@material-ui/icons/Cached';
|
||||||
@@ -1395,7 +1396,6 @@ const AngularWorkflow = (props) => {
|
|||||||
example = action.example
|
example = action.example
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("EXAMPLE: ", example)
|
|
||||||
node.data.example = example
|
node.data.example = example
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@@ -2438,6 +2438,7 @@ const AngularWorkflow = (props) => {
|
|||||||
const [actionlist, setActionlist] = React.useState([])
|
const [actionlist, setActionlist] = React.useState([])
|
||||||
const [jsonList, setJsonList] = React.useState([])
|
const [jsonList, setJsonList] = React.useState([])
|
||||||
const [showAutocomplete, setShowAutocomplete] = React.useState(false)
|
const [showAutocomplete, setShowAutocomplete] = React.useState(false)
|
||||||
|
const [menuPosition, setMenuPosition] = useState(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedActionParameters !== null && selectedActionParameters.length === 0) {
|
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)
|
var parents = getParents(selectedAction)
|
||||||
if (parents.length > 1) {
|
if (parents.length > 1) {
|
||||||
for (var key in parents) {
|
for (var key in parents) {
|
||||||
@@ -2477,8 +2479,39 @@ const AngularWorkflow = (props) => {
|
|||||||
continue
|
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
|
// 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)
|
actionlist.push(actionvalue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2502,12 +2535,18 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
// bad detection mechanism probably
|
// bad detection mechanism probably
|
||||||
if (event.target.value[event.target.value.length-1] === "." && actionlist.length > 0) {
|
if (event.target.value[event.target.value.length-1] === "." && actionlist.length > 0) {
|
||||||
|
console.log("GET THE LAST ARGUMENT FOR NODE!")
|
||||||
console.log("GET THE LAST ARGUMENT FOR !")
|
// THIS IS AN EXAMPLE OF SHOWING IT
|
||||||
//const [jsonList, getJsonList] = React.useState([])
|
/*
|
||||||
const inputdata = {"data": "1.2.3.4", "dataType": "4.5.6.6"}
|
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)
|
console.log(jsonList)
|
||||||
|
*/
|
||||||
|
|
||||||
// Search for the item backwards
|
// Search for the item backwards
|
||||||
// 1. Reverse search backwards from . -> $
|
// 1. Reverse search backwards from . -> $
|
||||||
@@ -2693,7 +2732,11 @@ const AngularWorkflow = (props) => {
|
|||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
<Tooltip title="Autocomplete text" placement="top">
|
<Tooltip title="Autocomplete text" placement="top">
|
||||||
<AddCircleOutlineIcon style={{cursor: "pointer"}} onClick={() => {
|
<AddCircleOutlineIcon style={{cursor: "pointer"}} onClick={(event) => {
|
||||||
|
setMenuPosition({
|
||||||
|
top: event.pageY,
|
||||||
|
left: event.pageX,
|
||||||
|
})
|
||||||
setShowDropdownNumber(count)
|
setShowDropdownNumber(count)
|
||||||
setShowDropdown(true)
|
setShowDropdown(true)
|
||||||
setShowAutocomplete(true)
|
setShowAutocomplete(true)
|
||||||
@@ -2862,7 +2905,180 @@ const AngularWorkflow = (props) => {
|
|||||||
)) : null}
|
)) : null}
|
||||||
</Select>
|
</Select>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
<div >
|
||||||
|
<Menu
|
||||||
|
anchorReference="anchorPosition"
|
||||||
|
anchorPosition={menuPosition}
|
||||||
|
onClose={() => {
|
||||||
|
handleMenuClose()
|
||||||
|
}}
|
||||||
|
open={!!menuPosition}
|
||||||
|
style={{
|
||||||
|
border: `2px solid #f85a3e`,
|
||||||
|
color: "white",
|
||||||
|
marginTop: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{actionlist.map(innerdata => {
|
||||||
|
const icon = innerdata.type === "action" ? <AppsIcon style={{marginRight: 10}} /> : innerdata.type === "workflow_variable" || innerdata.type === "execution_variable" ? <FavoriteBorderIcon style={{marginRight: 10}} /> : <ScheduleIcon style={{marginRight: 10}} />
|
||||||
|
|
||||||
|
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 ?
|
||||||
|
<NestedMenuItem
|
||||||
|
key={innerdata.name}
|
||||||
|
label={
|
||||||
|
<div style={{display: "flex"}}>
|
||||||
|
{icon} {innerdata.name}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
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" ? <VpnKeyIcon style={iconStyle} /> : pathdata.type === "list" ? <FormatListNumberedIcon style={iconStyle} /> : <ExpandMoreIcon style={iconStyle} />
|
||||||
|
return (
|
||||||
|
<MenuItem key={pathdata.name} style={{backgroundColor: inputColor, color: "white"}} value={pathdata} onMouseOver={() => {}}
|
||||||
|
onClick={() => {
|
||||||
|
handleItemClick([innerdata, pathdata])
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip color="primary" title={`Ex. value: ${pathdata.value}`} placement="left">
|
||||||
|
<div style={{display: "flex"}}>
|
||||||
|
{icon} {pathdata.name}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
})}
|
||||||
|
</NestedMenuItem>
|
||||||
|
:
|
||||||
|
<MenuItem key={innerdata.name} style={{backgroundColor: inputColor, color: "white"}} value={innerdata} onMouseOver={() => handleMouseover()} onMouseOut={() => {handleMouseOut()}}
|
||||||
|
onClick={() => {
|
||||||
|
handleItemClick([innerdata])
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip color="primary" title={`Value: ${innerdata.value}`} placement="left">
|
||||||
|
<div style={{display: "flex"}}>
|
||||||
|
{icon} {innerdata.name}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemColor = "#f85a3e"
|
var itemColor = "#f85a3e"
|
||||||
@@ -2942,7 +3158,6 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
selectedActionParameters[count].value += e.target.value.autocomplete
|
selectedActionParameters[count].value += e.target.value.autocomplete
|
||||||
selectedAction.parameters[count].value = selectedActionParameters[count].value
|
selectedAction.parameters[count].value = selectedActionParameters[count].value
|
||||||
console.log("TARGET: ", selectedActionParameters)
|
|
||||||
setSelectedAction(selectedAction)
|
setSelectedAction(selectedAction)
|
||||||
setUpdate(Math.random())
|
setUpdate(Math.random())
|
||||||
|
|
||||||
@@ -2969,106 +3184,7 @@ const AngularWorkflow = (props) => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
: null}
|
: null}
|
||||||
{showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length === 0 ?
|
{showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length === 0 ?
|
||||||
<FormControl fullWidth>
|
<ActionlistWrapper actionlist={actionlist} />
|
||||||
<InputLabel id="action-autocompleter" style={{marginLeft: 10, color: "white"}}>Autocomplete</InputLabel>
|
|
||||||
<Select
|
|
||||||
labelId="action-autocompleter"
|
|
||||||
SelectDisplayProps={{
|
|
||||||
style: {
|
|
||||||
marginLeft: 10,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClose={() => {
|
|
||||||
setShowAutocomplete(false)
|
|
||||||
|
|
||||||
if (!selectedActionParameters[count].value[selectedActionParameters[count].value.length-1] === "$") {
|
|
||||||
setShowDropdown(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
setUpdate(Math.random())
|
|
||||||
}}
|
|
||||||
onClick={() => setShowAutocomplete(true)}
|
|
||||||
open={showAutocomplete}
|
|
||||||
fullWidth
|
|
||||||
style={{border: `2px solid #f85a3e`, color: "white", height: 50, marginTop: 2,}}
|
|
||||||
onChange={(e) => {
|
|
||||||
console.log("CHANGE!")
|
|
||||||
const toComplete = selectedActionParameters[count].value.trim().endsWith("$") ? e.target.value.autocomplete : "$"+e.target.value.autocomplete
|
|
||||||
selectedActionParameters[count].value += toComplete
|
|
||||||
selectedAction.parameters[count].value = selectedActionParameters[count].value
|
|
||||||
console.log("TARGET: ", selectedActionParameters)
|
|
||||||
setSelectedAction(selectedAction)
|
|
||||||
setUpdate(Math.random())
|
|
||||||
|
|
||||||
setShowDropdown(false)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{actionlist.map(data => {
|
|
||||||
const icon = data.type === "action" ? <AppsIcon style={{marginRight: 10}} /> : data.type === "workflow_variable" || data.type === "execution_variable" ? <FavoriteBorderIcon style={{marginRight: 10}} /> : <ScheduleIcon style={{marginRight: 10}} />
|
|
||||||
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuItem key={data.name} style={{backgroundColor: inputColor, color: "white"}} value={data} onMouseOver={() => {
|
|
||||||
if (data.type === "Execution Argument") {
|
|
||||||
handleExecArgumentHover(true)
|
|
||||||
} else if (data.type === "action") {
|
|
||||||
handleActionHover(true, data.id)
|
|
||||||
}
|
|
||||||
}} onMouseOut={() => {
|
|
||||||
if (data.type === "Execution Argument") {
|
|
||||||
handleExecArgumentHover(false)
|
|
||||||
} else if (data.type === "action") {
|
|
||||||
handleActionHover(false, data.id)
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Tooltip color="primary" title={`Value: ${data.value}`} placement="left">
|
|
||||||
<div style={{display: "flex"}}>
|
|
||||||
{icon} {data.name}
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</MenuItem>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
: null}
|
: null}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ const inputColor = "#383B40"
|
|||||||
export const GetParsedPaths = (inputdata, basekey) => {
|
export const GetParsedPaths = (inputdata, basekey) => {
|
||||||
const splitkey = " => "
|
const splitkey = " => "
|
||||||
var parsedValues = []
|
var parsedValues = []
|
||||||
|
if (typeof(inputdata) !== "object") {
|
||||||
|
return parsedValues
|
||||||
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(inputdata)) {
|
for (const [key, value] of Object.entries(inputdata)) {
|
||||||
|
|
||||||
// Check if loop or JSON
|
// Check if loop or JSON
|
||||||
|
|||||||
Reference in New Issue
Block a user