From e3d75ede6558bf2770e832ca462290ec6851f692 Mon Sep 17 00:00:00 2001 From: frikky Date: Sun, 16 Aug 2020 09:29:51 +0200 Subject: [PATCH 01/17] #112: Fixed too large param and frontend app creator bugs --- backend/go-app/walkoff.go | 6 +++--- frontend/package-lock.json | 6 +++--- frontend/package.json | 2 +- frontend/src/views/AppCreator.jsx | 13 ++++++------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index db1e322f..d6b3ff9f 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -192,7 +192,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 +217,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 +307,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"` } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6f78e4b1..61b088a9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5868,9 +5868,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", diff --git a/frontend/package.json b/frontend/package.json index 129ec3e2..0c78e907 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", diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index 75182bf0..ef0d1b88 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -279,9 +279,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 +365,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 +380,6 @@ const AppCreator = (props) => { securitySchemes = data.components.securitySchemes } - - console.log(data) - // FIXME - headers? var newActions = [] var wordlist = {} @@ -398,7 +397,6 @@ const AppCreator = (props) => { "errors": [], } - for (var key in methodvalue.parameters) { const parameter = methodvalue.parameters[key] if (parameter.in === "query") { @@ -520,6 +518,7 @@ const AppCreator = (props) => { } setActions(newActions) + setIsAppLoaded(true) } // Saving the app that's been configured. @@ -1590,12 +1589,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, From 0dbf7e4573f97224b5278bc4541eeda23a12efea Mon Sep 17 00:00:00 2001 From: frikky Date: Sun, 16 Aug 2020 09:34:42 +0200 Subject: [PATCH 02/17] Cleaned up docker-compose.. again :) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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} From 9eb7818e288c61a9ae2ef81bea6642d62c0ca3b1 Mon Sep 17 00:00:00 2001 From: frikky Date: Tue, 18 Aug 2020 08:31:47 +0200 Subject: [PATCH 03/17] #117: Added environment variable for download. Only admin available. --- .env | 5 +- backend/go-app/main.go | 28 +++++++- backend/go-app/walkoff.go | 120 +++++++++++++++++++---------------- frontend/src/views/Admin.jsx | 3 +- 4 files changed, 97 insertions(+), 59 deletions(-) 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/main.go b/backend/go-app/main.go index 2560b69d..e44fba65 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -6327,8 +6327,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 +6388,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 d6b3ff9f..7322ded4 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -1121,6 +1121,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 { @@ -4045,6 +4049,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 +4124,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 +4153,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 +4501,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/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index 2707d140..03a53575 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -129,7 +129,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) } }), ) From 4148552b776eb31de13a353da79264286a25d0da Mon Sep 17 00:00:00 2001 From: frikky Date: Tue, 18 Aug 2020 08:44:10 +0200 Subject: [PATCH 04/17] Added an export all function --- frontend/src/views/Workflows.jsx | 41 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 1f55de4f..90190952 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) @@ -472,9 +480,9 @@ const Workflows = (props) => { setSelectedExecution(data) }}>
- + - +

Status: {data.status}

Actions: {results}/{actions} @@ -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
} From 90991071de00619c6f43f3de52920bc70d743eff Mon Sep 17 00:00:00 2001 From: frikky Date: Sun, 23 Aug 2020 12:50:55 +0200 Subject: [PATCH 05/17] Fixed workflow issues --- frontend/src/views/AngularWorkflow.jsx | 2 +- frontend/src/views/Workflows.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 294b4d2a..ef488d5d 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -183,7 +183,7 @@ const AngularWorkflow = (props) => { const [update, setUpdate] = useState(""); const [workflowExecutions, setWorkflowExecutions] = React.useState([]); - 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 diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 90190952..d0543815 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -689,7 +689,7 @@ const Workflows = (props) => { */ if (Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.workflow.actions !== null) { return ( -
+
Status: {selectedExecution.status}
From bdcb3ecfde7510a10f127267d6286f1ba2de6c20 Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 08:20:06 +0200 Subject: [PATCH 06/17] Added default environments --- backend/go-app/main.go | 35 ++++++++--- frontend/src/views/Admin.jsx | 109 +++++++++++++++++++++++++++++++---- install-guide.md | 1 - 3 files changed, 125 insertions(+), 20 deletions(-) diff --git a/backend/go-app/main.go b/backend/go-app/main.go index e44fba65..3cca96eb 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}`)) diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index 03a53575..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() @@ -170,7 +171,6 @@ const Admin = (props) => { } const submitUser = (data) => { - // FIXME - add some check here ROFL console.log("INPUT: ", data) // Just use this one? @@ -201,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]) @@ -227,6 +235,7 @@ const Admin = (props) => { response.json().then(responseJson => { if (responseJson["success"] === false) { alert.error(responseJson.reason) + getEnvironments() } else { setLoginInfo("") setModalOpen(false) @@ -234,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 @@ -258,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) @@ -343,7 +399,6 @@ const Admin = (props) => { return response.json() }) .then((responseJson) => { - console.log(responseJson) setEnvironments(responseJson) }) .catch(error => { @@ -935,6 +990,7 @@ const Admin = (props) => {
: null + console.log("Environments: ", environments) const environmentView = curTab === 2 ?
@@ -968,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/install-guide.md b/install-guide.md index 4e5161f2..a7256128 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 From 9fa286543016b4bb3e59a800ca471c5eb39ea1fc Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 08:34:42 +0200 Subject: [PATCH 07/17] Properly implemented default environment --- backend/go-app/walkoff.go | 29 +++++++++++--- frontend/src/views/AngularWorkflow.jsx | 53 +++++++++++++++++++------- frontend/src/views/Workflows.jsx | 6 +-- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 7322ded4..9620a140 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -1240,11 +1240,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" { @@ -1253,7 +1258,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\"" @@ -3104,6 +3109,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") diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index ef488d5d..21320d16 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -182,6 +182,7 @@ 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 without saving (CTRL+S)?' useBeforeunload(() => { @@ -910,9 +911,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 +1223,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 => { @@ -1827,7 +1846,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 +1860,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 +1873,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 +1885,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", }] @@ -2077,7 +2096,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, @@ -2295,9 +2314,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) @@ -3173,11 +3192,17 @@ const AngularWorkflow = (props) => { }} style={{backgroundColor: inputColor, color: "white", height: "50px"}} > - {environments.map(data => ( - - {data.Name} - - ))} + {environments.map(data => { + if (data.archived) { + return null + } + + return ( + + {data.Name} + + ) + })}
: null} diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index d0543815..d0f684b5 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -476,7 +476,7 @@ const Workflows = (props) => { var results = data.results.length } return ( - { + { setSelectedExecution(data) }}>
@@ -851,7 +851,7 @@ const Workflows = (props) => { } const modalView = modalOpen ? - {setModalOpen(false)}} PaperProps={{ @@ -1090,7 +1090,7 @@ const Workflows = (props) => { } const workflowDownloadModalOpen = loadWorkflowsModalOpen ? - { }} From 70cb64925caee199720ed4296965a06e1b3a776f Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 09:12:58 +0200 Subject: [PATCH 08/17] #119: Added autocomplete to conditions --- frontend/src/views/AngularWorkflow.jsx | 154 ++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 6 deletions(-) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 21320d16..600c9264 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -2844,7 +2844,7 @@ const AngularWorkflow = (props) => { {datafield} {showDropdown && showDropdownNumber === count && data.variant === "STATIC_VALUE" && jsonList.length > 0 ? - Autocomplete + Autocomplete { } return ( - + {data.Name} ) @@ -3433,6 +3433,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 @@ -3442,6 +3444,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" @@ -3543,6 +3586,105 @@ const AngularWorkflow = (props) => {
{datafield} + {actionlist.length === 0 ? null : + + Autocomplete + + + }
) } @@ -3560,7 +3702,7 @@ const AngularWorkflow = (props) => { style: { backgroundColor: surfaceColor, color: "white", - minWidth: "800px", + minWidth: 800, }, }} onClose={() => { @@ -3574,7 +3716,7 @@ const AngularWorkflow = (props) => {
Condition
-
- Date: Mon, 24 Aug 2020 09:24:47 +0200 Subject: [PATCH 09/17] Fixed app naming error --- backend/go-app/main.go | 2 +- frontend/src/views/AppCreator.jsx | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 3cca96eb..fc0d97cc 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -6012,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 } diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index ef0d1b88..47776d61 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -1569,7 +1569,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:{ From 0ee2cd5ece4bf4ac13dee030162f902b248c910d Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 09:34:09 +0200 Subject: [PATCH 10/17] #120: Fixed dot issue in path during code generation --- backend/go-app/codegen.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index f620cc7f..366130b0 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -245,6 +245,8 @@ func buildStructure(swagger *openapi3.Swagger, curHash string) (string, error) { // This function generates the python code that's being used. // This is really meta when you program it. Handling parameters is hard here. func makePythoncode(swagger *openapi3.Swagger, name, url, method string, parameters, optionalQueries, headers []string) (string, string) { + log.Printf("makePythoncode URL: %s", url) + method = strings.ToLower(method) queryString := "" queryData := "" @@ -398,6 +400,8 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet verifyAddin, ) + log.Printf(data) + //log.Printf("%s", data) return functionname, data } @@ -594,10 +598,12 @@ 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. + log.Printf("ActualPath: %s", actualPath) + // https://godoc.org/github.com/getkin/kin-openapi/openapi3#PathItem if path.Get != nil { action, curCode := handleGet(swagger, api, extraParameters, path, actualPath) From c88870f7af698ec670996287177a912b8f8db433 Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 09:47:09 +0200 Subject: [PATCH 11/17] #120: Fixed double query parsing --- backend/go-app/codegen.go | 33 +++++++++++++++++++++++++++++-- frontend/src/views/AppCreator.jsx | 9 +++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index 366130b0..471848f7 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -245,8 +245,6 @@ func buildStructure(swagger *openapi3.Swagger, curHash string) (string, error) { // This function generates the python code that's being used. // This is really meta when you program it. Handling parameters is hard here. func makePythoncode(swagger *openapi3.Swagger, name, url, method string, parameters, optionalQueries, headers []string) (string, string) { - log.Printf("makePythoncode URL: %s", url) - method = strings.ToLower(method) queryString := "" queryData := "" @@ -256,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" @@ -942,6 +943,10 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { @@ -1087,6 +1092,10 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { @@ -1230,6 +1239,10 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { @@ -1374,6 +1387,10 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { @@ -1517,6 +1534,10 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { @@ -1660,6 +1681,10 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { @@ -1803,6 +1828,10 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor continue } + if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) { + continue + } + if firstQuery { baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name) } else { diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index 47776d61..e75496f9 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -20,6 +20,7 @@ import Tooltip from '@material-ui/core/Tooltip'; import CheckCircleIcon from '@material-ui/icons/CheckCircle'; import Breadcrumbs from '@material-ui/core/Breadcrumbs'; import AppsIcon from '@material-ui/icons/Apps'; +import CircularProgress from '@material-ui/core/CircularProgress'; import ErrorOutline from '@material-ui/icons/ErrorOutline'; import { useAlert } from "react-alert"; @@ -210,6 +211,7 @@ const AppCreator = (props) => { const [, setBasedata] = React.useState({}) const [actions, setActions] = useState([]) const [errorCode, setErrorCode] = useState("") + const [appBuilding, setAppBuilding] = useState(false) //const [actions, setActions] = useState([{ // "name": "Get workflows", @@ -524,6 +526,7 @@ const AppCreator = (props) => { // Saving the app that's been configured. const submitApp = () => { alert.info("Uploading and building app " + name) + setAppBuilding(true) setErrorCode("") // Format the information @@ -717,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 } @@ -756,6 +760,7 @@ const AppCreator = (props) => { // throw new Error("NOT 200 :O") //} + setAppBuilding(false) return response.json() }) .then((responseJson) => { @@ -1705,10 +1710,10 @@ const AppCreator = (props) => { {testView} */} - {errorCode.length > 0 ? `Error: ${errorCode}` : null} From d8224e712e98d7ffd6ea172a943fd1d84a6595e0 Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 09:49:11 +0200 Subject: [PATCH 12/17] Fixed minor issue in app creator --- backend/go-app/codegen.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index 471848f7..1f4f9d47 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -947,7 +947,7 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [ continue } - if firstQuery { + 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) @@ -1096,7 +1096,7 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor continue } - if firstQuery { + 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) @@ -1243,7 +1243,7 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo continue } - if firstQuery { + 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) @@ -1391,7 +1391,7 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [] continue } - if firstQuery { + 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) @@ -1538,7 +1538,7 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo continue } - if firstQuery { + 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) @@ -1685,7 +1685,7 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W continue } - if firstQuery { + 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) @@ -1832,7 +1832,7 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor continue } - if firstQuery { + 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) From 47993ec03007e126cce7fb962b4384b5c21809af Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 24 Aug 2020 10:11:49 +0200 Subject: [PATCH 13/17] #118: Fixed webhook view issue --- backend/go-app/codegen.go | 6 ++-- frontend/src/views/AngularWorkflow.jsx | 42 +++++--------------------- 2 files changed, 9 insertions(+), 39 deletions(-) diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index 1f4f9d47..a2c0ca5c 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -261,7 +261,7 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet url += f"&%s={%s}"`, query, query, query) } } else { - log.Printf("No optional queries?") + //log.Printf("No optional queries?") } // api.Authentication.Parameters[0].Value = "BearerAuth" @@ -401,9 +401,7 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet verifyAddin, ) - log.Printf(data) - - //log.Printf("%s", data) + //log.Printf(data) return functionname, data } diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 600c9264..64b85d30 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -2001,9 +2001,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 = { @@ -2049,8 +2049,8 @@ const AngularWorkflow = (props) => { setWorkflow(workflow) if (data.trigger_type === "WEBHOOK") { - //newWebhook(newAppData) - //saveWorkflow(workflow) + newWebhook(newAppData) + saveWorkflow(workflow) } } } @@ -4331,42 +4331,14 @@ const AngularWorkflow = (props) => { setTriggerCronWrapper(e.target.value) }} /> -
-
-
- Execution argument: -
-
- { - setTriggerBodyWrapper(e.target.value) - }} - />
- -