Added PoC autocomplete feature based on app return example

This commit is contained in:
frikky
2020-07-09 11:42:36 +02:00
parent 82f08e3c6b
commit 65d4035cfd
4 changed files with 182 additions and 8 deletions
+11
View File
@@ -142,6 +142,7 @@ type WorkflowAppAction struct {
} `json:"execution_variable" datastore:"execution_variables"`
Returns struct {
Description string `json:"description" datastore:"returns" yaml:"description,omitempty"`
Example string `json:"example" datastore:"example" yaml:"example"`
ID string `json:"id" datastore:"id" yaml:"id,omitempty"`
Schema SchemaDefinition `json:"schema" datastore:"schema" yaml:"schema"`
} `json:"returns" datastore:"returns"`
@@ -4205,6 +4206,16 @@ func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra strin
}
}
/*
if workflowapp.Name == "thehive" {
for _, action := range workflowapp.Actions {
if len(action.Returns.Example) > 0 {
log.Printf("ACTION: %#v", action)
}
}
}
*/
if skip {
continue
}
+63 -2
View File
@@ -67,6 +67,7 @@ import cxtmenu from 'cytoscape-cxtmenu';
import { w3cwebsocket as W3CWebSocket } from "websocket";
import { useAlert } from "react-alert";
import { GetParsedPaths } from "./Apps";
const surfaceColor = "#27292D"
const inputColor = "#383B40"
@@ -2256,6 +2257,7 @@ const AngularWorkflow = (props) => {
const [showDropdown, setShowDropdown] = React.useState(false)
const [showDropdownNumber, setShowDropdownNumber] = React.useState(0)
const [actionlist, setActionlist] = React.useState([])
const [jsonList, setJsonList] = React.useState([])
useEffect(() => {
if (selectedActionParameters !== null && selectedActionParameters.length === 0) {
@@ -2317,6 +2319,20 @@ const AngularWorkflow = (props) => {
}
}
if (event.target.value[event.target.value.length-1] === ".") {
console.log("GET THE LAST ARGUMENT FOR !")
//const [jsonList, getJsonList] = React.useState([])
const inputdata = {"data": "1.2.3.4", "dataType": "4.5.6.6"}
const returnJson = GetParsedPaths(inputdata, "")
console.log(jsonList)
setJsonList(returnJson)
if (!showDropdown) {
setShowDropdown(true)
setShowDropdownNumber(count)
}
}
selectedActionParameters[count].value = event.target.value
selectedAction.parameters[count].value = event.target.value
setSelectedAction(selectedAction)
@@ -2605,7 +2621,49 @@ const AngularWorkflow = (props) => {
</Tooltip>
</div>
{datafield}
{showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" ?
{showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length > 0 ?
<FormControl fullWidth>
<InputLabel id="action-autocompleter" style={{marginLeft: 10, color: "white"}}><ArrowUpwardIcon />Autocomplete</InputLabel>
<Select
labelId="action-autocompleter"
SelectDisplayProps={{
style: {
marginLeft: 10,
}
}}
fullWidth
onChange={(e) => {
//parsedValues.push({"name": basekeyname, "autocomplete": `${basekey}.${key}`})
console.log("CHANGE!")
if (selectedActionParameters[count].value[selectedActionParameters[count].value.length-1] === ".") {
e.target.value.autocomplete = e.target.value.autocomplete.slice(1, e.target.value.autocomplete.length)
}
selectedActionParameters[count].value += e.target.value.autocomplete
selectedAction.parameters[count].value = selectedActionParameters[count].value
console.log("TARGET: ", selectedActionParameters)
setSelectedAction(selectedAction)
setUpdate("action"+e.target.value.name)
setShowDropdown(false)
}}
style={{border: `2px solid #f85a3e`, color: "white", height: "50px"}}
>
{jsonList.map(data => {
return (
<MenuItem key={data.name} style={{backgroundColor: inputColor, color: "white"}} value={data} onMouseOver={() => {}}>
<Tooltip color="primary" title={`Value: ${data.value}`} placement="left">
<div style={{display: "flex"}}>
{data.name}
</div>
</Tooltip>
</MenuItem>
)
})}
</Select>
</FormControl>
: null}
{showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length === 0 ?
<FormControl fullWidth>
<InputLabel id="action-autocompleter" style={{marginLeft: 10, color: "white"}}><ArrowUpwardIcon />Autocomplete</InputLabel>
<Select
@@ -2920,6 +2978,9 @@ const AngularWorkflow = (props) => {
<AppActionArguments key={selectedAction.id} selectedAction={selectedAction} />
</div>
<div style={{}}>
</div>
</div>
</div>
: null
@@ -3288,7 +3349,7 @@ const AngularWorkflow = (props) => {
</div>
</DialogContent>
<DialogActions>
<Button
<Button
style={{borderRadius: "0px"}}
onClick={() => {
setSelectedEdge({})
+102
View File
@@ -19,6 +19,7 @@ import Input from '@material-ui/core/Input';
import YAML from 'yaml'
import {Link} from 'react-router-dom';
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
import ReactJson from 'react-json-view'
import CachedIcon from '@material-ui/icons/Cached';
import CloudDownloadIcon from '@material-ui/icons/CloudDownload';
@@ -39,6 +40,51 @@ import CircularProgress from '@material-ui/core/CircularProgress';
const surfaceColor = "#27292D"
const inputColor = "#383B40"
// Parses JSON data into keys that can be used everywhere :)
export const GetParsedPaths = (inputdata, basekey) => {
const splitkey = " => "
var parsedValues = []
for (const [key, value] of Object.entries(inputdata)) {
// Check if loop or JSON
const extra = basekey.length > 0 ? splitkey : ""
const basekeyname = `${basekey.slice(1,basekey.length).split(".").join(splitkey)}${extra}${key}`
if (typeof(value) === 'object') {
if (Array.isArray(value)) {
// Check if each item is object
parsedValues.push({"name": basekeyname, "autocomplete": `${basekey}.${key}`})
parsedValues.push({"name": `${basekeyname}${splitkey}list`, "autocomplete": `${basekey}.${key}.#`})
// Only check the first. This would be probably be dumb otherwise.
for (var subkey in value) {
if (typeof(value) === 'object') {
const returnValues = GetParsedPaths(value[subkey], `${basekey}.${key}.#`)
for (var subkey in returnValues) {
parsedValues.push(returnValues[subkey])
}
}
// Don't need else as # (all items) is already defined before the loop
break
}
//console.log(key+" is array")
} else {
parsedValues.push({"name": basekeyname, "autocomplete": `${basekey}.${key}`})
const returnValues = GetParsedPaths(value, `${basekey}.${key}`)
for (var subkey in returnValues) {
parsedValues.push(returnValues[subkey])
}
}
} else {
parsedValues.push({"name": basekeyname, "autocomplete": `${basekey}.${key}`})
}
}
return parsedValues
}
const Apps = (props) => {
const { globalUrl, isLoggedIn, isLoaded } = props;
@@ -367,6 +413,61 @@ const Apps = (props) => {
:
<img alt={selectedApp.title} src={selectedApp.large_image} style={{width: 100, height: 100, maxWidth: "100%"}} />
const GetAppExample = () => {
if (selectedAction.returns === undefined) {
return null
}
var showResult = selectedAction.returns.example
if (showResult === undefined || showResult === null || showResult.length === 0) {
return null
}
var jsonvalid = true
try {
const tmp = String(JSON.parse(showResult))
if (!tmp.includes("{") && !tmp.includes("[")) {
jsonvalid = false
}
} catch (e) {
jsonvalid = false
}
// FIXME: In here -> parse the values into a list or something
if (jsonvalid) {
const paths = GetParsedPaths(JSON.parse(showResult), "")
console.log("PATHS: ", paths)
return (
<div>
{paths.map(data => {
const circleSize = 10
return (
<MenuItem style={{backgroundColor: inputColor, color: "white"}} value={data} onClick={() => console.log(data.autocomplete)}>
{data.name}
</MenuItem>
)
})}
<ReactJson
src={JSON.parse(showResult)}
theme="solarized"
collapsed={false}
displayDataTypes={true}
name={"Example return value"}
/>
</div>
)
}
return (
<div>
<b>Example return</b><div/>
{selectedAction.returns.example}
</div>
)
}
//fetch(globalUrl+"/api/v1/get_openapi/"+urlParams.get("id"), {
var baseInfo = newAppname.length > 0 ?
<div>
@@ -454,6 +555,7 @@ const Apps = (props) => {
{selectedAction.description}
</div>
: null}
<GetAppExample />
</div>
:
null
+6 -6
View File
@@ -185,15 +185,15 @@ const Workflows = (props) => {
return response.json()
})
.then((responseJson) => {
if (responseJson.success === true) {
setWorkflowExecutions(responseJson)
if (responseJson.success === false) {
alert.error("Failed getting executions")
} else {
if (responseJson.length > 0) {
setSelectedExecution(responseJson[0])
setWorkflowExecutions(responseJson)
} else {
alert.info("Couldn't find executions for the workflow")
}
} else if (!responseJson.success && responseJson.reason !== undefined) {
alert.error("Failed loading executions: "+responseJson.reason)
} else {
alert.error("Failed loading executions for workflow")
}
})
.catch(error => {