4235 lines
142 KiB
React
Executable File
4235 lines
142 KiB
React
Executable File
import React, { useState, useEffect, useLayoutEffect } from "react";
|
|
import { toast } from 'react-toastify';
|
|
import { makeStyles, createStyles } from "@mui/styles";
|
|
import theme from '../theme.jsx';
|
|
|
|
|
|
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
|
import { GetParsedPaths } from "../views/Apps.jsx";
|
|
import { sortByKey } from "../views/AngularWorkflow.jsx";
|
|
import { NestedMenuItem } from "mui-nested-menu";
|
|
import { parsedDatatypeImages } from "../components/AppFramework.jsx";
|
|
//import { useAlert
|
|
|
|
import {
|
|
Chip,
|
|
ButtonGroup,
|
|
Popper,
|
|
TextField,
|
|
TextareaAutosize,
|
|
Drawer,
|
|
Button,
|
|
Paper,
|
|
Tabs,
|
|
InputAdornment,
|
|
Tab,
|
|
ButtonBase,
|
|
Tooltip,
|
|
Select,
|
|
MenuItem,
|
|
Divider,
|
|
Dialog,
|
|
Modal,
|
|
DialogActions,
|
|
DialogTitle,
|
|
InputLabel,
|
|
DialogContent,
|
|
FormControl,
|
|
IconButton,
|
|
Menu,
|
|
Input,
|
|
FormGroup,
|
|
FormControlLabel,
|
|
Typography,
|
|
Checkbox,
|
|
Breadcrumbs,
|
|
CircularProgress,
|
|
Switch,
|
|
Collapse,
|
|
Autocomplete
|
|
} from "@mui/material";
|
|
|
|
import {
|
|
HelpOutline as HelpOutlineIcon,
|
|
Description as DescriptionIcon,
|
|
GetApp as GetAppIcon,
|
|
Search as SearchIcon,
|
|
ArrowUpward as ArrowUpwardIcon,
|
|
Visibility as VisibilityIcon,
|
|
Done as DoneIcon,
|
|
Close as CloseIcon,
|
|
Error as ErrorIcon,
|
|
FindReplace as FindreplaceIcon,
|
|
ArrowLeft as ArrowLeftIcon,
|
|
Cached as CachedIcon,
|
|
DirectionsRun as DirectionsRunIcon,
|
|
Add as AddIcon,
|
|
Polymer as PolymerIcon,
|
|
FormatListNumbered as FormatListNumberedIcon,
|
|
Create as CreateIcon,
|
|
PlayArrow as PlayArrowIcon,
|
|
AspectRatio as AspectRatioIcon,
|
|
MoreVert as MoreVertIcon,
|
|
Apps as AppsIcon,
|
|
Schedule as ScheduleIcon,
|
|
FavoriteBorder as FavoriteBorderIcon,
|
|
Pause as PauseIcon,
|
|
Delete as DeleteIcon,
|
|
AddCircleOutline as AddCircleOutlineIcon,
|
|
Save as SaveIcon,
|
|
KeyboardArrowLeft as KeyboardArrowLeftIcon,
|
|
KeyboardArrowRight as KeyboardArrowRightIcon,
|
|
ArrowBack as ArrowBackIcon,
|
|
Settings as SettingsIcon,
|
|
LockOpen as LockOpenIcon,
|
|
ExpandMore as ExpandMoreIcon,
|
|
VpnKey as VpnKeyIcon,
|
|
AutoFixHigh as AutoFixHighIcon,
|
|
Circle as CircleIcon,
|
|
SquareFoot as SquareFootIcon,
|
|
Storage as StorageIcon,
|
|
} from '@mui/icons-material';
|
|
|
|
const useStyles = makeStyles({
|
|
notchedOutline: {
|
|
borderColor: "#f85a3e !important",
|
|
},
|
|
root: {
|
|
"& .MuiAutocomplete-listbox": {
|
|
border: "2px solid grey",
|
|
color: "white",
|
|
fontSize: 18,
|
|
"& li:nth-child(even)": {
|
|
backgroundColor: "#CCC",
|
|
},
|
|
"& li:nth-child(odd)": {
|
|
backgroundColor: "#FFF",
|
|
},
|
|
},
|
|
},
|
|
inputRoot: {
|
|
color: "white",
|
|
"&:hover .MuiOutlinedInput-notchedOutline": {
|
|
borderColor: "#f86a3e",
|
|
},
|
|
},
|
|
});
|
|
|
|
const openApiFieldDesc = "Generated by OpenAPI body example";
|
|
const ParsedAction = (props) => {
|
|
const {
|
|
workflow,
|
|
files,
|
|
setWorkflow,
|
|
setAction,
|
|
setSelectedAction,
|
|
setUpdate,
|
|
appActionArguments,
|
|
selectedApp,
|
|
workflowExecutions,
|
|
setSelectedResult,
|
|
selectedAction,
|
|
setSelectedApp,
|
|
setSelectedTrigger,
|
|
setSelectedEdge,
|
|
setCurrentView,
|
|
cy,
|
|
setAuthenticationModalOpen,
|
|
setVariablesModalOpen,
|
|
setCodeModalOpen,
|
|
selectedNameChange,
|
|
rightsidebarStyle,
|
|
showEnvironment,
|
|
selectedActionEnvironment,
|
|
environments,
|
|
setNewSelectedAction,
|
|
appApiViewStyle,
|
|
globalUrl,
|
|
setSelectedActionEnvironment,
|
|
requiresAuthentication,
|
|
hideExtraTypes,
|
|
scrollConfig,
|
|
setScrollConfig,
|
|
authenticationType,
|
|
appAuthentication,
|
|
getAppAuthentication,
|
|
actionDelayChange,
|
|
getParents,
|
|
isCloud,
|
|
lastSaved,
|
|
setLastSaved,
|
|
setShowVideo,
|
|
toolsAppId,
|
|
aiSubmit,
|
|
|
|
expansionModalOpen,
|
|
setExpansionModalOpen,
|
|
|
|
listCache,
|
|
|
|
authGroups,
|
|
apps,
|
|
setEditorData,
|
|
setcodedata,
|
|
setAiQueryModalOpen,
|
|
} = props;
|
|
|
|
const classes = useStyles();
|
|
const [hideBody, setHideBody] = React.useState(true);
|
|
const [activateHidingBodyButton, setActivateHidingBodyButton] = React.useState(false);
|
|
|
|
const [fieldCount, setFieldCount] = React.useState(0);
|
|
const [hiddenDescription, setHiddenDescription] = React.useState(true);
|
|
|
|
const [autoCompleting, setAutocompleting] = React.useState(false);
|
|
|
|
const isIntegration = selectedAction.app_id === "integration"
|
|
|
|
useEffect(() => {
|
|
if (setLastSaved !== undefined) {
|
|
setLastSaved(false)
|
|
}
|
|
}, [expansionModalOpen])
|
|
|
|
useEffect(() => {
|
|
if (selectedAction.parameters === null || selectedAction.parameters === undefined) {
|
|
return
|
|
}
|
|
|
|
const paramcheck = selectedAction.parameters.find(param => param.name === "body")
|
|
if (paramcheck === undefined || paramcheck === null) {
|
|
return
|
|
}
|
|
|
|
// This was just opposite..
|
|
if (paramcheck.id === "TOGGLED"){
|
|
setHideBody(true)
|
|
} else {
|
|
setHideBody(false)
|
|
|
|
if (paramcheck.id === "UNTOGGLED") {
|
|
setActivateHidingBodyButton(false)
|
|
}
|
|
}
|
|
|
|
}, [])
|
|
|
|
const keywords = [
|
|
"len(",
|
|
"lower(",
|
|
"upper(",
|
|
"trim(",
|
|
"split(",
|
|
"length(",
|
|
"number(",
|
|
"parse(",
|
|
"join(",
|
|
];
|
|
|
|
const getApp = (appId, setApp) => {
|
|
fetch(globalUrl + "/api/v1/apps/" + appId + "/config?openapi=false", {
|
|
headers: {
|
|
Accept: "application/json",
|
|
},
|
|
credentials: "include",
|
|
})
|
|
.then((response) => {
|
|
if (response.status === 200) {
|
|
//toast("Successfully GOT app "+appId)
|
|
} else {
|
|
toast("Failed getting app");
|
|
}
|
|
|
|
return response.json();
|
|
})
|
|
.then((responseJson) => {
|
|
console.log("RESPONSE: ", responseJson);
|
|
|
|
const parsedapp =
|
|
responseJson.app !== undefined && responseJson.app !== null
|
|
? JSON.parse(atob(responseJson.app))
|
|
: {};
|
|
console.log("PARSED: ", parsedapp);
|
|
//data = parsedapp.body === undefined ? parsedapp : parsedapp.body
|
|
|
|
if (
|
|
setApp &&
|
|
parsedapp.actions !== undefined &&
|
|
parsedapp.actions !== null
|
|
) {
|
|
console.log("Inside first if");
|
|
if (
|
|
selectedApp.versions !== undefined &&
|
|
selectedApp.versions !== null
|
|
) {
|
|
parsedapp.versions = selectedApp.versions;
|
|
}
|
|
|
|
if (
|
|
selectedApp.loop_versions !== undefined &&
|
|
selectedApp.loop_versions !== null
|
|
) {
|
|
parsedapp.loop_versions = selectedApp.loop_versions;
|
|
}
|
|
|
|
// Find authentication, and if it works?
|
|
// If authentication has less OR more fields, it has to change
|
|
//console.log(selected
|
|
|
|
console.log("Inside first if2");
|
|
var foundAction = parsedapp.actions.find(
|
|
(action) =>
|
|
action.name.toLowerCase() === selectedAction.name.toLowerCase()
|
|
);
|
|
console.log("FOUNDACTION: ", foundAction);
|
|
if (foundAction !== null && foundAction !== undefined) {
|
|
var foundparams = [];
|
|
for (let [paramkey,paramkeyval] in Object.entries(foundAction.parameters)) {
|
|
const param = foundAction.parameters[paramkey];
|
|
|
|
const foundParam = selectedAction.parameters.find(
|
|
(item) => item.name.toLowerCase() === param.name.toLowerCase()
|
|
);
|
|
if (foundParam === undefined) {
|
|
console.log("COULDNT find Param: ", param);
|
|
} else {
|
|
foundAction.parameters[paramkey] = foundParam;
|
|
}
|
|
//foundparams.push(param.name)
|
|
}
|
|
} else {
|
|
toast("Couldn't find action " + selectedAction.name);
|
|
}
|
|
|
|
selectedAction.errors = [];
|
|
selectedAction.is_valid = true;
|
|
|
|
// Updating params for the new action
|
|
selectedAction.parameters = foundAction.parameters;
|
|
selectedAction.app_id = appId;
|
|
selectedAction.app_version = parsedapp.app_version;
|
|
|
|
setSelectedAction(selectedAction);
|
|
setSelectedApp(parsedapp);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
toast(error.toString());
|
|
});
|
|
};
|
|
|
|
|
|
|
|
const defineStartnode = () => {
|
|
if (cy === undefined) {
|
|
return;
|
|
}
|
|
|
|
var oldstartnode = cy.getElementById(workflow.start);
|
|
if (oldstartnode.length > 0) {
|
|
oldstartnode[0].data("isStartNode", false);
|
|
var oldnodecnt = workflow.actions.findIndex(
|
|
(a) => a.id === workflow.start
|
|
);
|
|
if (workflow.actions[oldnodecnt] !== undefined) {
|
|
workflow.actions[oldnodecnt].isStartNode = false;
|
|
}
|
|
}
|
|
|
|
var newstartnode = cy.getElementById(selectedAction.id);
|
|
if (newstartnode.length > 0) {
|
|
newstartnode[0].data("isStartNode", true);
|
|
var newnodecnt = workflow.actions.findIndex(
|
|
(a) => a.id === selectedAction.id
|
|
);
|
|
console.log("NEW NODE CNT: ", newnodecnt);
|
|
if (workflow.actions[newnodecnt] !== undefined) {
|
|
workflow.actions[newnodecnt].isStartNode = true;
|
|
console.log(workflow.actions[newnodecnt]);
|
|
}
|
|
}
|
|
|
|
// Find branches with triggers as source nodes
|
|
// Move these targets to be the new node
|
|
// Set arrows pointing to new startnode with errors
|
|
//for (var key in workflow.branches) {
|
|
// var item = workflow.branches[key]
|
|
// if (item.destination_id === oldstartnode[0].data()["id"]) {
|
|
// var curbranch = cy.getElementById(item.id)
|
|
// if (curbranch.length > 0) {
|
|
// //console.log(curbranch[0].data())
|
|
// //curbranch[0].data("target", selectedAction.id)
|
|
// //curbranch[0].data("hasErrors", true)
|
|
// //workflow.branches[key].destination_id = selectedAction.id
|
|
// //console.log(curbranch[0].data())
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
setUpdate("start_node" + selectedAction.id);
|
|
workflow.start = selectedAction.id;
|
|
setWorkflow(workflow);
|
|
//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
|
|
) {
|
|
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
|
|
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
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
}
|
|
} 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);
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
const calculateHelpertext = (input_data) => {
|
|
var helperText = ""
|
|
var looperText = ""
|
|
//const found = input_data.match(/[$]{1}([a-zA-Z0-9_-]+\.?){1}([a-zA-Z0-9#_-]+\.?){0,}/g)
|
|
var found = input_data.match(/[\\]{0,1}[$]{1}([a-zA-Z0-9_@-]+\.?){1}([a-zA-Z0-9#_@-]+\.?){0,}/g)
|
|
|
|
if (found !== null && found !== undefined) {
|
|
var new_occurences = []
|
|
for (let [key,keyval] in Object.entries(found)) {
|
|
if (found[key][0] !== "\\") {
|
|
new_occurences.push(found[key])
|
|
}
|
|
}
|
|
|
|
found = new_occurences.valueOf()
|
|
}
|
|
|
|
if (found !== null) {
|
|
try {
|
|
// When the found array is empty.
|
|
for (let i = 0; i < found.length; i++) {
|
|
const variableSplit = found[i].split(".#")
|
|
if ((variableSplit.length-1) > 1) {
|
|
//console.log("Larger than 1: ", variableSplit)
|
|
if (looperText.length === 0) {
|
|
looperText += "PS: Double looping (.#.#) may cause problems."
|
|
}
|
|
}
|
|
|
|
var foundSlice = false
|
|
for (let j = 0; j < actionlist.length; j++) {
|
|
//console.log("ACTION: ", found[i], actionlist[j])
|
|
//console.log("ACTION :", found[i].split(".")[0].slice(1,).toLowerCase(), actionlist[j].autocomplete.toLowerCase())
|
|
if(found[i].split(".")[0].slice(1,).toLowerCase() == actionlist[j].autocomplete.toLowerCase()){
|
|
//console.log("Found: ", found[i])
|
|
// Validate path?
|
|
|
|
foundSlice = true
|
|
}
|
|
}
|
|
|
|
if (!foundSlice) {
|
|
if (!helperText.includes("Invalid variables")) {
|
|
helperText+= "Invalid variables: "
|
|
}
|
|
helperText+= found[i] + ", "
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log("Parsing error: ", e)
|
|
}
|
|
}
|
|
|
|
if (looperText.length > 0) {
|
|
if (helperText.length > 0) {
|
|
helperText += ". "
|
|
}
|
|
|
|
helperText += looperText
|
|
}
|
|
|
|
return helperText
|
|
}
|
|
|
|
const changeActionParameter = (event, count, data, viewForceUpdate) => {
|
|
//console.log("Action change: ", selectedAction, data)
|
|
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
|
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
|
const paramcheck = selectedAction.parameters.find((param) => param.name === "body");
|
|
|
|
if (paramcheck !== undefined) {
|
|
// Escapes all double quotes
|
|
var toReplace = event.target.value.trim()
|
|
|
|
|
|
if (!toReplace.startsWith("{") && !toReplace.startsWith("[")) {
|
|
toReplace = toReplace.replaceAll('\\"', '"').replaceAll('"', '\\"')
|
|
}
|
|
|
|
console.log("REPLACE WITH: ", toReplace);
|
|
if (
|
|
paramcheck["value_replace"] === undefined ||
|
|
paramcheck["value_replace"] === null
|
|
) {
|
|
paramcheck["value_replace"] = [
|
|
{
|
|
key: data.name,
|
|
value: toReplace,
|
|
},
|
|
];
|
|
|
|
console.log("IN IF: ", paramcheck);
|
|
} else {
|
|
const subparamindex = paramcheck["value_replace"].findIndex(
|
|
(param) => param.key === data.name
|
|
);
|
|
if (subparamindex === -1) {
|
|
paramcheck["value_replace"].push({
|
|
key: data.name,
|
|
value: toReplace,
|
|
});
|
|
} else {
|
|
paramcheck["value_replace"][subparamindex]["value"] = toReplace;
|
|
}
|
|
|
|
console.log("IN ELSE: ", paramcheck);
|
|
}
|
|
//console.log("PARAM: ", paramcheck)
|
|
//if (paramcheck.id === undefined) {
|
|
// console.log("Normal paramcheck")
|
|
//} else {
|
|
// selectedActionParameters[count]["value_replace"] = paramcheck
|
|
// selectedAction.parameters[count]["value_replace"] = paramcheck
|
|
//}
|
|
|
|
if (paramcheck["value_replace"] === undefined) {
|
|
selectedActionParameters[count]["value_replace"] = paramcheck;
|
|
selectedAction.parameters[count]["value_replace"] = paramcheck;
|
|
} else {
|
|
selectedActionParameters[count]["value_replace"] =
|
|
paramcheck["value_replace"];
|
|
selectedAction.parameters[count]["value_replace"] =
|
|
paramcheck["value_replace"];
|
|
}
|
|
setSelectedAction(selectedAction);
|
|
//setUpdate(Math.random())
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (event.target.value[event.target.value.length - 1] === "$") {
|
|
if (!showDropdown) {
|
|
setShowAutocomplete(false);
|
|
setShowDropdown(true);
|
|
setShowDropdownNumber(count);
|
|
}
|
|
} else {
|
|
if (showDropdown) {
|
|
setShowDropdown(false);
|
|
}
|
|
}
|
|
|
|
// bad detection mechanism probably
|
|
if (event.target.value[event.target.value.length - 1] === "." && actionlist.length > 0) {
|
|
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"}
|
|
setJsonList(GetParsedPaths(inputdata, ""))
|
|
if (!showDropdown) {
|
|
setShowAutocomplete(false)
|
|
setShowDropdown(true)
|
|
setShowDropdownNumber(count)
|
|
}
|
|
console.log(jsonList)
|
|
*/
|
|
|
|
// Search for the item backwards
|
|
// 1. Reverse search backwards from . -> $
|
|
// 2. Search the actionlist for the item
|
|
// 3. Find the data for the specific item
|
|
|
|
var curstring = "";
|
|
var record = false;
|
|
for (let [key,keyval] in Object.entries(selectedActionParameters[count].value)) {
|
|
const item = selectedActionParameters[count].value[key];
|
|
if (record) {
|
|
curstring += item;
|
|
}
|
|
|
|
if (item === "$") {
|
|
record = true;
|
|
curstring = "";
|
|
}
|
|
}
|
|
|
|
//console.log("CURSTRING: ", curstring)
|
|
if (curstring.length > 0 && actionlist !== null) {
|
|
// Search back in the action list
|
|
curstring = curstring.split(" ").join("_").toLowerCase();
|
|
var actionItem = actionlist.find(
|
|
(data) =>
|
|
data.autocomplete.split(" ").join("_").toLowerCase() === curstring
|
|
);
|
|
if (actionItem !== undefined) {
|
|
console.log("Found item: ", actionItem);
|
|
|
|
//actionItem.example = actionItem.example.trim()
|
|
//actionItem.example = actionItem.example.split(" None").join(" \"None\"")
|
|
//actionItem.example = actionItem.example.split("\'").join("\"")
|
|
|
|
var jsonvalid = true;
|
|
try {
|
|
const tmp = String(JSON.parse(actionItem.example));
|
|
if (
|
|
!actionItem.example.includes("{") &&
|
|
!actionItem.example.includes("[")
|
|
) {
|
|
jsonvalid = false;
|
|
}
|
|
} catch (e) {
|
|
jsonvalid = false;
|
|
}
|
|
|
|
if (jsonvalid) {
|
|
setJsonList(GetParsedPaths(JSON.parse(actionItem.example), ""));
|
|
|
|
if (!showDropdown) {
|
|
setShowAutocomplete(false);
|
|
setShowDropdown(true);
|
|
setShowDropdownNumber(count);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (jsonList.length > 0) {
|
|
setJsonList([]);
|
|
}
|
|
}
|
|
|
|
//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;
|
|
|
|
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") {
|
|
console.log("APIKEY - this shouldn't show up!")
|
|
}
|
|
|
|
if (selectedAction.app_name === "Shuffle Tools" && selectedAction.name === "filter_list" && data.name === "input_list") {
|
|
//console.log("FILTER LIST!: ", event, count, data)
|
|
const parsedvalue = event.target.value
|
|
if (parsedvalue.includes("#")) {
|
|
const splitparsed = parsedvalue.split(".#.")
|
|
//console.log("Cant contain #: ", splitparsed)
|
|
if (splitparsed.length > 1) {
|
|
data.value = splitparsed[0]
|
|
|
|
selectedActionParameters[count].value = splitparsed[0]
|
|
selectedAction.parameters[count].value = splitparsed[0]
|
|
|
|
selectedActionParameters[1].value = splitparsed[1]
|
|
selectedAction.parameters[1].value = splitparsed[1]
|
|
forceUpdate = true
|
|
}
|
|
}
|
|
}
|
|
|
|
setSelectedAction(selectedAction);
|
|
if (forceUpdate || viewForceUpdate === true) {
|
|
setUpdate(Math.random())
|
|
}
|
|
//setUpdate(event.target.value)
|
|
};
|
|
|
|
|
|
const changeActionParameterCodeMirror = (event, count, data) => {
|
|
if (data.startsWith("${") && data.endsWith("}")) {
|
|
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
|
const paramcheck = selectedAction.parameters.find(param => param.name === "body")
|
|
if (paramcheck !== undefined) {
|
|
// Escapes all double quotes
|
|
const toReplace = event.target.value.trim().replaceAll("\\\"", "\"").replaceAll("\"", "\\\"");
|
|
console.log("REPLACE WITH: ", toReplace)
|
|
if (paramcheck["value_replace"] === undefined || paramcheck["value_replace"] === null) {
|
|
paramcheck["value_replace"] = [{
|
|
"key": data.name,
|
|
"value": toReplace,
|
|
}]
|
|
|
|
console.log("IN IF: ", paramcheck)
|
|
|
|
} else {
|
|
const subparamindex = paramcheck["value_replace"].findIndex(param => param.key === data.name)
|
|
if (subparamindex === -1) {
|
|
paramcheck["value_replace"].push({
|
|
"key": data.name,
|
|
"value": toReplace,
|
|
})
|
|
} else {
|
|
paramcheck["value_replace"][subparamindex]["value"] = toReplace
|
|
}
|
|
|
|
console.log("IN ELSE: ", paramcheck)
|
|
}
|
|
//console.log("PARAM: ", paramcheck)
|
|
//if (paramcheck.id === undefined) {
|
|
// console.log("Normal paramcheck")
|
|
//} else {
|
|
// selectedActionParameters[count]["value_replace"] = paramcheck
|
|
// selectedAction.parameters[count]["value_replace"] = paramcheck
|
|
//}
|
|
|
|
if (paramcheck["value_replace"] === undefined) {
|
|
selectedActionParameters[count]["value_replace"] = paramcheck
|
|
selectedAction.parameters[count]["value_replace"] = paramcheck
|
|
} else {
|
|
selectedActionParameters[count]["value_replace"] = paramcheck["value_replace"]
|
|
selectedAction.parameters[count]["value_replace"] = paramcheck["value_replace"]
|
|
}
|
|
console.log("RESULT: ", selectedAction)
|
|
setSelectedAction(selectedAction)
|
|
//setUpdate(Math.random())
|
|
return
|
|
}
|
|
}
|
|
|
|
if (event.target.value[event.target.value.length-1] === "$") {
|
|
if (!showDropdown) {
|
|
setShowAutocomplete(false)
|
|
setShowDropdown(true)
|
|
setShowDropdownNumber(count)
|
|
}
|
|
} else {
|
|
if (showDropdown) {
|
|
setShowDropdown(false)
|
|
}
|
|
}
|
|
|
|
// bad detection mechanism probably
|
|
if (event.target.value[event.target.value.length-1] === "." && actionlist.length > 0) {
|
|
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"}
|
|
setJsonList(GetParsedPaths(inputdata, ""))
|
|
if (!showDropdown) {
|
|
setShowAutocomplete(false)
|
|
setShowDropdown(true)
|
|
setShowDropdownNumber(count)
|
|
}
|
|
console.log(jsonList)
|
|
*/
|
|
|
|
// Search for the item backwards
|
|
// 1. Reverse search backwards from . -> $
|
|
// 2. Search the actionlist for the item
|
|
// 3. Find the data for the specific item
|
|
|
|
var curstring = ""
|
|
var record = false
|
|
for (let [key,keyval] in Object.entries(selectedActionParameters[count].value)) {
|
|
const item = selectedActionParameters[count].value[key]
|
|
if (record) {
|
|
curstring += item
|
|
}
|
|
|
|
if (item === "$") {
|
|
record = true
|
|
curstring = ""
|
|
}
|
|
}
|
|
|
|
//console.log("CURSTRING: ", curstring)
|
|
if (curstring.length > 0 && actionlist !== null) {
|
|
// Search back in the action list
|
|
curstring = curstring.split(" ").join("_").toLowerCase()
|
|
var actionItem = actionlist.find(data => data.autocomplete.split(" ").join("_").toLowerCase() === curstring)
|
|
if (actionItem !== undefined) {
|
|
console.log("Found item: ", actionItem)
|
|
|
|
//actionItem.example = actionItem.example.trim()
|
|
//actionItem.example = actionItem.example.split(" None").join(" \"None\"")
|
|
//actionItem.example = actionItem.example.split("\'").join("\"")
|
|
|
|
var jsonvalid = true
|
|
try {
|
|
const tmp = String(JSON.parse(actionItem.example))
|
|
if (!actionItem.example.includes("{") && !actionItem.example.includes("[")) {
|
|
jsonvalid = false
|
|
}
|
|
} catch (e) {
|
|
jsonvalid = false
|
|
}
|
|
|
|
if (jsonvalid) {
|
|
setJsonList(GetParsedPaths(JSON.parse(actionItem.example), ""))
|
|
|
|
if (!showDropdown) {
|
|
setShowAutocomplete(false)
|
|
setShowDropdown(true)
|
|
setShowDropdownNumber(count)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (jsonList.length > 0) {
|
|
setJsonList([])
|
|
}
|
|
}
|
|
|
|
selectedActionParameters[count].autocompleted = false
|
|
selectedAction.parameters[count].autocompleted = false
|
|
selectedActionParameters[count].value = data
|
|
selectedAction.parameters[count].value = data
|
|
setSelectedAction(selectedAction)
|
|
//setUpdate(Math.random())
|
|
//setUpdate(event.target.value)
|
|
}
|
|
|
|
|
|
const changeActionParameterVariable = (fieldvalue, count) => {
|
|
//console.log("CALLED THIS ONE WITH VALUE!", fieldvalue)
|
|
//if (selectedVariableParameter === fieldvalue) {
|
|
// return
|
|
//}
|
|
|
|
setSelectedVariableParameter(fieldvalue);
|
|
|
|
selectedActionParameters[count].action_field = fieldvalue;
|
|
selectedAction.parameters = selectedActionParameters;
|
|
|
|
setSelectedApp(selectedApp);
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(fieldvalue);
|
|
};
|
|
|
|
// Sets ACTION_RESULT things
|
|
const changeActionParameterActionResult = (fieldvalue, count) => {
|
|
//cy.nodes().forEach(function( ele ) {
|
|
// if (ele.data()["label"] === fieldvalue) {
|
|
// selectedActionParameters[count].action_field = ele.id()
|
|
// return
|
|
// }
|
|
//});
|
|
|
|
selectedActionParameters[count].action_field = fieldvalue;
|
|
selectedAction.parameters = selectedActionParameters;
|
|
|
|
// FIXME - check if startnode
|
|
|
|
// Set value
|
|
setSelectedApp(selectedApp);
|
|
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
};
|
|
|
|
const changeActionParameterVariant = (data, count) => {
|
|
selectedActionParameters[count].variant = data;
|
|
selectedActionParameters[count].value = "";
|
|
|
|
if (data === "ACTION_RESULT" && getParents !== undefined) {
|
|
var parents = getParents(selectedAction);
|
|
if (parents.length > 0) {
|
|
selectedActionParameters[count].action_field = parents[0].label;
|
|
} else {
|
|
selectedActionParameters[count].action_field = "";
|
|
}
|
|
} else if (data === "WORKFLOW_VARIABLE") {
|
|
if (
|
|
workflow.workflow_variables !== null &&
|
|
workflow.workflow_variables !== undefined &&
|
|
workflow.workflow_variables.length > 0
|
|
) {
|
|
selectedActionParameters[count].action_field =
|
|
workflow.workflow_variables[0].name;
|
|
}
|
|
}
|
|
|
|
selectedAction.parameters = selectedActionParameters;
|
|
|
|
// This is a stupid workaround to make it refresh rofl
|
|
setSelectedAction({});
|
|
|
|
if (setSelectedTrigger !== undefined) {
|
|
setSelectedTrigger({});
|
|
setSelectedApp({});
|
|
setSelectedEdge({});
|
|
}
|
|
// FIXME - check if startnode
|
|
|
|
// Set value
|
|
setSelectedApp(selectedApp);
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
};
|
|
|
|
|
|
const returnHelperText = (name, value) => {
|
|
if (name === undefined || value === undefined || name === null || value === null || name === "" || value === "") {
|
|
//console.log("RETURNING EMPTY")
|
|
return ""
|
|
}
|
|
|
|
var helperText = ""
|
|
if (name.includes("url")) {
|
|
if (value.includes("localhost") || value.includes("127.0.0.1")) {
|
|
helperText = "Can't use localhost. Please change to your external IP."
|
|
}
|
|
}
|
|
|
|
// Helpertext for openapi fields
|
|
//if (helperText === "" && name === "body" && selectedApp.generated && selectedApp.activated) {
|
|
// helperText = <span style={{color: "white", marginBottom: 5, marginleft: 5}}>
|
|
//}
|
|
|
|
return helperText
|
|
}
|
|
|
|
const analyzeFields = () => {
|
|
|
|
if (selectedAction === undefined || selectedAction === null) {
|
|
return null
|
|
}
|
|
|
|
if (selectedActionParameters === undefined || selectedActionParameters === null || selectedActionParameters.length === 0) {
|
|
return null
|
|
}
|
|
|
|
// Only shuffle tools for now
|
|
if (selectedAction.app_name !== "Shuffle Tools") {
|
|
return null
|
|
}
|
|
|
|
// Custom rules
|
|
if (selectedAction.name === "set_cache_value") {
|
|
var actionKey = ""
|
|
var actionValue = ""
|
|
for (let [key,keyval] in Object.entries(selectedActionParameters)) {
|
|
const param = selectedActionParameters[key]
|
|
if (param.name === "key") {
|
|
actionKey = param.value
|
|
}
|
|
|
|
if (param.name === "value") {
|
|
actionValue = param.value
|
|
}
|
|
}
|
|
|
|
if (actionKey === "" || actionValue === "") {
|
|
return null
|
|
}
|
|
|
|
if (!actionKey.includes(".#") && actionValue.includes(".#")) {
|
|
return <span>When the key ({actionKey}) is static, but the value is a list ({actionValue}), it will overwrite the list. You may be looking for the <span onClick={() => {}} style={{cursor: "pointer", color: "#f85a3e", }}>Check Cache Contains</span> action instead.</span>
|
|
}
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
const suggestionInfo = () => {
|
|
const suggestionText = analyzeFields()
|
|
if (suggestionText === undefined || suggestionText === null) {
|
|
return null
|
|
}
|
|
|
|
if (selectedAction.errors === undefined || selectedAction.errors === null || selectedAction.errors.length === 0) {
|
|
selectedAction.errors = ["Suggestion: " + suggestionText]
|
|
}
|
|
|
|
return <Paper style={{padding: 10, backgroundColor: theme.palette.surfaceColor, border: "1px solid red",}}>
|
|
<Typography variant="body" style={{color: "white", }}>
|
|
<b>Tip:</b> {suggestionText}
|
|
</Typography>
|
|
</Paper>
|
|
}
|
|
|
|
// FIXME: Issue #40 - selectedActionParameters not reset
|
|
if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0) {
|
|
|
|
var wrapperapp = {
|
|
"id": "",
|
|
"name": "noapp",
|
|
"large_image": "",
|
|
}
|
|
|
|
var actionname = selectedAction.name.toLowerCase()
|
|
if (actionname === "email" || actionname === "communication") {
|
|
actionname = "comms"
|
|
}
|
|
|
|
if (isIntegration) {
|
|
|
|
// Check if actionname uppercase is in the parsedDatatypeImages() dictionary
|
|
if (parsedDatatypeImages()[actionname.toUpperCase()] !== undefined) {
|
|
var newimage = parsedDatatypeImages()[actionname.toUpperCase()]
|
|
//newimage = <img src={newimage} style={{width: 35, height: 35, marginRight: 5, borderRadius: 5, cursor: "pointer", border: noAppSelected ? "3px solid #86c142" : "2px solid rgba(255,255,255,0.6)"}} />
|
|
wrapperapp.large_image = newimage
|
|
} else {
|
|
console.log("Couldn't find actionname: ", actionname)
|
|
}
|
|
}
|
|
|
|
var authWritten = false;
|
|
var noAppSelected = false
|
|
const 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
|
|
}
|
|
return (
|
|
<div style={{ marginTop: hideExtraTypes ? 10 : 30 }}>
|
|
{isIntegration ?
|
|
apps !== undefined && apps !== null && apps.length > 0 ?
|
|
<div style={{display: "flex", maxWidth: 335, overflowX: "auto", overflowY: "hidden",}}>
|
|
<div onClick={() => {
|
|
|
|
selectedAction.example = "noapp"
|
|
selectedAction.large_image = newimage
|
|
if (cy !== undefined && cy !== null) {
|
|
const foundnode = cy.getElementById(selectedAction.id)
|
|
if (foundnode !== undefined && foundnode !== null) {
|
|
foundnode.data("large_image", newimage)
|
|
}
|
|
}
|
|
|
|
const iconInfo = GetIconInfo(selectedAction)
|
|
if (iconInfo !== undefined && iconInfo !== null) {
|
|
selectedAction.fillGradient = iconInfo.fillGradient
|
|
|
|
selectedAction.iconBackground = iconInfo.iconBackgroundColor
|
|
selectedAction.fillstyle = "linear-gradient"
|
|
}
|
|
|
|
if (paramIndex === -1) {
|
|
console.log("Couldn't find app_name parameter")
|
|
selectedAction.parameters.push({
|
|
name: "app_name",
|
|
value: wrapperapp.name,
|
|
autocompleted: false,
|
|
})
|
|
} else {
|
|
selectedAction.parameters[paramIndex].value = wrapperapp.name
|
|
}
|
|
|
|
setSelectedAction(selectedAction)
|
|
setUpdate(Math.random())
|
|
|
|
}}>
|
|
<Tooltip title={"Unselect which App to use"} placement="top">
|
|
<div style={{textAlign: "center", }}>
|
|
<img
|
|
src={wrapperapp.large_image}
|
|
style={{
|
|
minWidth: 30,
|
|
maxWidth: 30,
|
|
minHeight: 30,
|
|
maxHeight: 30,
|
|
|
|
marginRight: 5,
|
|
borderRadius: 5,
|
|
cursor: "pointer",
|
|
border: noAppSelected ? "3px solid #86c142" : "2px solid rgba(255,255,255,0.6)",
|
|
|
|
paddingLeft: 5,
|
|
paddingTop: 5,
|
|
}} />
|
|
</div>
|
|
</Tooltip>
|
|
</div>
|
|
{apps.map((app, appIndex) => {
|
|
if (app.categories === undefined || app.categories === null || app.categories.length === 0) {
|
|
return null
|
|
}
|
|
|
|
var found = false
|
|
|
|
|
|
for (var key in app.categories) {
|
|
if (app.categories[key].toLowerCase() !== actionname) {
|
|
continue
|
|
}
|
|
|
|
found = true
|
|
break
|
|
}
|
|
|
|
if (!found) {
|
|
return null
|
|
}
|
|
|
|
var isAppSelected = false
|
|
const paramIndex = selectedAction.parameters.findIndex((param) => param.name === "app_name")
|
|
if (paramIndex > -1) {
|
|
// Check the actual value and if it's the same
|
|
if (selectedAction.parameters[paramIndex].value === app.name) {
|
|
isAppSelected = true
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div onClick={() => {
|
|
selectedAction.example = ""
|
|
selectedAction.large_image = app.large_image
|
|
if (cy !== undefined && cy !== null) {
|
|
const foundnode = cy.getElementById(selectedAction.id)
|
|
if (foundnode !== undefined && foundnode !== null) {
|
|
foundnode.data("large_image", app.large_image)
|
|
}
|
|
}
|
|
|
|
if (paramIndex === -1) {
|
|
console.log("Couldn't find app_name parameter")
|
|
selectedAction.parameters.push({
|
|
name: "app_name",
|
|
value: app.name,
|
|
autocompleted: false,
|
|
})
|
|
} else {
|
|
selectedAction.parameters[paramIndex].value = app.name
|
|
}
|
|
|
|
setSelectedAction(selectedAction)
|
|
setUpdate(Math.random())
|
|
|
|
}}>
|
|
<Tooltip title={`Select ${app.name.replaceAll("_", " ")}`} placement="top">
|
|
<img
|
|
src={app.large_image}
|
|
style={{
|
|
width: 35,
|
|
height: 35,
|
|
marginRight: 5,
|
|
borderRadius: 5,
|
|
cursor: "pointer",
|
|
border: isAppSelected ? "3px solid #86c142" : "2px solid rgba(255,255,255,0.6)",
|
|
}} />
|
|
</Tooltip>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
: null
|
|
:
|
|
<Tooltip
|
|
color="secondary"
|
|
title={"Click to learn more about this action"}
|
|
placement="top"
|
|
>
|
|
<Button
|
|
variant="text"
|
|
color="secondary"
|
|
style={{justifyContent: "flex-start", textAlign: "left", textTransform: "none", width: "100%",}}
|
|
fullWidth
|
|
disabled={selectedAction.description === undefined || selectedAction.description === null || selectedAction.description.length === 0}
|
|
onClick={() => {
|
|
setHiddenDescription(!hiddenDescription)
|
|
}}
|
|
>
|
|
<b>Parameters</b>
|
|
</Button>
|
|
</Tooltip>
|
|
}
|
|
|
|
{selectedAction.template === true && selectedAction.matching_actions !== undefined && selectedAction.matching_actions !== null && selectedAction.matching_actions.length > 0 ?
|
|
<div>
|
|
<Typography variant="body1">
|
|
Select an app you want to use
|
|
</Typography>
|
|
<Autocomplete
|
|
id="template_action_search"
|
|
autoHighlight
|
|
value={selectedAction}
|
|
classes={{ inputRoot: classes.inputRoot }}
|
|
ListboxProps={{
|
|
style: {
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
},
|
|
}}
|
|
getOptionLabel={(option) => {
|
|
console.log("LABEL: ", option)
|
|
if (
|
|
option === undefined ||
|
|
option === null ||
|
|
option.app_name === undefined ||
|
|
option.app_name === null
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const newname = (
|
|
option.app_name.charAt(0).toUpperCase() + option.app_name.substring(1)
|
|
).replaceAll("_", " ");
|
|
return newname;
|
|
}}
|
|
options={selectedAction.matching_actions}
|
|
fullWidth
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
height: 50,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
onChange={(event, newValue) => {
|
|
console.log("SELECT: ", event, newValue)
|
|
// Workaround with event lol
|
|
//if (newValue !== undefined && newValue !== null) {
|
|
// setNewSelectedAction({ target: { value: newValue.name } });
|
|
//}
|
|
}}
|
|
renderOption={(props, data, state) => {
|
|
var newActionname = data.app_name;
|
|
if (
|
|
data.label !== undefined &&
|
|
data.label !== null &&
|
|
data.label.length > 0
|
|
) {
|
|
newActionname = data.label;
|
|
}
|
|
|
|
const iconInfo = GetIconInfo({ name: data.app_name });
|
|
const useIcon = iconInfo.originalIcon;
|
|
|
|
console.log("Actionname 1: ", newActionname)
|
|
|
|
newActionname = (
|
|
newActionname.charAt(0).toUpperCase() +
|
|
newActionname.substring(1)
|
|
).replaceAll("_", " ");
|
|
|
|
return (
|
|
<div style={{ display: "flex" }}>
|
|
<span
|
|
style={{
|
|
marginRight: 10,
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
}}
|
|
>
|
|
{useIcon}
|
|
</span>
|
|
<span style={{}}>{newActionname}</span>
|
|
</div>
|
|
);
|
|
}}
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
return (
|
|
<TextField
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
{...params}
|
|
label="Find App to Translate"
|
|
variant="outlined"
|
|
/>
|
|
);
|
|
}}
|
|
/>
|
|
</div>
|
|
: null}
|
|
{selectedAction.description !== undefined && selectedAction.description !== null && selectedAction.description.length > 0 && hiddenDescription === false ? (
|
|
<div
|
|
style={{
|
|
border: "1px solid rgba(255,255,255,0.6)",
|
|
borderRadius: theme.palette.borderRadius,
|
|
marginTop: 15,
|
|
marginBottom: 10,
|
|
maxHeight: 70,
|
|
overflow: "auto",
|
|
padding: 15,
|
|
}}
|
|
>
|
|
<Typography style={{}}>
|
|
<b>Description</b>
|
|
</Typography>
|
|
<Typography style={{}}>
|
|
{selectedAction.description}
|
|
</Typography>
|
|
</div>
|
|
) : null}
|
|
|
|
{suggestionInfo()}
|
|
|
|
{selectedActionParameters.map((data, count) => {
|
|
if (data.variant === "") {
|
|
data.variant = "STATIC_VALUE";
|
|
}
|
|
|
|
if (isIntegration && data.name === "app_name") {
|
|
return null
|
|
}
|
|
|
|
// selectedAction.selectedAuthentication = e.target.value
|
|
// selectedAction.authentication_id = e.target.value.id
|
|
if (
|
|
!selectedAction.auth_not_required &&
|
|
selectedAction.selectedAuthentication !== undefined &&
|
|
selectedAction.selectedAuthentication.fields !== undefined &&
|
|
selectedAction.selectedAuthentication.fields[data.name] !==
|
|
undefined
|
|
) {
|
|
// This sets the placeholder in the frontend. (Replaced in backend)
|
|
selectedActionParameters[count].value =
|
|
selectedAction.selectedAuthentication.fields[data.name];
|
|
selectedAction.parameters[count].value =
|
|
selectedAction.selectedAuthentication.fields[data.name];
|
|
setSelectedAction(selectedAction);
|
|
//setUpdate(Math.random())
|
|
|
|
if (authWritten) {
|
|
return null;
|
|
}
|
|
|
|
authWritten = true;
|
|
return (
|
|
<Typography
|
|
key={count}
|
|
id="skip_auth"
|
|
variant="body2"
|
|
color="textSecondary"
|
|
style={{ marginTop: 5 }}
|
|
>
|
|
Authentication fields are hidden
|
|
</Typography>
|
|
);
|
|
}
|
|
|
|
// Added autofill to make this ALOT simpler
|
|
if (isCloud && (selectedAction.app_name === "Shuffle Tools" || selectedAction.app_name === "email") && (selectedAction.name === "send_email_shuffle" || selectedAction.name === "send_sms_shuffle") && data.name === "apikey") {
|
|
if (selectedActionParameters[count].length === 0) {
|
|
selectedAction.parameters[count].value = "TMP: Will be replaced during execution if cloud"
|
|
setSelectedAction(selectedAction)
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
var staticcolor = "inherit";
|
|
var actioncolor = "inherit";
|
|
var varcolor = "inherit";
|
|
var multiline
|
|
if (
|
|
data.multiline !== undefined &&
|
|
data.multiline !== null &&
|
|
data.multiline === true
|
|
) {
|
|
multiline = true;
|
|
}
|
|
|
|
// make data.value from array to comma separated string if it is an array
|
|
if (data.value !== undefined && data.value !== null && Array.isArray(data.value)) {
|
|
data.value = data.value.join(",")
|
|
}
|
|
|
|
if (
|
|
data.value !== undefined &&
|
|
data.value !== null &&
|
|
data.value.startsWith("{") &&
|
|
data.value.endsWith("}")
|
|
) {
|
|
multiline = true;
|
|
}
|
|
|
|
var placeholder = "Value";
|
|
if (data.example !== undefined && data.example !== null && data.example.length > 0) {
|
|
|
|
placeholder = data.example;
|
|
|
|
if (data.name === "url" && data.value !== undefined && data.value !== null && data.value.length === 0) {
|
|
data.value = data.example;
|
|
}
|
|
// In case of data.example
|
|
if (data.value === undefined || data.value === null) {
|
|
data.value = ""
|
|
}
|
|
|
|
if (data.value.length === 0) {
|
|
if (data.name.toLowerCase() === "headers") {
|
|
console.log("Should show headers field instead with + and -!")
|
|
|
|
// Check if file ID exists
|
|
//
|
|
const fileFound = selectedActionParameters.find(param => param.name === "file_id")
|
|
if (fileFound === undefined || fileFound === null) {
|
|
data.value = data.example
|
|
} else {
|
|
// Purposely unset it if set by default when using files
|
|
data.value = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (data.name !== "queries" && data.name !== "key" && data.name !== "value" ) {
|
|
data.value = data.example
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
if (selectedAction.name === "custom_action" && data.name === "body") {
|
|
for (var key in selectedActionParameters) {
|
|
const param = selectedActionParameters[key]
|
|
if (param.name === "method") {
|
|
if (param.value === "GET") {
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
|
const paramcheck = selectedAction.parameters.find((param) => param.name === "body");
|
|
|
|
|
|
if (paramcheck !== undefined && paramcheck !== null) {
|
|
if (
|
|
paramcheck["value_replace"] !== undefined &&
|
|
paramcheck["value_replace"] !== null
|
|
) {
|
|
//console.log("IN THE VALUE REPLACE: ", paramcheck["value_replace"])
|
|
const subparamindex = paramcheck["value_replace"].findIndex(
|
|
(param) => param.key === data.name
|
|
);
|
|
if (subparamindex !== -1) {
|
|
data.value =
|
|
paramcheck["value_replace"][subparamindex]["value"];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
var showCacheConfig = false
|
|
if (data.name === "key" && selectedAction.name.includes("cache") && selectedAction.app_name === "Shuffle Tools") {
|
|
// Show a key popout button
|
|
showCacheConfig = true
|
|
}
|
|
|
|
var disabled = false;
|
|
var rows = "3";
|
|
var openApiHelperText = "This is an OpenAPI specific field";
|
|
|
|
if (selectedApp.generated && data.name === "headers") {
|
|
//console.log("HEADER: ", data)
|
|
//if (data.value.length === 0) {
|
|
//}
|
|
//setSelectedActionParameters(selectedActionParameters)
|
|
}
|
|
|
|
var hideBodyButton = "";
|
|
const hideBodyButtonValue = (
|
|
<div
|
|
key={data.name}
|
|
id="hide_body_button"
|
|
style={{
|
|
marginTop: 50,
|
|
border: "1px solid rgba(255,255,255,0.7)",
|
|
borderTop: "1px solid rgba(255,255,255,0.7)",
|
|
borderRadius: theme.palette.borderRadius,
|
|
alignItems: "center",
|
|
textAlign: "center",
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="secondary"
|
|
title={hideBody ? "Hide all body fields and only show the body itself" : "Show all body fields instead of the body itself"}
|
|
placement="top"
|
|
>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
tabIndex="-1"
|
|
checked={hideBody}
|
|
style={{
|
|
color: theme.palette.primary.secondary,
|
|
}}
|
|
onChange={(event) => {
|
|
var tag = "TOGGLED"
|
|
if (hideBody) {
|
|
tag = "UNTOGGLED"
|
|
}
|
|
|
|
setHideBody(!hideBody)
|
|
for (let paramkey in Object.entries(selectedActionParameters)) {
|
|
var currentItem = selectedActionParameters[paramkey];
|
|
if (currentItem.name === "ssl_verify") {
|
|
|
|
}
|
|
|
|
if (currentItem.name === "body") {
|
|
currentItem.id = tag
|
|
}
|
|
|
|
if (currentItem.description === openApiFieldDesc) {
|
|
currentItem.field_active = !hideBody
|
|
}
|
|
}
|
|
|
|
|
|
// Scroll to hide_body_button
|
|
setTimeout(() => {
|
|
var element = document.getElementById("hide_body_button")
|
|
if (element !== undefined && element !== null) {
|
|
// Keep the button a little below the top
|
|
element.scrollIntoView({
|
|
behavior: "smooth",
|
|
block: "center",
|
|
})
|
|
}
|
|
}, 100)
|
|
|
|
|
|
}}
|
|
name="requires_unique"
|
|
/>
|
|
}
|
|
label={hideBody ? "Show Body" : "Hide Body"}
|
|
/>
|
|
</Tooltip>
|
|
</div>
|
|
)
|
|
|
|
if (selectedApp.generated && data.name === "body") {
|
|
const regex = /\${(\w+)}/g;
|
|
const found = placeholder.match(regex);
|
|
|
|
// setActivateHidingBodyButton(false)
|
|
//
|
|
hideBodyButton = hideBodyButtonValue;
|
|
if (found === null || !hideBody) {
|
|
if (found === null) {
|
|
setActivateHidingBodyButton(true);
|
|
} else {
|
|
//console.log("In found: ", found, hideBody)
|
|
}
|
|
} else {
|
|
|
|
rows = "1";
|
|
disabled = true;
|
|
openApiHelperText = "OpenAPI spec: fill the following fields.";
|
|
|
|
var changed = false;
|
|
var tempArray = []
|
|
for (let specKey in found) {
|
|
const tmpitem = found[specKey];
|
|
var skip = false;
|
|
|
|
for (let innerkey in selectedActionParameters) {
|
|
if (selectedActionParameters[innerkey].name === tmpitem) {
|
|
skip = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (skip) {
|
|
//console.log("SKIPPING ", tmpitem)
|
|
continue;
|
|
}
|
|
|
|
changed = true;
|
|
var isRequired = false
|
|
// Check if original field name is in the selectedAction.required_body_fields
|
|
if (selectedAction.required_body_fields !== undefined && selectedAction.required_body_fields !== null) {
|
|
for (let innerkey in selectedAction.required_body_fields) {
|
|
if (selectedAction.required_body_fields[innerkey] === tmpitem) {
|
|
isRequired = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
tempArray.push({
|
|
action_field: "",
|
|
configuration: false,
|
|
description: openApiFieldDesc,
|
|
example: "",
|
|
id: "",
|
|
multiline: true,
|
|
name: tmpitem,
|
|
options: null,
|
|
required: isRequired,
|
|
schema: { type: "string" },
|
|
skip_multicheck: false,
|
|
tags: null,
|
|
value: "",
|
|
variant: "STATIC_VALUE",
|
|
field_active: true,
|
|
|
|
autocompleted: true,
|
|
});
|
|
}
|
|
|
|
console.log("TEMP ARRAY: ", tempArray)
|
|
var required = selectedActionParameters.filter(item => item.required === true)
|
|
var notRequired = selectedActionParameters.filter(item => item.required === false)
|
|
|
|
if (tempArray.length > 0) {
|
|
// Sort tempArray based on tempArray.required
|
|
tempArray.sort((a, b) => (a.required < b.required) ? 1 : -1)
|
|
// Add all items to the selectedActionParameters array
|
|
for (let innerkey in tempArray) {
|
|
tempArray[innerkey].id = "ADDED"
|
|
|
|
if (tempArray[innerkey].required === true) {
|
|
required.push(tempArray[innerkey])
|
|
} else {
|
|
notRequired.push(tempArray[innerkey])
|
|
}
|
|
}
|
|
}
|
|
//selectedActionParameters
|
|
|
|
if (changed) {
|
|
// Sort selectedActionParameters based on selectedActionParameters.required
|
|
//selectedActionParameters.sort((a, b) => (a.required < b.required) ? 1 : -1)
|
|
// Find the "headers" and "queries" field names and put them on the first indexes anyway
|
|
var newArray = required.concat(notRequired)
|
|
|
|
|
|
setSelectedActionParameters(newArray)
|
|
}
|
|
|
|
return hideBodyButton;
|
|
}
|
|
}
|
|
|
|
if (activateHidingBodyButton === true) {
|
|
hideBodyButton = "";
|
|
}
|
|
|
|
const clickedFieldId = "rightside_field_" + count;
|
|
|
|
var baseHelperText = ""
|
|
if (data !== undefined && data !== null && data.value !== undefined && data.value !== null && data.value.length > 0) {
|
|
baseHelperText = calculateHelpertext(data.value)
|
|
}
|
|
|
|
|
|
var tmpitem = data.name.valueOf();
|
|
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
|
tmpitem = tmpitem.slice(2, data.name.length - 1);
|
|
}
|
|
|
|
if (tmpitem === "from_shuffle") {
|
|
tmpitem = "from"
|
|
}
|
|
|
|
tmpitem = (
|
|
tmpitem.charAt(0).toUpperCase() + tmpitem.substring(1)
|
|
).replaceAll("_", " ");
|
|
|
|
if (tmpitem === "Username basic") {
|
|
tmpitem = "Username"
|
|
} else if (tmpitem === "Password basic") {
|
|
tmpitem = "Password"
|
|
}
|
|
|
|
multiline = data.name.startsWith("${") && data.name.endsWith("}") ? true : multiline
|
|
|
|
var datafield = (
|
|
<TextField
|
|
disabled={disabled}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
borderRadius: theme.palette.borderRadius,
|
|
border:
|
|
selectedActionParameters[count].required ||
|
|
selectedActionParameters[count].configuration
|
|
? "2px solid #f85a3e"
|
|
: "",
|
|
color: "white",
|
|
width: "100%",
|
|
fontSize: "1em",
|
|
}}
|
|
InputProps={{
|
|
disableUnderline: true,
|
|
endAdornment: hideExtraTypes ? null : (
|
|
<InputAdornment position="end">
|
|
<ButtonGroup orientation={multiline ? "vertical" : "horizontal"}>
|
|
<Tooltip title="Expand window" placement="top">
|
|
<AspectRatioIcon
|
|
style={{ cursor: "pointer", margin: multiline ? 5 : 0 ,}}
|
|
onClick={(event) => {
|
|
event.preventDefault()
|
|
setFieldCount(count)
|
|
setExpansionModalOpen(true)
|
|
|
|
//setcodedata(data.value)
|
|
var parsedvalue = data.value
|
|
if (parsedvalue === undefined || parsedvalue === null) {
|
|
parsedvalue = ""
|
|
}
|
|
|
|
setEditorData({
|
|
"name": data.name,
|
|
"value": parsedvalue,
|
|
"field_number": count,
|
|
"actionlist": actionlist,
|
|
"field_id": clickedFieldId,
|
|
})
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
<Tooltip title="Autocomplete text" placement="bottom">
|
|
<AddCircleOutlineIcon
|
|
style={{ cursor: "pointer", margin: multiline ? 5 : 0, }}
|
|
onClick={(event) => {
|
|
event.preventDefault()
|
|
|
|
// Get cursor position
|
|
// This makes it so we can put it in the right location?
|
|
setMenuPosition({
|
|
top: event.pageY + 10,
|
|
left: event.pageX + 10,
|
|
});
|
|
setShowDropdownNumber(count);
|
|
setShowDropdown(true);
|
|
setShowAutocomplete(true);
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
</ButtonGroup>
|
|
</InputAdornment>
|
|
),
|
|
}}
|
|
multiline={data.name.startsWith("${") && data.name.endsWith("}") ? true : multiline}
|
|
onClick={() => {
|
|
/*
|
|
setExpansionModalOpen(false);
|
|
*/
|
|
|
|
if (setScrollConfig !== undefined && scrollConfig !== null && scrollConfig !== undefined && scrollConfig.selected !== clickedFieldId) {
|
|
|
|
scrollConfig.selected = clickedFieldId
|
|
setScrollConfig(scrollConfig)
|
|
}
|
|
}}
|
|
id={clickedFieldId}
|
|
rows={data.name.startsWith("${") && data.name.endsWith("}") ? 2 : rows}
|
|
color="primary"
|
|
defaultValue={data.value}
|
|
//value={data.value}
|
|
//options={{
|
|
// theme: 'gruvbox-dark',
|
|
// keyMap: 'sublime',
|
|
// mode: 'python',
|
|
//}}
|
|
//height={multiline ? 50 : 150}
|
|
|
|
type={
|
|
placeholder.includes("***") ||
|
|
(data.configuration &&
|
|
(data.name.toLowerCase().includes("api") ||
|
|
data.name.toLowerCase().includes("key") ||
|
|
data.name.toLowerCase().includes("pass")))
|
|
? "password"
|
|
: "text"
|
|
}
|
|
placeholder={placeholder}
|
|
onChange={(event) => {
|
|
//changeActionParameterCodemirror(event, count, data)
|
|
changeActionParameter(event, count, data);
|
|
}}
|
|
helperText={returnHelperText(data.name, data.value)}
|
|
onBlur={(event) => {
|
|
baseHelperText = calculateHelpertext(event.target.value)
|
|
if (setLastSaved !== undefined) {
|
|
setLastSaved(false)
|
|
}
|
|
}}
|
|
/>
|
|
);
|
|
|
|
// Finds headers from a string to be used for autocompletion
|
|
const findHeaders = (inputdata) => {
|
|
var splitdata = inputdata.split("\n")
|
|
|
|
var foundnewline = false
|
|
var allValues = []
|
|
for (let [key,keyval] in Object.entries(splitdata)) {
|
|
const line = splitdata[key]
|
|
if (line === "") {
|
|
foundnewline = true
|
|
continue
|
|
}
|
|
|
|
var splitvalue = ""
|
|
if (line.includes(":")) {
|
|
splitvalue = ":"
|
|
}
|
|
|
|
if (line.includes("=")) {
|
|
splitvalue = "="
|
|
}
|
|
|
|
if (splitvalue.length === 0){
|
|
allValues.push({
|
|
key: line,
|
|
value: "",
|
|
})
|
|
continue
|
|
}
|
|
|
|
var splitKeys = line.split(splitvalue)
|
|
if (splitKeys.length > 1) {
|
|
allValues.push({
|
|
key: splitKeys[0].trim(),
|
|
value: splitKeys[1].trim(),
|
|
})
|
|
} else {
|
|
console.log("No keys for ", line)
|
|
}
|
|
}
|
|
|
|
// Just add one
|
|
if (foundnewline) {
|
|
allValues.push({
|
|
key: "",
|
|
value: "",
|
|
})
|
|
}
|
|
|
|
return allValues
|
|
}
|
|
|
|
if (data.name.toLowerCase() === "headers") {
|
|
//var tmpheaders = findHeaders(data.value)
|
|
var tmpheaders = findHeaders(selectedActionParameters[count].value)
|
|
const tmpdatafield =
|
|
<div>
|
|
{tmpheaders.map((inputdata, index) => {
|
|
const oldkey = inputdata.key
|
|
const oldval = inputdata.value
|
|
|
|
return (
|
|
<span key={index}>
|
|
<div style={{display: "flex"}}>
|
|
<TextField
|
|
placeholder="Key"
|
|
style={{flex: 5}}
|
|
defaultValue={inputdata.key}
|
|
onBlur={(e) => {
|
|
console.log("Change from oldkey to new: ", oldkey, e.target.value)
|
|
|
|
// Find the right line to replace!
|
|
//const newval = selectedActionParameters[count].value.replace(oldval, e.target.value, 1)
|
|
const tmpsplit = selectedActionParameters[count].value.split("\n")
|
|
var valsplit = []
|
|
var add_empty = false
|
|
for (let [key,keyval] in Object.entries(tmpsplit)) {
|
|
if (tmpsplit[key] === "") {
|
|
add_empty = true
|
|
continue
|
|
}
|
|
|
|
valsplit.push(tmpsplit[key])
|
|
}
|
|
|
|
if (add_empty) {
|
|
valsplit.push("")
|
|
}
|
|
console.log("Split: ", valsplit)
|
|
|
|
var newarr = []
|
|
for (let [key,keyval] in Object.entries(valsplit)) {
|
|
var line = valsplit[key]
|
|
|
|
if (key == index) {
|
|
if (oldkey === "") {
|
|
if (line.includes("=") || line.includes(":")) {
|
|
newarr.push(e.target.value + line)
|
|
} else {
|
|
newarr.push(e.target.value + ": " + line)
|
|
}
|
|
} else {
|
|
newarr.push(line.replace(oldkey, e.target.value, 1))
|
|
}
|
|
|
|
} else {
|
|
newarr.push(line)
|
|
}
|
|
}
|
|
|
|
var newval = newarr.join("\n")
|
|
console.log("Fixed: ", newval)
|
|
|
|
selectedActionParameters[count].value = newval
|
|
selectedAction.parameters[count].value = newval
|
|
setSelectedAction(selectedAction)
|
|
setSelectedActionParameters(selectedActionParameters)
|
|
}}
|
|
/>
|
|
<TextField
|
|
placeholder="Value"
|
|
style={{flex: 6}}
|
|
defaultValue={inputdata.value}
|
|
onBlur={(e) => {
|
|
console.log("Change from oldval to new: ", oldval, e.target.value)
|
|
|
|
// Find the right line to replace!
|
|
//const newval = selectedActionParameters[count].value.replace(oldval, e.target.value, 1)
|
|
var tmpsplit = selectedActionParameters[count].value.split("\n")
|
|
var valsplit = []
|
|
var add_empty = false
|
|
for (let [key,keyval] in Object.entries(tmpsplit)) {
|
|
if (tmpsplit[key] === "") {
|
|
add_empty = true
|
|
continue
|
|
}
|
|
|
|
valsplit.push(tmpsplit[key])
|
|
}
|
|
|
|
if (add_empty) {
|
|
valsplit.push("")
|
|
}
|
|
console.log("Split: ", valsplit)
|
|
|
|
var newarr = []
|
|
for (let [key,keyval] in Object.entries(valsplit)) {
|
|
var line = valsplit[key]
|
|
|
|
if (key == index) {
|
|
if (oldval === "") {
|
|
if (line.includes("=") || line.includes(":")) {
|
|
newarr.push(line + e.target.value)
|
|
} else {
|
|
newarr.push(line + ": " + e.target.value)
|
|
}
|
|
} else {
|
|
newarr.push(line.replace(oldval, e.target.value, 1))
|
|
}
|
|
|
|
} else {
|
|
newarr.push(line)
|
|
}
|
|
}
|
|
|
|
var newval = newarr.join("\n")
|
|
console.log("Fixed: ", newval)
|
|
|
|
selectedActionParameters[count].value = newval
|
|
selectedAction.parameters[count].value = newval
|
|
setSelectedAction(selectedAction)
|
|
setSelectedActionParameters(selectedActionParameters)
|
|
}}
|
|
/>
|
|
</div>
|
|
</span>
|
|
)
|
|
})}
|
|
<Button variant="outlined" fullWidth onClick={() => {
|
|
console.log("Add header")
|
|
|
|
selectedActionParameters[count].value += "\n"
|
|
selectedAction.parameters[count].value += "\n"
|
|
setSelectedActionParameters(selectedActionParameters)
|
|
setSelectedAction(selectedAction)
|
|
setUpdate(Math.random())
|
|
}}>
|
|
<AddIcon style={{ marginRight: 10 }} /> Add header
|
|
</Button>
|
|
</div>
|
|
}
|
|
|
|
//console.log("FIELD VALUE: ", data.value)
|
|
//const regexp = new RegExp("\W+\.", "g")
|
|
//let match
|
|
//while ((match = regexp.exec(data.value)) !== null) {
|
|
// console.log(`Found ${match[0]} start=${match.index} end=${regexp.lastIndex}.`);
|
|
//}
|
|
|
|
//const str = = data.value.search(submatch)
|
|
//console.log("FOUND? ", n)
|
|
//for (var key in keywords) {
|
|
// const keyword = keywords[key]
|
|
// if (data.value.includes(keyword)) {
|
|
// console.log("INCLUDED: ", keyword)
|
|
// }
|
|
//}
|
|
|
|
// Basic helpertext
|
|
|
|
if (files !== undefined && files !== null && data.name.toLowerCase() === "file_category") {
|
|
//selectedActionParameters[count].options.length > 0
|
|
console.log("FileS: ", files)
|
|
if (files.namespaces !== undefined && files.namespaces !== null && files.namespaces.length > 0) {
|
|
data.options = files.namespaces
|
|
}
|
|
}
|
|
|
|
//const keywords = ["len", "lower", "upper", "trim", "split", "length", "number", "parse", "join"]
|
|
if (
|
|
selectedActionParameters[count].schema !== undefined &&
|
|
selectedActionParameters[count].schema !== null &&
|
|
selectedActionParameters[count].schema.type === "file"
|
|
) {
|
|
datafield = (
|
|
<TextField
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
InputProps={{
|
|
endAdornment: hideExtraTypes ? null : (
|
|
<InputAdornment position="end">
|
|
<Tooltip title="Autocomplete text" placement="top">
|
|
<AddCircleOutlineIcon
|
|
style={{ cursor: "pointer" }}
|
|
onClick={(event) => {
|
|
setMenuPosition({
|
|
top: event.pageY + 10,
|
|
left: event.pageX + 10,
|
|
});
|
|
setShowDropdownNumber(count);
|
|
setShowDropdown(true);
|
|
setShowAutocomplete(true);
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
</InputAdornment>
|
|
),
|
|
}}
|
|
helperText={returnHelperText(data.name, data.value)}
|
|
fullWidth
|
|
multiline={multiline}
|
|
rows={"3"}
|
|
color="primary"
|
|
defaultValue={data.value}
|
|
type={"text"}
|
|
placeholder={"The file ID to get"}
|
|
id={"rightside_field_" + count}
|
|
onChange={(event) => {
|
|
changeActionParameter(event, count, data);
|
|
}}
|
|
onBlur={(event) => {}}
|
|
/>
|
|
);
|
|
//const fileId = "6daabec1-892b-469c-b603-c902e47223a9"
|
|
//datafield = `SHOW FILES FROM OTHER NODES? Filename: ${selectedActionParameters[count].value}`
|
|
/*
|
|
if (selectedActionParameters[count].value != fileId) {
|
|
changeActionParameter(fileId, count, data)
|
|
setUpdate(Math.random())
|
|
|
|
}
|
|
*/
|
|
} else if (
|
|
(data.options !== undefined &&
|
|
data.options !== null &&
|
|
data.options.length > 0)
|
|
||
|
|
(selectedActionParameters[count].options !== undefined &&
|
|
selectedActionParameters[count].options !== null &&
|
|
selectedActionParameters[count].options.length > 0)
|
|
) {
|
|
const parsedoptions = data.options !== undefined && data.options !== null && data.options.length > 0 ? data.options : selectedActionParameters[count].options
|
|
|
|
if (selectedActionParameters[count].value === "") {
|
|
// && selectedActionParameters[count].required) {
|
|
// Rofl, dirty workaround :)
|
|
const e = {
|
|
target: {
|
|
value: parsedoptions[0],
|
|
},
|
|
};
|
|
|
|
changeActionParameter(e, count, data);
|
|
}
|
|
|
|
var multi = false
|
|
if (selectedActionParameters[count].multiselect !== undefined && selectedActionParameters[count].multiselect !== null && selectedActionParameters[count].multiselect === true) {
|
|
multi = true
|
|
|
|
selectedActionParameters[count].value = selectedActionParameters[count].value.split(",")
|
|
}
|
|
|
|
datafield = (
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
SelectDisplayProps={{
|
|
style: {
|
|
},
|
|
}}
|
|
multiple={multi}
|
|
value={selectedActionParameters[count].value}
|
|
fullWidth
|
|
id={"rightside_field_" + count}
|
|
onChange={(e) => {
|
|
console.log("MULTI SELECT: ", multi, e.target.value)
|
|
|
|
changeActionParameter(e, count, data);
|
|
setUpdate(Math.random());
|
|
}}
|
|
style={{
|
|
backgroundColor: theme.palette.surfaceColor,
|
|
color: "white",
|
|
height: "50px",
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
>
|
|
{parsedoptions.map(
|
|
(data, index) => {
|
|
const split_data = data.split("||");
|
|
var viewed_data = data
|
|
if (split_data.length > 1) {
|
|
viewed_data = split_data[0]
|
|
}
|
|
|
|
viewed_data = (viewed_data.charAt(0).toUpperCase() + viewed_data.slice(1)).replaceAll("_", " ")
|
|
|
|
return (
|
|
<MenuItem
|
|
key={data}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value={data}
|
|
>
|
|
{viewed_data}
|
|
</MenuItem>
|
|
);
|
|
}
|
|
)}
|
|
</Select>
|
|
);
|
|
} else if (data.variant === "STATIC_VALUE") {
|
|
staticcolor = "#f85a3e";
|
|
}
|
|
|
|
if (data.field_active === false) {
|
|
return 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) => {
|
|
console.log("In normal itemclick")
|
|
if (values === undefined ||values === null ||values.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var toComplete = selectedActionParameters[count].value.trim()
|
|
.endsWith("$")
|
|
? values[0].autocomplete
|
|
: "$" + values[0].autocomplete;
|
|
|
|
toComplete = toComplete.toLowerCase().replaceAll(" ", "_");
|
|
for (let [key,keyval] in Object.entries(values)) {
|
|
if (key == 0 || values[key].autocomplete.length === 0) {
|
|
continue;
|
|
}
|
|
|
|
toComplete += values[key].autocomplete;
|
|
}
|
|
|
|
|
|
|
|
// Handles the fields under OpenAPI body to be parsed.
|
|
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
|
console.log("INSIDE VALUE REPLACE: ", data.name, toComplete);
|
|
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
|
const paramcheck = selectedAction.parameters.find(
|
|
(param) => param.name === "body"
|
|
);
|
|
if (paramcheck !== undefined) {
|
|
if (
|
|
paramcheck["value_replace"] === undefined ||
|
|
paramcheck["value_replace"] === null
|
|
) {
|
|
paramcheck["value_replace"] = [
|
|
{
|
|
key: data.name,
|
|
value: toComplete,
|
|
},
|
|
];
|
|
} else {
|
|
const subparamindex = paramcheck[
|
|
"value_replace"
|
|
].findIndex((param) => param.key === data.name);
|
|
if (subparamindex === -1) {
|
|
paramcheck["value_replace"].push({
|
|
key: data.name,
|
|
value: toComplete,
|
|
});
|
|
} else {
|
|
paramcheck["value_replace"][subparamindex]["value"] +=
|
|
toComplete;
|
|
}
|
|
}
|
|
|
|
selectedActionParameters[count]["value_replace"] = paramcheck;
|
|
selectedAction.parameters[count]["value_replace"] = paramcheck;
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
|
|
setShowDropdown(false);
|
|
setMenuPosition(null);
|
|
return;
|
|
}
|
|
}
|
|
|
|
console.log("In nestedclick!!")
|
|
var newValue = selectedActionParameters[count].value + toComplete
|
|
changeActionParameter({target: {value: newValue}}, count, data, true)
|
|
//selectedActionParameters[count].value += toComplete;
|
|
//selectedAction.parameters[count].value = selectedActionParameters[count].value;
|
|
//setSelectedAction(selectedAction);
|
|
//setUpdate(Math.random());
|
|
|
|
setShowDropdown(false);
|
|
setMenuPosition(null);
|
|
};
|
|
|
|
const iconStyle = {
|
|
marginRight: 15,
|
|
};
|
|
|
|
return (
|
|
<Menu
|
|
anchorReference="anchorPosition"
|
|
anchorPosition={menuPosition}
|
|
onClose={() => {
|
|
handleMenuClose();
|
|
}}
|
|
open={!!menuPosition}
|
|
style={{
|
|
color: "white",
|
|
marginTop: 2,
|
|
maxHeight: 650,
|
|
}}
|
|
>
|
|
{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 (let [key,keyval] in Object.entries(workflow.triggers)) {
|
|
const item = workflow.triggers[key];
|
|
|
|
if (cy !== undefined) {
|
|
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) => {
|
|
if (cy !== undefined) {
|
|
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, "");
|
|
}
|
|
|
|
const coverColor = "#82ccc3"
|
|
//menuPosition.left -= 50
|
|
//menuPosition.top -= 250
|
|
//console.log("POS: ", menuPosition1)
|
|
var menuPosition1 = menuPosition
|
|
if (menuPosition1 === null) {
|
|
menuPosition1 = {
|
|
"left": 0,
|
|
"top": 0,
|
|
}
|
|
} else if (menuPosition1.top === null || menuPosition1.top === undefined) {
|
|
menuPosition1.top = 0
|
|
} else if (menuPosition1.left === null || menuPosition1.left === undefined) {
|
|
menuPosition1.left = 0
|
|
}
|
|
|
|
//console.log("POS1: ", menuPosition1)
|
|
|
|
return parsedPaths.length > 0 ? (
|
|
<NestedMenuItem
|
|
key={innerdata.name}
|
|
label={
|
|
<div style={{ display: "flex", marginLeft: 0, }}>
|
|
{icon} {innerdata.name}
|
|
</div>
|
|
}
|
|
parentMenuOpen={!!menuPosition}
|
|
style={{
|
|
color: "white",
|
|
minWidth: 250,
|
|
maxWidth: 250,
|
|
maxHeight: 50,
|
|
overflow: "hidden",
|
|
}}
|
|
onClick={() => {
|
|
console.log("CLICKED: ", innerdata);
|
|
console.log(innerdata.example)
|
|
handleItemClick([innerdata]);
|
|
}}
|
|
>
|
|
<Paper style={{minHeight: 500, maxHeight: 500, minWidth: 275, maxWidth: 275, position: "fixed", top: menuPosition1.top-200, left: menuPosition1.left-450, padding: "10px 0px 10px 10px", overflow: "hidden", overflowY: "auto", border: "1px solid rgba(255,255,255,0.3)",}}>
|
|
<MenuItem
|
|
key={innerdata.name}
|
|
style={{
|
|
marginLeft: 15,
|
|
color: "white",
|
|
minWidth: 250,
|
|
maxWidth: 250,
|
|
padding: 0,
|
|
position: "relative",
|
|
}}
|
|
value={innerdata}
|
|
onMouseOver={() => {
|
|
//console.log("HOVER: ", pathdata);
|
|
}}
|
|
onClick={() => {
|
|
handleItemClick([innerdata]);
|
|
}}
|
|
>
|
|
<Typography variant="h6" style={{paddingBottom: 5}}>
|
|
{innerdata.name}
|
|
</Typography>
|
|
</MenuItem>
|
|
{parsedPaths.map((pathdata, index) => {
|
|
// FIXME: Should be recursive in here
|
|
//<VpnKeyIcon style={iconStyle} />
|
|
const icon =
|
|
pathdata.type === "value" ? (
|
|
<span style={{marginLeft: 9, }} />
|
|
) : pathdata.type === "list" ? (
|
|
<FormatListNumberedIcon style={{marginLeft: 9, marginRight: 10, }} />
|
|
) : (
|
|
<CircleIcon style={{marginLeft: 9, marginRight: 10, color: coverColor}}/>
|
|
);
|
|
//<ExpandMoreIcon style={iconStyle} />
|
|
|
|
const indentation_count = (pathdata.name.match(/\./g) || []).length+1
|
|
const baseIndent = <div style={{marginLeft: 20, height: 30, width: 1, backgroundColor: coverColor,}} />
|
|
//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 (
|
|
<MenuItem
|
|
key={pathdata.name}
|
|
style={{
|
|
color: "white",
|
|
minWidth: 250,
|
|
maxWidth: 250,
|
|
padding: boxPadding,
|
|
}}
|
|
value={pathdata}
|
|
onMouseOver={() => {
|
|
//console.log("HOVER: ", pathdata);
|
|
}}
|
|
onClick={() => {
|
|
handleItemClick([innerdata, pathdata]);
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title={`Ex. value: ${pathdata.value}`}
|
|
placement="left"
|
|
>
|
|
<div style={{ display: "flex", height: 30, }}>
|
|
{Array(indentation_count).fill().map((subdata, subindex) => {
|
|
return (
|
|
baseIndent
|
|
)
|
|
})}
|
|
{icon} {newname}
|
|
{pathdata.type === "list" ? <SquareFootIcon style={{marginleft: 10, }} onClick={(e) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
console.log("INNER: ", innerdata, pathdata)
|
|
|
|
// Removing .list from autocomplete
|
|
var newname = pathdata.name
|
|
if (newname.length > 5) {
|
|
newname = newname.slice(0, newname.length-5)
|
|
}
|
|
|
|
selectedActionParameters[count].value += `{{ $${innerdata.name}.${newname} | size }}`
|
|
selectedAction.parameters[count].value = selectedActionParameters[count].value;
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
setShowDropdown(false);
|
|
setMenuPosition(null);
|
|
}} /> : null}
|
|
</div>
|
|
</Tooltip>
|
|
</MenuItem>
|
|
);
|
|
})}
|
|
</Paper>
|
|
</NestedMenuItem>
|
|
) : (
|
|
<MenuItem
|
|
key={innerdata.name}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
minWidth: 250,
|
|
maxWidth: 250,
|
|
marginRight: 0,
|
|
}}
|
|
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>
|
|
);
|
|
};
|
|
|
|
const description =
|
|
data.description === undefined ? "" : data.description;
|
|
const tooltipDescription = (
|
|
<span>
|
|
<Typography variant="body2">
|
|
- Required:{" "}
|
|
{data.required === true || data.configuration === true
|
|
? "True"
|
|
: "False"}
|
|
</Typography>
|
|
<Typography variant="body2">
|
|
- Example: {data.example}
|
|
</Typography>
|
|
<Typography variant="body2">
|
|
- Description: {description}
|
|
</Typography>
|
|
</span>
|
|
);
|
|
|
|
//var itemColor = "#f85a3e"
|
|
//if (!data.required) {
|
|
// itemColor = "#ffeb3b"
|
|
//}
|
|
{
|
|
/*<div style={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10, marginTop: 2, marginTop: "auto", marginBottom: "auto",}}/>*/
|
|
}
|
|
|
|
const buttonTitle = `Authenticate ${selectedApp.name.replaceAll("_", " ")}`
|
|
const hasAutocomplete = data.autocompleted === true
|
|
return (
|
|
<div key={data.name}>
|
|
{hideBodyButton}
|
|
<div
|
|
style={{ marginTop: 20, marginBottom: 0, display: "flex" }}
|
|
>
|
|
{data.configuration === true ? (
|
|
<Tooltip
|
|
title={buttonTitle}
|
|
placement="top"
|
|
>
|
|
<LockOpenIcon
|
|
style={{
|
|
cursor: "pointer",
|
|
width: 24,
|
|
height: 24,
|
|
marginRight: 10,
|
|
color: "rgba(255,255,255,0.6)",
|
|
}}
|
|
onClick={() => {
|
|
setAuthenticationModalOpen(true);
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
) : null}
|
|
|
|
{hasAutocomplete === true ?
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Field was autocompleted by Shuffle based on previous actions (same fields or parent nodes)"}
|
|
placement="top"
|
|
>
|
|
<AutoFixHighIcon style={{
|
|
color: "rgba(255,255,255,0.7)" ,
|
|
marginRight: 10,
|
|
}}/>
|
|
</Tooltip>
|
|
:
|
|
null}
|
|
|
|
{showCacheConfig === true ?
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Explore your keys in Datastore"}
|
|
placement="top"
|
|
>
|
|
<a href="/admin?tab=cache" target="_blank" style={{textDecoration: "none"}}>
|
|
<StorageIcon style={{
|
|
color: "#f85a3e",
|
|
marginRight: 10,
|
|
}}/>
|
|
</a>
|
|
</Tooltip>
|
|
: null}
|
|
|
|
<div
|
|
style={{
|
|
flex: "10",
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
}}
|
|
>
|
|
<Tooltip title={tooltipDescription} placement="top">
|
|
<b>{tmpitem} </b>
|
|
</Tooltip>
|
|
</div>
|
|
|
|
{/*selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0 ? null :
|
|
<div style={{display: "flex"}}>
|
|
<Tooltip color="primary" title="Static data" placement="top">
|
|
<div style={{cursor: "pointer", color: staticcolor}} onClick={(e) => {
|
|
e.preventDefault()
|
|
changeActionParameterVariant("STATIC_VALUE", count)
|
|
}}>
|
|
<CreateIcon />
|
|
</div>
|
|
</Tooltip>
|
|
|
|
|
<Tooltip color="primary" title="Data from previous action" placement="top">
|
|
<div style={{cursor: "pointer", color: actioncolor}} onClick={(e) => {
|
|
e.preventDefault()
|
|
changeActionParameterVariant("ACTION_RESULT", count)
|
|
}}>
|
|
<AppsIcon />
|
|
</div>
|
|
</Tooltip>
|
|
|
|
|
<Tooltip color="primary" title="Use local variable" placement="top">
|
|
<div style={{cursor: "pointer", color: varcolor}} onClick={(e) => {
|
|
e.preventDefault()
|
|
changeActionParameterVariant("WORKFLOW_VARIABLE", count)
|
|
}}>
|
|
<FavoriteBorderIcon />
|
|
</div>
|
|
</Tooltip>
|
|
</div>
|
|
*/}
|
|
{/*(selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0 && selectedActionParameters[count].required === true && selectedActionParameters[count].unique_toggled !== undefined) || hideExtraTypes ? null :
|
|
<div style={{display: "flex"}}>
|
|
<Tooltip color="secondary" title="Value must be unique" placement="top">
|
|
<div style={{cursor: "pointer", color: staticcolor}} onClick={(e) => {}}>
|
|
<Checkbox
|
|
tabIndex="-1"
|
|
checked={selectedActionParameters[count].unique_toggled}
|
|
style={{
|
|
color: theme.palette.primary.secondary,
|
|
}}
|
|
onChange={(event) => {
|
|
//console.log("CHECKED!: ", selectedActionParameters[count])
|
|
selectedActionParameters[count].unique_toggled = !selectedActionParameters[count].unique_toggled
|
|
selectedAction.parameters[count].unique_toggled = selectedActionParameters[count].unique_toggled
|
|
setSelectedActionParameters(selectedActionParameters)
|
|
setSelectedAction(selectedAction)
|
|
setUpdate(Math.random())
|
|
}}
|
|
name="requires_unique"
|
|
/>
|
|
</div>
|
|
</Tooltip>
|
|
</div>
|
|
*/}
|
|
</div>
|
|
{datafield}
|
|
{/*shufflecode*/}
|
|
{showDropdown &&
|
|
showDropdownNumber === count &&
|
|
data.variant === "STATIC_VALUE" &&
|
|
jsonList.length > 0 ? (
|
|
<FormControl fullWidth style={{ marginTop: 0 }}>
|
|
<InputLabel
|
|
id="action-autocompleter"
|
|
style={{ marginLeft: 10, color: "white" }}
|
|
>
|
|
Autocomplete
|
|
</InputLabel>
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
labelId="action-autocompleter"
|
|
SelectDisplayProps={{
|
|
style: {
|
|
},
|
|
}}
|
|
onClose={() => {
|
|
setShowAutocomplete(false);
|
|
|
|
if (
|
|
!selectedActionParameters[count].value[
|
|
selectedActionParameters[count].value.length - 1
|
|
] === "."
|
|
) {
|
|
setShowDropdown(false);
|
|
}
|
|
|
|
setUpdate(Math.random());
|
|
}}
|
|
onClick={() => {
|
|
setShowAutocomplete(true)
|
|
}}
|
|
fullWidth
|
|
open={showAutocomplete}
|
|
style={{
|
|
color: "white",
|
|
height: 50,
|
|
marginTop: 2,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
onChange={(e) => {
|
|
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;
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
|
|
setShowDropdown(false);
|
|
}}
|
|
>
|
|
{jsonList.map((data) => {
|
|
const iconStyle = {
|
|
marginRight: 15,
|
|
};
|
|
|
|
const icon =
|
|
data.type === "value" ? (
|
|
<VpnKeyIcon style={iconStyle} />
|
|
) : data.type === "list" ? (
|
|
<FormatListNumberedIcon style={iconStyle} />
|
|
) : (
|
|
<ExpandMoreIcon style={iconStyle} />
|
|
)
|
|
|
|
return (
|
|
<MenuItem
|
|
key={data.name}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value={data}
|
|
onMouseOver={() => {}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title={`Ex. value: ${data.value}`}
|
|
placement="left"
|
|
>
|
|
<div style={{ display: "flex" }}>
|
|
{icon} {data.name}
|
|
</div>
|
|
</Tooltip>
|
|
</MenuItem>
|
|
);
|
|
})}
|
|
</Select>
|
|
</FormControl>
|
|
) : null}
|
|
{showDropdown &&
|
|
showDropdownNumber === count &&
|
|
data.variant === "STATIC_VALUE" &&
|
|
jsonList.length === 0 ? (
|
|
<ActionlistWrapper actionlist={actionlist} />
|
|
) : null}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
|
|
const ActionSelectOption = (actionprops) => {
|
|
const { data, newActionname, newActiondescription, useIcon, extraDescription, } = actionprops;
|
|
const [hover, setHover] = React.useState(false);
|
|
|
|
return (
|
|
<Tooltip
|
|
color="secondary"
|
|
title={newActiondescription}
|
|
placement="left"
|
|
>
|
|
<div style={{
|
|
cursor: "pointer",
|
|
padding: 8,
|
|
paddingLeft: 14,
|
|
paddingBottom: 4,
|
|
backgroundColor: hover ? theme.palette.surfaceColor : theme.palette.inputColor,
|
|
}} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
|
|
onClick={() => {
|
|
//setSelectedAction(actionprops)
|
|
//setShowActionList(false)
|
|
//setUpdate(Math.random())
|
|
//
|
|
if (data !== undefined && data !== null) {
|
|
setNewSelectedAction({
|
|
target: {
|
|
value: data.name
|
|
}
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
<div style={{ display: "flex", marginBottom: 0,}}>
|
|
<span
|
|
style={{
|
|
marginRight: 10,
|
|
marginTop: "auto",
|
|
marginBottom: 0,
|
|
}}
|
|
>
|
|
{useIcon}
|
|
</span>
|
|
<span style={{marginBottom: 0, marginTop: 3, }}>{newActionname}</span>
|
|
</div>
|
|
{extraDescription.length > 0 ?
|
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 0, overflow: "hidden", whiteSpace: "nowrap", display: "block",}}>
|
|
{extraDescription}
|
|
</Typography>
|
|
: null}
|
|
</div>
|
|
</Tooltip>
|
|
)
|
|
}
|
|
|
|
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 (
|
|
<div style={appApiViewStyle} id="parsed_action_view">
|
|
|
|
{hideExtraTypes === true ? null : (
|
|
<span>
|
|
<div style={{ display: "flex", minHeight: 40, marginBottom: 30 }}>
|
|
<div style={{ flex: 1 }}>
|
|
<div style={{ display: "flex", }}
|
|
onClick={() => {
|
|
//window.open("/apps/${selectedAction.app_id}", "_blank")
|
|
}}
|
|
>
|
|
<Tooltip title={"App: "+selectedAction.app_name} placement="top">
|
|
<img src={selectedAppIcon} style={{
|
|
width: 30,
|
|
height: 30,
|
|
marginRight: 10,
|
|
borderRadius: 5,
|
|
marginTop: 13,
|
|
border: "2px solid rgba(255,255,255,0.3)",
|
|
}} />
|
|
</Tooltip>
|
|
<h3 style={{ }}>
|
|
{(
|
|
selectedAction.app_name.charAt(0).toUpperCase() +
|
|
selectedAction.app_name.substring(1)
|
|
).replaceAll("_", " ")}
|
|
</h3>
|
|
</div>
|
|
<div style={{display: "flex", marginTop: 0, }}>
|
|
<IconButton
|
|
style={{
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
height: 30,
|
|
paddingLeft: 0,
|
|
paddingRight: 0,
|
|
}}
|
|
onClick={() => {
|
|
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.")
|
|
}
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title="See previous results for this action"
|
|
placement="top"
|
|
>
|
|
<ArrowLeftIcon style={{ color: "rgba(255,255,255,0.7)" }} />
|
|
</Tooltip>
|
|
</IconButton>
|
|
<IconButton
|
|
style={{
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
height: 30,
|
|
marginLeft: 15,
|
|
paddingRight: 0,
|
|
}}
|
|
onClick={() => {
|
|
setAuthenticationModalOpen(true)
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title="Find app documentation"
|
|
placement="top"
|
|
>
|
|
<DescriptionIcon style={{ color: "rgba(255,255,255,0.7)" }} />
|
|
</Tooltip>
|
|
</IconButton>
|
|
{/*
|
|
<IconButton
|
|
style={{
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
height: 30,
|
|
marginLeft: 15,
|
|
paddingRight: 0,
|
|
}}
|
|
onClick={() => {}}
|
|
>
|
|
<a
|
|
href="https://shuffler.io/docs/workflows#nodes"
|
|
rel="norefferer"
|
|
target="_blank"
|
|
style={{ textDecoration: "none", color: "#f85a3e" }}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title="What are actions?"
|
|
placement="top"
|
|
>
|
|
<HelpOutlineIcon style={{ color: "rgba(255,255,255,0.7)" }} />
|
|
</Tooltip>
|
|
</a>
|
|
</IconButton>
|
|
*/}
|
|
{/*
|
|
<IconButton
|
|
style={{
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
height: 30,
|
|
marginLeft: 15,
|
|
paddingRight: 0,
|
|
}}
|
|
onClick={() => {
|
|
//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());
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title={selectedAction.run_magic_output === undefined || selectedAction.run_magic_output === null || selectedAction.run_magic_output === false ? "Click to enable magic parsing" : "Click to disable magic parsing"}
|
|
placement="top"
|
|
>
|
|
<AutoFixHighIcon style={{ color: selectedAction.run_magic_output === undefined || selectedAction.run_magic_output === null || selectedAction.run_magic_output === false ? "rgba(255,255,255,0.7)" : "#f86a3e"}} />
|
|
</Tooltip>
|
|
</IconButton>
|
|
*/}
|
|
{/*
|
|
<IconButton
|
|
style={{
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
height: 30,
|
|
marginLeft: 15,
|
|
paddingRight: 0,
|
|
}}
|
|
onClick={() => {
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Find related tworkflows"}
|
|
placement="top"
|
|
>
|
|
<a href={`https://shuffler.io/search?tab=workflows&q=${selectedAction.app_name}`} target="_blank">
|
|
<SearchIcon style={{ color: "rgba(255,255,255,0.7)"}} />
|
|
</a>
|
|
</Tooltip>
|
|
</IconButton>
|
|
*/}
|
|
<IconButton
|
|
style={{
|
|
marginTop: "auto",
|
|
marginBottom: "auto",
|
|
height: 30,
|
|
marginLeft: 15,
|
|
paddingRight: 0,
|
|
}}
|
|
disabled={autoCompleting}
|
|
onClick={() => {
|
|
//if (setAiQueryModalOpen !== undefined) {
|
|
// setAiQueryModalOpen(true)
|
|
//} else {
|
|
aiSubmit("Fill based on previous values", undefined, undefined, selectedAction)
|
|
//}
|
|
setAutocompleting(true)
|
|
}}
|
|
>
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Autocomplete fields. Uses the name of the current action, the fields and previous actions' results"}
|
|
placement="top"
|
|
>
|
|
{autoCompleting ?
|
|
<CircularProgress style={{height: 20, width: 20, }} />
|
|
:
|
|
<AutoFixHighIcon style={{ color: "rgba(255,255,255,0.7)", height: 24, }} />
|
|
}
|
|
</Tooltip>
|
|
</IconButton>
|
|
</div>
|
|
</div>
|
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
|
{/*selectedAction.id === workflow.start ? null :
|
|
|
|
<Tooltip color="primary" title={"Make this node the start action"} placement="top">
|
|
<Button style={{zIndex: 5000, marginTop: 10,}} color="primary" variant="outlined" onClick={(e) => {
|
|
defineStartnode(e)
|
|
}}>
|
|
<KeyboardArrowRightIcon />
|
|
</Button>
|
|
</Tooltip>
|
|
*/}
|
|
{selectedApp.versions !== null &&
|
|
selectedApp.versions !== undefined &&
|
|
selectedApp.versions.length > 1 ? (
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
defaultValue={selectedAction.app_version}
|
|
onChange={(event) => {
|
|
const newversion = selectedApp.versions.find(
|
|
(tmpApp) => tmpApp.version == event.target.value
|
|
)
|
|
|
|
if (newversion !== undefined && newversion !== null) {
|
|
getApp(newversion.id, true)
|
|
}
|
|
|
|
// Change in all actions in the workflow at the same time and add a toast.success() about it
|
|
for (var actionkey in workflow.actions) {
|
|
const action = workflow.actions[actionkey]
|
|
if (action.app_name === selectedAction.app_name) {
|
|
workflow.actions[actionkey].app_version = event.target.value
|
|
}
|
|
}
|
|
|
|
toast.success("Changed version of all nodes to "+event.target.value)
|
|
}}
|
|
style={{
|
|
marginTop: 10,
|
|
backgroundColor: theme.palette.surfaceColor,
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
height: 35,
|
|
marginleft: 10,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
SelectDisplayProps={{
|
|
style: {
|
|
},
|
|
}}
|
|
>
|
|
{selectedApp.versions.map((data, index) => {
|
|
return (
|
|
<MenuItem
|
|
key={index}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value={data.version}
|
|
>
|
|
{data.version}
|
|
</MenuItem>
|
|
);
|
|
})}
|
|
</Select>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
<div style={{display: "flex"}}>
|
|
<div style={{flex: 5}}>
|
|
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Name</Typography>
|
|
<TextField
|
|
|
|
style={theme.palette.textFieldStyle}
|
|
InputProps={{
|
|
style: theme.palette.innerTextfieldStyle,
|
|
disableUnderline: true,
|
|
}}
|
|
fullWidth
|
|
color="primary"
|
|
placeholder={selectedAction.label}
|
|
defaultValue={selectedAction.label}
|
|
onChange={selectedNameChange}
|
|
onBlur={(e) => {
|
|
// 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
|
|
}}
|
|
/>
|
|
</div>
|
|
{/*!isCloud ? null :*/}
|
|
<div style={{flex: 1, marginLeft: 5,}}>
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Delay before action executes (in seconds)"}
|
|
placement="top"
|
|
>
|
|
<span>
|
|
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Delay</Typography>
|
|
<TextField
|
|
InputProps={{
|
|
style: theme.palette.innerTextfieldStyle,
|
|
disableUnderline: true,
|
|
}}
|
|
placeholder={selectedAction.execution_delay}
|
|
defaultValue={selectedAction.execution_delay}
|
|
onChange={(event) => {
|
|
if (actionDelayChange !== undefined) {
|
|
actionDelayChange(event)
|
|
}
|
|
}}
|
|
/>
|
|
</span>
|
|
</Tooltip>
|
|
</div>
|
|
{/**/}
|
|
</div>
|
|
</span>
|
|
)}
|
|
{selectedApp.name !== undefined &&
|
|
selectedAction.authentication !== null &&
|
|
selectedAction.authentication !== undefined &&
|
|
selectedAction.authentication.length === 0 &&
|
|
requiresAuthentication ? (
|
|
<div style={{ marginTop: 15 }}>
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Add authentication option"}
|
|
placement="top"
|
|
>
|
|
<span>
|
|
<Button
|
|
color="primary"
|
|
style={{}}
|
|
fullWidth
|
|
variant="contained"
|
|
onClick={() => {
|
|
//if (authenticationType.type === "oauth2" && authenticationType.redirect_uri !== undefined && authenticationType.redirect_uri !== null) {
|
|
// return null
|
|
//}
|
|
|
|
setAuthenticationModalOpen(true);
|
|
}}
|
|
>
|
|
<AddIcon style={{ marginRight: 10 }} /> Authenticate{" "}
|
|
{selectedApp.name.replaceAll("_", " ")}
|
|
</Button>
|
|
</span>
|
|
</Tooltip>
|
|
</div>
|
|
) : null}
|
|
|
|
{selectedAction.authentication !== undefined &&
|
|
selectedAction.authentication !== null &&
|
|
selectedAction.authentication.length > 0 ? (
|
|
<div style={{ marginTop: 15 }}>
|
|
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Authentication</Typography>
|
|
<div style={{ display: "flex" }}>
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
labelId="select-app-auth"
|
|
value={
|
|
selectedAction.authentication_id === "authgroups" ? "authgroups" :
|
|
Object.getOwnPropertyNames(selectedAction.selectedAuthentication).length === 0
|
|
? "No selection"
|
|
: selectedAction.selectedAuthentication
|
|
}
|
|
SelectDisplayProps={{
|
|
style: {
|
|
maxWidth: 250,
|
|
},
|
|
}}
|
|
fullWidth
|
|
onChange={(e) => {
|
|
console.log("AUTH CHANGE: ", e.target.value)
|
|
|
|
if (e.target.value === "No selection") {
|
|
selectedAction.selectedAuthentication = {};
|
|
selectedAction.authentication_id = "";
|
|
|
|
for (let [key,keyval] in Object.entries(selectedAction.parameters)) {
|
|
//console.log(selectedAction.parameters[key])
|
|
if (selectedAction.parameters[key].configuration) {
|
|
selectedAction.parameters[key].value = "";
|
|
}
|
|
}
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random())
|
|
|
|
} else if (e.target.value === "authgroups") {
|
|
if (authGroups !== undefined && authGroups !== null && authGroups.length === 0) {
|
|
toast("No auth groups created. Opening window to create one")
|
|
|
|
setTimeout(() => {
|
|
window.open("/admin?tab=app_auth", "_blank")
|
|
}, 2500)
|
|
} else {
|
|
selectedAction.selectedAuthentication = {};
|
|
selectedAction.authentication_id = "authgroups"
|
|
|
|
for (let [key,keyval] in Object.entries(selectedAction.parameters)) {
|
|
//console.log(selectedAction.parameters[key])
|
|
if (selectedAction.parameters[key].configuration) {
|
|
selectedAction.parameters[key].value = "authgroup controlled"
|
|
}
|
|
}
|
|
|
|
setSelectedAction(selectedAction)
|
|
setUpdate(Math.random())
|
|
}
|
|
} else {
|
|
selectedAction.selectedAuthentication = e.target.value;
|
|
selectedAction.authentication_id = e.target.value.id;
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
}
|
|
|
|
}}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
height: 50,
|
|
maxWidth: rightsidebarStyle.maxWidth - 80,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
>
|
|
<MenuItem
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value="No selection"
|
|
>
|
|
<em>No selection</em>
|
|
</MenuItem>
|
|
|
|
{selectedAction.authentication.map((data) => {
|
|
if (data.last_modified === true) {
|
|
//console.log("LAST MODIFIED: ", data.label)
|
|
}
|
|
|
|
return (
|
|
<MenuItem
|
|
key={data.id}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
maxWidth: 500,
|
|
overflowX: "auto",
|
|
}}
|
|
value={data}
|
|
>
|
|
{data.last_modified === true ?
|
|
<Chip
|
|
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
|
label={"Latest"}
|
|
variant="outlined"
|
|
color="secondary"
|
|
/>
|
|
: null}
|
|
{data.app.app_version !== undefined && data.app.app_version !== null && data.app.app_version !== "" && data.app.app_version !== "undefined" ?
|
|
<Chip
|
|
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
|
label={data.app.app_version}
|
|
variant="outlined"
|
|
color="secondary"
|
|
/>
|
|
: null}
|
|
{data.label}
|
|
</MenuItem>
|
|
);
|
|
})}
|
|
|
|
|
|
<Divider style={{marginTop: 10, marginBottom: 10, }}/>
|
|
|
|
<MenuItem
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value="authgroups"
|
|
>
|
|
<em>Auth Groups</em>
|
|
</MenuItem>
|
|
|
|
</Select>
|
|
|
|
{/*
|
|
|
|
<Button fullWidth style={{margin: "auto", marginTop: "10px",}} color="primary" variant="contained" onClick={() => setAuthenticationModalOpen(true)}>
|
|
AUTHENTICATE
|
|
</Button>
|
|
curaction.authentication = authenticationOptions
|
|
if (curaction.selectedAuthentication === null || curaction.selectedAuthentication === undefined || curaction.selectedAuthentication.length === "")
|
|
*/}
|
|
<Tooltip
|
|
color="primary"
|
|
title={"Add authentication option"}
|
|
placement="top"
|
|
>
|
|
<IconButton
|
|
color="primary"
|
|
variant="outlined"
|
|
style={{}}
|
|
onClick={() => {
|
|
setAuthenticationModalOpen(true);
|
|
}}
|
|
>
|
|
<AddIcon />
|
|
</IconButton>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
|
|
|
|
{showEnvironment !== undefined && showEnvironment && environments.length > 1 && !isIntegration ? (
|
|
<div style={{ marginTop: "20px" }}>
|
|
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Environment</Typography>
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
value={
|
|
selectedActionEnvironment === undefined || selectedActionEnvironment === null || selectedActionEnvironment.Name === undefined || selectedActionEnvironment.Name === null
|
|
?
|
|
selectedAction.environment !== undefined && selectedAction.environment !== null && selectedAction.environment.length > 0 ? selectedAction.environment : isCloud ? "Cloud" : "Shuffle"
|
|
: selectedActionEnvironment.Name
|
|
}
|
|
SelectDisplayProps={{
|
|
style: {
|
|
},
|
|
}}
|
|
fullWidth
|
|
onChange={(e) => {
|
|
const env = environments.find((a) => a.Name === e.target.value);
|
|
setSelectedActionEnvironment(env);
|
|
selectedAction.environment = env.Name;
|
|
setSelectedAction(selectedAction);
|
|
|
|
for (let actionkey in workflow.actions) {
|
|
workflow.actions[actionkey].environment = env.Name
|
|
}
|
|
setWorkflow(workflow)
|
|
toast("Set environment for ALL actions to " + env.Name)
|
|
}}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
height: "50px",
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
>
|
|
{environments.map((data, index) => {
|
|
if (data.archived === true) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<MenuItem
|
|
key={index}
|
|
key={data.Name}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value={data.Name}
|
|
>
|
|
{data.default === true ?
|
|
<Chip
|
|
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
|
label={"Default"}
|
|
variant="outlined"
|
|
color="secondary"
|
|
/>
|
|
: null}
|
|
{data.Name}
|
|
</MenuItem>
|
|
);
|
|
})}
|
|
</Select>
|
|
</div>
|
|
) : null}
|
|
|
|
{workflow.execution_variables !== undefined &&
|
|
workflow.execution_variables !== null &&
|
|
workflow.execution_variables.length > 0 ? (
|
|
<div style={{ marginTop: "20px" }}>
|
|
<Typography>Execution variable (optional)</Typography>
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
value={
|
|
selectedAction.execution_variable !== undefined
|
|
&& selectedAction.execution_variable !== null
|
|
&& selectedAction.execution_variable.name !== undefined
|
|
&& selectedAction.execution_variable.name !== null
|
|
&& selectedAction.execution_variable.name.length > 0
|
|
? selectedAction.execution_variable.name
|
|
: "No selection"
|
|
}
|
|
SelectDisplayProps={{
|
|
style: {
|
|
},
|
|
}}
|
|
fullWidth
|
|
onChange={(e) => {
|
|
if (e.target.value === "No selection") {
|
|
selectedAction.execution_variable = { name: "No selection" };
|
|
} else {
|
|
const value = workflow.execution_variables.find(
|
|
(a) => a.name === e.target.value
|
|
);
|
|
selectedAction.execution_variable = value;
|
|
}
|
|
setSelectedAction(selectedAction);
|
|
setUpdate(Math.random());
|
|
}}
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
height: "50px",
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
>
|
|
<MenuItem
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value="No selection"
|
|
>
|
|
<em>No selection</em>
|
|
</MenuItem>
|
|
<Divider style={{ backgroundColor: theme.palette.inputColor }} />
|
|
{workflow.execution_variables.map((data) => (
|
|
<MenuItem
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
color: "white",
|
|
}}
|
|
value={data.name}
|
|
>
|
|
{data.name}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
</div>
|
|
) : null}
|
|
|
|
<Divider
|
|
style={{
|
|
marginTop: "20px",
|
|
height: "1px",
|
|
width: "100%",
|
|
backgroundColor: "rgb(91, 96, 100)",
|
|
}}
|
|
/>
|
|
<div style={{ flex: "6", marginTop: "20px" }}>
|
|
{/*hideExtraTypes ? null :
|
|
<div style={{marginBottom: 5}}>
|
|
<b>Actions</b>
|
|
</div>
|
|
*/}
|
|
|
|
{setNewSelectedAction !== undefined ? (
|
|
<Autocomplete
|
|
id="action_search"
|
|
autoHighlight
|
|
value={selectedAction}
|
|
classes={{ inputRoot: classes.inputRoot }}
|
|
groupBy={(option) => {
|
|
// 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 (
|
|
<li key={params.key}>
|
|
<Typography variant="body1" style={{textAlign: "center", marginLeft: 10, marginTop: 25, marginBottom: 10, }}>{params.group}</Typography>
|
|
<Typography variant="body2">{params.children}</Typography>
|
|
</li>
|
|
)
|
|
}}
|
|
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 (
|
|
<ActionSelectOption
|
|
data={data}
|
|
newActiondescription={newActiondescription}
|
|
useIcon={useIcon}
|
|
newActionname={newActionname}
|
|
extraDescription={extraDescription}
|
|
/>
|
|
);
|
|
}}
|
|
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 (
|
|
<TextField
|
|
{...params}
|
|
|
|
data-lpignore="true"
|
|
autocomplete="off"
|
|
dataLPIgnore="true"
|
|
autoComplete="off"
|
|
|
|
color="primary"
|
|
id="checkbox-search"
|
|
variant="body1"
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
borderRadius: theme.palette.borderRadius,
|
|
}}
|
|
label={isIntegration ? "Choose a category" : "Find Actions"}
|
|
variant="outlined"
|
|
name={`disable_autocomplete_${Math.random()}`}
|
|
|
|
/>
|
|
);
|
|
}}
|
|
/>
|
|
) : null}
|
|
|
|
{/*setNewSelectedAction !== undefined ?
|
|
<Select
|
|
MenuProps={{
|
|
disableScrollLock: true,
|
|
}}
|
|
value={selectedAction.name}
|
|
fullWidth
|
|
onChange={setNewSelectedAction}
|
|
style={{backgroundColor: theme.palette.inputColor, color: "white", height: 50, borderRadius: theme.palette.borderRadius,}}
|
|
SelectDisplayProps={{
|
|
style: {
|
|
marginLeft: 10,
|
|
maxHeight: 200,
|
|
}
|
|
}}
|
|
>
|
|
{sortByKey(selectedApp.actions, "label").map(data => {
|
|
var newActionname = data.name
|
|
if (data.label !== undefined && data.label !== null && data.label.length > 0) {
|
|
newActionname = data.label
|
|
}
|
|
|
|
const iconInfo = GetIconInfo({"name": data.name})
|
|
const useIcon = iconInfo.originalIcon
|
|
|
|
// ROFL FIXME - loop
|
|
newActionname = newActionname.replaceAll("_", " ")
|
|
newActionname = newActionname.charAt(0).toUpperCase()+newActionname.substring(1)
|
|
return (
|
|
<MenuItem key={data.name} style={{maxWidth: 400, overflowX: "hidden", backgroundColor: theme.palette.inputColor, color: "white", display: "flex",}} value={data.name}>
|
|
<span style={{marginRight: 10, marginTop: "auto", marginBottom: "auto",}}>{useIcon}</span>
|
|
<span style={{}}>{newActionname}</span>
|
|
</MenuItem>
|
|
)
|
|
})}
|
|
</Select>
|
|
: null*/}
|
|
|
|
<div
|
|
style={{
|
|
marginTop: "10px",
|
|
borderColor: "white",
|
|
borderWidth: "2px",
|
|
marginBottom: hideExtraTypes ? 50 : 200,
|
|
}}
|
|
>
|
|
<AppActionArguments
|
|
key={selectedAction.id}
|
|
selectedAction={selectedAction}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ParsedAction;
|