Fixed clipboard issues - requires HTTPS or localhost
This commit is contained in:
@@ -2,7 +2,7 @@ module shuffle
|
|||||||
|
|
||||||
go 1.13
|
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
|
//replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi
|
||||||
|
|
||||||
|
|||||||
@@ -5805,7 +5805,6 @@ func initHandlers() {
|
|||||||
r.HandleFunc("/api/v1/apps/authentication", shuffle.GetAppAuthentication).Methods("GET", "OPTIONS")
|
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", 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}/config", shuffle.SetAuthenticationConfig).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
r.HandleFunc("/api/v1/apps/authentication/{appauthId}", shuffle.DeleteAppAuthentication).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/authentication/{appauthId}", shuffle.DeleteAppAuthentication).Methods("DELETE", "OPTIONS")
|
||||||
|
|
||||||
// Legacy app things
|
// 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}/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}/get_cache", shuffle.HandleGetCacheKey).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/orgs/{orgId}/set_cache", shuffle.HandleSetCacheKey).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
|
// Docker orborus specific - downloads an image
|
||||||
r.HandleFunc("/api/v1/get_docker_image", getDockerImage).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/get_docker_image", getDockerImage).Methods("POST", "OPTIONS")
|
||||||
|
|||||||
@@ -4385,3 +4385,86 @@ func handleUserInput(trigger shuffle.Trigger, organizationId string, workflowId
|
|||||||
|
|
||||||
return nil
|
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)
|
||||||
|
}
|
||||||
|
|||||||
+4
-1
@@ -31,6 +31,9 @@ services:
|
|||||||
- ${SHUFFLE_FILE_LOCATION}:/shuffle-files
|
- ${SHUFFLE_FILE_LOCATION}:/shuffle-files
|
||||||
#- ${SHUFFLE_OPENSEARCH_CERTIFICATE_FILE}:/shuffle-files/es_certificate
|
#- ${SHUFFLE_OPENSEARCH_CERTIFICATE_FILE}:/shuffle-files/es_certificate
|
||||||
env_file: .env
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
- SHUFFLE_APP_HOTLOAD_FOLDER=/shuffle-apps
|
||||||
|
- SHUFFLE_FILE_LOCATION=/shuffle-files
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- opensearch
|
- opensearch
|
||||||
@@ -46,7 +49,7 @@ services:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
environment:
|
environment:
|
||||||
- SHUFFLE_APP_SDK_VERSION=0.8.97
|
- SHUFFLE_APP_SDK_VERSION=0.8.97
|
||||||
- SHUFFLE_WORKER_VERSION=nightly
|
- SHUFFLE_WORKER_VERSION=0.8.97
|
||||||
- ORG_ID=${ORG_ID}
|
- ORG_ID=${ORG_ID}
|
||||||
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
|
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
|
||||||
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
|
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
"version": "0.8.92",
|
"version": "0.8.92",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-regex": "^7.10.5",
|
|
||||||
"@material-ui/core": "^4.5.2",
|
"@material-ui/core": "^4.5.2",
|
||||||
"@material-ui/data-grid": "^4.0.0-alpha.22",
|
"@material-ui/data-grid": "^4.0.0-alpha.22",
|
||||||
"@material-ui/icons": "^4.5.1",
|
"@material-ui/icons": "^4.5.1",
|
||||||
@@ -12,17 +11,15 @@
|
|||||||
"@material-ui/styles": "^4.5.2",
|
"@material-ui/styles": "^4.5.2",
|
||||||
"@use-it/interval": "^1.0.0",
|
"@use-it/interval": "^1.0.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"cache-base": "^4.0.0",
|
|
||||||
"class-transformer": "^0.3.1",
|
"class-transformer": "^0.3.1",
|
||||||
"create-react-app": "^2.0.3",
|
"create-react-app": "^2.0.3",
|
||||||
"cytoscape": "^3.19.0",
|
"cytoscape": "^3.11.0",
|
||||||
"cytoscape-clipboard": "^2.2.1",
|
"cytoscape-clipboard": "^2.2.1",
|
||||||
"cytoscape-cxtmenu": "^3.1.1",
|
"cytoscape-cxtmenu": "^3.1.1",
|
||||||
"cytoscape-edgehandles": "^3.6.0",
|
"cytoscape-edgehandles": "^3.6.0",
|
||||||
"cytoscape-grid-guide": "~2.1.2",
|
"cytoscape-grid-guide": "~2.1.2",
|
||||||
"cytoscape-node-html-label": "^1.1.5",
|
"cytoscape-node-html-label": "^1.1.5",
|
||||||
"cytoscape-panzoom": "^2.5.2",
|
"cytoscape-panzoom": "^2.5.2",
|
||||||
"cytoscape-popper": "^2.0.0",
|
|
||||||
"cytoscape-undo-redo": "^1.3.2",
|
"cytoscape-undo-redo": "^1.3.2",
|
||||||
"d3": "~4.10.0",
|
"d3": "~4.10.0",
|
||||||
"dotenv": "^6.1.0",
|
"dotenv": "^6.1.0",
|
||||||
@@ -47,7 +44,7 @@
|
|||||||
"react-cytoscapejs": "^1.2.0",
|
"react-cytoscapejs": "^1.2.0",
|
||||||
"react-device-detect": "^1.9.10",
|
"react-device-detect": "^1.9.10",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
"react-draggable": "4.4.3",
|
"react-draggable": "^3.3.2",
|
||||||
"react-dropzone": "^10.1.10",
|
"react-dropzone": "^10.1.10",
|
||||||
"react-ga": "^2.7.0",
|
"react-ga": "^2.7.0",
|
||||||
"react-iframe": "^1.8.0",
|
"react-iframe": "^1.8.0",
|
||||||
@@ -59,7 +56,6 @@
|
|||||||
"react-router": "^4.3.1",
|
"react-router": "^4.3.1",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
"react-scripts": "^4.0.1",
|
"react-scripts": "^4.0.1",
|
||||||
"react-scroll": "^1.8.2",
|
|
||||||
"reactstrap": "^7.1.0",
|
"reactstrap": "^7.1.0",
|
||||||
"shellwords": "^0.1.1",
|
"shellwords": "^0.1.1",
|
||||||
"simplebar": "^4.2.3",
|
"simplebar": "^4.2.3",
|
||||||
|
|||||||
@@ -1522,6 +1522,12 @@ const Admin = (props) => {
|
|||||||
const org_id = selectedOrganization.id
|
const org_id = selectedOrganization.id
|
||||||
var copyText = document.getElementById(elementName);
|
var copyText = document.getElementById(elementName);
|
||||||
if (copyText !== null && copyText !== undefined) {
|
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)
|
navigator.clipboard.writeText(org_id)
|
||||||
copyText.select();
|
copyText.select();
|
||||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||||
@@ -1910,6 +1916,12 @@ const Admin = (props) => {
|
|||||||
const elementName = "copy_element_shuffle"
|
const elementName = "copy_element_shuffle"
|
||||||
var copyText = document.getElementById(elementName);
|
var copyText = document.getElementById(elementName);
|
||||||
if (copyText !== null && copyText !== undefined) {
|
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)
|
navigator.clipboard.writeText(data.apikey)
|
||||||
copyText.select();
|
copyText.select();
|
||||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||||
@@ -2161,6 +2173,12 @@ const Admin = (props) => {
|
|||||||
const elementName = "copy_element_shuffle"
|
const elementName = "copy_element_shuffle"
|
||||||
var copyText = document.getElementById(elementName);
|
var copyText = document.getElementById(elementName);
|
||||||
if (copyText !== null && copyText !== undefined) {
|
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)
|
navigator.clipboard.writeText(file.id)
|
||||||
copyText.select();
|
copyText.select();
|
||||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||||
|
|||||||
@@ -2228,7 +2228,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var parents = getParents(dstdata)
|
var parents = getParents(dstdata)
|
||||||
console.log("PARENTS: ", parents)
|
//console.log("PARENTS: ", parents)
|
||||||
if (parents.length > 1) {
|
if (parents.length > 1) {
|
||||||
for (var key in parents) {
|
for (var key in parents) {
|
||||||
const item = parents[key]
|
const item = parents[key]
|
||||||
@@ -2272,8 +2272,9 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
// Checks for errors in edges when they're added
|
// Checks for errors in edges when they're added
|
||||||
const onEdgeAdded = (event) => {
|
const onEdgeAdded = (event) => {
|
||||||
setLastSaved(false)
|
|
||||||
const edge = event.target.data()
|
const edge = event.target.data()
|
||||||
|
console.log("EDGE ADDED: ", edge)
|
||||||
|
//setLastSaved(false)
|
||||||
var targetnode = workflow.triggers.findIndex(data => data.id === edge.target)
|
var targetnode = workflow.triggers.findIndex(data => data.id === edge.target)
|
||||||
if (targetnode !== -1) {
|
if (targetnode !== -1) {
|
||||||
console.log("TARGETNODE: ", targetnode)
|
console.log("TARGETNODE: ", targetnode)
|
||||||
@@ -2892,6 +2893,9 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
setEstablished(true)
|
setEstablished(true)
|
||||||
// Validate if the node is just a node lol
|
// Validate if the node is just a node lol
|
||||||
|
console.log("CY: ", cy)
|
||||||
|
//console.log("CY: ", cy.edgehandles())
|
||||||
|
//try {
|
||||||
cy.edgehandles({
|
cy.edgehandles({
|
||||||
handleNodes: (el) => el.isNode() && !el.data("isButton") && !el.data("isDescriptor"),
|
handleNodes: (el) => el.isNode() && !el.data("isButton") && !el.data("isDescriptor"),
|
||||||
preview: false,
|
preview: false,
|
||||||
@@ -2900,6 +2904,9 @@ const AngularWorkflow = (props) => {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
//} catch (e) {
|
||||||
|
// console.log("Error in edgehandles: ", e)
|
||||||
|
//}
|
||||||
|
|
||||||
cy.fit(null, 200)
|
cy.fit(null, 200)
|
||||||
|
|
||||||
@@ -6276,6 +6283,12 @@ const AngularWorkflow = (props) => {
|
|||||||
var copyText = document.getElementById("webhook_uri_field")
|
var copyText = document.getElementById("webhook_uri_field")
|
||||||
if (copyText !== undefined && copyText !== null) {
|
if (copyText !== undefined && copyText !== null) {
|
||||||
console.log("NAVIGATOR: ", navigator)
|
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)
|
navigator.clipboard.writeText(copyText.value)
|
||||||
copyText.select()
|
copyText.select()
|
||||||
copyText.setSelectionRange(0, 99999) /* For mobile devices */
|
copyText.setSelectionRange(0, 99999) /* For mobile devices */
|
||||||
@@ -7510,6 +7523,12 @@ const AngularWorkflow = (props) => {
|
|||||||
console.log("NEW: ", copy)
|
console.log("NEW: ", copy)
|
||||||
console.log("NAVIGATOR: ", navigator)
|
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))
|
navigator.clipboard.writeText(JSON.stringify(copy))
|
||||||
copyText.select()
|
copyText.select()
|
||||||
copyText.setSelectionRange(0, 99999) /* For mobile devices */
|
copyText.setSelectionRange(0, 99999) /* For mobile devices */
|
||||||
@@ -7560,6 +7579,12 @@ const AngularWorkflow = (props) => {
|
|||||||
var copyText = document.getElementById(elementName)
|
var copyText = document.getElementById(elementName)
|
||||||
if (copyText !== null && copyText !== undefined) {
|
if (copyText !== null && copyText !== undefined) {
|
||||||
console.log("NAVIGATOR: ", navigator)
|
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)
|
navigator.clipboard.writeText(to_be_copied)
|
||||||
copyText.select()
|
copyText.select()
|
||||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||||
@@ -8093,7 +8118,14 @@ const AngularWorkflow = (props) => {
|
|||||||
if (copyText !== null && copyText !== undefined) {
|
if (copyText !== null && copyText !== undefined) {
|
||||||
console.log("COPY: ", copyText)
|
console.log("COPY: ", copyText)
|
||||||
console.log("NAVIGATOR: ", navigator)
|
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)
|
navigator.clipboard.writeText(to_be_copied)
|
||||||
|
|
||||||
copyText.select();
|
copyText.select();
|
||||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState, useEffect} from 'react';
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
|
import { useTheme } from '@material-ui/core/styles';
|
||||||
import {BrowserView, MobileView} from "react-device-detect";
|
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 {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 {Link} from 'react-router-dom';
|
||||||
import YAML from 'yaml'
|
import YAML from 'yaml'
|
||||||
import ChipInput from 'material-ui-chip-input'
|
import ChipInput from 'material-ui-chip-input'
|
||||||
@@ -192,6 +194,7 @@ const AppCreator = (props) => {
|
|||||||
const { globalUrl, isLoaded } = props;
|
const { globalUrl, isLoaded } = props;
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const alert = useAlert()
|
const alert = useAlert()
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
var upload = ""
|
var upload = ""
|
||||||
const increaseAmount = 50
|
const increaseAmount = 50
|
||||||
@@ -237,6 +240,12 @@ const AppCreator = (props) => {
|
|||||||
}
|
}
|
||||||
const [extraAuth, setExtraAuth] = useState([])
|
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([{
|
//const [actions, setActions] = useState([{
|
||||||
// "name": "Get workflows",
|
// "name": "Get workflows",
|
||||||
// "description": "Get workflows",
|
// "description": "Get workflows",
|
||||||
@@ -2416,6 +2425,401 @@ const AppCreator = (props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div>
|
||||||
|
The API endpoint to use (URL) - predefined in the app
|
||||||
|
<TextField
|
||||||
|
style={{backgroundColor: inputColor, borderRadius: theme.palette.borderRadius,}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
height: 50,
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
type="text"
|
||||||
|
color="primary"
|
||||||
|
disabled={true}
|
||||||
|
placeholder="Bearer token"
|
||||||
|
defaultValue={selectedApp.link}
|
||||||
|
onChange={(event) => {
|
||||||
|
setTmpVar(event.target.value)
|
||||||
|
}}
|
||||||
|
onBlur={() => {
|
||||||
|
selectedApp.link = tmpVar
|
||||||
|
console.log("LINK: ", selectedApp.link)
|
||||||
|
setSelectedApp(selectedApp)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 => (
|
||||||
|
<MenuItem key={data.id} style={{backgroundColor: inputColor, color: "white"}} value={data}>
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authenticationOption.label === null || authenticationOption.label === undefined) {
|
||||||
|
authenticationOption.label = selectedApp.name+" authentication"
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DialogContent>
|
||||||
|
<a target="_blank" rel="norefferer" href="https://shuffler.io/docs/apps#authentication" style={{textDecoration: "none", color: "#f85a3e"}}>What is this?</a><div/>
|
||||||
|
These are required fields for authenticating with {selectedApp.name}
|
||||||
|
<div style={{marginTop: 15}}/>
|
||||||
|
<b>Name - what is this used for?</b>
|
||||||
|
<TextField
|
||||||
|
style={{backgroundColor: inputColor, borderRadius: theme.palette.borderRadius,}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
marginLeft: "5px",
|
||||||
|
maxWidth: "95%",
|
||||||
|
height: 50,
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
color="primary"
|
||||||
|
placeholder={"Auth july 2020"}
|
||||||
|
defaultValue={`Auth for ${selectedApp.name}`}
|
||||||
|
onChange={(event) => {
|
||||||
|
authenticationOption.label = event.target.value
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{selectedApp.link.length > 0 ? <div style={{marginTop: 15}}><EndpointData /></div> : null}
|
||||||
|
<Divider style={{marginTop: 15, marginBottom: 15, backgroundColor: "rgb(91, 96, 100)"}}/>
|
||||||
|
<div style={{}}/>
|
||||||
|
{selectedApp.authentication.parameters.map((data, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index} style={{marginTop: 10}}>
|
||||||
|
<LockOpenIcon style={{marginRight: 10}}/>
|
||||||
|
<b>{data.name}</b>
|
||||||
|
<TextField
|
||||||
|
style={{backgroundColor: inputColor, borderRadius: theme.palette.borderRadius,}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
marginLeft: "5px",
|
||||||
|
maxWidth: "95%",
|
||||||
|
height: 50,
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
type={data.example !== undefined && data.example.includes("***") ? "password" : "text"}
|
||||||
|
color="primary"
|
||||||
|
placeholder={data.example}
|
||||||
|
onChange={(event) => {
|
||||||
|
authenticationOption.fields[data.name] = event.target.value
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
style={{borderRadius: "0px"}}
|
||||||
|
onClick={() => {
|
||||||
|
setAuthenticationModalOpen(false)
|
||||||
|
}} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button style={{borderRadius: "0px"}} onClick={() => {
|
||||||
|
handleSubmitCheck()
|
||||||
|
}} color="primary">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const actionView =
|
const actionView =
|
||||||
<div style={{color: "white", position: "relative",}}>
|
<div style={{color: "white", position: "relative",}}>
|
||||||
<div style={{position: "absolute", right: 0, top: 0,}}>
|
<div style={{position: "absolute", right: 0, top: 0,}}>
|
||||||
@@ -2628,6 +3032,7 @@ const AppCreator = (props) => {
|
|||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
<ParsedActionHandler />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
Reference in New Issue
Block a user