From 07bbf19d33853459f16ac6b8c161b47c0a46b2e4 Mon Sep 17 00:00:00 2001 From: frikky Date: Sun, 4 Apr 2021 17:28:32 +0200 Subject: [PATCH] #285: Made apps send available versions and mapped them in workflow view --- backend/go-app/go.mod | 4 +- backend/go-app/go.sum | 2 + backend/go-app/main.go | 2 +- backend/go-app/walkoff.go | 207 ------------------------- frontend/src/views/AngularWorkflow.jsx | 100 +++++++++++- frontend/src/views/Apps.jsx | 77 ++++++++- 6 files changed, 174 insertions(+), 218 deletions(-) diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 02af7a49..55b11a4d 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -3,6 +3,7 @@ module shuffle go 1.13 replace github.com/frikky/shuffle-shared => ../../../../git/shuffle-shared + //replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi require ( @@ -10,14 +11,15 @@ require ( cloud.google.com/go/datastore v1.4.0 cloud.google.com/go/pubsub v1.3.1 cloud.google.com/go/storage v1.12.0 + github.com/Masterminds/semver v1.5.0 // indirect github.com/Microsoft/go-winio v0.4.14 // indirect github.com/basgys/goxml2json v1.1.0 - github.com/frikky/kin-openapi v0.38.0 github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82 github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/docker v1.13.1 github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 // indirect + github.com/frikky/kin-openapi v0.38.0 github.com/frikky/shuffle-shared v0.0.23 github.com/ghodss/yaml v1.0.0 github.com/go-git/go-billy/v5 v5.0.0 diff --git a/backend/go-app/go.sum b/backend/go-app/go.sum index 21fd33ff..8d8cf6ec 100644 --- a/backend/go-app/go.sum +++ b/backend/go-app/go.sum @@ -48,6 +48,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 56b4ec22..edd8e863 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -6189,11 +6189,11 @@ func initHandlers() { // From here down isnt checked for org specific r.HandleFunc("/api/v1/apps/{appId}", shuffle.UpdateWorkflowAppConfig).Methods("PATCH", "OPTIONS") r.HandleFunc("/api/v1/apps/{appId}", shuffle.DeleteWorkflowApp).Methods("DELETE", "OPTIONS") + r.HandleFunc("/api/v1/apps/{appId}/config", shuffle.GetWorkflowAppConfig).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/apps/run_hotload", handleAppHotloadRequest).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/apps/download_remote", loadSpecificApps).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/apps/validate", validateAppInput).Methods("POST", "OPTIONS") - r.HandleFunc("/api/v1/apps/{appId}/config", getWorkflowAppConfig).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/apps", getWorkflowApps).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/apps", setNewWorkflowApp).Methods("PUT", "OPTIONS") r.HandleFunc("/api/v1/apps/search", getSpecificApps).Methods("POST", "OPTIONS") diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 49b550d2..3b780cdf 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -3396,113 +3396,6 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) { resp.Write([]byte(`{"success": true}`)) } -func getWorkflowAppConfig(resp http.ResponseWriter, request *http.Request) { - cors := handleCors(resp, request) - if cors { - return - } - - ctx := context.Background() - - location := strings.Split(request.URL.String(), "/") - var fileId string - if location[1] == "api" { - if len(location) <= 4 { - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - fileId = location[4] - } - - app, err := shuffle.GetApp(ctx, fileId, shuffle.User{}) - if err != nil { - log.Printf("[WARNING] Error getting app %s (app config): %s", fileId, err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) - return - } - - //if IsValid bool `json:"is_valid" yaml:"is_valid" required:true datastore:"is_valid"` - // Sharing bool `json:"sharing" yaml:"sharing" required:false datastore:"sharing"` - //log.Printf("Sharing: %s", app.Sharing) - //log.Printf("Generated: %s", app.Generated) - //log.Printf("Downloaded: %s", app.Downloaded) - - // FIXME - Handle sharing and such PROPERLY - if app.Sharing && app.Generated { - log.Printf("CAN SHARE APP!") - parsedApi, err := getOpenApiDatastore(ctx, fileId) - if err != nil { - log.Printf("[WARNING] OpenApi doesn't exist for: %s - err: %s", fileId, err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - if len(parsedApi.ID) > 0 { - parsedApi.Success = true - } else { - parsedApi.Success = false - } - - //log.Printf("PARSEDAPI: %#v", parsedApi) - data, err := json.Marshal(parsedApi) - if err != nil { - log.Printf("[WARNING] Error parsing api json: %s", err) - resp.WriteHeader(422) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed marshalling new parsed swagger: %s"}`, err))) - return - } - - resp.WriteHeader(200) - resp.Write(data) - return - } - - user, userErr := shuffle.HandleApiAuthentication(resp, request) - if userErr != nil { - log.Printf("[WARNING] Api authentication failed in get app: %s", userErr) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - if user.Id != app.Owner { - log.Printf("[WARNING] Wrong user (%s) for app %s", user.Username, app.Name) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - log.Printf("[INFO] Getting app %s (OpenAPI)", fileId) - parsedApi, err := getOpenApiDatastore(ctx, fileId) - if err != nil { - log.Printf("OpenApi doesn't exist for: %s - err: %s", fileId, err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - //log.Printf("Parsed API: %#v", parsedApi) - if len(parsedApi.ID) > 0 { - parsedApi.Success = true - } else { - parsedApi.Success = false - } - - data, err := json.Marshal(parsedApi) - if err != nil { - resp.WriteHeader(422) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed marshalling new parsed swagger: %s"}`, err))) - return - } - - resp.WriteHeader(200) - resp.Write(data) -} - func getWorkflowApps(resp http.ResponseWriter, request *http.Request) { cors := handleCors(resp, request) if cors { @@ -3525,34 +3418,6 @@ func getWorkflowApps(resp http.ResponseWriter, request *http.Request) { //return } - //if item, err := memcache.Get(ctx, memcacheName); err == memcache.ErrCacheMiss { - // // Not in cache - // log.Printf("Apps not in cache.") - //} else if err != nil { - // log.Printf("Error getting item: %v", err) - //} else { - // // FIXME - verify if value is ok? Can unmarshal etc. - // allApps := item.Value - - // if userErr == nil && len(user.PrivateApps) > 0 { - // var parsedApps []WorkflowApp - // err = json.Unmarshal(allApps, &parsedApps) - // if err == nil { - // log.Printf("Shouldve added %d apps", len(user.PrivateApps)) - // user.PrivateApps = append(user.PrivateApps, parsedApps...) - - // tmpApps, err := json.Marshal(user.PrivateApps) - // if err == nil { - // allApps = tmpApps - // } - // } - // } - - // resp.WriteHeader(200) - // resp.Write(allApps) - // return - //} - workflowapps, err := shuffle.GetAllWorkflowApps(ctx, 500) if err != nil { log.Printf("Failed getting apps (getworkflowapps): %s", err) @@ -3560,52 +3425,8 @@ func getWorkflowApps(resp http.ResponseWriter, request *http.Request) { resp.Write([]byte(`{"success": false}`)) return } - //log.Printf("Length: %d", len(workflowapps)) - - // FIXME - this is really garbage, but is here to protect again null values etc. newapps := workflowapps - /* - skipApps := []string{"Shuffle Subflow"} - newapps := []WorkflowApp{} - baseApps := []WorkflowApp{} - for _, workflowapp := range workflowapps { - //if !workflowapp.Activated && workflowapp.Generated { - // continue - //} - - if workflowapp.Owner != user.Id && user.Role != "admin" && !workflowapp.Sharing { - continue - } - - continueOuter := false - for _, skip := range skipApps { - if workflowapp.Name == skip { - continueOuter = true - break - } - } - - if continueOuter { - continue - } - - //workflowapp.Environment = "cloud" - newactions := []WorkflowAppAction{} - for _, action := range workflowapp.Actions { - //action.Environment = workflowapp.Environment - if len(action.Parameters) == 0 { - action.Parameters = []WorkflowAppActionParameter{} - } - - newactions = append(newactions, action) - } - - workflowapp.Actions = newactions - newapps = append(newapps, workflowapp) - baseApps = append(baseApps, workflowapp) - } - */ if len(user.PrivateApps) > 0 { found := false @@ -3625,7 +3446,6 @@ func getWorkflowApps(resp http.ResponseWriter, request *http.Request) { // Double unmarshal because of user apps newbody, err := json.Marshal(newapps) - //newbody, err := json.Marshal(workflowapps) if err != nil { log.Printf("Failed unmarshalling all newapps: %s", err) resp.WriteHeader(401) @@ -3633,33 +3453,6 @@ func getWorkflowApps(resp http.ResponseWriter, request *http.Request) { return } - //basebody, err := json.Marshal(baseApps) - ////newbody, err := json.Marshal(workflowapps) - //if err != nil { - // log.Printf("Failed unmarshalling all baseapps: %s", err) - // resp.WriteHeader(401) - // resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed unpacking workflow apps"}`))) - // return - //} - - // Refreshed every hour - //item := &memcache.Item{ - // Key: memcacheName, - // Value: basebody, - // Expiration: time.Minute * 60, - //} - //if err := memcache.Add(ctx, item); err == memcache.ErrNotStored { - // if err := memcache.Set(ctx, item); err != nil { - // log.Printf("Error setting item: %v", err) - // } - //} else if err != nil { - // log.Printf("error adding item: %v", err) - //} else { - // log.Printf("Set cache for %s", item.Key) - //} - - //log.Println(string(body)) - //log.Println(string(newbody)) resp.WriteHeader(200) resp.Write(newbody) } diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 156e476c..96bdb439 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -1302,9 +1302,10 @@ const AngularWorkflow = (props) => { } - const curapp = apps.find(a => a.name === curaction.app_name && a.app_version === curaction.app_version) + console.log(apps) + const curapp = apps.find(a => a.name === curaction.app_name && (a.app_version === curaction.app_version || a.loop_versions.includes(curaction.app_version))) if (!curapp || curapp === undefined) { - alert.error("App "+curaction.app_name+" not found. Is it activated?") + alert.error(`App ${curaction.app_name}:${curaction.app_version} not found. Is it activated?`) //return } else { @@ -2169,9 +2170,9 @@ const AngularWorkflow = (props) => {
What are WORKFLOW variables? {workflow.workflow_variables === null ? - null : workflow.workflow_variables.map(variable=> { + null : workflow.workflow_variables.map((variable, index) => { return ( -
+
{ }}>
@@ -2906,7 +2907,6 @@ const AngularWorkflow = (props) => { id="appsearch" onKeyPress={(event) => { if (event.key === "Enter") { - console.log("ENTER!") runSearch(event.target.value) } }} @@ -4215,6 +4215,66 @@ const AngularWorkflow = (props) => { borderRadius: borderRadius, } + const getApp = (appId, setApp) => { + fetch(globalUrl+"/api/v1/apps/"+appId+"/config?openapi=false", { + headers: { + 'Accept': 'application/json', + }, + credentials: "include", + }) + .then((response) => { + if (response.status === 200) { + //alert.success("Successfully GOT app "+appId) + } else { + alert.error("Failed getting app") + } + + return response.json() + }) + .then((responseJson) => { + console.log(responseJson) + + if (setApp && responseJson.actions !== undefined && responseJson.actions !== null) { + if (selectedApp.versions !== undefined && selectedApp.versions !== null) { + responseJson.versions = selectedApp.versions + } + + if (selectedApp.loop_versions !== undefined && selectedApp.loop_versions !== null) { + responseJson.loop_versions = selectedApp.loop_versions + } + + var foundAction = responseJson.actions.find(action => action.name === selectedAction.name) + console.log("Old : ", selectedAction) + console.log("Found: ", foundAction) + if (foundAction !== null && foundAction !== undefined) { + for (var paramkey in foundAction.parameters) { + const param = foundAction.parameters[paramkey] + + const foundParam = selectedAction.parameters.find(item => item.name === param.name) + if (foundParam === undefined) { + console.log("COULDNT find Param: ", param) + } else { + console.log("FoundP: ", foundParam) + foundAction.parameters[paramkey] = foundParam + } + } + } else { + alert.error("Couldn't find action "+selectedAction.name) + } + + // Updating params for the new action + selectedAction.parameters = foundAction.parameters + selectedAction.app_id = appId + selectedAction.app_version = responseJson.app_version + + setSelectedAction(selectedAction) + setSelectedApp(responseJson) + } + }) + .catch(error => { + alert.error(error.toString()) + }); + } const innerTextfieldStyle = { color: "white", @@ -4267,16 +4327,42 @@ const AngularWorkflow = (props) => {
-
+
{selectedAction.id === workflow.start ? null : - } + {selectedApp.versions !== null && selectedApp.versions !== undefined && selectedApp.versions.length > 0 ? + + : null }
diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index 40d2cb4e..03b98a5f 100644 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -631,6 +631,37 @@ const Apps = (props) => {
+ {selectedApp.versions !== null && selectedApp.versions !== undefined && selectedApp.versions.length > 0 ? + + : null } {isCloud ? @@ -835,7 +866,7 @@ const Apps = (props) => { var tmpapps = searchableApps.filter(data => data.name.toLowerCase().includes(searchfield) || data.description.toLowerCase().includes(searchfield)) newapps.push(...tmpapps) - console.log(newapps) + //console.log(newapps) setFilteredApps(newapps) //if ((newapps.length === 0 || searchBackend) && !appSearchLoading) { @@ -1108,7 +1139,7 @@ const Apps = (props) => { setValidation(true) var cors = "cors" - if (openApi.includes("localhost")) { + if (openApi.includes("= localhost")) { cors = "no-cors" } @@ -1126,6 +1157,48 @@ const Apps = (props) => { }); } + const getApp = (appId, setApp) => { + fetch(globalUrl+"/api/v1/apps/"+appId+"/config?openapi=false", { + headers: { + 'Accept': 'application/json', + }, + credentials: "include", + }) + .then((response) => { + if (response.status === 200) { + //alert.success("Successfully GOT app "+appId) + } else { + alert.error("Failed getting app") + } + + return response.json() + }) + .then((responseJson) => { + console.log(responseJson) + + if (setApp) { + if (selectedApp.versions !== undefined && selectedApp.versions !== null) { + responseJson.versions = selectedApp.versions + } + + if (selectedApp.loop_versions !== undefined && selectedApp.loop_versions !== null) { + responseJson.loop_versions = selectedApp.loop_versions + } + + //alert.info("Should set app to selected") + if (responseJson.actions !== undefined && responseJson.actions !== null && responseJson.actions.length > 0) { + setSelectedAction(responseJson.actions[0]) + } else { + setSelectedAction({}) + } + setSelectedApp(responseJson) + } + }) + .catch(error => { + alert.error(error.toString()) + }); + } + const deleteApp = (appId) => { alert.info("Attempting to delete app") fetch(globalUrl+"/api/v1/apps/"+appId, {