diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod
index 74585b9b..569852b4 100644
--- a/backend/go-app/go.mod
+++ b/backend/go-app/go.mod
@@ -2,7 +2,7 @@ module shuffle
go 1.13
-//replace github.com/frikky/shuffle-shared => ../../../../git/shuffle-shared
+replace github.com/frikky/shuffle-shared => ../../../../git/shuffle-shared
//replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi
diff --git a/backend/go-app/main.go b/backend/go-app/main.go
index dd71a38f..bcf2abac 100644
--- a/backend/go-app/main.go
+++ b/backend/go-app/main.go
@@ -5805,7 +5805,6 @@ func initHandlers() {
r.HandleFunc("/api/v1/apps/authentication", shuffle.GetAppAuthentication).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/apps/authentication", shuffle.AddAppAuthentication).Methods("PUT", "OPTIONS")
r.HandleFunc("/api/v1/apps/authentication/{appauthId}/config", shuffle.SetAuthenticationConfig).Methods("POST", "OPTIONS")
-
r.HandleFunc("/api/v1/apps/authentication/{appauthId}", shuffle.DeleteAppAuthentication).Methods("DELETE", "OPTIONS")
// Legacy app things
@@ -5863,6 +5862,7 @@ func initHandlers() {
r.HandleFunc("/api/v1/orgs/{orgId}/validate_app_values", shuffle.HandleKeyValueCheck).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/orgs/{orgId}/get_cache", shuffle.HandleGetCacheKey).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/orgs/{orgId}/set_cache", shuffle.HandleSetCacheKey).Methods("POST", "OPTIONS")
+ r.HandleFunc("/api/v1/apps/{key}/execute", executeSingleAction).Methods("POST", "OPTIONS")
// Docker orborus specific - downloads an image
r.HandleFunc("/api/v1/get_docker_image", getDockerImage).Methods("POST", "OPTIONS")
diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go
index 42623468..a0614772 100644
--- a/backend/go-app/walkoff.go
+++ b/backend/go-app/walkoff.go
@@ -4385,3 +4385,86 @@ func handleUserInput(trigger shuffle.Trigger, organizationId string, workflowId
return nil
}
+
+func executeSingleAction(resp http.ResponseWriter, request *http.Request) {
+ cors := shuffle.HandleCors(resp, request)
+ if cors {
+ return
+ }
+
+ user, err := shuffle.HandleApiAuthentication(resp, request)
+ if err != nil {
+ log.Printf("[WARNING] Api authentication failed in execute SINGLE workflow - CONTINUING ANYWAY: %s", err)
+ resp.WriteHeader(401)
+ resp.Write([]byte(`{"success": false, "reason": "You need to sign up to try it out}`))
+ return
+ }
+
+ location := strings.Split(request.URL.String(), "/")
+ var fileId string
+ if location[1] == "api" {
+ if len(location) <= 4 {
+ resp.WriteHeader(401)
+ resp.Write([]byte(`{"success": false}`))
+ return
+ }
+
+ fileId = location[4]
+ }
+
+ body, err := ioutil.ReadAll(request.Body)
+ if err != nil {
+ log.Printf("[INFO] Failed workflowrequest POST read: %s", err)
+ resp.WriteHeader(401)
+ resp.Write([]byte(`{"success": false}`))
+ return
+ }
+
+ ctx := context.Background()
+ workflowExecution, err := shuffle.PrepareSingleAction(ctx, user, fileId, body)
+ if err != nil {
+ log.Printf("[INFO] Failed workflowrequest POST read: %s", err)
+ resp.WriteHeader(401)
+ resp.Write([]byte(`{"success": false}`))
+ return
+ }
+
+ //workflowExecution.ProjectId = gceProject
+ //workflowExecution.Locations = []string{defaultLocation}
+
+ environments, err := shuffle.GetEnvironments(ctx, user.ActiveOrg.Id)
+ environment := "Shuffle"
+ if len(environments) >= 1 {
+ environment = environments[0].Name
+ } else {
+ log.Printf("[ERROR] No environments found for org %s. Exiting", user.ActiveOrg.Id)
+ resp.WriteHeader(401)
+ resp.Write([]byte(`{"success": false}`))
+ return
+ }
+
+ log.Printf("[INFO] Execution: %s should execute onprem with execution environment \"%s\". Workflow: %s", workflowExecution.ExecutionId, environment, workflowExecution.Workflow.ID)
+
+ executionRequest := shuffle.ExecutionRequest{
+ ExecutionId: workflowExecution.ExecutionId,
+ WorkflowId: workflowExecution.Workflow.ID,
+ Authorization: workflowExecution.Authorization,
+ Environments: []string{environment},
+ }
+
+ err = shuffle.SetWorkflowQueue(ctx, executionRequest, environment)
+ if err != nil {
+ log.Printf("[ERROR] Failed adding execution to db: %s", err)
+ resp.WriteHeader(401)
+ resp.Write([]byte(`{"success": false}`))
+ return
+ }
+
+ time.Sleep(2 * time.Second)
+ log.Printf("[INFO] Starting validation of execution %s", workflowExecution.ExecutionId)
+
+ returnBytes := shuffle.HandleRetValidation(ctx, workflowExecution)
+
+ resp.WriteHeader(200)
+ resp.Write(returnBytes)
+}
diff --git a/docker-compose.yml b/docker-compose.yml
index 7cc35878..6b863b6e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -31,6 +31,9 @@ services:
- ${SHUFFLE_FILE_LOCATION}:/shuffle-files
#- ${SHUFFLE_OPENSEARCH_CERTIFICATE_FILE}:/shuffle-files/es_certificate
env_file: .env
+ environment:
+ - SHUFFLE_APP_HOTLOAD_FOLDER=/shuffle-apps
+ - SHUFFLE_FILE_LOCATION=/shuffle-files
restart: unless-stopped
depends_on:
- opensearch
@@ -46,7 +49,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- SHUFFLE_APP_SDK_VERSION=0.8.97
- - SHUFFLE_WORKER_VERSION=nightly
+ - SHUFFLE_WORKER_VERSION=0.8.97
- ORG_ID=${ORG_ID}
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
diff --git a/frontend/package.json b/frontend/package.json
index 7f872271..5b290522 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -4,7 +4,6 @@
"version": "0.8.92",
"private": true,
"dependencies": {
- "@babel/helper-regex": "^7.10.5",
"@material-ui/core": "^4.5.2",
"@material-ui/data-grid": "^4.0.0-alpha.22",
"@material-ui/icons": "^4.5.1",
@@ -12,17 +11,15 @@
"@material-ui/styles": "^4.5.2",
"@use-it/interval": "^1.0.0",
"babel-eslint": "^10.1.0",
- "cache-base": "^4.0.0",
"class-transformer": "^0.3.1",
"create-react-app": "^2.0.3",
- "cytoscape": "^3.19.0",
+ "cytoscape": "^3.11.0",
"cytoscape-clipboard": "^2.2.1",
"cytoscape-cxtmenu": "^3.1.1",
"cytoscape-edgehandles": "^3.6.0",
"cytoscape-grid-guide": "~2.1.2",
"cytoscape-node-html-label": "^1.1.5",
"cytoscape-panzoom": "^2.5.2",
- "cytoscape-popper": "^2.0.0",
"cytoscape-undo-redo": "^1.3.2",
"d3": "~4.10.0",
"dotenv": "^6.1.0",
@@ -47,7 +44,7 @@
"react-cytoscapejs": "^1.2.0",
"react-device-detect": "^1.9.10",
"react-dom": "^16.14.0",
- "react-draggable": "4.4.3",
+ "react-draggable": "^3.3.2",
"react-dropzone": "^10.1.10",
"react-ga": "^2.7.0",
"react-iframe": "^1.8.0",
@@ -59,7 +56,6 @@
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-scripts": "^4.0.1",
- "react-scroll": "^1.8.2",
"reactstrap": "^7.1.0",
"shellwords": "^0.1.1",
"simplebar": "^4.2.3",
diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx
index 7905e069..7d8a37b8 100644
--- a/frontend/src/views/Admin.jsx
+++ b/frontend/src/views/Admin.jsx
@@ -1522,14 +1522,20 @@ const Admin = (props) => {
const org_id = selectedOrganization.id
var copyText = document.getElementById(elementName);
if (copyText !== null && copyText !== undefined) {
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(org_id)
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
- /* Copy the text inside the text field */
- document.execCommand("copy");
+ /* Copy the text inside the text field */
+ document.execCommand("copy");
- alert.info(org_id + " copied to clipboard")
+ alert.info(org_id + " copied to clipboard")
}
}}>
@@ -1910,6 +1916,12 @@ const Admin = (props) => {
const elementName = "copy_element_shuffle"
var copyText = document.getElementById(elementName);
if (copyText !== null && copyText !== undefined) {
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(data.apikey)
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
@@ -2161,6 +2173,12 @@ const Admin = (props) => {
const elementName = "copy_element_shuffle"
var copyText = document.getElementById(elementName);
if (copyText !== null && copyText !== undefined) {
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(file.id)
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx
index e27e04ef..5a7a8c79 100644
--- a/frontend/src/views/AngularWorkflow.jsx
+++ b/frontend/src/views/AngularWorkflow.jsx
@@ -2228,7 +2228,7 @@ const AngularWorkflow = (props) => {
}
var parents = getParents(dstdata)
- console.log("PARENTS: ", parents)
+ //console.log("PARENTS: ", parents)
if (parents.length > 1) {
for (var key in parents) {
const item = parents[key]
@@ -2272,8 +2272,9 @@ const AngularWorkflow = (props) => {
// Checks for errors in edges when they're added
const onEdgeAdded = (event) => {
- setLastSaved(false)
const edge = event.target.data()
+ console.log("EDGE ADDED: ", edge)
+ //setLastSaved(false)
var targetnode = workflow.triggers.findIndex(data => data.id === edge.target)
if (targetnode !== -1) {
console.log("TARGETNODE: ", targetnode)
@@ -2892,6 +2893,9 @@ const AngularWorkflow = (props) => {
setEstablished(true)
// Validate if the node is just a node lol
+ console.log("CY: ", cy)
+ //console.log("CY: ", cy.edgehandles())
+ //try {
cy.edgehandles({
handleNodes: (el) => el.isNode() && !el.data("isButton") && !el.data("isDescriptor"),
preview: false,
@@ -2900,6 +2904,9 @@ const AngularWorkflow = (props) => {
return false;
},
})
+ //} catch (e) {
+ // console.log("Error in edgehandles: ", e)
+ //}
cy.fit(null, 200)
@@ -6276,6 +6283,12 @@ const AngularWorkflow = (props) => {
var copyText = document.getElementById("webhook_uri_field")
if (copyText !== undefined && copyText !== null) {
console.log("NAVIGATOR: ", navigator)
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(copyText.value)
copyText.select()
copyText.setSelectionRange(0, 99999) /* For mobile devices */
@@ -7510,6 +7523,12 @@ const AngularWorkflow = (props) => {
console.log("NEW: ", copy)
console.log("NAVIGATOR: ", navigator)
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(JSON.stringify(copy))
copyText.select()
copyText.setSelectionRange(0, 99999) /* For mobile devices */
@@ -7560,6 +7579,12 @@ const AngularWorkflow = (props) => {
var copyText = document.getElementById(elementName)
if (copyText !== null && copyText !== undefined) {
console.log("NAVIGATOR: ", navigator)
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(to_be_copied)
copyText.select()
copyText.setSelectionRange(0, 99999); /* For mobile devices */
@@ -8093,7 +8118,14 @@ const AngularWorkflow = (props) => {
if (copyText !== null && copyText !== undefined) {
console.log("COPY: ", copyText)
console.log("NAVIGATOR: ", navigator)
+ const clipboard = navigator.clipboard
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)")
+ return
+ }
+
navigator.clipboard.writeText(to_be_copied)
+
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx
index e12fb05b..f2e759f3 100644
--- a/frontend/src/views/AppCreator.jsx
+++ b/frontend/src/views/AppCreator.jsx
@@ -1,10 +1,12 @@
import React, {useState, useEffect} from 'react';
import { makeStyles } from '@material-ui/styles';
+import { useTheme } from '@material-ui/core/styles';
import {BrowserView, MobileView} from "react-device-detect";
import {Paper, Typography, FormControlLabel, Button, Divider, Select, MenuItem, FormControl, Switch, Dialog, DialogTitle, DialogContent, DialogActions, TextField, Tooltip, Breadcrumbs, CircularProgress, Chip} from '@material-ui/core';
-import {FileCopy as FileCopyIcon, Delete as DeleteIcon, Remove as RemoveIcon, Add as AddIcon, CheckCircle as CheckCircleIcon, AttachFile as AttachFileIcon, Apps as AppsIcon, ErrorOutline as ErrorOutlineIcon} from '@material-ui/icons';
+import {LockOpen as LockOpenIcon, FileCopy as FileCopyIcon, Delete as DeleteIcon, Remove as RemoveIcon, Add as AddIcon, CheckCircle as CheckCircleIcon, AttachFile as AttachFileIcon, Apps as AppsIcon, ErrorOutline as ErrorOutlineIcon} from '@material-ui/icons';
+import uuid from "uuid";
import {Link} from 'react-router-dom';
import YAML from 'yaml'
import ChipInput from 'material-ui-chip-input'
@@ -192,6 +194,7 @@ const AppCreator = (props) => {
const { globalUrl, isLoaded } = props;
const classes = useStyles();
const alert = useAlert()
+ const theme = useTheme();
var upload = ""
const increaseAmount = 50
@@ -237,6 +240,12 @@ const AppCreator = (props) => {
}
const [extraAuth, setExtraAuth] = useState([])
+
+ const [app, setApp] = useState({})
+ const [appAuthentication, setAppAuthentication] = React.useState([]);
+ const [selectedAction, setSelectedAction] = useState({})
+ const [authLoaded, setAuthLoaded] = useState(false)
+
//const [actions, setActions] = useState([{
// "name": "Get workflows",
// "description": "Get workflows",
@@ -2416,6 +2425,401 @@ const AppCreator = (props) => {
/>
+ const ParsedActionHandler = () => {
+ const passedOrg = {"id": "", "name": ""}
+ const owner = ""
+ const passedTags = ["single test"]
+
+ const [, setUpdate] = useState()
+ const [authenticationModalOpen, setAuthenticationModalOpen] = useState(false);
+ const [selectedApp, setSelectedApp] = useState({
+ versions: [{
+ "id": selectedAction.app_id,
+ "version": selectedAction.app_version,
+ }],
+ loop_versions: [selectedAction.app_version],
+ id: selectedAction.app_id,
+ name: selectedAction.app_name,
+ version: selectedAction.app_version,
+ })
+
+ const [requiresAuthentication, setRequiresAuthentication] = useState(app.authentication.required && app.authentication.parameters !== undefined && app.authentication.parameters !== null)
+ const [workflow, setWorkflow] = useState({
+ name: "",
+ description: "",
+ actions: [selectedAction],
+ start: selectedAction.id,
+ tags: passedTags,
+ execution_org: passedOrg,
+ org_id: passedOrg.id,
+ id: uuid.v4(),
+ isValid: true,
+ owner: owner,
+ created: Date.now(),
+ })
+
+ const EndpointData = () => {
+ const [tmpVar, setTmpVar] = React.useState("")
+
+ return (
+
+ The API endpoint to use (URL) - predefined in the app
+ {
+ setTmpVar(event.target.value)
+ }}
+ onBlur={() => {
+ selectedApp.link = tmpVar
+ console.log("LINK: ", selectedApp.link)
+ setSelectedApp(selectedApp)
+ }}
+ />
+
+ )
+ }
+
+ const setAppActionAuthentication = (newauth) => {
+ if (app.authentication.required) {
+ var findAuthId = ""
+ if (selectedAction.authentication_id !== null && selectedAction.authentication_id !== undefined && selectedAction.authentication_id.length > 0) {
+ findAuthId = selectedAction.authentication_id
+ }
+
+ var baseAuthOptions = []
+ for (var key in newauth) {
+ var item = newauth[key]
+
+ const newfields = {}
+ for (var filterkey in item.fields) {
+ newfields[item.fields[filterkey].key] = item.fields[filterkey].value
+ }
+
+ item.fields = newfields
+ if (item.app.name === app.name) {
+ baseAuthOptions.push(item)
+
+ if (item.id === findAuthId) {
+ selectedAction.selectedAuthentication = item
+ }
+ }
+ }
+
+ selectedAction.authentication = baseAuthOptions
+ //console.log("Authentication: ", authenticationOptions)
+ if (selectedAction.selectedAuthentication === null || selectedAction.selectedAuthentication === undefined || selectedAction.selectedAuthentication.length === "") {
+ selectedAction.selectedAuthentication = {}
+ }
+ } else {
+ selectedAction.authentication = []
+ selectedAction.authentication_id = ""
+ selectedAction.selectedAuthentication = {}
+ }
+
+ setSelectedAction(selectedAction)
+ console.log(selectedAction)
+ }
+
+ //{selectedAction.authentication !== undefined && selectedAction.authentication.length > 0 ?
+ const getAppAuthentication = () => {
+ fetch(globalUrl+"/api/v1/apps/authentication", {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for apps :O!")
+ }
+
+ return response.json()
+ })
+ .then((responseJson) => {
+ if (responseJson.success && responseJson.data !== undefined && responseJson.data !== null && responseJson.data.length !== 0) {
+ var newauth = []
+ for (var key in responseJson.data) {
+ if (responseJson.data[key].defined === false) {
+ continue
+ }
+
+ newauth.push(responseJson.data[key])
+ }
+
+ setAppAuthentication(newauth)
+ setAppActionAuthentication(newauth)
+ } else {
+ if (app.authentication.required) {
+ const tmpParams = selectedAction.parameters
+ selectedAction.parameters = []
+
+ for (var paramkey in app.authentication.parameters) {
+ var item = app.authentication.parameters[paramkey]
+ item.configuration = true
+
+ const found = selectedAction.parameters.find(param => param.name === item.name)
+ if (found === null || found === undefined) {
+ selectedAction.parameters.push(item)
+ }
+ }
+
+ for (var paramkey in tmpParams) {
+ var item = tmpParams[paramkey]
+ //item.configuration = true
+
+ const found = selectedAction.parameters.find(param => param.name === item.name)
+ if (found === null || found === undefined) {
+ selectedAction.parameters.push(item)
+ }
+ }
+
+ setSelectedAction(selectedAction)
+ }
+
+ //alert.error("Failed getting authentications")
+ }
+ })
+ .catch(error => {
+ alert.error("Auth loading error: "+error.toString())
+ })
+ }
+
+ if (!authLoaded && appAuthentication.length === 0 && selectedAction.id !== undefined) {
+ setAuthLoaded(true)
+ getAppAuthentication()
+ } else if (selectedAction.id === undefined && currentAction.name !== undefined && currentAction.name !== null && currentAction.name.length > 0) {
+ var methodName = `${currentAction.method}_${currentAction.name}`
+ if (currentAction.method.toLowerCase() === "custom" || currentAction.name.toLowerCase().startsWith(currentAction.method.toLowerCase())) {
+ methodName = currentAction.name
+ }
+
+ methodName = methodName.toLowerCase().replaceAll(" ", "_")
+ if (app.actions !== null && app.actions !== undefined) {
+ var newselectedaction = app.actions.find(item => item.name.toLowerCase().replaceAll(" ", "_") === methodName)
+ if (newselectedaction !== undefined && newselectedaction !== null) {
+ newselectedaction.app_id = app.id
+ newselectedaction.app_name = app.name
+ newselectedaction.app_version = app.app_version
+ newselectedaction.authentication = []
+ newselectedaction.authentication_id = ""
+ newselectedaction.selectedAuthentication = {}
+ setSelectedAction(newselectedaction)
+ }
+ }
+ }
+
+ const setNewAppAuth = (appAuthData) => {
+ //console.log("DAta: ", appAuthData)
+ fetch(globalUrl+"/api/v1/apps/authentication", {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ },
+ body: JSON.stringify(appAuthData),
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for setting app auth :O!")
+ }
+
+ return response.json()
+ })
+ .then((responseJson) => {
+ if (!responseJson.success) {
+ alert.error("Failed to set app auth: "+responseJson.reason)
+ } else {
+ getAppAuthentication(true)
+ setAuthenticationModalOpen(false)
+
+ // Needs a refresh with the new authentication..
+ //alert.success("Successfully saved new app auth")
+ }
+ })
+ .catch(error => {
+ alert.error(error.toString())
+ })
+ }
+
+ const AuthenticationData = (props) => {
+ const selectedApp = props.app
+ console.log("APP: ", selectedApp)
+
+ const [authenticationOption, setAuthenticationOptions] = React.useState({
+ app: JSON.parse(JSON.stringify(selectedApp)),
+ fields: {},
+ label: "",
+ usage: [{
+ workflow_id: workflow.id,
+ }],
+ id: uuid.v4(),
+ active: true,
+ })
+
+ if (selectedApp.authentication === undefined) {
+ return null
+ }
+
+ if (selectedApp.authentication.parameters === null || selectedApp.authentication.parameters === undefined || selectedApp.authentication.parameters.length === 0) {
+ return null
+ }
+
+ authenticationOption.app.actions = []
+
+ for (var key in selectedApp.authentication.parameters) {
+ if (authenticationOption.fields[selectedApp.authentication.parameters[key].name] === undefined) {
+ authenticationOption.fields[selectedApp.authentication.parameters[key].name] = ""
+ }
+ }
+
+ const handleSubmitCheck = () => {
+ console.log("NEW AUTH: ", authenticationOption)
+ if (authenticationOption.label.length === 0) {
+ authenticationOption.label = `Auth for ${selectedApp.name}`
+ //alert.info("Label can't be empty")
+ //return
+ }
+
+ for (var key in selectedApp.authentication.parameters) {
+ if (authenticationOption.fields[selectedApp.authentication.parameters[key].name].length === 0) {
+ alert.info("Field "+selectedApp.authentication.parameters[key].name+" can't be empty")
+ return
+ }
+ }
+
+ console.log("Action: ", selectedAction)
+ selectedAction.authentication_id = authenticationOption.id
+ selectedAction.selectedAuthentication = authenticationOption
+ if (selectedAction.authentication === undefined || selectedAction.authentication === null) {
+ selectedAction.authentication = [authenticationOption]
+ } else {
+ selectedAction.authentication.push(authenticationOption)
+ }
+
+ setSelectedAction(selectedAction)
+
+ var newAuthOption = JSON.parse(JSON.stringify(authenticationOption))
+ var newFields = []
+ for (const key in newAuthOption.fields) {
+ const value = newAuthOption.fields[key]
+ newFields.push({
+ key: key,
+ value: value,
+ })
+ }
+
+ console.log("FIELDS: ", newFields)
+ newAuthOption.fields = newFields
+ setNewAppAuth(newAuthOption)
+ //appAuthentication.push(newAuthOption)
+ //setAppAuthentication(appAuthentication)
+ //
+
+ setUpdate(authenticationOption.id)
+
+ /*
+ {selectedAction.authentication.map(data => (
+