Merge branch 'nightly' of https://github.com/Shuffle/Shuffle into release-changes
This commit is contained in:
@@ -1,3 +1,11 @@
|
|||||||
# No extra requirements needed
|
# No extra requirements needed
|
||||||
requests
|
requests==2.32.3
|
||||||
urllib3
|
urllib3==2.3.0
|
||||||
|
liquidpy==0.8.2
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
flask[async]==3.1.0
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
PyJWT==2.10.1
|
||||||
|
cryptography==44.0.2
|
||||||
|
shufflepy==0.1.0
|
||||||
|
shuffle-sdk==0.0.25
|
||||||
|
|||||||
+79
-68
@@ -211,7 +211,7 @@ func fixTags(tags []string) []string {
|
|||||||
func buildImageMemory(fs billy.Filesystem, tags []string, dockerfileFolder string, downloadIfFail bool) error {
|
func buildImageMemory(fs billy.Filesystem, tags []string, dockerfileFolder string, downloadIfFail bool) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client, err := client.NewEnvClient()
|
client, err := client.NewEnvClient()
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Unable to create docker client: %s", err)
|
log.Printf("Unable to create docker client: %s", err)
|
||||||
return err
|
return err
|
||||||
@@ -473,73 +473,84 @@ func buildImage(tags []string, dockerfileLocation string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
client, err := client.NewEnvClient()
|
|
||||||
defer client.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Unable to create docker client: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[INFO] Docker Tags: %s", tags)
|
|
||||||
dockerfileSplit := strings.Split(dockerfileLocation, "/")
|
|
||||||
|
|
||||||
// Create a buffer
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
tw := tar.NewWriter(buf)
|
|
||||||
defer tw.Close()
|
|
||||||
baseDir := strings.Join(dockerfileSplit[0:len(dockerfileSplit)-1], "/")
|
|
||||||
|
|
||||||
// Builds the entire folder into buf
|
|
||||||
err = getParsedTar(tw, baseDir, "")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Tar issue: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerFileTarReader := bytes.NewReader(buf.Bytes())
|
|
||||||
buildOptions := types.ImageBuildOptions{
|
|
||||||
Remove: true,
|
|
||||||
Tags: tags,
|
|
||||||
BuildArgs: map[string]*string{},
|
|
||||||
}
|
|
||||||
//NetworkMode: "host",
|
|
||||||
|
|
||||||
httpProxy := os.Getenv("HTTP_PROXY")
|
|
||||||
if len(httpProxy) > 0 {
|
|
||||||
buildOptions.BuildArgs["HTTP_PROXY"] = &httpProxy
|
|
||||||
}
|
|
||||||
httpsProxy := os.Getenv("HTTPS_PROXY")
|
|
||||||
if len(httpProxy) > 0 {
|
|
||||||
buildOptions.BuildArgs["https_proxy"] = &httpsProxy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the actual image
|
|
||||||
imageBuildResponse, err := client.ImageBuild(
|
|
||||||
ctx,
|
|
||||||
dockerFileTarReader,
|
|
||||||
buildOptions,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the STDOUT from the build process
|
|
||||||
defer imageBuildResponse.Body.Close()
|
|
||||||
buildBuf := new(strings.Builder)
|
|
||||||
_, err = io.Copy(buildBuf, imageBuildResponse.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
if strings.Contains(buildBuf.String(), "errorDetail") {
|
|
||||||
log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), strings.Join(tags, "\n"))
|
|
||||||
return errors.New(fmt.Sprintf("Failed building %s. Check backend logs for details. Most likely means you have an old version of Docker.", strings.Join(tags, ",")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
client, err := client.NewEnvClient()
|
||||||
|
defer client.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to create docker client: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Docker Tags: %s", tags)
|
||||||
|
dockerfileSplit := strings.Split(dockerfileLocation, "/")
|
||||||
|
|
||||||
|
// Create a buffer
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
tw := tar.NewWriter(buf)
|
||||||
|
defer tw.Close()
|
||||||
|
baseDir := strings.Join(dockerfileSplit[0:len(dockerfileSplit)-1], "/")
|
||||||
|
|
||||||
|
// Builds the entire folder into buf
|
||||||
|
err = getParsedTar(tw, baseDir, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Tar issue during app build: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerFileTarReader := bytes.NewReader(buf.Bytes())
|
||||||
|
buildOptions := types.ImageBuildOptions{
|
||||||
|
Remove: true,
|
||||||
|
Tags: tags,
|
||||||
|
BuildArgs: map[string]*string{},
|
||||||
|
}
|
||||||
|
//NetworkMode: "host",
|
||||||
|
|
||||||
|
httpProxy := os.Getenv("HTTP_PROXY")
|
||||||
|
if len(httpProxy) > 0 {
|
||||||
|
buildOptions.BuildArgs["HTTP_PROXY"] = &httpProxy
|
||||||
|
}
|
||||||
|
httpsProxy := os.Getenv("HTTPS_PROXY")
|
||||||
|
if len(httpProxy) > 0 {
|
||||||
|
buildOptions.BuildArgs["https_proxy"] = &httpsProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the actual file content from dockerFileTarReader
|
||||||
|
/*
|
||||||
|
data, err := ioutil.ReadAll(dockerFileTarReader)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed reading Dockerfile TAR reader: %s", err)
|
||||||
|
} else {
|
||||||
|
log.Printf("[DEBUG] Dockerfile TAR reader content: %s", string(data))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Build the actual image
|
||||||
|
imageBuildResponse, err := client.ImageBuild(
|
||||||
|
ctx,
|
||||||
|
dockerFileTarReader,
|
||||||
|
buildOptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the STDOUT from the build process
|
||||||
|
defer imageBuildResponse.Body.Close()
|
||||||
|
buildBuf := new(strings.Builder)
|
||||||
|
_, err = io.Copy(buildBuf, imageBuildResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
if strings.Contains(buildBuf.String(), "errorDetail") {
|
||||||
|
log.Printf("[ERROR] Docker build:\n%s\nERROR ABOVE: Trying to pull tags from: %s", buildBuf.String(), strings.Join(tags, "\n"))
|
||||||
|
return errors.New(fmt.Sprintf("Failed building %s. Check backend logs for details. Most likely means you have an old version of Docker.", strings.Join(tags, ",")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,7 +682,7 @@ func getDockerImage(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "message": "No image name"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "message": "No image name"}`)))
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Trying to download image: '%s'. Appname: '%s'. BaseAppname: '%s', Split2: %s", version.Name, appname, baseAppname, appnameSplit2)
|
log.Printf("[INFO] Trying to download image: '%s'. Appname: '%s'. BaseAppname: '%s', Split2: %s", version.Name, appname, baseAppname, appnameSplit2)
|
||||||
@@ -870,7 +881,7 @@ func handleRemoteDownloadApp(resp http.ResponseWriter, ctx context.Context, user
|
|||||||
type tmpapp struct {
|
type tmpapp struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
OpenAPI string `json:"openapi"`
|
OpenAPI string `json:"openapi"`
|
||||||
App string `json:"app"`
|
App string `json:"app"`
|
||||||
}
|
}
|
||||||
|
|
||||||
app := tmpapp{}
|
app := tmpapp{}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ require (
|
|||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/h2non/filetype v1.1.3
|
github.com/h2non/filetype v1.1.3
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shuffle/shuffle-shared v0.8.58
|
github.com/shuffle/shuffle-shared v0.8.72
|
||||||
golang.org/x/crypto v0.37.0
|
golang.org/x/crypto v0.37.0
|
||||||
google.golang.org/api v0.228.0
|
google.golang.org/api v0.228.0
|
||||||
google.golang.org/grpc v1.71.1
|
google.golang.org/grpc v1.71.1
|
||||||
|
|||||||
@@ -341,8 +341,8 @@ github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fc
|
|||||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
github.com/shuffle/shuffle-shared v0.8.58 h1:QzCKtQjuaozb+xyLkw6IjwqCNVWzpuJJnxkpXkLCP9M=
|
github.com/shuffle/shuffle-shared v0.8.72 h1:HVOsRt83/1k9P+8q1FAxXnDKyROoDAFa1A3MnoRJYb0=
|
||||||
github.com/shuffle/shuffle-shared v0.8.58/go.mod h1:OLAwH/Ym4941Jn5DF1oZaq6iBpmjG2SNrTZ9Xqck5So=
|
github.com/shuffle/shuffle-shared v0.8.72/go.mod h1:OLAwH/Ym4941Jn5DF1oZaq6iBpmjG2SNrTZ9Xqck5So=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
|||||||
+101
-59
@@ -11,17 +11,18 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"os/exec"
|
||||||
|
"net/http"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -35,9 +36,9 @@ import (
|
|||||||
|
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/storage/memory"
|
|
||||||
gitProxy "github.com/go-git/go-git/v5/plumbing/transport"
|
gitProxy "github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
http2 "github.com/go-git/go-git/v5/plumbing/transport/http"
|
http2 "github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
|
||||||
// Random
|
// Random
|
||||||
xj "github.com/basgys/goxml2json"
|
xj "github.com/basgys/goxml2json"
|
||||||
@@ -61,6 +62,7 @@ var registryName = "registry.hub.docker.com"
|
|||||||
var runningEnvironment = "onprem"
|
var runningEnvironment = "onprem"
|
||||||
|
|
||||||
var syncUrl = "https://shuffler.io"
|
var syncUrl = "https://shuffler.io"
|
||||||
|
//var syncUrl = "http://localhost:5002"
|
||||||
|
|
||||||
type retStruct struct {
|
type retStruct struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
@@ -447,7 +449,7 @@ func checkGitProxy(cloneOptions *git.CloneOptions) *git.CloneOptions {
|
|||||||
func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) error {
|
func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) error {
|
||||||
// Returns false if there is an issue
|
// Returns false if there is an issue
|
||||||
// Use this for register
|
// Use this for register
|
||||||
err := shuffle.CheckPasswordStrength(password)
|
err := shuffle.CheckPasswordStrength(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Bad password strength: %s", err)
|
log.Printf("[WARNING] Bad password strength: %s", err)
|
||||||
return err
|
return err
|
||||||
@@ -460,8 +462,6 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
//users, err := FindUser(ctx context.Context, username string) ([]User, error) {
|
|
||||||
|
|
||||||
users, err := shuffle.FindUser(ctx, strings.ToLower(strings.TrimSpace(username)))
|
users, err := shuffle.FindUser(ctx, strings.ToLower(strings.TrimSpace(username)))
|
||||||
if err != nil && len(users) == 0 {
|
if err != nil && len(users) == 0 {
|
||||||
log.Printf("[WARNING] Failed getting user %s: %s", username, err)
|
log.Printf("[WARNING] Failed getting user %s: %s", username, err)
|
||||||
@@ -486,7 +486,6 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini)
|
|||||||
newUser.Active = true
|
newUser.Active = true
|
||||||
newUser.Orgs = []string{org.Id}
|
newUser.Orgs = []string{org.Id}
|
||||||
|
|
||||||
// FIXME - Remove this later
|
|
||||||
if role == "admin" {
|
if role == "admin" {
|
||||||
newUser.Role = "admin"
|
newUser.Role = "admin"
|
||||||
newUser.Roles = []string{"admin"}
|
newUser.Roles = []string{"admin"}
|
||||||
@@ -1852,6 +1851,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// return
|
// return
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] HOOKS: webhook callback: %s", request.URL.String())
|
||||||
|
|
||||||
if request.Method != "POST" {
|
if request.Method != "POST" {
|
||||||
request.Method = "POST"
|
request.Method = "POST"
|
||||||
}
|
}
|
||||||
@@ -1863,6 +1864,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
path := strings.Split(request.URL.String(), "/")
|
path := strings.Split(request.URL.String(), "/")
|
||||||
if len(path) < 4 {
|
if len(path) < 4 {
|
||||||
|
log.Printf("[DEBUG] HOOKS: Invalid webhook path: %s", request.URL.String())
|
||||||
resp.WriteHeader(403)
|
resp.WriteHeader(403)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -1878,7 +1880,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
if location[1] == "api" {
|
if location[1] == "api" {
|
||||||
if len(location) <= 4 {
|
if len(location) <= 4 {
|
||||||
log.Printf("[INFO] Couldn't handle location. Too short in webhook: %d", len(location))
|
log.Printf("[INFO] Couldn't handle location. Too short in webhook: %d", len(location))
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1895,6 +1897,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] HOOKS: Pre user agent check")
|
||||||
|
|
||||||
// Find user agent header
|
// Find user agent header
|
||||||
userAgent := request.Header.Get("User-Agent")
|
userAgent := request.Header.Get("User-Agent")
|
||||||
if strings.Contains(strings.ToLower(userAgent), "microsoftpreview") || strings.Contains(strings.ToLower(userAgent), "googlebot") {
|
if strings.Contains(strings.ToLower(userAgent), "microsoftpreview") || strings.Contains(strings.ToLower(userAgent), "googlebot") {
|
||||||
@@ -1917,8 +1921,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
//log.Printf("HookID: %s", hookId)
|
//log.Printf("HookID: %s", hookId)
|
||||||
hook, err := shuffle.GetHook(ctx, hookId)
|
hook, err := shuffle.GetHook(ctx, hookId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Failed getting hook %s (callback): %s", hookId, err)
|
log.Printf("[WARNING] HOOKS: Failed getting hook %s (callback): %s", hookId, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1930,21 +1934,21 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
//resp.WriteHeader(200)
|
//resp.WriteHeader(200)
|
||||||
//resp.Write([]byte(`{"success": true}`))
|
//resp.Write([]byte(`{"success": true}`))
|
||||||
if hook.Status == "stopped" {
|
if hook.Status == "stopped" {
|
||||||
log.Printf("[WARNING] Not running %s because hook status is stopped", hook.Id)
|
log.Printf("[WARNING] HOOKS: Not running %s because hook status is stopped", hook.Id)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "The webhook isn't running. Is it running?"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "The webhook isn't running. Is it running?"}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hook.Workflows) == 0 {
|
if len(hook.Workflows) == 0 {
|
||||||
log.Printf("[DEBUG] Not running because hook isn't connected to any workflows")
|
log.Printf("[DEBUG] HOOKS: Not running because hook isn't connected to any workflows")
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No workflows are defined"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No workflows are defined"}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if hook.Environment == "cloud" {
|
if hook.Environment == "cloud" {
|
||||||
log.Printf("[DEBUG] This should trigger in the cloud. Duplicate action allowed onprem.")
|
log.Printf("[DEBUG] HOOKS: This should trigger in the cloud. Duplicate action allowed onprem.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check auth
|
// Check auth
|
||||||
@@ -1960,7 +1964,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[DEBUG] Body data error: %s", err)
|
log.Printf("[DEBUG] HOOKS: data read error: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -2001,7 +2005,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
b, err := json.Marshal(newBody)
|
b, err := json.Marshal(newBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed newBody marshaling for webhook: %s", err)
|
log.Printf("[ERROR] HOOKS: Failed newBody marshaling for webhook: %s", err)
|
||||||
resp.WriteHeader(500)
|
resp.WriteHeader(500)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -2017,7 +2021,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(hook.Start) == 0 {
|
if len(hook.Start) == 0 {
|
||||||
log.Printf("[WARNING] No start node for hook %s - running with workflow default.", hook.Id)
|
log.Printf("[ERROR] HOOKS: No start node for hook %s - running with workflow default.", hook.Id)
|
||||||
//bodyWrapper = string(parsedBody)
|
//bodyWrapper = string(parsedBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2029,7 +2033,6 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
// OrgId: activeOrgs[0].Id,
|
// OrgId: activeOrgs[0].Id,
|
||||||
workflowExecution, executionResp, err := handleExecution(item, workflow, newRequest, hook.OrgId)
|
workflowExecution, executionResp, err := handleExecution(item, workflow, newRequest, hook.OrgId)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if hook.Version == "v2" {
|
if hook.Version == "v2" {
|
||||||
timeout := 15
|
timeout := 15
|
||||||
@@ -2064,6 +2067,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "execution_id": "%s"}`, workflowExecution.ExecutionId)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "execution_id": "%s"}`, workflowExecution.ExecutionId)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2071,6 +2075,10 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, executionResp)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, executionResp)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[ERROR] HOOKS: END OF FUNCTION FOR '%s'. IF this is reached, something went wrong.", hook.Id)
|
||||||
|
resp.WriteHeader(500)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed to run workflow. Check logs."}`))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePipelineCallback(resp http.ResponseWriter, request *http.Request) {
|
func handlePipelineCallback(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -3087,7 +3095,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Id == app.Owner || (user.Role == "admin" && user.ActiveOrg.Id == app.ReferenceOrg) || shuffle.ArrayContains(app.Contributors, user.Id) {
|
if user.Id == app.Owner || (user.Role == "admin" && user.ActiveOrg.Id == app.ReferenceOrg) || shuffle.ArrayContains(app.Contributors, user.Id) {
|
||||||
log.Printf("[DEBUG] Editing app %s with user %s (%s) in org %s", test.Id, user.Username, user.Id, user.ActiveOrg.Id)
|
log.Printf("[DEBUG] Editing app %s with user %s (%s) in org %s", test.Id, user.Username, user.Id, user.ActiveOrg.Id)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name)
|
log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name)
|
||||||
@@ -3375,7 +3383,6 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
log.Printf("[DEBUG] Successfully built app %s (%s)", api.Name, api.ID)
|
log.Printf("[DEBUG] Successfully built app %s (%s)", api.Name, api.ID)
|
||||||
if len(user.Id) > 0 {
|
if len(user.Id) > 0 {
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
@@ -3799,30 +3806,56 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if org.SyncConfig.WorkflowBackup {
|
// Check if it's 1/20 times (600 seconds - 10 min on average)
|
||||||
workflows, err := shuffle.GetAllWorkflowsByQuery(ctx, foundUser, 250, "")
|
// Only problem: May take time to sync the first time, which is annoying
|
||||||
if err != nil {
|
shouldBackupData := false
|
||||||
log.Printf("[ERROR] Failed getting backup workflows for org %s: %s", org.Id, err)
|
randomNumber := rand.Intn(20)
|
||||||
} else {
|
if randomNumber == 0 {
|
||||||
backupJob.Workflows = workflows
|
shouldBackupData = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if org.SyncConfig.AppBackup && len(org.Users) > 0 {
|
// Just to prevent it from spamming large outbound requests
|
||||||
|
if shouldBackupData {
|
||||||
apps, err := shuffle.GetPrioritizedApps(ctx, foundUser)
|
if org.SyncConfig.WorkflowBackup {
|
||||||
if err != nil {
|
workflows, err := shuffle.GetAllWorkflowsByQuery(ctx, foundUser, 250, "")
|
||||||
log.Printf("[ERROR] Failed getting backup apps for org %s: %s", org.Id, err)
|
if err != nil {
|
||||||
} else {
|
log.Printf("[ERROR] Failed getting backup workflows for org %s: %s", org.Id, err)
|
||||||
backupJob.Apps = apps
|
} else {
|
||||||
|
backupJob.Workflows = workflows
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
info, err := shuffle.GetOrgStatistics(ctx, org.Id)
|
if org.SyncConfig.AppBackup && len(org.Users) > 0 {
|
||||||
if err != nil {
|
foundUser.ActiveOrg.Id = org.Id
|
||||||
log.Printf("[ERROR] Failed getting org statistics backup for org %s: %s", org.Id, err)
|
apps, err := shuffle.GetPrioritizedApps(ctx, foundUser)
|
||||||
} else {
|
if err != nil {
|
||||||
backupJob.Stats = *info
|
log.Printf("[ERROR] Failed getting backup apps for org %s: %s", org.Id, err)
|
||||||
|
} else {
|
||||||
|
parsedApps := []shuffle.WorkflowApp{}
|
||||||
|
for _, app := range apps {
|
||||||
|
if len(app.Actions) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !app.Generated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedApps = append(parsedApps, app)
|
||||||
|
}
|
||||||
|
|
||||||
|
backupJob.Apps = parsedApps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send stats once every 10 times or so..?
|
||||||
|
// For now, just send every time
|
||||||
|
info, err := shuffle.GetOrgStatistics(ctx, org.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed getting org statistics backup for org %s: %s", org.Id, err)
|
||||||
|
} else {
|
||||||
|
backupJob.Stats = *info
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backupJobData, err := json.Marshal(backupJob)
|
backupJobData, err := json.Marshal(backupJob)
|
||||||
@@ -3859,6 +3892,7 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
|
|||||||
//log.Printf("[ERROR] Failed cloud sync job controller run for '%s': %s", respBody, err)
|
//log.Printf("[ERROR] Failed cloud sync job controller run for '%s': %s", respBody, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3996,6 +4030,8 @@ func runInitEs(ctx context.Context) {
|
|||||||
time.Sleep(30 * time.Second)
|
time.Sleep(30 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This should ONLY run on one backend instance
|
||||||
|
|
||||||
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
|
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
|
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
|
||||||
@@ -4139,7 +4175,7 @@ func runInitEs(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//interval := int(org.SyncConfig.Interval)
|
//interval := int(org.SyncConfig.Interval)
|
||||||
interval := 15
|
interval := 30
|
||||||
if interval == 0 {
|
if interval == 0 {
|
||||||
log.Printf("[WARNING] Skipping org %s because sync isn't set (0).", org.Id)
|
log.Printf("[WARNING] Skipping org %s because sync isn't set (0).", org.Id)
|
||||||
continue
|
continue
|
||||||
@@ -4241,17 +4277,20 @@ func runInitEs(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if newresp.StatusCode != 200 {
|
|
||||||
log.Printf("[WARNING] Failed stopping runs in environment %s. Status code: %d", environment, newresp.StatusCode)
|
respBody, err := ioutil.ReadAll(newresp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed setting respbody %s for execution stop. Status: %d", err, newresp.StatusCode)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
//respBody, err := ioutil.ReadAll(newresp.Body)
|
if newresp.StatusCode != 200 {
|
||||||
//if err != nil {
|
if !strings.Contains(string(respBody), "is active") {
|
||||||
// log.Printf("[ERROR] Failed setting respbody %s", err)
|
log.Printf("[WARNING] Failed stopping runs in environment %s. Status code: %d. Body: %s", environment, newresp.StatusCode, string(respBody))
|
||||||
// continue
|
}
|
||||||
//}
|
|
||||||
//log.Printf("[DEBUG] Successfully ran workflow cleanup request for %s. Body: %s", environment, string(respBody))
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
url = fmt.Sprintf("http://localhost:%s/api/v1/environments/%s/rerun", backendPort, environment)
|
url = fmt.Sprintf("http://localhost:%s/api/v1/environments/%s/rerun", backendPort, environment)
|
||||||
req, err = http.NewRequest(
|
req, err = http.NewRequest(
|
||||||
@@ -4377,7 +4416,7 @@ func runInitEs(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if os.Getenv("SHUFFLE_HEALTHCHECK_DISABLED") != "true" {
|
if os.Getenv("SHUFFLE_HEALTHCHECK_DISABLED") != "true" {
|
||||||
healthcheckInterval := 60
|
healthcheckInterval := 60
|
||||||
log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats, and dashboard on /health. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval)
|
log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats, and dashboard on /health. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval)
|
||||||
job := func() {
|
job := func() {
|
||||||
// Prepare a fake http.responsewriter
|
// Prepare a fake http.responsewriter
|
||||||
@@ -4669,7 +4708,7 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// If you want to disable cloud sync, see previous section.
|
// If you want to disable cloud sync, see previous section.
|
||||||
if org.CloudSync {
|
if org.CloudSync {
|
||||||
log.Printf("[WARNING] Org %s is already syncing. Skip", org.Id)
|
log.Printf("[WARNING] Org %s is already syncing. Skip", org.Id)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Your org is already syncing. Nothing to set up."}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Your org is already syncing. Nothing to set up."}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -4746,6 +4785,9 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
|
|||||||
org.SyncConfig = shuffle.SyncConfig{
|
org.SyncConfig = shuffle.SyncConfig{
|
||||||
Apikey: responseData.SessionKey,
|
Apikey: responseData.SessionKey,
|
||||||
Interval: responseData.IntervalSeconds,
|
Interval: responseData.IntervalSeconds,
|
||||||
|
|
||||||
|
WorkflowBackup: true,
|
||||||
|
AppBackup: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
interval := int(responseData.IntervalSeconds)
|
interval := int(responseData.IntervalSeconds)
|
||||||
|
|||||||
@@ -1905,8 +1905,8 @@ func scheduleWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
err = shuffle.SetSchedule(ctx, newSchedule)
|
err = shuffle.SetSchedule(ctx, newSchedule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed setting cloud schedule: %s", err)
|
log.Printf("[ERROR] Failed setting cloud schedule: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1941,17 +1941,22 @@ func scheduleWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
// FIXME - real error message lol
|
// FIXME - real error message lol
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed creating schedule: %s", err)
|
log.Printf("[ERROR] Failed creating schedule: %s", err)
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Invalid argument. Try cron */15 * * * *"}`)))
|
resp.WriteHeader(400)
|
||||||
|
if schedule.Environment == "cloud" {
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Invalid argument. For cloud schedules, try cron */15 * * * *"}`)))
|
||||||
|
} else {
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Invalid argument. For onprem schedules, try 60 for 60 seconds"}`)))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//workflow.Schedules = append(workflow.Schedules, schedule)
|
//workflow.Schedules = append(workflow.Schedules, schedule)
|
||||||
err = shuffle.SetWorkflow(ctx, *workflow, workflow.ID)
|
err = shuffle.SetWorkflow(ctx, *workflow, workflow.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed setting workflow for schedule: %s", err)
|
log.Printf("[ERROR] Failed setting workflow for schedule: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ const App = (message, props) => {
|
|||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/AdminSetup"
|
path="/adminsetup"
|
||||||
element={
|
element={
|
||||||
<AdminSetup
|
<AdminSetup
|
||||||
isLoaded={isLoaded}
|
isLoaded={isLoaded}
|
||||||
|
|||||||
@@ -208,9 +208,17 @@ const AdminNavBar = (props) => {
|
|||||||
const ComponentToRender = selectedItemData.component;
|
const ComponentToRender = selectedItemData.component;
|
||||||
const componentProps = selectedItemData.props;
|
const componentProps = selectedItemData.props;
|
||||||
|
|
||||||
return <ComponentToRender {...componentProps} />;
|
const updatedProps = {
|
||||||
|
...componentProps,
|
||||||
|
notifications: notifications,
|
||||||
|
setNotifications: setNotifications,
|
||||||
|
userdata: userdata,
|
||||||
|
selectedOrganization: selectedOrganization
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return <ComponentToRender {...updatedProps} />;
|
||||||
|
};
|
||||||
|
|
||||||
const defaultImage = "/images/logos/orange_logo.svg"
|
const defaultImage = "/images/logos/orange_logo.svg"
|
||||||
const imageData =
|
const imageData =
|
||||||
selectedOrganization?.image === undefined || selectedOrganization?.image.length === 0
|
selectedOrganization?.image === undefined || selectedOrganization?.image.length === 0
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ import { Context } from '../context/ContextApi.jsx';
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
)
|
)
|
||||||
|
|
||||||
const AppAuthTab = memo((props) => {
|
const AppAuthTab = memo((props) => {
|
||||||
@@ -1181,6 +1181,47 @@ const AppAuthTab = memo((props) => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
<Tooltip
|
||||||
|
title={"Copy Auth ID"}
|
||||||
|
style={{}}
|
||||||
|
aria-label={"copy"}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
style = {{padding: "6px"}}
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(data.id);
|
||||||
|
document.execCommand("copy");
|
||||||
|
|
||||||
|
toast(data.id + " copied to clipboard");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fillOpacity="1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 4H7.6C7.17565 4 6.76869 4.16857 6.46863 4.46863C6.16857 4.76869 6 5.17565 6 5.6V18.4C6 18.8243 6.16857 19.2313 6.46863 19.5314C6.76869 19.8314 7.17565 20 7.6 20H17.2C17.6243 20 18.0313 19.8314 18.3314 19.5314C18.6314 19.2313 18.8 18.8243 18.8 18.4V8.8L14 4Z"
|
||||||
|
stroke={themeMode === "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 4V8.8H18.8"
|
||||||
|
stroke={themeMode === "dark" ? "#F1F1F1" : "#333"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={{ }}
|
style={{ }}
|
||||||
disabled={data.org_id !== selectedOrganization.id}
|
disabled={data.org_id !== selectedOrganization.id}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ import {
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
);
|
);
|
||||||
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import { Context } from '../context/ContextApi.jsx';
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
);;
|
);;
|
||||||
|
|
||||||
const AppModal = ({ open, onClose, app, globalUrl, getApps}) => {
|
const AppModal = ({ open, onClose, app, globalUrl, getApps}) => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
InputAdornment,
|
InputAdornment,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const Appsearch = props => {
|
const Appsearch = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp, placeholder,
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp, placeholder,
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import aa from 'search-insights'
|
import aa from 'search-insights'
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const Appsearch = props => {
|
const Appsearch = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
||||||
const { themeMode } = useContext(Context)
|
const { themeMode } = useContext(Context)
|
||||||
|
|||||||
@@ -52,11 +52,13 @@ import {
|
|||||||
|
|
||||||
//import { useAlert
|
//import { useAlert
|
||||||
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||||
import BillingStats from "./BillingStats.jsx";
|
import BillingStats from "../components/BillingStats.jsx";
|
||||||
|
import LicencePopup from "../components/LicencePopup.jsx";
|
||||||
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
|
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
|
||||||
import { Context } from "../context/ContextApi.jsx";
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import LicencePopup from "./LicencePopup.jsx";
|
|
||||||
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import { DataGrid } from "@mui/x-data-grid";
|
import { DataGrid } from "@mui/x-data-grid";
|
||||||
|
|
||||||
const Billing = memo((props) => {
|
const Billing = memo((props) => {
|
||||||
@@ -2597,64 +2599,87 @@ const Billing = memo((props) => {
|
|||||||
Utilization & Stats
|
Utilization & Stats
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
{isChildOrg ? (
|
<span>
|
||||||
<BillingStats
|
|
||||||
isCloud={isCloud}
|
|
||||||
clickedFromOrgTab={clickedFromOrgTab}
|
|
||||||
globalUrl={globalUrl}
|
|
||||||
selectedOrganization={selectedOrganization}
|
|
||||||
userdata={userdata}
|
|
||||||
/>
|
|
||||||
): (
|
|
||||||
<>
|
|
||||||
<Tabs
|
<Tabs
|
||||||
value={currentTab}
|
value={currentTab}
|
||||||
onChange={(event, newValue) => setCurrentTab(newValue)}
|
onChange={(event, newValue) => {
|
||||||
|
setCurrentTab(-1)
|
||||||
|
|
||||||
|
// Force re-render
|
||||||
|
setTimeout(() => {
|
||||||
|
setCurrentTab(newValue)
|
||||||
|
}, 100);
|
||||||
|
}}
|
||||||
style={{ marginTop: 20 }}
|
style={{ marginTop: 20 }}
|
||||||
TabIndicatorProps={{
|
TabIndicatorProps={{
|
||||||
style: {
|
style: {
|
||||||
height: 3,
|
height: 3,
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
marginLeft: 12,
|
marginLeft: 12,
|
||||||
marginRight: 12,
|
marginRight: 12,
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
label="Parent Organization"
|
label="Parent Organization"
|
||||||
style={{ textTransform: 'none', fontSize: 16, minWidth: 'auto', paddingLeft: 12, paddingRight: 12 }}
|
style={{ textTransform: 'none',}}
|
||||||
/>
|
value={0}
|
||||||
<Tab
|
/>
|
||||||
label="Child Organization"
|
|
||||||
style={{ textTransform: 'none', fontSize: 16, minWidth: 'auto', paddingLeft: 12, paddingRight: 12 }}
|
{isCloud ?
|
||||||
/>
|
<Tab
|
||||||
|
label="Cloud-Synced Stats"
|
||||||
|
style={{ textTransform: 'none', }}
|
||||||
|
value={1}
|
||||||
|
/>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
label="Child Organization Stats"
|
||||||
|
disabled={isChildOrg}
|
||||||
|
style={{ textTransform: 'none', }}
|
||||||
|
value={2}
|
||||||
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
{currentTab === 0 ? (
|
<div style={{paddingBottom: 200, minHeight: 750, }}>
|
||||||
<div style={{ marginTop: 30,}}>
|
{currentTab === 0 ?
|
||||||
<BillingStats
|
<div style={{ marginTop: 30,}}>
|
||||||
isCloud={isCloud}
|
<BillingStats
|
||||||
clickedFromOrgTab={clickedFromOrgTab}
|
isCloud={isCloud}
|
||||||
globalUrl={globalUrl}
|
clickedFromOrgTab={clickedFromOrgTab}
|
||||||
selectedOrganization={selectedOrganization}
|
globalUrl={globalUrl}
|
||||||
userdata={userdata}
|
selectedOrganization={selectedOrganization}
|
||||||
/>
|
userdata={userdata}
|
||||||
</div>
|
/>
|
||||||
): (
|
</div>
|
||||||
<BillingStatsChildOrg
|
: currentTab === 1 ?
|
||||||
isCloud={isCloud}
|
<div style={{ marginTop: 30,}}>
|
||||||
clickedFromOrgTab={clickedFromOrgTab}
|
<BillingStats
|
||||||
globalUrl={globalUrl}
|
isCloud={isCloud}
|
||||||
selectedOrganization={selectedOrganization}
|
clickedFromOrgTab={clickedFromOrgTab}
|
||||||
userdata={userdata}
|
globalUrl={globalUrl}
|
||||||
allChildOrgs={allChildOrgs}
|
selectedOrganization={selectedOrganization}
|
||||||
setAllChildOrgs={setAllChildOrgs}
|
userdata={userdata}
|
||||||
allChildOrgsStats={allChildOrgsStats}
|
|
||||||
setAllChildOrgsStats={setAllChildOrgsStats}
|
syncStats={true}
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
</>
|
:
|
||||||
)}
|
<BillingStatsChildOrg
|
||||||
|
isCloud={isCloud}
|
||||||
|
clickedFromOrgTab={clickedFromOrgTab}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
selectedOrganization={selectedOrganization}
|
||||||
|
userdata={userdata}
|
||||||
|
allChildOrgs={allChildOrgs}
|
||||||
|
setAllChildOrgs={setAllChildOrgs}
|
||||||
|
allChildOrgsStats={allChildOrgsStats}
|
||||||
|
setAllChildOrgsStats={setAllChildOrgsStats}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,8 +33,15 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
BarChart,
|
BarChart,
|
||||||
|
BarSeries,
|
||||||
|
Bar,
|
||||||
|
BarLabel,
|
||||||
|
|
||||||
GridlineSeries,
|
GridlineSeries,
|
||||||
Gridline,
|
Gridline,
|
||||||
|
TooltipArea,
|
||||||
|
ChartTooltip,
|
||||||
|
TooltipTemplate,
|
||||||
} from 'reaviz';
|
} from 'reaviz';
|
||||||
|
|
||||||
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||||
@@ -45,31 +52,52 @@ const LineChartWrapper = ({keys, inputname, height, width}) => {
|
|||||||
const inputdata = keys.data === undefined ? keys : keys.data
|
const inputdata = keys.data === undefined ? keys : keys.data
|
||||||
const {themeMode} = useContext(Context)
|
const {themeMode} = useContext(Context)
|
||||||
const theme = getTheme(themeMode)
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: "white", border: "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, padding: 30, marginTop: 15, backgroundColor: theme.palette.platformColor, overflow: "hidden", }}>
|
<div style={{color: "white", border: "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, padding: 30, marginTop: 15, backgroundColor: theme.palette.platformColor, overflow: "hidden", }}>
|
||||||
<Typography variant="h6" style={{marginBotton: 15, }}>
|
<Typography variant="h6" style={{marginBotton: 30, }}>
|
||||||
{inputname}
|
{inputname}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<BarChart
|
<BarChart
|
||||||
|
style={{marginTop: 100, }}
|
||||||
width={"100%"}
|
width={"100%"}
|
||||||
height={height}
|
height={height}
|
||||||
data={inputdata}
|
data={inputdata}
|
||||||
|
|
||||||
|
series={
|
||||||
|
<BarSeries
|
||||||
|
bar={
|
||||||
|
<Bar />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
gridlines={
|
gridlines={
|
||||||
<GridlineSeries line={<Gridline direction="all" />} />
|
<GridlineSeries line={<Gridline direction="all" />} />
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const AppStats = (defaultprops) => {
|
const AppStats = (defaultprops) => {
|
||||||
const { globalUrl, selectedOrganization, userdata, isCloud, inputWorkflows,clickedFromOrgTab } = defaultprops;
|
const {
|
||||||
|
globalUrl,
|
||||||
|
selectedOrganization,
|
||||||
|
userdata,
|
||||||
|
isCloud,
|
||||||
|
inputWorkflows,
|
||||||
|
clickedFromOrgTab,
|
||||||
|
syncStats,
|
||||||
|
} = defaultprops;
|
||||||
|
|
||||||
const [keys, setKeys] = useState([])
|
const [keys, setKeys] = useState([])
|
||||||
const [searches, setSearches] = useState([]);
|
const [searches, setSearches] = useState([]);
|
||||||
const [appRuns, setAppruns] = useState(undefined);
|
const [appRuns, setAppruns] = useState(undefined);
|
||||||
|
const [childOrgsAppRuns, setChildOrgsAppRuns] = useState(undefined);
|
||||||
const [appRunCosts, setApprunCosts] = useState(undefined);
|
const [appRunCosts, setApprunCosts] = useState(undefined);
|
||||||
const [workflowRuns, setWorkflowRuns] = useState(undefined);
|
const [workflowRuns, setWorkflowRuns] = useState(undefined);
|
||||||
const [subflowRuns, setSubflowRuns] = useState(undefined);
|
const [subflowRuns, setSubflowRuns] = useState(undefined);
|
||||||
@@ -99,9 +127,6 @@ const AppStats = (defaultprops) => {
|
|||||||
|
|
||||||
|
|
||||||
const getWorkflowStats = async (workflow, startTime, endTime) => {
|
const getWorkflowStats = async (workflow, startTime, endTime) => {
|
||||||
if (!userdata.support) {
|
|
||||||
return workflow
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workflow.id === undefined || workflow.id === null || workflow.id === "") {
|
if (workflow.id === undefined || workflow.id === null || workflow.id === "") {
|
||||||
return workflow
|
return workflow
|
||||||
@@ -166,12 +191,8 @@ const AppStats = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadWorkflowStats = (foundWorkflows, startTime, endTime) => {
|
const loadWorkflowStats = (foundWorkflows, startTime, endTime) => {
|
||||||
if (!userdata.support) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundWorkflows === undefined || foundWorkflows === null || foundWorkflows.length === 0) {
|
if (foundWorkflows === undefined || foundWorkflows === null || foundWorkflows.length === 0) {
|
||||||
console.log("Not workflows")
|
setResultLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +201,9 @@ const AppStats = (defaultprops) => {
|
|||||||
const promises = foundWorkflows.slice(0, 50).map(wf => getWorkflowStats(wf, startTime, endTime));
|
const promises = foundWorkflows.slice(0, 50).map(wf => getWorkflowStats(wf, startTime, endTime));
|
||||||
|
|
||||||
const allData = Promise.all(promises);
|
const allData = Promise.all(promises);
|
||||||
|
if (allData === undefined || allData === null) {
|
||||||
|
setResultLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
allData.then((data) => {
|
allData.then((data) => {
|
||||||
var total = 0
|
var total = 0
|
||||||
@@ -239,15 +263,16 @@ const AppStats = (defaultprops) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statistics["daily_statistics"] === undefined || statistics["daily_statistics"] === null) {
|
const statKey = syncStats === true ? "onprem_stats" : "daily_statistics"
|
||||||
|
if (statistics[statKey] === undefined || statistics[statKey] === null) {
|
||||||
setFilteredStatistics(statistics)
|
setFilteredStatistics(statistics)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate month to date cost
|
// Calculate month to date cost
|
||||||
var mtd_cost = 0
|
var mtd_cost = 0
|
||||||
for (let key in statistics["daily_statistics"]) {
|
for (let key in statistics[statKey]) {
|
||||||
const item = statistics["daily_statistics"][key]
|
const item = statistics[statKey][key]
|
||||||
if (item["date"] === undefined) {
|
if (item["date"] === undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -305,8 +330,8 @@ const AppStats = (defaultprops) => {
|
|||||||
|
|
||||||
// Check if start time is before the daily statistics["date"] string
|
// Check if start time is before the daily statistics["date"] string
|
||||||
var newlist = []
|
var newlist = []
|
||||||
for (let key in statistics["daily_statistics"]) {
|
for (let key in statistics[statKey]) {
|
||||||
const item = statistics["daily_statistics"][key]
|
const item = statistics[statKey][key]
|
||||||
if (item["date"] === undefined) {
|
if (item["date"] === undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -337,7 +362,7 @@ const AppStats = (defaultprops) => {
|
|||||||
var appexecutions = 0
|
var appexecutions = 0
|
||||||
var estimatedcost = 0
|
var estimatedcost = 0
|
||||||
if (newlist.length > 0) {
|
if (newlist.length > 0) {
|
||||||
tmpstats["daily_statistics"] = newlist
|
tmpstats[statKey] = newlist
|
||||||
|
|
||||||
for (let key in newlist) {
|
for (let key in newlist) {
|
||||||
const item = newlist[key]
|
const item = newlist[key]
|
||||||
@@ -391,7 +416,8 @@ const AppStats = (defaultprops) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dailyStats = inputdata.daily_statistics
|
const statKey = syncStats === true ? "onprem_stats" : "daily_statistics"
|
||||||
|
const dailyStats = inputdata[statKey]
|
||||||
if (dailyStats === undefined || dailyStats === null) {
|
if (dailyStats === undefined || dailyStats === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -401,6 +427,11 @@ const AppStats = (defaultprops) => {
|
|||||||
"data": []
|
"data": []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var childorgappRuns = {
|
||||||
|
"key": "Child Org App Runs",
|
||||||
|
"data": []
|
||||||
|
}
|
||||||
|
|
||||||
var workflowRuns = {
|
var workflowRuns = {
|
||||||
"key": "Workflow Runs (includes subflows)",
|
"key": "Workflow Runs (includes subflows)",
|
||||||
"data": []
|
"data": []
|
||||||
@@ -442,6 +473,13 @@ const AppStats = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item["child_app_executions"] !== undefined && item["child_app_executions"] !== null) {
|
||||||
|
childorgappRuns["data"].push({
|
||||||
|
key: new Date(item["date"]),
|
||||||
|
data: inputdata["child_app_executions"]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Check if workflow_executions key in item
|
// Check if workflow_executions key in item
|
||||||
if (item["workflow_executions"] !== undefined && item["workflow_executions"] !== null) {
|
if (item["workflow_executions"] !== undefined && item["workflow_executions"] !== null) {
|
||||||
workflowRuns["data"].push({
|
workflowRuns["data"].push({
|
||||||
@@ -471,6 +509,15 @@ const AppStats = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputdata["daily_child_app_executions"] !== undefined && inputdata["daily_app_executions"] !== null) {
|
||||||
|
childorgappRuns["data"].push({
|
||||||
|
key: new Date(),
|
||||||
|
data: inputdata["daily_child_app_executions"]
|
||||||
|
})
|
||||||
|
|
||||||
|
//setApprunCosts(appcostRuns)
|
||||||
|
}
|
||||||
|
|
||||||
if (inputdata["daily_workflow_executions"] !== undefined && inputdata["daily_workflow_executions"] !== null) {
|
if (inputdata["daily_workflow_executions"] !== undefined && inputdata["daily_workflow_executions"] !== null) {
|
||||||
workflowRuns["data"].push({
|
workflowRuns["data"].push({
|
||||||
key: new Date(),
|
key: new Date(),
|
||||||
@@ -485,6 +532,11 @@ const AppStats = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for parent orgs
|
||||||
|
if (childorgappRuns["data"].length > 0) {
|
||||||
|
setChildOrgsAppRuns(childorgappRuns)
|
||||||
|
}
|
||||||
|
|
||||||
setSubflowRuns(subflowRuns)
|
setSubflowRuns(subflowRuns)
|
||||||
setWorkflowRuns(workflowRuns)
|
setWorkflowRuns(workflowRuns)
|
||||||
setAppruns(appRuns)
|
setAppruns(appRuns)
|
||||||
@@ -659,44 +711,57 @@ const AppStats = (defaultprops) => {
|
|||||||
style={{ textDecoration: "none", color: theme.palette.linkColor,}}
|
style={{ textDecoration: "none", color: theme.palette.linkColor,}}
|
||||||
>Your Organisation Statistics. </a>
|
>Your Organisation Statistics. </a>
|
||||||
It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
|
It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
|
||||||
|
|
||||||
|
<br style={{}}/>
|
||||||
|
{syncStats !== true ? null :
|
||||||
|
"PS: You are currently looking at data from your onprem synced org"}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<div style={{display: "flex", flexDirection: "column", textAlign: "center",}}>
|
<div style={{display: "flex", flexDirection: "column", textAlign: "center",}}>
|
||||||
<div style={{flexDirection: "row", }}>
|
<div style={{flexDirection: "row", }}>
|
||||||
{filteredStatistics !== undefined ?
|
{filteredStatistics !== undefined ?
|
||||||
<div style={{flex: 1, display: "flex", textAlign: "center",}}>
|
<div style={{flex: 1, display: "flex", textAlign: "center",}}>
|
||||||
<Tooltip title={
|
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
{syncStats == true ? null :
|
||||||
The cost of app runs in the selected period based on {filteredStatistics.monthly_app_executions} App Runs. These numbers do not exclude your included 10.000/month or {includedExecutions} App Runs per month. App Run cost: ${invocationCost}.
|
<Tooltip title={
|
||||||
</Typography>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
}>
|
The cost of app runs in the selected period based on {filteredStatistics.monthly_app_executions} App Runs. These numbers do not exclude your included 10.000/month or {includedExecutions} App Runs per month. App Run cost: ${invocationCost}.
|
||||||
<Box sx={paperStyle}>
|
|
||||||
<Typography variant="h4">
|
|
||||||
${selectedOrganization?.lead_info?.customer === false && selectedOrganization?.lead_info?.pov === false ?
|
|
||||||
0
|
|
||||||
:
|
|
||||||
apprunCost
|
|
||||||
}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
}>
|
||||||
Period Cost
|
<Box sx={paperStyle}>
|
||||||
</Typography>
|
<Typography variant="h4">
|
||||||
</Box>
|
${selectedOrganization?.lead_info?.customer === false && selectedOrganization?.lead_info?.pov === false ?
|
||||||
</Tooltip>
|
0
|
||||||
|
:
|
||||||
|
apprunCost
|
||||||
|
}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="h6">
|
||||||
|
Period Cost
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
|
{syncStats === true ? null :
|
||||||
<Tooltip title={
|
<Tooltip title={
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
App runs in the selected period
|
App runs in the selected period
|
||||||
</Typography>
|
</Typography>
|
||||||
}>
|
}>
|
||||||
<Box sx={paperStyle}>
|
<Box sx={paperStyle}>
|
||||||
<Typography variant="h4">
|
<Typography variant="h4">
|
||||||
{filteredStatistics.monthly_app_executions === null || filteredStatistics.monthly_app_executions === undefined ? 0 : filteredStatistics.monthly_app_executions}
|
{filteredStatistics.monthly_app_executions === null || filteredStatistics.monthly_app_executions === undefined ? 0 : filteredStatistics.monthly_app_executions}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
App Runs
|
App Runs
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
|
{syncStats === true ? null :
|
||||||
<Tooltip title={
|
<Tooltip title={
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
Workflow runs in the selected period
|
Workflow runs in the selected period
|
||||||
@@ -711,20 +776,24 @@ const AppStats = (defaultprops) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={
|
}
|
||||||
<Typography variant="body1" style={{padding: 10, }}>
|
|
||||||
Estimated cost to be billed at the end of the current month. Subtracted contractually included app runs. Actual cost month to date: ${monthToDateCost}. App Run cost: ${invocationCost}.
|
{syncStats === true ? null :
|
||||||
</Typography>
|
<Tooltip title={
|
||||||
}>
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
<Box sx={paperStyle}>
|
Estimated cost to be billed at the end of the current month. Subtracted contractually included app runs. Actual cost month to date: ${monthToDateCost}. App Run cost: ${invocationCost}.
|
||||||
<Typography variant="h4">
|
|
||||||
${monthTotalCost}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6">
|
}>
|
||||||
Estimated cost
|
<Box sx={paperStyle}>
|
||||||
</Typography>
|
<Typography variant="h4">
|
||||||
</Box>
|
${monthTotalCost}
|
||||||
</Tooltip>
|
</Typography>
|
||||||
|
<Typography variant="h6">
|
||||||
|
Estimated cost
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
@@ -895,7 +964,13 @@ const AppStats = (defaultprops) => {
|
|||||||
{appRuns === undefined ?
|
{appRuns === undefined ?
|
||||||
null
|
null
|
||||||
:
|
:
|
||||||
<LineChartWrapper keys={appRuns} height={300} width={"100%"} inputname={"Daily App Runs"}/>
|
<LineChartWrapper keys={appRuns} height={300} width={"100%"} inputname={"App Runs - Current Org"}/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{childOrgsAppRuns === undefined ?
|
||||||
|
null
|
||||||
|
:
|
||||||
|
<LineChartWrapper keys={childOrgsAppRuns} height={300} width={"100%"} inputname={"Child Org App Runs"}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
{workflowRuns === undefined ?
|
{workflowRuns === undefined ?
|
||||||
@@ -916,56 +991,58 @@ const AppStats = (defaultprops) => {
|
|||||||
<LineChartWrapper keys={appRunCosts} height={300} width={"100%"} inputname={"Apprun cost - Cost per day"}/>
|
<LineChartWrapper keys={appRunCosts} height={300} width={"100%"} inputname={"Apprun cost - Cost per day"}/>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
|
{syncStats === true ? null :
|
||||||
|
<div style={{height: 150+resultRows.length * 25, padding: "10px 0px 10px 0px", }}>
|
||||||
|
{resultLoading ?
|
||||||
|
<div style={{margin: "auto", alignItems: "center", width: 350, height: "100%", }}>
|
||||||
|
<Typography variant="body2" color="textSecondary" component="p" style={{textAlign: "center", marginTop: 50, marginBottom: 15, }}>
|
||||||
|
Loading usage for selected period (may take a while)
|
||||||
|
|
||||||
|
<CircularProgress style={{marginTop: 15, }} />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<DataGrid
|
||||||
|
rows={resultRows}
|
||||||
|
columns={columns}
|
||||||
|
pageSize={100}
|
||||||
|
rowsPerPageOptions={[10, 20, 50, 100]}
|
||||||
|
checkboxSelection
|
||||||
|
disableSelectionOnClick
|
||||||
|
onPageSizeChange={(newPageSize) => {
|
||||||
|
//setRowsPerPage(newPageSize)
|
||||||
|
//submitSearch(workflowId, status, startTime, endTime, rowCursor, newPageSize)
|
||||||
|
}}
|
||||||
|
// event for when clicking next page
|
||||||
|
// Hide page changer
|
||||||
|
onPageChange={(params) => {
|
||||||
|
console.log("page params: ", params)
|
||||||
|
}}
|
||||||
|
onSelectionModelChange={(newSelection) => {
|
||||||
|
console.log("newSelection: ", newSelection)
|
||||||
|
//console.log("newSelection: ", newSelection)
|
||||||
|
//setSelectedWorkflowExecutionsIndexes(newSelection)
|
||||||
|
//var found = []
|
||||||
|
//for (var i = 0; i < newSelection.length; i++) {
|
||||||
|
// // Find the workflow in the resultRows
|
||||||
|
// var selected = resultRows.find((workflow) => {
|
||||||
|
// return workflow.id === newSelection[i]
|
||||||
|
// })
|
||||||
|
|
||||||
<div style={{height: 150+resultRows.length * 25, padding: "10px 0px 10px 0px", }}>
|
// if (selected === undefined || selected === null) {
|
||||||
{resultLoading ?
|
// continue
|
||||||
<div style={{margin: "auto", alignItems: "center", width: 350, height: "100%", }}>
|
// }
|
||||||
<Typography variant="body2" color="textSecondary" component="p" style={{textAlign: "center", marginTop: 50, marginBottom: 15, }}>
|
|
||||||
Loading usage for selected period (may take a while)
|
|
||||||
</Typography>
|
|
||||||
<CircularProgress style={{}} />
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<DataGrid
|
|
||||||
rows={resultRows}
|
|
||||||
columns={columns}
|
|
||||||
pageSize={100}
|
|
||||||
rowsPerPageOptions={[10, 20, 50, 100]}
|
|
||||||
checkboxSelection
|
|
||||||
disableSelectionOnClick
|
|
||||||
onPageSizeChange={(newPageSize) => {
|
|
||||||
//setRowsPerPage(newPageSize)
|
|
||||||
//submitSearch(workflowId, status, startTime, endTime, rowCursor, newPageSize)
|
|
||||||
}}
|
|
||||||
// event for when clicking next page
|
|
||||||
// Hide page changer
|
|
||||||
onPageChange={(params) => {
|
|
||||||
console.log("page params: ", params)
|
|
||||||
}}
|
|
||||||
onSelectionModelChange={(newSelection) => {
|
|
||||||
console.log("newSelection: ", newSelection)
|
|
||||||
//console.log("newSelection: ", newSelection)
|
|
||||||
//setSelectedWorkflowExecutionsIndexes(newSelection)
|
|
||||||
//var found = []
|
|
||||||
//for (var i = 0; i < newSelection.length; i++) {
|
|
||||||
// // Find the workflow in the resultRows
|
|
||||||
// var selected = resultRows.find((workflow) => {
|
|
||||||
// return workflow.id === newSelection[i]
|
|
||||||
// })
|
|
||||||
|
|
||||||
// if (selected === undefined || selected === null) {
|
// found.push(selected)
|
||||||
// continue
|
//}
|
||||||
// }
|
|
||||||
|
|
||||||
// found.push(selected)
|
//setSelectedWorkflowExecutions(found)
|
||||||
//}
|
}}
|
||||||
|
// Track which items are selected
|
||||||
//setSelectedWorkflowExecutions(found)
|
/>
|
||||||
}}
|
}
|
||||||
// Track which items are selected
|
</div>
|
||||||
/>
|
}
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const Branding = (props) => {
|
|||||||
const theme = getTheme(themeMode, brandColor)
|
const theme = getTheme(themeMode, brandColor)
|
||||||
const [selectedBrandColor, setSelectedBrandColor] = useState(theme?.palette?.main || "#FF8544")
|
const [selectedBrandColor, setSelectedBrandColor] = useState(theme?.palette?.main || "#FF8544")
|
||||||
const [selectedBrandName, setSelectedBrandName] = useState(selectedOrganization?.branding?.brand_name || "")
|
const [selectedBrandName, setSelectedBrandName] = useState(selectedOrganization?.branding?.brand_name || "")
|
||||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
|
||||||
const [isLoading,setIsLoading] = useState(false);
|
const [isLoading,setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleEditOrg = (joinStatus) => {
|
const handleEditOrg = (joinStatus) => {
|
||||||
@@ -391,7 +391,7 @@ const Branding = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{ integrationPartner ? (
|
{integrationPartner ? (
|
||||||
<>
|
<>
|
||||||
<Divider style={{marginTop: 50, marginBottom: 50, color: theme.palette.defaultBorder}} />
|
<Divider style={{marginTop: 50, marginBottom: 50, color: theme.palette.defaultBorder}} />
|
||||||
<Typography style={{fontSize: 24, fontWeight: "bold"}}>
|
<Typography style={{fontSize: 24, fontWeight: "bold"}}>
|
||||||
|
|||||||
@@ -867,7 +867,7 @@ const CacheView = memo((props) => {
|
|||||||
overflowX: "auto",
|
overflowX: "auto",
|
||||||
}}>
|
}}>
|
||||||
<ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore? theme.palette.defaultBorder :null, display: "table-row"}}>
|
<ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore? theme.palette.defaultBorder :null, display: "table-row"}}>
|
||||||
{["Key", "Value", "Actions", "Updated", "Distribution"].map((header, index) => (
|
{["Key", "Value", "workflow", "Actions", "Updated", "Distribution"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
key={index}
|
key={index}
|
||||||
primary={header}
|
primary={header}
|
||||||
@@ -891,7 +891,7 @@ const CacheView = memo((props) => {
|
|||||||
backgroundColor: theme.palette.platformColor,
|
backgroundColor: theme.palette.platformColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array(5)
|
{Array(6)
|
||||||
.fill()
|
.fill()
|
||||||
.map((_, colIndex) => (
|
.map((_, colIndex) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
@@ -1001,6 +1001,66 @@ const CacheView = memo((props) => {
|
|||||||
data.value
|
data.value
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary={
|
||||||
|
data.workflow_id === "" || data.workflow_id === null || data.workflow_id === undefined ?
|
||||||
|
<IconButton
|
||||||
|
disabled={data.workflow_id?.length === 0}
|
||||||
|
style={{marginLeft: 10}}
|
||||||
|
>
|
||||||
|
<OpenInNewIcon
|
||||||
|
style={{
|
||||||
|
color:
|
||||||
|
data.workflow_id?.length !== 0
|
||||||
|
? "#FF8444"
|
||||||
|
: "grey",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
: (
|
||||||
|
<Tooltip
|
||||||
|
title={"Go to workflow"}
|
||||||
|
style={{}}
|
||||||
|
aria-label={"Download"}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<a
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{
|
||||||
|
textDecoration: "none",
|
||||||
|
color: "#f85a3e",
|
||||||
|
}}
|
||||||
|
href={`/workflows/${data.workflow_id}`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
disabled={data.workflow_id?.length ===0}
|
||||||
|
style={{marginLeft: 10}}
|
||||||
|
>
|
||||||
|
<OpenInNewIcon
|
||||||
|
style={{
|
||||||
|
width: 24, height: 24,
|
||||||
|
color:
|
||||||
|
data.workflow_id?.length !== 0
|
||||||
|
? "#FF8444"
|
||||||
|
: "grey",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
display: "table-cell",
|
||||||
|
overflow: "hidden",
|
||||||
|
verticalAlign: "middle",
|
||||||
|
padding: "8px 8px 8px 15px",
|
||||||
|
maxWidth: 200,
|
||||||
|
overflowX: "auto",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
style={{
|
style={{
|
||||||
display: "table-cell",
|
display: "table-cell",
|
||||||
|
|||||||
@@ -48,15 +48,21 @@ const CloudSyncTab = (props) => {
|
|||||||
const [, forceUpdate] = React.useState();
|
const [, forceUpdate] = React.useState();
|
||||||
const itemColor = "white";
|
const itemColor = "white";
|
||||||
const isCloud = window?.location?.host === "localhost:3002" || window?.location?.host === "shuffler.io";
|
const isCloud = window?.location?.host === "localhost:3002" || window?.location?.host === "shuffler.io";
|
||||||
|
|
||||||
const { themeMode, brandColor } = useContext(Context);
|
const { themeMode, brandColor } = useContext(Context);
|
||||||
const theme = getTheme(themeMode, brandColor);
|
const theme = getTheme(themeMode, brandColor);
|
||||||
|
|
||||||
useEffect(() => { getSettings(); }, []);
|
useEffect(() => { getSettings(); }, []);
|
||||||
|
|
||||||
const GridItem = (props) => {
|
const GridItem = (props) => {
|
||||||
const [expanded, setExpanded] = React.useState(false);
|
const [expanded, setExpanded] = React.useState(false);
|
||||||
const [showEdit, setShowEdit] = React.useState(false);
|
const [showEdit, setShowEdit] = React.useState(false);
|
||||||
const [newValue, setNewValue] = React.useState(-100);
|
const [newValue, setNewValue] = React.useState(-100);
|
||||||
|
|
||||||
const primary = props.data.primary;
|
var primary = props.data.primary
|
||||||
|
|
||||||
|
const shownName = props.data.newname !== undefined && props.data.newname !== null && props.data.newname !== primary ? props.data.newname : primary
|
||||||
|
|
||||||
const secondary = props.data.secondary;
|
const secondary = props.data.secondary;
|
||||||
const primaryIcon = props.data.icon;
|
const primaryIcon = props.data.icon;
|
||||||
const secondaryIcon = props.data.active ?
|
const secondaryIcon = props.data.active ?
|
||||||
@@ -191,7 +197,7 @@ const CloudSyncTab = (props) => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
style={{ textTransform: "capitalize", color: theme.palette.text.primary, fontSize: 14, fontWeight: 400, }}
|
style={{ textTransform: "capitalize", color: theme.palette.text.primary, fontSize: 14, fontWeight: 400, }}
|
||||||
primary={primary}
|
primary={shownName}
|
||||||
/>
|
/>
|
||||||
{isCloud && userdata.support === true ?
|
{isCloud && userdata.support === true ?
|
||||||
<Tooltip title="Edit features (support users only)">
|
<Tooltip title="Edit features (support users only)">
|
||||||
@@ -477,7 +483,7 @@ const CloudSyncTab = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
toast("Cloud Syncronization successfully set up!");
|
toast("Cloud Syncronization successfully set up!");
|
||||||
setOrgSyncResponse(
|
setOrgSyncResponse(
|
||||||
"Successfully started syncronization. Cloud features you now have access to can be seen below."
|
"Successfully started syncronization. Cloud/Hybrid features are available below."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,8 +541,8 @@ const CloudSyncTab = (props) => {
|
|||||||
Cloud syncronization
|
Cloud syncronization
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" style={{ color: theme.palette.text.secondary, fontSize: 16, fontWeight: 400, }}>
|
<Typography variant="body2" style={{ color: theme.palette.text.secondary, fontSize: 16, fontWeight: 400, }}>
|
||||||
What does <a href="/docs/organizations#cloud_sync" target="_blank" rel="noopener noreferrer" style={{ color: theme.palette.linkColor, fontSize: 16, textDecoration: 'none', }}>cloud sync</a> do? Cloud synchronization is a way of getting more out of Shuffle. Shuffle will ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach.
|
What does <a href="/docs/organizations#cloud_sync" target="_blank" rel="noopener noreferrer" style={{ color: theme.palette.linkColor, fontSize: 16, textDecoration: 'none', }}>cloud sync</a> do? Cloud synchronization is a way of getting more out of Shuffle. Shuffle will ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach. This will by default back up apps and workflows.
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isCloud ? (
|
{isCloud ? (
|
||||||
@@ -708,7 +714,7 @@ const CloudSyncTab = (props) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Typography variant="h5" style={{ marginLeft: 5, marginTop: 40, marginBottom: 5 }}>
|
<Typography variant="h5" style={{ marginLeft: 5, marginTop: 40, marginBottom: 5 }}>
|
||||||
Features
|
{isCloud ? "Cloud" : "Hybrid"} Features
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 24, fontSize: 16, fontWeight: 400, marginLeft: 5, color: theme.palette.text.secondary }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 24, fontSize: 16, fontWeight: 400, marginLeft: 5, color: theme.palette.text.secondary }}>
|
||||||
Features and Limitations that are currently available to you in your Cloud or Hybrid Organization. App Executions (App Runs) reset monthly. If the organization is a customer or in a trial, these features limitations are not always enforced. </Typography>
|
Features and Limitations that are currently available to you in your Cloud or Hybrid Organization. App Executions (App Runs) reset monthly. If the organization is a customer or in a trial, these features limitations are not always enforced. </Typography>
|
||||||
@@ -717,7 +723,9 @@ const CloudSyncTab = (props) => {
|
|||||||
{selectedOrganization.sync_features === undefined ||
|
{selectedOrganization.sync_features === undefined ||
|
||||||
selectedOrganization.sync_features === null
|
selectedOrganization.sync_features === null
|
||||||
? <Grid container spacing={2} justifyContent="center">
|
? <Grid container spacing={2} justifyContent="center">
|
||||||
|
|
||||||
{[...Array(18)].map((_, i) => (
|
{[...Array(18)].map((_, i) => (
|
||||||
|
|
||||||
<Grid item xs={12} sm={6} md={4} key={i}>
|
<Grid item xs={12} sm={6} md={4} key={i}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -756,6 +764,13 @@ const CloudSyncTab = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newkey = key.replaceAll("_", " ");
|
const newkey = key.replaceAll("_", " ");
|
||||||
|
|
||||||
|
// Rewrites to frontend names
|
||||||
|
var newname = newkey
|
||||||
|
if (newkey === "app executions") {
|
||||||
|
newname = "app runs"
|
||||||
|
}
|
||||||
|
|
||||||
const griditem = {
|
const griditem = {
|
||||||
primary: newkey,
|
primary: newkey,
|
||||||
secondary:
|
secondary:
|
||||||
@@ -770,6 +785,8 @@ const CloudSyncTab = (props) => {
|
|||||||
data_collection: "None",
|
data_collection: "None",
|
||||||
active: item.active,
|
active: item.active,
|
||||||
icon: <PolylineIcon style={{ color: "#1a1a1a" }} />,
|
icon: <PolylineIcon style={{ color: "#1a1a1a" }} />,
|
||||||
|
|
||||||
|
newname: newname,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
if (aa !== undefined) {
|
if (aa !== undefined) {
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
})
|
})
|
||||||
|
|
||||||
const timestamp = new Date().getTime()
|
const timestamp = new Date().getTime()
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import {
|
|||||||
AvatarGroup,
|
AvatarGroup,
|
||||||
} from "@mui/material"
|
} from "@mui/material"
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const CreatorGrid = props => {
|
const CreatorGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, isHeader } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, isHeader } = props
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const DocsGrid = props => {
|
const DocsGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, } = props
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ const EditWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newWorkflow = isEditing === true ? false : true
|
const newWorkflow = isEditing === true ? false : true
|
||||||
const priority = userdata === undefined || userdata === null ? null : userdata.priorities.find(prio => prio.type === "usecase" && prio.active === true)
|
const priority = userdata === undefined || userdata === null || userdata.priorities === null || userdata.priorities === undefined ? null : userdata?.priorities?.find(prio => prio.type === "usecase" && prio.active === true)
|
||||||
var upload = "";
|
var upload = "";
|
||||||
var total_count = 0
|
var total_count = 0
|
||||||
|
|
||||||
@@ -226,8 +226,8 @@ const EditWorkflow = (props) => {
|
|||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<div style={{ flex: 1, color: theme.palette.textColor }}>
|
<div style={{ flex: 1, color: theme.palette.textColor }}>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<Typography variant="h4" style={{ flex: 9, }}>
|
<Typography variant="h4" style={{ flex: 9, marginTop: 25, }}>
|
||||||
{newWorkflow ? "New" : "Editing"} workflow
|
{newWorkflow ? "New" : "Editing"} Workflow
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{newWorkflow === true ? null :
|
{newWorkflow === true ? null :
|
||||||
@@ -393,7 +393,7 @@ const EditWorkflow = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogContent style={{ paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 200, paddingLeft: "50px" }}>
|
<DialogContent style={{ paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 400, paddingLeft: 50, }}>
|
||||||
<div style={{ minWidth: newWorkflow ? 500 : 550, maxWidth: newWorkflow ? 450 : 500, }}>
|
<div style={{ minWidth: newWorkflow ? 500 : 550, maxWidth: newWorkflow ? 450 : 500, }}>
|
||||||
<TextField
|
<TextField
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
|
|||||||
@@ -403,7 +403,6 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
|
|
||||||
const handleChangeTheme = (newTheme) => {
|
const handleChangeTheme = (newTheme) => {
|
||||||
|
|
||||||
toast.info("Changing theme to " + newTheme + " - please wait!");
|
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
"org_id": userdata?.active_org?.id,
|
"org_id": userdata?.active_org?.id,
|
||||||
@@ -449,8 +448,11 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleUpdateTheme = (newTheme) => {
|
const handleUpdateTheme = (newTheme) => {
|
||||||
|
handleThemeChange(newTheme);
|
||||||
|
setCurrentSelectedTheme(newTheme)
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
"user_id": userdata?.id,
|
"user_id": userdata?.id,
|
||||||
"theme": newTheme,
|
"theme": newTheme,
|
||||||
@@ -470,14 +472,11 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
}).then((response) =>
|
}).then((response) =>
|
||||||
response.json().then((responseJson) => {
|
response.json().then((responseJson) => {
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
toast("Failed updating theme: ", responseJson.reason);
|
toast("Failed saving your theme: ", responseJson.reason);
|
||||||
} else {
|
|
||||||
handleThemeChange(newTheme);
|
|
||||||
setCurrentSelectedTheme(newTheme);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
).catch((error) => {
|
).catch((error) => {
|
||||||
console.log("Error changing theme: ", error);
|
console.log("Error saving your theme: ", error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -518,6 +517,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
console.error("Logout error:", error);
|
console.error("Logout error:", error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const avatarMenu = (
|
const avatarMenu = (
|
||||||
<span>
|
<span>
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -588,7 +588,8 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
}
|
}
|
||||||
if (userdata?.org_status?.includes("integration_partner")){
|
if (userdata?.org_status?.includes("integration_partner")){
|
||||||
handleChangeTheme(newTheme);
|
handleChangeTheme(newTheme);
|
||||||
}else {
|
} else {
|
||||||
|
|
||||||
handleUpdateTheme(newTheme);
|
handleUpdateTheme(newTheme);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -646,7 +647,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
|
|
||||||
<Divider style={{ marginTop: 10, marginBottom: 10, }} />
|
<Divider style={{ marginTop: 10, marginBottom: 10, }} />
|
||||||
|
|
||||||
<Link to="/docs" style={hrefStyle}>
|
<Link to={userdata && userdata?.org_status?.includes("integration_partner") && userdata?.active_org?.branding?.documentation_link?.length > 0 ? userdata?.active_org?.branding?.documentation_link : "/docs" } target={userdata?.active_org?.branding?.documentation_link?.length > 0 && userdata?.org_status?.includes("integration_partner") ? "_blank" : "_self" } style={hrefStyle}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
handleClose();
|
handleClose();
|
||||||
@@ -670,7 +671,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
<Divider style={{ marginBottom: 10, }} />
|
<Divider style={{ marginBottom: 10, }} />
|
||||||
|
|
||||||
<Typography color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, fontSize: 18 }}>
|
<Typography color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, fontSize: 18 }}>
|
||||||
Version: 2.0.2
|
Version: 2.1.0-rc1
|
||||||
</Typography>
|
</Typography>
|
||||||
</Menu>
|
</Menu>
|
||||||
</span>
|
</span>
|
||||||
@@ -1632,7 +1633,8 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
component={Link}
|
component={Link}
|
||||||
to="/docs"
|
to={userdata?.org_status?.includes("integration_partner") && userdata?.active_org?.branding?.documentation_link?.length > 0 ? userdata?.active_org?.branding?.documentation_link : "/docs"}
|
||||||
|
target={userdata?.org_status?.includes("integration_partner") && userdata?.active_org?.branding?.documentation_link?.length > 0 ? "_blank" : "_self"}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setCurrentOpenTab("docs");
|
setCurrentOpenTab("docs");
|
||||||
localStorage.setItem("lastTabOpenByUser", "docs");
|
localStorage.setItem("lastTabOpenByUser", "docs");
|
||||||
@@ -1683,7 +1685,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
component={Link}
|
component={Link}
|
||||||
to={isCloud ? "/admin?admin_tab=billingstats" : "/admin?admin_tab=locations"}
|
to={isCloud ? "/admin" : "/admin"}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setCurrentOpenTab("admin");
|
setCurrentOpenTab("admin");
|
||||||
localStorage.setItem("lastTabOpenByUser", "admin");
|
localStorage.setItem("lastTabOpenByUser", "admin");
|
||||||
@@ -2105,4 +2107,4 @@ const ModalView = memo(({searchBarModalOpen, setSearchBarModalOpen, globalUrl, s
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1127,7 +1127,6 @@ const LicencePopup = (props) => {
|
|||||||
color: "white",
|
color: "white",
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Priceitem: ", shuffleVariant)
|
|
||||||
// const isLoggedInHandler = () => {
|
// const isLoggedInHandler = () => {
|
||||||
// if (calculatedCost === payasyougo) {
|
// if (calculatedCost === payasyougo) {
|
||||||
// handlePayasyougo(props.userdata)
|
// handlePayasyougo(props.userdata)
|
||||||
@@ -1237,12 +1236,11 @@ const LicencePopup = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("Selected Organization: ", selectedOrganization.subscriptions)
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Grid container spacing={2} style={{ flexDirection: "row", flexWrap: "nowrap", borderRadius: '16px', display: "flex"}}>
|
<Grid container spacing={2} style={{ flexDirection: "row", flexWrap: "nowrap", borderRadius: '16px', display: "flex"}}>
|
||||||
<Grid item maxWidth={licensePopup ? 400 : 450}>
|
<Grid item maxWidth={licensePopup ? 400 : 450}>
|
||||||
{selectedOrganization.subscriptions === undefined || selectedOrganization.subscriptions === null || selectedOrganization.subscriptions.length === 0 ?
|
{(selectedOrganization.subscriptions === undefined || selectedOrganization.subscriptions === null || selectedOrganization.subscriptions.length === 0) && isCloud ?
|
||||||
<SubscriptionObject
|
<SubscriptionObject
|
||||||
index={0}
|
index={0}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
|
|||||||
@@ -1216,7 +1216,7 @@ const ParsedAction = (props) => {
|
|||||||
selectedActionParameters[1].value = splitparsed[1]
|
selectedActionParameters[1].value = splitparsed[1]
|
||||||
selectedAction.parameters[1].value = splitparsed[1]
|
selectedAction.parameters[1].value = splitparsed[1]
|
||||||
|
|
||||||
if (splitparsed.length > 2) {
|
if (splitparsed.length >= 2) {
|
||||||
toast.warn("Filter list only supports filtering on the first list. If you want multi-level filtering, please use the 'execute python' action with the 'filter a list' function in the code editor.", {
|
toast.warn("Filter list only supports filtering on the first list. If you want multi-level filtering, please use the 'execute python' action with the 'filter a list' function in the code editor.", {
|
||||||
autoClose: 10000,
|
autoClose: 10000,
|
||||||
})
|
})
|
||||||
@@ -1494,7 +1494,7 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
// Helpertext for openapi fields
|
// Helpertext for openapi fields
|
||||||
//if (helperText === "" && name === "body" && selectedApp.generated && selectedApp.activated) {
|
//if (helperText === "" && name === "body" && selectedApp.generated && selectedApp.activated) {
|
||||||
// helperText = <span style={{color: "white", marginBottom: 5, marginleft: 5}}>
|
// helperText = <span style={{color: theme.palette.text.primary, marginBottom: 5, marginleft: 5}}>
|
||||||
//}
|
//}
|
||||||
|
|
||||||
return helperText
|
return helperText
|
||||||
@@ -1563,7 +1563,7 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <Paper style={{ padding: 10, backgroundColor: theme.palette.surfaceColor, border: "1px solid red", }}>
|
return <Paper style={{ padding: 10, backgroundColor: theme.palette.surfaceColor, border: "1px solid red", }}>
|
||||||
<Typography variant="body" style={{ color: "white", }}>
|
<Typography variant="body" style={{ color: theme.palette.text.primary, }}>
|
||||||
<b>Tip:</b> {suggestionText}
|
<b>Tip:</b> {suggestionText}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
@@ -2606,7 +2606,7 @@ const ParsedAction = (props) => {
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
height: "50px",
|
height: "50px",
|
||||||
borderRadius: theme.palette?.borderRadius,
|
borderRadius: theme.palette?.borderRadius,
|
||||||
}}
|
}}
|
||||||
@@ -2623,7 +2623,7 @@ const ParsedAction = (props) => {
|
|||||||
key={data.Name}
|
key={data.Name}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
value={data.Name}
|
value={data.Name}
|
||||||
>
|
>
|
||||||
@@ -2702,7 +2702,7 @@ const ParsedAction = (props) => {
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
height: "50px",
|
height: "50px",
|
||||||
borderRadius: theme.palette?.borderRadius,
|
borderRadius: theme.palette?.borderRadius,
|
||||||
}}
|
}}
|
||||||
@@ -2710,7 +2710,7 @@ const ParsedAction = (props) => {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
value="No selection"
|
value="No selection"
|
||||||
>
|
>
|
||||||
@@ -2721,7 +2721,7 @@ const ParsedAction = (props) => {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
value={data.name}
|
value={data.name}
|
||||||
>
|
>
|
||||||
@@ -2986,7 +2986,7 @@ const ParsedAction = (props) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginTop: "10px",
|
marginTop: "10px",
|
||||||
borderColor: "white",
|
borderColor: theme.palette.text.primary,
|
||||||
borderWidth: "2px",
|
borderWidth: "2px",
|
||||||
marginBottom: hideExtraTypes ? 50 : 200,
|
marginBottom: hideExtraTypes ? 50 : 200,
|
||||||
}}
|
}}
|
||||||
@@ -3182,7 +3182,7 @@ const ParsedAction = (props) => {
|
|||||||
ListboxProps={{
|
ListboxProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(option) => {
|
getOptionLabel={(option) => {
|
||||||
@@ -4422,7 +4422,7 @@ const ParsedAction = (props) => {
|
|||||||
}}
|
}}
|
||||||
open={!!menuPosition}
|
open={!!menuPosition}
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
maxHeight: 650,
|
maxHeight: 650,
|
||||||
}}
|
}}
|
||||||
@@ -4550,7 +4550,7 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
parentMenuOpen={!!menuPosition}
|
parentMenuOpen={!!menuPosition}
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
minWidth: 250,
|
minWidth: 250,
|
||||||
maxWidth: 250,
|
maxWidth: 250,
|
||||||
maxHeight: 50,
|
maxHeight: 50,
|
||||||
@@ -4566,7 +4566,7 @@ const ParsedAction = (props) => {
|
|||||||
key={innerdata.name}
|
key={innerdata.name}
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 15,
|
marginLeft: 15,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
minWidth: 250,
|
minWidth: 250,
|
||||||
maxWidth: 250,
|
maxWidth: 250,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
@@ -4607,7 +4607,7 @@ const ParsedAction = (props) => {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
key={pathdata.name}
|
key={pathdata.name}
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
minWidth: 250,
|
minWidth: 250,
|
||||||
maxWidth: 250,
|
maxWidth: 250,
|
||||||
padding: boxPadding,
|
padding: boxPadding,
|
||||||
@@ -4664,7 +4664,7 @@ const ParsedAction = (props) => {
|
|||||||
key={innerdata.name}
|
key={innerdata.name}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
minWidth: 250,
|
minWidth: 250,
|
||||||
maxWidth: 250,
|
maxWidth: 250,
|
||||||
marginRight: 0,
|
marginRight: 0,
|
||||||
@@ -4835,17 +4835,21 @@ const ParsedAction = (props) => {
|
|||||||
<OpenInFullIcon
|
<OpenInFullIcon
|
||||||
style={{ color: theme.palette.textPrimary, cursor: "pointer", margin: multiline ? 5 : 0, height: 20, width: 20, }}
|
style={{ color: theme.palette.textPrimary, cursor: "pointer", margin: multiline ? 5 : 0, height: 20, width: 20, }}
|
||||||
onMouseOver={(event) => {
|
onMouseOver={(event) => {
|
||||||
const clickedField = document.getElementById(clickedFieldId)
|
if(selectedAction?.name !== "filter_list"){
|
||||||
if (clickedField !== null) {
|
const clickedField = document.getElementById(clickedFieldId)
|
||||||
clickedField.focus()
|
if (clickedField !== null) {
|
||||||
|
clickedField.focus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
// Set focus to the Textfield we just clicked
|
// Set focus to the Textfield we just clicked
|
||||||
// This is to ensure focus is set correctly at all times with blur
|
// This is to ensure focus is set correctly at all times with blur
|
||||||
const clickedField = document.getElementById(clickedFieldId)
|
if(selectedAction?.name !== "filter_list"){
|
||||||
if (clickedField !== null) {
|
const clickedField = document.getElementById(clickedFieldId)
|
||||||
clickedField.focus()
|
if (clickedField !== null) {
|
||||||
|
clickedField.focus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@@ -4887,7 +4891,7 @@ const ParsedAction = (props) => {
|
|||||||
<FormControl fullWidth style={{ marginTop: 0 }}>
|
<FormControl fullWidth style={{ marginTop: 0 }}>
|
||||||
<InputLabel
|
<InputLabel
|
||||||
id="action-autocompleter"
|
id="action-autocompleter"
|
||||||
style={{ marginLeft: 10, color: "white" }}
|
style={{ marginLeft: 10, color: theme.palette.text.primary }}
|
||||||
>
|
>
|
||||||
Autocomplete
|
Autocomplete
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
@@ -4915,7 +4919,7 @@ const ParsedAction = (props) => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
open={showAutocomplete}
|
open={showAutocomplete}
|
||||||
style={{
|
style={{
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
height: 35,
|
height: 35,
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
borderRadius: theme.palette?.borderRadius,
|
borderRadius: theme.palette?.borderRadius,
|
||||||
@@ -4954,7 +4958,7 @@ const ParsedAction = (props) => {
|
|||||||
key={data.name}
|
key={data.name}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
color: "white",
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
value={data}
|
value={data}
|
||||||
onMouseOver={() => { }}
|
onMouseOver={() => { }}
|
||||||
|
|||||||
+1793
-647
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ const chipStyle = {
|
|||||||
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
|
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const SearchData = props => {
|
const SearchData = props => {
|
||||||
const { serverside, globalUrl, userdata } = props
|
const { serverside, globalUrl, userdata } = props
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ const CodeEditor = (props) => {
|
|||||||
fieldname,
|
fieldname,
|
||||||
contentLoading,
|
contentLoading,
|
||||||
editorData,
|
editorData,
|
||||||
handleSubflowParamChange,
|
handleTriggerParamChange,
|
||||||
setAiQueryModalOpen,
|
setAiQueryModalOpen,
|
||||||
fullScreenMode,
|
fullScreenMode,
|
||||||
environment,
|
environment,
|
||||||
@@ -212,7 +212,7 @@ const CodeEditor = (props) => {
|
|||||||
const triggerField = searchParams.get('trigger_field');
|
const triggerField = searchParams.get('trigger_field');
|
||||||
const triggerName = searchParams.get('trigger_name');
|
const triggerName = searchParams.get('trigger_name');
|
||||||
const conditionId = searchParams.get('condition_id');
|
const conditionId = searchParams.get('condition_id');
|
||||||
const conditionField = searchParams.get('field');
|
const conditionField = searchParams.get('condition_field');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (actionId === undefined || actionId === null) {
|
if (actionId === undefined || actionId === null) {
|
||||||
@@ -251,7 +251,7 @@ const CodeEditor = (props) => {
|
|||||||
setSelectedCondition(condition);
|
setSelectedCondition(condition);
|
||||||
// Update available variables when condition changes
|
// Update available variables when condition changes
|
||||||
updateAvailableVariables(actionlist);
|
updateAvailableVariables(actionlist);
|
||||||
}, [conditionId, fieldName])
|
}, [conditionId, conditionField])
|
||||||
|
|
||||||
// Extract variable updating logic into a separate function
|
// Extract variable updating logic into a separate function
|
||||||
const updateAvailableVariables = (actionlist) => {
|
const updateAvailableVariables = (actionlist) => {
|
||||||
@@ -2588,7 +2588,7 @@ const CodeEditor = (props) => {
|
|||||||
|
|
||||||
// Handle condition fields
|
// Handle condition fields
|
||||||
if (conditionField !== null && handleConditionFieldChange !== undefined) {
|
if (conditionField !== null && handleConditionFieldChange !== undefined) {
|
||||||
handleConditionFieldChange(conditionField, fieldName, fixedcodedata);
|
handleConditionFieldChange(conditionField, fixedcodedata);
|
||||||
}
|
}
|
||||||
// Handle action fields
|
// Handle action fields
|
||||||
else if (actionId !== undefined && actionId !== null && actionId.length > 0) {
|
else if (actionId !== undefined && actionId !== null && actionId.length > 0) {
|
||||||
@@ -2596,7 +2596,7 @@ const CodeEditor = (props) => {
|
|||||||
}
|
}
|
||||||
// Handle trigger fields
|
// Handle trigger fields
|
||||||
else if (triggerId !== undefined && triggerId !== null && triggerId.length > 0) {
|
else if (triggerId !== undefined && triggerId !== null && triggerId.length > 0) {
|
||||||
handleSubflowParamChange(triggerId, triggerField, fixedcodedata)
|
handleTriggerParamChange(triggerId, triggerField, fixedcodedata)
|
||||||
}
|
}
|
||||||
|
|
||||||
setExpansionModalOpen(false)
|
setExpansionModalOpen(false)
|
||||||
|
|||||||
@@ -1359,7 +1359,7 @@ const UserManagmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItem style={{ width: "100%", padding: "10px 10px 10px 0px", verticalAlign: 'middle', borderBottom: theme.palette.defaultBorder, display: "table-row" }}>
|
<ListItem style={{ width: "100%", padding: "10px 10px 10px 0px", verticalAlign: 'middle', borderBottom: theme.palette.defaultBorder, display: "table-row" }}>
|
||||||
{["Username", /*"API Key",*/ "Role", /*"Active",*/ "Type", "MFA", ...(selectedOrganization?.child_orgs?.length > 0 ? ["Suborgs"]: []), "Actions", "Last Login"].map((header, index) => (
|
{["Region", "Username", /*"API Key",*/ "Role", /*"Active",*/ "Type", "MFA", ...(selectedOrganization?.child_orgs?.length > 0 ? ["Suborgs"]: []), "Actions", "Last Login"].map((header, index) => (
|
||||||
<ListItemText
|
<ListItemText
|
||||||
key={index}
|
key={index}
|
||||||
primary={header}
|
primary={header}
|
||||||
@@ -1459,8 +1459,40 @@ const UserManagmentTab = memo((props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getRegionFlag = (region_url) => {
|
||||||
|
let regiontag = "UK";
|
||||||
|
let regionCode = "gb";
|
||||||
|
const regionsplit = region_url?.split(".");
|
||||||
|
if (regionsplit?.length > 2 && !regionsplit[0]?.includes("shuffler")) {
|
||||||
|
const namesplit = regionsplit[0]?.split("/");
|
||||||
|
regiontag = namesplit[namesplit?.length - 1];
|
||||||
|
|
||||||
|
if (regiontag === "california") {
|
||||||
|
regiontag = "US";
|
||||||
|
regionCode = "us";
|
||||||
|
} else if (regiontag === "frankfurt") {
|
||||||
|
regiontag = "EU-2";
|
||||||
|
regionCode = "eu";
|
||||||
|
} else if (regiontag === "ca") {
|
||||||
|
regiontag = "CA";
|
||||||
|
regionCode = "ca";
|
||||||
|
}else if (regiontag === "au") {
|
||||||
|
regiontag = "AUS";
|
||||||
|
regionCode = "au"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const userRegion = data?.user_geo_info?.country?.iso_code?.length > 0 ? data?.user_geo_info?.country?.iso_code : data?.active_org?.region_url?.length > 0 ? getRegionFlag(data?.active_org?.region_url) : "eu";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem key={index} style={{ backgroundColor: bgColor, display: 'table-row', borderBottomLeftRadius: users?.length - 1 === index ? 8 : 0, borderBottomRightRadius: users?.length - 1 === index ? 8 : 0 }}>
|
<ListItem key={index} style={{ backgroundColor: bgColor, display: 'table-row', borderBottomLeftRadius: users?.length - 1 === index ? 8 : 0, borderBottomRightRadius: users?.length - 1 === index ? 8 : 0 }}>
|
||||||
|
<ListItemText
|
||||||
|
primary={(<img src={`https://flagcdn.com/48x36/${userRegion.toLowerCase()}.png`} alt={data?.user_geo_info?.country?.iso_code} style={{ marginRight: 30, width: 25, height: 23, }} />)}
|
||||||
|
style={{ display: 'table-cell', verticalAlign: 'middle', textAlign: 'center' }}
|
||||||
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={(
|
primary={(
|
||||||
<Tooltip title={data.username || 'No username available'}>
|
<Tooltip title={data.username || 'No username available'}>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
import WorkflowPaper from "../components/WorkflowPaper.jsx"
|
import WorkflowPaper from "../components/WorkflowPaper.jsx"
|
||||||
import WorkflowPaperNew from "../components/WorkflowPaperNew.jsx"
|
import WorkflowPaperNew from "../components/WorkflowPaperNew.jsx"
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const AppGrid = props => {
|
const AppGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, alternativeView, onlyResults, inputsearch } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, alternativeView, onlyResults, inputsearch } = props
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import algoliasearch from 'algoliasearch';
|
|||||||
import { InstantSearch, connectSearchBox, connectHits } from 'react-instantsearch-dom';
|
import { InstantSearch, connectSearchBox, connectHits } from 'react-instantsearch-dom';
|
||||||
import { Grid, Paper, TextField, ButtonBase, InputAdornment, Typography, Button, Tooltip} from '@mui/material';
|
import { Grid, Paper, TextField, ButtonBase, InputAdornment, Typography, Button, Tooltip} from '@mui/material';
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const WorkflowSearch = props => {
|
const WorkflowSearch = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, selectAble, } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, selectAble, } = props
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
|
|||||||
@@ -334,7 +334,8 @@ const Admin2 = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 0.9}}>
|
//<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 0.9}}>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 1, }}>
|
||||||
<AdminNavBar userdata={userdata} isLoaded={isLoaded} isOrgLoaded={isOrgLoaded} selectedStatus={selectedStatus} setSelectedStatus={setSelectedStatus} selectedTab={selectedTab} orgId={selectedOrganization.id} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} setNotifications={setNotifications} stripeKey={stripeKey} notifications={notifications} checkLogin={checkLogin} globalUrl={globalUrl} isCloud={isCloud}/>
|
<AdminNavBar userdata={userdata} isLoaded={isLoaded} isOrgLoaded={isOrgLoaded} selectedStatus={selectedStatus} setSelectedStatus={setSelectedStatus} selectedTab={selectedTab} orgId={selectedOrganization.id} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} setNotifications={setNotifications} stripeKey={stripeKey} notifications={notifications} checkLogin={checkLogin} globalUrl={globalUrl} isCloud={isCloud}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -68,13 +68,19 @@ const AdminAccount = (props) => {
|
|||||||
.then((response) =>
|
.then((response) =>
|
||||||
response.json().then((responseJson) => {
|
response.json().then((responseJson) => {
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
setLoginInfo(responseJson["reason"]);
|
setLoginInfo(responseJson["reason"])
|
||||||
|
|
||||||
|
if (responseJson?.reason?.toLowerCase().includes("connection refused")) {
|
||||||
|
navigate("/loginsetup")
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (responseJson.reason === "redirect") {
|
if (responseJson.reason === "redirect") {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.pathname = "/login";
|
window.location.pathname = "/login"
|
||||||
}, 2500)
|
}, 2500)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -111,7 +117,7 @@ const AdminAccount = (props) => {
|
|||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
setLoginInfo(responseJson["reason"]);
|
setLoginInfo(responseJson["reason"]);
|
||||||
} else {
|
} else {
|
||||||
setLoginInfo("Successful register :)");
|
setLoginInfo("Successful register! Redirecting in a moment...");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.pathname = "/login";
|
window.location.pathname = "/login";
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|||||||
//const referenceUrl = "https://shuffler.io/functions/webhooks/"
|
//const referenceUrl = "https://shuffler.io/functions/webhooks/"
|
||||||
//const referenceUrl = window.location.origin+"/api/v1/hooks/"
|
//const referenceUrl = window.location.origin+"/api/v1/hooks/"
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const AngularWorkflow = (defaultprops) => {
|
const AngularWorkflow = (defaultprops) => {
|
||||||
const { globalUrl, setCookie, isLoggedIn, isLoaded, userdata, data_id, ReactGA, } = defaultprops;
|
const { globalUrl, setCookie, isLoggedIn, isLoaded, userdata, data_id, ReactGA, } = defaultprops;
|
||||||
const {themeMode, supportEmail, brandColor} = useContext(Context)
|
const {themeMode, supportEmail, brandColor} = useContext(Context)
|
||||||
@@ -790,7 +790,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fields",
|
"name": "fields",
|
||||||
"value": "",
|
"value": '{\n "ticket_id": "123456",\n "comment": "This is a comment"\n}',
|
||||||
"required": false,
|
"required": false,
|
||||||
"multiline": true,
|
"multiline": true,
|
||||||
},
|
},
|
||||||
@@ -3573,6 +3573,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
if (curapp?.actions === undefined || curapp?.actions === null || curapp?.actions?.length === 0 || curapp?.actions?.length === 1) {
|
if (curapp?.actions === undefined || curapp?.actions === null || curapp?.actions?.length === 0 || curapp?.actions?.length === 1) {
|
||||||
loadAppConfig(curapp?.id, false, true)
|
loadAppConfig(curapp?.id, false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key > 10) {
|
||||||
|
console.log("Breaking on 10 sideloads of total", responseJson.length)
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find app with ID "794e51c3c1a8b24b89ccc573a3defc47" (gmail) to force-break it,
|
// Find app with ID "794e51c3c1a8b24b89ccc573a3defc47" (gmail) to force-break it,
|
||||||
@@ -7000,7 +7006,11 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
toast("Failed to auto-activate the app. Go to /apps and activate it.")
|
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
||||||
|
toast.error("Failed to auto-activate the app: " + responseJson.reason)
|
||||||
|
} else {
|
||||||
|
toast.error("Failed to auto-activate the app. Go to /apps and activate it.")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (refresh === true) {
|
if (refresh === true) {
|
||||||
setHighlightedApp(appid)
|
setHighlightedApp(appid)
|
||||||
@@ -10312,7 +10322,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toast("Creating schedule")
|
toast.info("Creating schedule")
|
||||||
var data = {
|
var data = {
|
||||||
name: trigger.name,
|
name: trigger.name,
|
||||||
frequency: workflow.triggers[triggerindex].parameters[0].value,
|
frequency: workflow.triggers[triggerindex].parameters[0].value,
|
||||||
@@ -10361,9 +10371,9 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (!responseJson.success) {
|
if (!responseJson.success) {
|
||||||
toast("Failed to set schedule: " + responseJson.reason);
|
toast.error("Failed to set schedule: " + responseJson.reason);
|
||||||
} else {
|
} else {
|
||||||
toast("Successfully created schedule");
|
toast.success("Successfully created schedule");
|
||||||
workflow.triggers[triggerindex].status = "running";
|
workflow.triggers[triggerindex].status = "running";
|
||||||
trigger.status = "running";
|
trigger.status = "running";
|
||||||
setSelectedTrigger(trigger);
|
setSelectedTrigger(trigger);
|
||||||
@@ -11852,7 +11862,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
if (queryID !== undefined && queryID !== null) {
|
if (queryID !== undefined && queryID !== null) {
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
})
|
})
|
||||||
|
|
||||||
const timestamp = new Date().getTime()
|
const timestamp = new Date().getTime()
|
||||||
@@ -11876,8 +11886,9 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
var type = "app"
|
var type = "app"
|
||||||
const baseImage = <LibraryBooksIcon />
|
const baseImage = <LibraryBooksIcon />
|
||||||
|
const width = 230
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "relative", marginTop: 15, marginLeft: 0, marginRight: 10, position: "absolute", color: theme.palette.textColor, zIndex: 1001, backgroundColor: theme.palette.textFieldStyle.backgroundColor, minWidth: leftBarSize+30, maxWidth: 340, boxShadows: "none", overflowX: "hidden", }}>
|
<div style={{ position: "relative", marginTop: 15, marginLeft: 0, marginRight: 10, position: "absolute", color: theme.palette.textColor, zIndex: 1001, backgroundColor: theme.palette.textFieldStyle.backgroundColor, /*minWidth: leftBarSize+30,*/ minWidth: width, maxWidth: width, boxShadows: "none", overflowX: "hidden", }}>
|
||||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
||||||
{hits.length === 0 ?
|
{hits.length === 0 ?
|
||||||
<ListItem style={outerlistitemStyle}>
|
<ListItem style={outerlistitemStyle}>
|
||||||
@@ -11971,7 +11982,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}}
|
}}
|
||||||
defaultPosition={{ x: 0, y: 0 }}
|
defaultPosition={{ x: 0, y: 0 }}
|
||||||
>
|
>
|
||||||
<div style={{ textDecoration: "none", color: theme.palette.text.primary, }} onClick={(event) => {
|
<div style={{ overflow: "hidden", textDecoration: "none", color: theme.palette.text.primary, }} onClick={(event) => {
|
||||||
clickedApp(hit)
|
clickedApp(hit)
|
||||||
|
|
||||||
}}>
|
}}>
|
||||||
@@ -12125,7 +12136,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((app.id === "integration" || app.id === "shuffle_agent") && userdata.support !== true) {
|
if ((app.id === "integration" || app.id === "shuffle_agent") && userdata.support !== true) {
|
||||||
return null
|
console.log("APPID: ", app.id, isCloud)
|
||||||
|
if (isCloud === false && app.id === "integration") {
|
||||||
|
} else {
|
||||||
|
console.log("RETURNING", app.id)
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewedApps.includes(app.id)) {
|
if (viewedApps.includes(app.id)) {
|
||||||
@@ -12190,7 +12206,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
</div>
|
</div>
|
||||||
) : apps.length > 0 ? (
|
) : apps.length > 0 ? (
|
||||||
<div
|
<div
|
||||||
style={{ textAlign: "center", width: leftBarSize, marginTop: 10, marginLeft: 5, marginRight: 5, }}
|
style={{ textAlign: "center", width: leftBarSize, marginTop: 25, marginLeft: 10 , marginRight: 10, }}
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
console.log("Should load in extra apps?")
|
console.log("Should load in extra apps?")
|
||||||
}}
|
}}
|
||||||
@@ -12198,6 +12214,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
<Typography variant="body1" color="textSecondary">
|
<Typography variant="body1" color="textSecondary">
|
||||||
Couldn't find the apps you were looking for? Searching unactivated apps. Click one of these apps to Activate it for your organisation.
|
Couldn't find the apps you were looking for? Searching unactivated apps. Click one of these apps to Activate it for your organisation.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||||
console.log("CLICKED")
|
console.log("CLICKED")
|
||||||
}}>
|
}}>
|
||||||
@@ -13021,7 +13038,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
setExpansionModalOpen(true)
|
setExpansionModalOpen(true)
|
||||||
setActiveDialog("codeeditor")
|
setActiveDialog("codeeditor")
|
||||||
navigate(`?condition_id=${data.id}&field=${data.name}`)
|
navigate(`?condition_id=${data.id}&condition_field=${data.name}`)
|
||||||
setEditorData({
|
setEditorData({
|
||||||
"name": data.name,
|
"name": data.name,
|
||||||
"value": data.value || "",
|
"value": data.value || "",
|
||||||
@@ -13106,9 +13123,9 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
// Update the field value based on type
|
// Update the field value based on type
|
||||||
if (type === "source") {
|
if (type === "source") {
|
||||||
handleConditionFieldChange("source", "value", toComplete);
|
handleConditionFieldChange("source", toComplete);
|
||||||
} else if (type === "destination") {
|
} else if (type === "destination") {
|
||||||
handleConditionFieldChange("destination", "value", toComplete);
|
handleConditionFieldChange("destination", toComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMenuClose();
|
handleMenuClose();
|
||||||
@@ -13985,7 +14002,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
const handleConditionFieldChange = (fieldType, fieldName, value) => {
|
const handleConditionFieldChange = (fieldType, value) => {
|
||||||
if (fieldType === "source") {
|
if (fieldType === "source") {
|
||||||
setSourceValue({
|
setSourceValue({
|
||||||
...sourceValue,
|
...sourceValue,
|
||||||
@@ -15186,7 +15203,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const handleSubflowParamChange = (triggerId, triggerField, newData) => {
|
const handleTriggerParamChange = (triggerId, triggerField, newData) => {
|
||||||
var updateFail = ""
|
var updateFail = ""
|
||||||
|
|
||||||
if (workflow !== undefined && workflow !== null) {
|
if (workflow !== undefined && workflow !== null) {
|
||||||
@@ -15303,7 +15320,8 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
<Typography>Name</Typography>
|
<Typography>Name</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
borderRadius: theme.palette?.borderRadius,
|
borderRadius: theme.palette?.borderRadius,
|
||||||
marginTop: 3,
|
marginTop: 3,
|
||||||
}}
|
}}
|
||||||
@@ -15332,7 +15350,8 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
<Typography>Delay</Typography>
|
<Typography>Delay</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#212121",
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
marginTop: 3,
|
marginTop: 3,
|
||||||
maxWidth: 50,
|
maxWidth: 50,
|
||||||
}}
|
}}
|
||||||
@@ -17323,9 +17342,13 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
rows="4"
|
rows="4"
|
||||||
multiline
|
multiline
|
||||||
defaultValue={selectedTrigger.parameters[0]?.value}
|
value={selectedTriggerValue || ""}
|
||||||
color="primary"
|
color="primary"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
setLastSaved(false)
|
||||||
|
setSelectedTriggerValue(e.target.value)
|
||||||
|
}}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
setLastSaved(false)
|
setLastSaved(false)
|
||||||
setTriggerTextInformationWrapper(e.target.value);
|
setTriggerTextInformationWrapper(e.target.value);
|
||||||
@@ -18681,7 +18704,9 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
{originalWorkflow?.suborg_distribution === undefined || originalWorkflow?.suborg_distribution === null || originalWorkflow?.suborg_distribution?.length === 0 || originalWorkflow?.suborg_distribution.includes("none") ?
|
{originalWorkflow?.suborg_distribution === undefined || originalWorkflow?.suborg_distribution === null || originalWorkflow?.suborg_distribution?.length === 0 || originalWorkflow?.suborg_distribution.includes("none") ?
|
||||||
|
|
||||||
originalWorkflow?.parentorg_workflow !== undefined && originalWorkflow?.parentorg_workflow !== null && originalWorkflow?.parentorg_workflow.length > 0 || workflow?.parentorg_workflow !== undefined && workflow?.parentorg_workflow !== null && workflow?.parentorg_workflow.length > 0 ?
|
<div>
|
||||||
|
{originalWorkflow?.parentorg_workflow !== undefined && originalWorkflow?.parentorg_workflow !== null && originalWorkflow?.parentorg_workflow.length > 0 || workflow?.parentorg_workflow !== undefined && workflow?.parentorg_workflow !== null && workflow?.parentorg_workflow.length > 0 ?
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -18691,7 +18716,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
marginLeft: 10,
|
marginLeft: 10,
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate(`/workflows/${workflow.parentorg_workflow}`)
|
navigate(`/workflows/${workflow.parentorg_workflow}`)
|
||||||
// Reload the page
|
// Reload the page
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
@@ -18699,7 +18724,10 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
>
|
>
|
||||||
Go to parent org workflow
|
Go to parent org workflow
|
||||||
</Button>
|
</Button>
|
||||||
: userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 1 && workflow?.id !== undefined && workflow?.id && workflow?.id?.length > 0 ?
|
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 1 && workflow?.id !== undefined && workflow?.id && workflow?.id?.length > 0 ?
|
||||||
<Button
|
<Button
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -18715,8 +18743,8 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
>
|
>
|
||||||
Enable Suborg Distribution
|
Enable Suborg Distribution
|
||||||
</Button>
|
</Button>
|
||||||
: null
|
: null}
|
||||||
|
</div>
|
||||||
:
|
:
|
||||||
|
|
||||||
<Tooltip title={lastSaved === false && originalWorkflow.id === workflow.id ?
|
<Tooltip title={lastSaved === false && originalWorkflow.id === workflow.id ?
|
||||||
@@ -20063,7 +20091,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
if (queryID !== undefined && queryID !== null) {
|
if (queryID !== undefined && queryID !== null) {
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
})
|
})
|
||||||
|
|
||||||
const timestamp = new Date().getTime()
|
const timestamp = new Date().getTime()
|
||||||
@@ -25459,7 +25487,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
// selectedTrigger={selectedTrigger}
|
// selectedTrigger={selectedTrigger}
|
||||||
aiSubmit={aiSubmit}
|
aiSubmit={aiSubmit}
|
||||||
toolsAppId={toolsApp.id}
|
toolsAppId={toolsApp.id}
|
||||||
handleSubflowParamChange={handleSubflowParamChange}
|
handleTriggerParamChange={handleTriggerParamChange}
|
||||||
codedata={editorData.value}
|
codedata={editorData.value}
|
||||||
setcodedata={setcodedata}
|
setcodedata={setcodedata}
|
||||||
selectedEdge={selectedEdge}
|
selectedEdge={selectedEdge}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import { green } from "../views/AngularWorkflow.jsx"
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lazy loading of ApiExplorer component to reduce initial load time
|
// Lazy loading of ApiExplorer component to reduce initial load time
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ import aa from "search-insights";
|
|||||||
// 2 = OpenAPI (Invalid)
|
// 2 = OpenAPI (Invalid)
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
)
|
)
|
||||||
|
|
||||||
const AppExplorer = (props) => {
|
const AppExplorer = (props) => {
|
||||||
@@ -3996,7 +3996,7 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
|
|||||||
if (queryID !== undefined && queryID !== null) {
|
if (queryID !== undefined && queryID !== null) {
|
||||||
aa("init", {
|
aa("init", {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
});
|
});
|
||||||
|
|
||||||
const timestamp = new Date().getTime();
|
const timestamp = new Date().getTime();
|
||||||
@@ -4085,7 +4085,7 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
|
|||||||
if (queryID !== undefined && queryID !== null) {
|
if (queryID !== undefined && queryID !== null) {
|
||||||
aa("init", {
|
aa("init", {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
});
|
});
|
||||||
|
|
||||||
const timestamp = new Date().getTime();
|
const timestamp = new Date().getTime();
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ export const GetParsedPaths = (inputdata, basekey) => {
|
|||||||
return parsedValues;
|
return parsedValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
|
||||||
const Apps = (props) => {
|
const Apps = (props) => {
|
||||||
const { globalUrl, isLoggedIn, isLoaded, userdata, serverside, } = props;
|
const { globalUrl, isLoggedIn, isLoaded, userdata, serverside, } = props;
|
||||||
|
|
||||||
@@ -1305,7 +1305,7 @@ const Apps = (props) => {
|
|||||||
if (queryID !== undefined && queryID !== null) {
|
if (queryID !== undefined && queryID !== null) {
|
||||||
aa("init", {
|
aa("init", {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
});
|
});
|
||||||
|
|
||||||
const timestamp = new Date().getTime();
|
const timestamp = new Date().getTime();
|
||||||
@@ -2036,7 +2036,7 @@ const Apps = (props) => {
|
|||||||
if (queryID !== undefined && queryID !== null) {
|
if (queryID !== undefined && queryID !== null) {
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: "JNSS5CFDZZ",
|
appId: "JNSS5CFDZZ",
|
||||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
apiKey: "c8f882473ff42d41158430be09ec2b4e",
|
||||||
})
|
})
|
||||||
|
|
||||||
const timestamp = new Date().getTime()
|
const timestamp = new Date().getTime()
|
||||||
|
|||||||
+68
-102
@@ -46,7 +46,7 @@ import AppCreationModal from "../components/AppCreationModal.jsx";
|
|||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
"JNSS5CFDZZ",
|
"JNSS5CFDZZ",
|
||||||
"db08e40265e2941b9a7d8f644b6e5240"
|
"c8f882473ff42d41158430be09ec2b4e"
|
||||||
);
|
);
|
||||||
|
|
||||||
// AppCard Component
|
// AppCard Component
|
||||||
@@ -1122,6 +1122,7 @@ const Apps2 = (props) => {
|
|||||||
const [defaultSearch, setDefaultSearch] = useState("");
|
const [defaultSearch, setDefaultSearch] = useState("");
|
||||||
|
|
||||||
const [apps, setApps] = useState([]);
|
const [apps, setApps] = useState([]);
|
||||||
|
const [backupApps, setBackupApps] = useState([]);
|
||||||
const [filteredApps, setFilteredApps] = useState([]);
|
const [filteredApps, setFilteredApps] = useState([]);
|
||||||
const [appSearchLoading, setAppSearchLoading] = useState(false);
|
const [appSearchLoading, setAppSearchLoading] = useState(false);
|
||||||
const [creatorProfile, setCreatorProfile] = useState({});
|
const [creatorProfile, setCreatorProfile] = useState({});
|
||||||
@@ -1198,57 +1199,9 @@ const Apps2 = (props) => {
|
|||||||
getFramework();
|
getFramework();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Fetch apps based on the current tab : 0 -> org_apps, 1 -> my_apps, 2 -> all_apps
|
|
||||||
const fetchApps = async () => {
|
|
||||||
const baseUrl = globalUrl;
|
|
||||||
let url;
|
|
||||||
setIsLoading(true);
|
|
||||||
const userId = userdata?.id;
|
|
||||||
if (currTab === 1 && userId) {
|
|
||||||
url = `${baseUrl}/api/v1/users/${userId}/apps`;
|
|
||||||
} else if (currTab === 0) {
|
|
||||||
url = `${baseUrl}/api/v1/apps`;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: "GET",
|
|
||||||
credentials: "include",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
if (currTab === 1) {
|
|
||||||
setAppsToShow(data);
|
|
||||||
setUserApps(data);
|
|
||||||
} else if (currTab === 0) {
|
|
||||||
setAppsToShow(data);
|
|
||||||
setOrgApps(data);
|
|
||||||
// For testing the empty state
|
|
||||||
// setAppsToShow([]);
|
|
||||||
// setOrgApps([]);
|
|
||||||
}
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error fetching apps:", err);
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
getApps()
|
||||||
// Only fetch if we have required data
|
}, [])
|
||||||
if (globalUrl && (currTab === 0 || (currTab === 1 && userdata?.id))) {
|
|
||||||
fetchApps();
|
|
||||||
}
|
|
||||||
}, [currTab, globalUrl, userdata?.id]); // Remove location.search dependency
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// // setSearchQuery("");
|
|
||||||
// setSelectedCategory([]);
|
|
||||||
// setSelectedLabel([]);
|
|
||||||
// }, [currTab])
|
|
||||||
|
|
||||||
|
|
||||||
// Find top categories and tags based on the current tab
|
// Find top categories and tags based on the current tab
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1293,11 +1246,13 @@ const Apps2 = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (serverside) {
|
if (serverside) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}, [serverside]);
|
}, [serverside]);
|
||||||
|
*/
|
||||||
|
|
||||||
const getApps = () => {
|
const getApps = () => {
|
||||||
// Get apps from localstorage
|
// Get apps from localstorage
|
||||||
@@ -1308,7 +1263,7 @@ const Apps2 = (props) => {
|
|||||||
if (storageApps === null || storageApps === undefined || storageApps.length === 0) {
|
if (storageApps === null || storageApps === undefined || storageApps.length === 0) {
|
||||||
storageApps = []
|
storageApps = []
|
||||||
} else {
|
} else {
|
||||||
setAppsToShow(storageApps)
|
//setAppsToShow(storageApps)
|
||||||
setOrgApps(storageApps)
|
setOrgApps(storageApps)
|
||||||
setApps(storageApps)
|
setApps(storageApps)
|
||||||
// setFilteredApps(storageApps)
|
// setFilteredApps(storageApps)
|
||||||
@@ -1344,18 +1299,25 @@ const Apps2 = (props) => {
|
|||||||
var privateapps = [];
|
var privateapps = [];
|
||||||
var valid = [];
|
var valid = [];
|
||||||
var invalid = [];
|
var invalid = [];
|
||||||
|
|
||||||
|
var backups = []
|
||||||
for (var key in responseJson) {
|
for (var key in responseJson) {
|
||||||
const app = responseJson[key];
|
const app = responseJson[key];
|
||||||
|
|
||||||
if (app.categories !== undefined && app.categories !== null && app?.categories.includes("Eradication")) {
|
if (app?.reference_info?.onprem_backup === true) {
|
||||||
|
backups.push(app)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app?.categories !== undefined && app?.categories !== null && app?.categories?.includes("Eradication")) {
|
||||||
app.categories = ["EDR"]
|
app.categories = ["EDR"]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.is_valid && !(!app.activated && app.generated)) {
|
if (app?.is_valid && !(!app?.activated && app?.generated)) {
|
||||||
privateapps.push(app);
|
privateapps.push(app);
|
||||||
} else if (
|
} else if (
|
||||||
app.private_id !== undefined &&
|
app?.private_id !== undefined &&
|
||||||
app.private_id.length > 0
|
app?.private_id.length > 0
|
||||||
) {
|
) {
|
||||||
valid.push(app);
|
valid.push(app);
|
||||||
} else {
|
} else {
|
||||||
@@ -1363,6 +1325,11 @@ const Apps2 = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("BACKUPAPPS: ", backups)
|
||||||
|
if (backups.length > 0) {
|
||||||
|
setBackupApps(backups)
|
||||||
|
}
|
||||||
|
|
||||||
privateapps.push(...valid);
|
privateapps.push(...valid);
|
||||||
privateapps.push(...invalid);
|
privateapps.push(...invalid);
|
||||||
console.log("privateapps: setting apps ", privateapps)
|
console.log("privateapps: setting apps ", privateapps)
|
||||||
@@ -1372,39 +1339,22 @@ const Apps2 = (props) => {
|
|||||||
|
|
||||||
// setFilteredApps(privateapps);
|
// setFilteredApps(privateapps);
|
||||||
if (privateapps.length > 0) {
|
if (privateapps.length > 0) {
|
||||||
if (selectedApp.id === undefined || selectedApp.id === null) {
|
if (selectedApp?.id === undefined || selectedApp?.id === null) {
|
||||||
if (privateapps[0].owner !== undefined && privateapps[0].owner !== null) {
|
if (privateapps[0]?.owner !== undefined && privateapps[0]?.owner !== null) {
|
||||||
getUserProfile(privateapps[0].owner);
|
getUserProfile(privateapps[0]?.owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setContact(privateapps[0].contact_info)
|
|
||||||
|
|
||||||
// setSelectedApp(privateapps[0]);
|
|
||||||
// setSharingConfiguration(privateapps[0].sharing === true ? "public" : "you")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (
|
|
||||||
// privateapps[0].actions !== null &&
|
|
||||||
// privateapps[0].actions.length > 0
|
|
||||||
// ) {
|
|
||||||
// setSelectedAction(privateapps[0].actions[0]);
|
|
||||||
// } else {
|
|
||||||
// setSelectedAction({});
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
if (privateapps.length > 0 && storageApps.length === 0) {
|
if (privateapps?.length > 0 && storageApps?.length === 0) {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem("apps", JSON.stringify(privateapps))
|
localStorage.setItem("apps", JSON.stringify(privateapps))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Failed to set apps in localstorage: ", e)
|
console.log("Failed to set apps in localstorage: ", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//setTimeout(() => {
|
|
||||||
// setFirstLoad(false)
|
|
||||||
//}, 5000)
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
console.log("Failed to get apps: ", error.toString());
|
||||||
toast(error.toString());
|
toast(error.toString());
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
});
|
});
|
||||||
@@ -1780,7 +1730,6 @@ const Apps2 = (props) => {
|
|||||||
// setOpenModal(true);
|
// setOpenModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const apps = currTab === 1 ? userApps : orgApps;
|
const apps = currTab === 1 ? userApps : orgApps;
|
||||||
const filteredUserAppdata = filterApps(apps, searchQuery, selectedCategory, selectedLabel);
|
const filteredUserAppdata = filterApps(apps, searchQuery, selectedCategory, selectedLabel);
|
||||||
@@ -1798,33 +1747,38 @@ const Apps2 = (props) => {
|
|||||||
} else if (newTab === 1) {
|
} else if (newTab === 1) {
|
||||||
const filteredUserApps = filterApps(userApps, searchQuery, selectedCategory, selectedLabel);
|
const filteredUserApps = filterApps(userApps, searchQuery, selectedCategory, selectedLabel);
|
||||||
setAppsToShow(filteredUserApps);
|
setAppsToShow(filteredUserApps);
|
||||||
}
|
} else if (newTab === 3) {
|
||||||
|
const filteredUserApps = filterApps(backupApps, searchQuery, selectedCategory, selectedLabel);
|
||||||
|
setAppsToShow(filteredUserApps);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update URL query params based on tab index
|
// Update URL query params based on tab index
|
||||||
const tabMapping = {
|
const tabMapping = {
|
||||||
0: 'org_apps',
|
0: 'org_apps',
|
||||||
1: 'my_apps',
|
1: 'my_apps',
|
||||||
2: 'all_apps'
|
2: 'all_apps',
|
||||||
|
3: 'backup_apps',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
queryParams.set('tab', tabMapping[newTab]);
|
queryParams.set('tab', tabMapping[newTab]);
|
||||||
|
|
||||||
// Maintain search query in URL regardless of tab
|
// Maintain search query in URL regardless of tab
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
queryParams.set('q', searchQuery);
|
queryParams.set('q', searchQuery);
|
||||||
} else {
|
} else {
|
||||||
queryParams.delete('q');
|
queryParams.delete('q');
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(`${location.pathname}?${queryParams.toString()}`);
|
navigate(`${location.pathname}?${queryParams.toString()}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update useEffect for filtering without URL manipulation
|
// Update useEffect for filtering without URL manipulation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currTab === 2) return; // Skip for "Discover Apps" tab as it uses Algolia
|
if (currTab === 2) return; // Skip for "Discover Apps" tab as it uses Algolia
|
||||||
|
|
||||||
const apps = currTab === 1 ? userApps : orgApps;
|
const apps = currTab === 1 ? userApps : currTab === 3 ? backupApps : orgApps;
|
||||||
const filteredApps = filterApps(apps, searchQuery, selectedCategory, selectedLabel);
|
const filteredApps = filterApps(apps, searchQuery, selectedCategory, selectedLabel);
|
||||||
setAppsToShow(filteredApps);
|
setAppsToShow(filteredApps);
|
||||||
}, [searchQuery, selectedCategory, selectedLabel, currTab, userApps, orgApps]);
|
}, [searchQuery, selectedCategory, selectedLabel, currTab, userApps, orgApps]);
|
||||||
@@ -1914,7 +1868,7 @@ const Apps2 = (props) => {
|
|||||||
<div style={boxStyle}>
|
<div style={boxStyle}>
|
||||||
<div style={{ display: "flex", flexDirection: "row", width: "100%", justifyContent: "space-between" }}>
|
<div style={{ display: "flex", flexDirection: "row", width: "100%", justifyContent: "space-between" }}>
|
||||||
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: theme?.typography?.fontFamily }}>
|
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: theme?.typography?.fontFamily }}>
|
||||||
{currTab === 0 ? "Org" : currTab === 1 ? "Your" : "Discover"} Apps
|
{currTab === 0 ? "Org" : currTab === 1 ? "Your" : currTab === 3 ? "Backup" : "Discover"} Apps
|
||||||
</Typography>
|
</Typography>
|
||||||
{isCloud ? null : (
|
{isCloud ? null : (
|
||||||
<span style={{ display: "flex", gap: 15 }}>
|
<span style={{ display: "flex", gap: 15 }}>
|
||||||
@@ -1940,7 +1894,7 @@ const Apps2 = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
height: 45,
|
height: 45,
|
||||||
minWidth: 45,
|
minWidth: 45,
|
||||||
backgroundColor: "#2F2F2F",
|
backgroundColor: theme.palette.platformColor,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
padding: "8px 16px",
|
padding: "8px 16px",
|
||||||
}}
|
}}
|
||||||
@@ -1950,9 +1904,9 @@ const Apps2 = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<CircularProgress size={20} style={{ color: "#FF8544" }} />
|
<CircularProgress size={20} style={{ color: theme.palette.primary.main }} />
|
||||||
) : (
|
) : (
|
||||||
<CachedIcon style={{ color: "#F1F1F1" }} />
|
<CachedIcon style={{ color: theme.palette.text.primary }} />
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1980,7 +1934,7 @@ const Apps2 = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
height: 45,
|
height: 45,
|
||||||
minWidth: 45,
|
minWidth: 45,
|
||||||
backgroundColor: "#2F2F2F",
|
backgroundColor: theme.palette.platformColor,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
padding: "8px 16px",
|
padding: "8px 16px",
|
||||||
}}
|
}}
|
||||||
@@ -1992,9 +1946,9 @@ const Apps2 = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<CircularProgress size={20} style={{ color: "#FF8544" }} />
|
<CircularProgress size={20} style={{ color: theme.palette.primary.main }} />
|
||||||
) : (
|
) : (
|
||||||
<CloudDownloadIcon style={{ color: "#F1F1F1" }} />
|
<CloudDownloadIcon style={{ color: theme.palette.text.primary }} />
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -2027,6 +1981,7 @@ const Apps2 = (props) => {
|
|||||||
...(currTab === 1 ? tabActive : {})
|
...(currTab === 1 ? tabActive : {})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label="Discover Public Apps"
|
label="Discover Public Apps"
|
||||||
style={{
|
style={{
|
||||||
@@ -2035,6 +1990,17 @@ const Apps2 = (props) => {
|
|||||||
...(currTab === 2 ? tabActive : {})
|
...(currTab === 2 ? tabActive : {})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{backupApps.length > 0 &&
|
||||||
|
<Tab
|
||||||
|
label={`Onprem Backup (${backupApps.length})`}
|
||||||
|
style={{
|
||||||
|
...tabStyle,
|
||||||
|
marginLeft: 25,
|
||||||
|
...(currTab === 3 ? tabActive : {})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45, paddingRight: 25 }}>
|
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45, paddingRight: 25 }}>
|
||||||
@@ -2043,7 +2009,7 @@ const Apps2 = (props) => {
|
|||||||
minWidth: "25%",
|
minWidth: "25%",
|
||||||
maxWidth: "25%"
|
maxWidth: "25%"
|
||||||
}}>
|
}}>
|
||||||
{(currTab === 0 || currTab === 1) ? (
|
{(currTab === 0 || currTab === 1 || currTab === 3) ? (
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -2253,7 +2219,7 @@ const Apps2 = (props) => {
|
|||||||
<div>
|
<div>
|
||||||
|
|
||||||
{
|
{
|
||||||
currTab === 0 && (
|
currTab === 0 || currTab === 3 && (
|
||||||
<div style={{ minHeight: 570 }}>
|
<div style={{ minHeight: 570 }}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<LoadingGrid />
|
<LoadingGrid />
|
||||||
@@ -2285,7 +2251,7 @@ const Apps2 = (props) => {
|
|||||||
handleAppClick={handleAppClick}
|
handleAppClick={handleAppClick}
|
||||||
leftSideBarOpenByClick={leftSideBarOpenByClick}
|
leftSideBarOpenByClick={leftSideBarOpenByClick}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
fetchApps={fetchApps}
|
fetchApps={getApps}
|
||||||
|
|
||||||
setUserApps={setUserApps}
|
setUserApps={setUserApps}
|
||||||
appsToShow={appsToShow}
|
appsToShow={appsToShow}
|
||||||
@@ -2338,7 +2304,7 @@ const Apps2 = (props) => {
|
|||||||
{appsToShow.map((data, index) => (
|
{appsToShow.map((data, index) => (
|
||||||
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} userdata={userdata}
|
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} userdata={userdata}
|
||||||
handleAppClick={handleAppClick} leftSideBarOpenByClick={leftSideBarOpenByClick}
|
handleAppClick={handleAppClick} leftSideBarOpenByClick={leftSideBarOpenByClick}
|
||||||
fetchApps={fetchApps}
|
fetchApps={getApps}
|
||||||
setUserApps={setUserApps}
|
setUserApps={setUserApps}
|
||||||
appsToShow={appsToShow}
|
appsToShow={appsToShow}
|
||||||
setAppsToShow={setAppsToShow}
|
setAppsToShow={setAppsToShow}
|
||||||
|
|||||||
@@ -314,12 +314,15 @@ const LoginPage = props => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (serverside !== true) {
|
useEffect(() => {
|
||||||
const tmpMessage = new URLSearchParams(window.location.search).get("message")
|
if (serverside !== true) {
|
||||||
if (tmpMessage !== undefined && tmpMessage !== null && message !== tmpMessage) {
|
const tmpMessage = new URLSearchParams(window.location.search).get("message")
|
||||||
setMessage(tmpMessage)
|
if (tmpMessage !== undefined && tmpMessage !== null && message !== tmpMessage) {
|
||||||
|
setMessage(tmpMessage)
|
||||||
|
toast(tmpMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
if (document !== undefined) {
|
if (document !== undefined) {
|
||||||
if (register) {
|
if (register) {
|
||||||
@@ -361,7 +364,7 @@ const LoginPage = props => {
|
|||||||
console.log("Should login instead of register!")
|
console.log("Should login instead of register!")
|
||||||
setRegister(!register)
|
setRegister(!register)
|
||||||
} else {
|
} else {
|
||||||
console.log("Path: " + path, "Register: " + register)
|
//console.log("Path: " + path, "Register: " + register)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,13 +447,17 @@ const LoginPage = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isLoggedIn === true && serverside !== true) {
|
if (isLoggedIn === true && serverside !== true) {
|
||||||
const tmpView = new URLSearchParams(window.location.search).get("view")
|
const tmpView = new URLSearchParams(window.location.search).get("view");
|
||||||
if (tmpView !== undefined && tmpView !== null && tmpView === "pricing") {
|
if (tmpView !== undefined && tmpView !== null) {
|
||||||
window.location.pathname = "/pricing"
|
let pathOnly = tmpView.split("?")[0];
|
||||||
return
|
if (!pathOnly.startsWith("/")) pathOnly = "/" + pathOnly;
|
||||||
} else if (tmpView !== undefined && tmpView !== null) {
|
|
||||||
window.location.pathname = tmpView
|
if (pathOnly === "/pricing" || pathOnly === "admin") {
|
||||||
return
|
window.location.replace(pathOnly + window.location.search);
|
||||||
|
} else {
|
||||||
|
window.location.replace(pathOnly);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.pathname = "/workflows"
|
window.location.pathname = "/workflows"
|
||||||
@@ -468,6 +475,11 @@ const LoginPage = props => {
|
|||||||
response.json().then((responseJson) => {
|
response.json().then((responseJson) => {
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
setLoginInfo(responseJson["reason"]);
|
setLoginInfo(responseJson["reason"]);
|
||||||
|
|
||||||
|
if (responseJson?.reason?.toLowerCase().includes("connection refused")) {
|
||||||
|
navigate("/loginsetup")
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
|
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
|
||||||
setSSOUrl(responseJson.sso_url);
|
setSSOUrl(responseJson.sso_url);
|
||||||
@@ -570,20 +582,17 @@ const LoginPage = props => {
|
|||||||
setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" })
|
setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" })
|
||||||
}
|
}
|
||||||
|
|
||||||
const tmpView = new URLSearchParams(window.location.search).get("view")
|
const tmpView = new URLSearchParams(window.location.search).get("view");
|
||||||
if (tmpView !== undefined && tmpView !== null) {
|
if (tmpView !== undefined && tmpView !== null) {
|
||||||
//const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}`
|
let pathOnly = tmpView.split("?")[0];
|
||||||
// Check if slash in the url
|
if (!pathOnly.startsWith("/")) pathOnly = "/" + pathOnly;
|
||||||
|
|
||||||
var newUrl = `/${tmpView}`
|
if (pathOnly === "/pricing" || pathOnly === "admin") {
|
||||||
if (tmpView.startsWith("/")) {
|
window.location.replace(pathOnly + window.location.search);
|
||||||
newUrl = `${tmpView}`
|
} else {
|
||||||
|
window.location.replace(pathOnly);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
console.log("Found url: ", newUrl)
|
|
||||||
|
|
||||||
window.location.pathname = newUrl
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("LOGIN DATA: ", responseJson)
|
console.log("LOGIN DATA: ", responseJson)
|
||||||
@@ -642,9 +651,14 @@ const LoginPage = props => {
|
|||||||
|
|
||||||
const tmpView = new URLSearchParams(window.location.search).get("view")
|
const tmpView = new URLSearchParams(window.location.search).get("view")
|
||||||
if (tmpView !== undefined && tmpView !== null) {
|
if (tmpView !== undefined && tmpView !== null) {
|
||||||
//const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}`
|
let pathOnly = tmpView.split("?")[0];
|
||||||
const newUrl = `/${tmpView}`
|
if (!pathOnly.startsWith("/")) pathOnly = "/" + pathOnly;
|
||||||
window.location.pathname = newUrl
|
|
||||||
|
if (pathOnly === "/pricing" || pathOnly === "admin") {
|
||||||
|
window.location.replace(pathOnly + window.location.search);
|
||||||
|
} else {
|
||||||
|
window.location.replace(pathOnly);
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,13 @@ const LoginDialog = (props) => {
|
|||||||
.then((response) =>
|
.then((response) =>
|
||||||
response.json().then((responseJson) => {
|
response.json().then((responseJson) => {
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
setLoginInfo(responseJson["reason"]);
|
setLoginInfo(responseJson["reason"])
|
||||||
|
|
||||||
|
if (responseJson?.reason?.toLowerCase().includes("connection refused")) {
|
||||||
|
setLoginViewLoading(true)
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
|
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
|
||||||
|
|||||||
@@ -458,7 +458,12 @@ const Settings = (props) => {
|
|||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
setPasswordFormMessage(responseJson["reason"]);
|
setPasswordFormMessage(responseJson["reason"]);
|
||||||
} else {
|
} else {
|
||||||
toast("Changed password!");
|
var reason = ""
|
||||||
|
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
||||||
|
reason += responseJson.reason
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success("Changed password! " + reason);
|
||||||
setPasswordFormMessage("");
|
setPasswordFormMessage("");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -126,6 +126,13 @@ const UsecaseListComponent = (props) => {
|
|||||||
const { themeMode, brandName } = useContext(Context)
|
const { themeMode, brandName } = useContext(Context)
|
||||||
const theme = getTheme(themeMode)
|
const theme = getTheme(themeMode)
|
||||||
|
|
||||||
|
const usecaseLightThemeColor = {
|
||||||
|
"collect": "#FB47A0",
|
||||||
|
"enrich": "#F38B14",
|
||||||
|
"detect": "#0AAD65",
|
||||||
|
"respond": "#289BDB",
|
||||||
|
"verify": "#624CE9",
|
||||||
|
}
|
||||||
const [expandedIndex, setExpandedIndex] = useState(-1);
|
const [expandedIndex, setExpandedIndex] = useState(-1);
|
||||||
const [expandedItem, setExpandedItem] = useState(-1);
|
const [expandedItem, setExpandedItem] = useState(-1);
|
||||||
const [inputUsecase, setInputUsecase] = useState({});
|
const [inputUsecase, setInputUsecase] = useState({});
|
||||||
@@ -743,7 +750,7 @@ const UsecaseListComponent = (props) => {
|
|||||||
{keys.map((usecase, index) => {
|
{keys.map((usecase, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={index} style={{marginTop: 75, }}>
|
<div key={index} style={{marginTop: 75, }}>
|
||||||
<Typography variant="body1" style={{color: usecase.color, textAlign: "left", marginBottom: 10, }}>
|
<Typography variant="body1" style={{color: themeMode === "dark" ? usecase.color : usecaseLightThemeColor[usecase.name.slice(3, 100).toLowerCase()], textAlign: "left", marginBottom: 10, }}>
|
||||||
<b>{index+1}. {usecase.name.slice(3, 100)}</b>
|
<b>{index+1}. {usecase.name.slice(3, 100)}</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ import { removeQuery } from "../components/ScrollToTop.jsx";
|
|||||||
import {green, yellow, red, grey } from "../views/AngularWorkflow.jsx"
|
import {green, yellow, red, grey } from "../views/AngularWorkflow.jsx"
|
||||||
|
|
||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240");
|
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e");
|
||||||
|
|
||||||
const svgSize = 24;
|
const svgSize = 24;
|
||||||
const imagesize = 22;
|
const imagesize = 22;
|
||||||
@@ -678,6 +678,7 @@ const Workflows2 = (props) => {
|
|||||||
var upload = "";
|
var upload = "";
|
||||||
|
|
||||||
const [workflows, setWorkflows] = React.useState([]);
|
const [workflows, setWorkflows] = React.useState([]);
|
||||||
|
const [backupWorkflows, setBackupWorkflows] = React.useState([]);
|
||||||
const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove
|
const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove
|
||||||
const [selectedUsecases, setSelectedUsecases] = React.useState([]);
|
const [selectedUsecases, setSelectedUsecases] = React.useState([]);
|
||||||
const [filteredWorkflows, setFilteredWorkflows] = React.useState([]);
|
const [filteredWorkflows, setFilteredWorkflows] = React.useState([]);
|
||||||
@@ -756,7 +757,8 @@ const Workflows2 = (props) => {
|
|||||||
const tabMapping = {
|
const tabMapping = {
|
||||||
0: 'org_workflows',
|
0: 'org_workflows',
|
||||||
1: 'my_workflows',
|
1: 'my_workflows',
|
||||||
2: 'all_workflows'
|
2: 'all_workflows',
|
||||||
|
3: 'backup_apps',
|
||||||
};
|
};
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
queryParams.set('tab', tabMapping[newValue]);
|
queryParams.set('tab', tabMapping[newValue]);
|
||||||
@@ -1107,23 +1109,31 @@ const Workflows2 = (props) => {
|
|||||||
setSelectedWorkflowId("");
|
setSelectedWorkflowId("");
|
||||||
}}
|
}}
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
style: {
|
sx: {
|
||||||
backgroundColor: theme.palette.surfaceColor,
|
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
|
||||||
color: "white",
|
border: theme?.palette?.DialogStyle?.border,
|
||||||
minWidth: 500,
|
minWidth: '440px',
|
||||||
padding: 50,
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
},
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
}}
|
zIndex: 1000,
|
||||||
|
'& .MuiDialogContent-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
'& .MuiDialogTitle-root': {
|
||||||
|
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<div style={{ textAlign: "center", color: "rgba(255,255,255,0.9)" }}>
|
<div style={{ textAlign: "center", color: theme.palette.DialogStyle?.color }}>
|
||||||
Are you sure you want to delete {selectedWorkflowId.length > 0 ? filteredWorkflows.find((w) => w.id === selectedWorkflowId)?.name : `${selectedWorkflowIndexes.length} workflow${selectedWorkflowIndexes.length === 1 ? '' : 's'}`}? <div />
|
Are you sure you want to delete {selectedWorkflowId.length > 0 ? filteredWorkflows.find((w) => w.id === selectedWorkflowId)?.name : `${selectedWorkflowIndexes.length} workflow${selectedWorkflowIndexes.length === 1 ? '' : 's'}`}? <div />
|
||||||
|
|
||||||
Other workflows relying on {selectedWorkflowIndexes.length > 0 ? "them" : "it"} one will stop working
|
Other workflows relying on {selectedWorkflowIndexes.length > 0 ? "them" : "it"} one will stop working
|
||||||
</div>
|
</div>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
style={{ color: "rgba(255,255,255,0.65)", textAlign: "center" }}
|
style={{ color: theme.palette.DialogStyle.color, textAlign: "center" }}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
style={{}}
|
style={{}}
|
||||||
@@ -1216,7 +1226,7 @@ const Workflows2 = (props) => {
|
|||||||
data.status
|
data.status
|
||||||
).then((response) => {
|
).then((response) => {
|
||||||
if (response !== undefined) {
|
if (response !== undefined) {
|
||||||
toast(`Successfully imported ${data.name}`);
|
toast.success(`Successfully imported ${data.name}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1341,21 +1351,33 @@ const Workflows2 = (props) => {
|
|||||||
// When there are no workflows, we can set the loading to false
|
// When there are no workflows, we can set the loading to false
|
||||||
setIsLoadingWorkflow(false)
|
setIsLoadingWorkflow(false)
|
||||||
if (currTab !== 2) {
|
if (currTab !== 2) {
|
||||||
toast("No workflows found. Showing workflow discovery")
|
toast.info("No workflows found in this org. Feel free to look into our public workflows!" , {
|
||||||
|
timeout: 7500,
|
||||||
|
})
|
||||||
setCurrTab(2)
|
setCurrTab(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var newarray = []
|
var newarray = []
|
||||||
|
var backupWf = []
|
||||||
for (var wfkey in responseJson) {
|
for (var wfkey in responseJson) {
|
||||||
const wf = responseJson[wfkey]
|
const wf = responseJson[wfkey]
|
||||||
if (wf.public === true || wf.hidden === true) {
|
if (wf.public === true || wf.hidden === true) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wf?.backup_config?.onprem_backup === true) {
|
||||||
|
backupWf.push(wf)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
newarray.push(wf)
|
newarray.push(wf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (backupWf.length > 0) {
|
||||||
|
setBackupWorkflows(backupWf)
|
||||||
|
}
|
||||||
|
|
||||||
var setProdFilter = false
|
var setProdFilter = false
|
||||||
|
|
||||||
var actionnamelist = [];
|
var actionnamelist = [];
|
||||||
@@ -2073,7 +2095,7 @@ const Workflows2 = (props) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bulk !== true) {
|
if (bulk !== true) {
|
||||||
toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`)
|
toast.success(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2087,7 +2109,7 @@ const Workflows2 = (props) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast(error.toString());
|
toast.error(error.toString());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3040,7 +3062,7 @@ const Workflows2 = (props) => {
|
|||||||
data.status,
|
data.status,
|
||||||
).then((response) => {
|
).then((response) => {
|
||||||
if (response !== undefined) {
|
if (response !== undefined) {
|
||||||
toast("Successfully imported " + data.name);
|
toast.success("Imported " + data.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -4322,6 +4344,17 @@ const Workflows2 = (props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{backupWorkflows.length > 0 &&
|
||||||
|
<Tab
|
||||||
|
label={`Onprem Backup (${backupWorkflows.length})`}
|
||||||
|
style={{
|
||||||
|
...tabStyle,
|
||||||
|
marginLeft: 25,
|
||||||
|
...(currTab === 3 ? tabActive : {})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label="Org Forms"
|
label="Org Forms"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -4331,7 +4364,7 @@ const Workflows2 = (props) => {
|
|||||||
...tabStyle,
|
...tabStyle,
|
||||||
marginRight: 0,
|
marginRight: 0,
|
||||||
marginLeft: 25,
|
marginLeft: 25,
|
||||||
...(currTab === 3 ? tabActive : {})
|
...(currTab === 4 ? tabActive : {})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
@@ -4666,8 +4699,6 @@ const Workflows2 = (props) => {
|
|||||||
paddingBottom: 40
|
paddingBottom: 40
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{currTab === 0 && orgWorkflows.map((data, index) => {
|
{currTab === 0 && orgWorkflows.map((data, index) => {
|
||||||
// Shouldn't be a part of this list
|
// Shouldn't be a part of this list
|
||||||
if (data.public === true) {
|
if (data.public === true) {
|
||||||
@@ -4689,6 +4720,27 @@ const Workflows2 = (props) => {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
{currTab === 3 && backupWorkflows.map((data, index) => {
|
||||||
|
// Shouldn't be a part of this list
|
||||||
|
if (data.public === true) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (firstLoad) {
|
||||||
|
// workflowDelay += 75
|
||||||
|
// } else {
|
||||||
|
// return <WorkflowPaper key={index} data={data} />
|
||||||
|
// }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span key={index}>
|
||||||
|
{/*<Zoom key={index} in={true} style={{ transitionDelay: `${workflowDelay}ms` }}>*/}
|
||||||
|
<WorkflowPaper data={data} />
|
||||||
|
{/*</Zoom>*/}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
{
|
{
|
||||||
currTab === 1 && myWorkflows.map((data, index) => {
|
currTab === 1 && myWorkflows.map((data, index) => {
|
||||||
if (data.public === true) {
|
if (data.public === true) {
|
||||||
@@ -5134,7 +5186,9 @@ const Workflows2 = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
<Typography>Loading Workflows</Typography>
|
<Typography style={{marginTop: 5, }}>
|
||||||
|
Loading Workflows and Apps
|
||||||
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -610,13 +610,31 @@ func deployServiceWorkers(image string) {
|
|||||||
|
|
||||||
if defaultNetworkAttach == true || strings.ToLower(os.Getenv("SHUFFLE_DEFAULT_NETWORK_ATTACH")) == "true" {
|
if defaultNetworkAttach == true || strings.ToLower(os.Getenv("SHUFFLE_DEFAULT_NETWORK_ATTACH")) == "true" {
|
||||||
targetName := "shuffle_shuffle"
|
targetName := "shuffle_shuffle"
|
||||||
log.Printf("[DEBUG] Adding network attach for network %s to worker in swarm", targetName)
|
isAttachable := false
|
||||||
serviceSpec.Networks = append(serviceSpec.Networks, swarm.NetworkAttachmentConfig{
|
networks, err := dockercli.NetworkList(ctx, network.ListOptions{})
|
||||||
Target: targetName,
|
if err == nil {
|
||||||
})
|
for _, net := range networks {
|
||||||
|
if net.Name == targetName {
|
||||||
|
if net.Scope == "swarm" {
|
||||||
|
log.Printf("[DEBUG] Found swarm-scoped network: %s", targetName)
|
||||||
|
isAttachable = true
|
||||||
|
} else {
|
||||||
|
log.Printf("[WARNING] Network %s exist but is not swarm scoped (scope=%s)", targetName, net.Scope)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXM: Remove this if deployment fails?
|
if isAttachable {
|
||||||
serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("SHUFFLE_SWARM_OTHER_NETWORK=%s", targetName))
|
log.Printf("[DEBUG] Adding network attach for network %s to worker in swarm", targetName)
|
||||||
|
serviceSpec.Networks = append(serviceSpec.Networks, swarm.NetworkAttachmentConfig{
|
||||||
|
Target: targetName,
|
||||||
|
})
|
||||||
|
|
||||||
|
// FIXM: Remove this if deployment fails?
|
||||||
|
serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("SHUFFLE_SWARM_OTHER_NETWORK=%s", targetName))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dockerApiVersion != "" {
|
if dockerApiVersion != "" {
|
||||||
@@ -709,6 +727,34 @@ func deployServiceWorkers(image string) {
|
|||||||
} else {
|
} else {
|
||||||
if !strings.Contains(fmt.Sprintf("%s", err), "Already Exists") && !strings.Contains(fmt.Sprintf("%s", err), "is already in use by service") {
|
if !strings.Contains(fmt.Sprintf("%s", err), "Already Exists") && !strings.Contains(fmt.Sprintf("%s", err), "is already in use by service") {
|
||||||
log.Printf("[ERROR] Failed making service: %s", err)
|
log.Printf("[ERROR] Failed making service: %s", err)
|
||||||
|
if strings.Contains(fmt.Sprintf("%s", err), "networks scoped to the swarm can be used") {
|
||||||
|
log.Printf("[WARNING] Swarm network attachment failed, retrying without shuffle_shuffle")
|
||||||
|
|
||||||
|
var updatedNetworks []swarm.NetworkAttachmentConfig
|
||||||
|
for _, net := range serviceSpec.Networks {
|
||||||
|
if net.Target != "shuffle_shuffle" {
|
||||||
|
updatedNetworks = append(updatedNetworks, net)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceSpec.Networks = updatedNetworks
|
||||||
|
|
||||||
|
var updatedEnv []string
|
||||||
|
for _, env := range serviceSpec.TaskTemplate.ContainerSpec.Env {
|
||||||
|
if !strings.HasPrefix(env, "SHUFFLE_SWARM_OTHER_NETWORK=") {
|
||||||
|
updatedEnv = append(updatedEnv, env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceSpec.TaskTemplate.ContainerSpec.Env = updatedEnv
|
||||||
|
serviceOptions := types.ServiceCreateOptions{}
|
||||||
|
_, err = dockercli.ServiceCreate(
|
||||||
|
ctx,
|
||||||
|
serviceSpec,
|
||||||
|
serviceOptions,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to deploy service even without shuffle_shuffle network: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[WARNING] Failed deploying workers: %s", err)
|
log.Printf("[WARNING] Failed deploying workers: %s", err)
|
||||||
if len(serviceSpec.Networks) > 1 {
|
if len(serviceSpec.Networks) > 1 {
|
||||||
|
|||||||
Reference in New Issue
Block a user