#259: Added authentication header possibility to webhooks

This commit is contained in:
frikky
2021-05-29 13:57:25 +02:00
parent fd4a87bfe6
commit 597c0b0e3d
13 changed files with 355 additions and 75 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ require (
github.com/elastic/go-elasticsearch/v7 v7.12.0 // indirect github.com/elastic/go-elasticsearch/v7 v7.12.0 // indirect
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210519083322-55daf7425ecb // indirect github.com/elastic/go-elasticsearch/v8 v8.0.0-20210519083322-55daf7425ecb // indirect
github.com/frikky/kin-openapi v0.39.0 github.com/frikky/kin-openapi v0.39.0
github.com/frikky/shuffle-shared v0.0.51 github.com/frikky/shuffle-shared v0.0.52
github.com/fsouza/go-dockerclient v1.7.2 // indirect github.com/fsouza/go-dockerclient v1.7.2 // indirect
github.com/ghodss/yaml v1.0.0 github.com/ghodss/yaml v1.0.0
github.com/go-git/go-billy/v5 v5.0.0 github.com/go-git/go-billy/v5 v5.0.0
+2
View File
@@ -161,6 +161,8 @@ github.com/frikky/shuffle-shared v0.0.50 h1:dQIXf4mwUHuEVsXiMtZaSznz6vWt+C0KjyTA
github.com/frikky/shuffle-shared v0.0.50/go.mod h1:BknTfpun3qte5bumR3OqQHf9XWPIsyj8woiXCjIlbBc= github.com/frikky/shuffle-shared v0.0.50/go.mod h1:BknTfpun3qte5bumR3OqQHf9XWPIsyj8woiXCjIlbBc=
github.com/frikky/shuffle-shared v0.0.51 h1:JrCGoRNj/LkAvSlkyx7tLv7ToNtJDIAqKqiA/poO+G4= github.com/frikky/shuffle-shared v0.0.51 h1:JrCGoRNj/LkAvSlkyx7tLv7ToNtJDIAqKqiA/poO+G4=
github.com/frikky/shuffle-shared v0.0.51/go.mod h1:BknTfpun3qte5bumR3OqQHf9XWPIsyj8woiXCjIlbBc= github.com/frikky/shuffle-shared v0.0.51/go.mod h1:BknTfpun3qte5bumR3OqQHf9XWPIsyj8woiXCjIlbBc=
github.com/frikky/shuffle-shared v0.0.52 h1:sCSJl6WakYit32UjaRn0wsy4YhTBE6QZbCofYKtuATg=
github.com/frikky/shuffle-shared v0.0.52/go.mod h1:BknTfpun3qte5bumR3OqQHf9XWPIsyj8woiXCjIlbBc=
github.com/fsouza/go-dockerclient v1.7.2 h1:bBEAcqLTkpq205jooP5RVroUKiVEWgGecHyeZc4OFjo= github.com/fsouza/go-dockerclient v1.7.2 h1:bBEAcqLTkpq205jooP5RVroUKiVEWgGecHyeZc4OFjo=
github.com/fsouza/go-dockerclient v1.7.2/go.mod h1:+ugtMCVRwnPfY7d8/baCzZ3uwB0BrG5DB8OzbtxaRz8= github.com/fsouza/go-dockerclient v1.7.2/go.mod h1:+ugtMCVRwnPfY7d8/baCzZ3uwB0BrG5DB8OzbtxaRz8=
github.com/getkin/kin-openapi v0.8.0 h1:a6TQjTqwkyscC4/hShJX7WhCVE+4bi9lzw61XHQW5hE= github.com/getkin/kin-openapi v0.8.0 h1:a6TQjTqwkyscC4/hShJX7WhCVE+4bi9lzw61XHQW5hE=
+13 -2
View File
@@ -2001,6 +2001,17 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
log.Printf("This should trigger in the cloud. Duplicate action allowed onprem.") log.Printf("This should trigger in the cloud. Duplicate action allowed onprem.")
} }
// Check auth
if len(hook.Auth) > 0 {
err = shuffle.CheckHookAuth(request, hook.Auth)
if err != nil {
log.Printf("[WARNING] Failed auth for hook %s: %s", hook.Id, err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Bad authentication headers"}`))
return
}
}
body, err := ioutil.ReadAll(request.Body) body, err := ioutil.ReadAll(request.Body)
if err != nil { if err != nil {
log.Printf("Body data error: %s", err) log.Printf("Body data error: %s", err)
@@ -3262,7 +3273,7 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) {
return return
} }
log.Printf("[INFO] SETTING APP TO LIVE!!!") log.Printf("[INFO] TRY TO SET APP TO LIVE!!!")
user, err := shuffle.HandleApiAuthentication(resp, request) user, err := shuffle.HandleApiAuthentication(resp, request)
if err != nil { if err != nil {
log.Printf("Api authentication failed in verify swagger: %s", err) log.Printf("Api authentication failed in verify swagger: %s", err)
@@ -4210,7 +4221,7 @@ func runInitEs(ctx context.Context) {
// Getting apps to see if we should initialize a test // Getting apps to see if we should initialize a test
workflowapps, err := shuffle.GetAllWorkflowApps(ctx, 500) workflowapps, err := shuffle.GetAllWorkflowApps(ctx, 500)
log.Printf("[INFO] Getting and validating workflowapps. Got %d with err %s", len(workflowapps), err) log.Printf("[INFO] Getting and validating workflowapps. Got %d with err %#v", len(workflowapps), err)
if err != nil && len(workflowapps) == 0 { if err != nil && len(workflowapps) == 0 {
log.Printf("[WARNING] Failed getting apps (runInit): %s", err) log.Printf("[WARNING] Failed getting apps (runInit): %s", err)
} else if err == nil { } else if err == nil {
+2 -2
View File
@@ -3461,7 +3461,7 @@ func iterateOpenApiGithub(fs billy.Filesystem, dir []os.FileInfo, extra string,
continue continue
} else { } else {
appCounter += 1 appCounter += 1
log.Printf("Added %s:%s to the database from OpenAPI repo", api.Name, api.AppVersion) log.Printf("[INFO] Added %s:%s to the database from OpenAPI repo", api.Name, api.AppVersion)
// Set OpenAPI datastore // Set OpenAPI datastore
err = shuffle.SetOpenApiDatastore(ctx, parsedOpenApi.ID, parsedOpenApi) err = shuffle.SetOpenApiDatastore(ctx, parsedOpenApi.ID, parsedOpenApi)
@@ -4064,7 +4064,7 @@ func setNewWorkflowApp(resp http.ResponseWriter, request *http.Request) {
resp.Write([]byte(`{"success": false}`)) resp.Write([]byte(`{"success": false}`))
return return
} else { } else {
log.Printf("Added %s:%s to the database", workflowapp.Name, workflowapp.AppVersion) log.Printf("[INFO] Added %s:%s to the database", workflowapp.Name, workflowapp.AppVersion)
} }
cacheKey := fmt.Sprintf("workflowapps-sorted-100") cacheKey := fmt.Sprintf("workflowapps-sorted-100")
+4 -4
View File
@@ -1,8 +1,8 @@
version: '3' version: '3'
services: services:
frontend: frontend:
#build: ./frontend build: ./frontend
image: ghcr.io/frikky/shuffle-frontend:0.8.93 image: ghcr.io/frikky/shuffle-frontend:0.8.96
container_name: shuffle-frontend container_name: shuffle-frontend
hostname: shuffle-frontend hostname: shuffle-frontend
ports: ports:
@@ -16,8 +16,8 @@ services:
depends_on: depends_on:
- backend - backend
backend: backend:
#build: ./backend build: ./backend
image: ghcr.io/frikky/shuffle-backend:0.8.95 image: ghcr.io/frikky/shuffle-backend:0.8.96
container_name: shuffle-backend container_name: shuffle-backend
hostname: ${BACKEND_HOSTNAME} hostname: ${BACKEND_HOSTNAME}
# Here for debugging: # Here for debugging:
+29 -21
View File
@@ -12,8 +12,11 @@ import {Popper, TextField, Drawer, Button, Paper, Grid, Tabs, InputAdornment, Ta
import {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} from '@material-ui/icons'; import {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} from '@material-ui/icons';
import Autocomplete from '@material-ui/lab/Autocomplete'; import Autocomplete from '@material-ui/lab/Autocomplete';
const useStyles = makeStyles((theme) =>
createStyles({ const useStyles = makeStyles({
notchedOutline: {
borderColor: "#f85a3e !important"
},
root: { root: {
"& .MuiAutocomplete-listbox": { "& .MuiAutocomplete-listbox": {
border: "2px solid grey", border: "2px solid grey",
@@ -35,7 +38,12 @@ const useStyles = makeStyles((theme) =>
}, },
} }
}) })
) //const useStyles = makeStyles((theme) =>
// createStyles({
// notchedOutline: {
// borderColor: "#f85a3e !important"
// },
//)
const ParsedAction = (props) => { const ParsedAction = (props) => {
const {workflow, 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 } = props const {workflow, 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 } = props
@@ -678,11 +686,8 @@ const ParsedAction = (props) => {
var datafield = var datafield =
<TextField <TextField
disabled={disabled} disabled={disabled}
style={{backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius,}} style={{backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius, border: selectedActionParameters[count].required || selectedActionParameters[count].configuration ? "2px solid #f85a3e" : "",}}
InputProps={{ InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style:{ style:{
color: "white", color: "white",
minHeight: 50, minHeight: 50,
@@ -1069,20 +1074,26 @@ const ParsedAction = (props) => {
) )
} }
var itemColor = "#f85a3e"
if (!data.required) {
itemColor = "#ffeb3b"
}
var tmpitem = data.name.valueOf() var tmpitem = data.name.valueOf()
if (data.name.startsWith("${") && data.name.endsWith("}")) { if (data.name.startsWith("${") && data.name.endsWith("}")) {
tmpitem = tmpitem.slice(2, data.name.length-1) tmpitem = tmpitem.slice(2, data.name.length-1)
} }
tmpitem = tmpitem.charAt(0).toUpperCase()+tmpitem.substring(1) tmpitem = (tmpitem.charAt(0).toUpperCase()+tmpitem.substring(1)).replaceAll("_", " ")
tmpitem = tmpitem.replaceAll("_", " ")
const description = data.description === undefined ? "" : data.description 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",}}/>*/}
return ( return (
<div key={data.name}> <div key={data.name}>
<div style={{marginTop: 20, marginBottom: 0, display: "flex"}}> <div style={{marginTop: 20, marginBottom: 0, display: "flex"}}>
@@ -1093,10 +1104,10 @@ const ParsedAction = (props) => {
}}/> }}/>
</Tooltip> </Tooltip>
: :
<div style={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10, marginTop: 2, marginTop: "auto", marginBottom: "auto",}}/> null
} }
<div style={{flex: "10", marginTop: "auto", marginBottom: "auto",}}> <div style={{flex: "10", marginTop: "auto", marginBottom: "auto",}}>
<Tooltip title={description} placement="top"> <Tooltip title={tooltipDescription} placement="top">
<b>{tmpitem} </b> <b>{tmpitem} </b>
</Tooltip> </Tooltip>
</div> </div>
@@ -1133,12 +1144,12 @@ const ParsedAction = (props) => {
*/} */}
{(selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0 && selectedActionParameters[count].required === true && selectedActionParameters[count].unique_toggled !== undefined) || hideExtraTypes ? null : {(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"}}> <div style={{display: "flex"}}>
<Tooltip color="primary" title="Value must be unique" placement="top"> <Tooltip color="secondary" title="Value must be unique" placement="top">
<div style={{cursor: "pointer", color: staticcolor}} onClick={(e) => {}}> <div style={{cursor: "pointer", color: staticcolor}} onClick={(e) => {}}>
<Checkbox <Checkbox
checked={selectedActionParameters[count].unique_toggled} checked={selectedActionParameters[count].unique_toggled}
style={{ style={{
color: theme.palette.primary.main, color: theme.palette.primary.secondary,
}} }}
onChange={(event) => { onChange={(event) => {
//console.log("CHECKED!: ", selectedActionParameters[count]) //console.log("CHECKED!: ", selectedActionParameters[count])
@@ -1235,7 +1246,7 @@ const ParsedAction = (props) => {
<span> <span>
<div style={{display: "flex", minHeight: 40, marginBottom: 30}}> <div style={{display: "flex", minHeight: 40, marginBottom: 30}}>
<div style={{flex: 1}}> <div style={{flex: 1}}>
<h3 style={{marginBottom: 5}}>{selectedAction.app_name.replaceAll("_", " ")}</h3> <h3 style={{marginBottom: 5}}>{(selectedAction.app_name.charAt(0).toUpperCase()+selectedAction.app_name.substring(1)).replaceAll("_", " ")}</h3>
<div style={{display: "flex",}}> <div style={{display: "flex",}}>
<IconButton style={{marginTop: "auto", marginBottom: "auto", height: 30, paddingLeft: 0, paddingRight: 0}} onClick={() => { <IconButton style={{marginTop: "auto", marginBottom: "auto", height: 30, paddingLeft: 0, paddingRight: 0}} onClick={() => {
console.log("FIND EXAMPLE RESULTS FOR ", selectedAction) console.log("FIND EXAMPLE RESULTS FOR ", selectedAction)
@@ -1322,9 +1333,6 @@ const ParsedAction = (props) => {
<TextField <TextField
style={theme.palette.textFieldStyle} style={theme.palette.textFieldStyle}
InputProps={{ InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: theme.palette.innerTextfieldStyle, style: theme.palette.innerTextfieldStyle,
}} }}
fullWidth fullWidth
+15 -1
View File
@@ -328,7 +328,21 @@ const data = [{
css: { css: {
'target-arrow-color': '#f85a3e', 'target-arrow-color': '#f85a3e',
}, },
} },
{
selector: `edge[?source_workflow]`,
css: {
"background-opacity": "1",
'font-size': '0px',
},
},
{
selector: `node[?source_workflow]`,
css: {
"background-opacity": "0",
'font-size': '0px',
},
},
] ]
//{ //{
+7 -1
View File
@@ -26,7 +26,13 @@ const theme = createMuiTheme({
maxWidth: "95%", maxWidth: "95%",
fontSize: "1em", fontSize: "1em",
borderRadius: 5, borderRadius: 5,
} },
tooltip: {
backgroundColor: "white",
color: 'rgba(0, 0, 0, 0.87)',
boxShadow: 1,
fontSize: 11,
},
}, },
typography: { typography: {
"fontFamily": `"Roboto", "Helvetica", "Arial", sans-serif`, "fontFamily": `"Roboto", "Helvetica", "Arial", sans-serif`,
+1 -1
View File
@@ -154,7 +154,7 @@ const Admin = (props) => {
// Need to wait because query in ES is too fast // Need to wait because query in ES is too fast
setTimeout(() => { setTimeout(() => {
getAppAuthentication() getAppAuthentication()
}, 1000); }, 1000)
alert.success("Successfully deleted authentication!") alert.success("Successfully deleted authentication!")
} }
}), }),
+221 -4
View File
@@ -1202,8 +1202,10 @@ const AngularWorkflow = (props) => {
}); });
} }
const getWorkflow = () => { const getWorkflow = (workflow_id, sourcenode) => {
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key, { console.log(`Getting workflow ${workflow_id} with append value ${sourcenode}`)
fetch(globalUrl+"/api/v1/workflows/"+workflow_id, {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -1234,6 +1236,114 @@ const AngularWorkflow = (props) => {
//setLastSaved(false) //setLastSaved(false)
} }
// Appends SUBFLOWS. Does NOT run during normal grabbing of workflows.
if (sourcenode.id !== undefined) {
console.log("WORKFLOW: ", responseJson)
var nodefound = false
const target = sourcenode.parameters.find(item => item.name === "startnode")
console.log(sourcenode.parameters)
console.log(target)
const target_id = target === undefined ? "" : target.value
const actions = responseJson.actions.map(action => {
const node = {
group: "nodes",
}
// Set it dynamically?
node.position = {
x: sourcenode.position.x+action.position.x,
y: sourcenode.position.y+action.position.y,
}
node.data = action
node.data._id = action["id"]
node.data.type = "ACTION"
node.data.source_workflow = responseJson.id
if (action.id === target_id) {
nodefound = true
}
var example = ""
if (action.example !== undefined && action.example !== null && action.example.length > 0) {
example = action.example
}
node.data.example = example
return node;
})
var edges = responseJson.branches.map((branch, index) => {
const edge = { };
var conditions = responseJson.branches[index].conditions
if (conditions === undefined || conditions === null) {
conditions = []
}
var label = ""
if (conditions.length === 1) {
label = conditions.length+" condition"
} else if (conditions.length > 1) {
label = conditions.length+" conditions"
}
const sourceFound = actions.findIndex(action => action.data.id === branch.source_id)
if (sourceFound < 0) {
return null
}
const destinationFound = actions.findIndex(action => action.data.id === branch.destination_id)
if (destinationFound < 0) {
return null
}
edge.data = {
id: branch.id,
_id: branch.id,
source: branch.source_id,
target: branch.destination_id,
label: label,
conditions: conditions,
hasErrors: branch.has_errors,
decorator: false,
source_workflow: responseJson.id,
}
return edge;
})
//console.log("Adding node: ", node)
//cy.on('add', 'node', (e) => onNodeAdded(e))
edges = edges.filter(edge => edge !== null)
cy.removeListener('add')
cy.add(actions)
cy.add(edges)
if (nodefound === true) {
const newId = uuid.v4()
cy.add({
group: "edges",
data: {
id: newId,
_id: newId,
source: sourcenode.id,
target: target_id,
label: "Subflow",
decorator: true,
source_workflow: responseJson.id,
}
})
}
cy.fit(null, 100)
//cy.zoom(2.0)
cy.on('add', 'node', (e) => onNodeAdded(e))
cy.on('add', 'edge', (e) => onEdgeAdded(e))
//for (var key in
} else {
setWorkflow(responseJson) setWorkflow(responseJson)
setWorkflowDone(true) setWorkflowDone(true)
@@ -1245,6 +1355,7 @@ const AngularWorkflow = (props) => {
setConfigureWorkflowModalOpen(true) setConfigureWorkflowModalOpen(true)
} }
} }
}
}) })
.catch(error => { .catch(error => {
alert.error(error.toString()) alert.error(error.toString())
@@ -1356,6 +1467,57 @@ const AngularWorkflow = (props) => {
y: 0, y: 0,
} }
const onCtxTap = (event) => {
const nodedata = event.target.data()
console.log(nodedata)
if (nodedata.type === "TRIGGER" && nodedata.app_name === "Shuffle Workflow") {
if (nodedata.parameters === null) {
alert.error("Set a workflow first")
return
}
const workflow_id = nodedata.parameters.find(param => param.name === "workflow")
if (workflow.id === workflow_id.valu) {
return
}
cy.animation({
zoom: 0,
center: {
eles: event.target,
},
})
.play()
.promise()
.then( () => {
console.log("DONE: ", workflow_id)
//cy.elements().remove()
getWorkflow(workflow_id.value, nodedata)
cy.fit(null, 50)
//props.match.params.key
//cy.animation({
// zoom: 500,
// center: {
// eles: cy.nodes(),
// },
//})
//.play()
//.promise()
})
//const animationDuration = 150
//style: {
//maxZoom={2.00}
//cy.animate({
// fit: 100,
//}, {
// duration: 500,
//})
}
}
//cy.on('cxttap', "node", (e) => onCtxTap(e))
var hiddenNodes = [] var hiddenNodes = []
const onNodeDragStop = (event, selectedAction) => { const onNodeDragStop = (event, selectedAction) => {
const nodedata = event.target.data() const nodedata = event.target.data()
@@ -2398,7 +2560,7 @@ const AngularWorkflow = (props) => {
useEffect(() => { useEffect(() => {
if (firstrequest) { if (firstrequest) {
setFirstrequest(false) setFirstrequest(false)
getWorkflow() getWorkflow(props.match.params.key, {})
getApps() getApps()
getAppAuthentication() getAppAuthentication()
getEnvironments() getEnvironments()
@@ -2464,6 +2626,8 @@ const AngularWorkflow = (props) => {
cy.on('drag', 'node', (e) => onNodeDrag(e, selectedAction)) cy.on('drag', 'node', (e) => onNodeDrag(e, selectedAction))
cy.on('free', 'node', (e) => onNodeDragStop(e, selectedAction)) cy.on('free', 'node', (e) => onNodeDragStop(e, selectedAction))
cy.on('cxttap', "node", (e) => onCtxTap(e))
//let popper2 = cy.popper({ //let popper2 = cy.popper({
// content: () => { // content: () => {
// let div = document.createElement('div'); // let div = document.createElement('div');
@@ -5663,8 +5827,11 @@ const AngularWorkflow = (props) => {
workflow.triggers[selectedTriggerIndex].parameters = [] workflow.triggers[selectedTriggerIndex].parameters = []
workflow.triggers[selectedTriggerIndex].parameters[0] = {"name": "url", "value": referenceUrl+"webhook_"+selectedTrigger.id} workflow.triggers[selectedTriggerIndex].parameters[0] = {"name": "url", "value": referenceUrl+"webhook_"+selectedTrigger.id}
workflow.triggers[selectedTriggerIndex].parameters[1] = {"name": "tmp", "value": "webhook_"+selectedTrigger.id} workflow.triggers[selectedTriggerIndex].parameters[1] = {"name": "tmp", "value": "webhook_"+selectedTrigger.id}
workflow.triggers[selectedTriggerIndex].parameters[2] = {"name": "auth_headers", "value": ""}
setWorkflow(workflow) setWorkflow(workflow)
} }
const trigger_header_auth = workflow.triggers[selectedTriggerIndex].parameters.length > 2 ? workflow.triggers[selectedTriggerIndex].parameters[2].value : ""
//const cronValue = "*/15 * * * *" //const cronValue = "*/15 * * * *"
return( return(
@@ -5758,6 +5925,7 @@ const AngularWorkflow = (props) => {
onClick={() => { onClick={() => {
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)
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 */
@@ -5787,10 +5955,47 @@ const AngularWorkflow = (props) => {
setTriggerCronWrapper(e.target.value) setTriggerCronWrapper(e.target.value)
}} }}
/> />
<div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}>
<div style={{width: "17px", height: "17px", borderRadius: 17 / 2, backgroundColor: yellow, marginRight: "10px"}}/>
<div style={{flex: "10"}}>
<b>Required headers</b>
</div>
</div>
<div>
<TextField
style={{backgroundColor: inputColor, borderRadius: theme.palette.borderRadius,}}
id="webhook_uri_header"
onClick={() => {}}
InputProps={{
style:{
color: "white",
marginLeft: "5px",
maxWidth: "95%",
fontSize: "1em",
},
}}
fullWidth
multiline
rows="4"
defaultValue={trigger_header_auth}
color="primary"
placeholder={"AUTH_HEADER=AUTH_VALUE1"}
onBlur={(e) => {
const value = e.target.value
if (selectedTrigger.parameters === null) {
selectedTrigger.parameters = []
}
workflow.triggers[selectedTriggerIndex].parameters[2] = {"value": value, "name": "auth_headers"}
//setSelectedTrigger(workflow.triggers[selectedTr
setWorkflow(workflow)
}}
/>
</div>
<Divider style={{marginTop: "20px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/> <Divider style={{marginTop: "20px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
<div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}> <div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}>
<Button variant="contained" style={{flex: "1",}} disabled={selectedTrigger.status === "running"} onClick={() => { <Button variant="contained" style={{flex: "1",}} disabled={selectedTrigger.status === "running"} onClick={() => {
newWebhook(selectedTrigger) newWebhook(workflow.triggers[selectedTriggerIndex])
}} color="primary"> }} color="primary">
Start Start
</Button> </Button>
@@ -5953,6 +6158,14 @@ const AngularWorkflow = (props) => {
startNode = branch.destination_id startNode = branch.destination_id
} }
const param = trigger.parameters.find(param => param.name === "auth_headers")
console.log("PARAM: ", param)
var auth = ""
if (param !== undefined && param !== null) {
auth = param.value
}
console.log("TRIG: ", trigger)
const data = { const data = {
"name": hookname, "name": hookname,
"type": "webhook", "type": "webhook",
@@ -5960,6 +6173,7 @@ const AngularWorkflow = (props) => {
"workflow": workflow.id, "workflow": workflow.id,
"start": startNode, "start": startNode,
"environment": trigger.environment, "environment": trigger.environment,
"auth": auth,
} }
fetch(globalUrl+"/api/v1/hooks/new", { fetch(globalUrl+"/api/v1/hooks/new", {
@@ -6943,6 +7157,7 @@ const AngularWorkflow = (props) => {
} }
console.log("NEW: ", copy) console.log("NEW: ", copy)
console.log("NAVIGATOR: ", navigator)
navigator.clipboard.writeText(JSON.stringify(copy)) navigator.clipboard.writeText(JSON.stringify(copy))
copyText.select() copyText.select()
@@ -6993,6 +7208,7 @@ const AngularWorkflow = (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) {
console.log("NAVIGATOR: ", navigator)
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 */
@@ -7525,6 +7741,7 @@ const AngularWorkflow = (props) => {
console.log("PRECOPY: ", to_be_copied) console.log("PRECOPY: ", to_be_copied)
if (copyText !== null && copyText !== undefined) { if (copyText !== null && copyText !== undefined) {
console.log("COPY: ", copyText) console.log("COPY: ", copyText)
console.log("NAVIGATOR: ", navigator)
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 */
+22 -5
View File
@@ -659,6 +659,11 @@ const AppCreator = (props) => {
var newbody = {} var newbody = {}
for (var propkey in parameter.properties) { for (var propkey in parameter.properties) {
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase() const parsedkey = propkey.replaceAll(" ", "_").toLowerCase()
if (parameter.properties[propkey].type === undefined) {
console.log("Skipping: ", parameter.properties[propkey])
continue
}
if (parameter.properties[propkey].type === "string") { if (parameter.properties[propkey].type === "string") {
if (parameter.properties[propkey].description !== undefined) { if (parameter.properties[propkey].description !== undefined) {
newbody[parsedkey] = parameter.properties[propkey].description newbody[parsedkey] = parameter.properties[propkey].description
@@ -668,7 +673,7 @@ const AppCreator = (props) => {
} else if (parameter.properties[propkey].type.includes("int")) { } else if (parameter.properties[propkey].type.includes("int")) {
newbody[parsedkey] = 0 newbody[parsedkey] = 0
} else { } else {
console.log("CANT HANDLE TYPE ", parameter.properties[propkey].type) console.log("CANT HANDLE JSON TYPE ", parameter.properties[propkey].type, parameter.properties[propkey])
newbody[parsedkey] = [] newbody[parsedkey] = []
} }
} }
@@ -690,6 +695,11 @@ const AppCreator = (props) => {
var newbody = {} var newbody = {}
for (var propkey in parameter.properties) { for (var propkey in parameter.properties) {
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase() const parsedkey = propkey.replaceAll(" ", "_").toLowerCase()
if (parameter.properties[propkey].type === undefined) {
console.log("Skipping: ", parameter.properties[propkey])
continue
}
if (parameter.properties[propkey].type === "string") { if (parameter.properties[propkey].type === "string") {
if (parameter.properties[propkey].description !== undefined) { if (parameter.properties[propkey].description !== undefined) {
newbody[parsedkey] = parameter.properties[propkey].description newbody[parsedkey] = parameter.properties[propkey].description
@@ -699,7 +709,7 @@ const AppCreator = (props) => {
} else if (parameter.properties[propkey].type.includes("int")) { } else if (parameter.properties[propkey].type.includes("int")) {
newbody[parsedkey] = 0 newbody[parsedkey] = 0
} else { } else {
console.log("CANT HANDLE TYPE ", parameter.properties[propkey].type) console.log("CANT HANDLE JSON TYPE (2) ", parameter.properties[propkey].type)
newbody[parsedkey] = [] newbody[parsedkey] = []
} }
} }
@@ -720,16 +730,22 @@ const AppCreator = (props) => {
var newbody = {} var newbody = {}
for (var propkey in parameter.properties) { for (var propkey in parameter.properties) {
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase() const parsedkey = propkey.replaceAll(" ", "_").toLowerCase()
if (parameter.properties[propkey].type === undefined) {
console.log("Skipping: ", parameter.properties[propkey])
continue
}
if (parameter.properties[propkey].type === "string") { if (parameter.properties[propkey].type === "string") {
if (parameter.properties[propkey].description !== undefined) { if (parameter.properties[propkey].description !== undefined) {
newbody[parsedkey] = parameter.properties[propkey].description newbody[parsedkey] = parameter.properties[propkey].description
} else { } else {
newbody[parsedkey] = "" newbody[parsedkey] = ""
} }
console.log(parameter.properties[propkey])
} else if (parameter.properties[propkey].type.includes("int")) { } else if (parameter.properties[propkey].type.includes("int")) {
newbody[parsedkey] = 0 newbody[parsedkey] = 0
} else { } else {
console.log("CANT HANDLE TYPE ", parameter.properties[propkey].type) console.log("CANT HANDLE JSON TYPE (3) ", parameter.properties[propkey].type)
newbody[parsedkey] = [] newbody[parsedkey] = []
} }
} }
@@ -882,6 +898,8 @@ const AppCreator = (props) => {
if (value.scheme === "bearer") { if (value.scheme === "bearer") {
setAuthenticationOption("Bearer auth") setAuthenticationOption("Bearer auth")
setAuthenticationRequired(true) setAuthenticationRequired(true)
} else if (key === "oauth2") {
alert.info("Can't handle Oauth2 auth yet.")
} else if (key === "ApiKeyAuth") { } else if (key === "ApiKeyAuth") {
setAuthenticationOption("API key") setAuthenticationOption("API key")
@@ -1460,7 +1478,7 @@ const AppCreator = (props) => {
const extraKeys = const extraKeys =
<div style={{marginTop: 50}}> <div style={{marginTop: 50}}>
<div style={{display: "flex"}}> <div style={{display: "flex"}}>
<Typography variant="body1">Extra authentication options</Typography> <Typography variant="body1">Add global headers or queries</Typography>
{extraAuth.length === 0 ? {extraAuth.length === 0 ?
<Button color="primary" style={{maxWidth: 50, marginLeft: 15, }} variant="contained" onClick={() => { <Button color="primary" style={{maxWidth: 50, marginLeft: 15, }} variant="contained" onClick={() => {
console.log("ADD NEW!") console.log("ADD NEW!")
@@ -1506,7 +1524,6 @@ const AppCreator = (props) => {
style={{height: 50, marginTop: 0, marginBottom: 0, flex: 2, backgroundColor: inputColor, marginRight: 5,}} style={{height: 50, marginTop: 0, marginBottom: 0, flex: 2, backgroundColor: inputColor, marginRight: 5,}}
fullWidth={true} fullWidth={true}
placeholder="Example - input an example for the user" placeholder="Example - input an example for the user"
type="name"
id="standard-required" id="standard-required"
margin="normal" margin="normal"
variant="outlined" variant="outlined"
+3
View File
@@ -243,6 +243,7 @@ const Apps = (props) => {
privateapps.push(...invalid) privateapps.push(...invalid)
setApps(privateapps) setApps(privateapps)
setCursearch("")
//handleSearchChange(event.target.value) //handleSearchChange(event.target.value)
//setCursearch(event.target.value) //setCursearch(event.target.value)
@@ -1241,7 +1242,9 @@ const Apps = (props) => {
.then((response) => { .then((response) => {
if (response.status === 200) { if (response.status === 200) {
alert.success("Successfully deleted app") alert.success("Successfully deleted app")
setTimeout(() => {
getApps() getApps()
}, 1000);
} else { } else {
alert.error("Failed deleting app") alert.error("Failed deleting app")
} }
+2
View File
@@ -458,7 +458,9 @@ const Workflows = (props) => {
console.log("Editing: ", editingWorkflow) console.log("Editing: ", editingWorkflow)
if (selectedWorkflowId) { if (selectedWorkflowId) {
deleteWorkflow(selectedWorkflowId) deleteWorkflow(selectedWorkflowId)
setTimeout(() => {
getAvailableWorkflows() getAvailableWorkflows()
}, 1000)
} }
setDeleteModalOpen(false) setDeleteModalOpen(false)
}} color="primary"> }} color="primary">