Merge pull request #126 from frikky/1.0.0

0.6.5
This commit is contained in:
Frikky
2020-08-24 19:37:33 +02:00
committed by GitHub
13 changed files with 1056 additions and 299 deletions
+3 -2
View File
@@ -3,9 +3,10 @@ ORG_ID=Shuffle
ENVIRONMENT_NAME=Shuffle
# Remote github config for first load
SHUFFLE_DOWNLOAD_WORKFLOW_LOCATION=
SHUFFLE_DOWNLOAD_AUTH_USERNAME=
SHUFFLE_DOWNLOAD_AUTH_PASSWORD=
APP_DOWNLOAD_LOCATION=https://github.com/frikky/shuffle-apps
APP_DOWNLOAD_AUTH_USERNAME=
APP_DOWNLOAD_AUTH_PASSWORD=
# User config for first load. Username & PW: min length 3
SHUFFLE_DEFAULT_USERNAME=
+41 -10
View File
@@ -254,11 +254,14 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
if len(optionalQueries) > 0 {
queryString += ", "
for _, query := range optionalQueries {
// Check if it's a part of the URL already
queryString += fmt.Sprintf("%s=\"\", ", query)
queryData += fmt.Sprintf(`
if %s:
url += f"&%s={%s}"`, query, query, query)
}
} else {
//log.Printf("No optional queries?")
}
// api.Authentication.Parameters[0].Value = "BearerAuth"
@@ -398,7 +401,7 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
verifyAddin,
)
//log.Printf("%s", data)
//log.Printf(data)
return functionname, data
}
@@ -594,10 +597,10 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger,
pythonFunctions := []string{}
for actualPath, path := range swagger.Paths {
actualPath = strings.Replace(actualPath, " ", "_", -1)
actualPath = strings.Replace(actualPath, ".", "", -1)
actualPath = strings.Replace(actualPath, ".", "", -1)
//actualPath = strings.Replace(actualPath, ".", "", -1)
actualPath = strings.Replace(actualPath, "\\", "", -1)
// FIXME: Handle everything behind questionmark (?) with dots as well.
// https://godoc.org/github.com/getkin/kin-openapi/openapi3#PathItem
if path.Get != nil {
action, curCode := handleGet(swagger, api, extraParameters, path, actualPath)
@@ -936,7 +939,11 @@ func handleConnect(swagger *openapi3.Swagger, api WorkflowApp, extraParameters [
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
@@ -1081,7 +1088,11 @@ func handleGet(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
@@ -1224,7 +1235,11 @@ func handleHead(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
@@ -1368,7 +1383,11 @@ func handleDelete(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
@@ -1511,7 +1530,11 @@ func handlePost(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wo
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
@@ -1654,7 +1677,11 @@ func handlePatch(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []W
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
@@ -1797,7 +1824,11 @@ func handlePut(swagger *openapi3.Swagger, api WorkflowApp, extraParameters []Wor
continue
}
if firstQuery {
if strings.Contains(baseUrl, fmt.Sprintf("{%s}", param.Value.Name)) {
continue
}
if firstQuery && !strings.Contains(baseUrl, "?") {
baseUrl = fmt.Sprintf("%s?%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
} else {
baseUrl = fmt.Sprintf("%s&%s={%s}", baseUrl, param.Value.Name, param.Value.Name)
+53 -12
View File
@@ -158,6 +158,9 @@ type Environment struct {
Name string `datastore:"name"`
Type string `datastore:"type"`
Registered bool `datastore:"registered"`
Default bool `datastore:"default" json:"default"`
Archived bool `datastore:"archived" json:"archived"`
Id string `datastore:"id" json:"id"`
}
type User struct {
@@ -1053,16 +1056,29 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) {
return
}
// Clear old data
for _, item := range environments {
err = DeleteKey(ctx, "Environments", item.Name)
if err != nil {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Error cleaning up environment"}`))
return
// Clear old data? Removed for archiving purpose. No straight deletion
//for _, item := range environments {
// err = DeleteKey(ctx, "Environments", item.Name)
// if err != nil {
// resp.WriteHeader(401)
// resp.Write([]byte(`{"success": false, "reason": "Error cleaning up environment"}`))
// return
// }
//}
openEnvironments := 0
for _, item := range newEnvironments {
if !item.Archived {
openEnvironments += 1
}
}
if openEnvironments < 1 {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Can't archived all environments"}`))
return
}
for _, item := range newEnvironments {
err = setEnvironment(ctx, &item)
if err != nil {
@@ -1072,9 +1088,10 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) {
}
}
//DeleteKey(ctx, entity string, value string) error {
// FIXME - check which are in use
log.Printf("FIXME: Set new environments: %#v", newEnvironments)
log.Printf("DONT DELETE ONES THAT ARE IN USE")
//log.Printf("FIXME: Set new environments: %#v", newEnvironments)
//log.Printf("DONT DELETE ONES THAT ARE IN USE")
resp.WriteHeader(200)
resp.Write([]byte(`{"success": true}`))
@@ -5995,7 +6012,7 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) {
if err != nil {
log.Printf("Docker build error: %s", err)
resp.WriteHeader(500)
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "Error in Docker build"}`)))
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Error in Docker build"}`)))
return
}
@@ -6327,8 +6344,8 @@ func runInit(ctx context.Context) {
url = "https://github.com/frikky/shuffle-apps"
}
username := os.Getenv("APP_DOWNLOAD_AUTH_USERNAME")
password := os.Getenv("APP_DOWNLOAD_AUTH_PASSWORD")
username := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_USERNAME")
password := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_PASSWORD")
cloneOptions := &git.CloneOptions{
URL: url,
}
@@ -6388,6 +6405,30 @@ func runInit(ctx context.Context) {
log.Printf("Finished downloading extra API samples")
}
workflowLocation := os.Getenv("SHUFFLE_DOWNLOAD_WORKFLOW_LOCATION")
if len(workflowLocation) > 0 {
log.Printf("Downloading WORKFLOWS from %s if no workflows - EXTRA workflows", workflowLocation)
q := datastore.NewQuery("workflow")
var workflows []Workflow
_, err = dbclient.GetAll(ctx, q, &workflows)
if err != nil {
log.Printf("Error getting workflows: %s", err)
} else {
if len(workflows) == 0 {
username := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_USERNAME")
password := os.Getenv("SHUFFLE_DOWNLOAD_AUTH_PASSWORD")
err = loadGithubWorkflows(workflowLocation, username, password, "")
if err != nil {
log.Printf("Failed to upload workflows from github: %s", err)
} else {
log.Printf("Finished downloading workflows from github!")
}
} else {
log.Printf("Skipping because there are %d workflows already", len(workflows))
}
}
}
log.Printf("Finished INIT")
}
+95 -63
View File
@@ -120,6 +120,8 @@ type WorkflowApp struct {
} `json:"contact_info" datastore:"contact_info" yaml:"contact_info" required:false`
Actions []WorkflowAppAction `json:"actions" yaml:"actions" required:true datastore:"actions,noindex"`
Authentication Authentication `json:"authentication" yaml:"authentication" required:false datastore:"authentication"`
Tags []string `json:"tags" yaml:"tags" required:false datastore:"activated"`
Category []string `json:"category" yaml:"category" required:false datastore:"category"`
}
type WorkflowAppActionParameter struct {
@@ -129,6 +131,7 @@ type WorkflowAppActionParameter struct {
Example string `json:"example" datastore:"example" yaml:"example"`
Value string `json:"value" datastore:"value" yaml:"value,omitempty"`
Multiline bool `json:"multiline" datastore:"multiline" yaml:"multiline"`
Options []string `json:"options" datastore:"options" yaml:"options"`
ActionField string `json:"action_field" datastore:"action_field" yaml:"actionfield,omitempty"`
Variant string `json:"variant" datastore:"variant" yaml:"variant,omitempty"`
Required bool `json:"required" datastore:"required" yaml:"required"`
@@ -192,7 +195,7 @@ type WorkflowExecution struct {
Description string `json:"description" datastore:"description"`
ID string `json:"id" datastore:"id"`
Name string `json:"name" datastore:"name"`
Value string `json:"value" datastore:"value"`
Value string `json:"value" datastore:"value,noindex"`
} `json:"execution_variables,omitempty" datastore:"execution_variables,omitempty"`
}
@@ -217,7 +220,7 @@ type Action struct {
Description string `json:"description" datastore:"description"`
ID string `json:"id" datastore:"id"`
Name string `json:"name" datastore:"name"`
Value string `json:"value" datastore:"value"`
Value string `json:"value" datastore:"value,noindex"`
} `json:"execution_variable,omitempty" datastore:"execution_variable,omitempty"`
Position struct {
X float64 `json:"x" datastore:"x"`
@@ -307,7 +310,7 @@ type Workflow struct {
Description string `json:"description" datastore:"description"`
ID string `json:"id" datastore:"id"`
Name string `json:"name" datastore:"name"`
Value string `json:"value" datastore:"value"`
Value string `json:"value" datastore:"value,noindex"`
} `json:"execution_variables,omitempty" datastore:"execution_variables"`
}
@@ -1121,6 +1124,10 @@ func getWorkflows(resp http.ResponseWriter, request *http.Request) {
// With user, do a search for workflows with user or user's org attached
q := datastore.NewQuery("workflow").Filter("owner =", user.Id)
if user.Role == "admin" {
q = datastore.NewQuery("workflow")
}
var workflows []Workflow
_, err = dbclient.GetAll(ctx, q, &workflows)
if err != nil {
@@ -1236,11 +1243,16 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) {
workflowapps, err := getAllWorkflowApps(ctx)
if err == nil {
// FIXME: Add real env
//q := datastore.NewQuery("Environments").Limit(1)
//count, err := dbclient.Get(ctx, q)
//envName := "Shuffle"
//if err == nil {
//}
envName := "Shuffle"
environments, err := getEnvironments(ctx)
if err == nil {
for _, env := range environments {
if env.Default {
envName = env.Name
break
}
}
}
for _, item := range workflowapps {
if item.Name == "Testing" && item.AppVersion == "1.0.0" {
@@ -1249,7 +1261,7 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) {
newActions = append(newActions, Action{
Label: "Start node",
Name: "hello_world",
Environment: "Shuffle",
Environment: envName,
Parameters: []WorkflowAppActionParameter{},
Position: struct {
X float64 "json:\"x\" datastore:\"x\""
@@ -3100,6 +3112,18 @@ func getWorkflow(ctx context.Context, id string) (*Workflow, error) {
return workflow, nil
}
func getEnvironments(ctx context.Context) ([]Environment, error) {
var environments []Environment
q := datastore.NewQuery("Environments")
_, err := dbclient.GetAll(ctx, q, &environments)
if err != nil {
return []Environment{}, err
}
return environments, nil
}
func getAllWorkflows(ctx context.Context) ([]Workflow, error) {
var allworkflows []Workflow
q := datastore.NewQuery("workflow")
@@ -4045,6 +4069,62 @@ func deployWebhookFunction(ctx context.Context, name, localization, applocation
return nil
}
func loadGithubWorkflows(url, username, password, userId string) error {
fs := memfs.New()
if strings.Contains(url, "github") || strings.Contains(url, "gitlab") || strings.Contains(url, "bitbucket") {
cloneOptions := &git.CloneOptions{
URL: url,
}
// FIXME: Better auth.
if len(username) > 0 && len(password) > 0 {
cloneOptions.Auth = &http2.BasicAuth{
Username: username,
Password: password,
}
}
storer := memory.NewStorage()
r, err := git.Clone(storer, fs, cloneOptions)
if err != nil {
log.Printf("Failed loading repo into memory: %s", err)
return err
}
dir, err := fs.ReadDir("/")
if err != nil {
log.Printf("FAiled reading folder: %s", err)
}
_ = r
log.Printf("Starting workflow folder iteration")
iterateWorkflowGithubFolders(fs, dir, "", "", userId)
} else if strings.Contains(url, "s3") {
//https://docs.aws.amazon.com/sdk-for-go/api/service/s3/
//sess := session.Must(session.NewSession())
//downloader := s3manager.NewDownloader(sess)
//// Write the contents of S3 Object to the file
//storer := memory.NewStorage()
//n, err := downloader.Download(storer, &s3.GetObjectInput{
// Bucket: aws.String(myBucket),
// Key: aws.String(myString),
//})
//if err != nil {
// return fmt.Errorf("failed to download file, %v", err)
//}
//fmt.Printf("file downloaded, %d bytes\n", n)
} else {
return errors.New(fmt.Sprintf("URL %s is unsupported when downloading workflows", url))
}
return nil
}
func loadSpecificWorkflows(resp http.ResponseWriter, request *http.Request) {
cors := handleCors(resp, request)
if cors {
@@ -4064,7 +4144,7 @@ func loadSpecificWorkflows(resp http.ResponseWriter, request *http.Request) {
if user.Role != "admin" {
log.Printf("Wrong user (%s) when downloading from github", user.Username)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
resp.Write([]byte(`{"success": false, "reason": "Downloading remotely requires admin"}`))
return
}
@@ -4093,59 +4173,11 @@ func loadSpecificWorkflows(resp http.ResponseWriter, request *http.Request) {
return
}
fs := memfs.New()
if strings.Contains(tmpBody.URL, "github") || strings.Contains(tmpBody.URL, "gitlab") || strings.Contains(tmpBody.URL, "bitbucket") {
cloneOptions := &git.CloneOptions{
URL: tmpBody.URL,
}
// FIXME: Better auth.
if len(tmpBody.Field1) > 0 && len(tmpBody.Field2) > 0 {
cloneOptions.Auth = &http2.BasicAuth{
Username: tmpBody.Field1,
Password: tmpBody.Field2,
}
}
storer := memory.NewStorage()
r, err := git.Clone(storer, fs, cloneOptions)
if err != nil {
log.Printf("Failed loading repo into memory: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
return
}
dir, err := fs.ReadDir("/")
if err != nil {
log.Printf("FAiled reading folder: %s", err)
}
_ = r
log.Printf("Starting workflow folder iteration")
iterateWorkflowGithubFolders(fs, dir, "", "", user.Id)
} else if strings.Contains(tmpBody.URL, "s3") {
//https://docs.aws.amazon.com/sdk-for-go/api/service/s3/
//sess := session.Must(session.NewSession())
//downloader := s3manager.NewDownloader(sess)
//// Write the contents of S3 Object to the file
//storer := memory.NewStorage()
//n, err := downloader.Download(storer, &s3.GetObjectInput{
// Bucket: aws.String(myBucket),
// Key: aws.String(myString),
//})
//if err != nil {
// return fmt.Errorf("failed to download file, %v", err)
//}
//fmt.Printf("file downloaded, %d bytes\n", n)
} else {
err = loadGithubWorkflows(tmpBody.URL, tmpBody.Field1, tmpBody.Field2, user.Id)
if err != nil {
log.Printf("Failed to update workflows: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s is unsupported. Try e.g. github"}`, tmpBody.URL)))
resp.Write([]byte(`{"success": false}`))
return
}
@@ -4489,7 +4521,7 @@ func iterateWorkflowGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra
log.Printf("Failed setting (download) workflow: %s", err)
continue
}
log.Printf("Uploaded workflow %s!", filename)
log.Printf("Uploaded workflow %s for user %s!", filename, userId)
}
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ services:
depends_on:
- backend
backend:
build: ./backend
#build: ./backend
image: frikky/shuffle:backend
container_name: shuffle-backend
hostname: ${BACKEND_HOSTNAME}
+6
View File
@@ -2,8 +2,10 @@
FROM node as builder
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json /usr/src/app/package.json
RUN npm install --verbose
@@ -15,6 +17,10 @@ COPY ./src /usr/src/app/src/
COPY ./*.sh /usr/src/app/
COPY ./*.json /usr/src/app/
# There were issues with the webpack installer from package.json
RUN rm -rf /usr/src/app/node_modules/webpack
RUN npm install webpack@4.42.0
RUN npm run-script build
# Production environment
+396 -43
View File
@@ -4332,13 +4332,14 @@
}
},
"asn1.js": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
"integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
"requires": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
"minimalistic-assert": "^1.0.0",
"safer-buffer": "^2.1.0"
},
"dependencies": {
"bn.js": {
@@ -5265,9 +5266,9 @@
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"bn.js": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz",
"integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA=="
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
"integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ=="
},
"body-parser": {
"version": "1.19.0",
@@ -5438,15 +5439,15 @@
}
},
"browserify-sign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz",
"integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
"integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
"requires": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"elliptic": "^6.5.2",
"elliptic": "^6.5.3",
"inherits": "^2.0.4",
"parse-asn1": "^5.1.5",
"readable-stream": "^3.6.0",
@@ -5868,9 +5869,9 @@
}
},
"class-transformer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.2.3.tgz",
"integrity": "sha512-qsP+0xoavpOlJHuYsQJsN58HXSl8Jvveo+T37rEvCEeRfMWoytAyR0Ua/YsFgpM6AZYZ/og2PJwArwzJl1aXtQ=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz",
"integrity": "sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA=="
},
"class-utils": {
"version": "0.3.6",
@@ -6341,12 +6342,12 @@
}
},
"create-ecdh": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
"integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
"integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
"requires": {
"bn.js": "^4.1.0",
"elliptic": "^6.0.0"
"elliptic": "^6.5.3"
},
"dependencies": {
"bn.js": {
@@ -7558,9 +7559,9 @@
"integrity": "sha512-vcTeLpPm4+ccoYFXnepvkFt0KujdyrBU19KNEO40Pnkhta6mUi2K0Dn7NmpRcNz7BvysnSqeuIYScP003HWuYg=="
},
"elliptic": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
"integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
@@ -7610,9 +7611,9 @@
}
},
"enhanced-resolve": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz",
"integrity": "sha512-S7eiFb/erugyd1rLb6mQ3Vuq+EXHv5cpCkNqqIkYkBgN2QdFnyCZzFBleqwGEx4lgNGYij81BWnCrFNK7vxvjQ==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz",
"integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==",
"requires": {
"graceful-fs": "^4.1.2",
"memory-fs": "^0.5.0",
@@ -8250,9 +8251,9 @@
"integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ=="
},
"events": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
"integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg=="
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
"integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg=="
},
"eventsource": {
"version": "1.0.7",
@@ -13442,13 +13443,12 @@
}
},
"parse-asn1": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
"integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==",
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
"integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
"requires": {
"asn1.js": "^4.0.0",
"asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0",
"create-hash": "^1.1.0",
"evp_bytestokey": "^1.0.0",
"pbkdf2": "^3.0.3",
"safe-buffer": "^5.1.1"
@@ -15566,11 +15566,205 @@
"workbox-webpack-plugin": "4.3.1"
},
"dependencies": {
"@webassemblyjs/ast": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
"integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==",
"requires": {
"@webassemblyjs/helper-module-context": "1.8.5",
"@webassemblyjs/helper-wasm-bytecode": "1.8.5",
"@webassemblyjs/wast-parser": "1.8.5"
}
},
"@webassemblyjs/floating-point-hex-parser": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz",
"integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ=="
},
"@webassemblyjs/helper-api-error": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz",
"integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA=="
},
"@webassemblyjs/helper-buffer": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz",
"integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q=="
},
"@webassemblyjs/helper-code-frame": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz",
"integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==",
"requires": {
"@webassemblyjs/wast-printer": "1.8.5"
}
},
"@webassemblyjs/helper-fsm": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz",
"integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow=="
},
"@webassemblyjs/helper-module-context": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz",
"integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"mamacro": "^0.0.3"
}
},
"@webassemblyjs/helper-wasm-bytecode": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz",
"integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ=="
},
"@webassemblyjs/helper-wasm-section": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz",
"integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/helper-buffer": "1.8.5",
"@webassemblyjs/helper-wasm-bytecode": "1.8.5",
"@webassemblyjs/wasm-gen": "1.8.5"
}
},
"@webassemblyjs/ieee754": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz",
"integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==",
"requires": {
"@xtuc/ieee754": "^1.2.0"
}
},
"@webassemblyjs/leb128": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz",
"integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==",
"requires": {
"@xtuc/long": "4.2.2"
}
},
"@webassemblyjs/utf8": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz",
"integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw=="
},
"@webassemblyjs/wasm-edit": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz",
"integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/helper-buffer": "1.8.5",
"@webassemblyjs/helper-wasm-bytecode": "1.8.5",
"@webassemblyjs/helper-wasm-section": "1.8.5",
"@webassemblyjs/wasm-gen": "1.8.5",
"@webassemblyjs/wasm-opt": "1.8.5",
"@webassemblyjs/wasm-parser": "1.8.5",
"@webassemblyjs/wast-printer": "1.8.5"
}
},
"@webassemblyjs/wasm-gen": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz",
"integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/helper-wasm-bytecode": "1.8.5",
"@webassemblyjs/ieee754": "1.8.5",
"@webassemblyjs/leb128": "1.8.5",
"@webassemblyjs/utf8": "1.8.5"
}
},
"@webassemblyjs/wasm-opt": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz",
"integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/helper-buffer": "1.8.5",
"@webassemblyjs/wasm-gen": "1.8.5",
"@webassemblyjs/wasm-parser": "1.8.5"
}
},
"@webassemblyjs/wasm-parser": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz",
"integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/helper-api-error": "1.8.5",
"@webassemblyjs/helper-wasm-bytecode": "1.8.5",
"@webassemblyjs/ieee754": "1.8.5",
"@webassemblyjs/leb128": "1.8.5",
"@webassemblyjs/utf8": "1.8.5"
}
},
"@webassemblyjs/wast-parser": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz",
"integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/floating-point-hex-parser": "1.8.5",
"@webassemblyjs/helper-api-error": "1.8.5",
"@webassemblyjs/helper-code-frame": "1.8.5",
"@webassemblyjs/helper-fsm": "1.8.5",
"@xtuc/long": "4.2.2"
}
},
"@webassemblyjs/wast-printer": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz",
"integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/wast-parser": "1.8.5",
"@xtuc/long": "4.2.2"
}
},
"acorn": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
},
"cacache": {
"version": "12.0.4",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
"integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
"requires": {
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
},
"eslint-scope": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
"integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
"requires": {
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -15586,10 +15780,102 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"requires": {
"yallist": "^3.0.2"
}
},
"schema-utils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"requires": {
"ajv": "^6.1.0",
"ajv-errors": "^1.0.0",
"ajv-keywords": "^3.1.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"requires": {
"randombytes": "^2.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"ssri": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
"requires": {
"figgy-pudding": "^3.5.1"
}
},
"webpack": {
"version": "4.42.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz",
"integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==",
"requires": {
"@webassemblyjs/ast": "1.8.5",
"@webassemblyjs/helper-module-context": "1.8.5",
"@webassemblyjs/wasm-edit": "1.8.5",
"@webassemblyjs/wasm-parser": "1.8.5",
"acorn": "^6.2.1",
"ajv": "^6.10.2",
"ajv-keywords": "^3.4.1",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^4.1.0",
"eslint-scope": "^4.0.3",
"json-parse-better-errors": "^1.0.2",
"loader-runner": "^2.4.0",
"loader-utils": "^1.2.3",
"memory-fs": "^0.4.1",
"micromatch": "^3.1.10",
"mkdirp": "^0.5.1",
"neo-async": "^2.6.1",
"node-libs-browser": "^2.2.1",
"schema-utils": "^1.0.0",
"tapable": "^1.1.3",
"terser-webpack-plugin": "^1.4.3",
"watchpack": "^1.6.0",
"webpack-sources": "^1.4.1"
},
"dependencies": {
"terser-webpack-plugin": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
"integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
"requires": {
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^4.0.0",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
}
}
}
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
},
@@ -18337,14 +18623,81 @@
}
},
"watchpack": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz",
"integrity": "sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==",
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",
"integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==",
"requires": {
"chokidar": "^3.4.0",
"chokidar": "^3.4.1",
"graceful-fs": "^4.1.2",
"neo-async": "^2.5.0",
"watchpack-chokidar2": "^2.0.0"
},
"dependencies": {
"anymatch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"optional": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"optional": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"chokidar": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
"integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
"optional": true,
"requires": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
"fsevents": "~2.1.2",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.4.0"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"optional": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"optional": true
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"optional": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"optional": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"watchpack-chokidar2": {
@@ -18574,9 +18927,9 @@
}
},
"serialize-javascript": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz",
"integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"requires": {
"randombytes": "^2.1.0"
}
@@ -18595,15 +18948,15 @@
}
},
"terser-webpack-plugin": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz",
"integrity": "sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==",
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
"integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
"requires": {
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^3.1.0",
"serialize-javascript": "^4.0.0",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
+2 -1
View File
@@ -8,7 +8,7 @@
"@material-ui/icons": "^4.5.1",
"@material-ui/styles": "^4.5.2",
"@use-it/interval": "^0.1.3",
"class-transformer": "^0.3.1",
"class-transformer": "^0.3.1",
"create-react-app": "^2.0.3",
"cytoscape": "^3.11.0",
"cytoscape-clipboard": "^2.2.1",
@@ -54,6 +54,7 @@
"shellwords": "^0.1.1",
"simplebar": "^4.2.3",
"styled-components": "^4.4.0",
"webpack": "^4.42.0",
"websocket": "^1.0.30",
"yaml": "^1.7.2",
"yamljs": "^0.3.0",
+101 -11
View File
@@ -47,6 +47,7 @@ const Admin = (props) => {
const [selectedUserModalOpen, setSelectedUserModalOpen] = React.useState(false)
const [selectedAuthentication, setSelectedAuthentication] = React.useState({})
const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false)
const [showArchived, setShowArchived] = React.useState(false)
const alert = useAlert()
@@ -129,7 +130,8 @@ const Admin = (props) => {
if (responseJson["success"] === false) {
alert.error("Failed setting new password")
} else {
alert.success("Changed password!")
alert.success("Successfully password!")
setSelectedUserModalOpen(false)
}
}),
)
@@ -169,7 +171,6 @@ const Admin = (props) => {
}
const submitUser = (data) => {
// FIXME - add some check here ROFL
console.log("INPUT: ", data)
// Just use this one?
@@ -200,13 +201,21 @@ const Admin = (props) => {
});
}
const deleteEnvironment = (name) => {
// Horrible frontend fix for environments
const setDefaultEnvironment = (name) => {
// FIXME - add some check here ROFL
alert.info("Deleting environment " + name)
alert.info("Setting default env to " + name)
var newEnv = []
for (var key in environments) {
if (environments[key].Name == name) {
continue
if (environments[key].archived) {
alert.error("Can't set archived to default")
return
}
environments[key].default = true
} else if (environments[key].default == true && environments[key].name !== name) {
environments[key].default = false
}
newEnv.push(environments[key])
@@ -226,6 +235,7 @@ const Admin = (props) => {
response.json().then(responseJson => {
if (responseJson["success"] === false) {
alert.error(responseJson.reason)
getEnvironments()
} else {
setLoginInfo("")
setModalOpen(false)
@@ -233,14 +243,60 @@ const Admin = (props) => {
}
}),
)
//.catch(error => {
// console.log("Error in userdata: ", error)
//});
.catch(error => {
console.log("Error in backend data: ", error)
})
}
const deleteEnvironment = (name) => {
// FIXME - add some check here ROFL
alert.info("Deleting environment " + name)
var newEnv = []
for (var key in environments) {
if (environments[key].Name == name) {
if (environments[key].default) {
alert.info("Can't delete the default environment")
return
}
environments[key].archived = true
}
newEnv.push(environments[key])
}
// Just use this one?
const url = globalUrl + '/api/v1/setenvironments';
fetch(url, {
method: 'PUT',
credentials: "include",
body: JSON.stringify(newEnv),
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
alert.error(responseJson.reason)
getEnvironments()
} else {
setLoginInfo("")
setModalOpen(false)
getEnvironments()
}
}),
)
.catch(error => {
console.log("Error when deleting: ", error)
})
}
const submitEnvironment = (data) => {
// FIXME - add some check here ROFL
environments.push({ "name": data.environment, "type": "onprem" })
environments.push({
"name": data.environment,
"type": "onprem",
})
// Just use this one?
var baseurl = globalUrl
@@ -257,6 +313,7 @@ const Admin = (props) => {
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setLoginInfo("Error in input: " + responseJson.reason)
getEnvironments()
} else {
setLoginInfo("")
setModalOpen(false)
@@ -342,7 +399,6 @@ const Admin = (props) => {
return response.json()
})
.then((responseJson) => {
console.log(responseJson)
setEnvironments(responseJson)
})
.catch(error => {
@@ -934,6 +990,7 @@ const Admin = (props) => {
</div>
: null
console.log("Environments: ", environments)
const environmentView = curTab === 2 ?
<div>
<div style={{marginTop: 20, marginBottom: 20,}}>
@@ -967,12 +1024,29 @@ const Admin = (props) => {
primary="Orborus running (TBD)"
style={{minWidth: 200, maxWidth: 200}}
/>
<ListItemText
primary="Default"
style={{minWidth: 150, maxWidth: 150}}
/>
<ListItemText
primary="Actions"
style={{minWidth: 150, maxWidth: 150}}
/>
<ListItemText
primary="Archived"
style={{minWidth: 150, maxWidth: 150}}
/>
</ListItem>
{environments === undefined ? null : environments.map(environment => {
if (!showArchived && environment.archived) {
return null
}
if (environment.archived === undefined) {
getEnvironments()
return null
}
return (
<ListItem>
<ListItemText
@@ -983,9 +1057,25 @@ const Admin = (props) => {
primary={"TBD"}
style={{minWidth: 200, maxWidth: 200, overflow: "hidden"}}
/>
<ListItemText>
<ListItemText
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
primary={environment.default ? "true" : null}
>
{environment.default ?
null
:
<Button variant="outlined" style={{borderRadius: "0px"}} onClick={() => setDefaultEnvironment(environment.Name)} color="primary">Set default</Button>
}
</ListItemText>
<ListItemText
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
>
<Button variant="outlined" style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment.Name)} color="primary">Delete</Button>
</ListItemText>
<ListItemText
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
primary={environment.archived.toString()}
/>
</ListItem>
)
})}
File diff suppressed because one or more lines are too long
+29 -10
View File
@@ -20,6 +20,7 @@ import Tooltip from '@material-ui/core/Tooltip';
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
import AppsIcon from '@material-ui/icons/Apps';
import CircularProgress from '@material-ui/core/CircularProgress';
import ErrorOutline from '@material-ui/icons/ErrorOutline';
import { useAlert } from "react-alert";
@@ -210,6 +211,7 @@ const AppCreator = (props) => {
const [, setBasedata] = React.useState({})
const [actions, setActions] = useState([])
const [errorCode, setErrorCode] = useState("")
const [appBuilding, setAppBuilding] = useState(false)
//const [actions, setActions] = useState([{
// "name": "Get workflows",
@@ -279,9 +281,9 @@ const AppCreator = (props) => {
return response.json()
})
.then((responseJson) => {
setIsAppLoaded(true)
if (!responseJson.success) {
alert.error("Failed to get the app")
setIsAppLoaded(true)
} else {
const data = JSON.parse(responseJson.body)
parseIncomingOpenapiData(data)
@@ -365,6 +367,8 @@ const AppCreator = (props) => {
var firstUrl = data.servers[0].url
if (firstUrl.endsWith("/")) {
setBaseUrl(firstUrl.slice(0, firstUrl.length-1))
} else {
setBaseUrl(firstUrl)
}
}
@@ -378,9 +382,6 @@ const AppCreator = (props) => {
securitySchemes = data.components.securitySchemes
}
console.log(data)
// FIXME - headers?
var newActions = []
var wordlist = {}
@@ -398,7 +399,6 @@ const AppCreator = (props) => {
"errors": [],
}
for (var key in methodvalue.parameters) {
const parameter = methodvalue.parameters[key]
if (parameter.in === "query") {
@@ -520,11 +520,13 @@ const AppCreator = (props) => {
}
setActions(newActions)
setIsAppLoaded(true)
}
// Saving the app that's been configured.
const submitApp = () => {
alert.info("Uploading and building app " + name)
setAppBuilding(true)
setErrorCode("")
// Format the information
@@ -718,6 +720,7 @@ const AppCreator = (props) => {
if (authenticationOption === "API key") {
if (parameterName.length === 0) {
alert.error("A field name for the APIkey must be defined")
setAppBuilding(false)
return
}
@@ -757,6 +760,7 @@ const AppCreator = (props) => {
// throw new Error("NOT 200 :O")
//}
setAppBuilding(false)
return response.json()
})
.then((responseJson) => {
@@ -1570,7 +1574,22 @@ const AppCreator = (props) => {
margin="normal"
variant="outlined"
value={name}
onChange={e => setName(e.target.value)}
onChange={e => {
const invalid = ["#", ":", "."]
for (var key in invalid) {
if (e.target.value.includes(invalid[key])) {
alert.error("Can't use "+invalid[key]+" in name")
return
}
}
if (e.target.value.length > 100) {
alert.error("Choose a shorter name.")
return
}
setName(e.target.value)
}}
color="primary"
InputProps={{
style:{
@@ -1590,12 +1609,12 @@ const AppCreator = (props) => {
style={{flex: "1", marginTop: "5px", marginRight: "15px", backgroundColor: inputColor}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="A description for the service"
value={description}
onChange={e => setDescription(e.target.value)}
onChange={e => setDescription(e.target.value)}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
@@ -1691,10 +1710,10 @@ const AppCreator = (props) => {
{testView}
*/}
<Button color="primary" variant="contained" style={{borderRadius: "0px", marginTop: "30px", height: "50px",}} onClick={() => {
<Button disabled={appBuilding} color="primary" variant="contained" style={{borderRadius: "0px", marginTop: "30px", height: "50px",}} onClick={() => {
submitApp()
}}>
Save
{appBuilding ? <CircularProgress /> : "Save"}
</Button>
{errorCode.length > 0 ? `Error: ${errorCode}` : null}
</Paper>
+32 -17
View File
@@ -16,6 +16,7 @@ import Switch from '@material-ui/core/Switch';
import CircularProgress from '@material-ui/core/CircularProgress';
import CachedIcon from '@material-ui/icons/Cached';
import GetAppIcon from '@material-ui/icons/GetApp';
import EditIcon from '@material-ui/icons/Edit';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
@@ -126,14 +127,15 @@ const Workflows = (props) => {
color: "#ffffff",
width: "100%",
display: "flex",
maxWidth: "1768px",
minWidth: 1366,
maxWidth: 1766,
margin: "auto",
maxHeight: "90vh",
}
const emptyWorkflowStyle = {
paddingTop: "200px",
width: "1024px",
width: 1024,
margin: "auto",
}
@@ -263,6 +265,12 @@ const Workflows = (props) => {
return new Promise((resolve) => setTimeout(resolve, time));
}
const exportAllWorkflows = () => {
for (var key in workflows) {
exportWorkflow(workflows[key])
}
}
const exportWorkflow = (data) => {
console.log("export")
let dataStr = JSON.stringify(data)
@@ -364,9 +372,9 @@ const Workflows = (props) => {
}}>
<div style={{marginLeft: "10px", marginTop: "5px", marginBottom: "5px", width: boxWidth, backgroundColor: boxColor}}>
</div>
<Grid container style={{margin: "10px 10px 10px 10px", flex: "1"}}>
<Grid container style={{margin: "10px 10px 10px 10px", flex: 1}}>
<Grid style={{display: "flex", flexDirection: "column", width: "100%"}}>
<Grid item style={{flex: "1", display: "flex"}}>
<Grid item style={{flex: 1, display: "flex"}}>
<div style={{flex: "10",}} onClick={() => {
if (selectedWorkflow.id !== data.id) {
setSelectedWorkflow(data)
@@ -418,7 +426,7 @@ const Workflows = (props) => {
</Menu>
</div>
</Grid>
<div style={{display: "flex", flex: "1"}} onClick={() => {
<div style={{display: "flex", flex: 1}} onClick={() => {
if (selectedWorkflow.id !== data.id) {
setSelectedWorkflow(data)
getWorkflowExecution(data.id)
@@ -468,13 +476,13 @@ const Workflows = (props) => {
var results = data.results.length
}
return (
<Paper square style={paperAppStyle} onClick={() => {
<Paper key={data.id} square style={paperAppStyle} onClick={() => {
setSelectedExecution(data)
}}>
<div style={{marginLeft: "10px", marginTop: "5px", marginBottom: "5px", width: boxWidth, backgroundColor: boxColor}} />
<Grid container style={{margin: "10px 10px 10px 10px", flex: "1"}}>
<Grid container style={{margin: "10px 10px 10px 10px", flex: 1}}>
<Grid style={{display: "flex", flexDirection: "column", width: "100%"}}>
<Grid item style={{flex: "1", display: "flex"}}>
<Grid item style={{flex: 1, display: "flex"}}>
<div style={{flex: "5"}}>
<h3 style={{marginBottom: "0px", marginTop: "10px"}}><b>Status</b>: {data.status}</h3>
Actions: {results}/{actions}
@@ -681,7 +689,7 @@ const Workflows = (props) => {
*/
if (Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.workflow.actions !== null) {
return (
<div>
<div style={{overflowX: "hidden"}}>
<div>
<b>Status:</b> {selectedExecution.status}
</div>
@@ -843,7 +851,7 @@ const Workflows = (props) => {
}
const modalView = modalOpen ?
<Dialog modal
<Dialog
open={modalOpen}
onClose={() => {setModalOpen(false)}}
PaperProps={{
@@ -910,9 +918,9 @@ const Workflows = (props) => {
const viewSize = {
workflowView: 1,
executionsView: 1,
executionResults: 2,
workflowView: 4,
executionsView: 3,
executionResults: 4,
}
const workflowViewStyle = {
@@ -943,7 +951,14 @@ const Workflows = (props) => {
</Button>
</Tooltip>
*/}
<Tooltip color="primary" title={"Download / Import workflows"} placement="top">
<Tooltip color="primary" title={`Download ALL workflows (${workflows.length})`} placement="top">
<Button color="primary" style={{}} variant="text" onClick={() => {
exportAllWorkflows()
}}>
<GetAppIcon />
</Button>
</Tooltip>
<Tooltip color="primary" title={"Import workflows"} placement="top">
<Button color="primary" style={{}} variant="text" onClick={() => setLoadWorkflowsModalOpen(true)}>
<CloudDownloadIcon />
</Button>
@@ -982,10 +997,10 @@ const Workflows = (props) => {
</div>
<div style={{flex: viewSize.executionResults, marginLeft: "10px", marginRight: "10px", minWidth: "33%"}}>
<div style={{display: "flex"}}>
<div style={{flex: "3"}}>
<div style={{flex: "1"}}>
<h2>Execution Timeline</h2>
</div>
<div style={{flex: "1"}}>
<div style={{flex: 1}}>
<FormControlLabel
style={{color: "white", marginBottom: "0px", marginTop: "10px"}}
label={<div style={{color: "white"}}>Collapse results</div>}
@@ -1075,7 +1090,7 @@ const Workflows = (props) => {
}
const workflowDownloadModalOpen = loadWorkflowsModalOpen ?
<Dialog modal
<Dialog
open={loadWorkflowsModalOpen}
onClose={() => {
}}
+18 -7
View File
@@ -7,7 +7,6 @@ The Docker setup is done with docker-compose and is a single command to get set
**PS: if you're setting up Shuffle on Windows, go to the next step (Windows Docker setup)**
1. Make sure you have Docker and [docker-compose](https://docs.docker.com/compose/install/) installed.
2. Run docker-compose.
```
git clone https://github.com/frikky/Shuffle
@@ -20,7 +19,7 @@ When you're done, skip to the "After installation" step below.
## Windows Docker setup
This step is for setting up with Docker on windows from scratch.
1. Make sure you have [Docker](https://docs.docker.com/docker-for-windows/install/) and [docker-compose](https://docs.docker.com/compose/install/) installed
1. Make sure you have [Docker](https://docs.docker.com/docker-for-windows/install/) and [docker-compose](https://docs.docker.com/compose/install/) installed. WSL2 may be required.
2. Go to https://github.com/frikky/shuffle/releases and download the latest .zip release (or install git)
3. Unzip the folder and enter it
4. Open the .env file and change the line with "OUTER_HOSTNAME" to contain your IP:
@@ -84,14 +83,16 @@ docker-compose up
Related issue: #47
## Local development installation
Frontend - requires [npm](https://nodejs.org/en/download/)/[yarn](https://yarnpkg.com/lang/en/docs/install/#debian-stable)/your preferred manager. Runs independently from backend - edit frontend/src/App.yaml (line 44~) from window.location.origin to http://YOUR IP:5001
**Frontend - ReactJS /w cytoscape**
http://localhost:3000 - Requires [npm](https://nodejs.org/en/download/)/[yarn](https://yarnpkg.com/lang/en/docs/install/#debian-stable)/your preferred manager. Runs independently from backend.
```bash
cd frontend
npm i
npm start
```
Backend - API calls - requires [>=go1.13](https://golang.org/dl/)
**Backend - Golang**
http://localhost:5001 - REST API - requires [>=go1.13](https://golang.org/dl/)
```bash
export DATASTORE_EMULATOR_HOST=0.0.0.0:8000
cd backend/go-app
@@ -99,16 +100,26 @@ go build
go run *.go
```
Database - Datastore:
**Database - Datastore**
Based on Google datastore
```
docker run -p 8000:8000 google/cloud-sdk gcloud beta emulators datastore start --project=shuffle --host-port 0.0.0.0:8000 --no-store-on-disk
```
Orborus - Execution of Workflows:
PS: This requires some specific environment variables.
**Orborus**
Execution of Workflows:
PS: This requires some specific environment variables
```
cd functions/onprem/orborus
go run orborus.go
```
Environments:
```
export ORG_ID=Shuffle
export ENVIRONMENT_NAME=Shuffle
export BASE_URL=http://YOUR-IP:5001
export DOCKER_API_VERSION=1.40
export SHUFFLE_PASS_WORKER_PROXY=${SHUFFLE_PASS_WORKER_PROXY}
```