diff --git a/.env b/.env index 6af3f207..a07a0644 100644 --- a/.env +++ b/.env @@ -13,3 +13,4 @@ BACKEND_PORT=5001 FRONTEND_PORT=3001 FRONTEND_PORT_HTTPS=3443 OUTER_HOSTNAME=shuffle-backend +DB_LOCATION=/etc/shuffle diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index d15792a0..03a71e01 100644 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -588,6 +588,7 @@ class AppBase: logging.basicConfig(format="{asctime} - {name} - {levelname}:{message}", style='{') logger = logging.getLogger(f"{cls.__name__}") logger.setLevel(logging.DEBUG) + print("Started execution!!") app = cls(redis=None, logger=logger, console_logger=logger) diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index abe03fa8..d1cf6ac0 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -4,17 +4,19 @@ import ( "archive/zip" "bytes" "context" + "encoding/json" "errors" "fmt" "io" "io/ioutil" "log" "os" + "strconv" "strings" "cloud.google.com/go/storage" "github.com/getkin/kin-openapi/openapi3" - "github.com/satori/go.uuid" + //"github.com/satori/go.uuid" "gopkg.in/yaml.v2" ) @@ -277,7 +279,13 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet if swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.In == "header" { authenticationSetup = fmt.Sprintf("headers[\"%s\"] = apikey", swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name) } else if swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.In == "query" { - authenticationSetup = fmt.Sprintf("url+=f\"?%s={apikey}\"", swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name) + // This might suck lol + key := "?" + if strings.Contains(url, "?") { + key = "&" + } + + authenticationSetup = fmt.Sprintf("url+=f\"%s%s={apikey}\"", key, swagger.Components.SecuritySchemes["ApiKeyAuth"].Value.Name) } } } @@ -306,46 +314,75 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet bodyParameter := "" bodyAddin := "" + bodyFormatter := "" postParameters := []string{"post", "patch", "put"} for _, item := range postParameters { if method == item { bodyParameter = ", body=\"\"" - bodyAddin = ", json=body" + bodyAddin = ", data=body" + + // FIXME: Does JSON data work? + bodyFormatter = ` + if (body.startswith("{") and body.endswith("}")) or (body.startswith("[") and body.endswith("]")): + try: + body = json.dumps(body) + except: + pass + ` break } } // Extra param for url if it's changeable // Extra param for authentication scheme(s) - data := fmt.Sprintf(` async def %s(self%s%s%s%s%s): headers={} url=f"%s%s" %s %s + %s return requests.%s(url, headers=headers%s%s).text - `, functionname, authenticationParameter, urlParameter, parameterData, queryString, bodyParameter, urlInline, url, authenticationSetup, queryData, method, authenticationAddin, bodyAddin) + `, + functionname, + authenticationParameter, + urlParameter, + parameterData, + queryString, + bodyParameter, + urlInline, + url, + authenticationSetup, + queryData, + bodyFormatter, + method, + authenticationAddin, + bodyAddin, + ) //log.Println(data) //log.Println(functionname) return functionname, data } -func generateYaml(swagger *openapi3.Swagger, newmd5 string) (WorkflowApp, []string, error) { +func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger, WorkflowApp, []string, error) { api := WorkflowApp{} //log.Printf("%#v", swagger.Info) if len(swagger.Info.Title) == 0 { - return WorkflowApp{}, []string{}, errors.New("Swagger.Info.Title can't be empty.") + return swagger, WorkflowApp{}, []string{}, errors.New("Swagger.Info.Title can't be empty.") } if len(swagger.Servers) == 0 { - return WorkflowApp{}, []string{}, errors.New("Swagger.Servers can't be empty. Add 'servers':[{'url':'hostname.com'}'") + return swagger, WorkflowApp{}, []string{}, errors.New("Swagger.Servers can't be empty. Add 'servers':[{'url':'hostname.com'}'") } api.Name = swagger.Info.Title api.Description = swagger.Info.Description - api.ID = uuid.NewV4().String() + + // FIXME: Versioning issue? + api.ID = newmd5 + //uuid.NewV4().String() + api.IsValid = true api.Link = swagger.Servers[0].URL // host doesnt exist lol if strings.HasSuffix(api.Link, "/") { @@ -365,6 +402,20 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (WorkflowApp, []stri // Setting up security schemes extraParameters := []WorkflowAppActionParameter{} + if val, ok := swagger.Info.ExtensionProps.Extensions["x-logo"]; ok { + j, err := json.Marshal(&val) + if err == nil { + if j[0] == 0x22 && j[len(j)-1] == 0x22 { + j = j[1 : len(j)-1] + } + + //log.Printf("%s", j) + api.SmallImage = string(j) + api.LargeImage = string(j) + log.Printf("Set images!") + } + } + securitySchemes := swagger.Components.SecuritySchemes if securitySchemes != nil { //log.Printf("%#v", securitySchemes) @@ -456,53 +507,57 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (WorkflowApp, []stri // This is the python code to be generated // Could just as well be go at this point lol pythonFunctions := []string{} - for actualPath, path := range swagger.Paths { - - //log.Printf("%#v", path) - //log.Printf("%#v", actualPath) - // FIXME: Add everything from here: // https://godoc.org/github.com/getkin/kin-openapi/openapi3#PathItem - firstQuery := true if path.Get != nil { - action, curCode := handleGet(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handleGet(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } if path.Connect != nil { - action, curCode := handleConnect(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handleConnect(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } if path.Head != nil { - action, curCode := handleHead(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handleHead(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } if path.Delete != nil { - action, curCode := handleDelete(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handleDelete(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } if path.Post != nil { - action, curCode := handlePost(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handlePost(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } if path.Patch != nil { - action, curCode := handlePatch(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handlePatch(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } if path.Put != nil { - action, curCode := handlePut(swagger, api, extraParameters, path, actualPath, firstQuery) + action, curCode := handlePut(swagger, api, extraParameters, path, actualPath) api.Actions = append(api.Actions, action) pythonFunctions = append(pythonFunctions, curCode) } + + // Has to be here because its used differently above. + // FIXING this is done during export instead? + //log.Printf("OLDPATH: %s", actualPath) + //if strings.Contains(actualPath, "?") { + // actualPath = strings.Split(actualPath, "?")[0] + //} + + //log.Printf("NEWPATH: %s", actualPath) + //newPaths[actualPath] = path } - return api, pythonFunctions, nil + return swagger, api, pythonFunctions, nil } // FIXME - have this give a real version? @@ -637,6 +692,7 @@ func getRunner(classname string) string { return fmt.Sprintf(` # Run the actual thing after we've checked params def run(request): + print("Started execution!") action = request.get_json() print(action) print(type(action)) @@ -679,7 +735,7 @@ func fixFunctionName(functionName, actualPath string) string { return functionName } -func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm functionName := fixFunctionName(path.Connect.Summary, actualPath) @@ -699,13 +755,13 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} parameters := []string{} optionalParameters := []WorkflowAppActionParameter{} if len(path.Connect.Parameters) > 0 { for _, param := range path.Connect.Parameters { - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } curParam := WorkflowAppActionParameter{ @@ -718,6 +774,24 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -737,13 +811,16 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ parameters = append(parameters, param.Value.Name) + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } @@ -764,7 +841,7 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ return action, curCode } -func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm functionName := fixFunctionName(path.Get.Summary, actualPath) @@ -784,7 +861,7 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} // FIXME - remove this when authentication is properly introduced @@ -793,8 +870,7 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor optionalParameters := []WorkflowAppActionParameter{} if len(path.Get.Parameters) > 0 { for _, param := range path.Get.Parameters { - //log.Printf("TYPE: %#v", param.Value.Schema) - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } @@ -808,6 +884,24 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -827,13 +921,17 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor parameters = append(parameters, param.Value.Name) + // Skipping simial + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } @@ -854,7 +952,7 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor return action, curCode } -func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm functionName := fixFunctionName(path.Head.Summary, actualPath) @@ -874,13 +972,13 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} parameters := []string{} optionalParameters := []WorkflowAppActionParameter{} if len(path.Head.Parameters) > 0 { for _, param := range path.Head.Parameters { - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } curParam := WorkflowAppActionParameter{ @@ -893,6 +991,24 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -912,13 +1028,16 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo parameters = append(parameters, param.Value.Name) + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } @@ -939,7 +1058,7 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo return action, curCode } -func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm functionName := fixFunctionName(path.Delete.Summary, actualPath) @@ -959,13 +1078,13 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} parameters := []string{} optionalParameters := []WorkflowAppActionParameter{} if len(path.Delete.Parameters) > 0 { for _, param := range path.Delete.Parameters { - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } curParam := WorkflowAppActionParameter{ @@ -978,6 +1097,24 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -997,13 +1134,16 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] parameters = append(parameters, param.Value.Name) + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } @@ -1024,7 +1164,7 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] return action, curCode } -func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm //log.Printf("PATH: %s", actualPath) functionName := fixFunctionName(path.Post.Summary, actualPath) @@ -1038,33 +1178,26 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo Parameters: extraParameters, } + if path.Post.RequestBody != nil { + log.Printf("RequestBody: %#v", path.Post.RequestBody) + } + action.Returns.Schema.Type = "string" baseUrl := fmt.Sprintf("%s%s", api.Link, actualPath) - //log.Println(path.Parameters) - // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} parameters := []string{} - optionalParameters := []WorkflowAppActionParameter{ - WorkflowAppActionParameter{ - Name: "body", - Description: "The body to use", - Multiline: true, - Required: false, - Example: `{"username": "test"}`, - Schema: SchemaDefinition{ - Type: "string", - }, - }, - } + optionalParameters := []WorkflowAppActionParameter{} + if len(path.Post.Parameters) > 0 { for _, param := range path.Post.Parameters { - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } + curParam := WorkflowAppActionParameter{ Name: param.Value.Name, Description: param.Value.Description, @@ -1075,6 +1208,24 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -1094,13 +1245,16 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo parameters = append(parameters, param.Value.Name) + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } @@ -1121,7 +1275,7 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo return action, curCode } -func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm functionName := fixFunctionName(path.Patch.Summary, actualPath) @@ -1141,24 +1295,13 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} parameters := []string{} - optionalParameters := []WorkflowAppActionParameter{ - WorkflowAppActionParameter{ - Name: "body", - Description: "The body to use", - Multiline: true, - Required: false, - Example: `{"username": "test"}`, - Schema: SchemaDefinition{ - Type: "string", - }, - }, - } + optionalParameters := []WorkflowAppActionParameter{} if len(path.Patch.Parameters) > 0 { for _, param := range path.Patch.Parameters { - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } curParam := WorkflowAppActionParameter{ @@ -1171,6 +1314,24 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -1190,13 +1351,16 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W parameters = append(parameters, param.Value.Name) + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } @@ -1217,7 +1381,7 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W return action, curCode } -func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string, firstQuery bool) (WorkflowAppAction, string) { +func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []WorkflowAppActionParameter, path *openapi3.PathItem, actualPath string) (WorkflowAppAction, string) { // What to do with this, hmm functionName := fixFunctionName(path.Put.Summary, actualPath) @@ -1237,24 +1401,14 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor // Parameters: []WorkflowAppActionParameter{}, // FIXME - add data for POST stuff - firstQuery = true + firstQuery := true optionalQueries := []string{} parameters := []string{} - optionalParameters := []WorkflowAppActionParameter{ - WorkflowAppActionParameter{ - Name: "body", - Description: "The body to use", - Multiline: true, - Required: false, - Example: `{"username": "test"}`, - Schema: SchemaDefinition{ - Type: "string", - }, - }, - } + optionalParameters := []WorkflowAppActionParameter{} + if len(path.Put.Parameters) > 0 { for _, param := range path.Put.Parameters { - if param.Value.Schema == nil { + if param.Value.Schema == nil || param.Value.In == "header" { continue } curParam := WorkflowAppActionParameter{ @@ -1267,6 +1421,24 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor }, } + // FIXME: Example & Multiline + if param.Value.Example != nil { + curParam.Example = param.Value.Example.(string) + + if param.Value.Name == "body" { + curParam.Value = param.Value.Example.(string) + } + } + if val, ok := param.Value.ExtensionProps.Extensions["multiline"]; ok { + j, err := json.Marshal(&val) + if err == nil { + b, err := strconv.ParseBool(string(j)) + if err == nil { + curParam.Multiline = b + } + } + } + if param.Value.Required { action.Parameters = append(action.Parameters, curParam) } else { @@ -1286,13 +1458,16 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor parameters = append(parameters, param.Value.Name) + if strings.Contains(baseUrl, fmt.Sprintf("%s={%s}", param.Value.Name, param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) - firstQuery = false } + firstQuery = false } } diff --git a/backend/go-app/main.go b/backend/go-app/main.go index dc73b5c4..bac7e31a 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -1906,6 +1906,7 @@ func checkAdminLogin(resp http.ResponseWriter, request *http.Request) { if err != nil { resp.WriteHeader(401) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err))) + return } if count == 0 { @@ -2112,7 +2113,6 @@ func SetSession(ctx context.Context, Userdata User, value string) error { func setOpenApiDatastore(ctx context.Context, id string, data ParsedOpenApi) error { k := datastore.NameKey("openapi3", id, nil) if _, err := dbclient.Put(ctx, k, &data); err != nil { - log.Println(err) return err } @@ -5075,6 +5075,8 @@ func getOpenapi(resp http.ResponseWriter, request *http.Request) { return } + log.Printf("API LENGTH GET: %d, ID: %s", len(parsedApi.Body), id) + parsedApi.Success = true data, err := json.Marshal(parsedApi) if err != nil { @@ -5505,13 +5507,6 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { // Test = client side with fetch? ctx := context.Background() - //client, err := storage.NewClient(ctx) - //if err != nil { - // log.Printf("Failed to create client (storage): %v", err) - // resp.WriteHeader(401) - // resp.Write([]byte(`{"success": false, "reason": "Failed creating client"}`)) - // return - //} swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(body) if err != nil { @@ -5534,7 +5529,7 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { } //log.Printf("Should generate yaml") - api, pythonfunctions, err := generateYaml(swagger, newmd5) + swagger, api, pythonfunctions, err := generateYaml(swagger, newmd5) if err != nil { log.Printf("Failed building and generating yaml: %s", err) resp.WriteHeader(500) @@ -5542,12 +5537,28 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { return } - api.Owner = user.Id - if len(test.Image) > 0 { - api.SmallImage = test.Image - api.LargeImage = test.Image + // FIXME: CHECK IF SAME NAME AS NORMAL APP + // Can't overwrite existing normal app + workflowApps, err := getAllWorkflowApps(ctx) + if err != nil { + log.Printf("Failed getting all workflow apps from database to verify: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Failed to verify existence"}`)) + return } + // Same name only? + lowerName := strings.ToLower(swagger.Info.Title) + for _, app := range workflowApps { + if app.Downloaded && !app.Generated && strings.ToLower(app.Name) == lowerName { + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Normal app with name %s already exists. Delete it first."}`, swagger.Info.Title))) + return + } + } + + api.Owner = user.Id + err = dumpApi(basePath, api) if err != nil { log.Printf("Failed dumping yaml: %s", err) @@ -5569,7 +5580,7 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { identifier = strings.Replace(identifier, " ", "-", -1) identifier = strings.Replace(identifier, "_", "-", -1) - log.Printf("Successfully uploaded %s to bucket. Proceeding to cloud function", identifier) + log.Printf("Successfully parsed %s. Proceeding to docker container", identifier) // Now that the baseline is setup, we need to make it into a cloud function // 1. Upload the API to datastore for use @@ -5684,24 +5695,38 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { return } + log.Printf("DO I REACH HERE WHEN SAVING?") parsed := ParsedOpenApi{ - ID: api.ID, + ID: newmd5, Body: string(body), } + log.Printf("API LENGTH: %d, ID: %s", len(parsed.Body), newmd5) + // FIXME: Might cause versioning issues if we re-use the same!! + // FIXME: Need a way to track different versions of the same app properly. + // Hint: Save API.id somewhere, and use newmd5 to save latest version + err = setOpenApiDatastore(ctx, newmd5, parsed) + if err != nil { + log.Printf("Failed saving to datastore: %s", err) + resp.WriteHeader(500) + resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "%"}`, err))) + } + + // Backup every single one setOpenApiDatastore(ctx, api.ID, parsed) - err = increaseStatisticsField(ctx, "total_apps_created", api.ID, 1) + + err = increaseStatisticsField(ctx, "total_apps_created", newmd5, 1) if err != nil { log.Printf("Failed to increase success execution stats: %s", err) } - err = increaseStatisticsField(ctx, "openapi_apps_created", api.ID, 1) + err = increaseStatisticsField(ctx, "openapi_apps_created", newmd5, 1) if err != nil { log.Printf("Failed to increase success execution stats: %s", err) } resp.WriteHeader(200) - resp.Write([]byte(`{"success": true}`)) + resp.Write([]byte(fmt.Sprintf(`{"success": true, "id": "%s"}`, api.ID))) } func healthCheckHandler(resp http.ResponseWriter, request *http.Request) { @@ -5748,10 +5773,10 @@ func runInit(ctx context.Context) { } } + //log.Printf("Schedule time: every %d seconds", schedule.Seconds) jobret, err := newscheduler.Every(schedule.Seconds).Seconds().NotImmediately().Run(job) if err != nil { log.Printf("Failed to schedule workflow: %s", err) - // FIXME: what now? lol:w } scheduledJobs[schedule.Id] = jobret @@ -5837,7 +5862,7 @@ func init() { log.Printf("Running INIT process") dbclient, err = datastore.NewClient(ctx, gceProject) if err != nil { - log.Printf("DBclient error during init: %s", err) + panic(fmt.Sprintf("DBclient error during init: %s", err)) } go runInit(ctx) diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 07ae2c18..5ba6c7f5 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -1360,10 +1360,11 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) { break } - if app.Name == action.AppName && app.AppVersion == action.AppVersion { - curapp = app - break - } + // Has to NOT be generated + //if app.Name == action.AppName && app.AppVersion == action.AppVersion { + // curapp = app + // break + //} } // Check to see if the whole app is valid @@ -1381,7 +1382,6 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) { curappaction = curAction break } - log.Println(action.Name, curAction.Name) } // Check to see if the action is valid @@ -2340,7 +2340,16 @@ func scheduleWorkflow(resp http.ResponseWriter, request *http.Request) { return } - log.Printf("Schedulearg: %s", string(scheduleArg)) + // Clean up garbage. This might be wrong in some very specific use-cases + parsedBody := string(scheduleArg) + parsedBody = strings.Replace(parsedBody, "\\\"", "\"", -1) + if len(parsedBody) > 0 { + if string(parsedBody[0]) == `"` && string(parsedBody[len(parsedBody)-1]) == "\"" { + parsedBody = parsedBody[1 : len(parsedBody)-1] + } + } + + log.Printf("Schedulearg: %s", parsedBody) err = createSchedule( ctx, @@ -2348,7 +2357,7 @@ func scheduleWorkflow(resp http.ResponseWriter, request *http.Request) { workflow.ID, schedule.Name, schedule.Frequency, - scheduleArg, + []byte(parsedBody), ) // FIXME - real error message lol @@ -2736,6 +2745,9 @@ func getWorkflowAppConfig(resp http.ResponseWriter, request *http.Request) { return } + //log.Printf("%#v", parsedApi) + log.Printf("API LEN: %d, ID: %s", len(parsedApi.Body), fileId) + //log.Printf("Parsed API: %#v", parsedApi) if len(parsedApi.ID) > 0 { parsedApi.Success = true @@ -3325,7 +3337,6 @@ func iterateOpenApiGithub(fs billy.Filesystem, dir []os.FileInfo, extra string, // Check the file filename := file.Name() if strings.Contains(filename, "yaml") || strings.Contains(filename, "yml") { - appCounter += 1 //log.Printf("File: %s", filename) //log.Printf("Found file: %s", filename) tmpExtra := fmt.Sprintf("%s%s/", extra, file.Name()) @@ -3365,7 +3376,7 @@ func iterateOpenApiGithub(fs billy.Filesystem, dir []os.FileInfo, extra string, } //log.Printf("Should generate yaml") - api, _, err := generateYaml(swagger, parsedOpenApi.ID) + swagger, api, _, err := generateYaml(swagger, parsedOpenApi.ID) if err != nil { log.Printf("Failed building and generating yaml in loop (%s): %s", filename, err) continue @@ -3395,6 +3406,7 @@ func iterateOpenApiGithub(fs billy.Filesystem, dir []os.FileInfo, extra string, log.Printf("Failed setting workflowapp in loop: %s", err) continue } else { + appCounter += 1 log.Printf("Added %s:%s to the database from OpenAPI repo", api.Name, api.AppVersion) // Set OpenAPI datastore diff --git a/docker-compose.yml b/docker-compose.yml index e04cdbbe..0fbc7c41 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: - shuffle restart: unless-stopped volumes: - - /etc/shuffle:/etc/shuffle + - ${DB_LOCATION}:/etc/shuffle backend: #build: ./backend image: frikky/shuffle:backend diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 94f34ac5..a249ae8d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -960,9 +960,9 @@ "integrity": "sha512-b0JQb10Lie07iW2/9uKCQSrXif262d6zfYBstCLLJUk0JVA+7o/yLDg5p2+GkjgJbmodjHozIXs4Bi34RRhL8Q==" }, "@emotion/hash": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.3.tgz", - "integrity": "sha512-14ZVlsB9akwvydAdaEnVnvqu6J2P6ySv39hYyl/aoB6w/V+bXX0tay8cF6paqbgZsN2n5Xh15uF4pE+GvE+itw==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, "@emotion/is-prop-valid": { "version": "0.8.3", @@ -988,37 +988,87 @@ "integrity": "sha512-XiUPoS79r1G7PcpnNtq85TJ7inJWe0v+b5oZJZKb0pGHNIV6+UiNeQWiFGmuQ0aj7GEhnD/v9iqxIsjuRKtEnQ==" }, "@material-ui/core": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.9.3.tgz", - "integrity": "sha512-REIj62+zEvTgI/C//YL4fZxrCVIySygmpZglsu/Nl5jPqy3CDjZv1F9ubBYorHqmRgeVPh64EghMMWqk4egmfg==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.10.0.tgz", + "integrity": "sha512-yVlHe4b8AaoiTHhCOZeszHZ+T2iHU5DncdMGeNcQaaaO+q/Qrq0hxP3iFzTbgjRWnWwftEVQL668GRxcPJVRaQ==", "requires": { - "@babel/runtime": "^7.2.0", - "@material-ui/system": "^3.0.0-alpha.0", - "@material-ui/utils": "^3.0.0-alpha.2", - "@types/jss": "^9.5.6", - "@types/react-transition-group": "^2.0.8", - "brcast": "^3.0.1", - "classnames": "^2.2.5", - "csstype": "^2.5.2", - "debounce": "^1.1.0", - "deepmerge": "^3.0.0", - "dom-helpers": "^3.2.1", - "hoist-non-react-statics": "^3.2.1", - "is-plain-object": "^2.0.4", - "jss": "^9.8.7", - "jss-camel-case": "^6.0.0", - "jss-default-unit": "^8.0.2", - "jss-global": "^3.0.0", - "jss-nested": "^6.0.1", - "jss-props-sort": "^6.0.0", - "jss-vendor-prefixer": "^7.0.0", - "normalize-scroll-left": "^0.1.2", - "popper.js": "^1.14.1", - "prop-types": "^15.6.0", - "react-event-listener": "^0.6.2", - "react-transition-group": "^2.2.1", - "recompose": "0.28.0 - 0.30.0", - "warning": "^4.0.1" + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.10.0", + "@material-ui/system": "^4.9.14", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.12", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "^1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0", + "react-transition-group": "^4.4.0" + }, + "dependencies": { + "csstype": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz", + "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==" + }, + "dom-helpers": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz", + "integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^2.6.7" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.1.tgz", + "integrity": "sha512-nQbbCbQc9u/rpg1XCxoMYQTbSMVZjCDxErQ1ClCn9Pvcmv1lGads19ep0a2VsEiIJeHqjZley6EQGEC3Yo1xMA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.1.tgz", + "integrity": "sha512-nQbbCbQc9u/rpg1XCxoMYQTbSMVZjCDxErQ1ClCn9Pvcmv1lGads19ep0a2VsEiIJeHqjZley6EQGEC3Yo1xMA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" + } } }, "@material-ui/icons": { @@ -1030,84 +1080,62 @@ } }, "@material-ui/styles": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.5.0.tgz", - "integrity": "sha512-O0NSAECHK9f3DZK6wy56PZzp8b/7KSdfpJs8DSC7vnXUAoMPCTtchBKLzMtUsNlijiJFeJjSxNdQfjWXgyur5A==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz", + "integrity": "sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==", "requires": { "@babel/runtime": "^7.4.4", - "@emotion/hash": "^0.7.1", - "@material-ui/types": "^4.1.1", - "@material-ui/utils": "^4.1.0", - "clsx": "^1.0.2", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", "csstype": "^2.5.2", - "deepmerge": "^4.0.0", - "hoist-non-react-statics": "^3.2.1", - "jss": "^10.0.0", - "jss-plugin-camel-case": "^10.0.0", - "jss-plugin-default-unit": "^10.0.0", - "jss-plugin-global": "^10.0.0", - "jss-plugin-nested": "^10.0.0", - "jss-plugin-props-sort": "^10.0.0", - "jss-plugin-rule-value-function": "^10.0.0", - "jss-plugin-vendor-prefixer": "^10.0.0", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", "prop-types": "^15.7.2" }, "dependencies": { - "@material-ui/utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.4.0.tgz", - "integrity": "sha512-UXoQVwArQEQWXxf2FPs0iJGT+MePQpKr0Qh0CPoLc1OdF0GSMTmQczcqCzwZkeHxHAOq/NkIKM1Pb/ih1Avicg==", + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "requires": { - "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.6" - } - }, - "deepmerge": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.0.tgz", - "integrity": "sha512-/pED+kD8V9n15L1lon8DXEiWLQMW4tTiegn1kIWIQ+DBudOkFitz1cfjWQiSeKMPBQOknT3LpueyAmMVJ1Ho2g==" - }, - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" + "react-is": "^16.7.0" } } } }, "@material-ui/system": { - "version": "3.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-3.0.0-alpha.2.tgz", - "integrity": "sha512-odmxQ0peKpP7RQBQ8koly06YhsPzcoVib1vByVPBH4QhwqBXuYoqlCjt02846fYspAqkrWzjxnWUD311EBbxOA==", + "version": "4.9.14", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", + "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", "requires": { - "@babel/runtime": "^7.2.0", - "deepmerge": "^3.0.0", - "prop-types": "^15.6.0", - "warning": "^4.0.1" + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" } }, "@material-ui/types": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-4.1.1.tgz", - "integrity": "sha512-AN+GZNXytX9yxGi0JOfxHrRTbhFybjUJ05rnsBVjcB+16e466Z0Xe5IxawuOayVZgTBNDxmPKo5j4V6OnMtaSQ==", - "requires": { - "@types/react": "*" - } + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" }, "@material-ui/utils": { - "version": "3.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-3.0.0-alpha.3.tgz", - "integrity": "sha512-rwMdMZptX0DivkqBuC+Jdq7BYTXwqKai5G5ejPpuEDKpWzi1Oxp+LygGw329FrKpuKeiqpcymlqJTjmy+quWng==", + "version": "4.9.12", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.9.12.tgz", + "integrity": "sha512-/0rgZPEOcZq5CFA4+4n6Q6zk7fi8skHhH2Bcra8R3epoJEYy5PL55LuMazPtPH1oKeRausDV/Omz4BbgFsn1HQ==", "requires": { - "@babel/runtime": "^7.2.0", - "prop-types": "^15.6.0", - "react-is": "^16.6.3" + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" } }, "@mrmlnc/readdir-enhanced": { @@ -1337,9 +1365,9 @@ } }, "@types/react-transition-group": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.2.tgz", - "integrity": "sha512-5Fv2DQNO+GpdPZcxp2x/OQG/H19A01WlmpjVD9cKvVFmoVLOZ9LvBgSWG6pSXIU4og5fgbvGPaCV5+VGkWAEHA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", + "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", "requires": { "@types/react": "*" } @@ -4788,11 +4816,27 @@ "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=" }, "css-vendor": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz", - "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", "requires": { + "@babel/runtime": "^7.8.3", "is-in-browser": "^1.0.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.1.tgz", + "integrity": "sha512-nQbbCbQc9u/rpg1XCxoMYQTbSMVZjCDxErQ1ClCn9Pvcmv1lGads19ep0a2VsEiIJeHqjZley6EQGEC3Yo1xMA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" + } } }, "css-what": { @@ -5504,9 +5548,9 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "deepmerge": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.2.1.tgz", - "integrity": "sha512-+hbDSzTqEW0fWgnlKksg7XAOtT+ddZS5lHZJ6f6MdixRs9wQy+50fm1uUCVb1IkvjLUYX/SfFO021ZNwriURTw==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", + "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==" }, "default-gateway": { "version": "2.7.2", @@ -11052,23 +11096,14 @@ } }, "jss": { - "version": "9.8.7", - "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", - "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.1.1.tgz", + "integrity": "sha512-Xz3qgRUFlxbWk1czCZibUJqhVPObrZHxY3FPsjCXhDld4NOj1BgM14Ir5hVm+Qr6OLqVljjGvoMcCdXNOAbdkQ==", "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^2.6.5", "is-in-browser": "^1.1.3", - "symbol-observable": "^1.1.0", - "warning": "^3.0.0" - }, - "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "requires": { - "loose-envify": "^1.0.0" - } - } + "tiny-warning": "^1.0.2" } }, "jss-camel-case": { @@ -11108,179 +11143,69 @@ } }, "jss-plugin-camel-case": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.0.tgz", - "integrity": "sha512-yALDL00+pPR4FJh+k07A8FeDvfoPPuXU48HLy63enAubcVd3DnS+2rgqPXglHDGixIDVkCSXecl/l5GAMjzIbA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.1.1.tgz", + "integrity": "sha512-MDIaw8FeD5uFz1seQBKz4pnvDLnj5vIKV5hXSVdMaAVq13xR6SVTVWkIV/keyTs5txxTvzGJ9hXoxgd1WTUlBw==", "requires": { "@babel/runtime": "^7.3.1", "hyphenate-style-name": "^1.0.3", - "jss": "10.0.0" - }, - "dependencies": { - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } + "jss": "10.1.1" } }, "jss-plugin-default-unit": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.0.tgz", - "integrity": "sha512-sURozIOdCtGg9ap18erQ+ijndAfEGtTaetxfU3H4qwC18Bi+fdvjlY/ahKbuu0ASs7R/+WKCP7UaRZOjUDMcdQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.1.1.tgz", + "integrity": "sha512-UkeVCA/b3QEA4k0nIKS4uWXDCNmV73WLHdh2oDGZZc3GsQtlOCuiH3EkB/qI60v2MiCq356/SYWsDXt21yjwdg==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.0.0" - }, - "dependencies": { - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } + "jss": "10.1.1" } }, "jss-plugin-global": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.0.tgz", - "integrity": "sha512-80ofWKSQUo62bxLtRoTNe0kFPtHgUbAJeOeR36WEGgWIBEsXLyXOnD5KNnjPqG4heuEkz9eSLccjYST50JnI7Q==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.1.1.tgz", + "integrity": "sha512-VBG3wRyi3Z8S4kMhm8rZV6caYBegsk+QnQZSVmrWw6GVOT/Z4FA7eyMu5SdkorDlG/HVpHh91oFN56O4R9m2VA==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.0.0" - }, - "dependencies": { - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } + "jss": "10.1.1" } }, "jss-plugin-nested": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.0.tgz", - "integrity": "sha512-waxxwl/po1hN3azTyixKnr8ReEqUv5WK7WsO+5AWB0bFndML5Yqnt8ARZ90HEg8/P6WlqE/AB2413TkCRZE8bA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.1.1.tgz", + "integrity": "sha512-ozEu7ZBSVrMYxSDplPX3H82XHNQk2DQEJ9TEyo7OVTPJ1hEieqjDFiOQOxXEj9z3PMqkylnUbvWIZRDKCFYw5Q==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.0.0", + "jss": "10.1.1", "tiny-warning": "^1.0.2" - }, - "dependencies": { - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } } }, "jss-plugin-props-sort": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.0.tgz", - "integrity": "sha512-41mf22CImjwNdtOG3r+cdC8+RhwNm616sjHx5YlqTwtSJLyLFinbQC/a4PIFk8xqf1qpFH1kEAIw+yx9HaqZ3g==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.1.1.tgz", + "integrity": "sha512-g/joK3eTDZB4pkqpZB38257yD4LXB0X15jxtZAGbUzcKAVUHPl9Jb47Y7lYmiGsShiV4YmQRqG1p2DHMYoK91g==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.0.0" - }, - "dependencies": { - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } + "jss": "10.1.1" } }, "jss-plugin-rule-value-function": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.0.tgz", - "integrity": "sha512-Jw+BZ8JIw1f12V0SERqGlBT1JEPWax3vuZpMym54NAXpPb7R1LYHiCTIlaJUyqvIfEy3kiHMtgI+r2whGgRIxQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.1.1.tgz", + "integrity": "sha512-ClV1lvJ3laU9la1CUzaDugEcwnpjPTuJ0yGy2YtcU+gG/w9HMInD5vEv7xKAz53Bk4WiJm5uLOElSEshHyhKNw==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.0.0" - }, - "dependencies": { - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } + "jss": "10.1.1" } }, "jss-plugin-vendor-prefixer": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.0.tgz", - "integrity": "sha512-qslqvL0MUbWuzXJWdUxpj6mdNUX8jr4FFTo3aZnAT65nmzWL7g8oTr9ZxmTXXgdp7ANhS1QWE7036/Q2isFBpw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.1.1.tgz", + "integrity": "sha512-09MZpQ6onQrhaVSF6GHC4iYifQ7+4YC/tAP6D4ZWeZotvCMq1mHLqNKRIaqQ2lkgANjlEot2JnVi1ktu4+L4pw==", "requires": { "@babel/runtime": "^7.3.1", - "css-vendor": "^2.0.6", - "jss": "10.0.0" - }, - "dependencies": { - "css-vendor": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.7.tgz", - "integrity": "sha512-VS9Rjt79+p7M0WkPqcAza4Yq1ZHrsHrwf7hPL/bjQB+c1lwmAI+1FXxYTYt818D/50fFVflw0XKleiBN5RITkg==", - "requires": { - "@babel/runtime": "^7.6.2", - "is-in-browser": "^1.0.2" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", - "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - } - } - }, - "jss": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz", - "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - } + "css-vendor": "^2.0.7", + "jss": "10.1.1" } }, "jss-props-sort": { @@ -11294,6 +11219,16 @@ "integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==", "requires": { "css-vendor": "^0.3.8" + }, + "dependencies": { + "css-vendor": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz", + "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=", + "requires": { + "is-in-browser": "^1.0.2" + } + } } }, "jsx-ast-utils": { @@ -11753,6 +11688,102 @@ "react-transition-group": "4.0.1" }, "dependencies": { + "@material-ui/core": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.9.3.tgz", + "integrity": "sha512-REIj62+zEvTgI/C//YL4fZxrCVIySygmpZglsu/Nl5jPqy3CDjZv1F9ubBYorHqmRgeVPh64EghMMWqk4egmfg==", + "requires": { + "@babel/runtime": "^7.2.0", + "@material-ui/system": "^3.0.0-alpha.0", + "@material-ui/utils": "^3.0.0-alpha.2", + "@types/jss": "^9.5.6", + "@types/react-transition-group": "^2.0.8", + "brcast": "^3.0.1", + "classnames": "^2.2.5", + "csstype": "^2.5.2", + "debounce": "^1.1.0", + "deepmerge": "^3.0.0", + "dom-helpers": "^3.2.1", + "hoist-non-react-statics": "^3.2.1", + "is-plain-object": "^2.0.4", + "jss": "^9.8.7", + "jss-camel-case": "^6.0.0", + "jss-default-unit": "^8.0.2", + "jss-global": "^3.0.0", + "jss-nested": "^6.0.1", + "jss-props-sort": "^6.0.0", + "jss-vendor-prefixer": "^7.0.0", + "normalize-scroll-left": "^0.1.2", + "popper.js": "^1.14.1", + "prop-types": "^15.6.0", + "react-event-listener": "^0.6.2", + "react-transition-group": "^2.2.1", + "recompose": "0.28.0 - 0.30.0", + "warning": "^4.0.1" + }, + "dependencies": { + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + } + } + }, + "@material-ui/system": { + "version": "3.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-3.0.0-alpha.2.tgz", + "integrity": "sha512-odmxQ0peKpP7RQBQ8koly06YhsPzcoVib1vByVPBH4QhwqBXuYoqlCjt02846fYspAqkrWzjxnWUD311EBbxOA==", + "requires": { + "@babel/runtime": "^7.2.0", + "deepmerge": "^3.0.0", + "prop-types": "^15.6.0", + "warning": "^4.0.1" + } + }, + "@material-ui/utils": { + "version": "3.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-3.0.0-alpha.3.tgz", + "integrity": "sha512-rwMdMZptX0DivkqBuC+Jdq7BYTXwqKai5G5ejPpuEDKpWzi1Oxp+LygGw329FrKpuKeiqpcymlqJTjmy+quWng==", + "requires": { + "@babel/runtime": "^7.2.0", + "prop-types": "^15.6.0", + "react-is": "^16.6.3" + } + }, + "@types/react-transition-group": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.2.tgz", + "integrity": "sha512-5Fv2DQNO+GpdPZcxp2x/OQG/H19A01WlmpjVD9cKvVFmoVLOZ9LvBgSWG6pSXIU4og5fgbvGPaCV5+VGkWAEHA==", + "requires": { + "@types/react": "*" + } + }, + "jss": { + "version": "9.8.7", + "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", + "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", + "requires": { + "is-in-browser": "^1.1.3", + "symbol-observable": "^1.1.0", + "warning": "^3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", @@ -18083,6 +18114,14 @@ "pure-color": "^1.2.0" } }, + "react-beforeunload": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-beforeunload/-/react-beforeunload-2.2.1.tgz", + "integrity": "sha512-qydpYQuGUaB1C5EP2EFN0YjPo9kgV10Z4suIZ79GIhp0DWNJxHyuR8BiTViOBltTIn9PwlpSqX4fE3uprsdqKA==", + "requires": { + "prop-types": "^15.7.2" + } + }, "react-chartjs-2": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.8.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index d9e800a9..a7f6e0b1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,9 +4,9 @@ "version": "0.3.0", "private": true, "dependencies": { - "@material-ui/core": "^3.9.3", + "@material-ui/core": "^4.5.2", "@material-ui/icons": "^4.5.1", - "@material-ui/styles": "^4.5.0", + "@material-ui/styles": "^4.5.2", "@use-it/interval": "^0.1.3", "class-transformer": "^0.2.0", "create-react-app": "^2.0.3", @@ -32,6 +32,7 @@ "react": "^16.10.2", "react-alert": "^5.5.0", "react-alert-template-basic": "^1.0.0", + "react-beforeunload": "^2.2.1", "react-chartjs-2": "^2.8.0", "react-cookie": "^4.0.1", "react-cytoscapejs": "^1.2.0", @@ -50,6 +51,7 @@ "react-router-dom": "^4.3.1", "react-scripts": "^2.1.8", "reactstrap": "^7.1.0", + "shellwords": "^0.1.1", "simplebar": "^4.2.3", "styled-components": "^4.4.0", "websocket": "^1.0.30", diff --git a/frontend/src/AngularWorkflow.js b/frontend/src/AngularWorkflow.js index bc9d99fe..86fb1b6c 100644 --- a/frontend/src/AngularWorkflow.js +++ b/frontend/src/AngularWorkflow.js @@ -4,6 +4,7 @@ import { useInterval } from 'react-powerhooks'; import uuid from "uuid"; import {Link} from 'react-router-dom'; +import { Prompt } from 'react-router' import TextField from '@material-ui/core/TextField'; import Drawer from '@material-ui/core/Drawer'; import Button from '@material-ui/core/Button'; @@ -28,6 +29,7 @@ import Checkbox from '@material-ui/core/Checkbox'; import Breadcrumbs from '@material-ui/core/Breadcrumbs'; import CircularProgress from '@material-ui/core/CircularProgress'; import ReactJson from 'react-json-view' +import { useBeforeunload } from 'react-beforeunload'; import DirectionsRunIcon from '@material-ui/icons/DirectionsRun'; import PolymerIcon from '@material-ui/icons/Polymer'; @@ -169,6 +171,9 @@ const AngularWorkflow = (props) => { const [update, setUpdate] = useState(""); const [workflowExecutions, setWorkflowExecutions] = React.useState([]); + const unloadText = 'Are you sure you want to leave?' + useBeforeunload(() => unloadText) + const [elements, setElements] = useState([]) const { start, stop } = useInterval({ duration: 2500, @@ -176,7 +181,7 @@ const AngularWorkflow = (props) => { callback: () => { fetchUpdates() } - }); + }) const getWorkflowExecution = (id) => { fetch(globalUrl+"/api/v1/workflows/"+id+"/executions", { @@ -798,16 +803,17 @@ const AngularWorkflow = (props) => { } const onUnselect = (event) => { - //console.log("Unselect?") console.time("UNSELECT") // FIXME - check if they have value before overriding like this for no reason. // Would save a lot of time (400~ ms -> 30ms) - //setSelectedActionName({}) + //console.log("ACTION: ", selectedAction) + //console.log("APP: ", selectedApp) setSelectedAction({}) - setSelectedApp({}) - setSelectedTrigger({}) - setSelectedEdge({}) + //setSelectedApp({}) + //setSelectedTrigger({}) + //setSelectedEdge({}) + // setSelectedTriggerIndex(-1) //setSelectedActionEnvironment({}) //setSelectedEdge({}) @@ -821,10 +827,15 @@ const AngularWorkflow = (props) => { } const onEdgeSelect = (event) => { + setRightSideBarOpen(true) + const triggercheck = workflow.triggers.find(trigger => trigger.id === event.target.data()["source"]) if (triggercheck === undefined) { setSelectedEdgeIndex(workflow.branches.findIndex(data => data.id === event.target.data()["id"])) setSelectedEdge(event.target.data()) + + setSelectedAction({}) + setSelectedTrigger({}) } else { alert.info("Can't edit branches from triggers") } @@ -837,7 +848,7 @@ const AngularWorkflow = (props) => { if (data.type === "ACTION") { // FIXME - unselect //console.log(cy.elements('[_id!="${data._id}"]`)) - console.time('ACTIONSTART'); + // Does it choose the wrong action? const curaction = workflow.actions.find(a => a.id === data.id) if (!curaction || curaction === undefined) { //console.log("Action not found error") @@ -855,25 +866,24 @@ const AngularWorkflow = (props) => { env = environments[0] } - console.log("Selected: ", data.id) - console.log(curaction) - - setRequiresAuthentication(curapp.authentication.required) setSelectedApp(curapp) + setSelectedAction(curaction) setSelectedActionEnvironment(env) setSelectedActionName(curaction.name) - setSelectedAction(curaction) + setRequiresAuthentication(curapp.authentication.required) } else if (data.type === "TRIGGER") { //console.log("Should handle trigger "+data.triggertype) //console.log(data) setSelectedTriggerIndex(workflow.triggers.findIndex(a => a.id === data.id)) setSelectedTrigger(data) - setSelectedActionEnvironment(data.env) setSelectedActionName(data.name) + setSelectedActionEnvironment(data.env) } else { - console.log("Should handle type "+data.type) + alert.error("Can't handle "+data.type) } + + setRightSideBarOpen(true) } const onEdgeAdded = (event) => { @@ -2103,8 +2113,9 @@ const AngularWorkflow = (props) => { const setNewSelectedAction = (e) => { const newaction = selectedApp.actions.find(a => a.name === e.target.value) + // Does this one find the wrong one? selectedAction.name = newaction.name - selectedAction.parameters = newaction.parameters + selectedAction.parameters = JSON.parse(JSON.stringify(newaction.parameters)) // FIXME - this is broken sometimes lol //var env = environments.find(a => a.name === newaction.environment) @@ -2180,7 +2191,7 @@ const AngularWorkflow = (props) => { // Dropdown -> static, action, local env, global env // VALUE (JSON) // {data.name}, {data.description}, {data.required}, {data.schema.type} - const AppActionArguments = () => { + const AppActionArguments = (props) => { const [selectedActionParameters, setSelectedActionParameters] = React.useState([]) const [selectedVariableParameter, setSelectedVariableParameter] = React.useState() @@ -2189,7 +2200,10 @@ const AngularWorkflow = (props) => { if (requiresAuthentication) { console.log("ADD AUTHENTICATION FIELDS") } - setSelectedActionParameters(selectedAction.parameters) + + if (selectedAction.parameters !== null && selectedAction.parameters.length > 0) { + setSelectedActionParameters(selectedAction.parameters) + } } if ((selectedVariableParameter === null || selectedVariableParameter === undefined) && (workflow.workflow_variables !== null && workflow.workflow_variables.length > 0)) { @@ -2201,20 +2215,20 @@ const AngularWorkflow = (props) => { const changeActionParameter = (event, count) => { selectedActionParameters[count].value = event.target.value - selectedAction.parameters = selectedActionParameters + selectedAction.parameters[count].value = event.target.value setSelectedAction(selectedAction) + //setUpdate(event.target.value) } - const changeActionParameterVariable = (fieldvalue, count) => { setSelectedVariableParameter(fieldvalue) // this isn't updated anywhere in the workflow - setSelectedActionName({}) - setSelectedAction({}) - setSelectedTrigger({}) - setSelectedApp({}) - setSelectedEdge({}) + // setSelectedActionName({}) + // setSelectedAction({}) + // setSelectedTrigger({}) + // setSelectedApp({}) + // setSelectedEdge({}) selectedActionParameters[count].action_field = fieldvalue selectedAction.parameters = selectedActionParameters @@ -2222,6 +2236,7 @@ const AngularWorkflow = (props) => { setSelectedActionName(selectedActionName) setSelectedApp(selectedApp) setSelectedAction(selectedAction) + setUpdate(fieldvalue) } // Sets ACTION_RESULT things @@ -2236,11 +2251,6 @@ const AngularWorkflow = (props) => { selectedActionParameters[count].action_field = fieldvalue selectedAction.parameters = selectedActionParameters - setSelectedActionName({}) - setSelectedAction({}) - setSelectedTrigger({}) - setSelectedApp({}) - setSelectedEdge({}) // FIXME - check if startnode // Set value @@ -2248,6 +2258,7 @@ const AngularWorkflow = (props) => { setSelectedApp(selectedApp) setSelectedAction(selectedAction) + setUpdate(fieldvalue) } const changeActionParameterVariant = (data, count) => { @@ -2283,7 +2294,8 @@ const AngularWorkflow = (props) => { setSelectedAction(selectedAction) } - if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters) { + // FIXME: Issue #40 - selectedActionParameters not reset + if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0) { return (