diff --git a/.env b/.env index 397e67bf..86a2b1f1 100644 --- a/.env +++ b/.env @@ -3,9 +3,10 @@ ORG_ID=Shuffle ENVIRONMENT_NAME=Shuffle # Remote github config for first load +SHUFFLE_DOWNLOAD_WORKFLOW_LOCATION= +SHUFFLE_DOWNLOAD_AUTH_USERNAME= +SHUFFLE_DOWNLOAD_AUTH_PASSWORD= APP_DOWNLOAD_LOCATION=https://github.com/frikky/shuffle-apps -APP_DOWNLOAD_AUTH_USERNAME= -APP_DOWNLOAD_AUTH_PASSWORD= # User config for first load. Username & PW: min length 3 SHUFFLE_DEFAULT_USERNAME= diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index f620cc7f..90460ad1 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -254,11 +254,14 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet if len(optionalQueries) > 0 { queryString += ", " for _, query := range optionalQueries { + // Check if it's a part of the URL already queryString += fmt.Sprintf("%s=\"\", ", query) queryData += fmt.Sprintf(` if %s: url += f"&%s={%s}"`, query, query, query) } + } else { + //log.Printf("No optional queries?") } // api.Authentication.Parameters[0].Value = "BearerAuth" @@ -398,7 +401,7 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet verifyAddin, ) - //log.Printf("%s", data) + //log.Printf(data) return functionname, data } @@ -594,10 +597,10 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger, pythonFunctions := []string{} for actualPath, path := range swagger.Paths { actualPath = strings.Replace(actualPath, " ", "_", -1) - actualPath = strings.Replace(actualPath, ".", "", -1) - actualPath = strings.Replace(actualPath, ".", "", -1) + //actualPath = strings.Replace(actualPath, ".", "", -1) actualPath = strings.Replace(actualPath, "\\", "", -1) + // FIXME: Handle everything behind questionmark (?) with dots as well. // https://godoc.org/github.com/getkin/kin-openapi/openapi3#PathItem if path.Get != nil { action, curCode := handleGet(swagger, api, extraParameters, path, actualPath) @@ -936,7 +939,11 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) @@ -1081,7 +1088,11 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) @@ -1224,7 +1235,11 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) @@ -1368,7 +1383,11 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) @@ -1511,7 +1530,11 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) @@ -1654,7 +1677,11 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) @@ -1797,7 +1824,11 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor continue } - if firstQuery { + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + + if firstQuery && !strings.Contains(baseUrl, "?") { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name) diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 2560b69d..fc0d97cc 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -158,6 +158,9 @@ type Environment struct { Name string `datastore:"name"` Type string `datastore:"type"` Registered bool `datastore:"registered"` + Default bool `datastore:"default" json:"default"` + Archived bool `datastore:"archived" json:"archived"` + Id string `datastore:"id" json:"id"` } type User struct { @@ -1053,16 +1056,29 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) { return } - // Clear old data - for _, item := range environments { - err = DeleteKey(ctx, "Environments", item.Name) - if err != nil { - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "Error cleaning up environment"}`)) - return + // Clear old data? Removed for archiving purpose. No straight deletion + //for _, item := range environments { + // err = DeleteKey(ctx, "Environments", item.Name) + // if err != nil { + // resp.WriteHeader(401) + // resp.Write([]byte(`{"success": false, "reason": "Error cleaning up environment"}`)) + // return + // } + //} + + openEnvironments := 0 + for _, item := range newEnvironments { + if !item.Archived { + openEnvironments += 1 } } + if openEnvironments < 1 { + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Can't archived all environments"}`)) + return + } + for _, item := range newEnvironments { err = setEnvironment(ctx, &item) if err != nil { @@ -1072,9 +1088,10 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) { } } + //DeleteKey(ctx, entity string, value string) error { // FIXME - check which are in use - log.Printf("FIXME: Set new environments: %#v", newEnvironments) - log.Printf("DONT DELETE ONES THAT ARE IN USE") + //log.Printf("FIXME: Set new environments: %#v", newEnvironments) + //log.Printf("DONT DELETE ONES THAT ARE IN USE") resp.WriteHeader(200) resp.Write([]byte(`{"success": true}`)) @@ -5995,7 +6012,7 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { if err != nil { log.Printf("Docker build error: %s", err) resp.WriteHeader(500) - resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "Error in Docker build"}`))) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Error in Docker build"}`))) return } @@ -6327,8 +6344,8 @@ func runInit(ctx context.Context) { url = "https://github.com/frikky/shuffle-apps" } - username := os.Getenv("APP_DOWNLOAD_AUTH_USERNAME") - password := os.Getenv("APP_DOWNLOAD_AUTH_PASSWORD") + username := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_USERNAME") + password := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_PASSWORD") cloneOptions := &git.CloneOptions{ URL: url, } @@ -6388,6 +6405,30 @@ func runInit(ctx context.Context) { log.Printf("Finished downloading extra API samples") } + workflowLocation := os.Getenv("SHUFFLE_DOWNLOAD_WORKFLOW_LOCATION") + if len(workflowLocation) > 0 { + log.Printf("Downloading WORKFLOWS from %s if no workflows - EXTRA workflows", workflowLocation) + q := datastore.NewQuery("workflow") + var workflows []Workflow + _, err = dbclient.GetAll(ctx, q, &workflows) + if err != nil { + log.Printf("Error getting workflows: %s", err) + } else { + if len(workflows) == 0 { + username := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_USERNAME") + password := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_PASSWORD") + err = loadGithubWorkflows(workflowLocation, username, password, "") + if err != nil { + log.Printf("Failed to upload workflows from github: %s", err) + } else { + log.Printf("Finished downloading workflows from github!") + } + } else { + log.Printf("Skipping because there are %d workflows already", len(workflows)) + } + + } + } log.Printf("Finished INIT") } diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index db1e322f..084c9a79 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -120,6 +120,8 @@ type WorkflowApp struct { } `json:"contact_info" datastore:"contact_info" yaml:"contact_info" required:false` Actions []WorkflowAppAction `json:"actions" yaml:"actions" required:true datastore:"actions,noindex"` Authentication Authentication `json:"authentication" yaml:"authentication" required:false datastore:"authentication"` + Tags []string `json:"tags" yaml:"tags" required:false datastore:"activated"` + Category []string `json:"category" yaml:"category" required:false datastore:"category"` } type WorkflowAppActionParameter struct { @@ -129,6 +131,7 @@ type WorkflowAppActionParameter struct { Example string `json:"example" datastore:"example" yaml:"example"` Value string `json:"value" datastore:"value" yaml:"value,omitempty"` Multiline bool `json:"multiline" datastore:"multiline" yaml:"multiline"` + Options []string `json:"options" datastore:"options" yaml:"options"` ActionField string `json:"action_field" datastore:"action_field" yaml:"actionfield,omitempty"` Variant string `json:"variant" datastore:"variant" yaml:"variant,omitempty"` Required bool `json:"required" datastore:"required" yaml:"required"` @@ -192,7 +195,7 @@ type WorkflowExecution struct { Description string `json:"description" datastore:"description"` ID string `json:"id" datastore:"id"` Name string `json:"name" datastore:"name"` - Value string `json:"value" datastore:"value"` + Value string `json:"value" datastore:"value,noindex"` } `json:"execution_variables,omitempty" datastore:"execution_variables,omitempty"` } @@ -217,7 +220,7 @@ type Action struct { Description string `json:"description" datastore:"description"` ID string `json:"id" datastore:"id"` Name string `json:"name" datastore:"name"` - Value string `json:"value" datastore:"value"` + Value string `json:"value" datastore:"value,noindex"` } `json:"execution_variable,omitempty" datastore:"execution_variable,omitempty"` Position struct { X float64 `json:"x" datastore:"x"` @@ -307,7 +310,7 @@ type Workflow struct { Description string `json:"description" datastore:"description"` ID string `json:"id" datastore:"id"` Name string `json:"name" datastore:"name"` - Value string `json:"value" datastore:"value"` + Value string `json:"value" datastore:"value,noindex"` } `json:"execution_variables,omitempty" datastore:"execution_variables"` } @@ -1121,6 +1124,10 @@ func getWorkflows(resp http.ResponseWriter, request *http.Request) { // With user, do a search for workflows with user or user's org attached q := datastore.NewQuery("workflow").Filter("owner =", user.Id) + if user.Role == "admin" { + q = datastore.NewQuery("workflow") + } + var workflows []Workflow _, err = dbclient.GetAll(ctx, q, &workflows) if err != nil { @@ -1236,11 +1243,16 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) { workflowapps, err := getAllWorkflowApps(ctx) if err == nil { // FIXME: Add real env - //q := datastore.NewQuery("Environments").Limit(1) - //count, err := dbclient.Get(ctx, q) - //envName := "Shuffle" - //if err == nil { - //} + envName := "Shuffle" + environments, err := getEnvironments(ctx) + if err == nil { + for _, env := range environments { + if env.Default { + envName = env.Name + break + } + } + } for _, item := range workflowapps { if item.Name == "Testing" && item.AppVersion == "1.0.0" { @@ -1249,7 +1261,7 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) { newActions = append(newActions, Action{ Label: "Start node", Name: "hello_world", - Environment: "Shuffle", + Environment: envName, Parameters: []WorkflowAppActionParameter{}, Position: struct { X float64 "json:\"x\" datastore:\"x\"" @@ -3100,6 +3112,18 @@ func getWorkflow(ctx context.Context, id string) (*Workflow, error) { return workflow, nil } +func getEnvironments(ctx context.Context) ([]Environment, error) { + var environments []Environment + q := datastore.NewQuery("Environments") + + _, err := dbclient.GetAll(ctx, q, &environments) + if err != nil { + return []Environment{}, err + } + + return environments, nil +} + func getAllWorkflows(ctx context.Context) ([]Workflow, error) { var allworkflows []Workflow q := datastore.NewQuery("workflow") @@ -4045,6 +4069,62 @@ func deployWebhookFunction(ctx context.Context, name, localization, applocation return nil } +func loadGithubWorkflows(url, username, password, userId string) error { + fs := memfs.New() + + if strings.Contains(url, "github") || strings.Contains(url, "gitlab") || strings.Contains(url, "bitbucket") { + cloneOptions := &git.CloneOptions{ + URL: url, + } + + // FIXME: Better auth. + if len(username) > 0 && len(password) > 0 { + cloneOptions.Auth = &http2.BasicAuth{ + + Username: username, + Password: password, + } + } + + storer := memory.NewStorage() + r, err := git.Clone(storer, fs, cloneOptions) + if err != nil { + log.Printf("Failed loading repo into memory: %s", err) + return err + } + + dir, err := fs.ReadDir("/") + if err != nil { + log.Printf("FAiled reading folder: %s", err) + } + _ = r + + log.Printf("Starting workflow folder iteration") + iterateWorkflowGithubFolders(fs, dir, "", "", userId) + + } else if strings.Contains(url, "s3") { + //https://docs.aws.amazon.com/sdk-for-go/api/service/s3/ + + //sess := session.Must(session.NewSession()) + //downloader := s3manager.NewDownloader(sess) + + //// Write the contents of S3 Object to the file + //storer := memory.NewStorage() + //n, err := downloader.Download(storer, &s3.GetObjectInput{ + // Bucket: aws.String(myBucket), + // Key: aws.String(myString), + //}) + //if err != nil { + // return fmt.Errorf("failed to download file, %v", err) + //} + //fmt.Printf("file downloaded, %d bytes\n", n) + } else { + return errors.New(fmt.Sprintf("URL %s is unsupported when downloading workflows", url)) + } + + return nil +} + func loadSpecificWorkflows(resp http.ResponseWriter, request *http.Request) { cors := handleCors(resp, request) if cors { @@ -4064,7 +4144,7 @@ func loadSpecificWorkflows(resp http.ResponseWriter, request *http.Request) { if user.Role != "admin" { log.Printf("Wrong user (%s) when downloading from github", user.Username) resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) + resp.Write([]byte(`{"success": false, "reason": "Downloading remotely requires admin"}`)) return } @@ -4093,59 +4173,11 @@ func loadSpecificWorkflows(resp http.ResponseWriter, request *http.Request) { return } - fs := memfs.New() - - if strings.Contains(tmpBody.URL, "github") || strings.Contains(tmpBody.URL, "gitlab") || strings.Contains(tmpBody.URL, "bitbucket") { - cloneOptions := &git.CloneOptions{ - URL: tmpBody.URL, - } - - // FIXME: Better auth. - if len(tmpBody.Field1) > 0 && len(tmpBody.Field2) > 0 { - cloneOptions.Auth = &http2.BasicAuth{ - - Username: tmpBody.Field1, - Password: tmpBody.Field2, - } - } - - storer := memory.NewStorage() - r, err := git.Clone(storer, fs, cloneOptions) - if err != nil { - log.Printf("Failed loading repo into memory: %s", err) - resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err))) - return - } - - dir, err := fs.ReadDir("/") - if err != nil { - log.Printf("FAiled reading folder: %s", err) - } - _ = r - - log.Printf("Starting workflow folder iteration") - iterateWorkflowGithubFolders(fs, dir, "", "", user.Id) - - } else if strings.Contains(tmpBody.URL, "s3") { - //https://docs.aws.amazon.com/sdk-for-go/api/service/s3/ - - //sess := session.Must(session.NewSession()) - //downloader := s3manager.NewDownloader(sess) - - //// Write the contents of S3 Object to the file - //storer := memory.NewStorage() - //n, err := downloader.Download(storer, &s3.GetObjectInput{ - // Bucket: aws.String(myBucket), - // Key: aws.String(myString), - //}) - //if err != nil { - // return fmt.Errorf("failed to download file, %v", err) - //} - //fmt.Printf("file downloaded, %d bytes\n", n) - } else { + err = loadGithubWorkflows(tmpBody.URL, tmpBody.Field1, tmpBody.Field2, user.Id) + if err != nil { + log.Printf("Failed to update workflows: %s", err) resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s is unsupported. Try e.g. github"}`, tmpBody.URL))) + resp.Write([]byte(`{"success": false}`)) return } @@ -4489,7 +4521,7 @@ func iterateWorkflowGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra log.Printf("Failed setting (download) workflow: %s", err) continue } - log.Printf("Uploaded workflow %s!", filename) + log.Printf("Uploaded workflow %s for user %s!", filename, userId) } } } diff --git a/docker-compose.yml b/docker-compose.yml index 4a7cfb64..8faba6f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,7 @@ services: depends_on: - backend backend: - build: ./backend + #build: ./backend image: frikky/shuffle:backend container_name: shuffle-backend hostname: ${BACKEND_HOSTNAME} diff --git a/frontend/Dockerfile b/frontend/Dockerfile index a5525f42..cc791b82 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -2,8 +2,10 @@ FROM node as builder RUN mkdir /usr/src/app + WORKDIR /usr/src/app ENV PATH /usr/src/app/node_modules/.bin:$PATH + COPY package.json /usr/src/app/package.json RUN npm install --verbose @@ -15,6 +17,10 @@ COPY ./src /usr/src/app/src/ COPY ./*.sh /usr/src/app/ COPY ./*.json /usr/src/app/ +# There were issues with the webpack installer from package.json +RUN rm -rf /usr/src/app/node_modules/webpack +RUN npm install webpack@4.42.0 + RUN npm run-script build # Production environment diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6f78e4b1..546cc877 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -4332,13 +4332,14 @@ } }, "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" }, "dependencies": { "bn.js": { @@ -5265,9 +5266,9 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", - "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" }, "body-parser": { "version": "1.19.0", @@ -5438,15 +5439,15 @@ } }, "browserify-sign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", - "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "requires": { "bn.js": "^5.1.1", "browserify-rsa": "^4.0.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.2", + "elliptic": "^6.5.3", "inherits": "^2.0.4", "parse-asn1": "^5.1.5", "readable-stream": "^3.6.0", @@ -5868,9 +5869,9 @@ } }, "class-transformer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.2.3.tgz", - "integrity": "sha512-qsP+0xoavpOlJHuYsQJsN58HXSl8Jvveo+T37rEvCEeRfMWoytAyR0Ua/YsFgpM6AZYZ/og2PJwArwzJl1aXtQ==" + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz", + "integrity": "sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==" }, "class-utils": { "version": "0.3.6", @@ -6341,12 +6342,12 @@ } }, "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "requires": { "bn.js": "^4.1.0", - "elliptic": "^6.0.0" + "elliptic": "^6.5.3" }, "dependencies": { "bn.js": { @@ -7558,9 +7559,9 @@ "integrity": "sha512-vcTeLpPm4+ccoYFXnepvkFt0KujdyrBU19KNEO40Pnkhta6mUi2K0Dn7NmpRcNz7BvysnSqeuIYScP003HWuYg==" }, "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -7610,9 +7611,9 @@ } }, "enhanced-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz", - "integrity": "sha512-S7eiFb/erugyd1rLb6mQ3Vuq+EXHv5cpCkNqqIkYkBgN2QdFnyCZzFBleqwGEx4lgNGYij81BWnCrFNK7vxvjQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", "requires": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", @@ -8250,9 +8251,9 @@ "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "events": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", - "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" }, "eventsource": { "version": "1.0.7", @@ -13442,13 +13443,12 @@ } }, "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "requires": { - "asn1.js": "^4.0.0", + "asn1.js": "^5.2.0", "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", "pbkdf2": "^3.0.3", "safe-buffer": "^5.1.1" @@ -15566,11 +15566,205 @@ "workbox-webpack-plugin": "4.3.1" }, "dependencies": { + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, "dotenv": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -15586,10 +15780,102 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "webpack": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } }, @@ -18337,14 +18623,81 @@ } }, "watchpack": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", - "integrity": "sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", + "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", "requires": { - "chokidar": "^3.4.0", + "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0", "watchpack-chokidar2": "^2.0.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "optional": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } } }, "watchpack-chokidar2": { @@ -18574,9 +18927,9 @@ } }, "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", - "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "requires": { "randombytes": "^2.1.0" } @@ -18595,15 +18948,15 @@ } }, "terser-webpack-plugin": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz", - "integrity": "sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", - "serialize-javascript": "^3.1.0", + "serialize-javascript": "^4.0.0", "source-map": "^0.6.1", "terser": "^4.1.2", "webpack-sources": "^1.4.0", diff --git a/frontend/package.json b/frontend/package.json index 129ec3e2..d4253b00 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,7 +8,7 @@ "@material-ui/icons": "^4.5.1", "@material-ui/styles": "^4.5.2", "@use-it/interval": "^0.1.3", - "class-transformer": "^0.3.1", + "class-transformer": "^0.3.1", "create-react-app": "^2.0.3", "cytoscape": "^3.11.0", "cytoscape-clipboard": "^2.2.1", @@ -54,6 +54,7 @@ "shellwords": "^0.1.1", "simplebar": "^4.2.3", "styled-components": "^4.4.0", + "webpack": "^4.42.0", "websocket": "^1.0.30", "yaml": "^1.7.2", "yamljs": "^0.3.0", diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index 2707d140..ae1756c3 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -47,6 +47,7 @@ const Admin = (props) => { const [selectedUserModalOpen, setSelectedUserModalOpen] = React.useState(false) const [selectedAuthentication, setSelectedAuthentication] = React.useState({}) const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false) + const [showArchived, setShowArchived] = React.useState(false) const alert = useAlert() @@ -129,7 +130,8 @@ const Admin = (props) => { if (responseJson["success"] === false) { alert.error("Failed setting new password") } else { - alert.success("Changed password!") + alert.success("Successfully password!") + setSelectedUserModalOpen(false) } }), ) @@ -169,7 +171,6 @@ const Admin = (props) => { } const submitUser = (data) => { - // FIXME - add some check here ROFL console.log("INPUT: ", data) // Just use this one? @@ -200,13 +201,21 @@ const Admin = (props) => { }); } - const deleteEnvironment = (name) => { + // Horrible frontend fix for environments + const setDefaultEnvironment = (name) => { // FIXME - add some check here ROFL - alert.info("Deleting environment " + name) + alert.info("Setting default env to " + name) var newEnv = [] for (var key in environments) { if (environments[key].Name == name) { - continue + if (environments[key].archived) { + alert.error("Can't set archived to default") + return + } + + environments[key].default = true + } else if (environments[key].default == true && environments[key].name !== name) { + environments[key].default = false } newEnv.push(environments[key]) @@ -226,6 +235,7 @@ const Admin = (props) => { response.json().then(responseJson => { if (responseJson["success"] === false) { alert.error(responseJson.reason) + getEnvironments() } else { setLoginInfo("") setModalOpen(false) @@ -233,14 +243,60 @@ const Admin = (props) => { } }), ) - //.catch(error => { - // console.log("Error in userdata: ", error) - //}); + .catch(error => { + console.log("Error in backend data: ", error) + }) + } + + const deleteEnvironment = (name) => { + // FIXME - add some check here ROFL + alert.info("Deleting environment " + name) + var newEnv = [] + for (var key in environments) { + if (environments[key].Name == name) { + if (environments[key].default) { + alert.info("Can't delete the default environment") + return + } + environments[key].archived = true + } + + newEnv.push(environments[key]) + } + + // Just use this one? + const url = globalUrl + '/api/v1/setenvironments'; + fetch(url, { + method: 'PUT', + credentials: "include", + body: JSON.stringify(newEnv), + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(response => + response.json().then(responseJson => { + if (responseJson["success"] === false) { + alert.error(responseJson.reason) + getEnvironments() + } else { + setLoginInfo("") + setModalOpen(false) + getEnvironments() + } + }), + ) + .catch(error => { + console.log("Error when deleting: ", error) + }) } const submitEnvironment = (data) => { // FIXME - add some check here ROFL - environments.push({ "name": data.environment, "type": "onprem" }) + environments.push({ + "name": data.environment, + "type": "onprem", + }) // Just use this one? var baseurl = globalUrl @@ -257,6 +313,7 @@ const Admin = (props) => { response.json().then(responseJson => { if (responseJson["success"] === false) { setLoginInfo("Error in input: " + responseJson.reason) + getEnvironments() } else { setLoginInfo("") setModalOpen(false) @@ -342,7 +399,6 @@ const Admin = (props) => { return response.json() }) .then((responseJson) => { - console.log(responseJson) setEnvironments(responseJson) }) .catch(error => { @@ -934,6 +990,7 @@ const Admin = (props) => { : null + console.log("Environments: ", environments) const environmentView = curTab === 2 ?
@@ -967,12 +1024,29 @@ const Admin = (props) => { primary="Orborus running (TBD)" style={{minWidth: 200, maxWidth: 200}} /> + + {environments === undefined ? null : environments.map(environment => { + if (!showArchived && environment.archived) { + return null + } + + if (environment.archived === undefined) { + getEnvironments() + return null + } + return ( { primary={"TBD"} style={{minWidth: 200, maxWidth: 200, overflow: "hidden"}} /> - + + {environment.default ? + null + : + + } + + + ) })} diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 294b4d2a..018d6004 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -29,6 +29,7 @@ import Menu from '@material-ui/core/Menu'; import Input from '@material-ui/core/Input'; import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Typography from '@material-ui/core/Typography'; import Checkbox from '@material-ui/core/Checkbox'; import Breadcrumbs from '@material-ui/core/Breadcrumbs'; import CircularProgress from '@material-ui/core/CircularProgress'; @@ -106,6 +107,7 @@ const AngularWorkflow = (props) => { const { globalUrl, isLoggedIn, isLoaded } = props; const referenceUrl = globalUrl+"/api/v1/hooks/" const alert = useAlert() + const borderRadius = 3 const [bodyWidth, bodyHeight] = useWindowSize(); const appBarSize = 74 @@ -182,8 +184,9 @@ const AngularWorkflow = (props) => { const [appAdded, setAppAdded] = useState(false) const [update, setUpdate] = useState(""); const [workflowExecutions, setWorkflowExecutions] = React.useState([]); + const [defaultEnvironmentIndex, setDefaultEnvironmentIndex] = React.useState(0) - const unloadText = 'Are you sure you want to leave?' + const unloadText = 'Are you sure you want to leave without saving (CTRL+S)?' useBeforeunload(() => { if (!lastSaved) { return unloadText @@ -910,9 +913,9 @@ const AngularWorkflow = (props) => { return } - var env = environments.find(a => a.name === curaction.environment) + var env = environments.find(a => a.Name === curaction.environment) if (!env || env === undefined) { - env = environments[0] + env = environments[defaultEnvironmentIndex] } setSelectedActionEnvironment(env) @@ -1222,6 +1225,24 @@ const AngularWorkflow = (props) => { return response.json() }) .then((responseJson) => { + var found = false + for (var key in responseJson) { + if (responseJson[key].default) { + setDefaultEnvironmentIndex(key) + found = true + break + } + } + + if (!found) { + for (var key in responseJson) { + if (!responseJson[key].archived) { + setDefaultEnvironmentIndex(key) + break + } + } + } + setEnvironments(responseJson) }) .catch(error => { @@ -1556,6 +1577,7 @@ const AngularWorkflow = (props) => { } const paperAppStyle = { + borderRadius: borderRadius, minHeight: "100px", maxHeight: "100px", minWidth: "100%", @@ -1568,6 +1590,7 @@ const AngularWorkflow = (props) => { } const paperVariableStyle = { + borderRadius: borderRadius, minHeight: "50px", maxHeight: "50px", minWidth: "100%", @@ -1827,7 +1850,7 @@ const AngularWorkflow = (props) => { "large_image": 'data:image/png;base64,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', "is_valid": true, "label": "Webhook", - "environment": environments[0] === undefined ? {} : environments[0].Name, + "environment": environments[defaultEnvironmentIndex] === undefined ? {} : environments[defaultEnvironmentIndex].Name, "description": "Simple HTTP webhook", "long_description": "Execute a workflow with an unauthicated POST request", }, @@ -1841,7 +1864,7 @@ const AngularWorkflow = (props) => { "errors": null, "is_valid": false, "label": "User input", - "environment": environments[0] === undefined ? {} : environments[0].Name, + "environment": environments[defaultEnvironmentIndex] === undefined ? {} : environments[defaultEnvironmentIndex].Name, "long_description": "Take user input to continue execution", }, { @@ -1854,7 +1877,7 @@ const AngularWorkflow = (props) => { "large_image": "data:image/png;base64,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", "is_valid": true, "label": "Schedule", - "environment": environments[0] === undefined ? {} : environments[0].Name, + "environment": environments[defaultEnvironmentIndex] === undefined ? {} : environments[defaultEnvironmentIndex].Name, "long_description": "Create a schedule based on cron", }, { @@ -1866,7 +1889,7 @@ const AngularWorkflow = (props) => { "errors": null, "is_valid": false, "label": "Email", - "environment": environments[0] === undefined ? {} : environments[0].Name, + "environment": environments[defaultEnvironmentIndex] === undefined ? {} : environments[defaultEnvironmentIndex].Name, "large_image": 'data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/hAytodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Nzg4QTJBMjVEMDI1MTFFN0EwQUVDODc5QjYyQkFCMUQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Nzg4QTJBMjZEMDI1MTFFN0EwQUVDODc5QjYyQkFCMUQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3ODhBMkEyM0QwMjUxMUU3QTBBRUM4NzlCNjJCQUIxRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3ODhBMkEyNEQwMjUxMUU3QTBBRUM4NzlCNjJCQUIxRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/bAEMAAwICAgICAwICAgMDAwMEBgQEBAQECAYGBQYJCAoKCQgJCQoM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', "long_description": "Execute a workflow when you get an email", }] @@ -1982,9 +2005,9 @@ const AngularWorkflow = (props) => { position: newposition, } - //if (data.trigger_type === "WEBHOOK") { - // newAppData.status = "running" - //} + if (data.trigger_type === "WEBHOOK") { + newAppData.status = "running" + } // Can all the data be in here? hmm const nodeToBeAdded = { @@ -2030,8 +2053,8 @@ const AngularWorkflow = (props) => { setWorkflow(workflow) if (data.trigger_type === "WEBHOOK") { - //newWebhook(newAppData) - //saveWorkflow(workflow) + newWebhook(newAppData) + saveWorkflow(workflow) } } } @@ -2077,7 +2100,7 @@ const AngularWorkflow = (props) => { app_id: app.id, sharing: app.sharing, private_id: app.private_id, - environment: environments[0].Name, + environment: environments[defaultEnvironmentIndex].Name, errors: [], id_: newNodeId, _id_: newNodeId, @@ -2188,6 +2211,7 @@ const AngularWorkflow = (props) => {
{/* {
-
+
@@ -2295,9 +2319,9 @@ const AngularWorkflow = (props) => { } // FIXME - this is broken sometimes lol - //var env = environments.find(a => a.name === newaction.environment) + //var env = environments.find(a => a.Name === newaction.environment) //if ((!env || env === undefined) && selectedAction.environment === undefined ) { - // env = environments[0] + // env = environments[defaultEnvironmentIndex] //} //setSelectedActionEnvironment(env) @@ -2377,7 +2401,7 @@ const AngularWorkflow = (props) => { // {data.name}, {data.description}, {data.required}, {data.schema.type} const AppActionArguments = (props) => { const [selectedActionParameters, setSelectedActionParameters] = React.useState([]) - const [selectedVariableParameter, setSelectedVariableParameter] = React.useState() + const [selectedVariableParameter, setSelectedVariableParameter] = React.useState("") const [showDropdown, setShowDropdown] = React.useState(false) const [showDropdownNumber, setShowDropdownNumber] = React.useState(0) const [actionlist, setActionlist] = React.useState([]) @@ -2514,14 +2538,12 @@ const AngularWorkflow = (props) => { } const changeActionParameterVariable = (fieldvalue, count) => { - setSelectedVariableParameter(fieldvalue) + //console.log("CALLED THIS ONE WITH VALUE!", fieldvalue) + //if (selectedVariableParameter === fieldvalue) { + // return + //} - // this isn't updated anywhere in the workflow - // setSelectedActionName({}) - // setSelectedAction({}) - // setSelectedTrigger({}) - // setSelectedApp({}) - // setSelectedEdge({}) + setSelectedVariableParameter(fieldvalue) selectedActionParameters[count].action_field = fieldvalue selectedAction.parameters = selectedActionParameters @@ -2625,7 +2647,7 @@ const AngularWorkflow = (props) => { var datafield = { }} /> + if (selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0) { + if (selectedActionParameters[count].value === "" && selectedActionParameters[count].required) { + // Rofl, dirty workaround :) + const e = { + target: { + value: selectedActionParameters[count].options[0], + } + } - // Remap data based on variant - if (data.variant === "STATIC_VALUE") { + changeActionParameter(e, count) + } + + datafield = + + + } else if (data.variant === "STATIC_VALUE") { staticcolor = "#f85a3e" } else if (data.variant === "ACTION_RESULT") { // Gets the parents of the current node @@ -2706,7 +2761,7 @@ const AngularWorkflow = (props) => { ))} { {datafield} {showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length > 0 ? - Autocomplete + Autocomplete { selectedAction.parameters[count].value = selectedActionParameters[count].value console.log("TARGET: ", selectedActionParameters) setSelectedAction(selectedAction) - setUpdate("action"+e.target.value.name) + setUpdate(Math.random()) setShowDropdown(false) }} @@ -2997,8 +3052,8 @@ const AngularWorkflow = (props) => { flexDirection: "column", backgroundColor: "#1F2023", color: "white", - paddingRight: 10, - paddingLeft: 10, + paddingRight: 15, + paddingLeft: 15, minHeight: "100%", zIndex: 1000, resize: "vertical", @@ -3061,7 +3116,7 @@ const AngularWorkflow = (props) => {

{selectedAction.app_name}

- What are actions? + What are actions? {selectedAction.errors !== null && selectedAction.errors.length > 0 ?
Errors: {selectedAction.errors.join("\n")} @@ -3076,17 +3131,17 @@ const AngularWorkflow = (props) => {
-
+ Name -
+ { selectedAction.selectedAuthentication = e.target.value selectedAction.authentication_id = e.target.value.id setSelectedAction(selectedAction) - setUpdate("update auth") + setUpdate(Math.random()) }} style={{backgroundColor: inputColor, color: "white", height: "50px"}} > @@ -3156,12 +3211,15 @@ const AngularWorkflow = (props) => { : null} {environments !== undefined && environments !== null && environments.length > 1 ?
- Environment + + Environment +
: null} @@ -3200,7 +3264,7 @@ const AngularWorkflow = (props) => { selectedAction.execution_variable = value } setSelectedAction(selectedAction) - setUpdate("actionname "+e.target.value+selectedAction.Label) + setUpdate(Math.random()) }} style={{backgroundColor: inputColor, color: "white", height: "50px"}} > @@ -3408,6 +3472,8 @@ const AngularWorkflow = (props) => { const { tmpdata, type } = props const [data, ] = useState(tmpdata) const [multiline, setMultiline] = useState(false) + const [showAutocomplete, setShowAutocomplete] = React.useState(false) + const [actionlist, setActionlist] = React.useState([]) if (tmpdata === undefined) { return tmpdata @@ -3417,6 +3483,47 @@ const AngularWorkflow = (props) => { data.variant = "STATIC_VALUE" } + + // Set actions based on NEXT node, since it should be able to involve those two + console.log("IN APPACTIONARG: ", selectedEdge) + if (actionlist.length === 0) { + // FIXME: Have previous execution values in here + actionlist.push({"type": "Execution Argument", "name": "Execution Argument", "value": "$exec", "highlight": "exec", "autocomplete": "exec", "example": "hello"}) + + if (workflow.workflow_variables !== null && workflow.workflow_variables !== undefined && workflow.workflow_variables.length > 0) { + for (var key in workflow.workflow_variables) { + const item = workflow.workflow_variables[key] + actionlist.push({"type": "workflow_variable", "name": item.name, "value": item.value, "id": item.id, "autocomplete": `${item.name.split(" ").join("_")}`, "example": item.value}) + } + } + + // FIXME: Add values from previous executions if they exist + if (workflow.execution_variables !== null && workflow.execution_variables !== undefined && workflow.execution_variables.length > 0) { + for (var key in workflow.execution_variables) { + const item = workflow.execution_variables[key] + actionlist.push({"type": "execution_variable", "name": item.name, "value": item.value, "id": item.id, "autocomplete": `${item.name.split(" ").join("_")}`, "example": ""}) + } + } + + const destAction = cy.getElementById(selectedEdge.target) + console.log(destAction.data()) + var parents = getParents(destAction.data()) + if (parents.length > 1) { + for (var key in parents) { + const item = parents[key] + if (item.label === "Execution Argument") { + continue + } + + // 1. Take + const actionvalue = {"type": "action", "id": item.id, "name": item.label, "autocomplete": `${item.label.split(" ").join("_")}`, "example": item.example === undefined ? "" : item.example} + actionlist.push(actionvalue) + } + } + + setActionlist(actionlist) + } + var staticcolor = "inherit" var actioncolor = "inherit" var varcolor = "inherit" @@ -3431,7 +3538,7 @@ const AngularWorkflow = (props) => { var datafield = {
{datafield} + {actionlist.length === 0 ? null : + + Autocomplete + + + }
) } @@ -3535,7 +3741,7 @@ const AngularWorkflow = (props) => { style: { backgroundColor: surfaceColor, color: "white", - minWidth: "800px", + minWidth: 800, }, }} onClose={() => { @@ -3549,11 +3755,11 @@ const AngularWorkflow = (props) => {
Condition
- @@ -3562,7 +3768,7 @@ const AngularWorkflow = (props) => {
- { setSelectedEdge(selectedEdge) setOpen(false) - setUpdate("delete "+conditionIndex) + setUpdate(Math.random()) } const paperVariableStyle = { @@ -4008,7 +4214,7 @@ const AngularWorkflow = (props) => { Name
{
Environment: { Name
{ placeholder={selectedTrigger.label} onChange={selectedTriggerChange} /> - -
- Environment: - -
@@ -4141,7 +4326,7 @@ const AngularWorkflow = (props) => {
{ //alert.info("Saved URI to clipboard") console.log("Copy to clipboooooard") @@ -4164,42 +4349,14 @@ const AngularWorkflow = (props) => { setTriggerCronWrapper(e.target.value) }} /> -
-
-
- Execution argument: -
-
- { - setTriggerBodyWrapper(e.target.value) - }} - />
- -
{
Environment: {
{ Name
{
Environment: {
{ { { return (
- What is this? - - These are required fields for authenticating with {selectedApp.name} + What is this?
+ These are required fields for authenticating with {selectedApp.name}
{selectedApp.link.length > 0 ? : null} - Label (to remember it) + Name - what is this used for? { {data.name} {
The API endpoint to use (URL) - leave this if you're unsure { const [, setBasedata] = React.useState({}) const [actions, setActions] = useState([]) const [errorCode, setErrorCode] = useState("") + const [appBuilding, setAppBuilding] = useState(false) //const [actions, setActions] = useState([{ // "name": "Get workflows", @@ -279,9 +281,9 @@ const AppCreator = (props) => { return response.json() }) .then((responseJson) => { - setIsAppLoaded(true) if (!responseJson.success) { alert.error("Failed to get the app") + setIsAppLoaded(true) } else { const data = JSON.parse(responseJson.body) parseIncomingOpenapiData(data) @@ -365,6 +367,8 @@ const AppCreator = (props) => { var firstUrl = data.servers[0].url if (firstUrl.endsWith("/")) { setBaseUrl(firstUrl.slice(0, firstUrl.length-1)) + } else { + setBaseUrl(firstUrl) } } @@ -378,9 +382,6 @@ const AppCreator = (props) => { securitySchemes = data.components.securitySchemes } - - console.log(data) - // FIXME - headers? var newActions = [] var wordlist = {} @@ -398,7 +399,6 @@ const AppCreator = (props) => { "errors": [], } - for (var key in methodvalue.parameters) { const parameter = methodvalue.parameters[key] if (parameter.in === "query") { @@ -520,11 +520,13 @@ const AppCreator = (props) => { } setActions(newActions) + setIsAppLoaded(true) } // Saving the app that's been configured. const submitApp = () => { alert.info("Uploading and building app " + name) + setAppBuilding(true) setErrorCode("") // Format the information @@ -718,6 +720,7 @@ const AppCreator = (props) => { if (authenticationOption === "API key") { if (parameterName.length === 0) { alert.error("A field name for the APIkey must be defined") + setAppBuilding(false) return } @@ -757,6 +760,7 @@ const AppCreator = (props) => { // throw new Error("NOT 200 :O") //} + setAppBuilding(false) return response.json() }) .then((responseJson) => { @@ -1570,7 +1574,22 @@ const AppCreator = (props) => { margin="normal" variant="outlined" value={name} - onChange={e => setName(e.target.value)} + onChange={e => { + const invalid = ["#", ":", "."] + for (var key in invalid) { + if (e.target.value.includes(invalid[key])) { + alert.error("Can't use "+invalid[key]+" in name") + return + } + } + + if (e.target.value.length > 100) { + alert.error("Choose a shorter name.") + return + } + + setName(e.target.value) + }} color="primary" InputProps={{ style:{ @@ -1590,12 +1609,12 @@ const AppCreator = (props) => { style={{flex: "1", marginTop: "5px", marginRight: "15px", backgroundColor: inputColor}} fullWidth={true} type="name" - id="outlined-with-placeholder" + id="outlined-with-placeholder" margin="normal" variant="outlined" placeholder="A description for the service" value={description} - onChange={e => setDescription(e.target.value)} + onChange={e => setDescription(e.target.value)} InputProps={{ classes: { notchedOutline: classes.notchedOutline, @@ -1691,10 +1710,10 @@ const AppCreator = (props) => { {testView} */} - {errorCode.length > 0 ? `Error: ${errorCode}` : null} diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 1f55de4f..d0f684b5 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -16,6 +16,7 @@ import Switch from '@material-ui/core/Switch'; import CircularProgress from '@material-ui/core/CircularProgress'; import CachedIcon from '@material-ui/icons/Cached'; +import GetAppIcon from '@material-ui/icons/GetApp'; import EditIcon from '@material-ui/icons/Edit'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import PlayArrowIcon from '@material-ui/icons/PlayArrow'; @@ -126,14 +127,15 @@ const Workflows = (props) => { color: "#ffffff", width: "100%", display: "flex", - maxWidth: "1768px", + minWidth: 1366, + maxWidth: 1766, margin: "auto", maxHeight: "90vh", } const emptyWorkflowStyle = { paddingTop: "200px", - width: "1024px", + width: 1024, margin: "auto", } @@ -263,6 +265,12 @@ const Workflows = (props) => { return new Promise((resolve) => setTimeout(resolve, time)); } + const exportAllWorkflows = () => { + for (var key in workflows) { + exportWorkflow(workflows[key]) + } + } + const exportWorkflow = (data) => { console.log("export") let dataStr = JSON.stringify(data) @@ -364,9 +372,9 @@ const Workflows = (props) => { }}>
- + - +
{ if (selectedWorkflow.id !== data.id) { setSelectedWorkflow(data) @@ -418,7 +426,7 @@ const Workflows = (props) => {
-
{ +
{ if (selectedWorkflow.id !== data.id) { setSelectedWorkflow(data) getWorkflowExecution(data.id) @@ -468,13 +476,13 @@ const Workflows = (props) => { var results = data.results.length } return ( - { + { setSelectedExecution(data) }}>
- + - +

Status: {data.status}

Actions: {results}/{actions} @@ -681,7 +689,7 @@ const Workflows = (props) => { */ if (Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.workflow.actions !== null) { return ( -
+
Status: {selectedExecution.status}
@@ -843,7 +851,7 @@ const Workflows = (props) => { } const modalView = modalOpen ? - {setModalOpen(false)}} PaperProps={{ @@ -910,9 +918,9 @@ const Workflows = (props) => { const viewSize = { - workflowView: 1, - executionsView: 1, - executionResults: 2, + workflowView: 4, + executionsView: 3, + executionResults: 4, } const workflowViewStyle = { @@ -943,7 +951,14 @@ const Workflows = (props) => { */} - + + + + @@ -982,10 +997,10 @@ const Workflows = (props) => {
-
+

Execution Timeline

-
+
Collapse results
} @@ -1075,7 +1090,7 @@ const Workflows = (props) => { } const workflowDownloadModalOpen = loadWorkflowsModalOpen ? - { }} diff --git a/install-guide.md b/install-guide.md index 4e5161f2..5f5fbd22 100644 --- a/install-guide.md +++ b/install-guide.md @@ -7,7 +7,6 @@ The Docker setup is done with docker-compose and is a single command to get set **PS: if you're setting up Shuffle on Windows, go to the next step (Windows Docker setup)** 1. Make sure you have Docker and [docker-compose](https://docs.docker.com/compose/install/) installed. - 2. Run docker-compose. ``` git clone https://github.com/frikky/Shuffle @@ -20,7 +19,7 @@ When you're done, skip to the "After installation" step below. ## Windows Docker setup This step is for setting up with Docker on windows from scratch. -1. Make sure you have [Docker](https://docs.docker.com/docker-for-windows/install/) and [docker-compose](https://docs.docker.com/compose/install/) installed +1. Make sure you have [Docker](https://docs.docker.com/docker-for-windows/install/) and [docker-compose](https://docs.docker.com/compose/install/) installed. WSL2 may be required. 2. Go to https://github.com/frikky/shuffle/releases and download the latest .zip release (or install git) 3. Unzip the folder and enter it 4. Open the .env file and change the line with "OUTER_HOSTNAME" to contain your IP: @@ -84,14 +83,16 @@ docker-compose up Related issue: #47 ## Local development installation -Frontend - requires [npm](https://nodejs.org/en/download/)/[yarn](https://yarnpkg.com/lang/en/docs/install/#debian-stable)/your preferred manager. Runs independently from backend - edit frontend/src/App.yaml (line 44~) from window.location.origin to http://YOUR IP:5001 +**Frontend - ReactJS /w cytoscape** +http://localhost:3000 - Requires [npm](https://nodejs.org/en/download/)/[yarn](https://yarnpkg.com/lang/en/docs/install/#debian-stable)/your preferred manager. Runs independently from backend. ```bash cd frontend npm i npm start ``` -Backend - API calls - requires [>=go1.13](https://golang.org/dl/) +**Backend - Golang** +http://localhost:5001 - REST API - requires [>=go1.13](https://golang.org/dl/) ```bash export DATASTORE_EMULATOR_HOST=0.0.0.0:8000 cd backend/go-app @@ -99,16 +100,26 @@ go build go run *.go ``` -Database - Datastore: +**Database - Datastore** +Based on Google datastore ``` docker run -p 8000:8000 google/cloud-sdk gcloud beta emulators datastore start --project=shuffle --host-port 0.0.0.0:8000 --no-store-on-disk ``` -Orborus - Execution of Workflows: -PS: This requires some specific environment variables. +**Orborus** +Execution of Workflows: +PS: This requires some specific environment variables ``` cd functions/onprem/orborus go run orborus.go ``` +Environments: +``` +export ORG_ID=Shuffle +export ENVIRONMENT_NAME=Shuffle +export BASE_URL=http://YOUR-IP:5001 +export DOCKER_API_VERSION=1.40 +export SHUFFLE_PASS_WORKER_PROXY=${SHUFFLE_PASS_WORKER_PROXY} +```