#60: Created API endpoint to hotload apps from directory
@@ -13,4 +13,4 @@ BACKEND_PORT=5001
|
|||||||
FRONTEND_PORT=3001
|
FRONTEND_PORT=3001
|
||||||
FRONTEND_PORT_HTTPS=3443
|
FRONTEND_PORT_HTTPS=3443
|
||||||
OUTER_HOSTNAME=shuffle-backend
|
OUTER_HOSTNAME=shuffle-backend
|
||||||
DB_LOCATION=/etc/shuffle
|
DB_LOCATION=./shuffle-database
|
||||||
|
|||||||
@@ -3,21 +3,30 @@
|
|||||||
|
|
||||||
**It's in BETA** - [Get in touch](https://shuffler.io/contact), send a mail to [frikky@shuffler.io](mailto:frikky@shuffler.io) or poke me on twitter [@frikkylikeme](https://twitter.com/frikkylikeme)
|
**It's in BETA** - [Get in touch](https://shuffler.io/contact), send a mail to [frikky@shuffler.io](mailto:frikky@shuffler.io) or poke me on twitter [@frikkylikeme](https://twitter.com/frikkylikeme)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Try it
|
## Try it
|
||||||
* Self-hosted: Check out the [installation guide](https://github.com/frikky/shuffle/blob/master/install-guide.md).
|
* Self-hosted: Check out the [installation guide](https://github.com/frikky/shuffle/blob/master/install-guide.md).
|
||||||
* Cloud: Register at https://shuffler.io/register and get cooking (old, missing a lot of features)
|
* Cloud: Register at https://shuffler.io/register and get cooking (missing a lot of features)
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
* Self-hosted: Check out the [installation guide](https://github.com/frikky/shuffle/blob/master/install-guide.md) and [getting started](https://shuffler.io/docs/getting_started)
|
||||||
|
* Cloud: Register at https://shuffler.io/register and get cooking (there are some differences!)
|
||||||
|
|
||||||
|
## Blogposts
|
||||||
|
* [1. Introducing Shuffle](https://medium.com/security-operation-capybara/introducing-shuffle-an-open-source-soar-platform-part-1-58a529de7d12)
|
||||||
|
* [2. Getting started with Shuffle](https://medium.com/security-operation-capybara/getting-started-with-shuffle-an-open-source-soar-platform-part-2-1d7c67a64244)
|
||||||
|
* [3. Integrating Shuffle with Virustotal and TheHive](https://medium.com/@Frikkylikeme/integrating-shuffle-with-virustotal-and-thehive-open-source-soar-part-3-8e2e0d3396a9)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
[Documentation](https://shuffler.io/docs) can be found on https://shuffler.io/docs and is written in https://github.com/frikky/shuffle-docs.
|
||||||
|
|
||||||
## Related repositories
|
## Related repositories
|
||||||
* Apps: https://github.com/frikky/shuffle-apps
|
* Apps: https://github.com/frikky/shuffle-apps
|
||||||
* Workflows: https://github.com/frikky/shuffle-workflows (empty)
|
* Workflows: https://github.com/frikky/shuffle-workflows
|
||||||
* Security OpenAPI apps: https://github.com/frikky/OpenAPI-security-definitions
|
* Security OpenAPI apps: https://github.com/frikky/security-openapis
|
||||||
* Documentation: https://github.com/frikky/shuffle-docs
|
* Documentation: https://github.com/frikky/shuffle-docs
|
||||||
|
|
||||||
## Documentation
|
|
||||||
Documentation can be found on https://shuffler.io/docs.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Simple workflow automation editor
|
* Simple workflow automation editor
|
||||||
* Premade apps for a number of security tools
|
* Premade apps for a number of security tools
|
||||||
|
|||||||
@@ -73,12 +73,9 @@ class AppBase:
|
|||||||
except requests.exceptions.ConnectionError as e:
|
except requests.exceptions.ConnectionError as e:
|
||||||
print("Connectionerror: %s" % e)
|
print("Connectionerror: %s" % e)
|
||||||
return
|
return
|
||||||
#self.logger.info("AFTER initial stream result")
|
|
||||||
self.logger.info("THIS IS THE NEW UPDATE")
|
|
||||||
|
|
||||||
# Verify whether there are any parameters with ACTION_RESULT required
|
# Verify whether there are any parameters with ACTION_RESULT required
|
||||||
# If found, we get the full results list from backend
|
# If found, we get the full results list from backend
|
||||||
|
|
||||||
fullexecution = {}
|
fullexecution = {}
|
||||||
try:
|
try:
|
||||||
tmpdata = {
|
tmpdata = {
|
||||||
@@ -195,10 +192,9 @@ class AppBase:
|
|||||||
# Regex to find all the things
|
# Regex to find all the things
|
||||||
if parameter["variant"] == "STATIC_VALUE":
|
if parameter["variant"] == "STATIC_VALUE":
|
||||||
data = parameter["value"]
|
data = parameter["value"]
|
||||||
self.logger.debug(f"\n\nHandle static data with JSON: {data}\n\n")
|
|
||||||
|
|
||||||
actualitem = re.findall(match, data, re.MULTILINE)
|
actualitem = re.findall(match, data, re.MULTILINE)
|
||||||
self.logger.info("STATIC PARSED: %s" % actualitem)
|
#self.logger.debug(f"\n\nHandle static data with JSON: {data}\n\n")
|
||||||
|
#self.logger.info("STATIC PARSED: %s" % actualitem)
|
||||||
if len(actualitem) > 0:
|
if len(actualitem) > 0:
|
||||||
for replace in actualitem:
|
for replace in actualitem:
|
||||||
try:
|
try:
|
||||||
@@ -487,7 +483,6 @@ class AppBase:
|
|||||||
# With this parameter ready, add it to... a greater list of parameters. Rofl
|
# With this parameter ready, add it to... a greater list of parameters. Rofl
|
||||||
multi_parameters[parameter["name"]] = resultarray
|
multi_parameters[parameter["name"]] = resultarray
|
||||||
else:
|
else:
|
||||||
print("Hello, in here?: %s" % value)
|
|
||||||
params[parameter["name"]] = value
|
params[parameter["name"]] = value
|
||||||
multi_parameters[parameter["name"]] = value
|
multi_parameters[parameter["name"]] = value
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,9 @@ func buildStructure(swagger *openapi3.Swagger, curHash string) (string, error) {
|
|||||||
return appPath, nil
|
return appPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePythoncode(swagger *openapi3.Swagger, name, url, method string, parameters, optionalQueries []string) (string, string) {
|
// This function generates the python code that's being used.
|
||||||
|
// This is really meta when you program it. Handling parameters is hard here.
|
||||||
|
func makePythoncode(swagger *openapi3.Swagger, name, url, method string, parameters, optionalQueries, headers []string) (string, string) {
|
||||||
method = strings.ToLower(method)
|
method = strings.ToLower(method)
|
||||||
queryString := ""
|
queryString := ""
|
||||||
queryData := ""
|
queryData := ""
|
||||||
@@ -259,9 +261,6 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// How to add authentication?
|
|
||||||
// I think it should be like:
|
|
||||||
// async def(self, auth, baseurl, data):
|
|
||||||
// api.Authentication.Parameters[0].Value = "BearerAuth"
|
// api.Authentication.Parameters[0].Value = "BearerAuth"
|
||||||
authenticationParameter := ""
|
authenticationParameter := ""
|
||||||
authenticationSetup := ""
|
authenticationSetup := ""
|
||||||
@@ -270,14 +269,15 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
if swagger.Components.SecuritySchemes != nil {
|
if swagger.Components.SecuritySchemes != nil {
|
||||||
if swagger.Components.SecuritySchemes["BearerAuth"] != nil {
|
if swagger.Components.SecuritySchemes["BearerAuth"] != nil {
|
||||||
authenticationParameter = ", apikey"
|
authenticationParameter = ", apikey"
|
||||||
authenticationSetup = "headers[\"Authorization\"] = f\"Bearer {apikey}\""
|
authenticationSetup = "if apikey != \" \": headers[\"Authorization\"] = f\"Bearer {apikey}\""
|
||||||
} else if swagger.Components.SecuritySchemes["BasicAuth"] != nil {
|
} else if swagger.Components.SecuritySchemes["BasicAuth"] != nil {
|
||||||
authenticationParameter = ", username, password"
|
authenticationParameter = ", username, password"
|
||||||
authenticationAddin = ", auth=(username, password)"
|
authenticationAddin = ", auth=(username, password)"
|
||||||
} else if swagger.Components.SecuritySchemes["ApiKeyAuth"] != nil {
|
} else if swagger.Components.SecuritySchemes["ApiKeyAuth"] != nil {
|
||||||
authenticationParameter = ", apikey"
|
authenticationParameter = ", apikey"
|
||||||
if swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.In == "header" {
|
if swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.In == "header" {
|
||||||
authenticationSetup = fmt.Sprintf("headers[\"%s\"] = apikey", swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name)
|
// This is a way to bypass apikeys by passing " "
|
||||||
|
authenticationSetup = fmt.Sprintf(`if apikey != " ": headers["%s"] = apikey`, swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name)
|
||||||
} else if swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.In == "query" {
|
} else if swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.In == "query" {
|
||||||
// This might suck lol
|
// This might suck lol
|
||||||
key := "?"
|
key := "?"
|
||||||
@@ -285,7 +285,7 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
key = "&"
|
key = "&"
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticationSetup = fmt.Sprintf("url+=f\"%s%s={apikey}\"", key, swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name)
|
authenticationSetup = fmt.Sprintf("if apikey != \" \": url+=f\"%s%s={apikey}\"", key, swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,6 +301,23 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
urlInline = "{url}"
|
urlInline = "{url}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specific check for SSL verification
|
||||||
|
// This is critical for onprem stuff.
|
||||||
|
verifyParam := ""
|
||||||
|
verifyWrapper := ""
|
||||||
|
verifyAddin := ""
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
verifyParam = ", verify=True"
|
||||||
|
verifyWrapper = `if type(ssl_verify) == str: ssl_verify = False if ssl_verify.lower() == "false" or ssl_verify == "0" else True`
|
||||||
|
verifyAddin = ", verify=ssl_verify"
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
verifyParam = ", ssl_verify=True"
|
||||||
|
verifyWrapper = `if type(ssl_verify) == str: ssl_verify = False if ssl_verify.lower() == "false" or ssl_verify == "0" else True`
|
||||||
|
verifyAddin = ", verify=ssl_verify"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(parameters) > 0 {
|
if len(parameters) > 0 {
|
||||||
parameterData = fmt.Sprintf(", %s", strings.Join(parameters, ", "))
|
parameterData = fmt.Sprintf(", %s", strings.Join(parameters, ", "))
|
||||||
}
|
}
|
||||||
@@ -333,15 +350,39 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preparedHeaders := "headers={}"
|
||||||
|
if len(headers) > 0 {
|
||||||
|
preparedHeaders = "headers={"
|
||||||
|
for count, header := range headers {
|
||||||
|
headerSplit := strings.Split(header, "=")
|
||||||
|
added := false
|
||||||
|
if len(headerSplit) == 2 {
|
||||||
|
if strings.Contains(preparedHeaders, headerSplit[0]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
preparedHeaders += fmt.Sprintf(`"%s": "%s"`, headerSplit[0], headerSplit[1])
|
||||||
|
added = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if count != len(headers)-1 && added {
|
||||||
|
preparedHeaders += ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preparedHeaders += "}"
|
||||||
|
}
|
||||||
|
|
||||||
// Extra param for url if it's changeable
|
// Extra param for url if it's changeable
|
||||||
// Extra param for authentication scheme(s)
|
// Extra param for authentication scheme(s)
|
||||||
data := fmt.Sprintf(` async def %s(self%s%s%s%s%s):
|
data := fmt.Sprintf(` async def %s(self%s%s%s%s%s%s):
|
||||||
headers={}
|
%s
|
||||||
url=f"%s%s"
|
url=f"%s%s"
|
||||||
%s
|
%s
|
||||||
|
%s
|
||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
return requests.%s(url, headers=headers%s%s).text
|
return requests.%s(url, headers=headers%s%s%s).text
|
||||||
`,
|
`,
|
||||||
functionname,
|
functionname,
|
||||||
authenticationParameter,
|
authenticationParameter,
|
||||||
@@ -349,14 +390,18 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
parameterData,
|
parameterData,
|
||||||
queryString,
|
queryString,
|
||||||
bodyParameter,
|
bodyParameter,
|
||||||
|
verifyParam,
|
||||||
|
preparedHeaders,
|
||||||
urlInline,
|
urlInline,
|
||||||
url,
|
url,
|
||||||
|
verifyWrapper,
|
||||||
authenticationSetup,
|
authenticationSetup,
|
||||||
queryData,
|
queryData,
|
||||||
bodyFormatter,
|
bodyFormatter,
|
||||||
method,
|
method,
|
||||||
authenticationAddin,
|
authenticationAddin,
|
||||||
bodyAddin,
|
bodyAddin,
|
||||||
|
verifyAddin,
|
||||||
)
|
)
|
||||||
|
|
||||||
//log.Println(data)
|
//log.Println(data)
|
||||||
@@ -412,7 +457,6 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
|
|||||||
//log.Printf("%s", j)
|
//log.Printf("%s", j)
|
||||||
api.SmallImage = string(j)
|
api.SmallImage = string(j)
|
||||||
api.LargeImage = string(j)
|
api.LargeImage = string(j)
|
||||||
log.Printf("Set images!")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,6 +488,7 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
|
|||||||
Description: "The apikey to use",
|
Description: "The apikey to use",
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: true,
|
Required: true,
|
||||||
|
Example: "The API key to use. Space = skip",
|
||||||
Schema: SchemaDefinition{
|
Schema: SchemaDefinition{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
},
|
},
|
||||||
@@ -460,6 +505,7 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
|
|||||||
Description: "The apikey to use",
|
Description: "The apikey to use",
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: true,
|
Required: true,
|
||||||
|
Example: "The API key to use. Space = skip",
|
||||||
Schema: SchemaDefinition{
|
Schema: SchemaDefinition{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
},
|
},
|
||||||
@@ -475,6 +521,7 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
|
|||||||
Description: "The username to use",
|
Description: "The username to use",
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: true,
|
Required: true,
|
||||||
|
Example: "The username to use",
|
||||||
Schema: SchemaDefinition{
|
Schema: SchemaDefinition{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
},
|
},
|
||||||
@@ -484,6 +531,7 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
|
|||||||
Description: "The password to use",
|
Description: "The password to use",
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: true,
|
Required: true,
|
||||||
|
Example: "The password to use",
|
||||||
Schema: SchemaDefinition{
|
Schema: SchemaDefinition{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
},
|
},
|
||||||
@@ -508,7 +556,11 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
|
|||||||
// Could just as well be go at this point lol
|
// Could just as well be go at this point lol
|
||||||
pythonFunctions := []string{}
|
pythonFunctions := []string{}
|
||||||
for actualPath, path := range swagger.Paths {
|
for actualPath, path := range swagger.Paths {
|
||||||
// FIXME: Add everything from here:
|
actualPath = strings.Replace(actualPath, " ", "_", -1)
|
||||||
|
actualPath = strings.Replace(actualPath, ".", "", -1)
|
||||||
|
actualPath = strings.Replace(actualPath, ".", "", -1)
|
||||||
|
actualPath = strings.Replace(actualPath, "\\", "", -1)
|
||||||
|
|
||||||
// https://godoc.org/github.com/getkin/kin-openapi/openapi3#PathItem
|
// https://godoc.org/github.com/getkin/kin-openapi/openapi3#PathItem
|
||||||
if path.Get != nil {
|
if path.Get != nil {
|
||||||
action, curCode := handleGet(swagger, api, extraParameters, path, actualPath)
|
action, curCode := handleGet(swagger, api, extraParameters, path, actualPath)
|
||||||
@@ -759,13 +811,52 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [
|
|||||||
optionalQueries := []string{}
|
optionalQueries := []string{}
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Connect.Parameters) > 0 {
|
if len(path.Connect.Parameters) > 0 {
|
||||||
for _, param := range path.Connect.Parameters {
|
for counter, param := range path.Connect.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Connect.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -792,15 +883,8 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
//log.Printf("PATH!: %s", param.Value.Name)
|
parameters = append(parameters, curParam.Name)
|
||||||
parameters = append(parameters, param.Value.Name)
|
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
//log.Printf("QUERY!: %s", param.Value.Name)
|
//log.Printf("QUERY!: %s", param.Value.Name)
|
||||||
@@ -823,6 +907,12 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [
|
|||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +922,7 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "connect", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "connect", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
@@ -857,8 +947,6 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
action.Returns.Schema.Type = "string"
|
action.Returns.Schema.Type = "string"
|
||||||
baseUrl := fmt.Sprintf("%s%s", api.Link, actualPath)
|
baseUrl := fmt.Sprintf("%s%s", api.Link, actualPath)
|
||||||
|
|
||||||
//log.Println(path.Parameters)
|
|
||||||
|
|
||||||
// Parameters: []WorkflowAppActionParameter{},
|
// Parameters: []WorkflowAppActionParameter{},
|
||||||
// FIXME - add data for POST stuff
|
// FIXME - add data for POST stuff
|
||||||
firstQuery := true
|
firstQuery := true
|
||||||
@@ -866,16 +954,53 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
|
|
||||||
// FIXME - remove this when authentication is properly introduced
|
// FIXME - remove this when authentication is properly introduced
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
|
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify the SSL certificate request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "False - default=True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Get.Parameters) > 0 {
|
if len(path.Get.Parameters) > 0 {
|
||||||
for _, param := range path.Get.Parameters {
|
for counter, param := range path.Get.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Get.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -902,15 +1027,8 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
log.Printf("PATH!: %s", param.Value.Name)
|
parameters = append(parameters, curParam.Name)
|
||||||
parameters = append(parameters, param.Value.Name)
|
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
//log.Printf("QUERY!: %s", param.Value.Name)
|
//log.Printf("QUERY!: %s", param.Value.Name)
|
||||||
@@ -933,6 +1051,11 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
}
|
}
|
||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -943,7 +1066,7 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "get", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "get", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
@@ -976,13 +1099,52 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
optionalQueries := []string{}
|
optionalQueries := []string{}
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Head.Parameters) > 0 {
|
if len(path.Head.Parameters) > 0 {
|
||||||
for _, param := range path.Head.Parameters {
|
for counter, param := range path.Head.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Head.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -1009,15 +1171,8 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
//log.Printf("PATH!: %s", param.Value.Name)
|
parameters = append(parameters, curParam.Name)
|
||||||
parameters = append(parameters, param.Value.Name)
|
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
//log.Printf("QUERY!: %s", param.Value.Name)
|
//log.Printf("QUERY!: %s", param.Value.Name)
|
||||||
@@ -1040,6 +1195,12 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1049,7 +1210,7 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "head", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "head", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
@@ -1082,13 +1243,52 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []
|
|||||||
optionalQueries := []string{}
|
optionalQueries := []string{}
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Delete.Parameters) > 0 {
|
if len(path.Delete.Parameters) > 0 {
|
||||||
for _, param := range path.Delete.Parameters {
|
for counter, param := range path.Delete.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Delete.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -1115,15 +1315,8 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
//log.Printf("PATH!: %s", param.Value.Name)
|
parameters = append(parameters, curParam.Name)
|
||||||
parameters = append(parameters, param.Value.Name)
|
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
//log.Printf("QUERY!: %s", param.Value.Name)
|
//log.Printf("QUERY!: %s", param.Value.Name)
|
||||||
@@ -1146,6 +1339,12 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []
|
|||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1155,7 +1354,7 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "delete", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "delete", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
@@ -1178,10 +1377,6 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
Parameters: extraParameters,
|
Parameters: extraParameters,
|
||||||
}
|
}
|
||||||
|
|
||||||
if path.Post.RequestBody != nil {
|
|
||||||
log.Printf("RequestBody: %#v", path.Post.RequestBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
action.Returns.Schema.Type = "string"
|
action.Returns.Schema.Type = "string"
|
||||||
baseUrl := fmt.Sprintf("%s%s", api.Link, actualPath)
|
baseUrl := fmt.Sprintf("%s%s", api.Link, actualPath)
|
||||||
|
|
||||||
@@ -1191,15 +1386,52 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
optionalQueries := []string{}
|
optionalQueries := []string{}
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Post.Parameters) > 0 {
|
if len(path.Post.Parameters) > 0 {
|
||||||
for _, param := range path.Post.Parameters {
|
for counter, param := range path.Post.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Post.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -1212,7 +1444,7 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
if param.Value.Example != nil {
|
if param.Value.Example != nil {
|
||||||
curParam.Example = param.Value.Example.(string)
|
curParam.Example = param.Value.Example.(string)
|
||||||
|
|
||||||
if param.Value.Name == "body" {
|
if parsedName == "body" {
|
||||||
curParam.Value = param.Value.Example.(string)
|
curParam.Value = param.Value.Example.(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1226,15 +1458,8 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
//log.Printf("PATH!: %s", param.Value.Name)
|
parameters = append(parameters, curParam.Name)
|
||||||
parameters = append(parameters, param.Value.Name)
|
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
//log.Printf("QUERY!: %s", param.Value.Name)
|
//log.Printf("QUERY!: %s", param.Value.Name)
|
||||||
@@ -1257,6 +1482,11 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1266,7 +1496,7 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "post", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "post", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
@@ -1299,13 +1529,52 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W
|
|||||||
optionalQueries := []string{}
|
optionalQueries := []string{}
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Patch.Parameters) > 0 {
|
if len(path.Patch.Parameters) > 0 {
|
||||||
for _, param := range path.Patch.Parameters {
|
for counter, param := range path.Patch.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Patch.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -1332,15 +1601,8 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
//log.Printf("PATH!: %s", param.Value.Name)
|
parameters = append(parameters, curParam.Name)
|
||||||
parameters = append(parameters, param.Value.Name)
|
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
//log.Printf("QUERY!: %s", param.Value.Name)
|
//log.Printf("QUERY!: %s", param.Value.Name)
|
||||||
@@ -1363,6 +1625,11 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W
|
|||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1372,7 +1639,7 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "patch", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "delete", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
@@ -1405,14 +1672,52 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
optionalQueries := []string{}
|
optionalQueries := []string{}
|
||||||
parameters := []string{}
|
parameters := []string{}
|
||||||
optionalParameters := []WorkflowAppActionParameter{}
|
optionalParameters := []WorkflowAppActionParameter{}
|
||||||
|
if len(swagger.Servers) == 0 {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if swagger.Servers[0].URL == "" {
|
||||||
|
optionalParameters = append(optionalParameters, WorkflowAppActionParameter{
|
||||||
|
Name: "ssl_verify",
|
||||||
|
Description: "Check if you want to verify request",
|
||||||
|
Multiline: false,
|
||||||
|
Required: false,
|
||||||
|
Example: "True",
|
||||||
|
Schema: SchemaDefinition{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headersFound := []string{}
|
||||||
if len(path.Put.Parameters) > 0 {
|
if len(path.Put.Parameters) > 0 {
|
||||||
for _, param := range path.Put.Parameters {
|
for counter, param := range path.Put.Parameters {
|
||||||
if param.Value.Schema == nil || param.Value.In == "header" {
|
if param.Value.Schema == nil {
|
||||||
|
continue
|
||||||
|
} else if param.Value.In == "header" {
|
||||||
|
headersFound = append(headersFound, fmt.Sprintf("%s=%s", param.Value.Name, param.Value.Example))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsedName := param.Value.Name
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, " ", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ",", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, ".", "_")
|
||||||
|
parsedName = strings.ReplaceAll(parsedName, "|", "_")
|
||||||
|
param.Value.Name = parsedName
|
||||||
|
path.Put.Parameters[counter].Value.Name = parsedName
|
||||||
|
|
||||||
curParam := WorkflowAppActionParameter{
|
curParam := WorkflowAppActionParameter{
|
||||||
Name: param.Value.Name,
|
Name: parsedName,
|
||||||
Description: param.Value.Description,
|
Description: param.Value.Description,
|
||||||
Multiline: false,
|
Multiline: false,
|
||||||
Required: param.Value.Required,
|
Required: param.Value.Required,
|
||||||
@@ -1439,14 +1744,7 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Value.Required {
|
|
||||||
action.Parameters = append(action.Parameters, curParam)
|
|
||||||
} else {
|
|
||||||
optionalParameters = append(optionalParameters, curParam)
|
|
||||||
}
|
|
||||||
|
|
||||||
if param.Value.In == "path" {
|
if param.Value.In == "path" {
|
||||||
//log.Printf("PATH!: %s", param.Value.Name)
|
|
||||||
parameters = append(parameters, param.Value.Name)
|
parameters = append(parameters, param.Value.Name)
|
||||||
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
//baseUrl = fmt.Sprintf("%s%s", baseUrl)
|
||||||
} else if param.Value.In == "query" {
|
} else if param.Value.In == "query" {
|
||||||
@@ -1470,6 +1768,12 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
firstQuery = false
|
firstQuery = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if param.Value.Required {
|
||||||
|
action.Parameters = append(action.Parameters, curParam)
|
||||||
|
} else {
|
||||||
|
optionalParameters = append(optionalParameters, curParam)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1479,7 +1783,7 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
|
|||||||
action.Parameters = append(action.Parameters, optionalParam)
|
action.Parameters = append(action.Parameters, optionalParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "put", parameters, optionalQueries)
|
functionname, curCode := makePythoncode(swagger, functionName, baseUrl, "delete", parameters, optionalQueries, headersFound)
|
||||||
|
|
||||||
if len(functionname) > 0 {
|
if len(functionname) > 0 {
|
||||||
action.Name = functionname
|
action.Name = functionname
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -36,7 +37,9 @@ import (
|
|||||||
"github.com/google/go-github/v28/github"
|
"github.com/google/go-github/v28/github"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
|
"github.com/go-git/go-billy/v5"
|
||||||
"github.com/go-git/go-billy/v5/memfs"
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
|
"github.com/go-git/go-billy/v5/osfs"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/storage/memory"
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
|
||||||
@@ -238,7 +241,7 @@ type AppInfo struct {
|
|||||||
type ScheduleOld struct {
|
type ScheduleOld struct {
|
||||||
Id string `json:"id" datastore:"id"`
|
Id string `json:"id" datastore:"id"`
|
||||||
Seconds int `json:"seconds" datastore:"seconds"`
|
Seconds int `json:"seconds" datastore:"seconds"`
|
||||||
WorkflowId string `json:"workflow_id datastore:"workflow_id", `
|
WorkflowId string `json:"workflow_id" datastore:"workflow_id", `
|
||||||
Argument string `json:"argument" datastore:"argument"`
|
Argument string `json:"argument" datastore:"argument"`
|
||||||
AppInfo AppInfo `json:"appinfo" datastore:"appinfo,noindex"`
|
AppInfo AppInfo `json:"appinfo" datastore:"appinfo,noindex"`
|
||||||
Finished bool `json:"finished" finished:"id"`
|
Finished bool `json:"finished" finished:"id"`
|
||||||
@@ -1803,6 +1806,49 @@ func getUserCount() (int, error) {
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleGetSchedules(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
cors := handleCors(resp, request)
|
||||||
|
if cors {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := handleApiAuthentication(resp, request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Role != "admin" {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Admin required"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
schedules, err := getAllSchedules(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed getting schedules: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Couldn't get schedules"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newjson, err := json.Marshal(schedules)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed unmarshal: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed unpacking environments"}`)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("Existing environments: %s", string(newjson))
|
||||||
|
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write(newjson)
|
||||||
|
}
|
||||||
|
|
||||||
func handleGetEnvironments(resp http.ResponseWriter, request *http.Request) {
|
func handleGetEnvironments(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
@@ -1897,10 +1943,12 @@ func handleGetUsers(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
|
func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
log.Printf("HELLO?")
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("HELLO2?")
|
||||||
|
|
||||||
count, err := getUserCount()
|
count, err := getUserCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2635,6 +2683,21 @@ func handleDeleteSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user, err := handleApiAuthentication(resp, request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: IAM - Get workflow and check owner
|
||||||
|
if user.Role != "admin" {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Admin required"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
location := strings.Split(request.URL.String(), "/")
|
location := strings.Split(request.URL.String(), "/")
|
||||||
|
|
||||||
var workflowId string
|
var workflowId string
|
||||||
@@ -2655,7 +2718,7 @@ func handleDeleteSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := DeleteKey(ctx, "schedules", workflowId)
|
err = DeleteKey(ctx, "schedules", workflowId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "message": "Can't delete"}`))
|
resp.Write([]byte(`{"success": false, "message": "Can't delete"}`))
|
||||||
@@ -4648,7 +4711,7 @@ func handleDeleteOutlookSub(resp http.ResponseWriter, request *http.Request) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
workflow, err := getWorkflow(ctx, workflowId)
|
workflow, err := getWorkflow(ctx, workflowId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed getting the workflow locally: %s", err)
|
log.Printf("Failed getting the workflow locally (delete outlook): %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -4782,7 +4845,7 @@ func createOutlookSub(resp http.ResponseWriter, request *http.Request) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
workflow, err := getWorkflow(ctx, workflowId)
|
workflow, err := getWorkflow(ctx, workflowId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed getting the workflow locally: %s", err)
|
log.Printf("Failed getting the workflow locally (outlook sub): %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -5729,6 +5792,86 @@ func healthCheckHandler(resp http.ResponseWriter, request *http.Request) {
|
|||||||
fmt.Fprint(resp, "OK")
|
fmt.Fprint(resp, "OK")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates osfs from folderpath with a basepath as directory base
|
||||||
|
func createFs(basepath, pathname string) (billy.Filesystem, error) {
|
||||||
|
fs := osfs.New("")
|
||||||
|
|
||||||
|
err := filepath.Walk(pathname,
|
||||||
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(path, ".git") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fullpath := fmt.Sprintf("%s%s", basepath, path)
|
||||||
|
switch mode := info.Mode(); {
|
||||||
|
case mode.IsDir():
|
||||||
|
err = fs.MkdirAll(fullpath, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed making folder: %s", err)
|
||||||
|
}
|
||||||
|
case mode.IsRegular():
|
||||||
|
srcData, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Src error: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//if strings.Contains(path, "yaml") {
|
||||||
|
// log.Printf("PATH: %s -> %s", path, fullpath)
|
||||||
|
// //log.Printf("DATA: %s", string(srcData))
|
||||||
|
//}
|
||||||
|
|
||||||
|
dst, err := fs.Create(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Dst error: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dst.Write(srcData)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Dst write error: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return fs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotloads new apps from a folder
|
||||||
|
// FIXME: Not finished
|
||||||
|
func handleAppHotload(location string) error {
|
||||||
|
basepath := "base"
|
||||||
|
fs, err := createFs(basepath, location)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed making files and stuff: %s", err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
log.Printf("Hotloading from %s finished", location)
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err := fs.ReadDir(basepath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed reading folder: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = iterateAppGithubFolders(fs, dir, "", "")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Err: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles configuration items during Shuffle startup
|
||||||
func runInit(ctx context.Context) {
|
func runInit(ctx context.Context) {
|
||||||
// Setting stats for backend starts (failure count as well)
|
// Setting stats for backend starts (failure count as well)
|
||||||
err := increaseStatisticsField(ctx, "backend_executions", "", 1)
|
err := increaseStatisticsField(ctx, "backend_executions", "", 1)
|
||||||
@@ -5765,7 +5908,7 @@ func runInit(ctx context.Context) {
|
|||||||
|
|
||||||
_, _, err := handleExecution(schedule.WorkflowId, Workflow{}, request)
|
_, _, err := handleExecution(schedule.WorkflowId, Workflow{}, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to execute: %s", err)
|
log.Printf("Failed to execute %s: %s", schedule.WorkflowId, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5822,10 +5965,16 @@ func runInit(ctx context.Context) {
|
|||||||
|
|
||||||
// FIXME: Get all the apps?
|
// FIXME: Get all the apps?
|
||||||
iterateAppGithubFolders(fs, dir, "", "")
|
iterateAppGithubFolders(fs, dir, "", "")
|
||||||
|
|
||||||
|
// Hotloads locally
|
||||||
|
location := os.Getenv("APP_HOTLOAD_FOLDER")
|
||||||
|
if len(location) != 0 {
|
||||||
|
handleAppHotload(location)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Downloading OpenAPI data for search - EXTRA APPS")
|
log.Printf("Downloading OpenAPI data for search - EXTRA APPS")
|
||||||
apis := "https://github.com/frikky/OpenAPI-security-definitions"
|
apis := "https://github.com/frikky/security-openapis"
|
||||||
|
|
||||||
// THis gets memory problems hahah
|
// THis gets memory problems hahah
|
||||||
//apis := "https://github.com/APIs-guru/openapi-directory"
|
//apis := "https://github.com/APIs-guru/openapi-directory"
|
||||||
@@ -5896,7 +6045,9 @@ func init() {
|
|||||||
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
// App specific
|
// App specific
|
||||||
|
r.HandleFunc("/api/v1/apps/run_hotload", handleAppHotloadRequest).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/apps/download_remote", loadSpecificApps).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{appId}", deleteWorkflowApp).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{appId}", deleteWorkflowApp).Methods("DELETE", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{appId}/config", getWorkflowAppConfig).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{appId}/config", getWorkflowAppConfig).Methods("GET", "OPTIONS")
|
||||||
@@ -5914,6 +6065,8 @@ func init() {
|
|||||||
/* Everything below here increases the counters*/
|
/* Everything below here increases the counters*/
|
||||||
r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/workflows/schedules", handleGetSchedules).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/workflows/download_remote", loadSpecificWorkflows).Methods("POST", "OPTIONS")
|
||||||
//r.HandleFunc("/api/v1/workflows/{key}/execute_fs", executeWorkflowFS)
|
//r.HandleFunc("/api/v1/workflows/{key}/execute_fs", executeWorkflowFS)
|
||||||
r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows/{key}/schedule", scheduleWorkflow).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/{key}/schedule", scheduleWorkflow).Methods("POST", "OPTIONS")
|
||||||
|
|||||||
@@ -13,20 +13,8 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
database:
|
|
||||||
#build: ./backend/database
|
|
||||||
image: frikky/shuffle:database
|
|
||||||
container_name: shuffle-database
|
|
||||||
hostname: shuffle-database
|
|
||||||
ports:
|
|
||||||
- "8000:8000"
|
|
||||||
networks:
|
|
||||||
- shuffle
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- ${DB_LOCATION}:/etc/shuffle
|
|
||||||
backend:
|
backend:
|
||||||
#build: ./backend
|
build: ./backend
|
||||||
image: frikky/shuffle:backend
|
image: frikky/shuffle:backend
|
||||||
container_name: shuffle-backend
|
container_name: shuffle-backend
|
||||||
hostname: ${BACKEND_HOSTNAME}
|
hostname: ${BACKEND_HOSTNAME}
|
||||||
@@ -59,6 +47,18 @@ services:
|
|||||||
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
|
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
|
||||||
- DOCKER_API_VERSION=1.40
|
- DOCKER_API_VERSION=1.40
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
database:
|
||||||
|
#build: ./backend/database
|
||||||
|
image: frikky/shuffle:database
|
||||||
|
container_name: shuffle-database
|
||||||
|
hostname: shuffle-database
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
networks:
|
||||||
|
- shuffle
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ${DB_LOCATION}:/etc/shuffle
|
||||||
networks:
|
networks:
|
||||||
shuffle:
|
shuffle:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import ListItem from '@material-ui/core/ListItem';
|
|||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
import Tabs from '@material-ui/core/Tabs';
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
import Tab from '@material-ui/core/Tab';
|
import Tab from '@material-ui/core/Tab';
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
|
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
||||||
|
|
||||||
import { useAlert } from "react-alert";
|
import { useAlert } from "react-alert";
|
||||||
|
|
||||||
@@ -29,9 +30,39 @@ const Admin = (props) => {
|
|||||||
const [curTab, setCurTab] = React.useState(0);
|
const [curTab, setCurTab] = React.useState(0);
|
||||||
const [users, setUsers] = React.useState([]);
|
const [users, setUsers] = React.useState([]);
|
||||||
const [environments, setEnvironments] = React.useState([]);
|
const [environments, setEnvironments] = React.useState([]);
|
||||||
|
const [schedules, setSchedules] = React.useState([])
|
||||||
|
|
||||||
const alert = useAlert()
|
const alert = useAlert()
|
||||||
|
|
||||||
|
const deleteSchedule = (data) => {
|
||||||
|
// FIXME - add some check here ROFL
|
||||||
|
console.log("INPUT: ", data)
|
||||||
|
|
||||||
|
// Just use this one?
|
||||||
|
const url = globalUrl+'/api/v1/workflows/'+data["workflow_id datastore:"]+"/schedule/"+data.id
|
||||||
|
console.log("URL: ", url)
|
||||||
|
fetch(url, {
|
||||||
|
method: 'DELETE',
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response =>
|
||||||
|
response.json().then(responseJson => {
|
||||||
|
if (responseJson["success"] === false) {
|
||||||
|
alert.error("Failed stopping schedule")
|
||||||
|
} else {
|
||||||
|
getSchedules()
|
||||||
|
alert.success("Successfully stopped schedule!")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
console.log("Error in userdata: ", error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const submitUser = (data) => {
|
const submitUser = (data) => {
|
||||||
// FIXME - add some check here ROFL
|
// FIXME - add some check here ROFL
|
||||||
console.log("INPUT: ", data)
|
console.log("INPUT: ", data)
|
||||||
@@ -132,6 +163,31 @@ const Admin = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSchedules = () => {
|
||||||
|
fetch(globalUrl+"/api/v1/workflows/schedules", {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
setSchedules(responseJson)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
alert.error(error.toString())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const getEnvironments = () => {
|
const getEnvironments = () => {
|
||||||
fetch(globalUrl+"/api/v1/getenvironments", {
|
fetch(globalUrl+"/api/v1/getenvironments", {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -329,6 +385,54 @@ const Admin = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
const schedulesView = curTab === 2 ?
|
||||||
|
<div>
|
||||||
|
<h2>
|
||||||
|
Schedules
|
||||||
|
</h2>
|
||||||
|
<Divider style={{marginTop: 20, marginBottom: 20, backgroundColor: inputColor}}/>
|
||||||
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText
|
||||||
|
primary="Interval (seconds)"
|
||||||
|
style={{maxWidth: 200}}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary="Argument"
|
||||||
|
style={{maxWidth: 400, overflow: "hidden"}}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary="Actions"
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{schedules === undefined || schedules === null ? null : schedules.map(schedule => {
|
||||||
|
return (
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText
|
||||||
|
style={{maxWidth: 200}}
|
||||||
|
primary={schedule.seconds}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary={schedule.argument}
|
||||||
|
style={{maxWidth: 400, overflow: "hidden"}}
|
||||||
|
/>
|
||||||
|
<ListItemText>
|
||||||
|
<Button
|
||||||
|
style={{}}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => deleteSchedule(schedule)}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
: null
|
||||||
|
|
||||||
const environmentView = curTab === 1 ?
|
const environmentView = curTab === 1 ?
|
||||||
<div>
|
<div>
|
||||||
<h2>
|
<h2>
|
||||||
@@ -359,6 +463,8 @@ const Admin = (props) => {
|
|||||||
const setConfig = (event, newValue) => {
|
const setConfig = (event, newValue) => {
|
||||||
if (newValue === 1) {
|
if (newValue === 1) {
|
||||||
getEnvironments()
|
getEnvironments()
|
||||||
|
} else if (newValue === 2) {
|
||||||
|
getSchedules()
|
||||||
}
|
}
|
||||||
|
|
||||||
setModalUser({})
|
setModalUser({})
|
||||||
@@ -377,10 +483,12 @@ const Admin = (props) => {
|
|||||||
>
|
>
|
||||||
<Tab label="Users" />
|
<Tab label="Users" />
|
||||||
<Tab label="Environments"/>
|
<Tab label="Environments"/>
|
||||||
|
<Tab label="Schedules"/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<div style={{marginBottom: 10}}/>
|
<div style={{marginBottom: 10}}/>
|
||||||
{usersView}
|
{usersView}
|
||||||
{environmentView}
|
{environmentView}
|
||||||
|
{schedulesView}
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import Drawer from '@material-ui/core/Drawer';
|
|||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
import Paper from '@material-ui/core/Paper';
|
import Paper from '@material-ui/core/Paper';
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
|
import Tab from '@material-ui/core/Tab';
|
||||||
import ButtonBase from '@material-ui/core/ButtonBase';
|
import ButtonBase from '@material-ui/core/ButtonBase';
|
||||||
import Tooltip from '@material-ui/core/Tooltip';
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Select from '@material-ui/core/Select';
|
import Select from '@material-ui/core/Select';
|
||||||
@@ -60,8 +62,6 @@ import cxtmenu from 'cytoscape-cxtmenu';
|
|||||||
import { w3cwebsocket as W3CWebSocket } from "websocket";
|
import { w3cwebsocket as W3CWebSocket } from "websocket";
|
||||||
import { useAlert } from "react-alert";
|
import { useAlert } from "react-alert";
|
||||||
|
|
||||||
const hoverColor = "#f85a3e"
|
|
||||||
const hoverOutColor = "#e8eaf6"
|
|
||||||
const surfaceColor = "#27292D"
|
const surfaceColor = "#27292D"
|
||||||
const inputColor = "#383B40"
|
const inputColor = "#383B40"
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ const AngularWorkflow = (props) => {
|
|||||||
const [cy, setCy] = React.useState()
|
const [cy, setCy] = React.useState()
|
||||||
|
|
||||||
const [appSearch, setAppSearch] = React.useState("")
|
const [appSearch, setAppSearch] = React.useState("")
|
||||||
const [currentView, setCurrentView] = React.useState("apps")
|
const [currentView, setCurrentView] = React.useState(0)
|
||||||
const [triggerAuthentication, setTriggerAuthentication] = React.useState({})
|
const [triggerAuthentication, setTriggerAuthentication] = React.useState({})
|
||||||
const [triggerFolders, setTriggerFolders] = React.useState([])
|
const [triggerFolders, setTriggerFolders] = React.useState([])
|
||||||
|
|
||||||
@@ -164,9 +164,6 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
const [lastSaved, setLastSaved] = React.useState(true)
|
const [lastSaved, setLastSaved] = React.useState(true)
|
||||||
|
|
||||||
const [AppsHoverColor, setAppsHoverColor] = useState(hoverOutColor);
|
|
||||||
const [VariablesHoverColor, setVariablesHoverColor] = useState(hoverOutColor);
|
|
||||||
const [HookHoverColor, setHookHoverColor] = useState(hoverOutColor);
|
|
||||||
const [appAdded, setAppAdded] = useState(false)
|
const [appAdded, setAppAdded] = useState(false)
|
||||||
const [update, setUpdate] = useState("");
|
const [update, setUpdate] = useState("");
|
||||||
const [workflowExecutions, setWorkflowExecutions] = React.useState([]);
|
const [workflowExecutions, setWorkflowExecutions] = React.useState([]);
|
||||||
@@ -262,7 +259,7 @@ const AngularWorkflow = (props) => {
|
|||||||
const abortExecution = () => {
|
const abortExecution = () => {
|
||||||
setExecutionRunning(false)
|
setExecutionRunning(false)
|
||||||
|
|
||||||
alert.success("Aborting execution")
|
alert.info("Aborting execution")
|
||||||
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/executions/"+executionRequest.execution_id+"/abort", {
|
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/executions/"+executionRequest.execution_id+"/abort", {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -274,7 +271,9 @@ const AngularWorkflow = (props) => {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
||||||
}
|
} else {
|
||||||
|
alert.success("Execution aborted")
|
||||||
|
}
|
||||||
|
|
||||||
return response.json()
|
return response.json()
|
||||||
})
|
})
|
||||||
@@ -547,68 +546,6 @@ const AngularWorkflow = (props) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const executeWorkflowWebsocket = () => {
|
|
||||||
if (!lastSaved) {
|
|
||||||
//alert.error("You might have forgotten to save before executing.")
|
|
||||||
console.log("FIXME: Might have forgotten to save before executing.")
|
|
||||||
}
|
|
||||||
|
|
||||||
var returncheck = monitorUpdates()
|
|
||||||
if (!returncheck) {
|
|
||||||
alert.error("No startnode set.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setVisited([])
|
|
||||||
setExecutionRunning(true)
|
|
||||||
setExecutionRequest({})
|
|
||||||
|
|
||||||
var curelements = cy.elements()
|
|
||||||
for (var i = 0; i < curelements.length; i++) {
|
|
||||||
curelements[i].addClass("not-executing-highlight")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (executionText.length > 0) {
|
|
||||||
alert.success("Starting execution with argument "+executionText)
|
|
||||||
} else {
|
|
||||||
alert.success("Starting execution")
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {"execution_argument": executionText}
|
|
||||||
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/execute_fs", {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
credentials: "include",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (response.status !== 200) {
|
|
||||||
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json()
|
|
||||||
})
|
|
||||||
.then((responseJson) => {
|
|
||||||
if (!responseJson.success) {
|
|
||||||
alert.error("Failed to start: "+responseJson.reason)
|
|
||||||
stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setExecutionRequest({
|
|
||||||
"execution_id": responseJson.execution_id,
|
|
||||||
"authorization": responseJson.authorization,
|
|
||||||
})
|
|
||||||
setExecutingNodes([workflow.start])
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
alert.error(error.toString())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const executeWorkflow = () => {
|
const executeWorkflow = () => {
|
||||||
if (!lastSaved) {
|
if (!lastSaved) {
|
||||||
//alert.error("You might have forgotten to save before executing.")
|
//alert.error("You might have forgotten to save before executing.")
|
||||||
@@ -639,14 +576,14 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
const data = {"execution_argument": executionText, "start": workflow.start}
|
const data = {"execution_argument": executionText, "start": workflow.start}
|
||||||
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/execute", {
|
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/execute", {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
||||||
@@ -657,7 +594,13 @@ const AngularWorkflow = (props) => {
|
|||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (!responseJson.success) {
|
if (!responseJson.success) {
|
||||||
alert.error("Failed to start: "+responseJson.reason)
|
alert.error("Failed to start: "+responseJson.reason)
|
||||||
|
setExecutionRunning(false)
|
||||||
|
setExecutionRequestStarted(false)
|
||||||
stop()
|
stop()
|
||||||
|
|
||||||
|
for (var i = 0; i < curelements.length; i++) {
|
||||||
|
curelements[i].removeClass("not-executing-highlight")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
setExecutionRunning(true)
|
setExecutionRunning(true)
|
||||||
@@ -1197,7 +1140,6 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onNodeHover = (event) => {
|
const onNodeHover = (event) => {
|
||||||
//event.target.style("border-width", "5px")
|
|
||||||
event.target.animate({
|
event.target.animate({
|
||||||
style: {
|
style: {
|
||||||
"border-width": "5px",
|
"border-width": "5px",
|
||||||
@@ -1211,24 +1153,22 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onEdgeHoverOut = (event) => {
|
const onEdgeHoverOut = (event) => {
|
||||||
//event.target.removeStyle()
|
event.target.removeStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is here to have a proper transition for lines
|
// This is here to have a proper transition for lines
|
||||||
const onEdgeHover = (event) => {
|
const onEdgeHover = (event) => {
|
||||||
|
const sourcecolor = cy.getElementById(event.target.data("source")).style("border-color")
|
||||||
//console.log(event.target.data())
|
const targetcolor = cy.getElementById(event.target.data("target")).style("border-color")
|
||||||
//const sourcecolor = cy.getElementById(event.target.data("source")).style("border-color")
|
event.target.animate({
|
||||||
//const targetcolor = cy.getElementById(event.target.data("target")).style("border-color")
|
style: {
|
||||||
//event.target.animate({
|
"line-fill": "linear-gradient",
|
||||||
// style: {
|
'target-arrow-color': targetcolor,
|
||||||
// "line-fill": "linear-gradient",
|
"line-gradient-stop-colors": [sourcecolor, targetcolor],
|
||||||
// 'target-arrow-color': targetcolor,
|
"line-gradient-stop-positions": [0, 1],
|
||||||
// "line-gradient-stop-colors": [sourcecolor, targetcolor],
|
},
|
||||||
// "line-gradient-stop-positions": [0, 1],
|
duration: 0,
|
||||||
// },
|
})
|
||||||
// duration: 0,
|
|
||||||
//})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1429,16 +1369,17 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const appViewStyle = {
|
const appViewStyle = {
|
||||||
marginLeft: "5px",
|
marginLeft: 5,
|
||||||
marginRight: "5px",
|
marginRight: 5,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
height: "100%",
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollStyle = {
|
const scrollStyle = {
|
||||||
marginTop: "10px",
|
marginTop: 10,
|
||||||
overflow: "scroll",
|
overflow: "scroll",
|
||||||
height: "66vh",
|
height: "100%",
|
||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
}
|
}
|
||||||
@@ -1455,37 +1396,6 @@ const AngularWorkflow = (props) => {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
}
|
}
|
||||||
|
|
||||||
// All this is stupid lmao
|
|
||||||
const handleHookHover = () => {
|
|
||||||
setHookHoverColor(hoverColor)
|
|
||||||
setAppsHoverColor(hoverOutColor)
|
|
||||||
setVariablesHoverColor(hoverOutColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleHookHoverOut = () => {
|
|
||||||
setHookHoverColor(hoverOutColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAppsHover = () => {
|
|
||||||
setAppsHoverColor(hoverColor)
|
|
||||||
setHookHoverColor(hoverOutColor)
|
|
||||||
setVariablesHoverColor(hoverOutColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAppsHoverOut = () => {
|
|
||||||
setAppsHoverColor(hoverOutColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleVariablesHover = () => {
|
|
||||||
setVariablesHoverColor(hoverColor)
|
|
||||||
setHookHoverColor(hoverOutColor)
|
|
||||||
setAppsHoverColor(hoverOutColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleVariablesHoverOut = () => {
|
|
||||||
setVariablesHoverColor(hoverOutColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const paperVariableStyle = {
|
const paperVariableStyle = {
|
||||||
minHeight: "50px",
|
minHeight: "50px",
|
||||||
maxHeight: "50px",
|
maxHeight: "50px",
|
||||||
@@ -1560,6 +1470,7 @@ const AngularWorkflow = (props) => {
|
|||||||
aria-controls="long-menu"
|
aria-controls="long-menu"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
onClick={menuClick}
|
onClick={menuClick}
|
||||||
|
style={{color: "white"}}
|
||||||
>
|
>
|
||||||
<MoreVertIcon />
|
<MoreVertIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -1605,57 +1516,77 @@ const AngularWorkflow = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const curTab = 0
|
||||||
|
const handleSetTab = (event, newValue) => {
|
||||||
|
setCurrentView(newValue)
|
||||||
|
}
|
||||||
|
|
||||||
const HandleLeftView = () => {
|
const HandleLeftView = () => {
|
||||||
// Defaults to apps.
|
// Defaults to apps.
|
||||||
var thisview = <AppView />
|
var thisview = <AppView />
|
||||||
if (currentView === "triggers") {
|
if (currentView === 1) {
|
||||||
thisview = <TriggersView />
|
thisview = <TriggersView />
|
||||||
} else if (currentView === "variables") {
|
} else if (currentView === 2) {
|
||||||
thisview = <VariablesView />
|
thisview = <VariablesView />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tabStyle = {
|
||||||
|
maxWidth: leftBarSize/3,
|
||||||
|
minWidth: leftBarSize/3,
|
||||||
|
flex: 1,
|
||||||
|
textTransform: "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconStyle = {
|
||||||
|
marginTop: 3,
|
||||||
|
marginRight: 5,
|
||||||
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
<Divider style={{marginTop: 10, height: 1, width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
|
<div style={{minHeight: bodyHeight-appBarSize-50, maxHeight: bodyHeight-appBarSize-50}}>
|
||||||
<div style={{minHeight: bodyHeight-appBarSize-150, maxHeight: bodyHeight-appBarSize-100}}>
|
|
||||||
{thisview}
|
{thisview}
|
||||||
</div>
|
</div>
|
||||||
<div style={{bottom: 0, left: 0}}>
|
<Divider style={{backgroundColor: "rgb(91, 96, 100)"}}/>
|
||||||
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
|
<Tabs
|
||||||
<div style={{display: "flex"}}>
|
value={currentView}
|
||||||
<div style={{flex: "1", marginLeft: "10px", marginTop: "10px", color: AppsHoverColor, cursor: "pointer", textAlign: "center"}} onMouseOver={handleAppsHover} onMouseOut={handleAppsHoverOut} onClick={() => {setCurrentView("apps")}}>
|
indicatorColor="primary"
|
||||||
<Grid container direction="row" alignItems="center">
|
textColor="white"
|
||||||
<Grid item>
|
onChange={handleSetTab}
|
||||||
<AppsIcon style={{marginTop: "3px", marginRight: "5px"}} />
|
aria-label="Left sidebar tab"
|
||||||
</Grid>
|
>
|
||||||
|
<Tab label={
|
||||||
|
<Grid container direction="row" alignItems="center">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
Apps
|
<AppsIcon style={iconStyle} />
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
<Grid item>
|
||||||
<div style={{flex: "1", marginLeft: "10px", marginTop: "10px", color: HookHoverColor, cursor: "pointer"}} onMouseOver={handleHookHover} onMouseOut={handleHookHoverOut} onClick={() => {setCurrentView("triggers")}}>
|
Apps
|
||||||
<Grid container direction="row" alignItems="center">
|
</Grid>
|
||||||
<Grid item>
|
</Grid>
|
||||||
<ScheduleIcon style={{marginTop: "3px", marginRight: "5px"}} />
|
} style={tabStyle} />
|
||||||
</Grid>
|
<Tab label={
|
||||||
|
<Grid container direction="row" alignItems="center">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
Triggers
|
<ScheduleIcon style={iconStyle} />
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
<Grid item>
|
||||||
<div style={{flex: "1", marginLeft: "10px", marginTop: "10px", color: VariablesHoverColor, cursor: "pointer"}} onMouseOver={handleVariablesHover} onMouseOut={handleVariablesHoverOut} onClick={() => {setCurrentView("variables")}}>
|
Triggers
|
||||||
<Grid container direction="row" alignItems="center">
|
</Grid>
|
||||||
<Grid item>
|
</Grid>
|
||||||
<FavoriteBorderIcon style={{marginTop: "3px", marginRight: "5px"}} />
|
} style={tabStyle} />
|
||||||
</Grid>
|
<Tab label={
|
||||||
|
<Grid container direction="row" alignItems="center">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
Variables
|
<FavoriteBorderIcon style={iconStyle} />
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
<Grid item>
|
||||||
</div>
|
Variables
|
||||||
</div>
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
}style={tabStyle} />
|
||||||
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1965,7 +1896,7 @@ const AngularWorkflow = (props) => {
|
|||||||
node.data.type = "ACTION"
|
node.data.type = "ACTION"
|
||||||
node.isStartNode = action["id"] === workflow.start
|
node.isStartNode = action["id"] === workflow.start
|
||||||
|
|
||||||
return node;
|
return node
|
||||||
})
|
})
|
||||||
|
|
||||||
const tmpelements = [].concat(actions)
|
const tmpelements = [].concat(actions)
|
||||||
@@ -2001,14 +1932,16 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDragStop = (e) => {
|
const handleDragStop = (e, app) => {
|
||||||
newNodeId = ""
|
newNodeId = ""
|
||||||
|
console.log("STOP!: ", e)
|
||||||
|
console.log("APP!: ", app)
|
||||||
}
|
}
|
||||||
|
|
||||||
const appScrollStyle = {
|
const appScrollStyle = {
|
||||||
overflow: "scroll",
|
overflow: "scroll",
|
||||||
maxHeight: bodyHeight-appBarSize-150,
|
maxHeight: bodyHeight-appBarSize-55,
|
||||||
minHeight: bodyHeight-appBarSize-150,
|
minHeight: bodyHeight-appBarSize-55,
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
}
|
}
|
||||||
@@ -2063,7 +1996,8 @@ const AngularWorkflow = (props) => {
|
|||||||
return(
|
return(
|
||||||
<Draggable
|
<Draggable
|
||||||
onDrag={(e) => {handleAppDrag(e, app)}}
|
onDrag={(e) => {handleAppDrag(e, app)}}
|
||||||
onStop={(e) => {handleDragStop(e)}}
|
onStop={(e) => {handleDragStop(e, app)}}
|
||||||
|
key={app.id}
|
||||||
dragging={false}
|
dragging={false}
|
||||||
position={{
|
position={{
|
||||||
x: 0,
|
x: 0,
|
||||||
@@ -2347,6 +2281,7 @@ const AngularWorkflow = (props) => {
|
|||||||
rows="5"
|
rows="5"
|
||||||
color="primary"
|
color="primary"
|
||||||
defaultValue={data.value}
|
defaultValue={data.value}
|
||||||
|
type={placeholder.includes("***") ? "password" : "text"}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
changeActionParameter(event, count)
|
changeActionParameter(event, count)
|
||||||
@@ -2427,7 +2362,7 @@ const AngularWorkflow = (props) => {
|
|||||||
} else if (data.variant === "WORKFLOW_VARIABLE") {
|
} else if (data.variant === "WORKFLOW_VARIABLE") {
|
||||||
varcolor = "#f85a3e"
|
varcolor = "#f85a3e"
|
||||||
if (workflow.workflow_variables === null || workflow.workflow_variables === undefined || workflow.workflow_variables.length === 0) {
|
if (workflow.workflow_variables === null || workflow.workflow_variables === undefined || workflow.workflow_variables.length === 0) {
|
||||||
setCurrentView("variables")
|
setCurrentView(2)
|
||||||
datafield =
|
datafield =
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@@ -2477,7 +2412,7 @@ const AngularWorkflow = (props) => {
|
|||||||
<div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}>
|
<div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}>
|
||||||
<div style={{width: "17px", height: "17px", borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: "10px"}}/>
|
<div style={{width: "17px", height: "17px", borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: "10px"}}/>
|
||||||
<div style={{flex: "10"}}>
|
<div style={{flex: "10"}}>
|
||||||
<b>{data.name}: </b>
|
<b>{data.name} </b>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip color="primary" title="Static data" placement="top">
|
<Tooltip color="primary" title="Static data" placement="top">
|
||||||
<div style={{cursor: "pointer", color: staticcolor}} onClick={(e) => {
|
<div style={{cursor: "pointer", color: staticcolor}} onClick={(e) => {
|
||||||
@@ -2563,6 +2498,13 @@ const AngularWorkflow = (props) => {
|
|||||||
//setStartNode(selectedAction.id)
|
//setStartNode(selectedAction.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortByKey(array, key) {
|
||||||
|
return array.sort(function(a, b) {
|
||||||
|
var x = a[key]; var y = b[key]
|
||||||
|
return ((x < y) ? -1 : ((x > y) ? 1 : 0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const appApiView = Object.getOwnPropertyNames(selectedAction).length > 0 && Object.getOwnPropertyNames(selectedApp).length > 0 ?
|
const appApiView = Object.getOwnPropertyNames(selectedAction).length > 0 && Object.getOwnPropertyNames(selectedApp).length > 0 ?
|
||||||
<div style={appApiViewStyle}>
|
<div style={appApiViewStyle}>
|
||||||
<div style={{display: "flex", minHeight: 40, marginBottom: 30}}>
|
<div style={{display: "flex", minHeight: 40, marginBottom: 30}}>
|
||||||
@@ -2644,7 +2586,7 @@ const AngularWorkflow = (props) => {
|
|||||||
: null*/}
|
: null*/}
|
||||||
<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={{flex: "6", marginTop: "20px"}}>
|
<div style={{flex: "6", marginTop: "20px"}}>
|
||||||
<div>
|
<div style={{marginBottom: 5}}>
|
||||||
<b>Actions</b>
|
<b>Actions</b>
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
@@ -2659,7 +2601,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectedApp.actions.map(data => {
|
{sortByKey(selectedApp.actions, "label").map(data => {
|
||||||
var newActionname = data.name
|
var newActionname = data.name
|
||||||
if (data.label !== undefined && data.label !== null && data.label.length > 0) {
|
if (data.label !== undefined && data.label !== null && data.label.length > 0) {
|
||||||
newActionname = data.label
|
newActionname = data.label
|
||||||
@@ -2671,13 +2613,17 @@ const AngularWorkflow = (props) => {
|
|||||||
newActionname = newActionname.replace("_", " ")
|
newActionname = newActionname.replace("_", " ")
|
||||||
newActionname = newActionname.charAt(0).toUpperCase()+newActionname.substring(1)
|
newActionname = newActionname.charAt(0).toUpperCase()+newActionname.substring(1)
|
||||||
return (
|
return (
|
||||||
<MenuItem style={{backgroundColor: inputColor, color: "white"}} value={data.name}>
|
<MenuItem style={{maxWidth: 400, overflowX: "hidden", backgroundColor: inputColor, color: "white"}} value={data.name}>
|
||||||
{newActionname}
|
{newActionname}
|
||||||
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Select>
|
</Select>
|
||||||
|
{selectedAction.description !== undefined && selectedAction.description.length > 0 ?
|
||||||
|
<div style={{marginTop: 10, marginBottom: 10, maxHeight: 60, overflow: "hidden"}}>
|
||||||
|
{selectedAction.description}
|
||||||
|
</div> : null}
|
||||||
<div style={{marginTop: "10px", borderColor: "white", borderWidth: "2px", marginBottom: 200}}>
|
<div style={{marginTop: "10px", borderColor: "white", borderWidth: "2px", marginBottom: 200}}>
|
||||||
<AppActionArguments key={selectedAction.id} selectedAction={selectedAction} />
|
<AppActionArguments key={selectedAction.id} selectedAction={selectedAction} />
|
||||||
|
|
||||||
@@ -2703,11 +2649,11 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const setTriggerFolderWrapperMulti = event => {
|
const setTriggerFolderWrapperMulti = event => {
|
||||||
const { options } = event.target;
|
const { options } = event.target
|
||||||
const value = [];
|
const value = []
|
||||||
for (let i = 0, l = options.length; i < l; i += 1) {
|
for (let i = 0, l = options.length; i < l; i += 1) {
|
||||||
if (options[i].selected) {
|
if (options[i].selected) {
|
||||||
value.push(options[i].value);
|
value.push(options[i].value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2783,7 +2729,7 @@ const AngularWorkflow = (props) => {
|
|||||||
if (splitItems.includes(value)) {
|
if (splitItems.includes(value)) {
|
||||||
for( var i = 0; i < splitItems.length; i++){
|
for( var i = 0; i < splitItems.length; i++){
|
||||||
if (splitItems[i] === value) {
|
if (splitItems[i] === value) {
|
||||||
splitItems.splice(i, 1);
|
splitItems.splice(i, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2793,7 +2739,7 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
for( var i = 0; i < splitItems.length; i++){
|
for( var i = 0; i < splitItems.length; i++){
|
||||||
if (splitItems[i] === "") {
|
if (splitItems[i] === "") {
|
||||||
splitItems.splice(i, 1);
|
splitItems.splice(i, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2824,7 +2770,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AppConditionHandler = (props) => {
|
const AppConditionHandler = (props) => {
|
||||||
const { tmpdata, type } = props;
|
const { tmpdata, type } = props
|
||||||
|
|
||||||
if (tmpdata === undefined) {
|
if (tmpdata === undefined) {
|
||||||
return tmpdata
|
return tmpdata
|
||||||
@@ -2933,7 +2879,7 @@ const AngularWorkflow = (props) => {
|
|||||||
} else if (data.variant === "WORKFLOW_VARIABLE") {
|
} else if (data.variant === "WORKFLOW_VARIABLE") {
|
||||||
varcolor = "#f85a3e"
|
varcolor = "#f85a3e"
|
||||||
if (workflow.workflow_variables === null || workflow.workflow_variables === undefined || workflow.workflow_variables.length === 0) {
|
if (workflow.workflow_variables === null || workflow.workflow_variables === undefined || workflow.workflow_variables.length === 0) {
|
||||||
setCurrentView("variables")
|
setCurrentView(2)
|
||||||
datafield =
|
datafield =
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@@ -3192,8 +3138,8 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
const EdgeSidebar = () => {
|
const EdgeSidebar = () => {
|
||||||
const ConditionHandler = (condition, index) => {
|
const ConditionHandler = (condition, index) => {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false)
|
||||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
const [anchorEl, setAnchorEl] = React.useState(null)
|
||||||
|
|
||||||
const deleteCondition = (conditionIndex) => {
|
const deleteCondition = (conditionIndex) => {
|
||||||
console.log(selectedEdge)
|
console.log(selectedEdge)
|
||||||
@@ -3223,7 +3169,7 @@ const AngularWorkflow = (props) => {
|
|||||||
const menuClick = (event) => {
|
const menuClick = (event) => {
|
||||||
console.log("MENU CLICK")
|
console.log("MENU CLICK")
|
||||||
setOpen(!open)
|
setOpen(!open)
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -3363,7 +3309,7 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log(error.toString())
|
console.log(error.toString())
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTriggerAuth = () => {
|
const getTriggerAuth = () => {
|
||||||
@@ -3384,7 +3330,7 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log(error.toString())
|
console.log(error.toString())
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting the triggers and the folders if they exist
|
// Getting the triggers and the folders if they exist
|
||||||
@@ -3426,8 +3372,8 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log(error.toString())
|
console.log(error.toString())
|
||||||
});
|
})
|
||||||
}, 2500);
|
}, 2500)
|
||||||
|
|
||||||
console.log(data)
|
console.log(data)
|
||||||
saveWorkflow(workflow)
|
saveWorkflow(workflow)
|
||||||
@@ -3801,7 +3747,7 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
alert.error(error.toString())
|
alert.error(error.toString())
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const startMailSub = (trigger, triggerindex) => {
|
const startMailSub = (trigger, triggerindex) => {
|
||||||
@@ -3857,7 +3803,7 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
alert.error(error.toString())
|
alert.error(error.toString())
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const newWebhook = (trigger) => {
|
const newWebhook = (trigger) => {
|
||||||
@@ -3903,7 +3849,7 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log(error.toString())
|
console.log(error.toString())
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteWebhook = (trigger, triggerindex) => {
|
const deleteWebhook = (trigger, triggerindex) => {
|
||||||
@@ -3942,7 +3888,7 @@ const AngularWorkflow = (props) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
alert.error(error.toString())
|
alert.error(error.toString())
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserinputSidebar = () => {
|
const UserinputSidebar = () => {
|
||||||
@@ -4356,7 +4302,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Object.getOwnPropertyNames(selectedAction).length > 0 && Object.getOwnPropertyNames(selectedApp).length > 0) {
|
if (Object.getOwnPropertyNames(selectedAction).length > 0 && Object.getOwnPropertyNames(selectedApp).length > 0) {
|
||||||
//console.time('ACTIONSTART');
|
//console.time('ACTIONSTART')
|
||||||
return(
|
return(
|
||||||
<div style={rightsidebarStyle}>
|
<div style={rightsidebarStyle}>
|
||||||
{appApiView}
|
{appApiView}
|
||||||
@@ -4479,11 +4425,13 @@ const AngularWorkflow = (props) => {
|
|||||||
<div style={{ marginTop: "auto", marginBottom: "auto", marginRight: 15, }}>
|
<div style={{ marginTop: "auto", marginBottom: "auto", marginRight: 15, }}>
|
||||||
{timestamp}
|
{timestamp}
|
||||||
</div>
|
</div>
|
||||||
<Tooltip color="primary" title={resultsLength+" actions ran"} placement="top">
|
{data.workflow.actions !== null ?
|
||||||
<div style={{marginRight: 10, marginTop: "auto", marginBottom: "auto",}}>
|
<Tooltip color="primary" title={resultsLength+" actions ran"} placement="top">
|
||||||
{resultsLength}/{data.workflow.actions.length}
|
<div style={{marginRight: 10, marginTop: "auto", marginBottom: "auto",}}>
|
||||||
</div>
|
{resultsLength}/{data.workflow.actions.length}
|
||||||
</Tooltip>
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
<Tooltip title={"Inspect execution"} placement="top">
|
<Tooltip title={"Inspect execution"} placement="top">
|
||||||
<KeyboardArrowRightIcon style={{marginTop: "auto", marginBottom: "auto"}}/>
|
<KeyboardArrowRightIcon style={{marginTop: "auto", marginBottom: "auto"}}/>
|
||||||
@@ -4545,7 +4493,7 @@ const AngularWorkflow = (props) => {
|
|||||||
executionData.results.map(data => {
|
executionData.results.map(data => {
|
||||||
var showResult = data.result.trim()
|
var showResult = data.result.trim()
|
||||||
showResult.split(" None").join(" \"None\"")
|
showResult.split(" None").join(" \"None\"")
|
||||||
//showResult = replaceAll(showResult, " None", " \"None\"");
|
//showResult = replaceAll(showResult, " None", " \"None\"")
|
||||||
var jsonvalid = true
|
var jsonvalid = true
|
||||||
try {
|
try {
|
||||||
JSON.parse(showResult)
|
JSON.parse(showResult)
|
||||||
@@ -4569,7 +4517,7 @@ const AngularWorkflow = (props) => {
|
|||||||
{jsonvalid ? <ReactJson
|
{jsonvalid ? <ReactJson
|
||||||
src={JSON.parse(showResult)}
|
src={JSON.parse(showResult)}
|
||||||
theme="solarized"
|
theme="solarized"
|
||||||
collapsed={false}
|
collapsed={true}
|
||||||
displayDataTypes={false}
|
displayDataTypes={false}
|
||||||
name={"Results for "+data.action.label}
|
name={"Results for "+data.action.label}
|
||||||
/>
|
/>
|
||||||
@@ -4600,6 +4548,9 @@ const AngularWorkflow = (props) => {
|
|||||||
boxSelectionEnabled={true}
|
boxSelectionEnabled={true}
|
||||||
autounselectify={false}
|
autounselectify={false}
|
||||||
cy={(incy) => {
|
cy={(incy) => {
|
||||||
|
// FIXME: There's something specific loading when
|
||||||
|
// you do the first hover of a node. Why is this different?
|
||||||
|
console.log("CY: ", incy)
|
||||||
setCy(incy)
|
setCy(incy)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -4608,7 +4559,6 @@ const AngularWorkflow = (props) => {
|
|||||||
<RightSideBar />
|
<RightSideBar />
|
||||||
<BottomCytoscapeBar />
|
<BottomCytoscapeBar />
|
||||||
<TopCytoscapeBar />
|
<TopCytoscapeBar />
|
||||||
<NoActionsBar />
|
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div style={{color: "white"}}>
|
<div style={{color: "white"}}>
|
||||||
@@ -4872,4 +4822,4 @@ const AngularWorkflow = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AngularWorkflow;
|
export default AngularWorkflow
|
||||||
|
|||||||
@@ -147,13 +147,13 @@ const App = (message, props) => {
|
|||||||
// This is a mess hahahah
|
// This is a mess hahahah
|
||||||
return (
|
return (
|
||||||
<MuiThemeProvider theme={theme}>
|
<MuiThemeProvider theme={theme}>
|
||||||
<CookiesProvider>
|
<CookiesProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Provider template={AlertTemplate} {...options}>
|
<Provider template={AlertTemplate} {...options}>
|
||||||
{includedData}
|
{includedData}
|
||||||
</Provider>
|
</Provider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</CookiesProvider>
|
</CookiesProvider>
|
||||||
</MuiThemeProvider>
|
</MuiThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import {BrowserView, MobileView} from "react-device-detect";
|
|||||||
|
|
||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
import Paper from '@material-ui/core/Paper';
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
import Divider from '@material-ui/core/Divider';
|
import Divider from '@material-ui/core/Divider';
|
||||||
import Select from '@material-ui/core/Select';
|
import Select from '@material-ui/core/Select';
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import FormControl from '@material-ui/core/FormControl';
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import Switch from '@material-ui/core/Switch';
|
||||||
import Dialog from '@material-ui/core/Dialog';
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import DialogContent from '@material-ui/core/DialogContent';
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
@@ -65,7 +67,7 @@ const useStyles = makeStyles({
|
|||||||
|
|
||||||
const rewrite = (args) => {
|
const rewrite = (args) => {
|
||||||
return args.reduce(function(args, a){
|
return args.reduce(function(args, a){
|
||||||
if (0 == a.indexOf('-X')) {
|
if (0 === a.indexOf('-X')) {
|
||||||
args.push('-X')
|
args.push('-X')
|
||||||
args.push(a.slice(2))
|
args.push(a.slice(2))
|
||||||
} else {
|
} else {
|
||||||
@@ -103,35 +105,35 @@ const parseCurl = (s) => {
|
|||||||
out.url = arg
|
out.url = arg
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-A' || arg == '--user-agent':
|
case arg === '-A' || arg === '--user-agent':
|
||||||
state = 'user-agent'
|
state = 'user-agent'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-H' || arg == '--header':
|
case arg === '-H' || arg === '--header':
|
||||||
state = 'header'
|
state = 'header'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-d' || arg == '--data' || arg == '--data-ascii':
|
case arg === '-d' || arg === '--data' || arg === '--data-ascii':
|
||||||
state = 'data'
|
state = 'data'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-u' || arg == '--user':
|
case arg === '-u' || arg === '--user':
|
||||||
state = 'user'
|
state = 'user'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-I' || arg == '--head':
|
case arg === '-I' || arg === '--head':
|
||||||
out.method = 'HEAD'
|
out.method = 'HEAD'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-X' || arg == '--request':
|
case arg === '-X' || arg === '--request':
|
||||||
state = 'method'
|
state = 'method'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '-b' || arg =='--cookie':
|
case arg === '-b' || arg === '--cookie':
|
||||||
state = 'cookie'
|
state = 'cookie'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case arg == '--compressed':
|
case arg === '--compressed':
|
||||||
out.header['Accept-Encoding'] = out.header['Accept-Encoding'] || 'deflate, gzip'
|
out.header['Accept-Encoding'] = out.header['Accept-Encoding'] || 'deflate, gzip'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -147,7 +149,7 @@ const parseCurl = (s) => {
|
|||||||
state = ''
|
state = ''
|
||||||
break;
|
break;
|
||||||
case 'data':
|
case 'data':
|
||||||
if (out.method == 'GET' || out.method == 'HEAD') out.method = 'POST'
|
if (out.method === 'GET' || out.method === 'HEAD') out.method = 'POST'
|
||||||
out.header['Content-Type'] = out.header['Content-Type'] || 'application/x-www-form-urlencoded'
|
out.header['Content-Type'] = out.header['Content-Type'] || 'application/x-www-form-urlencoded'
|
||||||
out.body = out.body
|
out.body = out.body
|
||||||
? out.body + '&' + arg
|
? out.body + '&' + arg
|
||||||
@@ -196,6 +198,7 @@ const AppCreator = (props) => {
|
|||||||
const [updater, setUpdater] = useState("tmp")
|
const [updater, setUpdater] = useState("tmp")
|
||||||
const [baseUrl, setBaseUrl] = useState("");
|
const [baseUrl, setBaseUrl] = useState("");
|
||||||
const [actionsModalOpen, setActionsModalOpen] = useState(false);
|
const [actionsModalOpen, setActionsModalOpen] = useState(false);
|
||||||
|
const [authenticationRequired, setAuthenticationRequired] = useState(false);
|
||||||
const [authenticationOption, setAuthenticationOption] = useState(authenticationOptions[0]);
|
const [authenticationOption, setAuthenticationOption] = useState(authenticationOptions[0]);
|
||||||
const [parameterName, setParameterName] = useState("");
|
const [parameterName, setParameterName] = useState("");
|
||||||
const [parameterLocation, setParameterLocation] = useState(apikeySelection.length > 0 ? apikeySelection[0] : "");
|
const [parameterLocation, setParameterLocation] = useState(apikeySelection.length > 0 ? apikeySelection[0] : "");
|
||||||
@@ -372,30 +375,6 @@ const AppCreator = (props) => {
|
|||||||
securitySchemes = data.components.securitySchemes
|
securitySchemes = data.components.securitySchemes
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Have multiple authentication options?
|
|
||||||
if (securitySchemes !== undefined) {
|
|
||||||
for (const [key, value] of Object.entries(securitySchemes)) {
|
|
||||||
if (value.scheme === "bearer") {
|
|
||||||
setAuthenticationOption("Bearer auth")
|
|
||||||
break
|
|
||||||
} else if (value.type === "apiKey") {
|
|
||||||
setAuthenticationOption("API key")
|
|
||||||
|
|
||||||
value.in = value.in.charAt(0).toUpperCase() + value.in.slice(1);
|
|
||||||
setParameterLocation(value.in)
|
|
||||||
if (!apikeySelection.includes(value.in)) {
|
|
||||||
console.log("APIKEY SELECT: ", apikeySelection)
|
|
||||||
alert.error("Might be error in setting up API key authentication")
|
|
||||||
}
|
|
||||||
|
|
||||||
setParameterName(value.name)
|
|
||||||
break
|
|
||||||
} else if (value.scheme === "basic") {
|
|
||||||
setAuthenticationOption("Basic auth")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(data)
|
console.log(data)
|
||||||
|
|
||||||
@@ -451,9 +430,39 @@ const AppCreator = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: Have multiple authentication options?
|
||||||
|
if (securitySchemes !== undefined) {
|
||||||
|
for (const [key, value] of Object.entries(securitySchemes)) {
|
||||||
|
if (value.scheme === "bearer") {
|
||||||
|
setAuthenticationOption("Bearer auth")
|
||||||
|
setAuthenticationRequired(true)
|
||||||
|
break
|
||||||
|
} else if (value.type === "apiKey") {
|
||||||
|
setAuthenticationOption("API key")
|
||||||
|
|
||||||
|
value.in = value.in.charAt(0).toUpperCase() + value.in.slice(1);
|
||||||
|
setParameterLocation(value.in)
|
||||||
|
if (!apikeySelection.includes(value.in)) {
|
||||||
|
console.log("APIKEY SELECT: ", apikeySelection)
|
||||||
|
alert.error("Might be error in setting up API key authentication")
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("PARAM NAME: ", value.name)
|
||||||
|
setParameterName(value.name)
|
||||||
|
setAuthenticationRequired(true)
|
||||||
|
break
|
||||||
|
} else if (value.scheme === "basic") {
|
||||||
|
setAuthenticationOption("Basic auth")
|
||||||
|
setAuthenticationRequired(true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setActions(newActions)
|
setActions(newActions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saving the app that's been configured.
|
// Saving the app that's been configured.
|
||||||
const submitApp = () => {
|
const submitApp = () => {
|
||||||
alert.info("Uploading and building app " + name)
|
alert.info("Uploading and building app " + name)
|
||||||
@@ -605,12 +614,25 @@ const AppCreator = (props) => {
|
|||||||
const headersSplit = item.headers.split("\n")
|
const headersSplit = item.headers.split("\n")
|
||||||
for (var key in headersSplit) {
|
for (var key in headersSplit) {
|
||||||
const header = headersSplit[key]
|
const header = headersSplit[key]
|
||||||
|
console.log("HEADER: ", header)
|
||||||
var key = ""
|
var key = ""
|
||||||
var value = ""
|
var value = ""
|
||||||
if (header.length > 0 && header.includes("=")) {
|
if (header.length > 0 && header.includes("= ")) {
|
||||||
|
const headersplit = header.split("= ")
|
||||||
|
key = headersplit[0]
|
||||||
|
value = headersplit[1]
|
||||||
|
} else if (header.length > 0 && header.includes("=")) {
|
||||||
const headersplit = header.split("=")
|
const headersplit = header.split("=")
|
||||||
key = headersplit[0]
|
key = headersplit[0]
|
||||||
value = headersplit[1]
|
value = headersplit[1]
|
||||||
|
} else if (header.length > 0 && header.includes(": ")) {
|
||||||
|
const headersplit = header.split(": ")
|
||||||
|
key = headersplit[0]
|
||||||
|
value = headersplit[1]
|
||||||
|
} else if (header.length > 0 && header.includes(":")) {
|
||||||
|
const headersplit = header.split(":")
|
||||||
|
key = headersplit[0]
|
||||||
|
value = headersplit[1]
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -701,7 +723,6 @@ const AppCreator = (props) => {
|
|||||||
</a>
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
Users will be required to submit their API as the header "Authorization: Bearer APIKEY"
|
Users will be required to submit their API as the header "Authorization: Bearer APIKEY"
|
||||||
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
|
|
||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
@@ -714,7 +735,6 @@ const AppCreator = (props) => {
|
|||||||
</a>
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
Users will be required to submit a valid username and password before using the API
|
Users will be required to submit a valid username and password before using the API
|
||||||
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
|
|
||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
@@ -810,7 +830,7 @@ const AppCreator = (props) => {
|
|||||||
id="standard-required"
|
id="standard-required"
|
||||||
margin="normal"
|
margin="normal"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
defaultValue={parameterName}
|
value={parameterName}
|
||||||
helperText={<div style={{color:"white", marginBottom: "2px",}}>Can't be empty. Can't contain any of the following characters: !#$%&'^+-._~|]+$</div>}
|
helperText={<div style={{color:"white", marginBottom: "2px",}}>Can't be empty. Can't contain any of the following characters: !#$%&'^+-._~|]+$</div>}
|
||||||
onChange={e => setParameterName(e.target.value)}
|
onChange={e => setParameterName(e.target.value)}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
@@ -847,7 +867,6 @@ const AppCreator = (props) => {
|
|||||||
)}
|
)}
|
||||||
)}
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
|
|
||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
@@ -926,11 +945,13 @@ const AppCreator = (props) => {
|
|||||||
{data.method} - {url} - {data.name}
|
{data.method} - {url} - {data.name}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{/*
|
||||||
<Tooltip title="Test action" placement="bottom">
|
<Tooltip title="Test action" placement="bottom">
|
||||||
<div style={{color: "#f85a3e", cursor: "pointer", marginRight: "10px", }} onClick={() => {testAction(index)}}>
|
<div style={{color: "#f85a3e", cursor: "pointer", marginRight: "10px", }} onClick={() => {testAction(index)}}>
|
||||||
Test
|
Test
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
*/}
|
||||||
<Tooltip title="Delete action" placement="bottom">
|
<Tooltip title="Delete action" placement="bottom">
|
||||||
<div style={{color: "#f85a3e", cursor: "pointer"}} onClick={() => {deleteAction(index)}}>
|
<div style={{color: "#f85a3e", cursor: "pointer"}} onClick={() => {deleteAction(index)}}>
|
||||||
Delete
|
Delete
|
||||||
@@ -999,7 +1020,7 @@ const AppCreator = (props) => {
|
|||||||
// Url verification
|
// Url verification
|
||||||
if (currentAction.url.length === 0) {
|
if (currentAction.url.length === 0) {
|
||||||
errormessage.push("URL path can't be empty.")
|
errormessage.push("URL path can't be empty.")
|
||||||
} else if (!currentAction.url.startsWith("/")) {
|
} else if (!currentAction.url.startsWith("/") && baseUrl.length > 0) {
|
||||||
errormessage.push("URL must start with /")
|
errormessage.push("URL must start with /")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1261,6 +1282,14 @@ const AppCreator = (props) => {
|
|||||||
if (request.header !== undefined && request.header !== null) {
|
if (request.header !== undefined && request.header !== null) {
|
||||||
var headers = []
|
var headers = []
|
||||||
for (let [key, value] of Object.entries(request.header)) {
|
for (let [key, value] of Object.entries(request.header)) {
|
||||||
|
if (parameterName !== undefined && key.toLowerCase() === parameterName.toLowerCase()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === "Authorization" && authenticationOption === "Bearer auth") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
headers += key+"="+value+"\n"
|
headers += key+"="+value+"\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1272,33 +1301,37 @@ const AppCreator = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse URL
|
// Parse URL
|
||||||
parsedurl = request.url
|
if (request.url !== undefined) {
|
||||||
|
parsedurl = request.url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsedurl.includes("<") && parsedurl.includes(">")) {
|
if (parsedurl !== undefined) {
|
||||||
parsedurl = parsedurl.split("<").join("{")
|
if (parsedurl.includes("<") && parsedurl.includes(">")) {
|
||||||
parsedurl = parsedurl.split(">").join("}")
|
parsedurl = parsedurl.split("<").join("{")
|
||||||
}
|
parsedurl = parsedurl.split(">").join("}")
|
||||||
|
|
||||||
if (parsedurl.startsWith("http") || parsedurl.startsWith("ftp")) {
|
|
||||||
if (parsedurl !== undefined && parsedurl.includes(parameterName)) {
|
|
||||||
// Remove <> etc.
|
|
||||||
//
|
|
||||||
|
|
||||||
console.log("IT HAS THE PARAM NAME!")
|
|
||||||
const newurl = new URL(encodeURI(parsedurl))
|
|
||||||
newurl.searchParams.delete(parameterName)
|
|
||||||
parsedurl = decodeURI(newurl.href)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the base URL itself
|
if (parsedurl.startsWith("http") || parsedurl.startsWith("ftp")) {
|
||||||
if (parsedurl !== undefined && baseUrl !== undefined && baseUrl.length > 0 && parsedurl.includes(baseUrl)) {
|
if (parsedurl !== undefined && parsedurl.includes(parameterName)) {
|
||||||
parsedurl = parsedurl.replace(baseUrl, "")
|
// Remove <> etc.
|
||||||
}
|
//
|
||||||
|
|
||||||
|
console.log("IT HAS THE PARAM NAME!")
|
||||||
|
const newurl = new URL(encodeURI(parsedurl))
|
||||||
|
newurl.searchParams.delete(parameterName)
|
||||||
|
parsedurl = decodeURI(newurl.href)
|
||||||
|
}
|
||||||
|
|
||||||
// Check URL query && headers
|
// Remove the base URL itself
|
||||||
setActionField("url", parsedurl)
|
if (parsedurl !== undefined && baseUrl !== undefined && baseUrl.length > 0 && parsedurl.includes(baseUrl)) {
|
||||||
setUrlPath(parsedurl)
|
parsedurl = parsedurl.replace(baseUrl, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check URL query && headers
|
||||||
|
setActionField("url", parsedurl)
|
||||||
|
setUrlPath(parsedurl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("URL: ", request.url)
|
//console.log("URL: ", request.url)
|
||||||
@@ -1550,11 +1583,17 @@ const AppCreator = (props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormControl style={{marginTop: "15px",}} variant="outlined">
|
<FormControl style={{marginTop: "15px",}} variant="outlined">
|
||||||
<h5 style={{marginBottom: "10px", color: "white",}}>Authentication</h5>
|
<h5 style={{marginBottom: "10px", color: "white",}}>Authentication
|
||||||
|
</h5>
|
||||||
<Select
|
<Select
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setAuthenticationOption(e.target.value)
|
setAuthenticationOption(e.target.value)
|
||||||
|
if (e.target.value === "No authentication") {
|
||||||
|
setAuthenticationRequired(false)
|
||||||
|
} else {
|
||||||
|
setAuthenticationRequired(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
value={authenticationOption}
|
value={authenticationOption}
|
||||||
style={{backgroundColor: inputColor, color: "white", height: "50px"}}
|
style={{backgroundColor: inputColor, color: "white", height: "50px"}}
|
||||||
@@ -1569,16 +1608,28 @@ const AppCreator = (props) => {
|
|||||||
{basicAuth}
|
{basicAuth}
|
||||||
{bearerAuth}
|
{bearerAuth}
|
||||||
{apiKey}
|
{apiKey}
|
||||||
|
|
||||||
|
{/*authenticationOption === "No authentication" ? null :
|
||||||
|
<FormControlLabel
|
||||||
|
style={{color: "white", marginBottom: 0, marginTop: 20}}
|
||||||
|
label=<div style={{color: "white"}}>Authentication required (default true)</div>
|
||||||
|
control={<Switch checked={authenticationRequired} onChange={() => {
|
||||||
|
setAuthenticationRequired(!authenticationRequired)
|
||||||
|
}} />}
|
||||||
|
/>*/}
|
||||||
|
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
|
||||||
<div style={{marginTop: "25px"}}>
|
<div style={{marginTop: "25px"}}>
|
||||||
{actionView}
|
{actionView}
|
||||||
</div>
|
</div>
|
||||||
|
{/*
|
||||||
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
|
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
|
||||||
{testView}
|
{testView}
|
||||||
|
*/}
|
||||||
|
|
||||||
<Button color="primary" variant="contained" style={{borderRadius: "0px", marginTop: "30px", height: "50px",}} onClick={() => {
|
<Button color="primary" variant="contained" style={{borderRadius: "0px", marginTop: "30px", height: "50px",}} onClick={() => {
|
||||||
submitApp()
|
submitApp()
|
||||||
}}>
|
}}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
{errorCode.length > 0 ? `Error: ${errorCode}` : null}
|
{errorCode.length > 0 ? `Error: ${errorCode}` : null}
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import YAML from 'yaml'
|
|||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
|
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
|
||||||
|
|
||||||
|
import CloudDownloadIcon from '@material-ui/icons/CloudDownload';
|
||||||
|
import PublishIcon from '@material-ui/icons/Publish';
|
||||||
import CloudDownload from '@material-ui/icons/CloudDownload';
|
import CloudDownload from '@material-ui/icons/CloudDownload';
|
||||||
import EditIcon from '@material-ui/icons/Edit';
|
import EditIcon from '@material-ui/icons/Edit';
|
||||||
import DeleteIcon from '@material-ui/icons/Delete';
|
import DeleteIcon from '@material-ui/icons/Delete';
|
||||||
@@ -346,7 +348,7 @@ const Apps = (props) => {
|
|||||||
Activate App
|
Activate App
|
||||||
</Button></Link> : null
|
</Button></Link> : null
|
||||||
|
|
||||||
var deleteButton = ((selectedApp.private_id !== undefined && selectedApp.private_id.length > 0 && selectedApp.generated) || (selectedApp.downloaded != undefined && selectedApp.downloaded == true)) && activateButton === null ?
|
var deleteButton = ((selectedApp.private_id !== undefined && selectedApp.private_id.length > 0 && selectedApp.generated) || (selectedApp.downloaded != undefined && selectedApp.downloaded === true)) && activateButton === null ?
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
component="label"
|
component="label"
|
||||||
@@ -455,14 +457,15 @@ const Apps = (props) => {
|
|||||||
<div style={{width: "100%", margin: 25}}>
|
<div style={{width: "100%", margin: 25}}>
|
||||||
<h2>App Creator</h2>
|
<h2>App Creator</h2>
|
||||||
<a href="/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a>
|
<a href="/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a>
|
||||||
- <a href="https://github.com/frikky/OpenAPI-security-definitions" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a>
|
- <a href="https://github.com/frikky/security-openapis" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a>
|
||||||
- <a href="https://apis.guru/browse-apis/" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">OpenAPI directory</a>
|
- <a href="https://apis.guru/browse-apis/" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">OpenAPI directory</a>
|
||||||
<div/>
|
<div/>
|
||||||
Apps interact with eachother in workflows. They are created with the app creator, using OpenAPI specification or manually in python. Use the links above to find potential apps you're looking for using OpenAPI or make one from scratch. There's 1000+ available.
|
Apps interact with eachother in workflows. They are created with the app creator, using OpenAPI specification or manually in python. Use the links above to find potential apps you're looking for using OpenAPI or make one from scratch. There's 1000+ available.
|
||||||
<div/>
|
<div/>
|
||||||
<div style={{marginTop: 20}}>
|
<Divider style={{height: 1, backgroundColor: dividerColor, marginTop: 20, marginBottom: 20}} />
|
||||||
|
<div style={{}}>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="text"
|
||||||
component="label"
|
component="label"
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{marginRight: 10, }}
|
style={{marginRight: 10, }}
|
||||||
@@ -470,11 +473,12 @@ const Apps = (props) => {
|
|||||||
setOpenApiModal(true)
|
setOpenApiModal(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Create from OpenAPI
|
<PublishIcon style={{marginRight: 5}} /> Create from OpenAPI
|
||||||
</Button>
|
</Button>
|
||||||
<Link to="/apps/new" style={{textDecoration: "none", color: "#f85a3e"}}>
|
OR
|
||||||
|
<Link to="/apps/new" style={{marginLeft: 5, textDecoration: "none", color: "#f85a3e"}}>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="text"
|
||||||
component="label"
|
component="label"
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{}}
|
style={{}}
|
||||||
@@ -508,9 +512,9 @@ const Apps = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const appView = isLoggedIn ?
|
const appView = isLoggedIn ?
|
||||||
<div style={{maxWidth: 1366, margin: "auto",}}>
|
<div style={{maxWidth: window.innerWidth > 1366 ? 1366 : 1200, margin: "auto",}}>
|
||||||
<div style={appViewStyle}>
|
<div style={appViewStyle}>
|
||||||
<div>
|
<div style={{flex: 1}}>
|
||||||
<Breadcrumbs aria-label="breadcrumb" separator="›" style={{color: "white",}}>
|
<Breadcrumbs aria-label="breadcrumb" separator="›" style={{color: "white",}}>
|
||||||
<Link to="/apps" style={{textDecoration: "none", color: "inherit",}}>
|
<Link to="/apps" style={{textDecoration: "none", color: "inherit",}}>
|
||||||
<h2 style={{color: "rgba(255,255,255,0.5)"}}>
|
<h2 style={{color: "rgba(255,255,255,0.5)"}}>
|
||||||
@@ -528,10 +532,10 @@ const Apps = (props) => {
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<UploadView/>
|
<UploadView/>
|
||||||
</div>
|
</div>
|
||||||
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "100%", width: "1px", backgroundColor: dividerColor}}/>
|
<Divider style={{marginBottom: 10, marginTop: 10, height: "100%", width: 1, backgroundColor: dividerColor}}/>
|
||||||
<div style={{flex: 1, marginLeft: 10, marginRight: 10}}>
|
<div style={{flex: 1, marginLeft: 10, marginRight: 10}}>
|
||||||
<div style={{display: "flex"}}>
|
<div style={{display: "flex"}}>
|
||||||
<div style={{flex: 10}}>
|
<div style={{flex: 1}}>
|
||||||
<h2>Available integrations</h2>
|
<h2>Available integrations</h2>
|
||||||
</div>
|
</div>
|
||||||
{isLoading ? <CircularProgress style={{marginTop: 13, marginRight: 15}} /> : null}
|
{isLoading ? <CircularProgress style={{marginTop: 13, marginRight: 15}} /> : null}
|
||||||
@@ -543,18 +547,20 @@ const Apps = (props) => {
|
|||||||
setSearchBackend(!searchBackend)}
|
setSearchBackend(!searchBackend)}
|
||||||
} />}
|
} />}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Tooltip title={"Download from Github"} style={{marginTop: "28px", width: "100%"}} aria-label={"Upload"}>
|
||||||
variant="outlined"
|
<Button
|
||||||
component="label"
|
variant="outlined"
|
||||||
color="primary"
|
component="label"
|
||||||
style={{margin: 5, maxHeight: 50, marginTop: 10}}
|
color="primary"
|
||||||
onClick={() => {
|
style={{margin: 5, maxHeight: 50, marginTop: 10}}
|
||||||
setOpenApi(baseRepository)
|
onClick={() => {
|
||||||
setLoadAppsModalOpen(true)
|
setOpenApi(baseRepository)
|
||||||
}}
|
setLoadAppsModalOpen(true)
|
||||||
>
|
}}
|
||||||
Download more apps
|
>
|
||||||
</Button>
|
<CloudDownloadIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<TextField
|
<TextField
|
||||||
style={{backgroundColor: inputColor}}
|
style={{backgroundColor: inputColor}}
|
||||||
@@ -577,7 +583,7 @@ const Apps = (props) => {
|
|||||||
<div style={{marginTop: 15}}>
|
<div style={{marginTop: 15}}>
|
||||||
{apps.length > 0 ?
|
{apps.length > 0 ?
|
||||||
filteredApps.length > 0 ?
|
filteredApps.length > 0 ?
|
||||||
<div style={{maxHeight: "78vh", overflowY: "scroll"}}>
|
<div style={{height: "75vh", overflowY: "scroll"}}>
|
||||||
{filteredApps.map(app => {
|
{filteredApps.map(app => {
|
||||||
return (
|
return (
|
||||||
appPaper(app)
|
appPaper(app)
|
||||||
@@ -642,10 +648,7 @@ const Apps = (props) => {
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
response.text().then(function (text) {
|
alert.success("Loaded existing apps!")
|
||||||
console.log("RETURN: ", text)
|
|
||||||
alert.success("Loaded existing apps!")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
stop()
|
stop()
|
||||||
@@ -656,11 +659,10 @@ const Apps = (props) => {
|
|||||||
console.log("DATA: ", responseJson)
|
console.log("DATA: ", responseJson)
|
||||||
if (responseJson.reason !== undefined) {
|
if (responseJson.reason !== undefined) {
|
||||||
alert.error("Failed loading: "+responseJson.reason)
|
alert.error("Failed loading: "+responseJson.reason)
|
||||||
} else {
|
|
||||||
alert.error("Failed loading")
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
console.log("ERROR: ", error.toString())
|
||||||
alert.error(error.toString())
|
alert.error(error.toString())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1017,13 +1019,13 @@ const Apps = (props) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{circularLoader}
|
{circularLoader}
|
||||||
<Button style={{borderRadius: "0px"}} onClick={() => setOpenApiModal(false)} color="primary">
|
<Button style={{borderRadius: "0px"}} onClick={() => setOpenApiModal(false)} color="primary">
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button style={{borderRadius: "0px"}} disabled={appValidation.length === 0} onClick={() => {
|
<Button style={{borderRadius: "0px"}} disabled={appValidation.length === 0} onClick={() => {
|
||||||
redirectOpenApi()
|
redirectOpenApi()
|
||||||
}} color="primary">
|
}} color="primary">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const hrefStyle = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Docs = (props) => {
|
const Docs = (props) => {
|
||||||
const { isLoaded, globalUrl } = props;
|
const { isLoaded, globalUrl, inputColor } = props;
|
||||||
|
|
||||||
const [data, setData] = useState("");
|
const [data, setData] = useState("");
|
||||||
const [firstrequest, setFirstrequest] = useState(true);
|
const [firstrequest, setFirstrequest] = useState(true);
|
||||||
@@ -58,8 +58,6 @@ const Docs = (props) => {
|
|||||||
|
|
||||||
// Continue this, and find the h2 with the data in it lol
|
// Continue this, and find the h2 with the data in it lol
|
||||||
if (window.location.hash.length > 0) {
|
if (window.location.hash.length > 0) {
|
||||||
console.log("HELLO")
|
|
||||||
|
|
||||||
var parent = document.getElementById("markdown_wrapper")
|
var parent = document.getElementById("markdown_wrapper")
|
||||||
if (parent !== null) {
|
if (parent !== null) {
|
||||||
var elements = parent.getElementsByTagName('h2')
|
var elements = parent.getElementsByTagName('h2')
|
||||||
@@ -166,6 +164,7 @@ const Docs = (props) => {
|
|||||||
flex: "1",
|
flex: "1",
|
||||||
maxWidth: 750,
|
maxWidth: 750,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
paddingBottom: 200,
|
||||||
}
|
}
|
||||||
|
|
||||||
function OuterLink(props) {
|
function OuterLink(props) {
|
||||||
@@ -179,6 +178,28 @@ const Docs = (props) => {
|
|||||||
return <img style={{maxWidth: "100%"}} alt={props.alt} src={props.src}/>
|
return <img style={{maxWidth: "100%"}} alt={props.alt} src={props.src}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CodeHandler(props) {
|
||||||
|
return (
|
||||||
|
<pre style={{padding: 10, minWidth: "50%", maxWidth: "100%", backgroundColor: inputColor}}>
|
||||||
|
<code>
|
||||||
|
{props.value}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Heading(props) {
|
||||||
|
const element = React.createElement(`h${props.level}`, {style: {marginTop: 25}}, props.children)
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{props.level !== 1 ? <Divider style={{width: "90%", marginTop: 25, backgroundColor: inputColor}} /> : null}
|
||||||
|
{element}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
//React.createElement("p", {style: {color: "red", backgroundColor: "blue"}}, this.props.paragraph)
|
||||||
|
|
||||||
|
|
||||||
//function unicodeToChar(text) {
|
//function unicodeToChar(text) {
|
||||||
// return text.replace(/\\u[\dA-F]{4}/gi,
|
// return text.replace(/\\u[\dA-F]{4}/gi,
|
||||||
// function (match) {
|
// function (match) {
|
||||||
@@ -191,11 +212,6 @@ const Docs = (props) => {
|
|||||||
<div style={Body}>
|
<div style={Body}>
|
||||||
<div style={SideBar}>
|
<div style={SideBar}>
|
||||||
<ul style={{listStyle: "none", paddingLeft: "0"}}>
|
<ul style={{listStyle: "none", paddingLeft: "0"}}>
|
||||||
<li style={{marginTop: "10px"}}>
|
|
||||||
<a style={hrefStyle} href="/">
|
|
||||||
<h2>Home</h2>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{list.map(item => {
|
{list.map(item => {
|
||||||
const path = "/docs/"+item
|
const path = "/docs/"+item
|
||||||
const newname = item.charAt(0).toUpperCase()+item.substring(1).split("_").join(" ")
|
const newname = item.charAt(0).toUpperCase()+item.substring(1).split("_").join(" ")
|
||||||
@@ -214,7 +230,12 @@ const Docs = (props) => {
|
|||||||
id="markdown_wrapper"
|
id="markdown_wrapper"
|
||||||
escapeHtml={false}
|
escapeHtml={false}
|
||||||
source={data}
|
source={data}
|
||||||
renderers={{link: OuterLink, image: Img}}
|
renderers={{
|
||||||
|
link: OuterLink,
|
||||||
|
image: Img,
|
||||||
|
code: CodeHandler,
|
||||||
|
heading: Heading,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import MenuItem from '@material-ui/core/MenuItem';
|
|||||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import Switch from '@material-ui/core/Switch';
|
import Switch from '@material-ui/core/Switch';
|
||||||
|
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
import CachedIcon from '@material-ui/icons/Cached';
|
import CachedIcon from '@material-ui/icons/Cached';
|
||||||
import EditIcon from '@material-ui/icons/Edit';
|
import EditIcon from '@material-ui/icons/Edit';
|
||||||
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||||
@@ -31,6 +32,9 @@ import Dialog from '@material-ui/core/Dialog';
|
|||||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import DialogActions from '@material-ui/core/DialogActions';
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
import DialogContent from '@material-ui/core/DialogContent';
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
|
import CloudDownloadIcon from '@material-ui/icons/CloudDownload';
|
||||||
|
|
||||||
|
const inputColor = "#383B40"
|
||||||
const surfaceColor = "#27292D"
|
const surfaceColor = "#27292D"
|
||||||
|
|
||||||
const Workflows = (props) => {
|
const Workflows = (props) => {
|
||||||
@@ -51,6 +55,10 @@ const Workflows = (props) => {
|
|||||||
const [, setTrackingId] = React.useState("")
|
const [, setTrackingId] = React.useState("")
|
||||||
|
|
||||||
const [collapseJson, setCollapseJson] = React.useState(false)
|
const [collapseJson, setCollapseJson] = React.useState(false)
|
||||||
|
const [field1, setField1] = React.useState("")
|
||||||
|
const [field2, setField2] = React.useState("")
|
||||||
|
const [downloadUrl, setDownloadUrl] = React.useState("https://github.com/frikky/shuffle-workflows")
|
||||||
|
const [loadWorkflowsModalOpen, setLoadWorkflowsModalOpen] = React.useState(false)
|
||||||
|
|
||||||
const [modalOpen, setModalOpen] = React.useState(false);
|
const [modalOpen, setModalOpen] = React.useState(false);
|
||||||
const [newWorkflowName, setNewWorkflowName] = React.useState("");
|
const [newWorkflowName, setNewWorkflowName] = React.useState("");
|
||||||
@@ -173,6 +181,7 @@ const Workflows = (props) => {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
||||||
|
alert.error("Failed loading executions for current workflow")
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json()
|
return response.json()
|
||||||
@@ -758,7 +767,10 @@ const Workflows = (props) => {
|
|||||||
for (var key in event.target.files) {
|
for (var key in event.target.files) {
|
||||||
const file = event.target.files[key]
|
const file = event.target.files[key]
|
||||||
if (file.type !== "application/json") {
|
if (file.type !== "application/json") {
|
||||||
//alert.error("File has to contain json.")
|
if (file.type !== undefined) {
|
||||||
|
alert.error("File has to contain valid json")
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,6 +810,8 @@ const Workflows = (props) => {
|
|||||||
reader.readAsText(file)
|
reader.readAsText(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setLoadWorkflowsModalOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const modalView = modalOpen ?
|
const modalView = modalOpen ?
|
||||||
@@ -886,11 +900,18 @@ const Workflows = (props) => {
|
|||||||
<Tooltip color="primary" title={"Create new workflow"} placement="top">
|
<Tooltip color="primary" title={"Create new workflow"} placement="top">
|
||||||
<Button color="primary" style={{}} variant="text" onClick={() => setModalOpen(true)}><AddIcon /></Button>
|
<Button color="primary" style={{}} variant="text" onClick={() => setModalOpen(true)}><AddIcon /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{/*
|
||||||
<Tooltip color="primary" title={"Import workflows"} placement="top">
|
<Tooltip color="primary" title={"Import workflows"} placement="top">
|
||||||
<Button color="primary" style={{}} variant="text" onClick={() => upload.click()}>
|
<Button color="primary" style={{}} variant="text" onClick={() => upload.click()}>
|
||||||
<PublishIcon />
|
<PublishIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
*/}
|
||||||
|
<Tooltip color="primary" title={"Download workflows"} placement="top">
|
||||||
|
<Button color="primary" style={{}} variant="text" onClick={() => setLoadWorkflowsModalOpen(true)}>
|
||||||
|
<CloudDownloadIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
<input hidden type="file" multiple="multiple" ref={(ref) => upload = ref} onChange={importFiles} />
|
<input hidden type="file" multiple="multiple" ref={(ref) => upload = ref} onChange={importFiles} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -962,10 +983,160 @@ const Workflows = (props) => {
|
|||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
const importWorkflowsFromUrl = (url) => {
|
||||||
|
console.log("IMPORT WORKFLOWS FROM ", downloadUrl)
|
||||||
|
|
||||||
|
const parsedData = {
|
||||||
|
"url": url,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field1.length > 0) {
|
||||||
|
parsedData["field_1"] = field1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field2.length > 0) {
|
||||||
|
parsedData["field_2"] = field2
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.success("Getting specific workflows from your URL.")
|
||||||
|
var cors = "cors"
|
||||||
|
fetch(globalUrl+"/api/v1/workflows/download_remote", {
|
||||||
|
method: "POST",
|
||||||
|
mode: "cors",
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(parsedData),
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
response.text().then(function (text) {
|
||||||
|
console.log("RETURN: ", text)
|
||||||
|
alert.success("Loaded existing apps!")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
console.log("DATA: ", responseJson)
|
||||||
|
if (responseJson.reason !== undefined) {
|
||||||
|
alert.error("Failed loading: "+responseJson.reason)
|
||||||
|
} else {
|
||||||
|
alert.error("Failed loading")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
alert.error(error.toString())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGithubValidation = () => {
|
||||||
|
importWorkflowsFromUrl(downloadUrl)
|
||||||
|
setLoadWorkflowsModalOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const workflowDownloadModalOpen = loadWorkflowsModalOpen ?
|
||||||
|
<Dialog modal
|
||||||
|
open={loadWorkflowsModalOpen}
|
||||||
|
onClose={() => {
|
||||||
|
}}
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
backgroundColor: surfaceColor,
|
||||||
|
color: "white",
|
||||||
|
minWidth: "800px",
|
||||||
|
minHeight: "320px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<div style={{color: "rgba(255,255,255,0.9)"}}>
|
||||||
|
Load workflows from github repo
|
||||||
|
<div style={{float: "right"}}>
|
||||||
|
<Tooltip color="primary" title={"Import manually"} placement="top">
|
||||||
|
<Button color="primary" style={{}} variant="text" onClick={() => upload.click()}>
|
||||||
|
<PublishIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent style={{color: "rgba(255,255,255,0.65)"}}>
|
||||||
|
Repository (supported: github, gitlab, bitbucket)
|
||||||
|
<TextField
|
||||||
|
style={{backgroundColor: inputColor}}
|
||||||
|
variant="outlined"
|
||||||
|
margin="normal"
|
||||||
|
value={downloadUrl}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
height: "50px",
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onChange={e => setDownloadUrl(e.target.value)}
|
||||||
|
placeholder="https://github.com/frikky/shuffle-apps"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span style={{marginTop: 10}}>Authentication (optional - private repos etc):</span>
|
||||||
|
<div style={{display: "flex"}}>
|
||||||
|
<TextField
|
||||||
|
style={{flex: 1, backgroundColor: inputColor}}
|
||||||
|
variant="outlined"
|
||||||
|
margin="normal"
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
height: "50px",
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onChange={e => setField1(e.target.value)}
|
||||||
|
type="username"
|
||||||
|
placeholder="Username / APIkey (optional)"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
style={{flex: 1, backgroundColor: inputColor}}
|
||||||
|
variant="outlined"
|
||||||
|
margin="normal"
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
height: "50px",
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onChange={e => setField2(e.target.value)}
|
||||||
|
type="password"
|
||||||
|
placeholder="Password (optional)"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button style={{borderRadius: "0px"}} onClick={() => setLoadWorkflowsModalOpen(false)} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button style={{borderRadius: "0px"}} disabled={downloadUrl.length === 0 || !downloadUrl.includes("http")} onClick={() => {
|
||||||
|
handleGithubValidation()
|
||||||
|
}} color="primary">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
: null
|
||||||
|
|
||||||
const loadedCheck = isLoaded && isLoggedIn && workflowDone ?
|
const loadedCheck = isLoaded && isLoggedIn && workflowDone ?
|
||||||
<div>
|
<div>
|
||||||
{workflowView}
|
{workflowView}
|
||||||
{modalView}
|
{modalView}
|
||||||
|
{workflowDownloadModalOpen}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!---->
|
||||||
|
<defs>
|
||||||
|
<linearGradient y2="0%" x2="100%" y1="0%" x1="0%" id="30c29011-a081-4741-b6bb-e06d8873e7b7" gradientTransform="rotate(25)">
|
||||||
|
<stop stop-color=" rgb(169, 37, 128)" offset="0%"/>
|
||||||
|
<stop stop-color=" rgb(247, 188, 0)" offset="100%"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<g>
|
||||||
|
<title>background</title>
|
||||||
|
<rect fill="none" id="canvas_background" height="202" width="202" y="-1" x="-1"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<title>Layer 1</title>
|
||||||
|
<g fill="url(#30c29011-a081-4741-b6bb-e06d8873e7b7)" transform="matrix(1.1414221157695137,0,0,1.1414221157695137,-10.343879888974278,-11.465698853151771) " id="1085c47b-b6bc-4e6d-b1f9-4301cfb34be7">
|
||||||
|
<switch transform="translate(2.6282968521118164,0) translate(0.0000033420565159758553,0) translate(-0.2776981592178345,0) translate(44.68110275268555,47.30940246582031) ">
|
||||||
|
<g id="svg_2">
|
||||||
|
<path id="svg_3" d="m89.141,35.617c-2.891,-12.765 -11.297,-21.212 -20.442,-25.253c11.371,10.018 21.846,29.405 8.814,47.069c-5.406,7.331 -16.217,10.228 -20.746,8.184c0,0 7.002,-1.487 11.357,-5.295c8.469,-8.017 11.299,-20.932 4.52,-32.673a25.839,25.839 0 0 0 -3.357,-4.575c-0.018,-0.021 -0.033,-0.042 -0.051,-0.062c-4.764,-5.683 -11.307,-9.075 -18.337,-10.116c-9.127,-1.715 -20.896,0.515 -29.71,8.666c-9.609,8.888 -12.721,20.391 -11.647,30.333c2.989,-14.858 14.542,-33.622 36.355,-31.171c9.053,1.019 16.965,8.932 17.461,13.877c0,0 -5.277,-8.281 -18.365,-8.281c-0.24,0.004 -0.747,0.024 -0.761,0.024l-0.167,0.01c-8.51,0.333 -16.783,4.784 -21.83,13.526a25.819,25.819 0 0 0 -2.284,5.195l-0.028,0.074c-2.539,6.968 -2.205,14.33 0.407,20.938c3.079,8.763 10.896,17.841 22.361,21.397c12.502,3.878 24.02,0.82 32.092,-5.079c-14.363,4.837 -36.389,4.216 -45.173,-15.899c-3.645,-8.35 -0.749,-19.159 3.287,-22.061c0,0 -4.534,8.71 2.012,20.044c4.482,7.484 12.617,12.658 22.949,12.658c0.498,0 4.488,-0.311 5.926,-0.633l0.08,-0.011c7.303,-1.286 13.512,-5.256 17.928,-10.822c6.05,-7.046 10.003,-18.356 7.349,-30.064z"/>
|
||||||
|
</g>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 440 KiB |
@@ -106,9 +106,9 @@ func deployWorker(cli *dockerclient.Client, image string, identifier string, env
|
|||||||
|
|
||||||
err = cli.ContainerStart(context.Background(), cont.ID, types.ContainerStartOptions{})
|
err = cli.ContainerStart(context.Background(), cont.ID, types.ContainerStartOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to start container: %s", err)
|
log.Printf("Failed to start container in environment %s: %s", environment, err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Container %s is created", cont.ID)
|
log.Printf("Container %s was created under environment %s", cont.ID, environment)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -401,7 +401,7 @@ func main() {
|
|||||||
//log.Println(string(body))
|
//log.Println(string(body))
|
||||||
//log.Println(resultResp)
|
//log.Println(resultResp)
|
||||||
if len(toBeRemoved.Data) == len(executionRequests.Data) {
|
if len(toBeRemoved.Data) == len(executionRequests.Data) {
|
||||||
log.Println("Should remove ALL!")
|
//log.Println("Should remove ALL!")
|
||||||
} else {
|
} else {
|
||||||
log.Printf("NOT IMPLEMENTED: Should remove %d workflows from backend because they're executed!", len(toBeRemoved.Data))
|
log.Printf("NOT IMPLEMENTED: Should remove %d workflows from backend because they're executed!", len(toBeRemoved.Data))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# Build script to make it work as an open source platform
|
|
||||||
|
|
||||||
# 1. Grab builtin functions - Done in backend as a button click
|
|
||||||
# 2. Upload to database & build docker images
|
|
||||||
# 3. Run docker-compose: frontend, backend, database & orborus
|
|
||||||
# 4. Set up docker swarm for apps?
|
|
||||||
|
|
||||||
# Basic overview of how it works:
|
|
||||||
#
|
|
||||||
# Backend: o
|
|
||||||
# |
|
|
||||||
# Orborus: o
|
|
||||||
# / \
|
|
||||||
# Workers: o o
|
|
||||||
# / / \
|
|
||||||
# Apps: o o o
|
|
||||||
|
|
||||||
# 1. Grab builtin functions
|
|
||||||
# Where should I have these? Maybe OpenAPI github repo and just preload?
|
|
||||||
|
|
||||||
echo "Building frontend"
|
|
||||||
cd frontend
|
|
||||||
npm run build
|
|
||||||
rm -rf ../backend/go-app/build
|
|
||||||
cp -r build/ ../backend/go-app/build
|
|
||||||
|
|
||||||
echo "Setting up backend"
|
|
||||||
cd ../backend/go-app
|
|
||||||
go build
|
|
||||||
go test
|
|
||||||
|
|
||||||
#gcloud app deploy $GOPATH/src/github.com/frikky/shuffle/app.yaml
|
|
||||||
echo "This script is not finished. Please follow the docker installation guide here: https://github.com/frikky/shuffle/blob/master/install-guide.md"
|
|
||||||