@@ -46,15 +46,17 @@ OUTER_HOSTNAME=shuffle-backend
|
||||
DB_LOCATION=./shuffle-database
|
||||
DOCKER_API_VERSION=1.40
|
||||
|
||||
# Proxy configurations. SHUFFLE_PASS_WORKER_PROXY must be FALSE to not pass the proxy information to sub-apps.
|
||||
# PS: It will skip proxy for
|
||||
# Orborus/Proxy configurations
|
||||
HTTP_PROXY=
|
||||
HTTPS_PROXY=
|
||||
SHUFFLE_PASS_WORKER_PROXY=TRUE
|
||||
SHUFFLE_PASS_APP_PROXY=FALSE
|
||||
SHUFFLE_PASS_WORKER_PROXY=TRUE # Decides if proxy configurations should be passed to workers or not
|
||||
SHUFFLE_PASS_APP_PROXY=TRUE # Decides if proxy configurations should be passed to apps or not. Requires SHUFFLE_PASS_WORKER_PROXY=true
|
||||
SHUFFLE_INTERNAL_HTTP_PROXY= # Used to differentiate proxies for shuffle internal vs external traffic
|
||||
SHUFFLE_INTERNAL_HTTPS_PROXY=
|
||||
TZ=Europe/Amsterdam # Timezone-handler in Orborus, Worker and Apps
|
||||
ORBORUS_CONTAINER_NAME= # Used to FIND the containername. cgroup v2: issue 501
|
||||
SHUFFLE_ORBORUS_STARTUP_DELAY= # Used for setting up a startup delay for Orborus
|
||||
SHUFFLE_SKIPSSL_VERIFY=true
|
||||
IS_KUBERNETES=false # Used for controlling if the environment should run in kubernetes or not
|
||||
|
||||
SHUFFLE_BASE_IMAGE_NAME=shuffle
|
||||
@@ -79,6 +81,7 @@ SHUFFLE_DISABLE_RERUN_AND_ABORT=false
|
||||
SHUFFLE_RERUN_SCHEDULE=300
|
||||
SHUFFLE_WORKER_SERVER_URL= # Definition in case Worker & Orborus is talking to the wrong server
|
||||
SHUFFLE_ORBORUS_PULL_TIME= # Definition in case Orborus is pulling too often/not often enough
|
||||
SHUFFLE_MAX_EXECUTION_DEPTH= # Max recursion depth for subflows
|
||||
|
||||
# DATABASE CONFIGURATIONS
|
||||
DATASTORE_EMULATOR_HOST=shuffle-database:8000
|
||||
|
||||
@@ -19,23 +19,23 @@ jobs:
|
||||
include:
|
||||
- app: frontend
|
||||
path: frontend
|
||||
version: 1.3.1
|
||||
version: 1.3.2
|
||||
experimental: true
|
||||
- app: backend
|
||||
path: backend
|
||||
version: 1.3.1
|
||||
version: 1.3.2
|
||||
experimental: true
|
||||
- app: app_sdk
|
||||
path: backend/app_sdk
|
||||
version: 1.3.1
|
||||
version: 1.3.2
|
||||
experimental: true
|
||||
- app: orborus
|
||||
path: functions/onprem/orborus
|
||||
version: 1.3.1
|
||||
version: 1.3.2
|
||||
experimental: true
|
||||
- app: worker
|
||||
path: functions/onprem/worker
|
||||
version: 1.3.1
|
||||
version: 1.3.2
|
||||
experimental: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
+122
-40
@@ -333,6 +333,16 @@ class AppBase:
|
||||
if len(os.getenv("SHUFFLE_INTERNAL_NO_PROXY", "")) > 0:
|
||||
self.proxy_config["no_proxy"] = os.getenv("SHUFFLE_INTERNAL_NO_PROXY", "")
|
||||
|
||||
try:
|
||||
if self.proxy_config["http"].lower() == "noproxy":
|
||||
self.proxy_config["http"] = ""
|
||||
if self.proxy_config["https"].lower() == "noproxy":
|
||||
self.proxy_config["https"] = ""
|
||||
except Exception as e:
|
||||
self.logger.info(f"[DEBUG] Failed setting proxy config: {e}. NOT important if running apps with webserver. This is NOT critical.")
|
||||
|
||||
self.logger.info(f"[DEBUG] Proxy config: {self.proxy_config}")
|
||||
|
||||
if isinstance(self.action, str):
|
||||
try:
|
||||
self.action = json.loads(self.action)
|
||||
@@ -525,6 +535,7 @@ class AppBase:
|
||||
|
||||
try:
|
||||
finished = False
|
||||
ret = {}
|
||||
for i in range (0, 10):
|
||||
# Random sleeptime between 0 and 1 second, with 0.1 increments
|
||||
sleeptime = float(random.randint(0, 10) / 10)
|
||||
@@ -532,22 +543,23 @@ class AppBase:
|
||||
try:
|
||||
ret = requests.post(url, headers=headers, json=action_result, timeout=10, verify=False, proxies=self.proxy_config)
|
||||
|
||||
self.logger.info(f"[DEBUG] Result: {ret.status_code} (break on 200 or 201)")
|
||||
self.logger.info(f"""[DEBUG] Successful request result request: Status= {ret.status_code} (break on 200/201) & Response= {ret.text}. Action status: {action_result["status"]}""")
|
||||
if ret.status_code == 200 or ret.status_code == 201:
|
||||
finished = True
|
||||
break
|
||||
else:
|
||||
self.logger.info(f"[ERROR] Bad resp {ret.status_code}: {ret.text}")
|
||||
time.sleep(sleeptime)
|
||||
|
||||
|
||||
# Proxyerrror
|
||||
except requests.exceptions.ProxyError as e:
|
||||
self.logger.info(f"[ERROR] Proxy error: {e}")
|
||||
self.logger.info(f"[ERROR] Proxy error for url {url}: {e}")
|
||||
self.proxy_config = {}
|
||||
continue
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.logger.info(f"[DEBUG] Request problem: {e}")
|
||||
self.logger.info(f"[DEBUG] Request problem for url {url}: {e}")
|
||||
time.sleep(sleeptime)
|
||||
|
||||
# Check if we have a read timeout. If we do, exit as we most likely sent the result without getting a good result
|
||||
@@ -599,7 +611,6 @@ class AppBase:
|
||||
self.send_result(action_result, {"Content-Type": "application/json", "Authorization": "Bearer %s" % self.authorization}, "/api/v1/streams")
|
||||
return
|
||||
|
||||
self.logger.info(f"""[DEBUG] Successful request result request: Status= {ret.status_code} & Response= {ret.text}. Action status: {action_result["status"]}""")
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
self.logger.info(f"[DEBUG] Unexpected ConnectionError happened: {e}")
|
||||
except TypeError as e:
|
||||
@@ -692,7 +703,7 @@ class AppBase:
|
||||
except (KeyError, NameError) as e:
|
||||
self.logger.info(f"""Key/NameError in param handler for {param["name"]}: {e}""")
|
||||
|
||||
self.logger.info(f"[DEBUG] OUTER VALUE: {param_value}")
|
||||
#self.logger.info(f"[DEBUG] OUTER VALUE: {param_value}")
|
||||
if len(param_value) > 0:
|
||||
md5 = hashlib.md5(param_value.encode('utf-8')).hexdigest()
|
||||
values.append(md5)
|
||||
@@ -1168,7 +1179,7 @@ class AppBase:
|
||||
#ret = ret[0]
|
||||
self.logger.info("[DEBUG] DONT make list of 1 into 0!!")
|
||||
|
||||
self.logger.info("Return from execution: %s" % ret)
|
||||
#self.logger.info("Return from execution: %s" % ret)
|
||||
if ret == None:
|
||||
results.append("")
|
||||
json_object = False
|
||||
@@ -1192,11 +1203,12 @@ class AppBase:
|
||||
except:
|
||||
results.append(ret)
|
||||
|
||||
if len(results) == 1:
|
||||
#results = results[0]
|
||||
self.logger.info("DONT MAKE LIST FROM 1 TO 0!!")
|
||||
#if len(results) == 1:
|
||||
# #results = results[0]
|
||||
# #self.logger.info("DONT MAKE LIST FROM 1 TO 0!!")
|
||||
# pass
|
||||
|
||||
self.logger.info("\nLOOP: %s\nRESULTS: %s" % (loop_wrapper, results))
|
||||
#self.logger.info("\nLOOP: %s\nRESULTS: %s" % (loop_wrapper, results))
|
||||
return results
|
||||
|
||||
# Downloads all files from a namespace
|
||||
@@ -1567,9 +1579,10 @@ class AppBase:
|
||||
"execution_id": self.current_execution_id
|
||||
}
|
||||
|
||||
self.logger.info("[ERROR] Before FULLEXEC stream result")
|
||||
resultsurl = "%s/api/v1/streams/results" % (self.base_url)
|
||||
#self.logger.info("[DEBUG] Before FULLEXEC stream result url '%s'" % (resultsurl))
|
||||
ret = requests.post(
|
||||
"%s/api/v1/streams/results" % (self.base_url),
|
||||
resultsurl,
|
||||
headers=headers,
|
||||
json=tmpdata,
|
||||
verify=False,
|
||||
@@ -1591,7 +1604,7 @@ class AppBase:
|
||||
continue
|
||||
|
||||
else:
|
||||
self.logger.info("[ERROR] Error in app with status code %d for results (2). Crashing because results can't be handled" % ret.status_code)
|
||||
self.logger.info("[ERROR] (fails: %d) Error in app with status code %d for results (2). Crashing because results can't be handled. Details: %s" % (i+1, ret.status_code, ret.text))
|
||||
|
||||
rettext = ret.text
|
||||
failed = True
|
||||
@@ -1612,11 +1625,21 @@ class AppBase:
|
||||
self.logger.info("[ERROR] FullExec Connectionerror: %s" % e)
|
||||
self.action_result["result"] = json.dumps({
|
||||
"success": False,
|
||||
"reason": f"Connection error during startup: {e}"
|
||||
"reason": f"Connection error during startup (connection error): {e}"
|
||||
})
|
||||
|
||||
self.send_result(self.action_result, headers, stream_path)
|
||||
return
|
||||
except Exception as e:
|
||||
self.logger.info("[ERROR] FullExec Exception outer: %s" % e)
|
||||
self.action_result["result"] = json.dumps({
|
||||
"success": False,
|
||||
"reason": f"Exception during startup of app (general error): {e}"
|
||||
})
|
||||
|
||||
self.send_result(self.action_result, headers, stream_path)
|
||||
return
|
||||
|
||||
else:
|
||||
self.logger.info(f"[DEBUG] Setting execution to default value with type {type(self.full_execution)}")
|
||||
try:
|
||||
@@ -2008,7 +2031,9 @@ class AppBase:
|
||||
outercnt = 0
|
||||
|
||||
# Loops over split values
|
||||
splitcnt = -1
|
||||
for value in parsersplit:
|
||||
splitcnt += 1
|
||||
#if " " in value:
|
||||
# value = value.replace(" ", "_", -1)
|
||||
|
||||
@@ -2016,6 +2041,10 @@ class AppBase:
|
||||
# Goes here if loop
|
||||
if value == "#":
|
||||
newvalue = []
|
||||
|
||||
if basejson == None:
|
||||
return "", False
|
||||
|
||||
for innervalue in basejson:
|
||||
# 1. Check the next item (message)
|
||||
# 2. Call this function again
|
||||
@@ -2049,9 +2078,9 @@ class AppBase:
|
||||
# Means it's a single item -> continue
|
||||
if seconditem == "":
|
||||
print("[INFO] In first - handling %s. Len: %d" % (firstitem, len(basejson)))
|
||||
if firstitem.lower() == "max" or firstitem.lower() == "last" or firstitem.lower() == "end":
|
||||
if str(firstitem).lower() == "max" or str(firstitem).lower() == "last" or str(firstitem).lower() == "end":
|
||||
firstitem = len(basejson)-1
|
||||
elif firstitem.lower() == "min" or firstitem.lower() == "first":
|
||||
elif str(firstitem).lower() == "min" or str(firstitem).lower() == "first":
|
||||
firstitem = 0
|
||||
else:
|
||||
firstitem = int(firstitem)
|
||||
@@ -2075,9 +2104,9 @@ class AppBase:
|
||||
firstitem = int(firstitem)
|
||||
|
||||
if isinstance(seconditem, str):
|
||||
if seconditem.lower() == "max" or seconditem.lower() == "last" or firstitem.lower() == "end":
|
||||
if str(seconditem).lower() == "max" or str(seconditem).lower() == "last" or str(firstitem).lower() == "end":
|
||||
seconditem = len(basejson)-1
|
||||
elif seconditem.lower() == "min" or seconditem.lower() == "first":
|
||||
elif str(seconditem).lower() == "min" or str(seconditem).lower() == "first":
|
||||
seconditem = 0
|
||||
else:
|
||||
seconditem = int(seconditem)
|
||||
@@ -2113,6 +2142,12 @@ class AppBase:
|
||||
if isinstance(basejson, list):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, bool):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, int):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson[value], str):
|
||||
try:
|
||||
if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
|
||||
@@ -2132,22 +2167,67 @@ class AppBase:
|
||||
elif " " in value:
|
||||
value = value.replace(" ", "_", -1)
|
||||
|
||||
if isinstance(basejson, list):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson[value], str):
|
||||
print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
|
||||
try:
|
||||
print("[DEBUG] BASEJSON: %s" % basejson)
|
||||
if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
|
||||
basejson = json.loads(basejson[value])
|
||||
else:
|
||||
try:
|
||||
if isinstance(basejson, list):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, bool):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, int):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson[value], str):
|
||||
print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
|
||||
try:
|
||||
print("[DEBUG] BASEJSON: %s" % basejson)
|
||||
if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
|
||||
basejson = json.loads(basejson[value])
|
||||
else:
|
||||
return str(basejson[value]), False
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
|
||||
return str(basejson[value]), False
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
|
||||
return str(basejson[value]), False
|
||||
else:
|
||||
basejson = basejson[value]
|
||||
else:
|
||||
basejson = basejson[value]
|
||||
|
||||
except KeyError as e:
|
||||
print("\n\n[WARNING] Running third dot notation fix that always find the correct value %s: %s" % (value, e))
|
||||
|
||||
try:
|
||||
currentsplitcnt = splitcnt
|
||||
recursed_value = value
|
||||
handled = False
|
||||
while True:
|
||||
newvalue = parsersplit[currentsplitcnt+1]
|
||||
if newvalue == "#" or newvalue == "":
|
||||
break
|
||||
|
||||
recursed_value += "." + newvalue
|
||||
found = False
|
||||
for key, value in basejson.items():
|
||||
if recursed_value.lower() in key.lower():
|
||||
found = True
|
||||
|
||||
if found == False:
|
||||
print("[INFO] DIDN'T FIND similar VALUE: ", recursed_value)
|
||||
break
|
||||
|
||||
if recursed_value in basejson:
|
||||
print("[INFO] FOUND RECURSED VALUE: ", recursed_value)
|
||||
basejson = basejson[recursed_value]
|
||||
handled = True
|
||||
break
|
||||
|
||||
currentsplitcnt += 1
|
||||
|
||||
if handled:
|
||||
continue
|
||||
|
||||
break
|
||||
except IndexError as e:
|
||||
print("[DEBUG] INDEXERROR: ", parsersplit[outercnt])
|
||||
break
|
||||
|
||||
|
||||
outercnt += 1
|
||||
@@ -2155,6 +2235,9 @@ class AppBase:
|
||||
except KeyError as e:
|
||||
print("[INFO] Lower keyerror: %s" % e)
|
||||
return "", False
|
||||
except Exception as e:
|
||||
print("[WARNING] Exception: %s" % e)
|
||||
return basejson, False
|
||||
|
||||
#return basejson
|
||||
#return "KeyError: Couldn't find key: %s" % e
|
||||
@@ -2682,7 +2765,7 @@ class AppBase:
|
||||
#self.logger.info(f"\n\nType of value: {type(value)}")
|
||||
if isinstance(value, str):
|
||||
# Could we take it here?
|
||||
self.logger.info(f"[DEBUG] Got value %s for parameter {paramname}" % value)
|
||||
#self.logger.info(f"[DEBUG] Got value %s for parameter {paramname}" % value)
|
||||
# Should check if there is are quotes infront of and after the to_be_replaced
|
||||
# If there are, then we need to sanitize the value
|
||||
# 1. Look for the to_be_replaced in the data
|
||||
@@ -2694,7 +2777,6 @@ class AppBase:
|
||||
# value = returnvalue
|
||||
|
||||
|
||||
|
||||
parameter["value"] = parameter["value"].replace(to_be_replaced, value)
|
||||
elif isinstance(value, dict) or isinstance(value, list):
|
||||
# Changed from JSON dump to str() 28.05.2021
|
||||
@@ -3225,7 +3307,7 @@ class AppBase:
|
||||
pass
|
||||
|
||||
|
||||
self.logger.info(f"""HANDLING BODY: {action["parameters"][counter]["value"]}""")
|
||||
#self.logger.info(f"""HANDLING BODY: {action["parameters"][counter]["value"]}""")
|
||||
action["parameters"][counter]["value"] = recurse_cleanup_script(action["parameters"][counter]["value"])
|
||||
|
||||
#self.logger.info(action["parameters"])
|
||||
@@ -3265,8 +3347,8 @@ class AppBase:
|
||||
"exception": f"Value Error: {check}",
|
||||
}))
|
||||
|
||||
if parameter["name"] == "body":
|
||||
self.logger.info(f"[INFO] Should debug field with liquid and other checks as it's BODY: {value}")
|
||||
#if parameter["name"] == "body":
|
||||
# #self.logger.info(f"[INFO] Should debug field with liquid and other checks as it's BODY: {value}")
|
||||
|
||||
# Custom format for ${name[0,1,2,...]}$
|
||||
#submatch = "([${]{2}([0-9a-zA-Z_-]+)(\[.*\])[}$]{2})"
|
||||
@@ -3655,9 +3737,9 @@ class AppBase:
|
||||
timeout_env = os.getenv("SHUFFLE_APP_SDK_TIMEOUT", timeout)
|
||||
try:
|
||||
timeout = int(timeout_env)
|
||||
self.logger.info(f"[DEBUG] Timeout set to {timeout} seconds")
|
||||
#self.logger.info(f"[DEBUG] Timeout set to {timeout} seconds")
|
||||
except Exception as e:
|
||||
self.logger.info(f"[WARNING] Failed parsing timeout to int: {e}")
|
||||
self.logger.info(f"[ERROR] Failed parsing timeout to int: {e}")
|
||||
|
||||
#timeout = 30
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
## A test script of the recurse_json function
|
||||
## to validate that it can handle the different types of data
|
||||
## and follow the dot formation format
|
||||
|
||||
|
||||
import re
|
||||
import json
|
||||
|
||||
def recurse_json(basejson, parsersplit):
|
||||
match = "#([0-9a-z]+):?-?([0-9a-z]+)?#?"
|
||||
try:
|
||||
outercnt = 0
|
||||
|
||||
# Loops over split values
|
||||
splitcnt = -1
|
||||
for value in parsersplit:
|
||||
splitcnt += 1
|
||||
#if " " in value:
|
||||
# value = value.replace(" ", "_", -1)
|
||||
|
||||
actualitem = re.findall(match, value, re.MULTILINE)
|
||||
# Goes here if loop
|
||||
if value == "#":
|
||||
newvalue = []
|
||||
|
||||
if basejson == None:
|
||||
return "", False
|
||||
|
||||
for innervalue in basejson:
|
||||
# 1. Check the next item (message)
|
||||
# 2. Call this function again
|
||||
|
||||
try:
|
||||
ret, is_loop = recurse_json(innervalue, parsersplit[outercnt+1:])
|
||||
except IndexError:
|
||||
# Only in here if it's the last loop without anything in it?
|
||||
ret, is_loop = recurse_json(innervalue, parsersplit[outercnt:])
|
||||
|
||||
newvalue.append(ret)
|
||||
|
||||
# Magical way of returning which makes app sdk identify
|
||||
# it as multi execution
|
||||
return newvalue, True
|
||||
|
||||
# Checks specific regex like #1-2 for index 1-2 in a loop
|
||||
elif len(actualitem) > 0:
|
||||
|
||||
is_loop = True
|
||||
newvalue = []
|
||||
firstitem = actualitem[0][0]
|
||||
seconditem = actualitem[0][1]
|
||||
if isinstance(firstitem, int):
|
||||
firstitem = str(firstitem)
|
||||
if isinstance(seconditem, int):
|
||||
seconditem = str(seconditem)
|
||||
|
||||
#print("[DEBUG] ACTUAL PARSED: %s" % actualitem)
|
||||
|
||||
# Means it's a single item -> continue
|
||||
if seconditem == "":
|
||||
print("[INFO] In first - handling %s. Len: %d" % (firstitem, len(basejson)))
|
||||
if str(firstitem).lower() == "max" or str(firstitem).lower() == "last" or str(firstitem).lower() == "end":
|
||||
firstitem = len(basejson)-1
|
||||
elif str(firstitem).lower() == "min" or str(firstitem).lower() == "first":
|
||||
firstitem = 0
|
||||
else:
|
||||
firstitem = int(firstitem)
|
||||
|
||||
print(f"[DEBUG] Post lower checks with item {firstitem}")
|
||||
tmpitem = basejson[int(firstitem)]
|
||||
try:
|
||||
newvalue, is_loop = recurse_json(tmpitem, parsersplit[outercnt+1:])
|
||||
except IndexError:
|
||||
newvalue, is_loop = (tmpitem, parsersplit[outercnt+1:])
|
||||
else:
|
||||
print("[INFO] In ELSE - handling %s and %s" % (firstitem, seconditem))
|
||||
if isinstance(firstitem, str):
|
||||
if firstitem.lower() == "max" or firstitem.lower() == "last" or firstitem.lower() == "end":
|
||||
firstitem = len(basejson)-1
|
||||
elif firstitem.lower() == "min" or firstitem.lower() == "first":
|
||||
firstitem = 0
|
||||
else:
|
||||
firstitem = int(firstitem)
|
||||
else:
|
||||
firstitem = int(firstitem)
|
||||
|
||||
if isinstance(seconditem, str):
|
||||
if str(seconditem).lower() == "max" or str(seconditem).lower() == "last" or str(firstitem).lower() == "end":
|
||||
seconditem = len(basejson)-1
|
||||
elif str(seconditem).lower() == "min" or str(seconditem).lower() == "first":
|
||||
seconditem = 0
|
||||
else:
|
||||
seconditem = int(seconditem)
|
||||
else:
|
||||
seconditem = int(seconditem)
|
||||
|
||||
print(f"[DEBUG] Post lower checks 2: {firstitem} AND {seconditem}")
|
||||
newvalue = []
|
||||
if int(seconditem) > len(basejson):
|
||||
seconditem = len(basejson)
|
||||
|
||||
for i in range(int(firstitem), int(seconditem)+1):
|
||||
# 1. Check the next item (message)
|
||||
# 2. Call this function again
|
||||
|
||||
try:
|
||||
ret, tmp_loop = recurse_json(basejson[i], parsersplit[outercnt+1:])
|
||||
except IndexError:
|
||||
print("[DEBUG] INDEXERROR: ", parsersplit[outercnt])
|
||||
#ret = innervalue
|
||||
ret, tmp_loop = recurse_json(basejson[i], parsersplit[outercnt:])
|
||||
|
||||
newvalue.append(ret)
|
||||
|
||||
return newvalue, is_loop
|
||||
|
||||
else:
|
||||
print("IN ELSE WITH VALUE: %s" % value)
|
||||
if len(value) == 0:
|
||||
return basejson, False
|
||||
|
||||
try:
|
||||
print("PRINT:", basejson)
|
||||
if isinstance(basejson, list):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, bool):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, int):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson[value], str):
|
||||
try:
|
||||
if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
|
||||
basejson = json.loads(basejson[value])
|
||||
else:
|
||||
# Should we sanitize here?
|
||||
print("[DEBUG] VALUE TO SANITIZE?: %s" % basejson[value])
|
||||
return str(basejson[value]), False
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
return str(basejson[value]), False
|
||||
else:
|
||||
basejson = basejson[value]
|
||||
except KeyError as e:
|
||||
print("[WARNING] Running secondary value check with replacement of underscore in %s: %s" % (value, e))
|
||||
if "_" in value:
|
||||
value = value.replace("_", " ", -1)
|
||||
elif " " in value:
|
||||
value = value.replace(" ", "_", -1)
|
||||
|
||||
try:
|
||||
if isinstance(basejson, list):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, bool):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson, int):
|
||||
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
|
||||
return basejson, False
|
||||
elif isinstance(basejson[value], str):
|
||||
print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
|
||||
try:
|
||||
print("[DEBUG] BASEJSON: %s" % basejson)
|
||||
if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
|
||||
basejson = json.loads(basejson[value])
|
||||
else:
|
||||
return str(basejson[value]), False
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
|
||||
return str(basejson[value]), False
|
||||
else:
|
||||
basejson = basejson[value]
|
||||
except KeyError as e:
|
||||
print("\n\n[WARNING] Running third dot notation fix %s: %s" % (value, e))
|
||||
|
||||
try:
|
||||
|
||||
currentsplitcnt = splitcnt
|
||||
recursed_value = value
|
||||
handled = False
|
||||
while True:
|
||||
newvalue = parsersplit[currentsplitcnt+1]
|
||||
if newvalue == "#" or newvalue == "":
|
||||
break
|
||||
|
||||
recursed_value += "." + newvalue
|
||||
print("\n\nRECURSED: ", recursed_value)
|
||||
|
||||
found = False
|
||||
for key, value in basejson.items():
|
||||
if recursed_value.lower() in key.lower():
|
||||
found = True
|
||||
|
||||
if found == False:
|
||||
print("[INFO] DIDN'T FIND similar VALUE: ", recursed_value)
|
||||
break
|
||||
|
||||
if recursed_value in basejson:
|
||||
print("[INFO] FOUND RECURSED VALUE: ", recursed_value)
|
||||
basejson = basejson[recursed_value]
|
||||
handled = True
|
||||
break
|
||||
|
||||
currentsplitcnt += 1
|
||||
|
||||
if handled:
|
||||
continue
|
||||
|
||||
break
|
||||
except IndexError as e:
|
||||
print("[DEBUG] INDEXERROR: ", parsersplit[outercnt])
|
||||
break
|
||||
|
||||
outercnt += 1
|
||||
|
||||
except KeyError as e:
|
||||
print("[INFO] Lower keyerror: %s" % e)
|
||||
return "", False
|
||||
except Exception as e:
|
||||
print("[WARNING] Exception: %s" % e)
|
||||
return basejson, False
|
||||
|
||||
#return basejson
|
||||
#return "KeyError: Couldn't find key: %s" % e
|
||||
|
||||
return basejson, False
|
||||
|
||||
print("[INFO] Starting")
|
||||
|
||||
#input_data = "test"
|
||||
#input_data = "test2.data"
|
||||
#input_data = "test2.test3.data"
|
||||
input_data = "test2.test5.data.hello"
|
||||
parsersplit = input_data.split(".")
|
||||
|
||||
basejson = {
|
||||
"test": "hello",
|
||||
"test2": {
|
||||
"data": "hello2",
|
||||
"test3.data": "hello3",
|
||||
"test4.data.testing": {
|
||||
"value": "hello4"
|
||||
},
|
||||
"test5.data.hello": "wut"
|
||||
},
|
||||
}
|
||||
|
||||
ret, is_loop = recurse_json(basejson, parsersplit)
|
||||
print("\n\nOUTPUT RET (%s): %s" % (input_data, ret))
|
||||
@@ -821,6 +821,7 @@ func handleRemoteDownloadApp(resp http.ResponseWriter, ctx context.Context, user
|
||||
return
|
||||
}
|
||||
|
||||
defer newresp.Body.Close()
|
||||
respBody, err := ioutil.ReadAll(newresp.Body)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Failed setting respbody for workflow download: %s", err)
|
||||
|
||||
+18
-16
@@ -13,13 +13,13 @@ require (
|
||||
github.com/frikky/kin-openapi v0.42.0
|
||||
github.com/fsouza/go-dockerclient v1.9.7
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-git/go-billy/v5 v5.4.1
|
||||
github.com/go-git/go-git/v5 v5.7.0
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.11.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/h2non/filetype v1.1.3
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shuffle/shuffle-shared v0.5.30
|
||||
golang.org/x/crypto v0.14.0
|
||||
github.com/shuffle/shuffle-shared v0.5.65
|
||||
golang.org/x/crypto v0.16.0
|
||||
google.golang.org/api v0.125.0
|
||||
google.golang.org/grpc v1.55.0
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
@@ -34,10 +34,11 @@ require (
|
||||
cloud.google.com/go/compute v1.19.3 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.0.1 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/adrg/strutil v0.2.3 // indirect
|
||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1 // indirect
|
||||
@@ -46,19 +47,20 @@ require (
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/containerd/containerd v1.6.18 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-logr/logr v1.2.2 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-github/v28 v28.1.1 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
@@ -88,21 +90,21 @@ require (
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/skeema/knownhosts v1.1.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/src-d/gcfg v1.4.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
|
||||
@@ -47,6 +47,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
cloud.google.com/go/storage v1.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho=
|
||||
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
|
||||
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
@@ -65,10 +67,14 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||
@@ -81,6 +87,7 @@ github.com/algolia/algoliasearch-client-go/v3 v3.18.1 h1:FP2Xtqqs/sefR5Qluygp+jV
|
||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1/go.mod h1:i7tLoP7TYDmHX3Q7vkIOL4syVse/k5VJ+k0i8WqFiJk=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
@@ -108,6 +115,7 @@ github.com/bradfitz/gomemcache v0.0.0-20221031212613-62deef7fc822/go.mod h1:H0wQ
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82 h1:9bAydALqAjBfPHd/eAiJBHnMZUYov8m2PkXVr+YGQeI=
|
||||
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82/go.mod h1:tyA14J0sA3Hph4dt+AfCjPrYR13+vVodshQSM7km9qw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@@ -138,6 +146,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -153,6 +163,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
@@ -180,13 +192,19 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
|
||||
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -195,12 +213,17 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
@@ -253,6 +276,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
@@ -276,9 +301,11 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
|
||||
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
@@ -329,11 +356,13 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/libgit2/git2go/v34 v34.0.0/go.mod h1:blVco2jDAw6YTXkErMMqzHLcAjKkwF0aWIRHBqiJkZ0=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -341,6 +370,7 @@ github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
||||
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
|
||||
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
@@ -363,13 +393,44 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
|
||||
github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
|
||||
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
|
||||
github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
|
||||
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
|
||||
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||
github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
|
||||
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
||||
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
||||
@@ -388,6 +449,7 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -395,7 +457,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
@@ -422,12 +487,30 @@ github.com/shuffle/shuffle-shared v0.5.14 h1:d14u1e4k+qKgnf4Insq4x2S+0MMKlDqdyTT
|
||||
github.com/shuffle/shuffle-shared v0.5.14/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.29 h1:n4vThl7v3mFVXbrIW71XREFdmZZo7mOBAWxnsdiNjDk=
|
||||
github.com/shuffle/shuffle-shared v0.5.29/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.30 h1:ORWjQU3UJhdZY5mRsAoR2hvftNcJmiEekNKjbaMo7K8=
|
||||
github.com/shuffle/shuffle-shared v0.5.30/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.31 h1:OV4IIfKWWFW66WjGvyXOmmsSz3p8pW9L1ge1mDo8ftM=
|
||||
github.com/shuffle/shuffle-shared v0.5.31/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.44 h1:6WiFPIsij+IWvXY7vzVX7cUicb+PYOzhTbWF/gDmYeU=
|
||||
github.com/shuffle/shuffle-shared v0.5.44/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.60 h1:R0BWYp/DlgyNPU0xVNSPhsWBnJ+LeVD3iLoDRZmtKMo=
|
||||
github.com/shuffle/shuffle-shared v0.5.60/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
|
||||
github.com/shuffle/shuffle-shared v0.5.61 h1:Fkd7pvk8ypwaio1VvMOmJ6PQF9xCfNYx8RWjPnXjn5E=
|
||||
github.com/shuffle/shuffle-shared v0.5.61/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
|
||||
github.com/shuffle/shuffle-shared v0.5.62 h1:L1la7++aqPLPsh1z3cuGIzH+NTuvBlmEU/T2mQvfEk8=
|
||||
github.com/shuffle/shuffle-shared v0.5.62/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
|
||||
github.com/shuffle/shuffle-shared v0.5.65 h1:x4ZM+e0LK21rRtG0xbtnUb+6qU08+zNBQ6azUyhn8ck=
|
||||
github.com/shuffle/shuffle-shared v0.5.65/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE=
|
||||
github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
@@ -446,12 +529,14 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
@@ -463,6 +548,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
@@ -475,6 +561,7 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8=
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -483,14 +570,21 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -524,9 +618,16 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -562,16 +663,29 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -592,9 +706,12 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -634,32 +751,57 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -670,10 +812,16 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -729,12 +877,21 @@ golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4X
|
||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -851,6 +1008,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -910,6 +1068,7 @@ k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
|
||||
+68
-68
@@ -22,11 +22,8 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
// import httptest
|
||||
"net/http/httptest"
|
||||
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -34,7 +31,7 @@ import (
|
||||
"github.com/frikky/kin-openapi/openapi2conv"
|
||||
"github.com/frikky/kin-openapi/openapi3"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
//"github.com/go-git/go-billy/v5"
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
@@ -46,10 +43,6 @@ import (
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
// PROXY overrides
|
||||
//"gopkg.in/src-d/go-git.v4/plumbing/transport/client"
|
||||
// githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
||||
|
||||
// Web
|
||||
"github.com/gorilla/mux"
|
||||
http2 "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
||||
@@ -569,7 +562,7 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
|
||||
|
||||
currentOrg := user.ActiveOrg
|
||||
if user.ActiveOrg.Id == "" {
|
||||
log.Printf("[WARNING] There's no active org for the user %s. Checking if there's a single one to assing it to.", user.Username)
|
||||
log.Printf("[WARNING] There's no active org for the user %s. Checking if there's a single one to assign it to.", user.Username)
|
||||
|
||||
orgs, err := shuffle.GetAllOrgs(ctx)
|
||||
if err == nil && len(orgs) > 0 {
|
||||
@@ -627,10 +620,46 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
|
||||
|
||||
err = createNewUser(data.Username, data.Password, role, apikey, currentOrg)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] Failed registering user: %s", err)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||
return
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
// Assign it to the org
|
||||
log.Printf("[WARNING] User %s already exists. Assigning to org %s", data.Username, currentOrg.Name)
|
||||
|
||||
// Get the user
|
||||
users, err := shuffle.FindUser(ctx, data.Username)
|
||||
if err != nil || len(users) == 0 {
|
||||
log.Printf("[WARNING] Failed finding user %s: %s", data.Username, err)
|
||||
resp.WriteHeader(400)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||
return
|
||||
}
|
||||
|
||||
newUser := users[0]
|
||||
if !shuffle.ArrayContains(newUser.Orgs, currentOrg.Id) {
|
||||
newUser.Orgs = append(newUser.Orgs, currentOrg.Id)
|
||||
}
|
||||
|
||||
if newUser.ActiveOrg.Id == "" || newUser.ActiveOrg.Name == "" {
|
||||
newUser.ActiveOrg = currentOrg
|
||||
}
|
||||
|
||||
err = shuffle.SetUser(ctx, &newUser, true)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] Failed updating the user %s: %s", data.Username, err)
|
||||
resp.WriteHeader(400)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteHeader(200)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
||||
log.Printf("[INFO] %s Successfully re-added to org %s (%s)", data.Username, currentOrg.Name, currentOrg.Id)
|
||||
return
|
||||
} else {
|
||||
log.Printf("[WARNING] Failed registering user: %s", err)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteHeader(200)
|
||||
@@ -3055,61 +3084,13 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) {
|
||||
buildSwaggerApp(resp, body, user, false)
|
||||
}
|
||||
|
||||
// Creates osfs from folderpath with a basepath as directory base
|
||||
func createFs(basepath, pathname string) (billy.Filesystem, error) {
|
||||
log.Printf("[INFO] MemFS base: %s, pathname: %s", basepath, pathname)
|
||||
|
||||
fs := memfs.New()
|
||||
err := filepath.Walk(pathname,
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.Contains(path, ".git") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fix the inner path here
|
||||
newpath := strings.ReplaceAll(path, pathname, "")
|
||||
fullpath := fmt.Sprintf("%s%s", basepath, newpath)
|
||||
switch mode := info.Mode(); {
|
||||
case mode.IsDir():
|
||||
err = fs.MkdirAll(fullpath, 0644)
|
||||
if err != nil {
|
||||
log.Printf("Failed making folder: %s", err)
|
||||
}
|
||||
case mode.IsRegular():
|
||||
srcData, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Printf("Src error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
dst, err := fs.Create(fullpath)
|
||||
if err != nil {
|
||||
log.Printf("Dst error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = dst.Write(srcData)
|
||||
if err != nil {
|
||||
log.Printf("Dst write error: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return fs, err
|
||||
}
|
||||
|
||||
// Hotloads new apps from a folder
|
||||
func handleAppHotload(ctx context.Context, location string, forceUpdate bool) error {
|
||||
|
||||
basepath := "base"
|
||||
fs, err := createFs(basepath, location)
|
||||
fs, err := shuffle.CreateFs(basepath, location)
|
||||
if err != nil {
|
||||
log.Printf("Failed memfs creation - probably bad path: %s", err)
|
||||
return errors.New(fmt.Sprintf("Failed to find directory %s", location))
|
||||
@@ -3845,7 +3826,9 @@ func runInitEs(ctx context.Context) {
|
||||
}
|
||||
|
||||
// FIXME: Have this for all envs in all orgs (loop and find).
|
||||
if len(parsedApikey) > 0 {
|
||||
if len(parsedApikey) == 0 {
|
||||
log.Printf("[WARNING] No apikey found for cleanup. Skipping cleanup schedule.")
|
||||
} else {
|
||||
cleanupSchedule := 300
|
||||
|
||||
if len(os.Getenv("SHUFFLE_RERUN_SCHEDULE")) > 0 {
|
||||
@@ -3860,8 +3843,25 @@ func runInitEs(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
environments := []string{"Shuffle"}
|
||||
log.Printf("[DEBUG] Starting schedule setup for execution cleanup every %d seconds. Running first immediately.", cleanupSchedule)
|
||||
environments := []string{defaultEnv}
|
||||
|
||||
// Comma separated list of RERUN environments
|
||||
if len(os.Getenv("SHUFFLE_RERUN_ENVIRONMENTS")) > 0 {
|
||||
foundenv := strings.Split(os.Getenv("SHUFFLE_RERUN_ENVIRONMENTS"), ",")
|
||||
for i, env := range foundenv {
|
||||
if len(env) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
environments[i] = strings.TrimSpace(env)
|
||||
if !shuffle.ArrayContains(environments, env) {
|
||||
environments = append(foundenv, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Starting schedule setup for execution cleanup every %d seconds. Running first immediately. Environments: %#v", cleanupSchedule, environments)
|
||||
|
||||
cleanupJob := func() func() {
|
||||
return func() {
|
||||
log.Printf("[INFO] Running schedule for cleaning up or re-running unfinished workflows in %d environments.", len(environments))
|
||||
@@ -3931,8 +3931,6 @@ func runInitEs(ctx context.Context) {
|
||||
} else {
|
||||
_ = jobret
|
||||
}
|
||||
} else {
|
||||
log.Printf("[DEBUG] Couldn't find a valid API-key, hence couldn't run cleanup")
|
||||
}
|
||||
|
||||
// Getting apps to see if we should initialize a test
|
||||
@@ -4947,10 +4945,12 @@ func initHandlers() {
|
||||
r.HandleFunc("/api/v1/files", shuffle.HandleGetFiles).Methods("GET", "OPTIONS")
|
||||
|
||||
// Introduced in 0.9.21 to handle notifications for e.g. failed Workflow
|
||||
r.HandleFunc("/api/v1/notifications", shuffle.HandleCreateNotification).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/notifications", shuffle.HandleGetNotifications).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/notifications/clear", shuffle.HandleClearNotifications).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
||||
//r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
||||
|
||||
r.HandleFunc("/api/v1/users/notifications", shuffle.HandleCreateNotification).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/users/notifications", shuffle.HandleGetNotifications).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/users/notifications/clear", shuffle.HandleClearNotifications).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/users/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
||||
|
||||
@@ -106,7 +106,10 @@ func createSchedule(ctx context.Context, scheduleId, workflowId, name, startNode
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Starting frequency for execution: %d", newfrequency)
|
||||
jobret, err := newscheduler.Every(newfrequency).Seconds().NotImmediately().Run(job)
|
||||
|
||||
|
||||
//jobret, err := newscheduler.Every(newfrequency).Seconds().NotImmediately().Run(job)
|
||||
jobret, err := newscheduler.Every(newfrequency).Seconds().Run(job)
|
||||
if err != nil {
|
||||
log.Printf("Failed to schedule workflow: %s", err)
|
||||
return err
|
||||
@@ -305,8 +308,13 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
|
||||
environment = env.OrgId
|
||||
}
|
||||
|
||||
if request.Method == "POST" {
|
||||
if rand.Intn(1) == 0 {
|
||||
// FIXME: Workflow stats disabled for now
|
||||
// as it caused too many problems
|
||||
// goal: track docker stuff once a minute and graph it
|
||||
// For now: Disable this as it caused too many problems
|
||||
if request.Method == "POST" && true == false {
|
||||
//log.Printf("[DEBUG] POST to workflowqueue")
|
||||
if rand.Intn(10) == 0 {
|
||||
// Parse out body
|
||||
body, err := ioutil.ReadAll(request.Body)
|
||||
if err == nil {
|
||||
@@ -924,13 +932,15 @@ func deleteWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Attempting to delete the workflow %s from the database...", fileId)
|
||||
err = shuffle.DeleteKey(ctx, "workflow", fileId)
|
||||
if err != nil {
|
||||
log.Printf("[DEBUG]] Failed deleting key %s", fileId)
|
||||
resp.WriteHeader(401)
|
||||
log.Printf("[DEBUG] Failed deleting workflow key %s", fileId)
|
||||
resp.WriteHeader(400)
|
||||
resp.Write([]byte(`{"success": false, "reason": "Failed deleting key"}`))
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Should have deleted workflow %s (%s)", workflow.Name, fileId)
|
||||
|
||||
cacheKey := fmt.Sprintf("%s_workflows", user.Id)
|
||||
@@ -1048,7 +1058,15 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
|
||||
return shuffle.WorkflowExecution{}, fmt.Sprintf(`workflow %s is invalid`, workflow.ID), errors.New("Failed getting workflow")
|
||||
}
|
||||
|
||||
workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request, 10)
|
||||
maxExecutionDepth := 10
|
||||
if os.Getenv("SHUFFLE_MAX_EXECUTION_DEPTH") != "" {
|
||||
maxExecutionDepthNew, err := strconv.Atoi(os.Getenv("SHUFFLE_MAX_EXECUTION_DEPTH"))
|
||||
if err == nil && maxExecutionDepthNew > 1 && maxExecutionDepthNew < 1000 {
|
||||
maxExecutionDepth = maxExecutionDepthNew
|
||||
}
|
||||
}
|
||||
|
||||
workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request, int64(maxExecutionDepth))
|
||||
if err != nil {
|
||||
err = shuffle.SetWorkflowExecution(ctx, workflowExecution, true)
|
||||
if err != nil {
|
||||
@@ -1059,7 +1077,7 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
|
||||
// Special for user input callbacks
|
||||
return workflowExecution, fmt.Sprintf("%s", err), nil
|
||||
} else {
|
||||
log.Printf("[ERROR] Failed in prepareExecution: %s", err)
|
||||
log.Printf("[ERROR] Failed in prepareExecution: '%s'", err)
|
||||
return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed starting workflow: %s", err), err
|
||||
}
|
||||
}
|
||||
@@ -1884,7 +1902,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[AUDIT] Starting execution of workflow '%s' by user %s (%s)!", fileId, user.Username, user.Id)
|
||||
log.Printf("[AUDIT] Starting execution of workflow '%s' by user '%s' (%s). If this is empty, it's most likely a subflow!", fileId, user.Username, user.Id)
|
||||
|
||||
user.ActiveOrg.Users = []shuffle.UserMini{}
|
||||
workflow.ExecutingOrg = user.ActiveOrg
|
||||
|
||||
+66
-46
@@ -1,54 +1,64 @@
|
||||
{
|
||||
"name": "shuffler",
|
||||
"homepage": "https://shuffler.io",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.3",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@codemirror/commands": "^6.2.4",
|
||||
"@emotion/is-prop-valid": "^1.1.1",
|
||||
"@codemirror/lang-python": "^6.1.3",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@emotion/styled": "^11.6.0",
|
||||
"@lezer/highlight": "^1.1.3",
|
||||
"@metamask/detect-provider": "^1.2.0",
|
||||
"@mui/icons-material": "^5.14.0",
|
||||
"@mui/material": "^5.14.0",
|
||||
"@mui/styles": "^5.14.0",
|
||||
"@mui/x-data-grid": "^5.17.11",
|
||||
"@mui/x-date-pickers": "^6.11.1",
|
||||
"@types/algoliasearch": "^3.34.11",
|
||||
"@uiw/codemirror-theme-basic": "^4.21.20",
|
||||
"@uiw/codemirror-theme-vscode": "^4.21.20",
|
||||
"@uiw/codemirror-themes": "^4.21.9",
|
||||
"@uiw/react-codemirror": "^4.21.9",
|
||||
"@use-it/interval": "^1.0.0",
|
||||
"algoliasearch": "^4.13.1",
|
||||
"calculate-size": "^1.1.1",
|
||||
"class-transformer": "^0.4.0",
|
||||
"@uiw/react-codemirror": "^4.21.21",
|
||||
"@use-it/interval": "^0.1.3",
|
||||
"algoliasearch": "^4.8.3",
|
||||
"class-transformer": "^0.2.0",
|
||||
"codemirror": "^6.0.1",
|
||||
"cpx": "^1.5.0",
|
||||
"create-react-app": "^5.0.1",
|
||||
"cytoscape": "^3.15.1",
|
||||
"cytoscape-edgehandles": "^3.6.0",
|
||||
"cytoscape-node-html-label": "^1.1.5",
|
||||
"d3": "^7.1.1",
|
||||
"dayjs": "^1.11.9",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-clipboard": "^2.2.1",
|
||||
"cytoscape-cxtmenu": "^3.4.0",
|
||||
"cytoscape-edgehandles": "^3.5.1",
|
||||
"cytoscape-grid-guide": "~2.3.3",
|
||||
"cytoscape-node-html-label": "^1.2.2",
|
||||
"cytoscape-panzoom": "^2.5.3",
|
||||
"cytoscape-undo-redo": "^1.3.3",
|
||||
"d3": "~4.10.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"dotenv": "^6.1.0",
|
||||
"downshift": "^3.3.5",
|
||||
"downshift": "^3.4.8",
|
||||
"express": "^4.17.1",
|
||||
"express-useragent": "^1.0.15",
|
||||
"github-markdown-css": "^3.0.1",
|
||||
"i18next": "^22.3.0",
|
||||
"i18next-browser-languagedetector": "^7.0.1",
|
||||
"i18next-chained-backend": "^4.2.0",
|
||||
"i18next-http-backend": "^2.1.1",
|
||||
"i18next-localstorage-backend": "^4.1.0",
|
||||
"i18next-xhr-backend": "^3.2.2",
|
||||
"import": "0.0.6",
|
||||
"interweave": "^11.2.0",
|
||||
"jss": "^10.10.0",
|
||||
"jss-camel-case": "^6.1.0",
|
||||
"jss-default-unit": "^8.0.2",
|
||||
"jss-global": "^3.0.0",
|
||||
"jss-nested": "^6.0.1",
|
||||
"jss-props-sort": "^6.0.0",
|
||||
"jss-vendor-prefixer": "^8.0.1",
|
||||
"is-plain-obj": "^4.1.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"match-sorter": "^6.3.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"mdbreact": "^4.21.1",
|
||||
"mime": "^3.0.0",
|
||||
"moment": "^2.29.1",
|
||||
"moment": "~2.29.4",
|
||||
"mui-chips-input": "^2.1.3",
|
||||
"mui-nested-menu": "^3.2.1",
|
||||
"process": "^0.11.10",
|
||||
"react": "^18.2.0",
|
||||
"react-alert": "^7.0.3",
|
||||
"react-alert-template-basic": "^1.0.0",
|
||||
"react-alice-carousel": "^2.6.4",
|
||||
"react-avatar-editor": "^11.1.0",
|
||||
"react-beforeunload": "^2.2.1",
|
||||
@@ -57,31 +67,40 @@
|
||||
"react-cytoscapejs": "^2.0.0",
|
||||
"react-device-detect": "^2.2.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-draggable": "^3.3.2",
|
||||
"react-draggable": "^4.4.5",
|
||||
"react-driftjs": "^1.2.2",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-ga4": "^2.0.0",
|
||||
"react-hotkeys": "^2.0.0",
|
||||
"react-i18next": "^13.1.2",
|
||||
"react-instantsearch-dom": "^6.28.0",
|
||||
"react-json-pretty": "^2.2.0",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-json-view-ssr": "^1.19.1",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-markdown-github": "^3.3.1",
|
||||
"react-powerhooks": "^0.0.7",
|
||||
"react-router": "^6.14.1",
|
||||
"react-router-dom": "^6.14.1",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-social-icons": "^5.15.0",
|
||||
"react-stripe-elements": "^6.1.2",
|
||||
"react-toastify": "^9.1.3",
|
||||
"reaviz": "^14.9.4",
|
||||
"reaviz": "^14.9.7",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-html": "^16.0.1",
|
||||
"remark-images": "^4.0.0",
|
||||
"remark-rehype": "^11.0.0",
|
||||
"rsuite": "^5.23.0",
|
||||
"search-insights": "^2.2.1",
|
||||
"shellwords": "^0.1.1",
|
||||
"shellwords": "^1.0.1",
|
||||
"simplebar": "^4.2.3",
|
||||
"styled-components": "^4.4.0",
|
||||
"webpack": "^5.88.2",
|
||||
"yaml": "^1.7.2",
|
||||
"styled-components": "^4.4.1",
|
||||
"sync-fetch": "^0.3.0",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"yaml": "^1.10.0",
|
||||
"yamljs": "^0.3.0",
|
||||
"zone.js": "^0.13.1"
|
||||
"zone.js": "~0.8.26"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "HTTPS=false&&PORT=3000 GENERATE_SOURCEMAP=false react-scripts --openssl-legacy-provider start",
|
||||
@@ -92,12 +111,7 @@
|
||||
"lint_file": "eslint 'src/views/AngularWorkflow.jsx'"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app",
|
||||
"rules": {
|
||||
"jsx-a11y/img-redundant-alt": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-loop-func": "off"
|
||||
}
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
@@ -106,13 +120,19 @@
|
||||
"not op_mini all"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.8",
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"prettier": "2.4.1",
|
||||
"@babel/cli": "^7.22.10",
|
||||
"@babel/core": "^7.22.10",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.22.5",
|
||||
"@babel/preset-flow": "^7.22.5",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"babel-loader": "^8.0.5",
|
||||
"babel-plugin-css-modules-transform": "^1.6.2",
|
||||
"babel-plugin-react-css-modules": "^5.2.6",
|
||||
"babel-plugin-transform-imports": "^2.0.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"promise-window": "^1.2.1",
|
||||
"react-16": "npm:react@16.13.1",
|
||||
"react-dom-16": "npm:react-dom@16.13.1",
|
||||
"react-error-overlay": "6.0.9"
|
||||
"react-hot-loader": "^4.13.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg width="131" height="28" viewBox="0 0 131 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 2L-1.62024e-08 16.6087L4.80057 16.6087L4.80057 6.87052L24 6.87052L24 2L0 2Z" fill="#FF8444"/>
|
||||
<path d="M19.1994 11.3912L19.1994 21.1294L-1.08006e-08 21.1294L-1.62024e-08 25.9999L24 25.9999L24 11.3912L19.1994 11.3912Z" fill="#FF8444"/>
|
||||
<path d="M14.608 11.3914L9.39062 11.3914L9.39062 16.6088L14.608 16.6088L14.608 11.3914Z" fill="#FF8444"/>
|
||||
<path d="M47.752 5.92C49.176 5.92 50.408 6.192 51.448 6.736C52.488 7.264 53.368 8.048 54.088 9.088L52.36 10.744C51.752 9.816 51.064 9.152 50.296 8.752C49.544 8.336 48.648 8.128 47.608 8.128C46.84 8.128 46.208 8.232 45.712 8.44C45.216 8.648 44.848 8.928 44.608 9.28C44.384 9.616 44.272 10 44.272 10.432C44.272 10.928 44.44 11.36 44.776 11.728C45.128 12.096 45.776 12.384 46.72 12.592L49.936 13.312C51.472 13.648 52.56 14.16 53.2 14.848C53.84 15.536 54.16 16.408 54.16 17.464C54.16 18.44 53.896 19.288 53.368 20.008C52.84 20.728 52.104 21.28 51.16 21.664C50.232 22.048 49.136 22.24 47.872 22.24C46.752 22.24 45.744 22.096 44.848 21.808C43.952 21.52 43.168 21.128 42.496 20.632C41.824 20.136 41.272 19.568 40.84 18.928L42.616 17.152C42.952 17.712 43.376 18.216 43.888 18.664C44.4 19.096 44.992 19.432 45.664 19.672C46.352 19.912 47.112 20.032 47.944 20.032C48.68 20.032 49.312 19.944 49.84 19.768C50.384 19.592 50.792 19.336 51.064 19C51.352 18.648 51.496 18.232 51.496 17.752C51.496 17.288 51.336 16.88 51.016 16.528C50.712 16.176 50.136 15.904 49.288 15.712L45.808 14.92C44.848 14.712 44.056 14.416 43.432 14.032C42.808 13.648 42.344 13.184 42.04 12.64C41.736 12.08 41.584 11.456 41.584 10.768C41.584 9.872 41.824 9.064 42.304 8.344C42.8 7.608 43.512 7.024 44.44 6.592C45.368 6.144 46.472 5.92 47.752 5.92ZM57.3904 22V4.6H59.9584V11.92C60.3584 11.168 60.8944 10.624 61.5664 10.288C62.2544 9.936 63.0144 9.76 63.8464 9.76C64.6944 9.76 65.4544 9.928 66.1264 10.264C66.8144 10.584 67.3584 11.072 67.7584 11.728C68.1584 12.384 68.3584 13.216 68.3584 14.224V22H65.7904V15.04C65.7904 13.856 65.5424 13.032 65.0464 12.568C64.5664 12.104 63.9584 11.872 63.2224 11.872C62.7104 11.872 62.1984 12 61.6864 12.256C61.1904 12.496 60.7744 12.896 60.4384 13.456C60.1184 14 59.9584 14.736 59.9584 15.664V22H57.3904ZM76.5218 22.24C75.7378 22.24 75.0098 22.096 74.3378 21.808C73.6818 21.52 73.1538 21.056 72.7538 20.416C72.3538 19.776 72.1538 18.944 72.1538 17.92V10H74.7218V17.272C74.7218 18.36 74.9538 19.112 75.4178 19.528C75.8818 19.928 76.5298 20.128 77.3618 20.128C77.7618 20.128 78.1458 20.064 78.5138 19.936C78.8978 19.792 79.2418 19.576 79.5458 19.288C79.8498 18.984 80.0818 18.6 80.2418 18.136C80.4178 17.672 80.5058 17.128 80.5058 16.504V10H83.0738V22H80.8178L80.6978 20.056C80.2818 20.808 79.7218 21.36 79.0178 21.712C78.3138 22.064 77.4818 22.24 76.5218 22.24ZM92.1738 4.432C92.6698 4.432 93.1178 4.488 93.5178 4.6C93.9338 4.696 94.2458 4.832 94.4538 5.008L93.9738 6.856C93.7978 6.744 93.5978 6.664 93.3738 6.616C93.1498 6.552 92.8938 6.52 92.6058 6.52C91.9498 6.52 91.4298 6.672 91.0458 6.976C90.6778 7.28 90.4938 7.776 90.4938 8.464V10.216L90.5658 10.864V22H87.9978V8.272C87.9978 7.664 88.0858 7.12 88.2617 6.64C88.4538 6.16 88.7338 5.76 89.1018 5.44C89.4698 5.104 89.9098 4.856 90.4218 4.696C90.9498 4.52 91.5338 4.432 92.1738 4.432ZM94.3818 10V12.016H85.7418V10H94.3818ZM101.678 4.432C102.174 4.432 102.622 4.488 103.022 4.6C103.438 4.696 103.75 4.832 103.958 5.008L103.478 6.856C103.302 6.744 103.102 6.664 102.878 6.616C102.654 6.552 102.398 6.52 102.11 6.52C101.454 6.52 100.934 6.672 100.55 6.976C100.182 7.28 99.9978 7.776 99.9978 8.464V10.216L100.07 10.864V22H97.5018V8.272C97.5018 7.664 97.5898 7.12 97.7657 6.64C97.9578 6.16 98.2378 5.76 98.6058 5.44C98.9738 5.104 99.4138 4.856 99.9258 4.696C100.454 4.52 101.038 4.432 101.678 4.432ZM103.886 10V12.016H95.2458V10H103.886ZM108.662 4.6V18.64C108.662 19.232 108.766 19.64 108.974 19.864C109.182 20.088 109.526 20.2 110.006 20.2C110.294 20.2 110.534 20.184 110.726 20.152C110.934 20.104 111.19 20.024 111.494 19.912L111.206 21.832C110.934 21.96 110.622 22.056 110.27 22.12C109.918 22.2 109.566 22.24 109.214 22.24C108.142 22.24 107.35 21.968 106.838 21.424C106.342 20.864 106.094 20.008 106.094 18.856V4.6H108.662ZM118.967 22.24C117.767 22.24 116.711 21.992 115.799 21.496C114.887 21 114.175 20.288 113.663 19.36C113.167 18.416 112.919 17.296 112.919 16C112.919 14.704 113.167 13.592 113.663 12.664C114.175 11.72 114.879 11 115.775 10.504C116.671 10.008 117.687 9.76 118.823 9.76C119.991 9.76 120.983 10 121.799 10.48C122.615 10.96 123.239 11.616 123.671 12.448C124.103 13.28 124.319 14.224 124.319 15.28C124.319 15.568 124.311 15.84 124.295 16.096C124.279 16.352 124.255 16.576 124.223 16.768H114.575V14.8H123.095L121.823 15.184C121.823 14.096 121.551 13.264 121.007 12.688C120.463 12.096 119.719 11.8 118.775 11.8C118.087 11.8 117.487 11.96 116.975 12.28C116.463 12.6 116.071 13.08 115.799 13.72C115.527 14.344 115.391 15.112 115.391 16.024C115.391 16.92 115.535 17.68 115.823 18.304C116.111 18.928 116.519 19.4 117.047 19.72C117.575 20.04 118.199 20.2 118.919 20.2C119.719 20.2 120.367 20.048 120.863 19.744C121.359 19.44 121.751 19.016 122.039 18.472L124.079 19.432C123.791 20.008 123.399 20.512 122.903 20.944C122.423 21.36 121.847 21.68 121.175 21.904C120.503 22.128 119.767 22.24 118.967 22.24Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
+4
-10
@@ -8,8 +8,8 @@ import Workflows from "./views/Workflows";
|
||||
import GettingStarted from "./views/GettingStarted";
|
||||
import AngularWorkflow from "./views/AngularWorkflow.jsx";
|
||||
|
||||
//import Header from "./components/NewHeader.jsx";
|
||||
import Header from "./components/Header.jsx";
|
||||
import Header from "./components/NewHeader.jsx";
|
||||
//import Header from "./components/Header.jsx";
|
||||
import theme from "./theme";
|
||||
import Apps from "./views/Apps";
|
||||
import AppCreator from "./views/AppCreator";
|
||||
@@ -37,7 +37,6 @@ import UpdateAuthentication from "./views/UpdateAuthentication.jsx";
|
||||
import FrameworkWrapper from "./views/FrameworkWrapper.jsx";
|
||||
import ScrollToTop from "./components/ScrollToTop";
|
||||
import AlertTemplate from "./components/AlertTemplate";
|
||||
import { useAlert, positions, Provider } from "react-alert";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import RuntimeDebugger from "./components/RuntimeDebugger.jsx"
|
||||
|
||||
@@ -160,10 +159,6 @@ const App = (message, props) => {
|
||||
|
||||
// Dumb for content load (per now), but good for making the site not suddenly reload parts (ajax thingies)
|
||||
|
||||
const options = {
|
||||
timeout: 9000,
|
||||
position: positions.BOTTOM_LEFT,
|
||||
};
|
||||
|
||||
const handleFirstInteraction = (event) => {
|
||||
console.log("First interaction: ", event)
|
||||
@@ -245,6 +240,7 @@ const App = (message, props) => {
|
||||
setCookie={setCookie}
|
||||
cookies={cookies}
|
||||
checkLogin={checkLogin}
|
||||
notifications={notifications}
|
||||
{...props}
|
||||
/>
|
||||
}
|
||||
@@ -566,9 +562,7 @@ const App = (message, props) => {
|
||||
<CssBaseline />
|
||||
<CookiesProvider>
|
||||
<BrowserRouter>
|
||||
<Provider template={AlertTemplate} {...options}>
|
||||
{includedData}
|
||||
</Provider>
|
||||
{includedData}
|
||||
</BrowserRouter>
|
||||
<ToastContainer
|
||||
position="bottom-center"
|
||||
|
||||
@@ -1230,6 +1230,7 @@ const Billing = (props) => {
|
||||
</Typography>
|
||||
</div>
|
||||
<BillingStats
|
||||
isCloud={isCloud}
|
||||
globalUrl={globalUrl}
|
||||
selectedOrganization={selectedOrganization}
|
||||
userdata={userdata}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import classNames from "classnames";
|
||||
import theme from '../theme.jsx';
|
||||
import classNames from "classnames";
|
||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
||||
|
||||
import {
|
||||
DatePicker,
|
||||
DateTimePicker,
|
||||
LocalizationProvider,
|
||||
} from '@mui/x-date-pickers'
|
||||
|
||||
import {
|
||||
Tooltip,
|
||||
@@ -52,12 +59,14 @@ import {
|
||||
LinearXAxisTickLabel,
|
||||
} from 'reaviz';
|
||||
|
||||
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||
|
||||
const LineChartWrapper = ({keys, inputname, height, width}) => {
|
||||
const [hovered, setHovered] = useState("");
|
||||
const inputdata = keys.data === undefined ? keys : keys.data
|
||||
|
||||
return (
|
||||
<div style={{color: "white", border: "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette.borderRadius, padding: 30, marginTop: 15, }}>
|
||||
<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, }}>
|
||||
{inputname}
|
||||
</Typography>
|
||||
@@ -75,16 +84,174 @@ const LineChartWrapper = ({keys, inputname, height, width}) => {
|
||||
|
||||
|
||||
const AppStats = (defaultprops) => {
|
||||
const { globalUrl, selectedOrganization, userdata, } = defaultprops;
|
||||
const { globalUrl, selectedOrganization, userdata, isCloud, } = defaultprops;
|
||||
|
||||
const [keys, setKeys] = useState([])
|
||||
const [searches, setSearches] = useState([]);
|
||||
const [clickData, setClickData] = useState(undefined);
|
||||
const [conversionData, setConversionData] = useState(undefined);
|
||||
const [statistics, setStatistics] = useState(undefined);
|
||||
const [appRuns, setAppruns] = useState(undefined);
|
||||
const [appRunCosts, setApprunCosts] = useState(undefined);
|
||||
const [workflowRuns, setWorkflowRuns] = useState(undefined);
|
||||
const [subflowRuns, setSubflowRuns] = useState(undefined);
|
||||
|
||||
const [endTime, setEndTime] = useState("")
|
||||
const [startTime, setStartTime] = useState("")
|
||||
const [statistics, setStatistics] = useState(undefined);
|
||||
const [filteredStatistics, setFilteredStatistics] = useState(undefined);
|
||||
|
||||
const [apprunCost, setApprunCost] = useState(0)
|
||||
const [monthToDateCost, setMonthToDateCost] = useState(0)
|
||||
const [monthTotalCost, setMonthTotalCost] = useState(0)
|
||||
|
||||
const includedExecutions = selectedOrganization.sync_features.app_executions !== undefined ? selectedOrganization.sync_features.app_executions.limit : 0
|
||||
|
||||
// Cost in old contracts: 0.0009
|
||||
// Old contracts also always included 150.000 executions
|
||||
const invocationCost = includedExecutions === 150000 || includedExecutions === 250000 ? 0.0009 : typecost_single
|
||||
const defaultAmount = 10000
|
||||
|
||||
useEffect(() => {
|
||||
if (statistics === undefined || statistics === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (statistics["daily_statistics"] === undefined || statistics["daily_statistics"] === null) {
|
||||
setFilteredStatistics(statistics)
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate month to date cost
|
||||
var mtd_cost = 0
|
||||
for (let key in statistics["daily_statistics"]) {
|
||||
const item = statistics["daily_statistics"][key]
|
||||
if (item["date"] === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
const date = new Date(item["date"])
|
||||
const today = new Date()
|
||||
if (date.getMonth() === today.getMonth()) {
|
||||
mtd_cost += (item["app_executions"] * invocationCost)
|
||||
}
|
||||
}
|
||||
|
||||
if (isCloud && mtd_cost !== monthToDateCost) {
|
||||
// Find how many days there have been in the current month
|
||||
const today = new Date()
|
||||
const daysInMonth = new Date(today.getFullYear(), today.getMonth()+1, 0).getDate()
|
||||
// Find what day we are on
|
||||
const day = today.getDate()
|
||||
// Find how many days are left in the month
|
||||
const daysLeft = daysInMonth - day
|
||||
|
||||
// Calculate the cost of the entire month
|
||||
var monthTotalCost = mtd_cost/day*daysInMonth
|
||||
monthTotalCost -= defaultAmount*invocationCost
|
||||
monthTotalCost -= includedExecutions*invocationCost
|
||||
|
||||
// Remove included amount
|
||||
//const defaultAmount = 10000
|
||||
mtd_cost -= defaultAmount*invocationCost
|
||||
mtd_cost -= includedExecutions*invocationCost
|
||||
|
||||
if (monthTotalCost > 0) {
|
||||
setMonthTotalCost(monthTotalCost.toFixed(2))
|
||||
}
|
||||
|
||||
if (mtd_cost > 0) {
|
||||
setMonthToDateCost(mtd_cost.toFixed(2))
|
||||
}
|
||||
}
|
||||
|
||||
// Make a date at the 1st of the current month
|
||||
var foundstarttime = (new Date())
|
||||
foundstarttime.setDate(1)
|
||||
if (startTime !== "" && startTime !== undefined && startTime !== null) {
|
||||
foundstarttime = startTime
|
||||
}
|
||||
|
||||
// Set to tomorrow by default
|
||||
var foundendtime = (new Date())
|
||||
foundendtime.setDate(foundendtime.getDate() + 1)
|
||||
|
||||
// Check if endtime is after the daily statistics["date"] string
|
||||
if (endTime !== "" && endTime !== undefined && endTime !== null) {
|
||||
foundendtime = endTime
|
||||
}
|
||||
|
||||
// Check if start time is before the daily statistics["date"] string
|
||||
var newlist = []
|
||||
for (let key in statistics["daily_statistics"]) {
|
||||
const item = statistics["daily_statistics"][key]
|
||||
if (item["date"] === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
const date = new Date(item["date"])
|
||||
if (date >= foundstarttime) {
|
||||
if (date <= foundendtime) {
|
||||
newlist.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If newlist is empty, set the timestamp to 1 year back and check if there are any statistics there
|
||||
// If foundstarttime is more than 30 days back, don't do this
|
||||
/*
|
||||
if (newlist.length === 0 && foundstarttime.getDate() > 30) {
|
||||
// Set the timestamp to be back
|
||||
foundstarttime.setFullYear(foundstarttime.getFullYear() - 1)
|
||||
setStartTime(foundstarttime)
|
||||
|
||||
console.log("IN HERE")
|
||||
}
|
||||
*/
|
||||
|
||||
var tmpstats = JSON.parse(JSON.stringify(statistics))
|
||||
|
||||
var workflowexecutions = 0
|
||||
var appexecutions = 0
|
||||
var estimatedcost = 0
|
||||
if (newlist.length > 0) {
|
||||
tmpstats["daily_statistics"] = newlist
|
||||
|
||||
for (let key in newlist) {
|
||||
const item = newlist[key]
|
||||
if (item["workflow_executions"] === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
workflowexecutions += item["workflow_executions"]
|
||||
appexecutions += item["app_executions"]
|
||||
|
||||
estimatedcost += (item["app_executions"] * invocationCost)
|
||||
}
|
||||
|
||||
tmpstats["monthly_workflow_executions"] = workflowexecutions
|
||||
tmpstats["monthly_app_executions"] = appexecutions
|
||||
}
|
||||
|
||||
// Make estimatedcost have max 2 decimals
|
||||
if (isCloud) {
|
||||
// Exclude includedExecutions*month
|
||||
// const includedExecutions = 150000
|
||||
//estimatedcost -= (includedExecutions * invocationCost)
|
||||
|
||||
setApprunCost(estimatedcost.toFixed(2))
|
||||
}
|
||||
|
||||
setFilteredStatistics(tmpstats)
|
||||
handleDataSetting(tmpstats, "day")
|
||||
|
||||
}, [statistics, startTime, endTime])
|
||||
|
||||
const handleStartTimeChange = (date) => {
|
||||
setStartTime(date)
|
||||
}
|
||||
|
||||
const handleEndTimeChange = (date) => {
|
||||
setEndTime(date)
|
||||
}
|
||||
|
||||
const handleDataSetting = (inputdata, grouping) => {
|
||||
if (inputdata === undefined || inputdata === null) {
|
||||
return
|
||||
@@ -95,8 +262,6 @@ const AppStats = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Looking at daily data: ", inputdata)
|
||||
|
||||
var appRuns = {
|
||||
"key": "App Runs",
|
||||
"data": []
|
||||
@@ -112,6 +277,11 @@ const AppStats = (defaultprops) => {
|
||||
"data": []
|
||||
}
|
||||
|
||||
var appcostRuns = {
|
||||
"key": "Cost of App Runs",
|
||||
"data": []
|
||||
}
|
||||
|
||||
for (let key in dailyStats) {
|
||||
// Always skips first one as it has accumulated data in it
|
||||
if (key === 0) {
|
||||
@@ -119,7 +289,6 @@ const AppStats = (defaultprops) => {
|
||||
}
|
||||
|
||||
const item = dailyStats[key]
|
||||
|
||||
if (item["date"] === undefined) {
|
||||
console.log("No date: ", item)
|
||||
continue
|
||||
@@ -131,6 +300,12 @@ const AppStats = (defaultprops) => {
|
||||
key: new Date(item["date"]),
|
||||
data: item["app_executions"]
|
||||
})
|
||||
|
||||
// Add number
|
||||
appcostRuns["data"].push({
|
||||
key: new Date(item["date"]),
|
||||
data: (item["app_executions"] * invocationCost).toFixed(2)
|
||||
})
|
||||
}
|
||||
|
||||
// Check if workflow_executions key in item
|
||||
@@ -150,12 +325,16 @@ const AppStats = (defaultprops) => {
|
||||
}
|
||||
|
||||
// Adds data for today
|
||||
console.log("Inputdata: ", inputdata)
|
||||
if (inputdata["daily_app_executions"] !== undefined && inputdata["daily_app_executions"] !== null) {
|
||||
appRuns["data"].push({
|
||||
key: new Date(),
|
||||
data: inputdata["daily_app_executions"]
|
||||
})
|
||||
|
||||
appcostRuns["data"].push({
|
||||
key: new Date(),
|
||||
data: (inputdata["daily_app_executions"] * invocationCost).toFixed(2)
|
||||
})
|
||||
}
|
||||
|
||||
if (inputdata["daily_workflow_executions"] !== undefined && inputdata["daily_workflow_executions"] !== null) {
|
||||
@@ -175,6 +354,7 @@ const AppStats = (defaultprops) => {
|
||||
setSubflowRuns(subflowRuns)
|
||||
setWorkflowRuns(workflowRuns)
|
||||
setAppruns(appRuns)
|
||||
setApprunCosts(appcostRuns)
|
||||
}
|
||||
|
||||
const getStats = () => {
|
||||
@@ -186,25 +366,25 @@ const AppStats = (defaultprops) => {
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for workflows :O!: ", response.status);
|
||||
return;
|
||||
}
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for workflows :O!: ", response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
return
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
return
|
||||
}
|
||||
|
||||
setStatistics(responseJson)
|
||||
handleDataSetting(responseJson, "day")
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error: ", error)
|
||||
});
|
||||
setStatistics(responseJson)
|
||||
handleDataSetting(responseJson, "day")
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error: ", error)
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -215,40 +395,130 @@ const AppStats = (defaultprops) => {
|
||||
textAlign: "center",
|
||||
padding: 40,
|
||||
margin: 5,
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
maxWidth: 300,
|
||||
}
|
||||
|
||||
const data = (
|
||||
<div className="content" style={{width: "100%", margin: "auto", }}>
|
||||
<Typography variant="body1" style={{margin: "auto", marginLeft: 10, marginBottom: 20, }}>
|
||||
All Stat widgets are monthly and gathered from <a
|
||||
All shown statistics are gathered from <a
|
||||
href={`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`}
|
||||
target="_blank"
|
||||
style={{ textDecoration: "none", color: "#f85a3e",}}
|
||||
>Your Organization Statistics. </a>
|
||||
This is a feature to help give you more insight into Shuffle, and will be populating over time.
|
||||
>Your Organization Statistics </a>
|
||||
This is a feature to help give you more insight into Shuffle, 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>
|
||||
</Typography>
|
||||
{statistics !== undefined ?
|
||||
<div style={{display: "flex", textAlign: "center",}}>
|
||||
<Paper style={paperStyle}>
|
||||
<Typography variant="h4">
|
||||
{statistics.monthly_workflow_executions}
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
Workflow Runs
|
||||
</Typography>
|
||||
</Paper>
|
||||
<Paper style={paperStyle}>
|
||||
<Typography variant="h4">
|
||||
{statistics.monthly_app_executions}
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
App Runs
|
||||
</Typography>
|
||||
</Paper>
|
||||
</div>
|
||||
: null}
|
||||
|
||||
<div style={{display: "flex", textAlign: "center",}}>
|
||||
{filteredStatistics !== undefined ?
|
||||
<div style={{flex: 1, display: "flex", textAlign: "center",}}>
|
||||
<Tooltip title={
|
||||
<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}.
|
||||
</Typography>
|
||||
}>
|
||||
<Paper style={paperStyle}>
|
||||
<Typography variant="h4">
|
||||
{selectedOrganization.lead_info.customer === false && selectedOrganization.lead_info.pov === false ?
|
||||
0
|
||||
:
|
||||
apprunCost
|
||||
}
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
Period Cost
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
<Tooltip title={
|
||||
<Typography variant="body1" style={{padding: 10, }}>
|
||||
App runs in the selected period
|
||||
</Typography>
|
||||
}>
|
||||
<Paper style={paperStyle}>
|
||||
<Typography variant="h4">
|
||||
{filteredStatistics.monthly_app_executions === null || filteredStatistics.monthly_app_executions === undefined ? 0 : filteredStatistics.monthly_app_executions}
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
App Runs
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
<Tooltip title={
|
||||
<Typography variant="body1" style={{padding: 10, }}>
|
||||
Workflow runs in the selected period
|
||||
</Typography>
|
||||
}>
|
||||
<Paper style={paperStyle}>
|
||||
<Typography variant="h4">
|
||||
{filteredStatistics.monthly_workflow_executions === null || filteredStatistics.monthly_workflow_executions === undefined ? 0 : filteredStatistics.monthly_workflow_executions}
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
Workflow Runs
|
||||
</Typography>
|
||||
</Paper>
|
||||
</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}.
|
||||
</Typography>
|
||||
}>
|
||||
<Paper style={{
|
||||
textAlign: "center",
|
||||
padding: 40,
|
||||
margin: 5,
|
||||
marginLeft: 90,
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
maxWidth: 300,
|
||||
}}>
|
||||
<Typography variant="h4">
|
||||
${monthTotalCost}
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
Estimated cost
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
: null}
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs} style={{flex: 1, }}>
|
||||
<div style={{display: "flex", flexDirection: "column", }}>
|
||||
<DateTimePicker
|
||||
sx={{
|
||||
marginTop: 1,
|
||||
marginLeft: 1,
|
||||
minWidth: 240,
|
||||
maxWidth: 240,
|
||||
}}
|
||||
ampm={false}
|
||||
label="Search from"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value={startTime}
|
||||
onChange={handleStartTimeChange}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
<DateTimePicker
|
||||
sx={{
|
||||
marginTop: 1,
|
||||
marginLeft: 1,
|
||||
minWidth: 240,
|
||||
maxWidth: 240,
|
||||
}}
|
||||
ampm={false}
|
||||
label="Search until"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value={endTime}
|
||||
onChange={handleEndTimeChange}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
</div>
|
||||
</LocalizationProvider>
|
||||
|
||||
</div>
|
||||
|
||||
{appRuns === undefined ?
|
||||
null
|
||||
@@ -267,6 +537,12 @@ const AppStats = (defaultprops) => {
|
||||
:
|
||||
<LineChartWrapper keys={subflowRuns} height={300} width={"100%"} inputname={"Subflow Runs"}/>
|
||||
}
|
||||
|
||||
{/*appRunCosts === undefined ?
|
||||
null
|
||||
:
|
||||
<LineChartWrapper keys={appRunCosts} height={300} width={"100%"} inputname={"Apprun cost - Cost per day"}/>
|
||||
*/}
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import theme from "../theme.jsx";
|
||||
import { toast } from 'react-toastify';
|
||||
import ReactJson from "react-json-view";
|
||||
|
||||
import {
|
||||
Tooltip,
|
||||
@@ -42,6 +43,7 @@ import {
|
||||
Visibility as VisibilityIcon,
|
||||
VisibilityOff as VisibilityOffIcon,
|
||||
} from "@mui/icons-material";
|
||||
import { validateJson, } from "../views/Workflows.jsx";
|
||||
|
||||
const scrollStyle1 = {
|
||||
height: 100,
|
||||
@@ -59,6 +61,7 @@ const scrollStyle2 = {
|
||||
overflow: "scroll",
|
||||
}
|
||||
|
||||
|
||||
const CacheView = (props) => {
|
||||
const { globalUrl, userdata, serverside, orgId } = props;
|
||||
const [orgCache, setOrgCache] = React.useState("");
|
||||
@@ -150,11 +153,22 @@ const CacheView = (props) => {
|
||||
|
||||
const deleteCache = (orgId, key) => {
|
||||
toast("Attempting to delete Cache");
|
||||
fetch(globalUrl + `/api/v1/orgs/${orgId}/cache/${key}`, {
|
||||
method: "DELETE",
|
||||
|
||||
// method: "DELETE",
|
||||
const method = "POST"
|
||||
//const url = `${globalUrl}/api/v1/orgs/${orgId}/cache/${key}`
|
||||
const url = `${globalUrl}/api/v1/orgs/${orgId}/delete_cache`
|
||||
const parsed = {
|
||||
"org_id": orgId,
|
||||
"key": key,
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(parsed),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
@@ -334,7 +348,7 @@ const CacheView = (props) => {
|
||||
|
||||
return (
|
||||
|
||||
<div>
|
||||
<div style={{paddingBottom: 250, }}>
|
||||
{modalView}
|
||||
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
||||
<h2 style={{ display: "inline" }}>Shuffle Datastore</h2>
|
||||
@@ -380,19 +394,18 @@ const CacheView = (props) => {
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary="Key"
|
||||
// style={{ minWidth: 150, maxWidth: 150 }}
|
||||
style={{ minWidth: 250, maxWidth: 250, }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="value"
|
||||
// style={{ minWidth: 150, maxWidth: 150 }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Updated"
|
||||
// style={{ minWidth: 150, maxWidth: 150 }}
|
||||
primary="Value"
|
||||
style={{ minWidth: 400, maxWidth: 400, overflowX: "auto", overflowY: "hidden", }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Actions"
|
||||
// style={{ minWidth: 150, maxWidth: 150 }}
|
||||
style={{ minWidth: 150, maxWidth: 150, marginLeft: 50, }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Updated"
|
||||
/>
|
||||
</ListItem>
|
||||
{listCache === undefined || listCache === null
|
||||
@@ -402,58 +415,56 @@ const CacheView = (props) => {
|
||||
if (index % 2 === 0) {
|
||||
bgColor = "#1f2023";
|
||||
}
|
||||
|
||||
const validate = validateJson(data.value);
|
||||
console.log("Past validate: ", validate);
|
||||
|
||||
return (
|
||||
<ListItem key={index} style={{ backgroundColor: bgColor }}>
|
||||
<ListItemText
|
||||
style={{
|
||||
maxWidth: 225,
|
||||
minWidth: 225,
|
||||
maxWidth: 250,
|
||||
minWidth: 250,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
primary={data.key}
|
||||
/>
|
||||
<div style={scrollStyle1}>
|
||||
<ListItemText
|
||||
// style={{
|
||||
// maxWidth: 225,
|
||||
// maxHeight: 150,
|
||||
// // overflow: "hidden",
|
||||
// paddingLeft: "52px",
|
||||
// overflow: "scroll",
|
||||
|
||||
// }}
|
||||
style={scrollStyle2}
|
||||
// style={{ maxWidth: 100, minWidth: 100 }}
|
||||
// onMouseOver={() =>
|
||||
// setShow((prevState) => ({ ...prevState, [data.value]: true }))
|
||||
// }
|
||||
// onMouseLeave={() =>
|
||||
// setShow((prevState) => ({ ...prevState, [data.value]: false }))
|
||||
// }
|
||||
//primary={show[data.value] ? data.value : `${data.value.substring(0, 5)}...`}
|
||||
primary={data.value}
|
||||
/>
|
||||
</div>
|
||||
style={{
|
||||
minWidth: 400,
|
||||
maxWidth: 400,
|
||||
overflowX: "auto",
|
||||
overflowY: "hidden",
|
||||
}}
|
||||
primary={validate.valid ?
|
||||
<ReactJson
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={true}
|
||||
enableClipboard={(copy) => {
|
||||
//handleReactJsonClipboard(copy);
|
||||
}}
|
||||
displayDataTypes={false}
|
||||
onSelect={(select) => {
|
||||
//HandleJsonCopy(showResult, select, data.action.label);
|
||||
//console.log("SELECTED!: ", select);
|
||||
}}
|
||||
name={"value"}
|
||||
/>
|
||||
:
|
||||
data.value
|
||||
}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
maxWidth: 225,
|
||||
minWidth: 225,
|
||||
overflow: "hidden",
|
||||
marginLeft: "42px",
|
||||
}}
|
||||
primary={new Date(data.edited * 1000).toISOString()}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
minWidth: 250,
|
||||
maxWidth: 250,
|
||||
overflow: "hidden",
|
||||
paddingLeft: "155px",
|
||||
maxWidth: 150,
|
||||
minWidth: 150,
|
||||
marginLeft: 50,
|
||||
}}
|
||||
primary=<span style={{ display: "inline" }}>
|
||||
<Tooltip
|
||||
title="Edit"
|
||||
title="Edit item"
|
||||
style={{}}
|
||||
aria-label={"Edit"}
|
||||
>
|
||||
@@ -473,7 +484,7 @@ const CacheView = (props) => {
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={"Delete Cache"}
|
||||
title={"Delete item"}
|
||||
style={{ marginLeft: 15, }}
|
||||
aria-label={"Delete"}
|
||||
>
|
||||
@@ -493,6 +504,13 @@ const CacheView = (props) => {
|
||||
</Tooltip>
|
||||
</span>
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
maxWidth: 225,
|
||||
minWidth: 225,
|
||||
}}
|
||||
primary={new Date(data.edited * 1000).toISOString()}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -32,6 +32,8 @@ import {
|
||||
import { FixName } from "../views/Apps.jsx";
|
||||
import aa from 'search-insights'
|
||||
|
||||
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
||||
|
||||
// Handles workflow updates on first open to highlight the issues of the workflow
|
||||
// Variables
|
||||
// Action (exists, missing fields)
|
||||
@@ -60,6 +62,8 @@ const ConfigureWorkflow = (props) => {
|
||||
setAuthenticationType,
|
||||
setAuthenticationModalOpen,
|
||||
setConfigureWorkflowModalOpen,
|
||||
|
||||
setConfigurationFinished,
|
||||
} = props;
|
||||
|
||||
const [requiredActions, setRequiredActions] = React.useState([]);
|
||||
@@ -70,9 +74,19 @@ const ConfigureWorkflow = (props) => {
|
||||
const [firstLoad, setFirstLoad] = React.useState("");
|
||||
const [showFinalizeAnimation, setShowFinalizeAnimation] = React.useState(false);
|
||||
const [loopRunning, setLoopRunning] = useState(false)
|
||||
|
||||
const [checkStarted, setCheckStarted] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Required actions: ", requiredActions)
|
||||
if (requiredActions.length === 0) {
|
||||
console.log("No more actions? Set parent to done?")
|
||||
|
||||
if (setConfigurationFinished !== undefined) {
|
||||
setConfigurationFinished(true)
|
||||
}
|
||||
}
|
||||
}, [requiredActions])
|
||||
|
||||
const stop = () => {
|
||||
setLoopRunning(false)
|
||||
}
|
||||
@@ -81,6 +95,7 @@ const ConfigureWorkflow = (props) => {
|
||||
setLoopRunning(true)
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (loopRunning) {
|
||||
const intervalId = setInterval(() => {
|
||||
@@ -159,7 +174,6 @@ const ConfigureWorkflow = (props) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
console.log("ACTION: ", responseJson);
|
||||
if (
|
||||
responseJson.actions !== undefined &&
|
||||
responseJson.actions !== null
|
||||
@@ -215,6 +229,9 @@ const ConfigureWorkflow = (props) => {
|
||||
// without version match
|
||||
const newappname = action.app_name.toLowerCase().replaceAll(" ", "_")
|
||||
const app = apps.find((app) => app.id === action.app_id || app.name.toLowerCase().replaceAll(" ", "_") === newappname)
|
||||
|
||||
|
||||
|
||||
if (app === undefined || app === null) {
|
||||
|
||||
const subapp = apps.find(app => app.name === action.app_name)
|
||||
@@ -229,47 +246,51 @@ const ConfigureWorkflow = (props) => {
|
||||
"required": true,
|
||||
})
|
||||
} else {
|
||||
|
||||
if (action.authentication_id === "" && app.authentication.required === true && action.parameters !== undefined && action.parameters !== null) {
|
||||
// Check if configuration is filled or not
|
||||
// Check if configuration is filled or not
|
||||
var filled = true;
|
||||
for (let [key,keyval] in Object.entries(action.parameters)) {
|
||||
if (action.parameters[key].configuration) {
|
||||
//console.log("Found config: ", action.parameters[key])
|
||||
if (
|
||||
action.parameters[key].value === null ||
|
||||
action.parameters[key].value.length === 0
|
||||
) {
|
||||
if (action.parameters[key].value === null || action.parameters[key].value.length === 0) {
|
||||
filled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (app.authentication.type === "oauth2" || app.authentication.type === "oauth2-app") {
|
||||
filled = false
|
||||
|
||||
action.auth_type = "oauth2"
|
||||
}
|
||||
|
||||
newaction.steps.push({
|
||||
"title": "Authenticate app",
|
||||
"type": "authenticate",
|
||||
"required": true,
|
||||
"auth_type": app.authentication.type,
|
||||
})
|
||||
|
||||
if (!filled) {
|
||||
newaction.must_authenticate = true;
|
||||
newaction.action_ids.push(action.id);
|
||||
}
|
||||
} else if (action.authentication_id !== "" && app.authentication.required === true) {
|
||||
console.log("Should verify authentication ID ", action.authentication_id)
|
||||
|
||||
} else if (action.authentication_id !== undefined && action.authentication_id !== null && action.authentication_id !== "" && app.authentication.required === true) {
|
||||
console.log("FIXME: Should verify authentication ID ", action.authentication_id)
|
||||
}
|
||||
|
||||
newaction.app = app;
|
||||
}
|
||||
|
||||
if (
|
||||
action.errors !== undefined &&
|
||||
action.errors !== null &&
|
||||
action.errors.length > 0
|
||||
) {
|
||||
|
||||
if (newaction.errors !== undefined && newaction.errors !== null && newaction.errors.length > 0) {
|
||||
//console.log("Node has errors!: ", action.errors)
|
||||
}
|
||||
|
||||
//console.log(newaction.app_name,"AUTH: ", newaction.must_authenticate, " ACTIVATE: ", newaction.must_activate)
|
||||
|
||||
if (newaction.must_authenticate) {
|
||||
var authenticationOptions = [];
|
||||
for (let [key,keyval] in Object.entries(appAuthentication)) {
|
||||
@@ -395,29 +416,29 @@ const ConfigureWorkflow = (props) => {
|
||||
setRequiredActions(newactions);
|
||||
}
|
||||
|
||||
if (appAuthentication !== undefined && previousAuth !== undefined && appAuthentication.length !== previousAuth.length) {
|
||||
var newactions = []
|
||||
for (let [actionkey, actionkeyval] in Object.entries(requiredActions)) {
|
||||
var newaction = requiredActions[actionkey];
|
||||
const app = newaction.app;
|
||||
if (appAuthentication !== undefined && previousAuth !== undefined && appAuthentication.length !== previousAuth.length) {
|
||||
var newactions = []
|
||||
for (let [actionkey, actionkeyval] in Object.entries(requiredActions)) {
|
||||
var newaction = requiredActions[actionkey];
|
||||
const app = newaction.app;
|
||||
|
||||
for (let [key,keyval] in Object.entries(appAuthentication)) {
|
||||
const auth = appAuthentication[key];
|
||||
for (let [key,keyval] in Object.entries(appAuthentication)) {
|
||||
const auth = appAuthentication[key];
|
||||
|
||||
// Does this account for all the different ones of the same?
|
||||
if (auth.app.name === app.name && auth.active === true) {
|
||||
newaction.auth_done = true;
|
||||
break;
|
||||
// Does this account for all the different ones of the same?
|
||||
if (auth.app.name === app.name && auth.active === true) {
|
||||
newaction.auth_done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newactions.push(newaction);
|
||||
}
|
||||
|
||||
newactions.push(newaction);
|
||||
}
|
||||
|
||||
setRequiredActions(newactions);
|
||||
setPreviousAuth(appAuthentication);
|
||||
// Set auth done to true
|
||||
//"auth_done": false
|
||||
setRequiredActions(newactions);
|
||||
setPreviousAuth(appAuthentication);
|
||||
// Set auth done to true
|
||||
//"auth_done": false
|
||||
}
|
||||
|
||||
const TriggerSection = (props) => {
|
||||
@@ -610,14 +631,24 @@ const ConfigureWorkflow = (props) => {
|
||||
const [authFields, setAuthFields] = useState([])
|
||||
const [sensitiveFields, setSensitiveFields] = useState([])
|
||||
|
||||
//console.log("ACTION", action)
|
||||
|
||||
useEffect(() => {
|
||||
if (finalized === true) {
|
||||
setOpened(false)
|
||||
setFilled(true)
|
||||
}
|
||||
}, [finalized])
|
||||
|
||||
if (authFields.length === 0 && opened === true) {
|
||||
// Loop through fields of the action
|
||||
|
||||
|
||||
var newfields = []
|
||||
const params = action.action.parameters
|
||||
|
||||
var sensitiveIndexes = []
|
||||
var index = 0
|
||||
var sensitiveIndexes = []
|
||||
const params = action.action.parameters
|
||||
for (let key in params) {
|
||||
const param = params[key]
|
||||
|
||||
@@ -732,9 +763,34 @@ const ConfigureWorkflow = (props) => {
|
||||
<CheckIcon style={{color: theme.palette.green, marginLeft: 10, marginTop: 10, flex: 1, }} />
|
||||
: null}
|
||||
</div>
|
||||
|
||||
{opened ?
|
||||
<div style={{padding: 12, }}>
|
||||
{authFields.map((field, index) => {
|
||||
|
||||
{action.app.authentication.type === "oauth2-app" || action.app.authentication.type === "oauth2" || action.auth_type === "oauth2" ?
|
||||
<div>
|
||||
<AuthenticationOauth2
|
||||
selectedApp={action.app}
|
||||
selectedAction={{
|
||||
"app_name": action.app.name,
|
||||
"app_id": action.app.id,
|
||||
"app_version": action.app.version,
|
||||
"large_image": action.app.large_image,
|
||||
}}
|
||||
authenticationType={action.app.authentication}
|
||||
isCloud={isCloud}
|
||||
authButtonOnly={true}
|
||||
|
||||
isLoggedIn={true}
|
||||
getAppAuthentication={undefined}
|
||||
|
||||
setFinalized={setFinalized}
|
||||
/>
|
||||
</div>
|
||||
:
|
||||
authFields.map((field, index) => {
|
||||
console.log("THESE FIELDS?: ", field)
|
||||
|
||||
var parsedName = field.key
|
||||
// Remove _basic at the end if it exists
|
||||
if (parsedName.toLowerCase().endsWith("_basic")) {
|
||||
@@ -807,25 +863,28 @@ const ConfigureWorkflow = (props) => {
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: 15,
|
||||
width: 150,
|
||||
marginLeft: 135,
|
||||
}}
|
||||
disabled={!filled || submitted}
|
||||
onClick={() => {
|
||||
setSubmitted(true);
|
||||
|
||||
// const submitLocalAuth = (app, fields) => {
|
||||
submitLocalAuth({"id": action.app.id, "name": action.app.name, "version": action.app.version, "large_image": action.large_image, }, authFields);
|
||||
|
||||
}}
|
||||
>
|
||||
{submitted ? <CircularProgress style={{color: theme.palette.primary.main, }} /> : "Submit"}
|
||||
</Button>
|
||||
{action.app.authentication.type !== "oauth2-app" && action.app.authentication.type !== "oauth2" ?
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: 15,
|
||||
width: 150,
|
||||
marginLeft: 135,
|
||||
}}
|
||||
disabled={!filled || submitted}
|
||||
onClick={() => {
|
||||
setSubmitted(true);
|
||||
|
||||
// const submitLocalAuth = (app, fields) => {
|
||||
submitLocalAuth({"id": action.app.id, "name": action.app.name, "version": action.app.version, "large_image": action.large_image, }, authFields);
|
||||
|
||||
}}
|
||||
>
|
||||
{submitted ? <CircularProgress style={{color: theme.palette.primary.main, }} /> : "Submit"}
|
||||
</Button>
|
||||
: null}
|
||||
</div>
|
||||
: null}
|
||||
</div>
|
||||
@@ -1237,19 +1296,22 @@ const ConfigureWorkflow = (props) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{margin: setConfigureWorkflowModalOpen !== undefined ? "0px 50px 0px 50px" : "35px 0px 0px", maxHeight: 475, }}>
|
||||
<div style={{margin: setConfigureWorkflowModalOpen !== undefined ? "0px 50px 0px 50px" : "35px 0px 0px 0px", maxHeight: 475, }}>
|
||||
|
||||
|
||||
{setConfigureWorkflowModalOpen !== undefined ?
|
||||
<Typography variant="h6">{workflow.name}</Typography>
|
||||
<Typography variant="h6">
|
||||
{workflow.name}
|
||||
</Typography>
|
||||
: null
|
||||
}
|
||||
|
||||
<Typography variant="body2" style={{}}>
|
||||
Please configure the following apps for automatic startup of automation:
|
||||
</Typography>
|
||||
{requiredActions.length > 0 ? (
|
||||
<span>
|
||||
<Typography variant="body2" style={{}}>
|
||||
Please configure the following steps to help us complete your workflow. This can also be done later.
|
||||
</Typography>
|
||||
|
||||
{setConfigureWorkflowModalOpen !== undefined ?
|
||||
<Typography variant="body1" style={{ marginTop: 10, }}>
|
||||
Required Actions
|
||||
@@ -1258,6 +1320,11 @@ const ConfigureWorkflow = (props) => {
|
||||
|
||||
<List style={{paddingBottom: window.location.pathname.includes("/workflows/") ? 0 : 250, }}>
|
||||
{requiredActions.map((data, index) => {
|
||||
|
||||
// AppWrapper = Default in a workflow, only shows with steps
|
||||
// AppSection =
|
||||
// AppSectionSelfcontained = default for template generator
|
||||
|
||||
return (
|
||||
<div key={index} style={{marginBottom: 10, }}>
|
||||
{data.steps !== undefined && data.steps !== null && data.show_steps === true && setConfigureWorkflowModalOpen !== undefined ?
|
||||
|
||||
@@ -235,7 +235,7 @@ const Header = (props) => {
|
||||
setLoginHoverColor(hoverOutColor);
|
||||
};
|
||||
|
||||
const notificationWidth = 300
|
||||
const notificationWidth = 335
|
||||
const imagesize = 22;
|
||||
const boxColor = "#86c142";
|
||||
|
||||
@@ -398,7 +398,8 @@ const Header = (props) => {
|
||||
<Button
|
||||
color="primary"
|
||||
variant="contained"
|
||||
style={{ marginLeft: 30 }}
|
||||
disabled={notifications.filter((data) => !data.read).length === 0}
|
||||
style={{ marginLeft: 30, }}
|
||||
onClick={() => {
|
||||
clearNotifications();
|
||||
}}
|
||||
@@ -454,12 +455,9 @@ const Header = (props) => {
|
||||
return response.json();
|
||||
})
|
||||
.then(function (responseJson) {
|
||||
console.log("In here?")
|
||||
if (responseJson.success === true) {
|
||||
if (
|
||||
responseJson.region_url !== undefined &&
|
||||
responseJson.region_url !== null &&
|
||||
responseJson.region_url.length > 0
|
||||
) {
|
||||
if (responseJson.region_url !== undefined && responseJson.region_url !== null && responseJson.region_url.length > 0) {
|
||||
console.log("Region Change: ", responseJson.region_url);
|
||||
localStorage.setItem("globalUrl", responseJson.region_url);
|
||||
//globalUrl = responseJson.region_url
|
||||
@@ -468,9 +466,14 @@ const Header = (props) => {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
|
||||
toast("Successfully changed active organization - refreshing!");
|
||||
} else {
|
||||
toast("Failed changing org: ", responseJson.reason);
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
||||
toast(responseJson.reason);
|
||||
} else {
|
||||
toast("Failed changing org. Try again or contact support@shuffler.io if this persists.");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -613,7 +616,7 @@ const Header = (props) => {
|
||||
<Divider style={{marginBottom: 10, }}/>
|
||||
|
||||
<Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 5, marginBottom: 5,}}>
|
||||
Version: 1.3.1
|
||||
Version: 1.3.3
|
||||
</Typography>
|
||||
</Menu>
|
||||
</span>
|
||||
@@ -627,7 +630,7 @@ const Header = (props) => {
|
||||
};
|
||||
|
||||
// Handle top bar or something
|
||||
const defaultTop = isCloud ? 0 : 7;
|
||||
const defaultTop = -2
|
||||
const loginTextBrowser = !isLoggedIn ? (
|
||||
<div
|
||||
style={{
|
||||
@@ -660,7 +663,7 @@ const Header = (props) => {
|
||||
<img
|
||||
src={"/images/logos/topleft_logo.svg"}
|
||||
alt="shuffle logo"
|
||||
style={{ height: 25, marginTop: 5, }}
|
||||
style={{ height: 25, }}
|
||||
/>
|
||||
</Grid>
|
||||
</Link>
|
||||
|
||||
@@ -97,6 +97,8 @@ const AuthenticationOauth2 = (props) => {
|
||||
autoAuth,
|
||||
authButtonOnly,
|
||||
isLoggedIn,
|
||||
|
||||
setFinalized,
|
||||
} = props;
|
||||
|
||||
let navigate = useNavigate();
|
||||
@@ -489,20 +491,27 @@ const AuthenticationOauth2 = (props) => {
|
||||
var open = true;
|
||||
const timer = setInterval(() => {
|
||||
if (newwin.closed) {
|
||||
console.log("Closing?")
|
||||
|
||||
console.log("Closing?")
|
||||
|
||||
setButtonClicked(false);
|
||||
clearInterval(timer);
|
||||
//alert('"Secure Payment" window closed!');
|
||||
//
|
||||
|
||||
if (getAppAuthentication !== undefined) {
|
||||
getAppAuthentication(true, true, true);
|
||||
}
|
||||
if (getAppAuthentication !== undefined) {
|
||||
getAppAuthentication(true, true, true);
|
||||
}
|
||||
|
||||
// This is more a guess than anything
|
||||
// Should be handled in getAppAuthentication()
|
||||
// in the parent component to make it accurate,
|
||||
// seeing as we don't know what the parent component
|
||||
// wants to happen
|
||||
if (setFinalized !== undefined) {
|
||||
setFinalized(true)
|
||||
}
|
||||
} else {
|
||||
console.log("Not closed")
|
||||
}
|
||||
console.log("Not closed")
|
||||
}
|
||||
}, 1000);
|
||||
//do {
|
||||
// setTimeout(() => {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { NestedMenuItem } from "mui-nested-menu";
|
||||
//import { useAlert
|
||||
|
||||
import {
|
||||
Chip,
|
||||
ButtonGroup,
|
||||
Popper,
|
||||
TextField,
|
||||
@@ -174,8 +175,6 @@ const ParsedAction = (props) => {
|
||||
} = props;
|
||||
|
||||
const classes = useStyles();
|
||||
//const alert = useAlert()
|
||||
|
||||
const [hideBody, setHideBody] = React.useState(true);
|
||||
const [activateHidingBodyButton, setActivateHidingBodyButton] = React.useState(false);
|
||||
|
||||
@@ -184,31 +183,34 @@ const ParsedAction = (props) => {
|
||||
|
||||
const [autoCompleting, setAutocompleting] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (setLastSaved !== undefined) {
|
||||
setLastSaved(false)
|
||||
}
|
||||
}, [expansionModalOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if (setLastSaved !== undefined) {
|
||||
setLastSaved(false)
|
||||
}
|
||||
}, [expansionModalOpen])
|
||||
if (selectedAction.parameters === null || selectedAction.parameters === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAction.parameters !== null && selectedAction.parameters !== undefined) {
|
||||
const paramcheck = selectedAction.parameters.find(param => param.name === "body")
|
||||
//console.log("LOADED! Change hideBody based on input? Action: ", selectedAction, paramcheck)
|
||||
if (paramcheck !== undefined && paramcheck !== null) {
|
||||
if (paramcheck.id === "TOGGLED"){
|
||||
setHideBody(false)
|
||||
setActivateHidingBodyButton(false)
|
||||
} else {
|
||||
setHideBody(true)
|
||||
const paramcheck = selectedAction.parameters.find(param => param.name === "body")
|
||||
if (paramcheck === undefined || paramcheck === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (paramcheck.id === "UNTOGGLED") {
|
||||
setActivateHidingBodyButton(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
// This was just opposite..
|
||||
if (paramcheck.id === "TOGGLED"){
|
||||
setHideBody(true)
|
||||
} else {
|
||||
setHideBody(false)
|
||||
|
||||
if (paramcheck.id === "UNTOGGLED") {
|
||||
setActivateHidingBodyButton(false)
|
||||
}
|
||||
}, [])
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
||||
const keywords = [
|
||||
"len(",
|
||||
@@ -1189,14 +1191,14 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
{...params}
|
||||
label="Find App to Translate"
|
||||
variant="outlined"
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
{...params}
|
||||
label="Find App to Translate"
|
||||
variant="outlined"
|
||||
/>
|
||||
);
|
||||
}}
|
||||
@@ -1359,20 +1361,6 @@ const ParsedAction = (props) => {
|
||||
var disabled = false;
|
||||
var rows = "3";
|
||||
var openApiHelperText = "This is an OpenAPI specific field";
|
||||
/*
|
||||
if (
|
||||
selectedApp.generated &&
|
||||
data.name === "url" &&
|
||||
data.required &&
|
||||
data.configuration
|
||||
) {
|
||||
//&&
|
||||
//hideExtraTypes
|
||||
|
||||
//console.log("GENERATED WITH DATA: ", data);
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
|
||||
if (selectedApp.generated && data.name === "headers") {
|
||||
//console.log("HEADER: ", data)
|
||||
@@ -1385,8 +1373,9 @@ const ParsedAction = (props) => {
|
||||
const hideBodyButtonValue = (
|
||||
<div
|
||||
key={data.name}
|
||||
id="hide_body_button"
|
||||
style={{
|
||||
marginTop: 25,
|
||||
marginTop: 50,
|
||||
border: "1px solid rgba(255,255,255,0.7)",
|
||||
borderTop: "1px solid rgba(255,255,255,0.7)",
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
@@ -1396,7 +1385,7 @@ const ParsedAction = (props) => {
|
||||
>
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
title={"Show all body fields"}
|
||||
title={hideBody ? "Hide all body fields and only show the body itself" : "Show all body fields instead of the body itself"}
|
||||
placement="top"
|
||||
>
|
||||
<FormControlLabel
|
||||
@@ -1408,13 +1397,12 @@ const ParsedAction = (props) => {
|
||||
color: theme.palette.primary.secondary,
|
||||
}}
|
||||
onChange={(event) => {
|
||||
var tag = "TOGGLED"
|
||||
if (hideBody) {
|
||||
tag = "UNTOGGLED"
|
||||
}
|
||||
var tag = "TOGGLED"
|
||||
if (hideBody) {
|
||||
tag = "UNTOGGLED"
|
||||
}
|
||||
|
||||
setHideBody(!hideBody);
|
||||
|
||||
setHideBody(!hideBody)
|
||||
for (let paramkey in Object.entries(selectedActionParameters)) {
|
||||
var currentItem = selectedActionParameters[paramkey];
|
||||
if (currentItem.name === "ssl_verify") {
|
||||
@@ -1422,21 +1410,33 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
|
||||
if (currentItem.name === "body") {
|
||||
// FIXME: Workaround for toggling, as actions don't have IDs.
|
||||
// May screw up something in the future.
|
||||
currentItem.id = tag
|
||||
}
|
||||
|
||||
if (currentItem.description === openApiFieldDesc) {
|
||||
currentItem.field_active = !hideBody;
|
||||
//console.log("Changing", currentItem);
|
||||
currentItem.field_active = !hideBody
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Scroll to hide_body_button
|
||||
setTimeout(() => {
|
||||
var element = document.getElementById("hide_body_button")
|
||||
if (element !== undefined && element !== null) {
|
||||
// Keep the button a little below the top
|
||||
element.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
})
|
||||
}
|
||||
}, 100)
|
||||
|
||||
|
||||
}}
|
||||
name="requires_unique"
|
||||
/>
|
||||
}
|
||||
label={"Automatically fix body"}
|
||||
label={hideBody ? "Show Body" : "Hide Body"}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -1446,6 +1446,8 @@ const ParsedAction = (props) => {
|
||||
const regex = /\${(\w+)}/g;
|
||||
const found = placeholder.match(regex);
|
||||
|
||||
// setActivateHidingBodyButton(false)
|
||||
//
|
||||
hideBodyButton = hideBodyButtonValue;
|
||||
if (found === null || !hideBody) {
|
||||
if (found === null) {
|
||||
@@ -1454,13 +1456,13 @@ const ParsedAction = (props) => {
|
||||
//console.log("In found: ", found, hideBody)
|
||||
}
|
||||
} else {
|
||||
//console.log("SHOW BUTTON");
|
||||
|
||||
rows = "1";
|
||||
disabled = true;
|
||||
openApiHelperText = "OpenAPI spec: fill the following fields.";
|
||||
//console.log("SHOULD ADD TO selectedActionParameters!: ", found, selectedActionParameters)
|
||||
|
||||
var changed = false;
|
||||
var tempArray = []
|
||||
for (let specKey in found) {
|
||||
const tmpitem = found[specKey];
|
||||
var skip = false;
|
||||
@@ -1489,7 +1491,7 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
selectedActionParameters.push({
|
||||
tempArray.push({
|
||||
action_field: "",
|
||||
configuration: false,
|
||||
description: openApiFieldDesc,
|
||||
@@ -1505,11 +1507,39 @@ const ParsedAction = (props) => {
|
||||
value: "",
|
||||
variant: "STATIC_VALUE",
|
||||
field_active: true,
|
||||
|
||||
autocompleted: true,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("TEMP ARRAY: ", tempArray)
|
||||
var required = selectedActionParameters.filter(item => item.required === true)
|
||||
var notRequired = selectedActionParameters.filter(item => item.required === false)
|
||||
|
||||
if (tempArray.length > 0) {
|
||||
// Sort tempArray based on tempArray.required
|
||||
tempArray.sort((a, b) => (a.required < b.required) ? 1 : -1)
|
||||
// Add all items to the selectedActionParameters array
|
||||
for (let innerkey in tempArray) {
|
||||
tempArray[innerkey].id = "ADDED"
|
||||
|
||||
if (tempArray[innerkey].required === true) {
|
||||
required.push(tempArray[innerkey])
|
||||
} else {
|
||||
notRequired.push(tempArray[innerkey])
|
||||
}
|
||||
}
|
||||
}
|
||||
//selectedActionParameters
|
||||
|
||||
if (changed) {
|
||||
setSelectedActionParameters(selectedActionParameters);
|
||||
// Sort selectedActionParameters based on selectedActionParameters.required
|
||||
//selectedActionParameters.sort((a, b) => (a.required < b.required) ? 1 : -1)
|
||||
// Find the "headers" and "queries" field names and put them on the first indexes anyway
|
||||
var newArray = required.concat(notRequired)
|
||||
|
||||
|
||||
setSelectedActionParameters(newArray)
|
||||
}
|
||||
|
||||
return hideBodyButton;
|
||||
@@ -1522,9 +1552,6 @@ const ParsedAction = (props) => {
|
||||
|
||||
const clickedFieldId = "rightside_field_" + count;
|
||||
|
||||
//<TextareaAutosize
|
||||
// <CodeMirror
|
||||
//fullWidth
|
||||
var baseHelperText = ""
|
||||
if (data !== undefined && data !== null && data.value !== undefined && data.value !== null && data.value.length > 0) {
|
||||
baseHelperText = calculateHelpertext(data.value)
|
||||
@@ -1618,33 +1645,15 @@ const ParsedAction = (props) => {
|
||||
helperText={returnHelperText(data.name, data.value)}
|
||||
onClick={() => {
|
||||
console.log("Clicked field: ", clickedFieldId, data.name)
|
||||
/*
|
||||
setExpansionModalOpen(false);
|
||||
*/
|
||||
|
||||
//if (data.name === "file_id") {
|
||||
// console.log("show file video?")
|
||||
// if (setShowVideo !== undefined) {
|
||||
// setShowVideo("https://www.youtube.com/embed/DPYowyTbsSk")
|
||||
// }
|
||||
//}
|
||||
//(data.name.toLowerCase().includes("api") ||
|
||||
/*
|
||||
setExpansionModalOpen(false);
|
||||
if (
|
||||
setScrollConfig !== undefined &&
|
||||
scrollConfig !== null &&
|
||||
scrollConfig !== undefined &&
|
||||
scrollConfig.selected !== clickedFieldId
|
||||
) {
|
||||
scrollConfig.selected = clickedFieldId;
|
||||
setScrollConfig(scrollConfig);
|
||||
//console.log("Change field id!")
|
||||
}
|
||||
*/
|
||||
|
||||
//console.log("Clicked field: ", clickedFieldId)
|
||||
if (setScrollConfig !== undefined && scrollConfig !== null && scrollConfig !== undefined && scrollConfig.selected !== clickedFieldId) {
|
||||
console.log("IN SCROLL CONFIG!")
|
||||
|
||||
scrollConfig.selected = clickedFieldId
|
||||
setScrollConfig(scrollConfig)
|
||||
//console.log("Change field id!")
|
||||
}
|
||||
}}
|
||||
id={clickedFieldId}
|
||||
@@ -2475,19 +2484,19 @@ const ParsedAction = (props) => {
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
{hasAutocomplete === true ?
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Field was autocompleted by Shuffle based on previous actions (same fields or parent nodes)"}
|
||||
placement="top"
|
||||
>
|
||||
<AutoFixHighIcon style={{
|
||||
color: "rgba(255,255,255,0.7)" ,
|
||||
marginRight: 10,
|
||||
}}/>
|
||||
</Tooltip>
|
||||
:
|
||||
null}
|
||||
{hasAutocomplete === true ?
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Field was autocompleted by Shuffle based on previous actions (same fields or parent nodes)"}
|
||||
placement="top"
|
||||
>
|
||||
<AutoFixHighIcon style={{
|
||||
color: "rgba(255,255,255,0.7)" ,
|
||||
marginRight: 10,
|
||||
}}/>
|
||||
</Tooltip>
|
||||
:
|
||||
null}
|
||||
|
||||
<div
|
||||
style={{
|
||||
@@ -3028,8 +3037,6 @@ const ParsedAction = (props) => {
|
||||
const parsedBaseLabel = "$"+baselabel.toLowerCase().replaceAll(" ", "_")
|
||||
const newname = "$"+name.toLowerCase().replaceAll(" ", "_")
|
||||
|
||||
console.log("NAME: ", name)
|
||||
|
||||
// Check if it's the same as the current name in use
|
||||
//if (name === selectedAction.label) {
|
||||
// console.log("Returning from name thing")
|
||||
@@ -3298,14 +3305,12 @@ const ParsedAction = (props) => {
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Authentication</Typography>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Select
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
labelId="select-app-auth"
|
||||
value={
|
||||
Object.getOwnPropertyNames(
|
||||
selectedAction.selectedAuthentication
|
||||
).length === 0
|
||||
Object.getOwnPropertyNames(selectedAction.selectedAuthentication).length === 0
|
||||
? "No selection"
|
||||
: selectedAction.selectedAuthentication
|
||||
}
|
||||
@@ -3353,7 +3358,10 @@ const ParsedAction = (props) => {
|
||||
<em>No selection</em>
|
||||
</MenuItem>
|
||||
{selectedAction.authentication.map((data) => {
|
||||
//console.log("AUTH DATA: ", data)
|
||||
if (data.last_modified === true) {
|
||||
//console.log("LAST MODIFIED: ", data.label)
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={data.id}
|
||||
@@ -3363,7 +3371,23 @@ const ParsedAction = (props) => {
|
||||
}}
|
||||
value={data}
|
||||
>
|
||||
{data.label} - ({data.app.app_version})
|
||||
{data.last_modified === true ?
|
||||
<Chip
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
||||
label={"Latest"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/>
|
||||
: null}
|
||||
{data.app.app_version !== undefined && data.app.app_version !== null && data.app.app_version !== "" && data.app.app_version !== "undefined" ?
|
||||
<Chip
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
||||
label={data.app.app_version}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/>
|
||||
: null}
|
||||
{data.label}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
@@ -3449,6 +3473,14 @@ const ParsedAction = (props) => {
|
||||
}}
|
||||
value={data.Name}
|
||||
>
|
||||
{data.default === true ?
|
||||
<Chip
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
||||
label={"Default"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/>
|
||||
: null}
|
||||
{data.Name}
|
||||
</MenuItem>
|
||||
);
|
||||
@@ -3562,7 +3594,7 @@ const ParsedAction = (props) => {
|
||||
options={selectedApp.actions === undefined || selectedApp.actions === null ? [] : selectedApp.actions.filter((a) => a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label"))}
|
||||
ListboxProps={{
|
||||
style: {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
@@ -3709,9 +3741,12 @@ const ParsedAction = (props) => {
|
||||
|
||||
return (
|
||||
<TextField
|
||||
{...params}
|
||||
|
||||
data-lpignore="true"
|
||||
autocomplete="off"
|
||||
dataLPIgnore="true"
|
||||
autoComplete="off"
|
||||
|
||||
color="primary"
|
||||
id="checkbox-search"
|
||||
@@ -3720,9 +3755,10 @@ const ParsedAction = (props) => {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
{...params}
|
||||
label="Find Actions"
|
||||
variant="outlined"
|
||||
name={`disable_autocomplete_${Math.random()}`}
|
||||
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -54,6 +54,7 @@ const RuntimeDebugger = (props) => {
|
||||
const [status, setStatus] = useState("")
|
||||
const [endTime, setEndTime] = useState("")
|
||||
const [startTime, setStartTime] = useState("")
|
||||
const [totalCount, setTotalCount] = useState(0)
|
||||
|
||||
const [workflow, setWorkflow] = useState({})
|
||||
const [ignoreOrg, setIgnoreOrg] = useState(false)
|
||||
@@ -65,16 +66,80 @@ const RuntimeDebugger = (props) => {
|
||||
const [workflows, setWorkflows] = useState([
|
||||
{"id": "", "name": "All Workflows",}
|
||||
])
|
||||
/*
|
||||
[
|
||||
{id: "1", execution_id: "1", status: "FINISHED", startTimestamp: "2021-10-01 12:00:00", endTimestamp: "2021-10-01 12:00:00", workflow: {"id": "1234", "name": "what",}},
|
||||
{id: "2", execution_id: "2", status: "WAITING", startTimestamp: "2021-10-01 12:00:00", endTimestamp: "2021-10-01 12:00:00", workflow: {"id": "1234", "name": "what",}},
|
||||
{id: "3", execution_id: "3", status: "EXECUTING",startTimestamp: "2021-10-01 12:00:00", endTimestamp: "2021-10-01 12:00:00", workflow: {"id": "1234", "name": "what",}},
|
||||
{id: "4", execution_id: "4", status: "ABORTED", startTimestamp: "2021-10-01 12:00:00", endTimestamp: "2021-10-01 12:00:00", workflow: {"id": "1234", "name": "what",}},
|
||||
]);
|
||||
*/
|
||||
|
||||
// Shitty workflow search on purpose :)
|
||||
const handleWorkflowUsageCount = (workflows) => {
|
||||
if (workflows === undefined || workflows === null || workflows.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
setTotalCount(0)
|
||||
|
||||
var count = 0
|
||||
var starttime = startTime === undefined || startTime === null || startTime === "" ? "" : new Date(startTime).toISOString()
|
||||
var endtime = endTime === undefined || endTime === null || endTime == "" ? "" : new Date(endTime).toISOString()
|
||||
|
||||
var maxworkflows = 5
|
||||
|
||||
console.log("Looking for MAX this amount of workflows: ", maxworkflows)
|
||||
for (let key in workflows) {
|
||||
if (key > maxworkflows) {
|
||||
break
|
||||
}
|
||||
|
||||
const workflowId = workflows[key].id
|
||||
// Fetch the data for the workflow
|
||||
var url = `${globalUrl}/api/v1/workflows/${workflowId}/executions/count`
|
||||
if (starttime !== "") {
|
||||
url += `?start_time=${starttime}`
|
||||
}
|
||||
|
||||
if (endtime !== "") {
|
||||
if (starttime !== "") {
|
||||
url += `&end_time=${endtime}`
|
||||
} else {
|
||||
url += `?end_time=${endtime}`
|
||||
}
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for workflows :O!");
|
||||
return;
|
||||
}
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
if (data.count !== undefined && data.count !== null) {
|
||||
count += data.count
|
||||
}
|
||||
} else {
|
||||
console.log("Failed to get workflow usage count: ", data)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error);
|
||||
})
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("Setting total count: ", count)
|
||||
setTotalCount(count)
|
||||
}, maxworkflows*300)
|
||||
}
|
||||
|
||||
const submitSearch = (workflowId, status, startTime, endTime, cursor, limit) => {
|
||||
handleWorkflowUsageCount(workflows)
|
||||
|
||||
//setResultRows([])
|
||||
setSearchLoading(true)
|
||||
@@ -135,6 +200,7 @@ const RuntimeDebugger = (props) => {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const getAvailableWorkflows = () => {
|
||||
fetch(globalUrl + "/api/v1/workflows", {
|
||||
method: "GET",
|
||||
@@ -624,7 +690,7 @@ const RuntimeDebugger = (props) => {
|
||||
<div style={{minWidth: 1150, maxWidth: 1150, margin: "auto", }}>
|
||||
|
||||
<div style={{display: "flex", }}>
|
||||
<h1 style={{flex: 3, }}>Workflow Run Debugger</h1>
|
||||
<h1 style={{flex: 3, }}>Workflow Run Debugger {totalCount !== 0 ? ` (~${totalCount})` : ""}</h1>
|
||||
{selectedWorkflowExecutions.length > 0 ?
|
||||
<ButtonGroup>
|
||||
<Tooltip title="Reruns ALL selected workflows. This will make a new execution for them, and not continue the existing.">
|
||||
@@ -830,6 +896,7 @@ const RuntimeDebugger = (props) => {
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DateTimePicker
|
||||
sx={{
|
||||
@@ -859,8 +926,8 @@ const RuntimeDebugger = (props) => {
|
||||
onChange={handleEndTimeChange}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
|
||||
</LocalizationProvider>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
|
||||
@@ -42,14 +42,20 @@ const chipStyle = {
|
||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||
const SearchData = props => {
|
||||
const { serverside, userdata, setModalOpen, modalOpen } = props
|
||||
|
||||
let navigate = useNavigate();
|
||||
const borderRadius = 3
|
||||
const node = useRef()
|
||||
const [searchOpen, setSearchOpen] = useState(true)
|
||||
const [searchOpen, setSearchOpen] = useState(false)
|
||||
const [oldPath, setOldPath] = useState("")
|
||||
const [value, setValue] = useState("");
|
||||
const [userTyped, setUserTyped] = useState(false)
|
||||
|
||||
const handleLinkClick = () => {
|
||||
if (modalOpen) {
|
||||
setModalOpen(false); // Assuming setModalOpen is defined correctly
|
||||
} else {
|
||||
console.log("Condition not met, staying on the same page");
|
||||
}
|
||||
};
|
||||
|
||||
if (serverside === true) {
|
||||
return null
|
||||
@@ -72,37 +78,36 @@ const SearchData = props => {
|
||||
// }, searchOpen)
|
||||
|
||||
const SearchBox = ({ currentRefinement, refine, isSearchStalled, }) => {
|
||||
const [inputValue, setInputValue] = useState(currentRefinement);
|
||||
|
||||
const textFieldRef = useRef(null);
|
||||
const keyPressHandler = (e) => {
|
||||
// e.preventDefault();
|
||||
if (e.which === 13) {
|
||||
// alert("You pressed enter!");
|
||||
navigate("/search?q=" + currentRefinement, { state: value, replace: true });
|
||||
|
||||
setSearchOpen(false)
|
||||
setModalOpen(false)
|
||||
return
|
||||
|
||||
// navigate(`/search?q=${currentRefinement}`, { state: value, replace: true });
|
||||
// setModalOpen(false);
|
||||
const trimmedValue = inputValue.trim();
|
||||
if (trimmedValue !== '') {
|
||||
e.preventDefault();
|
||||
navigate(`/search?q=${trimmedValue}`, { state: trimmedValue, replace: true });
|
||||
setModalOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
/*
|
||||
endAdornment: (
|
||||
<InputAdornment position="end" style={{textAlign: "right", zIndex: 5001, cursor: "pointer", width: 100, }} onMouseOver={(event) => {
|
||||
event.preventDefault()
|
||||
}}>
|
||||
<CloseIcon style={{marginRight: 5,}} onClick={() => {
|
||||
setSearchOpen(false)
|
||||
}} />
|
||||
</InputAdornment>
|
||||
),
|
||||
*/
|
||||
|
||||
useEffect(() => {
|
||||
if (searchOpen && textFieldRef.current) {
|
||||
textFieldRef.current.focus();
|
||||
}
|
||||
}, [searchOpen]);
|
||||
|
||||
return (
|
||||
|
||||
<form id="search_form" noValidate type="searchbox" action="" role="search" onClick={() => {
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
fullWidth
|
||||
style={{ zIndex: 1100, marginTop:-20,marginBottom: 200, position:"fixed", backgroundColor: theme.palette.inputColor, borderRadius: borderRadius, width: 685, }}
|
||||
style={{ zIndex: 1100, marginTop: -20, marginBottom: 200, position: "fixed", backgroundColor: theme.palette.inputColor, borderRadius: borderRadius, width: 685, }}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
@@ -130,28 +135,30 @@ const SearchData = props => {
|
||||
type="search"
|
||||
color="primary"
|
||||
placeholder="Find Public Apps, Workflows, Documentation..."
|
||||
value={currentRefinement}
|
||||
onKeyDown={keyPressHandler}
|
||||
value={inputValue}
|
||||
id="shuffle_search_field"
|
||||
onClick={(event) => {
|
||||
if (!searchOpen) {
|
||||
setSearchOpen(true)
|
||||
setTimeout(() => {
|
||||
var tarfield = document.getElementById("shuffle_search_field")
|
||||
//console.log("TARFIELD: ", tarfield)
|
||||
tarfield.focus()
|
||||
}, 250)
|
||||
if (inputValue.trim() !== '') {
|
||||
setSearchOpen(true);
|
||||
}
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
//setTimeout(() => {
|
||||
// setSearchOpen(false)
|
||||
//}, 500)
|
||||
setSearchOpen(inputValue.trim() !== '')
|
||||
}}
|
||||
onChange={(event) => {
|
||||
refine(event.currentTarget.value)
|
||||
const newValue = event.target.value;
|
||||
setInputValue(newValue);
|
||||
refine(newValue);
|
||||
if (newValue.trim() !== '') {
|
||||
setSearchOpen(true);
|
||||
} else {
|
||||
setSearchOpen(false);
|
||||
}
|
||||
}}
|
||||
onKeyDown={keyPressHandler}
|
||||
inputRef={textFieldRef}
|
||||
limit={5}
|
||||
autoFocus
|
||||
/>
|
||||
{/*isSearchStalled ? 'My search is stalled' : ''*/}
|
||||
</form>
|
||||
@@ -183,8 +190,8 @@ const SearchData = props => {
|
||||
const baseImage = <CodeIcon />
|
||||
|
||||
return (
|
||||
<Card elevation={0} style={{ marginRight: 10,marginTop:50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 75, boxShadows: "none", }}>
|
||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color:"#FF8444", borderBottom: "1px solid", width: 105 }}>
|
||||
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 75, boxShadows: "none", }}>
|
||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 105 }}>
|
||||
Workflows
|
||||
</Typography>
|
||||
|
||||
@@ -234,7 +241,7 @@ const SearchData = props => {
|
||||
<Link key={hit.objectID} to={parsedUrl} rel="noopener noreferrer" style={{ textDecoration: "none", color: "white", }} onClick={(event) => {
|
||||
//console.log("CLICK")
|
||||
setSearchOpen(true)
|
||||
|
||||
setModalOpen(false)
|
||||
aa('init', {
|
||||
appId: searchClient.appId,
|
||||
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
||||
@@ -258,7 +265,6 @@ const SearchData = props => {
|
||||
event.preventDefault()
|
||||
window.open(parsedUrl, '_blank');
|
||||
}
|
||||
setModalOpen(false)
|
||||
}}>
|
||||
<ListItem key={hit.objectID} style={innerlistitemStyle} onMouseOver={() => {
|
||||
setMouseHoverIndex(index)
|
||||
@@ -350,7 +356,7 @@ const SearchData = props => {
|
||||
}}>
|
||||
<CloseIcon />
|
||||
</IconButton> */}
|
||||
<Typography variant="h6" style={{ margin: "40px 10px 0px 20px", color:"#FF8444", borderBottom: "1px solid", width: 50 }}>
|
||||
<Typography variant="h6" style={{ margin: "40px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 50 }}>
|
||||
Apps
|
||||
</Typography>
|
||||
|
||||
@@ -424,10 +430,9 @@ const SearchData = props => {
|
||||
|
||||
return (
|
||||
<Link key={hit.objectID} to={parsedUrl} style={{ textDecoration: "none", color: "white", }} onClick={(event) => {
|
||||
console.log("CLICK")
|
||||
setSearchOpen(true)
|
||||
setModalOpen(false)
|
||||
|
||||
setModalOpen(false)
|
||||
aa('init', {
|
||||
appId: searchClient.appId,
|
||||
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
||||
@@ -513,13 +518,13 @@ const SearchData = props => {
|
||||
//console.log(type, hits.length, hits)
|
||||
|
||||
return (
|
||||
<Card elevation={0} style={{ marginRight: 10,marginTop:50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 470, boxShadows: "none", }}>
|
||||
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 470, boxShadows: "none", }}>
|
||||
{/* <IconButton style={{ zIndex: 5000, position: "absolute", right: 14, color: "grey" }} onClick={() => {
|
||||
setSearchOpen(false)
|
||||
}}>
|
||||
<CloseIcon />
|
||||
</IconButton> */}
|
||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color:"#FF8444", borderBottom: "1px solid", width: 152}}>
|
||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 152 }}>
|
||||
Documentation
|
||||
</Typography>
|
||||
{/*
|
||||
@@ -608,7 +613,7 @@ const SearchData = props => {
|
||||
|
||||
console.log("CLICK")
|
||||
setSearchOpen(true)
|
||||
setModalOpen(false)
|
||||
setModalOpen(false)
|
||||
}}>
|
||||
<ListItem key={hit.objectID} style={innerlistitemStyle} onMouseOver={() => {
|
||||
setMouseHoverIndex(index)
|
||||
@@ -636,14 +641,14 @@ const SearchData = props => {
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
const gettingStartData = !searchOpen ? (
|
||||
const gettingStartData = !searchOpen ? (
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
// justify="space-evenly"
|
||||
>
|
||||
<Grid item xs={6} style={{ alignItems: "center", flexDirection: "row", marginTop: 70, }}>
|
||||
<Grid item xs={6} style={{ alignItems: "center", flexDirection: "row", marginTop: 70, }}>
|
||||
<List style={{ width: "100%", marginLeft: 10, color: "var(--Paragraph-text, #C8C8C8)" }}>
|
||||
<ListItem>
|
||||
<ArticleIcon style={{ marginRight: 10, display: "flex", width: 22 }} />
|
||||
@@ -651,28 +656,34 @@ const SearchData = props => {
|
||||
</ListItem>
|
||||
<div style={{ marginLeft: 25, }}>
|
||||
<ListItem>
|
||||
<Link onClick={() => { window.location = "/docs"; }} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/docs" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Documentation</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<Link to="https://github.com/Shuffle/Shuffle/blob/main/.github/install-guide.md" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Onprem Installation</Typography>
|
||||
<a
|
||||
href="https://github.com/Shuffle/Shuffle/blob/main/.github/install-guide.md"
|
||||
style={{
|
||||
textDecoration: "none",
|
||||
color: "var(--Paragraph-text, #C8C8C8)",
|
||||
display: "flex"
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" style={{ fontSize: 16 }}>
|
||||
Onprem Installation
|
||||
</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
</a>
|
||||
</ListItem>
|
||||
|
||||
|
||||
<ListItem>
|
||||
<Link to="/usecases" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/usecases" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Explore Usecases</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Link to="/search?tab=workflows" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/search?tab=workflows" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Find public workflows</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
@@ -688,25 +699,25 @@ const SearchData = props => {
|
||||
</ListItem>
|
||||
<div style={{ marginLeft: 35 }}>
|
||||
<ListItem>
|
||||
<Link to="/docs/app_creation" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/docs/app_creation" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Create Apps</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Link to="/apps" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/apps" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Find Apps</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Link to="/workflows" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/workflows" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Workflows</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Link to="/creators" style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Link to="/creators" onClick={handleLinkClick} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
|
||||
<Typography variant="body1" style={{ fontSize: 16, }}>Creator</Typography>
|
||||
<KeyboardArrowRightIcon />
|
||||
</Link>
|
||||
@@ -721,7 +732,7 @@ const SearchData = props => {
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
): null
|
||||
) : null
|
||||
|
||||
const CustomSearchBox = connectSearchBox(SearchBox)
|
||||
const CustomAppHits = connectHits(AppHits)
|
||||
@@ -731,17 +742,17 @@ const SearchData = props => {
|
||||
const modalView = (
|
||||
<div>
|
||||
<Grid container style={{ display: "contents", }}>
|
||||
<Grid item xs="auto" style={{ }}>
|
||||
<Grid item xs="auto" style={{}}>
|
||||
<Index indexName="appsearch">
|
||||
<CustomAppHits />
|
||||
</Index>
|
||||
</Grid>
|
||||
<Grid item xs="auto" style={{ }}>
|
||||
<Grid item xs="auto" style={{}}>
|
||||
<Index indexName="workflows">
|
||||
<CustomWorkflowHits />
|
||||
</Index>
|
||||
</Grid>
|
||||
<Grid item xs="auto" style={{ }}>
|
||||
<Grid item xs="auto" style={{}}>
|
||||
<Index indexName="documentation">
|
||||
<CustomDocHits />
|
||||
</Index>
|
||||
@@ -753,14 +764,14 @@ const SearchData = props => {
|
||||
return (
|
||||
<div ref={node} style={{ width: "100%", maxWidth: "100%", margin: "auto", }}>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||
|
||||
console.log("CLICKED")
|
||||
}}>
|
||||
<Configure clickAnalytics />
|
||||
<CustomSearchBox onClick={() => {
|
||||
console.log("Click 2")
|
||||
}}/>
|
||||
{modalView}
|
||||
<CustomSearchBox />
|
||||
{modalView}
|
||||
</InstantSearch>
|
||||
{gettingStartData}
|
||||
{gettingStartData}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
import theme from '../theme.jsx';
|
||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||
import SearchBox from "./SearchData.jsx";
|
||||
import SearchBox from "../components/SearchData.jsx";
|
||||
|
||||
import {
|
||||
Chip,
|
||||
@@ -91,8 +91,8 @@ const SearchField = props => {
|
||||
}}
|
||||
>
|
||||
{isHeader ? <div style={{ display: "flex"}}>
|
||||
<DialogTitle style={{ marginTop: 15, marginLeft: 5, color: "var(--Paragraph-text, #C8C8C8)" }} >Search for docs, apps, workflows and more</DialogTitle>
|
||||
<Button fullWidth style={{ marginLeft: 470 }} onClick={() => {
|
||||
<DialogTitle style={{ marginTop: 15, marginLeft: 5, color: "var(--Paragraph-text, #C8C8C8)" }} >Search for Docs, Apps, Workflows and more</DialogTitle>
|
||||
<Button fullWidth style={{ marginLeft:180, }} onClick={() => {
|
||||
setModalOpen(false);
|
||||
}}><CloseIcon /></Button>
|
||||
</div>
|
||||
|
||||
@@ -47,6 +47,7 @@ import ReactJson from "react-json-view";
|
||||
import PaperComponent from "../components/PaperComponent.jsx";
|
||||
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import { python } from '@codemirror/lang-python';
|
||||
//import 'codemirror/keymap/sublime';
|
||||
//import 'codemirror/addon/selection/mark-selection.js'
|
||||
//import 'codemirror/theme/gruvbox-dark.css';
|
||||
@@ -212,6 +213,80 @@ const CodeEditor = (props) => {
|
||||
expectedOutput(localcodedata)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
expectedOutput(localcodedata)
|
||||
}, [availableVariables])
|
||||
|
||||
var to_be_copied = "";
|
||||
const HandleJsonCopy = (base, copy, base_node_name) => {
|
||||
if (typeof copy.name === "string") {
|
||||
copy.name = copy.name.replaceAll(" ", "_");
|
||||
}
|
||||
|
||||
//lol
|
||||
if (typeof base === 'object' || typeof base === 'dict') {
|
||||
base = JSON.stringify(base)
|
||||
}
|
||||
|
||||
if (base_node_name === "execution_argument" || base_node_name === "Execution Argument") {
|
||||
base_node_name = "exec"
|
||||
}
|
||||
|
||||
console.log("COPY: ", base_node_name, copy);
|
||||
|
||||
//var newitem = JSON.parse(base);
|
||||
var newitem = validateJson(base).result
|
||||
|
||||
|
||||
to_be_copied = "$" + base_node_name.toLowerCase().replaceAll(" ", "_");
|
||||
for (let copykey in copy.namespace) {
|
||||
if (copy.namespace[copykey].includes("Results for")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newitem !== undefined && newitem !== null) {
|
||||
newitem = newitem[copy.namespace[copykey]];
|
||||
if (!isNaN(copy.namespace[copykey])) {
|
||||
to_be_copied += ".#";
|
||||
} else {
|
||||
to_be_copied += "." + copy.namespace[copykey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newitem !== undefined && newitem !== null) {
|
||||
newitem = newitem[copy.name];
|
||||
if (!isNaN(copy.name)) {
|
||||
to_be_copied += ".#";
|
||||
} else {
|
||||
to_be_copied += "." + copy.name;
|
||||
}
|
||||
}
|
||||
|
||||
to_be_copied.replaceAll(" ", "_");
|
||||
const elementName = "copy_element_shuffle";
|
||||
var copyText = document.getElementById(elementName);
|
||||
if (copyText !== null && copyText !== undefined) {
|
||||
console.log("NAVIGATOR: ", navigator);
|
||||
const clipboard = navigator.clipboard;
|
||||
if (clipboard === undefined) {
|
||||
toast("Can only copy over HTTPS (port 3443)");
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(to_be_copied);
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||
|
||||
/* Copy the text inside the text field */
|
||||
document.execCommand("copy");
|
||||
console.log("COPYING!");
|
||||
toast("Copied JSON path to clipboard.")
|
||||
} else {
|
||||
console.log("Couldn't find element ", elementName);
|
||||
}
|
||||
}
|
||||
|
||||
const aiSubmit = (value, inputAction) => {
|
||||
if (value === undefined || value === "") {
|
||||
console.log("No value input!")
|
||||
@@ -938,10 +1013,10 @@ const CodeEditor = (props) => {
|
||||
style: {
|
||||
zIndex: 12501,
|
||||
color: "white",
|
||||
minWidth: isMobile ? "100%" : isFileEditor ? 650 : 1200,
|
||||
maxWidth: isMobile ? "100%" : isFileEditor ? 650 : 1200,
|
||||
minHeight: isMobile ? "100%" : 720,
|
||||
maxHeight: isMobile ? "100%" : 720,
|
||||
minWidth: isMobile ? "100%" : isFileEditor ? 650 : 1165,
|
||||
maxWidth: isMobile ? "100%" : isFileEditor ? 650 : 1100,
|
||||
minHeight: isMobile ? "100%" : 700,
|
||||
maxHeight: isMobile ? "100%" : 700,
|
||||
border: theme.palette.defaultBorder,
|
||||
padding: isMobile ? "25px 10px 25px 10px" : 25,
|
||||
},
|
||||
@@ -951,8 +1026,8 @@ const CodeEditor = (props) => {
|
||||
style={{
|
||||
zIndex: 5000,
|
||||
position: "absolute",
|
||||
top: 14,
|
||||
right: 18,
|
||||
top: 6,
|
||||
right: 6,
|
||||
color: "grey",
|
||||
}}
|
||||
onClick={() => {
|
||||
@@ -1233,7 +1308,7 @@ const CodeEditor = (props) => {
|
||||
handleItemClick([innerdata]);
|
||||
}}
|
||||
>
|
||||
<Paper style={{minHeight: 500, maxHeight: 500, minWidth: 275, maxWidth: 275, position: "fixed", top: menuPosition1.top-200, left: menuPosition1.left-270, padding: "10px 0px 10px 10px", backgroundColor: theme.palette.inputColor, overflow: "hidden", overflowY: "auto", border: "1px solid rgba(255,255,255,0.3)",}}>
|
||||
<Paper style={{minHeight: 550, maxHeight: 550, minWidth: 275, maxWidth: 275, position: "fixed", top: menuPosition1.top-200, left: menuPosition1.left-270, padding: "10px 0px 10px 10px", backgroundColor: theme.palette.inputColor, overflow: "hidden", overflowY: "auto", border: "1px solid rgba(255,255,255,0.3)",}}>
|
||||
<MenuItem
|
||||
key={innerdata.name}
|
||||
style={{
|
||||
@@ -1425,22 +1500,26 @@ const CodeEditor = (props) => {
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
position: "relative",
|
||||
paddingTop: 0,
|
||||
minHeight: 548,
|
||||
overflow: "hidden",
|
||||
// minHeight: 548,
|
||||
// overflow: "hidden",
|
||||
}}>
|
||||
<CodeMirror
|
||||
theme={vscodeDark}
|
||||
value={localcodedata}
|
||||
height={isFileEditor ? 450 : 500}
|
||||
width={isFileEditor ? 650 : 600}
|
||||
extensions={[python({ py: true })]}
|
||||
height={isFileEditor ? 450 : 450}
|
||||
width={isFileEditor ? 650 : 550}
|
||||
style={{
|
||||
maxWidth: isFileEditor ? 450 : 600,
|
||||
maxHeight: 548,
|
||||
minHeight: 548,
|
||||
maxHeight: 450,
|
||||
minHeight: 450,
|
||||
wordBreak: "break-word",
|
||||
marginTop: 0,
|
||||
paddingBottom: 10,
|
||||
overflow: "hidden",
|
||||
// overflow: "hidden",
|
||||
overflowY: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
onCursorActivity = {(value) => {
|
||||
console.log("CURSOR: ", value.getCursor())
|
||||
@@ -1463,122 +1542,17 @@ const CodeEditor = (props) => {
|
||||
}}
|
||||
options={{
|
||||
mode: validation === true ? "json" : "python",
|
||||
lineWrapping: linewrap,
|
||||
lineWrapping: true,
|
||||
theme: vscodeDark,
|
||||
lineNumbers: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/*editorPopupOpen ?
|
||||
<Paper
|
||||
style={{
|
||||
margin: 10,
|
||||
padding: 10,
|
||||
width: isMobile ? "100%" : 250,
|
||||
height: 95,
|
||||
overflowY: 'auto',
|
||||
// textOverflow: 'ellipsis'
|
||||
}}
|
||||
>
|
||||
{mainVariables.map((data, index) => {
|
||||
// console.log(data)
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
// textOverflow: 'ellipsis'
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
replaceVariables(data.substring(1,))
|
||||
// console.log(currentCharacter, currentLine)
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: 7.5,
|
||||
cursor: 'pointer',
|
||||
width: '100%',
|
||||
textAlign: 'left'
|
||||
}}
|
||||
>
|
||||
{data.substring(0, 25)}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
: null*/}
|
||||
|
||||
<div
|
||||
style={{
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
<Typography
|
||||
variant = 'body2'
|
||||
color = 'textSecondary'
|
||||
style={{
|
||||
color: "white",
|
||||
paddingLeft: 340,
|
||||
width: 50,
|
||||
display: 'inline',
|
||||
}}
|
||||
>
|
||||
Line Wrap
|
||||
<Checkbox
|
||||
onClick={() => {
|
||||
if (linewrap) {
|
||||
setlinewrap(false)
|
||||
}
|
||||
if (!linewrap){
|
||||
setlinewrap(true)
|
||||
}
|
||||
}}
|
||||
defaultChecked
|
||||
size="small"
|
||||
sx={{
|
||||
color: orange[600],
|
||||
'&.Mui-checked': {
|
||||
color: orange[800],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant = 'body2'
|
||||
color = 'textSecondary'
|
||||
style={{
|
||||
color: "white",
|
||||
paddingLeft: 10,
|
||||
width: 100,
|
||||
display: 'inline',
|
||||
}}
|
||||
>
|
||||
Dark Theme
|
||||
<Checkbox
|
||||
onClick={() => {
|
||||
if (codeTheme === "gruvbox-dark") {
|
||||
setcodeTheme("duotone-light")
|
||||
}
|
||||
if (codeTheme === "duotone-light"){
|
||||
setcodeTheme("gruvbox-dark")
|
||||
}
|
||||
}}
|
||||
defaultChecked
|
||||
size="small"
|
||||
sx={{
|
||||
color: orange[600],
|
||||
'&.Mui-checked': {
|
||||
color: orange[800],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
*/}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1593,83 +1567,93 @@ const CodeEditor = (props) => {
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<span style={{color: "white"}}>
|
||||
Expected Output
|
||||
</span>
|
||||
|
||||
<Tooltip title="Try it! This runs the Shuffle Tools 'repeat back to me' or 'execute python' action with what you see in the expected output window. Commonly used to test your Python scripts or Liquid filters, not requiring the full workflow to run again." placement="top">
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={executing}
|
||||
color="primary"
|
||||
style={{
|
||||
border: `1px solid ${theme.palette.primary.main}`,
|
||||
marginLeft: 200,
|
||||
maxHeight: 35,
|
||||
minWidth: 70,
|
||||
}}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
executeSingleAction(expOutput)
|
||||
}}
|
||||
>
|
||||
{executing ?
|
||||
<CircularProgress style={{height: 18, width: 18, }} />
|
||||
:
|
||||
<span>Try it <PlayArrowIcon style={{height: 18, width: 18, marginBottom: -4, marginLeft: 5, }} /> </span>
|
||||
}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<div>
|
||||
<span style={{color: "white"}}>
|
||||
Expected Output
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</DialogTitle>
|
||||
}
|
||||
|
||||
{isMobile ? null :
|
||||
validation === true ?
|
||||
<ReactJson
|
||||
src={expOutput}
|
||||
theme={theme.palette.jsonTheme}
|
||||
<div style={{position: "relative", }}>
|
||||
<Tooltip title="Try it! This runs the Shuffle Tools 'repeat back to me' or 'execute python' action with what you see in the expected output window. Commonly used to test your Python scripts or Liquid filters, not requiring the full workflow to run again." placement="top">
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={executing}
|
||||
color="primary"
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
border: `2px solid ${theme.palette.inputColor}`,
|
||||
padding: 10,
|
||||
maxHeight: 500,
|
||||
minheight: 500,
|
||||
overflow: "auto",
|
||||
}}
|
||||
collapsed={false}
|
||||
enableClipboard={(copy) => {
|
||||
//handleReactJsonClipboard(copy);
|
||||
}}
|
||||
displayDataTypes={false}
|
||||
onSelect={(select) => {
|
||||
//HandleJsonCopy(validate.result, select, "exec");
|
||||
}}
|
||||
name={"JSON autocompletion"}
|
||||
/>
|
||||
:
|
||||
<p
|
||||
id='expOutput'
|
||||
style={{
|
||||
whiteSpace: "pre-wrap",
|
||||
color: "#ebdbb2",
|
||||
fontFamily: "monospace",
|
||||
backgroundColor: "#282828",
|
||||
padding: 10,
|
||||
marginTop: -2,
|
||||
border: `2px solid ${theme.palette.inputColor}`,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
maxHeight: 500,
|
||||
minHeight: 500,
|
||||
minWidth: 580,
|
||||
maxWidth: 580,
|
||||
overflow: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
border: `1px solid ${theme.palette.primary.main}`,
|
||||
position: "absolute",
|
||||
top: 10,
|
||||
right: 10,
|
||||
maxHeight: 35,
|
||||
minWidth: 70,
|
||||
}}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
executeSingleAction(expOutput)
|
||||
}}
|
||||
>
|
||||
{expOutput}
|
||||
</p>
|
||||
}
|
||||
{executing ?
|
||||
<CircularProgress style={{height: 18, width: 18, }} />
|
||||
:
|
||||
<span>Try it <PlayArrowIcon style={{height: 18, width: 18, marginBottom: -4, marginLeft: 5, }} /> </span>
|
||||
}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
{isMobile ? null :
|
||||
validation === true ?
|
||||
<ReactJson
|
||||
src={expOutput}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
border: `2px solid ${theme.palette.inputColor}`,
|
||||
padding: 10,
|
||||
maxHeight: 450,
|
||||
minheight: 450,
|
||||
overflow: "auto",
|
||||
}}
|
||||
collapsed={false}
|
||||
enableClipboard={(copy) => {
|
||||
//handleReactJsonClipboard(copy);
|
||||
}}
|
||||
displayDataTypes={false}
|
||||
onSelect={(select) => {
|
||||
var basename = "exec"
|
||||
if (selectedAction !== undefined && selectedAction !== null && Object.keys(selectedAction).length !== 0) {
|
||||
basename = selectedAction.label.toLowerCase().replaceAll(" ", "_")
|
||||
}
|
||||
|
||||
HandleJsonCopy(expOutput, select, basename)
|
||||
}}
|
||||
name={"JSON autocompletion"}
|
||||
/>
|
||||
:
|
||||
<p
|
||||
id='expOutput'
|
||||
style={{
|
||||
whiteSpace: "pre-wrap",
|
||||
color: "#ebdbb2",
|
||||
fontFamily: "monospace",
|
||||
backgroundColor: "#282828",
|
||||
padding: 10,
|
||||
marginTop: -2,
|
||||
border: `2px solid ${theme.palette.inputColor}`,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
maxHeight: 450,
|
||||
minHeight: 450,
|
||||
minWidth: 480,
|
||||
maxWidth: "100%",
|
||||
overflow: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
}}
|
||||
>
|
||||
{expOutput}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
{executionResult.valid === true ?
|
||||
<ReactJson
|
||||
@@ -1689,7 +1673,7 @@ const CodeEditor = (props) => {
|
||||
}}
|
||||
displayDataTypes={false}
|
||||
onSelect={(select) => {
|
||||
//HandleJsonCopy(validate.result, select, "exec");
|
||||
//HandleJsonCopy(executionResult.result, select, "exec");
|
||||
}}
|
||||
name={"Test result"}
|
||||
/>
|
||||
@@ -1705,9 +1689,18 @@ const CodeEditor = (props) => {
|
||||
</Typography>
|
||||
</span>
|
||||
:
|
||||
<Typography variant="body2" style={{maxHeight: 150, overflow: "auto", marginTop: 20,}}>
|
||||
No test output yet.
|
||||
</Typography>
|
||||
|
||||
<div>
|
||||
<Typography
|
||||
variant = 'body2'
|
||||
color = 'textSecondary'
|
||||
>
|
||||
Output is based on the last VALID run of the node(s) you are referencing. Only updates when you refresh the Workflow Window.
|
||||
</Typography>
|
||||
<Typography variant="body2" style={{maxHeight: 150, overflow: "auto", marginTop: 20,}}>
|
||||
No test output yet.
|
||||
</Typography>
|
||||
</div>
|
||||
}
|
||||
{executionResult.errors !== undefined && executionResult.errors !== null && executionResult.errors.length > 0 ?
|
||||
<Typography variant="body2" style={{maxHeight: 100, overflow: "auto", color: "#f85a3e",}}>
|
||||
@@ -1725,7 +1718,7 @@ const CodeEditor = (props) => {
|
||||
</div>
|
||||
|
||||
|
||||
<div style={{display: 'flex',}}>
|
||||
<div style={{display: 'flex'}}>
|
||||
<Button
|
||||
style={{
|
||||
height: 35,
|
||||
|
||||
@@ -43,6 +43,8 @@ const WorkflowTemplatePopup = (props) => {
|
||||
const [missingSource, setMissingSource] = React.useState(undefined)
|
||||
const [missingDestination, setMissingDestination] = React.useState(undefined);
|
||||
|
||||
const [configurationFinished, setConfigurationFinished] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
}, [missingSource, missingDestination])
|
||||
|
||||
@@ -175,6 +177,92 @@ const WorkflowTemplatePopup = (props) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Can create and set workflows
|
||||
const reloadWorkflow = (workflow_id) => {
|
||||
|
||||
const new_url = `${globalUrl}/api/v1/workflows/${workflow_id}`
|
||||
return fetch(new_url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for workflows :O!");
|
||||
return;
|
||||
}
|
||||
//setSubmitLoading(false);
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
if (responseJson.reason !== undefined) {
|
||||
toast("Error setting workflow: ", responseJson.reason)
|
||||
} else {
|
||||
toast("Error setting workflow.")
|
||||
}
|
||||
|
||||
return
|
||||
} else if (responseJson.id !== undefined && responseJson.id !== null && responseJson.id !== "") {
|
||||
setWorkflow(responseJson)
|
||||
}
|
||||
|
||||
return responseJson;
|
||||
})
|
||||
.catch((error) => {
|
||||
toast("Failed reloading configured workflow: ", error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
// Can create and set workflows
|
||||
const saveWorkflow = (workflowdata) => {
|
||||
|
||||
const new_url = `${globalUrl}/api/v1/workflows?set_auth=true`
|
||||
return fetch(new_url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(workflowdata),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for workflows :O!");
|
||||
return;
|
||||
}
|
||||
//setSubmitLoading(false);
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
if (responseJson.reason !== undefined) {
|
||||
toast("Error setting workflow: ", responseJson.reason)
|
||||
} else {
|
||||
toast("Error setting workflow.")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// In case it got a new id, this is to make sure it loads with the correct config
|
||||
if (responseJson.id !== undefined && responseJson.id !== null && responseJson.id !== "") {
|
||||
reloadWorkflow(responseJson.id)
|
||||
}
|
||||
|
||||
return responseJson;
|
||||
})
|
||||
.catch((error) => {
|
||||
toast("Failed generating workflow: ", error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const getGeneratedWorkflow = () => {
|
||||
// POST
|
||||
@@ -221,8 +309,10 @@ const WorkflowTemplatePopup = (props) => {
|
||||
},
|
||||
}
|
||||
|
||||
//fetch(globalUrl + "/api/v1/workflows/merge", {
|
||||
fetch("https://shuffler.io/api/v1/workflows/merge", {
|
||||
const url = isCloud ? `${globalUrl}/api/v1/workflows/merge` : `https://shuffler.io/api/v1/workflows/merge`
|
||||
//const url = `https://shuffler.io/api/v1/workflows/merge`
|
||||
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -243,13 +333,21 @@ const WorkflowTemplatePopup = (props) => {
|
||||
if (responseJson.id !== undefined && responseJson.id !== null && responseJson.id !== "" && responseJson.name !== undefined && responseJson.name !== null && responseJson.name !== "") {
|
||||
console.log("Success in workflow template (prebuilt): ", responseJson);
|
||||
setWorkflow(responseJson)
|
||||
|
||||
// Sets it in the database properly
|
||||
saveWorkflow(responseJson)
|
||||
return
|
||||
}
|
||||
|
||||
if (responseJson.success === false) {
|
||||
//console.log("Error in workflow template: ", responseJson.error);
|
||||
|
||||
setErrorMessage("Failed to generate workflow for these tools - the Shuffle team has been notified. Click out of this window to continue. Contact support@shuffler.io for further assistance.")
|
||||
const defaultMessage = "Failed to generate workflow the workflow - the Shuffle team has been notified. Contact support@shuffler.io for further assistance."
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason !== "") {
|
||||
setErrorMessage(defaultMessage + "\n\n" + responseJson.reason)
|
||||
} else {
|
||||
setErrorMessage(defaultMessage)
|
||||
}
|
||||
|
||||
setIsActive(true)
|
||||
//setTimeout(() => {
|
||||
@@ -365,7 +463,6 @@ const WorkflowTemplatePopup = (props) => {
|
||||
fontSize: 18,
|
||||
color: "rgba(255, 132, 68, 1)",
|
||||
marginTop: 32,
|
||||
justifyContent: isMobile ? "center" : null,
|
||||
fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)",
|
||||
fontWeight: 550,
|
||||
}}
|
||||
@@ -420,8 +517,22 @@ const WorkflowTemplatePopup = (props) => {
|
||||
appAuthentication={appAuthentication}
|
||||
setAppAuthentication={setAppAuthentication}
|
||||
apps={apps}
|
||||
|
||||
setConfigurationFinished={setConfigurationFinished}
|
||||
/>
|
||||
{errorMessage === "" ?
|
||||
|
||||
{errorMessage === "" && configurationFinished === true && workflow.id !== undefined && workflowLoading === false ?
|
||||
<Tooltip title="Workflow generated!" placement="top">
|
||||
<span style={{display: "flex", }}>
|
||||
{/*<CheckIcon color="primary" sx={{ borderRadius: 4 }} /> */}
|
||||
<Typography variant="h6" style={{ marginLeft: 20, }}>
|
||||
Workflow generated!
|
||||
</Typography>
|
||||
</span>
|
||||
</Tooltip>
|
||||
: null}
|
||||
|
||||
{/*errorMessage === "" ?
|
||||
<Button
|
||||
style={{marginTop: 50, }}
|
||||
variant={isFinished() ? "contained" : "outlined"}
|
||||
@@ -431,7 +542,7 @@ const WorkflowTemplatePopup = (props) => {
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
: null}
|
||||
: null*/}
|
||||
</DialogContent>
|
||||
</Drawer>
|
||||
)
|
||||
@@ -449,7 +560,7 @@ const WorkflowTemplatePopup = (props) => {
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", maxWidth: isCloud ? 470 : isMobile? null: 450, minWidth: isCloud ? 470 : isMobile? null: 450, height: 78, borderRadius: 8, }}>
|
||||
<div style={{ display: "flex", maxWidth: isCloud ? isMobile ? null : 470 : isMobile? 345: 450, minWidth: isCloud ? isMobile ? null : 470 : isMobile? null: 450, height: 78, borderRadius: 8, justifyContent: isMobile ? null : "center" }}>
|
||||
<ModalView />
|
||||
<div
|
||||
// variant={isActive === 1 ? "contained" : "outlined"}
|
||||
@@ -457,7 +568,7 @@ const WorkflowTemplatePopup = (props) => {
|
||||
disabled={visualOnly === true}
|
||||
style={{
|
||||
margin: isHomePage ? isMobile ? null : 4 : 4 ,
|
||||
width: "100%",
|
||||
width: isHomePage? isMobile ? null : "100%" : "100%",
|
||||
borderRadius: 8,
|
||||
textTransform: "none",
|
||||
backgroundColor: isHomePage ? null : theme.palette.inputColor,
|
||||
@@ -503,31 +614,31 @@ const WorkflowTemplatePopup = (props) => {
|
||||
<div style={{display: "flex", flex: 1, marginTop: 3, }}>
|
||||
{img1 !== undefined && img1 !== "" && srcapp !== undefined && srcapp !== "" ?
|
||||
<Tooltip title={srcapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
|
||||
<span style={srcapp !== undefined && srcapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
||||
<div style={srcapp !== undefined && srcapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
||||
<img src={img1} style={srcapp !== undefined && srcapp.includes(":default") ? imagestyleDefault : imagestyle} />
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
:
|
||||
<span style={{width: 50, }} />
|
||||
<div style={{width: 50, }} />
|
||||
}
|
||||
{img2 !== undefined && img2 !== "" && dstapp !== undefined && dstapp !== "" ?
|
||||
<Tooltip title={dstapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
|
||||
<span style={{display: "flex", }}>
|
||||
<div style={{display: "flex", }}>
|
||||
<TrendingFlatIcon style={{ marginTop: 7, }} />
|
||||
<span style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
||||
<div style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
||||
<img src={img2} style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleDefault : imagestyle} />
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
:
|
||||
<span style={{width: 50, }} />
|
||||
<div style={{width: 50, }} />
|
||||
}
|
||||
</div>
|
||||
<div style={{ flex: 3, marginLeft: 20, }}>
|
||||
<div style={{ flex: 3, marginLeft: 20, maxHeight: 50, overflow: "hidden", }}>
|
||||
<Typography variant="body1" style={{ marginTop: parsedDescription.length === 0 ? 10 : 0, fontSize: isMobile ? 13 : 16,fontWeight: isHomePage? 600 : null,textTransform: 'capitalize', color: isHomePage ? "var(--White-text, #F1F1F1)" :"rgba(241, 241, 241, 1)"}} >
|
||||
{parsedTitle}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary" style={{ fontSize: isMobile ? 10: 16, fontWeight: isHomePage ? 400 : null, textTransform: 'capitalize', marginTop: 0, overflow: "hidden", maxHeight: 21, overflow: "hidden",}} color="rgba(158, 158, 158, 1)">
|
||||
<Typography variant="body2" color="textSecondary" style={{ fontSize: isMobile ? 10: 16, fontWeight: isHomePage ? 400 : null, textTransform: 'capitalize', marginTop: 0, overflow: "hidden", maxHeight: 31,}} color="rgba(158, 158, 158, 1)">
|
||||
{parsedDescription}
|
||||
</Typography>
|
||||
</div>
|
||||
@@ -538,6 +649,8 @@ const WorkflowTemplatePopup = (props) => {
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ const theme = createTheme(adaptV4Theme({
|
||||
borderRadius: 5,
|
||||
border: "1px solid rgba(255,255,255,0.7)",
|
||||
padding: 5,
|
||||
width: "100%",
|
||||
},
|
||||
textFieldStyle: {
|
||||
backgroundColor: "#383B40",
|
||||
|
||||
+354
-99
@@ -73,6 +73,7 @@ import {
|
||||
Visibility as VisibilityIcon,
|
||||
VisibilityOff as VisibilityOffIcon,
|
||||
|
||||
Flag as FlagIcon,
|
||||
FmdGood as FmdGoodIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
@@ -87,7 +88,6 @@ import Priorities from "../components/Priorities.jsx";
|
||||
import Branding from "../components/Branding.jsx";
|
||||
import Files from "../components/Files.jsx";
|
||||
import { display, style } from "@mui/system";
|
||||
//import EnvironmentStats from "../components/EnvironmentStats.jsx";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
notchedOutline: {
|
||||
@@ -180,10 +180,12 @@ const Admin = (props) => {
|
||||
const [secret2FA, setSecret2FA] = React.useState("");
|
||||
const [show2faSetup, setShow2faSetup] = useState(false);
|
||||
|
||||
const [adminTab, setAdminTab] = React.useState(2);
|
||||
const [showApiKey, setShowApiKey] = useState(false);
|
||||
const [adminTab, setAdminTab] = React.useState(3);
|
||||
const [showApiKey, setShowApiKey] = useState(false);
|
||||
const [billingInfo, setBillingInfo] = React.useState({});
|
||||
const [selectedStatus, setSelectedStatus] = React.useState([]);
|
||||
const [selectedStatus, setSelectedStatus] = React.useState([]);
|
||||
|
||||
const [, forceUpdate] = React.useState();
|
||||
|
||||
useEffect(() => {
|
||||
getUsers()
|
||||
@@ -748,11 +750,20 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
toast("Failed changing authentication");
|
||||
// Check if .reason exists
|
||||
if (responseJson.reason !== undefined) {
|
||||
toast("Failed changing authentication: " + responseJson.reason);
|
||||
} else {
|
||||
toast("Failed changing authentication");
|
||||
}
|
||||
} else {
|
||||
//toast("Successfully password!")
|
||||
setSelectedUserModalOpen(false);
|
||||
getAppAuthentication();
|
||||
|
||||
|
||||
setSelectedAuthentication({});
|
||||
setSelectedAuthenticationModalOpen(false);
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -813,7 +824,8 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
const data = {
|
||||
id: id,
|
||||
action: parentAction !== undefined && parentAction !== null ? parentAction : "assign_everywhere",
|
||||
};
|
||||
}
|
||||
|
||||
const url = globalUrl + "/api/v1/apps/authentication/" + id + "/config";
|
||||
|
||||
fetch(url, {
|
||||
@@ -999,62 +1011,62 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
responseJson.sync_features = {};
|
||||
}
|
||||
|
||||
if (responseJson.lead_info !== undefined && responseJson.lead_info !== null) {
|
||||
var leads = []
|
||||
if (responseJson.lead_info.contacted) {
|
||||
leads.push("contacted")
|
||||
}
|
||||
if (responseJson.lead_info !== undefined && responseJson.lead_info !== null) {
|
||||
var leads = []
|
||||
if (responseJson.lead_info.contacted) {
|
||||
leads.push("contacted")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.customer) {
|
||||
leads.push("customer")
|
||||
}
|
||||
if (responseJson.lead_info.customer) {
|
||||
leads.push("customer")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.old_customer) {
|
||||
leads.push("old customer")
|
||||
}
|
||||
if (responseJson.lead_info.old_customer) {
|
||||
leads.push("old customer")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.old_lead) {
|
||||
leads.push("old lead")
|
||||
}
|
||||
if (responseJson.lead_info.old_lead) {
|
||||
leads.push("old lead")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.tech_partner) {
|
||||
leads.push("tech partner")
|
||||
}
|
||||
if (responseJson.lead_info.tech_partner) {
|
||||
leads.push("tech partner")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.creator) {
|
||||
leads.push("creator")
|
||||
}
|
||||
if (responseJson.lead_info.creator) {
|
||||
leads.push("creator")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.opensource) {
|
||||
leads.push("open source")
|
||||
}
|
||||
if (responseJson.lead_info.opensource) {
|
||||
leads.push("open source")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.demo_done) {
|
||||
leads.push("demo done")
|
||||
}
|
||||
if (responseJson.lead_info.demo_done) {
|
||||
leads.push("demo done")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.pov) {
|
||||
leads.push("pov")
|
||||
}
|
||||
if (responseJson.lead_info.pov) {
|
||||
leads.push("pov")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.lead) {
|
||||
leads.push("lead")
|
||||
}
|
||||
if (responseJson.lead_info.lead) {
|
||||
leads.push("lead")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.student) {
|
||||
leads.push("student")
|
||||
}
|
||||
if (responseJson.lead_info.student) {
|
||||
leads.push("student")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.internal) {
|
||||
leads.push("internal")
|
||||
}
|
||||
if (responseJson.lead_info.internal) {
|
||||
leads.push("internal")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.sub_org) {
|
||||
leads.push("sub_org")
|
||||
}
|
||||
if (responseJson.lead_info.sub_org) {
|
||||
leads.push("sub_org")
|
||||
}
|
||||
|
||||
setSelectedStatus(leads)
|
||||
}
|
||||
setSelectedStatus(leads)
|
||||
}
|
||||
|
||||
setSelectedOrganization(responseJson)
|
||||
var lists = {
|
||||
@@ -1491,6 +1503,19 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
})
|
||||
.then((responseJson) => {
|
||||
setEnvironments(responseJson);
|
||||
|
||||
// Helper info for users in case they have a large queue and don't know about queue flushing
|
||||
if (responseJson !== undefined && responseJson !== null && responseJson.length > 0) {
|
||||
for (var i = 0; i < responseJson.length; i++) {
|
||||
const env = responseJson[i];
|
||||
|
||||
// Check if queuesize is too large
|
||||
if (env.queue !== undefined && env.queue !== null && env.queue > 100) {
|
||||
toast("Queue size for " + env.name + " is very large. We recommend you to reduce it by flushing the queue before continuing.");
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
@@ -1798,17 +1823,60 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
>
|
||||
<DialogTitle>
|
||||
<span style={{ color: "white" }}>
|
||||
Edit authentication for {selectedAuthentication.app.name} (
|
||||
Edit authentication for {selectedAuthentication.app.name.replaceAll("_", " ")} (
|
||||
{selectedAuthentication.label})
|
||||
</span>
|
||||
<Typography variant="body1" color="textSecondary" style={{marginTop: 10}}>
|
||||
You can <b>not</b> see the previous values for an authentication while editing. This is to keep your data secure. You can overwrite one- or multiple fields at a time.
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{selectedAuthentication.fields.map((data, index) => {
|
||||
<Typography style={{ marginBottom: 0, marginTop: 10 }}>
|
||||
Authentication Label
|
||||
</Typography>
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginTop: 0,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
height: 50,
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
color="primary"
|
||||
required
|
||||
fullWidth={true}
|
||||
placeholder={selectedAuthentication.label}
|
||||
defaultValue={selectedAuthentication.label}
|
||||
type="text"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
onChange={(e) => {
|
||||
selectedAuthentication.label = e.target.value
|
||||
}}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
{selectedAuthentication.type === "oauth" || selectedAuthentication.type === "oauth2" || selectedAuthentication.type === "oauth2-app" ?
|
||||
<div>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginBottom: 0, marginTop: 10 }}>
|
||||
Only the name of the auth can be modified for Oauth2. Please remake the authentication to change the fields like Client ID, Secret, Scopes etc.
|
||||
</Typography>
|
||||
</div>
|
||||
:
|
||||
selectedAuthentication.fields.map((data, index) => {
|
||||
var fieldname = data.key.replaceAll("_", " ")
|
||||
if (fieldname.endsWith(" basic")) {
|
||||
fieldname = fieldname.substring(0, fieldname.length - 6)
|
||||
}
|
||||
|
||||
//console.log("DATA: ", data, selectedAuthentication)
|
||||
return (
|
||||
<div key={index}>
|
||||
<Typography style={{ marginBottom: 0, marginTop: 10 }}>
|
||||
{data.key}
|
||||
{fieldname}
|
||||
</Typography>
|
||||
<TextField
|
||||
style={{
|
||||
@@ -1824,7 +1892,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
color="primary"
|
||||
required
|
||||
fullWidth={true}
|
||||
placeholder={data.key}
|
||||
placeholder={fieldname}
|
||||
type="text"
|
||||
id={`authentication-${index}`}
|
||||
margin="normal"
|
||||
@@ -1851,9 +1919,11 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
var error = false;
|
||||
var fails = 0
|
||||
for (var key in authenticationFields) {
|
||||
const item = authenticationFields[key];
|
||||
if (item.value.length === 0) {
|
||||
fails += 1
|
||||
console.log("ITEM: ", item);
|
||||
//var currentnode = cy.getElementById(data.id)
|
||||
var textfield = document.getElementById(
|
||||
@@ -1866,14 +1936,17 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast("All fields must have a new value");
|
||||
if (selectedAuthentication.type === "oauth" || selectedAuthentication.type === "oauth2" || selectedAuthentication.type === "oauth2-app") {
|
||||
selectedAuthentication.fields = []
|
||||
}
|
||||
|
||||
if (error && fails === authenticationFields.length) {
|
||||
toast("Updating auth with new name only")
|
||||
saveAuthentication(selectedAuthentication);
|
||||
} else {
|
||||
toast("Saving new version of this authentication");
|
||||
selectedAuthentication.fields = authenticationFields;
|
||||
saveAuthentication(selectedAuthentication);
|
||||
setSelectedAuthentication({});
|
||||
setSelectedAuthenticationModalOpen(false);
|
||||
}
|
||||
}}
|
||||
color="primary"
|
||||
@@ -2195,35 +2268,124 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
|
||||
const GridItem = (props) => {
|
||||
const [expanded, setExpanded] = React.useState(false);
|
||||
const [showEdit, setShowEdit] = React.useState(false);
|
||||
const [newValue, setNewValue] = React.useState(-100);
|
||||
|
||||
const primary = props.data.primary;
|
||||
const secondary = props.data.secondary;
|
||||
const primaryIcon = props.data.icon;
|
||||
const secondaryIcon = props.data.active ? (
|
||||
const secondaryIcon = props.data.active ?
|
||||
<CheckCircleIcon style={{ color: "green" }} />
|
||||
) : (
|
||||
:
|
||||
<CloseIcon style={{ color: "red" }} />
|
||||
)
|
||||
|
||||
const submitFeatureEdit = (sync_features) => {
|
||||
if (!userdata.support) {
|
||||
console.log("User does not have support access and can't edit features");
|
||||
return
|
||||
}
|
||||
|
||||
sync_features.editing = true
|
||||
const data = {
|
||||
org_id: selectedOrganization.id,
|
||||
sync_features: sync_features,
|
||||
};
|
||||
|
||||
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
|
||||
fetch(url, {
|
||||
mode: "cors",
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
credentials: "include",
|
||||
crossDomain: true,
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
})
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
toast("Failed updating org: ", responseJson.reason);
|
||||
} else {
|
||||
toast("Successfully edited org!");
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
toast("Err: " + error.toString());
|
||||
});
|
||||
}
|
||||
|
||||
const enableFeature = () => {
|
||||
console.log("Enabling "+primary)
|
||||
|
||||
console.log(selectedOrganization.sync_features)
|
||||
// Check if primary is in sync_features
|
||||
var tmpprimary = primary.replaceAll(" ", "_")
|
||||
if (!(tmpprimary in selectedOrganization.sync_features)) {
|
||||
console.log("Primary not in sync_features: "+tmpprimary)
|
||||
return
|
||||
}
|
||||
|
||||
if (props.data.active) {
|
||||
selectedOrganization.sync_features[tmpprimary].active = false
|
||||
} else {
|
||||
selectedOrganization.sync_features[tmpprimary].active = true
|
||||
}
|
||||
|
||||
setSelectedOrganization(selectedOrganization)
|
||||
forceUpdate(Math.random())
|
||||
submitFeatureEdit(selectedOrganization.sync_features)
|
||||
}
|
||||
|
||||
const submitEdit = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Check if primary is in sync_features
|
||||
var tmpprimary = primary.replaceAll(" ", "_")
|
||||
if (!(tmpprimary in selectedOrganization.sync_features)) {
|
||||
console.log("Primary not in sync_features: "+tmpprimary)
|
||||
return
|
||||
}
|
||||
|
||||
// Make it into a number
|
||||
var tmp = parseInt(newValue)
|
||||
if (isNaN(tmp)) {
|
||||
console.log("Not a number: "+newValue)
|
||||
return
|
||||
}
|
||||
|
||||
selectedOrganization.sync_features[tmpprimary].limit = tmp
|
||||
|
||||
setSelectedOrganization(selectedOrganization)
|
||||
forceUpdate(Math.random())
|
||||
submitFeatureEdit(selectedOrganization.sync_features)
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid
|
||||
item
|
||||
xs={4}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
setExpanded(!expanded);
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
style={{
|
||||
margin: 4,
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
color: "white",
|
||||
minHeight: expanded ? 250 : "inherit",
|
||||
maxHeight: expanded ? 250 : "inherit",
|
||||
maxHeight: expanded ? 300 : "inherit",
|
||||
}}
|
||||
>
|
||||
<ListItem>
|
||||
<ListItem
|
||||
style={{cursor: "pointer", }}
|
||||
onClick={() => {
|
||||
setExpanded(!expanded);
|
||||
}}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>{primaryIcon}</Avatar>
|
||||
</ListItemAvatar>
|
||||
@@ -2231,9 +2393,46 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
style={{ textTransform: "capitalize" }}
|
||||
primary={primary}
|
||||
/>
|
||||
{secondaryIcon}
|
||||
{isCloud && userdata.support === true ?
|
||||
<Tooltip title="Edit features (support users only)">
|
||||
<EditIcon
|
||||
color="secondary"
|
||||
style={{marginRight: 10, cursor: "pointer", }}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (showEdit) {
|
||||
setShowEdit(false)
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Edit")
|
||||
|
||||
setShowEdit(true)
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
: null}
|
||||
<Tooltip title={props.data.active ? "Disable feature" : "Enable feature"}>
|
||||
<span
|
||||
style={{cursor: "pointer", marginTop: 5, }}
|
||||
onClick={(e) => {
|
||||
if (!isCloud || userdata.support !== true) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
enableFeature()
|
||||
}}
|
||||
>
|
||||
{secondaryIcon}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</ListItem>
|
||||
{expanded ? (
|
||||
{expanded ?
|
||||
<div style={{ padding: 15 }}>
|
||||
<Typography>
|
||||
<b>Usage: </b>
|
||||
@@ -2250,7 +2449,41 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
</Typography>*/}
|
||||
<Typography style={{maxHeight: 150, overflowX: "hidden", overflowY: "auto"}}><b>Description:</b> {secondary}</Typography>
|
||||
</div>
|
||||
) : null}
|
||||
: null}
|
||||
|
||||
|
||||
{showEdit ?
|
||||
<FormControl fullWidth onSubmit={(e) => {
|
||||
console.log("Submit")
|
||||
submitEdit(e)
|
||||
}}>
|
||||
<span style={{display: "flex", }}>
|
||||
|
||||
<TextField
|
||||
style={{flex: 3, }}
|
||||
color="primary"
|
||||
label={"Edit value"}
|
||||
defaultValue={props.data.limit}
|
||||
style={{
|
||||
}}
|
||||
onChange={(event) => {
|
||||
setNewValue(event.target.value)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
style={{flex: 1, }}
|
||||
variant="contained"
|
||||
disabled={newValue < -1}
|
||||
onClick={(e) => {
|
||||
console.log("Submit 2")
|
||||
submitEdit(e)
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</span>
|
||||
</FormControl>
|
||||
: null}
|
||||
</Card>
|
||||
</Grid>
|
||||
);
|
||||
@@ -2380,16 +2613,23 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
|
||||
var regiontag = "eu";
|
||||
if (userdata.region_url !== undefined && userdata.region_url !== null && userdata.region_url.length > 0) {
|
||||
const regionsplit = userdata.region_url.split(".");
|
||||
if (regionsplit.length > 2 && !regionsplit[0].includes("shuffler")) {
|
||||
const namesplit = regionsplit[0].split("/");
|
||||
|
||||
regiontag = namesplit[namesplit.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
const organizationView =
|
||||
curTab === 0 && selectedOrganization.id !== undefined ? (
|
||||
<div style={{ position: "relative" }}>
|
||||
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
||||
<h2 style={{ display: "inline" }}>Organization overview</h2>
|
||||
<span style={{ marginLeft: 25 }}>
|
||||
On this page you can configure individual parts of your
|
||||
organization.{" "}
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginLeft: 0}}>
|
||||
On this page organization admins can configure organisations, and sub-orgs (MSSP).{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -2398,7 +2638,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</span>
|
||||
</Typography>
|
||||
</div>
|
||||
{selectedOrganization.id === undefined ? (
|
||||
<div
|
||||
@@ -2471,6 +2711,21 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
</FormControl>
|
||||
</span>
|
||||
: null}
|
||||
{isCloud ?
|
||||
<Tooltip
|
||||
title={`Organization is in ${regiontag}. Click to change!`}
|
||||
style={{}}
|
||||
>
|
||||
<Avatar
|
||||
style={{ top: -10, right: 50, position: "absolute", }}
|
||||
onClick={() => {
|
||||
toast("Region change is not implemented yet for users. Please contact support.")
|
||||
}}
|
||||
>
|
||||
{regiontag}
|
||||
</Avatar>
|
||||
</Tooltip>
|
||||
: null}
|
||||
|
||||
<Tooltip
|
||||
title={"Copy Organization ID"}
|
||||
@@ -2550,13 +2805,13 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
value={adminTab}
|
||||
indicatorColor="primary"
|
||||
textColor="secondary"
|
||||
style={{marginTop: 20, }}
|
||||
style={{marginTop: 50, }}
|
||||
onChange={(event, inputValue) => {
|
||||
const newValue = parseInt(inputValue);
|
||||
const newValue = parseInt(inputValue);
|
||||
setAdminTab(newValue);
|
||||
|
||||
//const setConfig = (event, inputValue) => {
|
||||
navigate(`/admin?admin_tab=${admin_views[newValue]}`);
|
||||
//const setConfig = (event, inputValue) => {
|
||||
navigate(`/admin?admin_tab=${admin_views[newValue]}`);
|
||||
}}
|
||||
aria-label="disabled tabs example"
|
||||
>
|
||||
@@ -2577,7 +2832,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
/>
|
||||
<Tab
|
||||
label=<span>
|
||||
Licensing
|
||||
Billing & Stats
|
||||
</span>
|
||||
/>
|
||||
<Tab
|
||||
@@ -2777,12 +3032,12 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
</div>
|
||||
)}
|
||||
<Typography variant="h6" style={{ marginLeft: 5, marginTop: 40, marginBottom: 5 }}>
|
||||
Cloud sync features
|
||||
Features
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary" style={{marginBottom: 10, marginLeft: 5, }}>
|
||||
If not otherwise specified, Usage will reset monthly
|
||||
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>
|
||||
<Grid container style={{ width: "100%", marginBottom: 15 }}>
|
||||
<Grid container style={{ width: "100%", marginBottom: 15, paddingBottom: 150, }}>
|
||||
|
||||
{selectedOrganization.sync_features === undefined ||
|
||||
selectedOrganization.sync_features === null
|
||||
@@ -2791,15 +3046,15 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
key,
|
||||
index
|
||||
) {
|
||||
// unnecessary parts
|
||||
if (key === "schedule" || key === "apps" || key === "updates") {
|
||||
|
||||
if (key === "schedule" || key === "apps" || key === "updates" || key === "editing") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const item = selectedOrganization.sync_features[key];
|
||||
if (item === null) {
|
||||
return null
|
||||
}
|
||||
if (item === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const newkey = key.replaceAll("_", " ");
|
||||
const griditem = {
|
||||
@@ -3732,7 +3987,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
}}
|
||||
/>
|
||||
<ListItemText
|
||||
primary={data.app.name}
|
||||
primary={data.app.name.replaceAll("_", " ")}
|
||||
style={{ minWidth: 175, maxWidth: 175, marginLeft: 10 }}
|
||||
/>
|
||||
{/*
|
||||
@@ -3799,7 +4054,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
{data.defined ? (
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Set in EVERY workflow in the organization"
|
||||
title="Set for EVERY instance of this App being used in this organization"
|
||||
placement="top"
|
||||
>
|
||||
<IconButton
|
||||
@@ -3983,7 +4238,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Type"
|
||||
style={{ minWidth: 125, maxWidth: 125 }}
|
||||
style={{ minWidth: 100, maxWidth: 100, }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary={"In Queue"}
|
||||
@@ -3991,7 +4246,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Default"
|
||||
style={{ minWidth: 150, maxWidth: 150 }}
|
||||
style={{ minWidth: 100, maxWidth: 100 }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Actions"
|
||||
@@ -4031,7 +4286,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
|
||||
//console.log("Show CPU alert: ", showCPUAlert)
|
||||
|
||||
const queueSize = environment.queue !== undefined && environment.queue !== null ? environment.queue < 0 ? 0 : environment.queue > 99 ? ">99" : environment.queue : 0
|
||||
const queueSize = environment.queue !== undefined && environment.queue !== null ? environment.queue < 0 ? 0 : environment.queue > 1000 ? ">1000" : environment.queue : 0
|
||||
|
||||
return (
|
||||
<span key={index}>
|
||||
@@ -4121,22 +4376,22 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
|
||||
<ListItemText
|
||||
primary={environment.Type}
|
||||
style={{ minWidth: 125, maxWidth: 125 }}
|
||||
style={{ minWidth: 100, maxWidth: 100, }}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
overflow: "hidden",
|
||||
marginLeft: 10,
|
||||
marginLeft: 0,
|
||||
}}
|
||||
|
||||
primary={queueSize}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
minWidth: 140,
|
||||
maxWidth: 140,
|
||||
minWidth: 80,
|
||||
maxWidth: 80,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
primary={environment.default ? "true" : null}
|
||||
@@ -4144,7 +4399,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
{environment.default ? null : (
|
||||
<Button
|
||||
variant="outlined"
|
||||
style={{ marginRight: 5 }}
|
||||
style={{ marginLeft: 0, marginRight: 0, }}
|
||||
onClick={() => setDefaultEnvironment(environment)}
|
||||
color="primary"
|
||||
>
|
||||
@@ -4242,7 +4497,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
||||
<h2 style={{ display: "inline" }}>Organizations</h2>
|
||||
<span style={{ marginLeft: 25 }}>
|
||||
Global admin: control organizations
|
||||
Control sub organizations (tenants)! {isCloud ? "You can only make a sub organization if you are a customer of shuffle or running a POC of the platform. Please contact support@shuffler.io to try it out." : ""}. <a href="/docs/organizations" target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: theme.palette.primary.main }}>Learn more</a>
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
|
||||
@@ -128,8 +128,8 @@ import Draggable from "react-draggable";
|
||||
|
||||
import cytoscapestyle from "../defaultCytoscapeStyle.jsx";
|
||||
|
||||
import { validateJson, GetIconInfo } from "./Workflows.jsx";
|
||||
import { GetParsedPaths } from "./Apps.jsx";
|
||||
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
||||
import { GetParsedPaths, internalIds, } from "../views/Apps.jsx";
|
||||
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
||||
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
||||
import ParsedAction from "../components/ParsedAction.jsx";
|
||||
@@ -523,6 +523,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [_, setUpdate] = useState(""); // Used to force rendring, don't remove
|
||||
|
||||
const [workflowExecutions, setWorkflowExecutions] = React.useState([]);
|
||||
const [workflowExecutionCount, setWorkflowExecutionCount] = React.useState(0);
|
||||
const [defaultEnvironmentIndex, setDefaultEnvironmentIndex] = React.useState(0);
|
||||
const [workflowRecommendations, setWorkflowRecommendations] = React.useState(undefined);
|
||||
|
||||
@@ -547,6 +548,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"field_id": "",
|
||||
})
|
||||
|
||||
const [executionArgumentModalOpen, setExecutionArgumentModalOpen] = React.useState(false);
|
||||
|
||||
// This should all be set once, not on every iteration
|
||||
// Use states and don't update lol
|
||||
const cloudSyncEnabled =
|
||||
@@ -709,6 +712,33 @@ const AngularWorkflow = (defaultprops) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getWorkflowExecutionCount = (workflowId) => {
|
||||
fetch(`${globalUrl}/api/v1/workflows/${workflowId}/executions/count`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for workflow execution count: O!");
|
||||
return;
|
||||
} else {
|
||||
return response.json();
|
||||
}
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson !== undefined) {
|
||||
setWorkflowExecutionCount(responseJson.count || 0);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
const getAvailableWorkflows = (trigger_index) => {
|
||||
fetch(globalUrl + "/api/v1/workflows", {
|
||||
method: "GET",
|
||||
@@ -992,6 +1022,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
console.log("GOT A RESPONSE??")
|
||||
// getWorkflowExecutionCount(id);
|
||||
if (responseJson !== undefined && responseJson !== null && responseJson.executions !== undefined && responseJson.executions !== null) {
|
||||
|
||||
// - means it's opposite
|
||||
@@ -1362,7 +1393,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
if (streamDisabled) {
|
||||
console.log("Stream disabled")
|
||||
console.log("Stream disabled - send")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1377,13 +1408,20 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const streamUrl = "https://stream.shuffler.io"
|
||||
const url = `${streamUrl}/api/v1/workflows/${props.match.params.key}/stream`
|
||||
|
||||
var parsedbody = body
|
||||
try {
|
||||
parsedbody = JSON.stringify(body)
|
||||
} catch (e) {
|
||||
console.log("Error parsing body for stream: ", e)
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
body: parsedbody,
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
@@ -1733,6 +1771,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
};
|
||||
|
||||
const executeWorkflow = (executionArgument, startNode, hasSaved) => {
|
||||
|
||||
ReactDOM.unstable_batchedUpdates(() => {
|
||||
if (hasSaved === false) {
|
||||
setExecutionRequestStarted(true);
|
||||
@@ -1755,6 +1794,41 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setExecutionRequest({})
|
||||
stop()
|
||||
|
||||
// FIXME: Check if any node contains $exec in a param
|
||||
// If they do, show a popup asking if they want to execute it without an execution argument, or to use a previous one
|
||||
if (executionArgument === undefined || executionArgument === null || executionArgument.length === 0 && workflow.actions !== undefined && workflow.actions !== null && workflow.actions.length > 0) {
|
||||
var foundmissing = false
|
||||
for (let actionkey in workflow.actions) {
|
||||
if (workflow.actions[actionkey].parameters === undefined || workflow.actions[actionkey].parameters === null || workflow.actions[actionkey].parameters.length === 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (let paramkey in workflow.actions[actionkey].parameters) {
|
||||
const param = workflow.actions[actionkey].parameters[paramkey]
|
||||
if (param.value === undefined || param.value === null || param.value.length === 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (param.value.indexOf("$exec") !== -1) {
|
||||
foundmissing = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (foundmissing) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
console.log("FOUNDMISSING: ", foundmissing)
|
||||
if (foundmissing) {
|
||||
//toast("This workflow contains a node that requires an execution argument. Please provide one.")
|
||||
setExecutionRequestStarted(false)
|
||||
setExecutionArgumentModalOpen(true)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var curelements = cy.elements();
|
||||
for (let i = 0; i < curelements.length; i++) {
|
||||
curelements[i].addClass("not-executing-highlight");
|
||||
@@ -1782,18 +1856,22 @@ const AngularWorkflow = (defaultprops) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (!responseJson.success) {
|
||||
//toast("Failed to start: " + responseJson.reason);
|
||||
toast(responseJson.reason);
|
||||
//toast.error(responseJson.reason);
|
||||
setExecutionRunning(false);
|
||||
setExecutionRequestStarted(false);
|
||||
stop();
|
||||
//toast("Failed to start: " + responseJson.reason);
|
||||
toast(responseJson.reason);
|
||||
//toast.error(responseJson.reason);
|
||||
setExecutionRunning(false);
|
||||
setExecutionRequestStarted(false);
|
||||
stop();
|
||||
|
||||
for (let i = 0; i < curelements.length; i++) {
|
||||
curelements[i].removeClass("not-executing-highlight");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (responseJson.execution_id !== undefined && responseJson.execution_id !== null && responseJson.execution_id.length > 0) {
|
||||
navigate(`?execution_id=${responseJson.execution_id}`)
|
||||
}
|
||||
|
||||
setExecutionRunning(true);
|
||||
setExecutionRequestStarted(false);
|
||||
}
|
||||
@@ -1836,7 +1914,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// This can be used to only show prioritzed ones later
|
||||
// Right now, it can prioritize authenticated ones
|
||||
//"Testing",
|
||||
const internalIds = ["Shuffle Tools", "http", "email"];
|
||||
|
||||
const getAppAuthentication = (reset, updateAction, closeMenu) => {
|
||||
fetch(globalUrl + "/api/v1/apps/authentication", {
|
||||
@@ -2038,8 +2115,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setApps(responseJson);
|
||||
|
||||
if (isCloud) {
|
||||
setFilteredApps(responseJson.filter((app) => !internalIds.includes(app.name)));
|
||||
setPrioritizedApps(responseJson.filter((app) => internalIds.includes(app.name)));
|
||||
setFilteredApps(responseJson.filter((app) => !internalIds.includes(app.name.toLowerCase())));
|
||||
setPrioritizedApps(responseJson.filter((app) => internalIds.includes(app.name.toLowerCase())));
|
||||
|
||||
} else {
|
||||
//setFilteredApps(
|
||||
@@ -2050,12 +2127,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// )
|
||||
//);
|
||||
|
||||
var tmpFiltered = responseJson.filter((app) => !internalIds.includes(app.name))
|
||||
var tmpFiltered = responseJson.filter((app) => !internalIds.includes(app.name.toLowerCase()))
|
||||
//tmpFiltered = sortByKey(tmpFiltered, "activated")
|
||||
setFilteredApps(tmpFiltered)
|
||||
|
||||
//!(!app.activated && app.generated)
|
||||
setPrioritizedApps(responseJson.filter((app) => internalIds.includes(app.name)));
|
||||
setPrioritizedApps(responseJson.filter((app) => internalIds.includes(app.name.toLowerCase())));
|
||||
}
|
||||
|
||||
setAppsLoaded(true)
|
||||
@@ -2564,7 +2641,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const appendChunks = (result) => {
|
||||
var chunk = decoder.decode(result.value || new Uint8Array, {stream: !result.done});
|
||||
console.log("Got chunk: ", chunk)
|
||||
|
||||
if (chunk === undefined || chunk === null) {
|
||||
console.log("Chunk is undefined or null")
|
||||
@@ -2663,7 +2739,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
if (streamDisabled) {
|
||||
console.log("Stream disabled")
|
||||
console.log("Stream listener disabled")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2675,6 +2751,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const url = `${streamUrl}/api/v1/workflows/${workflowId}/stream`
|
||||
while (true) {
|
||||
if (streamDisabled === true || streamDisabled2 === true) {
|
||||
console.log("Stream disabled, breaking")
|
||||
break
|
||||
}
|
||||
|
||||
@@ -2711,8 +2788,11 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (response.status >= 500) {
|
||||
toast("Something went wrong while loading the workflow. Please reload.")
|
||||
} else {
|
||||
toast("You don't access to this workflow or loading failed.")
|
||||
window.location.pathname = "/workflows";
|
||||
toast("You don't access to this workflow or loading failed. Redirecting to workflows in a few seconds..")
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.pathname = "/workflows";
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3652,6 +3732,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
return
|
||||
} else if (data.buttonType === "set_startnode" && data.type !== "TRIGGER") {
|
||||
//console.log("STARTNODE")
|
||||
//event.preventDefault()
|
||||
//event.stopPropagation()
|
||||
|
||||
const parentNode = cy.getElementById(data.attachedTo);
|
||||
if (parentNode !== null && parentNode !== undefined) {
|
||||
var oldstartnode = cy.getElementById(workflow.start);
|
||||
@@ -3784,19 +3868,19 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return;
|
||||
} else if (data.isDescriptor) {
|
||||
console.log("Can't select descriptor");
|
||||
if (data.isTrigger) {
|
||||
console.log("But maybe we can select trigger descriptor? Maybe open execution tab?")
|
||||
setExecutionModalOpen(true)
|
||||
}
|
||||
if (data.isTrigger) {
|
||||
console.log("But maybe we can select trigger descriptor? Maybe open execution tab?")
|
||||
setExecutionModalOpen(true)
|
||||
}
|
||||
|
||||
event.target.unselect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.type === undefined) {
|
||||
console.log("No type, automatically setting to action");
|
||||
data.type = "ACTION"
|
||||
}
|
||||
if (data.type === undefined) {
|
||||
console.log("No type, automatically setting to action");
|
||||
data.type = "ACTION"
|
||||
}
|
||||
|
||||
if (data.type === "ACTION") {
|
||||
setSelectedComment({})
|
||||
@@ -3888,8 +3972,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
//}
|
||||
curaction.app_id = curapp.id
|
||||
|
||||
console.log("CURAPP: ", curapp.authentication)
|
||||
|
||||
setAuthenticationType(
|
||||
curapp.authentication.type === "oauth2" && curapp.authentication.redirect_uri !== undefined && curapp.authentication.redirect_uri !== null ? {
|
||||
type: "oauth2",
|
||||
@@ -3921,41 +4003,58 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const tmpAuth = JSON.parse(JSON.stringify(newAppAuth));
|
||||
//console.log("FOUND AUTH OPTIONS: ", tmpAuth)
|
||||
|
||||
const curappName = curapp.name.toLowerCase()
|
||||
for (let tmpAuthKey in tmpAuth) {
|
||||
var item = tmpAuth[tmpAuthKey];
|
||||
const curappName = curapp.name.toLowerCase()
|
||||
for (let tmpAuthKey in tmpAuth) {
|
||||
var item = tmpAuth[tmpAuthKey];
|
||||
|
||||
const newfields = {};
|
||||
if (item.app.name.toLowerCase() !== curappName) {
|
||||
continue
|
||||
}
|
||||
const newfields = {};
|
||||
if (item.app.name.toLowerCase() !== curappName) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Makes list into key:value object
|
||||
for (let fieldkey in item.fields) {
|
||||
if (item.fields[fieldkey] === undefined) {
|
||||
console.log("Problem with filterkey in Node select", fieldkey)
|
||||
continue
|
||||
}
|
||||
// Makes list into key:value object
|
||||
for (let fieldkey in item.fields) {
|
||||
if (item.fields[fieldkey] === undefined) {
|
||||
console.log("Problem with filterkey in Node select", fieldkey)
|
||||
continue
|
||||
}
|
||||
|
||||
const filterkey = item.fields[fieldkey]["key"]
|
||||
if (filterkey === null || filterkey === undefined) {
|
||||
console.log("Problem with filterkey 2. Null or undefined 3")
|
||||
continue
|
||||
}
|
||||
const filterkey = item.fields[fieldkey]["key"]
|
||||
if (filterkey === null || filterkey === undefined) {
|
||||
console.log("Problem with filterkey 2. Null or undefined 3")
|
||||
continue
|
||||
}
|
||||
|
||||
newfields[filterkey] = item.fields[fieldkey]["value"];
|
||||
}
|
||||
newfields[filterkey] = item.fields[fieldkey]["value"];
|
||||
}
|
||||
|
||||
item.fields = newfields;
|
||||
if (item.app.name.toLowerCase() === curappName) {
|
||||
authenticationOptions.push(item);
|
||||
if (item.id === findAuthId) {
|
||||
curaction.selectedAuthentication = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
item.fields = newfields;
|
||||
if (item.app.name.toLowerCase() === curappName) {
|
||||
authenticationOptions.push(item);
|
||||
if (item.id === findAuthId) {
|
||||
curaction.selectedAuthentication = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find with authenticationOption (authenticationOptions) has the highest .edited time. In this index, set the "last_modified" to true
|
||||
|
||||
var latesttime = 0
|
||||
var latestindex = -1
|
||||
|
||||
for (var i = 0; i < authenticationOptions.length; i++) {
|
||||
const authopt = authenticationOptions[i]
|
||||
|
||||
if (authopt.edited > latesttime) {
|
||||
latesttime = authopt.edited
|
||||
latestindex = i
|
||||
}
|
||||
}
|
||||
|
||||
if (latestindex !== -1) {
|
||||
authenticationOptions[latestindex].last_modified = true
|
||||
}
|
||||
|
||||
curaction.authentication = authenticationOptions;
|
||||
if (
|
||||
@@ -5833,7 +5932,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (workflow.actions.length < 4) {
|
||||
addSuggestionButtons(nodedata, event);
|
||||
} else {
|
||||
console.log("Too many actions to suggest (for now)")
|
||||
//console.log("Too many actions to suggest (for now)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7467,26 +7566,26 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const tmpAuth = JSON.parse(JSON.stringify(appAuthentication));
|
||||
for (let authkey in tmpAuth) {
|
||||
if (authkey === undefined) {
|
||||
continue
|
||||
}
|
||||
if (authkey === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
var item = tmpAuth[authkey];
|
||||
const newfields = {};
|
||||
for (let fieldkey in item.fields) {
|
||||
if (item.fields[fieldkey] === undefined) {
|
||||
console.log("Problem with filterkey in Node select", fieldkey)
|
||||
continue
|
||||
}
|
||||
for (let fieldkey in item.fields) {
|
||||
if (item.fields[fieldkey] === undefined) {
|
||||
console.log("Problem with filterkey in Node select", fieldkey)
|
||||
continue
|
||||
}
|
||||
|
||||
const filterkey = item.fields[fieldkey]["key"]
|
||||
if (filterkey === null || filterkey === undefined) {
|
||||
console.log("Problem with filterkey 2. Null or undefined 3")
|
||||
continue
|
||||
}
|
||||
const filterkey = item.fields[fieldkey]["key"]
|
||||
if (filterkey === null || filterkey === undefined) {
|
||||
console.log("Problem with filterkey 2. Null or undefined 3")
|
||||
continue
|
||||
}
|
||||
|
||||
newfields[filterkey] = item.fields[fieldkey]["value"];
|
||||
}
|
||||
newfields[filterkey] = item.fields[fieldkey]["value"];
|
||||
}
|
||||
|
||||
item.fields = newfields;
|
||||
if (item.app.id === app.id || item.app.name === app.name) {
|
||||
@@ -7733,9 +7832,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [visibleApps, setVisibleApps] = React.useState(
|
||||
Array.prototype.concat.apply(
|
||||
prioritizedApps,
|
||||
filteredApps.filter((innerapp) => !internalIds.includes(innerapp.id)),
|
||||
)
|
||||
);
|
||||
filteredApps.filter((innerapp) => !internalIds.includes(innerapp.id.toLowerCase()))
|
||||
)
|
||||
)
|
||||
|
||||
var delay = -75
|
||||
var runDelay = false
|
||||
@@ -7982,7 +8081,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setVisibleApps(
|
||||
prioritizedApps.concat(
|
||||
filteredApps.filter(
|
||||
(innerapp) => !internalIds.includes(innerapp.id)
|
||||
(innerapp) => !internalIds.includes(innerapp.id.toLowerCase())
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -9158,6 +9257,139 @@ const AngularWorkflow = (defaultprops) => {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
};
|
||||
|
||||
|
||||
// Makes a list of items the user can choose from based on previous runs
|
||||
var availableArguments = []
|
||||
if (executionArgumentModalOpen && workflowExecutions.length > 0) {
|
||||
for (let executionKey in workflowExecutions) {
|
||||
if (availableArguments.length > 5) {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
const execution = workflowExecutions[executionKey]
|
||||
if (execution.execution_argument === undefined || execution.execution_argument === null || execution.execution_argument.length < 2) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (execution.execution_argument.includes("too large ")) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (availableArguments.includes(execution.execution_argument)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
availableArguments.push(execution.execution_argument)
|
||||
}
|
||||
}
|
||||
|
||||
const executionArgumentModal =
|
||||
<Dialog
|
||||
PaperComponent={PaperComponent}
|
||||
disableEnforceFocus={true}
|
||||
hideBackdrop={true}
|
||||
disableBackdropClick={true}
|
||||
style={{ pointerEvents: "none" }}
|
||||
PaperComponent={PaperComponent}
|
||||
aria-labelledby="draggable-dialog-title"
|
||||
open={executionArgumentModalOpen}
|
||||
PaperProps={{
|
||||
style: {
|
||||
padding: 30,
|
||||
pointerEvents: "auto",
|
||||
color: "white",
|
||||
minWidth: isMobile ? "90%" : 800,
|
||||
border: theme.palette.defaultBorder,
|
||||
},
|
||||
}}
|
||||
onClose={() => {
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
title="Close window"
|
||||
placement="top"
|
||||
style={{ zIndex: 10011 }}
|
||||
>
|
||||
<IconButton
|
||||
style={{ zIndex: 5000, position: "absolute", top: 34, right: 34 }}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setExecutionArgumentModalOpen(false);
|
||||
}}
|
||||
>
|
||||
<CloseIcon style={{ color: "white" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<DialogTitle id="draggable-dialog-title" style={{ cursor: "move", }}>
|
||||
<span style={{ color: "white" }}>Please provide an execution argument</span>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
At least one node in this workflow requires an execution argument. Please select one below, or provide a custom one in the text field next to the run button.
|
||||
</Typography>
|
||||
{/*
|
||||
<div style={{marginTop: 10, }}>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="An argument to be used for execution. This is a variable available to every node in your workflow."
|
||||
placement="top"
|
||||
>
|
||||
<TextField
|
||||
id="execution_argument_input_field"
|
||||
style={theme.palette.textFieldStyle}
|
||||
disabled={workflow.public}
|
||||
color="secondary"
|
||||
placeholder={"Execution Argument"}
|
||||
defaultValue={executionText}
|
||||
onBlur={(e) => {
|
||||
setExecutionText(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
*/}
|
||||
|
||||
<Divider style={{marginTop: 10, marginBottom: 20, }}/>
|
||||
{availableArguments.length > 0 ?
|
||||
<div>
|
||||
<Typography variant="body1" style={{}}>
|
||||
Previously used arguments:
|
||||
</Typography>
|
||||
{availableArguments.map((data) => {
|
||||
return (
|
||||
<Paper style={{ padding: 10, marginTop: 10, backgroundColor: theme.palette.platformColor, maxHeight: 70, overflow: "auto", cursor: "pointer", position: "relative", }}
|
||||
onClick={() => {
|
||||
setExecutionText(data)
|
||||
executeWorkflow(data, workflow.start, lastSaved);
|
||||
setExecutionArgumentModalOpen(false)
|
||||
}}
|
||||
>
|
||||
<div style={{height: "100%", width: 2, backgroundColor: "rgba(255, 255, 255, 0.5)", position: "absolute", left: 0, top: 0}} />
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
{data}
|
||||
</Typography>
|
||||
</Paper>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
: null}
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
executeWorkflow(" ", workflow.start, lastSaved);
|
||||
setExecutionArgumentModalOpen(false);
|
||||
}}
|
||||
style={{ marginTop: 20, marginBottom: 20 }}
|
||||
>
|
||||
Run anyway
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
const aiQueryModal =
|
||||
<Dialog
|
||||
PaperComponent={PaperComponent}
|
||||
@@ -10420,7 +10652,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
};
|
||||
|
||||
const handleWorkflowSelectionUpdate = (e, isUserinput) => {
|
||||
setUpdate(Math.random());
|
||||
|
||||
if (e.target.value === undefined || e.target.value === null || e.target.value.id === undefined) {
|
||||
console.log("Returning as there's no id. Value: ", e.target.value);
|
||||
@@ -10428,6 +10659,16 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const paramIndex = isUserinput === true ? 5 : 0
|
||||
|
||||
console.log("USERINPUT: ", paramIndex, workflow.triggers[selectedTriggerIndex])
|
||||
if (workflow.triggers[selectedTriggerIndex].parameters[paramIndex] === undefined || workflow.triggers[selectedTriggerIndex].parameters[paramIndex] === null) {
|
||||
workflow.triggers[selectedTriggerIndex].parameters[paramIndex] = {
|
||||
"name": "subflow",
|
||||
"value": "",
|
||||
}
|
||||
}
|
||||
|
||||
setUpdate(Math.random());
|
||||
workflow.triggers[selectedTriggerIndex].parameters[paramIndex].value = e.target.value.id;
|
||||
setSubworkflow(e.target.value);
|
||||
|
||||
@@ -13489,9 +13730,54 @@ const AngularWorkflow = (defaultprops) => {
|
||||
variant="body2"
|
||||
>
|
||||
{workflow.errors.slice(0,3).map((error) => {
|
||||
// Loop through each word, and if it matches "Action <name> " then replace it with a link to the action
|
||||
var colornext = false
|
||||
const newerror = error === undefined || error == null ? "" : error.split(" ").map((word) => {
|
||||
if (colornext) {
|
||||
colornext = false
|
||||
return (
|
||||
<span
|
||||
style={{color: "#f85a3e", cursor: "pointer"}}
|
||||
onClick={() => {
|
||||
console.log("Clicked action: ", word)
|
||||
|
||||
// Find it in cytoscape
|
||||
if (cy === undefined || cy === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const foundnode = cy.nodes().filter((node) => {
|
||||
return node.data().label === word
|
||||
})
|
||||
|
||||
if (foundnode === undefined || foundnode === null || foundnode.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Found node: ", foundnode)
|
||||
cy.elements().unselect()
|
||||
foundnode[0].select()
|
||||
}}
|
||||
>
|
||||
{word}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (word.toLowerCase() === "action") {
|
||||
colornext = true
|
||||
}
|
||||
|
||||
return word + " "
|
||||
})
|
||||
|
||||
if (newerror === undefined || newerror === null || newerror === "") {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
- {error}
|
||||
- {newerror}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
@@ -13499,6 +13785,40 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</div>
|
||||
: null
|
||||
|
||||
const RightsideBar = () => {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed", right: -5, top: "40%", width: 70, height: 235, border: "1px solid #f85a3e", cursor: "pointer", borderRadius: theme.palette.borderRadius,
|
||||
padding: 10,
|
||||
backgroundColor: hovered ? theme.palette.surfaceColor : theme.palette.platformColor,
|
||||
}}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onClick={() => {
|
||||
setExecutionModalOpen(true);
|
||||
getWorkflowExecution(props.match.params.key, "");
|
||||
}}
|
||||
>
|
||||
<ArrowLeftIcon style={{marginTop: 10, marginLeft: 10, marginBottom: 10, }}/>
|
||||
<Typography
|
||||
variant="h6"
|
||||
style={{
|
||||
writingMode: "vertical-rl",
|
||||
textOrientation: "mixed",
|
||||
marginLeft: 10,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Explore runs
|
||||
</Typography>
|
||||
{/*<ArrowLeftIcon style={{marginTop: 10, marginLeft: 10, marginBottom: 10, }}/> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const BottomCytoscapeBar = () => {
|
||||
if (workflow.id === undefined || workflow.id === null || (!workflow.public && apps.length === 0)) {
|
||||
return null;
|
||||
@@ -13634,7 +13954,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
{workflow.public ? (
|
||||
{workflow.public || userdata.support == true ? (
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
title="Download workflow"
|
||||
@@ -14345,6 +14665,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex" }}>
|
||||
<IconButton
|
||||
@@ -14810,7 +15131,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
>
|
||||
<h2 style={{ color: "rgba(255,255,255,0.5)" }}>
|
||||
<DirectionsRunIcon style={{ marginRight: 10 }} />
|
||||
All Workflow Runs
|
||||
All Workflow Runs
|
||||
</h2>
|
||||
</Breadcrumbs>
|
||||
<Tooltip
|
||||
@@ -14818,7 +15139,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
placement="left-start"
|
||||
style={{ zIndex: 10010 }}
|
||||
>
|
||||
<a href={`/workflows/debug?workflow_id=${workflow.id}`} style={{textDecoration: "none", }}>
|
||||
<a target="_blank" href={`/workflows/debug?workflow_id=${workflow.id}`} style={{textDecoration: "none", }}>
|
||||
<Button
|
||||
color="secondary"
|
||||
style={{marginLeft: 50, maxHeight: 30, marginTop: 20, }}
|
||||
@@ -14838,7 +15159,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
color="primary"
|
||||
>
|
||||
<CachedIcon style={{ marginRight: 10 }} />
|
||||
Refresh Runs
|
||||
Refresh Runs
|
||||
</Button>
|
||||
<Divider
|
||||
style={{
|
||||
@@ -15538,13 +15859,17 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
|
||||
const chosenNodeId = new URLSearchParams(cursearch).get("node");
|
||||
const highlightNode = chosenNodeId !== null && chosenNodeId !== undefined && chosenNodeId !== "" && chosenNodeId === data.action.id
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
marginBottom: 20,
|
||||
border:
|
||||
border: highlightNode ? "2px solid red"
|
||||
:
|
||||
data.action.sub_action === true
|
||||
? "1px solid rgba(255,255,255,0.3)"
|
||||
: "1px solid rgba(255,255,255, 0.3)",
|
||||
@@ -16255,6 +16580,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
{showErrors}
|
||||
<BottomCytoscapeBar />
|
||||
<TopCytoscapeBar />
|
||||
<RightsideBar />
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
@@ -17909,6 +18235,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
{newView}
|
||||
<VariablesModal variableInfo={variableInfo} setVariableInfo={setVariableInfo} />
|
||||
<ExecutionVariableModal variableInfo={variableInfo} setVariableInfo={setVariableInfo} />
|
||||
{executionArgumentModal}
|
||||
{aiQueryModal}
|
||||
{conditionsModal}
|
||||
{authenticationModal}
|
||||
@@ -18026,28 +18353,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
);
|
||||
|
||||
// Awful way of handling scroll
|
||||
if (
|
||||
scrollConfig !== undefined &&
|
||||
setScrollConfig !== undefined &&
|
||||
Object.getOwnPropertyNames(selectedAction).length !== 0
|
||||
) {
|
||||
if (scrollConfig !== undefined && setScrollConfig !== undefined && Object.getOwnPropertyNames(selectedAction).length !== 0) {
|
||||
const rightSideActionView = document.getElementById("rightside_actions");
|
||||
if (rightSideActionView !== undefined && rightSideActionView !== null) {
|
||||
if (
|
||||
scrollConfig.top !== 0 &&
|
||||
scrollConfig.top !== undefined &&
|
||||
scrollConfig.top !== 0
|
||||
) {
|
||||
if (scrollConfig.top !== null && scrollConfig.top !== undefined && scrollConfig.top !== 0) {
|
||||
setTimeout(() => {
|
||||
if (
|
||||
scrollConfig.selected !== undefined &&
|
||||
scrollConfig.selected !== null
|
||||
) {
|
||||
const selectedField = document.getElementById(
|
||||
scrollConfig.selected
|
||||
);
|
||||
if (scrollConfig.selected !== undefined && scrollConfig.selected !== null) {
|
||||
const selectedField = document.getElementById(scrollConfig.selected)
|
||||
if (selectedField !== undefined && selectedField !== null) {
|
||||
selectedField.focus();
|
||||
selectedField.focus()
|
||||
}
|
||||
}
|
||||
}, 5);
|
||||
|
||||
+202
-103
@@ -20,6 +20,7 @@ import {
|
||||
TextField,
|
||||
Tooltip,
|
||||
Breadcrumbs,
|
||||
Drawer,
|
||||
CircularProgress,
|
||||
Chip,
|
||||
IconButton,
|
||||
@@ -43,6 +44,7 @@ import {
|
||||
Loop as LoopIcon,
|
||||
AddPhotoAlternate as AddPhotoAlternateIcon,
|
||||
CallMerge as CallMergeIcon,
|
||||
CloudDownload as CloudDownloadIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
@@ -448,6 +450,8 @@ const AppCreator = (defaultprops) => {
|
||||
const [openApiData, setOpenApiData] = React.useState("");
|
||||
const [openApiModal, setOpenApiModal] = React.useState(false);
|
||||
|
||||
const [appDownloadData, setAppDownloadData] = React.useState("");
|
||||
|
||||
useEffect(() => {
|
||||
console.log("In useEffect for openApiData: ", openApiData)
|
||||
}, [openApiData]);
|
||||
@@ -900,8 +904,9 @@ const AppCreator = (defaultprops) => {
|
||||
}
|
||||
|
||||
if (newaction.url !== undefined && newaction.url !== null && newaction.url.includes("_shuffle_replace_")) {
|
||||
const regex = /_shuffle_replace_\d/i;
|
||||
//console.log("NEW: ",
|
||||
//const regex = /_shuffle_replace_\d/i;
|
||||
const regex = /_shuffle_replace_\d+/i
|
||||
|
||||
newaction.url = newaction.url.replaceAll(new RegExp(regex, 'g'), "")
|
||||
}
|
||||
|
||||
@@ -911,11 +916,12 @@ const AppCreator = (defaultprops) => {
|
||||
var categoryindex = -1;
|
||||
// Stupid way of finding a category/grouping
|
||||
for (let splitkey in pathsplit) {
|
||||
if (pathsplit[splitkey].includes("_shuffle_replace_")) {
|
||||
const regex = /_shuffle_replace_\d/i;
|
||||
//console.log("NEW: ",
|
||||
pathsplit[splitkey] = pathsplit[splitkey].replaceAll(new RegExp(regex, 'g'), "")
|
||||
}
|
||||
if (pathsplit[splitkey].includes("_shuffle_replace_")) {
|
||||
//const regex = /_shuffle_replace_\d/i;
|
||||
const regex = /_shuffle_replace_\d+/i
|
||||
//console.log("NEW: ",
|
||||
pathsplit[splitkey] = pathsplit[splitkey].replaceAll(new RegExp(regex, 'g'), "")
|
||||
}
|
||||
|
||||
if (
|
||||
pathsplit[splitkey].length > 0 &&
|
||||
@@ -1205,9 +1211,9 @@ const AppCreator = (defaultprops) => {
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Param Error: ", e, path)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Param Error: ", e, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1527,6 +1533,10 @@ const AppCreator = (defaultprops) => {
|
||||
in: "query",
|
||||
};
|
||||
|
||||
if (parameter.example !== undefined && parameter.example !== null) {
|
||||
tmpaction.example = parameter.example
|
||||
}
|
||||
|
||||
if (parameter.required === undefined) {
|
||||
tmpaction.required = false;
|
||||
}
|
||||
@@ -2007,9 +2017,10 @@ const AppCreator = (defaultprops) => {
|
||||
var pathjoin = item.url+"_"+item.method.toLowerCase()
|
||||
if (handledPaths.includes(pathjoin)) {
|
||||
|
||||
// Max 100 of same lol
|
||||
for (let i = 0; i < 100; i++) {
|
||||
item.url = item.url+"_shuffle_replace_"+i
|
||||
// Max 1000 of same. Will it be ok for graphql longterm?
|
||||
const baseurl = item.url
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
item.url = baseurl+"_shuffle_replace_"+i
|
||||
|
||||
pathjoin = item.url+"_"+item.method.toLowerCase()
|
||||
if (handledPaths.includes(pathjoin)) {
|
||||
@@ -2289,7 +2300,7 @@ const AppCreator = (defaultprops) => {
|
||||
}
|
||||
|
||||
const methodname = item.method.toLowerCase()
|
||||
if (methodname === "post" || methodname === "put" || methodname === "patch") {
|
||||
if (methodname === "post" || methodname === "put" || methodname === "patch" || methodname === "delete") {
|
||||
if (
|
||||
item.body !== undefined &&
|
||||
item.body !== null &&
|
||||
@@ -2565,6 +2576,8 @@ const AppCreator = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
setAppDownloadData(JSON.stringify(data, null, 4))
|
||||
|
||||
fetch(globalUrl + "/api/v1/verify_openapi", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -2585,9 +2598,16 @@ const AppCreator = (defaultprops) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (!responseJson.success) {
|
||||
if (responseJson.extra !== undefined && responseJson.extra !== null) {
|
||||
toast("Failed building: " + responseJson.extra);
|
||||
}
|
||||
|
||||
if (responseJson.reason !== undefined) {
|
||||
setErrorCode(responseJson.reason);
|
||||
toast("Failed to verify: " + responseJson.reason);
|
||||
|
||||
if (responseJson.extra === undefined && responseJson.extra === null) {
|
||||
toast("Failed to verify: " + responseJson.reason);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
toast("Successfully uploaded openapi");
|
||||
@@ -3390,13 +3410,13 @@ const AppCreator = (defaultprops) => {
|
||||
}}
|
||||
label={parsedChip}
|
||||
onClick={() => {
|
||||
if (chipRequired) {
|
||||
currentAction["required_bodyfields"].splice(currentAction["required_bodyfields"].indexOf(chipData), 1)
|
||||
} else {
|
||||
currentAction["required_bodyfields"].push(chipData)
|
||||
}
|
||||
if (chipRequired) {
|
||||
currentAction["required_bodyfields"].splice(currentAction["required_bodyfields"].indexOf(chipData), 1)
|
||||
} else {
|
||||
currentAction["required_bodyfields"].push(chipData)
|
||||
}
|
||||
|
||||
setCurrentAction(currentAction);
|
||||
setCurrentAction(currentAction);
|
||||
setChipRequired(!chipRequired);
|
||||
}}
|
||||
/>
|
||||
@@ -3432,11 +3452,11 @@ const AppCreator = (defaultprops) => {
|
||||
};
|
||||
|
||||
const deletePathQuery = (index) => {
|
||||
console.log("Should delete index: ", index)
|
||||
var tmpqueries = JSON.parse(JSON.stringify(urlPathQueries))
|
||||
tmpqueries.splice(index, 1)
|
||||
console.log("Should delete index: ", index)
|
||||
var tmpqueries = JSON.parse(JSON.stringify(urlPathQueries))
|
||||
tmpqueries.splice(index, 1)
|
||||
|
||||
console.log("Queries: ", tmpqueries)
|
||||
console.log("Queries: ", tmpqueries)
|
||||
setUrlPathQueries(tmpqueries);
|
||||
|
||||
if (updater === "deleteupdater") {
|
||||
@@ -3683,48 +3703,55 @@ const AppCreator = (defaultprops) => {
|
||||
return errormessage;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const getBackgroundColor = (data) => {
|
||||
var bgColor = "#61afee";
|
||||
if (data === "POST") {
|
||||
bgColor = "#49cc90";
|
||||
} else if (data === "PUT") {
|
||||
bgColor = "#fca130";
|
||||
} else if (data === "PATCH") {
|
||||
bgColor = "#50e3c2";
|
||||
} else if (data === "DELETE") {
|
||||
bgColor = "#f93e3e";
|
||||
} else if (data === "HEAD") {
|
||||
bgColor = "#9012fe";
|
||||
}
|
||||
|
||||
return bgColor;
|
||||
}
|
||||
|
||||
|
||||
const newActionModal = (
|
||||
<Dialog
|
||||
<Drawer
|
||||
anchor={"right"}
|
||||
open={actionsModalOpen}
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: surfaceColor,
|
||||
color: "white",
|
||||
minWidth: 550,
|
||||
maxWidth: 550,
|
||||
maxHeight: 750,
|
||||
minWidth: 700,
|
||||
maxWidth: 700,
|
||||
},
|
||||
}}
|
||||
onClose={() => {
|
||||
setUrlPath("");
|
||||
setCurrentAction({
|
||||
name: "",
|
||||
description: "",
|
||||
url: "",
|
||||
file_field: "",
|
||||
headers: "",
|
||||
paths: [],
|
||||
queries: [],
|
||||
body: "",
|
||||
errors: [],
|
||||
method: actionNonBodyRequest[0],
|
||||
action_label: "No Label",
|
||||
required_bodyfields: [],
|
||||
});
|
||||
setCurrentActionMethod(apikeySelection[0]);
|
||||
setUrlPathQueries([]);
|
||||
setActionsModalOpen(false);
|
||||
setFileUploadEnabled(false);
|
||||
console.log("Closing modal");
|
||||
|
||||
console.log(currentAction);
|
||||
const errors = getActionErrors();
|
||||
addActionToView(errors);
|
||||
setActionsModalOpen(false);
|
||||
setUrlPathQueries([]);
|
||||
setUrlPath("");
|
||||
setFileUploadEnabled(false);
|
||||
}}
|
||||
>
|
||||
<FormControl style={{ backgroundColor: surfaceColor, color: "white" }}>
|
||||
<DialogTitle>
|
||||
<DialogTitle style={{marginTop: 30, }}>
|
||||
<div style={{ color: "white" }}>New action</div>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContent style={{paddingBottom: 100, }}>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://shuffler.io/docs/app_creation#actions"
|
||||
@@ -3750,7 +3777,8 @@ const AppCreator = (defaultprops) => {
|
||||
variant="outlined"
|
||||
defaultValue={currentAction["name"]}
|
||||
onChange={(e) => {
|
||||
setActionField("name", e.target.value);
|
||||
var trimmed = e.target.value.trim();
|
||||
setActionField("name", trimmed)
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
// Fix basic issues in frontend. Python functions run a-zA-Z0-9_
|
||||
@@ -3759,6 +3787,18 @@ const AppCreator = (defaultprops) => {
|
||||
if (found !== null) {
|
||||
setActionField("name", found.join(""));
|
||||
}
|
||||
|
||||
// Look through all actions and see if there is one with the same name
|
||||
if (currentAction.url === "" && actions !== undefined && actions !== null && actions.length > 0) {
|
||||
for (var i = 0; i < actions.length; i++) {
|
||||
if (actions[i].name.toLowerCase() === e.target.value.toLowerCase()) {
|
||||
toast("Action with name " + e.target.value + " already exists. If you keep this, it will be overwritten.")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
key={currentAction}
|
||||
InputProps={{
|
||||
@@ -3822,26 +3862,33 @@ const AppCreator = (defaultprops) => {
|
||||
id: "method-option",
|
||||
}}
|
||||
>
|
||||
{actionNonBodyRequest.map((data, index) => {
|
||||
|
||||
// Add actionBodyRequest to actionNonBodyRequest
|
||||
{actionNonBodyRequest.concat(actionBodyRequest).map((data, index) => {
|
||||
const backgroundColor = getBackgroundColor(data);
|
||||
return (
|
||||
<MenuItem
|
||||
key={index}
|
||||
style={{ backgroundColor: inputColor, color: "white" }}
|
||||
style={{}}
|
||||
value={data}
|
||||
>
|
||||
{data}
|
||||
<Chip
|
||||
style={{
|
||||
color: "white",
|
||||
borderRadius: 5,
|
||||
minWidth: 80,
|
||||
marginRight: 10,
|
||||
marginTop: 2,
|
||||
cursor: "pointer",
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
backgroundColor: backgroundColor,
|
||||
}}
|
||||
label={data}
|
||||
/>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
{actionBodyRequest.map((data, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
style={{ backgroundColor: inputColor, color: "white" }}
|
||||
value={data}
|
||||
>
|
||||
{data}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<div style={{ marginTop: "15px" }} />
|
||||
URL path / Curl statement
|
||||
@@ -4218,19 +4265,11 @@ const AppCreator = (defaultprops) => {
|
||||
/>
|
||||
{exampleResponse}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
setActionsModalOpen(false);
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<div style={{position: "fixed", backgroundColor: theme.palette.surfaceColor, bottom: 0, width: "100%", padding: 25, borderTop: "1px solid rgba(255,255,255,0.3)", }}>
|
||||
<Button
|
||||
color="primary"
|
||||
variant={urlPath.length > 0 ? "contained" : "outlined"}
|
||||
style={{ borderRadius: "0px" }}
|
||||
style={{ }}
|
||||
onClick={() => {
|
||||
//console.log(urlPathQueries)
|
||||
//console.log(urlPath)
|
||||
@@ -4245,9 +4284,19 @@ const AppCreator = (defaultprops) => {
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</DialogActions>
|
||||
{/*
|
||||
<Button
|
||||
style={{ marginLeft: 10, }}
|
||||
onClick={() => {
|
||||
setActionsModalOpen(false);
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
*/}
|
||||
</div>
|
||||
</FormControl>
|
||||
</Dialog>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
|
||||
@@ -4316,6 +4365,8 @@ const AppCreator = (defaultprops) => {
|
||||
|
||||
setCurrentAction(data);
|
||||
setCurrentActionMethod(data.method);
|
||||
|
||||
console.log("QUERIES: ", data.queries)
|
||||
setUrlPathQueries(data.queries);
|
||||
setUrlPath(data.url);
|
||||
setActionsModalOpen(true);
|
||||
@@ -4453,7 +4504,7 @@ const AppCreator = (defaultprops) => {
|
||||
style={{ borderRadius: 0, position: "absolute", top: 70, }}
|
||||
variant={actions.length === 0 ? "contained" : "outlined"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
|
||||
setCurrentActionMethod(actionNonBodyRequest[0]);
|
||||
setCurrentAction({
|
||||
@@ -4467,8 +4518,8 @@ const AppCreator = (defaultprops) => {
|
||||
body: "",
|
||||
errors: [],
|
||||
method: actionNonBodyRequest[0],
|
||||
action_label: "No Label",
|
||||
required_bodyfields: [],
|
||||
action_label: "No Label",
|
||||
required_bodyfields: [],
|
||||
});
|
||||
setActionsModalOpen(true);
|
||||
}}
|
||||
@@ -4485,20 +4536,20 @@ const AppCreator = (defaultprops) => {
|
||||
|
||||
//console.log("Actions: ", filteredActions)
|
||||
if (filteredActions === null || filteredActions === undefined || filteredActions.length === 0) {
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
return (
|
||||
<div>
|
||||
{filteredActions.slice(0, actionAmount).map((data, index) => {
|
||||
//console.log("Found action: ", data)
|
||||
return (
|
||||
<ActionPaper key={index} index={index} data={data} />
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ActionPaper key={index} index={index} data={data} />
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6097,20 +6148,68 @@ const AppCreator = (defaultprops) => {
|
||||
{testView}
|
||||
*/}
|
||||
|
||||
<Button
|
||||
disabled={appBuilding}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
style={{ borderRadius: "0px", marginTop: "30px", height: "50px" }}
|
||||
onClick={() => {
|
||||
submitApp();
|
||||
}}
|
||||
>
|
||||
{appBuilding ? <CircularProgress /> : "Save"}
|
||||
</Button>
|
||||
<Typography style={{ marginTop: 5 }}>
|
||||
{errorCode.length > 0 ? `Error: ${errorCode}` : null}
|
||||
</Typography>
|
||||
<div style={{display: "flex", marginTop: 35, }}>
|
||||
{appDownloadData.length > 0 ?
|
||||
<Tooltip title="Download the OpenAPI specification for the App" placement="bottom">
|
||||
<IconButton
|
||||
style={{marginRight: 25, }}
|
||||
onClick={() => {
|
||||
toast(`Downloading OpenAPI JSON data for for ${name}`)
|
||||
// Download as file
|
||||
var blob = new Blob([appDownloadData], {
|
||||
type: "application/octet-stream",
|
||||
});
|
||||
|
||||
var url = URL.createObjectURL(blob);
|
||||
var link = document.createElement("a");
|
||||
link.setAttribute("href", url);
|
||||
link.setAttribute("download", `${name}.json`);
|
||||
var event = document.createEvent("MouseEvents");
|
||||
event.initMouseEvent(
|
||||
"click",
|
||||
true,
|
||||
true,
|
||||
window,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
null
|
||||
);
|
||||
link.dispatchEvent(event);
|
||||
}}
|
||||
>
|
||||
<CloudDownloadIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
: null}
|
||||
<Button
|
||||
disabled={appBuilding}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
fullWidth
|
||||
style={{ height: "50px", flex: 1, }}
|
||||
onClick={() => {
|
||||
submitApp();
|
||||
}}
|
||||
>
|
||||
{appBuilding ? <CircularProgress /> : "Save"}
|
||||
</Button>
|
||||
{appDownloadData.length > 0 ?
|
||||
<div style={{width: 50, }}/>
|
||||
: null}
|
||||
</div>
|
||||
|
||||
<Typography style={{ marginTop: 25, textAlign: "center", }}>
|
||||
{errorCode.length > 0 ? `Upload Error: ${errorCode}` : null}
|
||||
</Typography>
|
||||
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
|
||||
+210
-59
@@ -88,6 +88,7 @@ export const FixName = (name) => {
|
||||
return newAppname;
|
||||
};
|
||||
|
||||
|
||||
// Takes input of e.g. $node.data.#.asd and a matching value from a json blob
|
||||
// Returns
|
||||
export const FindJsonPath = (path, inputdata) => {
|
||||
@@ -157,6 +158,8 @@ export const FindJsonPath = (path, inputdata) => {
|
||||
return inputdata
|
||||
}
|
||||
|
||||
export const internalIds = ["shuffle tools", "http", "email"];
|
||||
|
||||
// Parses JSON data into keys that can be used everywhere :)
|
||||
// Reverse of this is FindJsonPath
|
||||
export const GetParsedPaths = (inputdata, basekey) => {
|
||||
@@ -270,7 +273,7 @@ export const GetParsedPaths = (inputdata, basekey) => {
|
||||
|
||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||
const Apps = (props) => {
|
||||
const { globalUrl, isLoggedIn, isLoaded, userdata } = props;
|
||||
const { globalUrl, isLoggedIn, isLoaded, userdata, serverside, } = props;
|
||||
|
||||
//const [workflows, setWorkflows] = React.useState([]);
|
||||
const baseRepository = "https://github.com/frikky/shuffle-apps";
|
||||
@@ -304,6 +307,8 @@ const Apps = (props) => {
|
||||
const [cursearch, setCursearch] = React.useState("");
|
||||
const [sharingConfiguration, setSharingConfiguration] = React.useState("you");
|
||||
const [downloadBranch, setDownloadBranch] = React.useState("master");
|
||||
const [creatorProfile, setCreatorProfile] = React.useState({});
|
||||
const [contact, setContact] = React.useState("");
|
||||
|
||||
const [isDropzone, setIsDropzone] = React.useState(false);
|
||||
const upload = React.useRef(null);
|
||||
@@ -324,6 +329,40 @@ const Apps = (props) => {
|
||||
},
|
||||
});
|
||||
|
||||
const getUserProfile = (username) => {
|
||||
if (serverside === true || !isCloud) {
|
||||
setCreatorProfile({})
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`${globalUrl}/api/v1/users/creators/${username}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for WORKFLOW EXECUTION :O!");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success !== false) {
|
||||
setCreatorProfile(responseJson);
|
||||
} else {
|
||||
setCreatorProfile({})
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setCreatorProfile({})
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (apps.length <= 0 && firstrequest) {
|
||||
document.title = "Shuffle - Apps";
|
||||
@@ -441,6 +480,12 @@ const Apps = (props) => {
|
||||
setFilteredApps(privateapps);
|
||||
if (privateapps.length > 0) {
|
||||
if (selectedApp.id === undefined || selectedApp.id === null) {
|
||||
if (privateapps[0].owner !== undefined && privateapps[0].owner !== null) {
|
||||
getUserProfile(privateapps[0].owner);
|
||||
}
|
||||
|
||||
setContact(privateapps[0].contact_info)
|
||||
|
||||
setSelectedApp(privateapps[0]);
|
||||
setSharingConfiguration(privateapps[0].sharing === true ? "public" : "you")
|
||||
}
|
||||
@@ -646,6 +691,13 @@ const Apps = (props) => {
|
||||
style={paperAppStyle}
|
||||
onClick={() => {
|
||||
if (selectedApp.id !== data.id) {
|
||||
|
||||
if (data.owner !== undefined && data.owner !== null) {
|
||||
getUserProfile(data.owner);
|
||||
}
|
||||
|
||||
setContact(data.contact_info)
|
||||
|
||||
data.name = newAppname;
|
||||
setSelectedApp(data);
|
||||
setSharingConfiguration(data.sharing === true ? "public" : "you")
|
||||
@@ -869,6 +921,7 @@ const Apps = (props) => {
|
||||
</Link>
|
||||
: null
|
||||
|
||||
console.log("Sharing config: ", sharingConfiguration);
|
||||
const activateButton =
|
||||
selectedApp.generated && !selectedApp.activated ? (
|
||||
<div>
|
||||
@@ -882,7 +935,7 @@ const Apps = (props) => {
|
||||
Activate App
|
||||
</Button>
|
||||
</Link>
|
||||
<Tooltip title={"Delete app"}>
|
||||
<Tooltip title={"Delete app (confirm box will show)"}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
component="label"
|
||||
@@ -891,6 +944,7 @@ const Apps = (props) => {
|
||||
onClick={() => {
|
||||
setDeleteModalOpen(true);
|
||||
}}
|
||||
disabled={sharingConfiguration === undefined || sharingConfiguration === null || sharingConfiguration == "public"}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
@@ -905,7 +959,7 @@ const Apps = (props) => {
|
||||
(selectedApp.downloaded !== undefined && selectedApp.downloaded == true) ||
|
||||
!selectedApp.generated) &&
|
||||
activateButton === null ? (
|
||||
<Tooltip title={"Delete app"}>
|
||||
<Tooltip title={"Delete app (confirm box will show)"}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
component="label"
|
||||
@@ -914,6 +968,7 @@ const Apps = (props) => {
|
||||
onClick={() => {
|
||||
setDeleteModalOpen(true);
|
||||
}}
|
||||
disabled={sharingConfiguration === undefined || sharingConfiguration === null || sharingConfiguration == "public"}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
@@ -1114,7 +1169,7 @@ const Apps = (props) => {
|
||||
|
||||
{activateButton}
|
||||
|
||||
{ /* editNewButton === null && */ }
|
||||
{ /* editNewButton === null && */ }
|
||||
|
||||
{canEditApp ? (
|
||||
<div>
|
||||
@@ -1127,35 +1182,12 @@ const Apps = (props) => {
|
||||
{editNewButton}
|
||||
</div>
|
||||
}
|
||||
{selectedApp.tags !== undefined && selectedApp.tags !== null ? (
|
||||
<div
|
||||
style={{
|
||||
display: "inline-block",
|
||||
marginLeft: 15,
|
||||
float: "right",
|
||||
}}
|
||||
>
|
||||
{selectedApp.tags.map((tag, index) => {
|
||||
if (index >= 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Chip
|
||||
key={index}
|
||||
style={chipStyle}
|
||||
variant="outlined"
|
||||
label={tag}
|
||||
color="primary"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
{canEditApp
|
||||
? (
|
||||
<div style={{ marginTop: 15 }}>
|
||||
{canEditApp
|
||||
? (
|
||||
<div style={{ marginTop: 15, display: "flex", }}>
|
||||
{/*<p><b>ID:</b> {selectedApp.id}</p>*/}
|
||||
|
||||
<b style={{ marginRight: 15 }}>Sharing </b>
|
||||
<Select
|
||||
value={sharingConfiguration}
|
||||
@@ -1209,8 +1241,119 @@ const Apps = (props) => {
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
|
||||
{isCloud && (selectedApp.sharing === true || selectedApp.public === true || creatorProfile.github_avatar !== undefined) && !internalIds.includes(selectedApp.name.toLowerCase()) ?
|
||||
<Tooltip title="Deactivates this app for the current organisation. This means the app will not be usable again until you re-activate it." placement="top">
|
||||
<Button
|
||||
variant="contained"
|
||||
component="label"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
const tmpurl = new URL(window.location.href);
|
||||
const searchParams = tmpurl.searchParams;
|
||||
const queryID = searchParams.get("queryID");
|
||||
|
||||
if (queryID !== undefined && queryID !== null) {
|
||||
aa("init", {
|
||||
appId: "JNSS5CFDZZ",
|
||||
apiKey: "db08e40265e2941b9a7d8f644b6e5240",
|
||||
});
|
||||
|
||||
const timestamp = new Date().getTime();
|
||||
aa("sendEvents", [
|
||||
{
|
||||
eventType: "conversion",
|
||||
eventName: "Public App Activated",
|
||||
index: "appsearch",
|
||||
objectIDs: [selectedApp.id],
|
||||
timestamp: timestamp,
|
||||
queryID: queryID,
|
||||
userToken:
|
||||
userdata === undefined ||
|
||||
userdata === null ||
|
||||
userdata.id === undefined
|
||||
? "unauthenticated"
|
||||
: userdata.id,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
console.log("No query to handle when activating");
|
||||
}
|
||||
|
||||
activateApp(selectedApp.id, true)
|
||||
}}
|
||||
style={{ height: 35, marginTop: 0, marginLeft: 10, }}
|
||||
>
|
||||
Deactivate
|
||||
</Button>
|
||||
</Tooltip>
|
||||
: null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div style={{display: "flex", }}>
|
||||
{isCloud && Object.getOwnPropertyNames(creatorProfile).length !== 0 && creatorProfile.github_avatar !== undefined && creatorProfile.github_avatar !== null ?
|
||||
<div style={{ display: "flex", marginTop: 15, }}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
style={{ padding: 0, marginRight: 10 }}
|
||||
aria-controls="simple-menu"
|
||||
aria-haspopup="true"
|
||||
onClick={(event) => {
|
||||
//setAnchorElAvatar(event.currentTarget);
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to={`/creators/${creatorProfile.github_username}`}
|
||||
style={{ textDecoration: "none", color: "#f86a3e" }}
|
||||
>
|
||||
<Avatar
|
||||
style={{ height: 30, width: 30 }}
|
||||
alt={contact.name}
|
||||
src={creatorProfile.github_avatar}
|
||||
/>
|
||||
</Link>
|
||||
</IconButton>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="textSecondary"
|
||||
style={{ color: "" }}
|
||||
>
|
||||
Shared by{" "}
|
||||
<Link
|
||||
to={`/creators/${creatorProfile.github_username}`}
|
||||
style={{ textDecoration: "none", color: "#f86a3e" }}
|
||||
>
|
||||
{creatorProfile.github_username}
|
||||
</Link>
|
||||
</Typography>
|
||||
</div>
|
||||
: null}
|
||||
{selectedApp.tags !== undefined && selectedApp.tags !== null ? (
|
||||
<div
|
||||
style={{
|
||||
marginLeft: 20,
|
||||
marginTop: 15,
|
||||
}}
|
||||
>
|
||||
{selectedApp.tags.map((tag, index) => {
|
||||
if (index >= 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Chip
|
||||
key={index}
|
||||
style={chipStyle}
|
||||
variant="outlined"
|
||||
label={tag}
|
||||
color="primary"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{/*<p><b>Owner:</b> {selectedApp.owner}</p>*/}
|
||||
{selectedApp.privateId !== undefined &&
|
||||
selectedApp.privateId.length > 0 ? (
|
||||
@@ -1666,37 +1809,45 @@ const Apps = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
const activateApp = (appid, refresh) => {
|
||||
fetch(globalUrl + "/api/v1/apps/" + appid + "/activate", {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: "include",
|
||||
const activateApp = (appid, refresh) => {
|
||||
const appExists = userdata.active_apps !== undefined && userdata.active_apps !== null && userdata.active_apps.includes(appid)
|
||||
const url = appExists ? `${globalUrl}/api/v1/apps/${appid}/deactivate` : `${globalUrl}/api/v1/apps/${appid}/activate`
|
||||
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Failed to deactivate")
|
||||
}
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Failed to activate")
|
||||
}
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
toast("Failed to activate the app")
|
||||
} else {
|
||||
//toast("App activated for your organization! Refresh the page to use the app.")
|
||||
if (appExists) {
|
||||
toast("App deactivated for your organization! Existing workflows with the app will continue to work.")
|
||||
} else {
|
||||
toast("App activated for your organization!")
|
||||
}
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
toast("Failed to activate the app")
|
||||
} else {
|
||||
toast("App activated for your organization! Refresh the page to use the app.")
|
||||
|
||||
if (refresh === true) {
|
||||
getApps()
|
||||
}
|
||||
if (refresh === true) {
|
||||
getApps()
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
//toast(error.toString())
|
||||
console.log("Activate app error: ", error.toString())
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
//toast(error.toString())
|
||||
console.log("Deactivate app error: ", error.toString())
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -523,6 +523,12 @@ const Docs = (defaultprops) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (extraInfo !== "" && props.level === 1 && props.children !== undefined && props.children !== null && props.children.length > 0) {
|
||||
if (props.children[0].toLowerCase().includes("privacy") || props.children[0].toLowerCase().includes("terms")) {
|
||||
extraInfo = ""
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography
|
||||
onMouseOver={() => {
|
||||
|
||||
@@ -181,20 +181,20 @@ const LoginDialog = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) {
|
||||
console.log("RUN Welcome!!")
|
||||
window.location.pathname = "/welcome"
|
||||
return
|
||||
}
|
||||
if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) {
|
||||
console.log("RUN Welcome!!")
|
||||
window.location.pathname = "/welcome"
|
||||
return
|
||||
}
|
||||
|
||||
const tmpView = new URLSearchParams(window.location.search).get("view")
|
||||
if (tmpView !== undefined && tmpView !== null) {
|
||||
//const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}`
|
||||
const newUrl = `/${tmpView}`
|
||||
window.location.pathname = newUrl
|
||||
} else {
|
||||
window.location.pathname = "/workflows"
|
||||
}
|
||||
const tmpView = new URLSearchParams(window.location.search).get("view")
|
||||
if (tmpView !== undefined && tmpView !== null) {
|
||||
//const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}`
|
||||
const newUrl = `/${tmpView}`
|
||||
window.location.pathname = newUrl
|
||||
} else {
|
||||
window.location.pathname = "/workflows"
|
||||
}
|
||||
|
||||
setIsLoggedIn(true);
|
||||
}
|
||||
|
||||
@@ -290,59 +290,6 @@ const Settings = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
// const registerProviders = (userdata) => {
|
||||
// // Register hooks here
|
||||
// detectEthereumProvider().then((provider) => {
|
||||
// if (provider) {
|
||||
// if (!provider.isMetaMask) {
|
||||
// toast("Only MetaMask is supported as of now.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Find the ethereum network
|
||||
// // Get the users' account(s)
|
||||
// //toast("Connecting to MetaMask")
|
||||
// //console.log("Connected: ", provider.isConnected())
|
||||
|
||||
// if (!provider.isConnected()) {
|
||||
// toast("Metamask is not connected.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// provider.on("message", (event) => {
|
||||
// toast("Ethereum message: ", event);
|
||||
// });
|
||||
|
||||
// provider.on("chainChanged", (chainId) => {
|
||||
// console.log("Changed chain to: ", chainId);
|
||||
|
||||
// const method = "eth_getBalance";
|
||||
// const params = [userdata.eth_info.account, "latest"];
|
||||
// provider
|
||||
// .request({
|
||||
// method: method,
|
||||
// params,
|
||||
// })
|
||||
// .then((result) => {
|
||||
// console.log("Got result: ", result);
|
||||
// if (result !== undefined && result !== null) {
|
||||
// userdata.eth_info.balance = result;
|
||||
// userdata.eth_info.parsed_balance = result / 1000000000000000000;
|
||||
// console.log("INFO: ", userdata);
|
||||
// setUserData(userdata);
|
||||
// } else {
|
||||
// toast("Couldn't find balance: ", result);
|
||||
// }
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// // If the request fails, the Promise will reject with an error.
|
||||
// toast("Failed getting info from ethereum API: " + error);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
// This should "always" have data
|
||||
useEffect(() => {
|
||||
if (firstrequest) {
|
||||
|
||||
@@ -1336,16 +1336,21 @@ const Workflows = (props) => {
|
||||
};
|
||||
|
||||
const exportAllWorkflows = (allWorkflows) => {
|
||||
for (var i = 0; i < allWorkflows.length; i++) {
|
||||
console.log(allWorkflows[i])
|
||||
setTimeout(() => {
|
||||
console.log(allWorkflows[i])
|
||||
exportWorkflow(allWorkflows[i], false)
|
||||
}, i * 200);
|
||||
}
|
||||
for (var i = 0; i < allWorkflows.length; i++) {
|
||||
const wf = allWorkflows[i]
|
||||
|
||||
toast(`Exporting and keeping original for all ${allWorkflows.length} workflows`);
|
||||
};
|
||||
if (wf === undefined || wf.id === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
console.log("Exporting workflow: ", wf)
|
||||
setTimeout(() => {
|
||||
exportWorkflow(JSON.parse(JSON.stringify(wf)), false)
|
||||
}, i * 100);
|
||||
}
|
||||
|
||||
toast(`Exporting and keeping original for all ${allWorkflows.length} workflows`);
|
||||
}
|
||||
|
||||
const deduplicateIds = (data, skip_sanitize) => {
|
||||
if (data.triggers !== null && data.triggers !== undefined) {
|
||||
@@ -1498,7 +1503,12 @@ const Workflows = (props) => {
|
||||
};
|
||||
|
||||
const exportWorkflow = (data, sanitize) => {
|
||||
data = JSON.parse(JSON.stringify(data));
|
||||
try {
|
||||
data = JSON.parse(JSON.stringify(data));
|
||||
} catch (e) {
|
||||
console.log("Failed to parse JSON: ", e);
|
||||
}
|
||||
|
||||
let exportFileDefaultName = data.name + ".json";
|
||||
|
||||
if (sanitize === true) {
|
||||
@@ -2199,15 +2209,15 @@ const Workflows = (props) => {
|
||||
|
||||
// Can create and set workflows
|
||||
const setNewWorkflow = (
|
||||
name,
|
||||
description,
|
||||
tags,
|
||||
defaultReturnValue,
|
||||
editingWorkflow,
|
||||
redirect,
|
||||
currentUsecases,
|
||||
inputblogpost,
|
||||
inputstatus,
|
||||
name,
|
||||
description,
|
||||
tags,
|
||||
defaultReturnValue,
|
||||
editingWorkflow,
|
||||
redirect,
|
||||
currentUsecases,
|
||||
inputblogpost,
|
||||
inputstatus,
|
||||
) => {
|
||||
var method = "POST";
|
||||
var extraData = "";
|
||||
@@ -2292,7 +2302,7 @@ const Workflows = (props) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
setSubmitLoading(false)
|
||||
setSubmitLoading(false)
|
||||
setModalOpen(false);
|
||||
setSubmitLoading(false);
|
||||
});
|
||||
@@ -2859,55 +2869,55 @@ const Workflows = (props) => {
|
||||
<FormControl style={{flex: 1, marginLeft: 5, }}>
|
||||
<InputLabel htmlFor="grouped-select-usecase">Usecases</InputLabel>
|
||||
<Select
|
||||
defaultValue=""
|
||||
id="grouped-select"
|
||||
label="Matching Usecase"
|
||||
multiple
|
||||
value={selectedUsecases}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
onChange={(event) => {
|
||||
console.log("Changed: ", event)
|
||||
}}
|
||||
>
|
||||
defaultValue=""
|
||||
id="grouped-select"
|
||||
label="Matching Usecase"
|
||||
multiple
|
||||
value={selectedUsecases}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
onChange={(event) => {
|
||||
console.log("Changed: ", event)
|
||||
}}
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>None</em>
|
||||
</MenuItem>
|
||||
{usecases.map((usecase, index) => {
|
||||
//console.log(usecase)
|
||||
return (
|
||||
<span key={index}>
|
||||
<ListSubheader
|
||||
style={{
|
||||
color: usecase.color
|
||||
}}
|
||||
>
|
||||
{usecase.name}
|
||||
</ListSubheader>
|
||||
{usecase.list.map((subcase, subindex) => {
|
||||
//console.log(subcase)
|
||||
total_count += 1
|
||||
return (
|
||||
<MenuItem key={subindex} value={total_count} onClick={(event) => {
|
||||
if (selectedUsecases.includes(subcase.name)) {
|
||||
const itemIndex = selectedUsecases.indexOf(subcase.name)
|
||||
if (itemIndex > -1) {
|
||||
selectedUsecases.splice(itemIndex, 1)
|
||||
}
|
||||
} else {
|
||||
selectedUsecases.push(subcase.name)
|
||||
}
|
||||
{usecases.map((usecase, index) => {
|
||||
//console.log(usecase)
|
||||
return (
|
||||
<span key={index}>
|
||||
<ListSubheader
|
||||
style={{
|
||||
color: usecase.color
|
||||
}}
|
||||
>
|
||||
{usecase.name}
|
||||
</ListSubheader>
|
||||
{usecase.list.map((subcase, subindex) => {
|
||||
//console.log(subcase)
|
||||
total_count += 1
|
||||
return (
|
||||
<MenuItem key={subindex} value={total_count} onClick={(event) => {
|
||||
if (selectedUsecases.includes(subcase.name)) {
|
||||
const itemIndex = selectedUsecases.indexOf(subcase.name)
|
||||
if (itemIndex > -1) {
|
||||
selectedUsecases.splice(itemIndex, 1)
|
||||
}
|
||||
} else {
|
||||
selectedUsecases.push(subcase.name)
|
||||
}
|
||||
|
||||
setUpdate(Math.random());
|
||||
setSelectedUsecases(selectedUsecases)
|
||||
}}>
|
||||
<Checkbox style={{color: selectedUsecases.includes(subcase.name) ? usecase.color : theme.palette.inputColor}} checked={selectedUsecases.includes(subcase.name)} />
|
||||
<ListItemText primary={subcase.name} />
|
||||
</MenuItem>
|
||||
)
|
||||
})}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
setUpdate(Math.random());
|
||||
setSelectedUsecases(selectedUsecases)
|
||||
}}>
|
||||
<Checkbox style={{color: selectedUsecases.includes(subcase.name) ? usecase.color : theme.palette.inputColor}} checked={selectedUsecases.includes(subcase.name)} />
|
||||
<ListItemText primary={subcase.name} />
|
||||
</MenuItem>
|
||||
)
|
||||
})}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
: null}
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
github.com/mackerelio/go-osstat v0.2.3
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/shuffle/shuffle-shared v0.5.31
|
||||
github.com/shuffle/shuffle-shared v0.5.68
|
||||
k8s.io/api v0.28.1
|
||||
k8s.io/apimachinery v0.28.1
|
||||
k8s.io/client-go v0.28.1
|
||||
|
||||
@@ -280,8 +280,6 @@ github.com/shuffle/shuffle-shared v0.4.96 h1:iaIB/HP9eKpw9DMMJZhSLDbKdHJt075kFYL
|
||||
github.com/shuffle/shuffle-shared v0.4.96/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.29 h1:n4vThl7v3mFVXbrIW71XREFdmZZo7mOBAWxnsdiNjDk=
|
||||
github.com/shuffle/shuffle-shared v0.5.29/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.31 h1:OV4IIfKWWFW66WjGvyXOmmsSz3p8pW9L1ge1mDo8ftM=
|
||||
github.com/shuffle/shuffle-shared v0.5.31/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
||||
@@ -396,16 +396,16 @@ func deployServiceWorkers(image string) {
|
||||
}
|
||||
|
||||
innerContainerName := fmt.Sprintf("shuffle-workers")
|
||||
cnt, _ := findActiveSwarmNodes()
|
||||
cnt, err := findActiveSwarmNodes()
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Failed to find active swarm nodes: %s. Defaulting to 1", err)
|
||||
}
|
||||
|
||||
nodeCount := uint64(1)
|
||||
if cnt > 0 {
|
||||
nodeCount = uint64(cnt)
|
||||
}
|
||||
|
||||
if cnt == 0 {
|
||||
cnt = 1
|
||||
}
|
||||
|
||||
appReplicas := os.Getenv("SHUFFLE_APP_REPLICAS")
|
||||
appReplicaCnt := 1
|
||||
if len(appReplicas) > 0 {
|
||||
@@ -477,6 +477,8 @@ func deployServiceWorkers(image string) {
|
||||
fmt.Sprintf("SHUFFLE_LOGS_DISABLED=%s", os.Getenv("SHUFFLE_LOGS_DISABLED")),
|
||||
fmt.Sprintf("DEBUG_MEMORY=%s", os.Getenv("DEBUG_MEMORY")),
|
||||
fmt.Sprintf("SHUFFLE_APP_SDK_TIMEOUT=%s", os.Getenv("SHUFFLE_APP_SDK_TIMEOUT")),
|
||||
fmt.Sprintf("SHUFFLE_MAX_SWARM_NODES=%d", os.Getenv("SHUFFLE_MAX_SWARM_NODES")),
|
||||
fmt.Sprintf("SHUFFLE_BASE_IMAGE_NAME=%s", baseImageName),
|
||||
},
|
||||
//Hosts: []string{
|
||||
// innerContainerName,
|
||||
@@ -533,6 +535,10 @@ func deployServiceWorkers(image string) {
|
||||
serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("SHUFFLE_CLOUDRUN_URL=%s", os.Getenv("SHUFFLE_CLOUDRUN_URL")))
|
||||
}
|
||||
|
||||
if len(os.Getenv("SHUFFLE_AUTO_IMAGE_DOWNLOAD")) > 0 {
|
||||
serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("SHUFFLE_AUTO_IMAGE_DOWNLOAD=%s", os.Getenv("SHUFFLE_AUTO_IMAGE_DOWNLOAD")))
|
||||
}
|
||||
|
||||
if len(os.Getenv("DOCKER_HOST")) > 0 {
|
||||
serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("DOCKER_HOST=%s", os.Getenv("DOCKER_HOST")))
|
||||
} else {
|
||||
@@ -580,6 +586,8 @@ func deployServiceWorkers(image string) {
|
||||
serviceOptions,
|
||||
)
|
||||
|
||||
//dockercli.ServiceUpdate(
|
||||
|
||||
if err == nil {
|
||||
log.Printf("[DEBUG] Successfully deployed workers with %d replica(s) on %d node(s)", replicas, cnt)
|
||||
//time.Sleep(time.Duration(10) * time.Second)
|
||||
@@ -608,14 +616,14 @@ func deployServiceWorkers(image string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Deploys the internal worker whenever something happens
|
||||
// Deploys the worker with the current available environments
|
||||
// https://docs.docker.com/engine/api/sdk/examples/
|
||||
|
||||
func buildEnvVars(envMap map[string]string) []corev1.EnvVar {
|
||||
var envVars []corev1.EnvVar
|
||||
for key, value := range envMap {
|
||||
envVars = append(envVars, corev1.EnvVar{Name: key, Value: value})
|
||||
}
|
||||
|
||||
return envVars
|
||||
}
|
||||
|
||||
@@ -667,13 +675,18 @@ func deployWorker(image string, identifier string, env []string, executionReques
|
||||
},
|
||||
}
|
||||
|
||||
// Add environment variables
|
||||
// pod.Spec.Containers[0].Env = buildEnvVars(envMap)
|
||||
|
||||
createdPod, err := clientset.CoreV1().Pods("shuffle").Create(context.Background(), pod, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error creating pod: %v\n", err)
|
||||
log.Printf("[ERROR] Failed creating pod: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Created pod %q in namespace %q\n", createdPod.Name, createdPod.Namespace)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Binds is the actual "-v" volume.
|
||||
// Max 20% CPU every second
|
||||
@@ -717,26 +730,6 @@ func deployWorker(image string, identifier string, env []string, executionReques
|
||||
// In certain cases, a workflow may e.g. be aborted already. If it's aborted, that returns
|
||||
// a 401 from the worker, which returns an error here
|
||||
go sendWorkerRequest(executionRequest)
|
||||
//sendWorkerRequest(executionRequest)
|
||||
|
||||
//err := sendWorkerRequest(executionRequest)
|
||||
//if err != nil {
|
||||
// log.Printf("[ERROR] Failed worker request for %s: %s", executionRequest.ExecutionId, err)
|
||||
|
||||
// if strings.Contains(fmt.Sprintf("%s", err), "connection refused") || strings.Contains(fmt.Sprintf("%s", err), "EOF") {
|
||||
// workerImage := fmt.Sprintf("%s/%s/shuffle-worker:%s", baseimageregistry, baseimagename, workerVersion)
|
||||
// deployServiceWorkers(workerImage)
|
||||
|
||||
// time.Sleep(time.Duration(10) * time.Second)
|
||||
// err = sendWorkerRequest(executionRequest)
|
||||
// }
|
||||
//}
|
||||
|
||||
//if err == nil {
|
||||
// // FIXME: Readd this? Removed for rerun reasons
|
||||
// // executionIds = append(executionIds, executionRequest.ExecutionId)
|
||||
//}
|
||||
//}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -833,9 +826,6 @@ func deployWorker(image string, identifier string, env []string, executionReques
|
||||
log.Printf("[INFO][%s] New Worker created. Environment %s: docker logs %s", executionRequest.ExecutionId, environment, cont.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -922,7 +912,7 @@ func findActiveSwarmNodes() (int64, error) {
|
||||
ctx := context.Background()
|
||||
nodes, err := dockercli.NodeList(ctx, types.NodeListOptions{})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return 1, err
|
||||
}
|
||||
|
||||
nodeCount := int64(0)
|
||||
@@ -933,13 +923,21 @@ func findActiveSwarmNodes() (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return nodeCount, nil
|
||||
// Check for SHUFFLE_MAX_NODES
|
||||
// Make it into a number and check if it's lower than nodeCount
|
||||
maxNodesString := os.Getenv("SHUFFLE_MAX_SWARM_NODES")
|
||||
if len(maxNodesString) > 0 {
|
||||
maxNodes, err := strconv.ParseInt(maxNodesString, 10, 64)
|
||||
if err != nil {
|
||||
return nodeCount, err
|
||||
}
|
||||
|
||||
/*
|
||||
containers, err := dockercli.ContainerList(ctx, types.ContainerListOptions{
|
||||
All: true,
|
||||
})
|
||||
*/
|
||||
if nodeCount > maxNodes {
|
||||
nodeCount = maxNodes
|
||||
}
|
||||
}
|
||||
|
||||
return nodeCount, nil
|
||||
}
|
||||
|
||||
// Get IP
|
||||
@@ -1033,6 +1031,16 @@ func getOrborusStats(ctx context.Context) shuffle.OrborusStats {
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
// FIXME: Returning for now due to this causing network congestion
|
||||
// and database fillup. The backend api also has it disabled.
|
||||
return newStats
|
||||
|
||||
// Disable orborus stats
|
||||
if os.Getenv("SHUFFLE_STATS_DISABLED") == "true" {
|
||||
return newStats
|
||||
}
|
||||
|
||||
|
||||
if swarmConfig == "run" || swarmConfig == "swarm" {
|
||||
newStats.Swarm = true
|
||||
}
|
||||
@@ -1562,6 +1570,7 @@ func main() {
|
||||
fmt.Sprintf("SHUFFLE_PASS_APP_PROXY=%s", os.Getenv("SHUFFLE_PASS_APP_PROXY")),
|
||||
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
|
||||
fmt.Sprintf("SHUFFLE_LOGS_DISABLED=%s", os.Getenv("SHUFFLE_LOGS_DISABLED")),
|
||||
fmt.Sprintf("SHUFFLE_BASE_IMAGE_NAME=%s", baseimagename),
|
||||
}
|
||||
|
||||
//log.Printf("Running worker with proxy? %s", os.Getenv("SHUFFLE_PASS_WORKER_PROXY"))
|
||||
@@ -1611,12 +1620,16 @@ func main() {
|
||||
overrideHttpsProxy := os.Getenv("SHUFFLE_INTERNAL_HTTPS_PROXY")
|
||||
if len(overrideHttpProxy) > 0 {
|
||||
log.Printf("[DEBUG] Added internal proxy: %s", overrideHttpProxy)
|
||||
env = append(env, fmt.Sprintf("HTTP_PROXY=%s", overrideHttpProxy))
|
||||
env = append(env, fmt.Sprintf("SHUFFLE_INTERNAL_HTTP_PROXY=%s", overrideHttpProxy))
|
||||
}
|
||||
|
||||
if len(overrideHttpsProxy) > 0 {
|
||||
log.Printf("[DEBUG] Added internal proxy: %s", overrideHttpsProxy)
|
||||
env = append(env, fmt.Sprintf("HTTPS_PROXY=%s", overrideHttpsProxy))
|
||||
env = append(env, fmt.Sprintf("SHUFFLE_INTERNAL_HTTPS_PROXY=%s", overrideHttpsProxy))
|
||||
}
|
||||
|
||||
if len(os.Getenv("SHUFFLE_MAX_SWARM_NODES")) > 0 {
|
||||
env = append(env, fmt.Sprintf("SHUFFLE_MAX_SWARM_NODES=%s", os.Getenv("SHUFFLE_MAX_SWARM_NODES")))
|
||||
}
|
||||
|
||||
err = deployWorker(workerImage, containerName, env, execution)
|
||||
|
||||
@@ -5,13 +5,10 @@ go 1.19
|
||||
//replace github.com/shuffle/shuffle-shared => ../../../../shuffle-shared
|
||||
|
||||
require (
|
||||
cloud.google.com/go/datastore v1.10.0
|
||||
cloud.google.com/go/storage v1.29.0
|
||||
github.com/docker/docker v23.0.3+incompatible
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shuffle/shuffle-shared v0.5.31
|
||||
github.com/shuffle/shuffle-shared v0.5.68
|
||||
k8s.io/api v0.28.3
|
||||
k8s.io/apimachinery v0.28.3
|
||||
k8s.io/client-go v0.28.3
|
||||
@@ -21,21 +18,30 @@ require (
|
||||
cloud.google.com/go v0.107.0 // indirect
|
||||
cloud.google.com/go/compute v1.14.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/datastore v1.10.0 // indirect
|
||||
cloud.google.com/go/iam v0.8.0 // indirect
|
||||
cloud.google.com/go/storage v1.29.0 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
||||
github.com/adrg/strutil v0.2.3 // indirect
|
||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20221031212613-62deef7fc822 // indirect
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||
github.com/frikky/go-elasticsearch/v8 v8.13.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/frikky/kin-openapi v0.41.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.11.0 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
@@ -44,7 +50,7 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-github/v28 v28.1.1 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
@@ -52,8 +58,10 @@ require (
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.1 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||
github.com/imdario/mergo v0.3.6 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -64,20 +72,25 @@ require (
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opensearch-project/opensearch-go v1.1.0 // indirect
|
||||
github.com/opensearch-project/opensearch-go/v2 v2.3.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.8.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.106.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
@@ -85,6 +98,7 @@ require (
|
||||
google.golang.org/grpc v1.51.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gotest.tools/v3 v3.4.0 // indirect
|
||||
|
||||
+229
-59
@@ -48,18 +48,29 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
cloud.google.com/go/storage v1.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho=
|
||||
cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
|
||||
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/adrg/strutil v0.2.3 h1:WZVn3ItPBovFmP4wMHHVXUr8luRaHrbyIuLlHt32GZQ=
|
||||
github.com/adrg/strutil v0.2.3/go.mod h1:+SNxbiH6t+O+5SZqIj5n/9i5yUjR+S3XXVrjEcN2mxg=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1 h1:FP2Xtqqs/sefR5Qluygp+jVV+juXzEdJaPrZTCDLhDQ=
|
||||
github.com/algolia/algoliasearch-client-go/v3 v3.18.1/go.mod h1:i7tLoP7TYDmHX3Q7vkIOL4syVse/k5VJ+k0i8WqFiJk=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
|
||||
github.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
@@ -78,17 +89,20 @@ github.com/bradfitz/gomemcache v0.0.0-20221031212613-62deef7fc822 h1:hjXJeBcAMS1
|
||||
github.com/bradfitz/gomemcache v0.0.0-20221031212613-62deef7fc822/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -100,42 +114,61 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/frikky/go-elasticsearch/v8 v8.13.1 h1:GB+Wr0Yx8efG7D1jc9fGGiqjjRRngWJTcMSua3QIDaM=
|
||||
github.com/frikky/go-elasticsearch/v8 v8.13.1/go.mod h1:RPq0JXPQVVSFHTlPwj/go8BZ1hegRf+StaSpT2iGIoQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/frikky/kin-openapi v0.41.0 h1:oMmjo+ekGS971lb3KLeZZOqRDZOwWi3+g/OiSWP08+s=
|
||||
github.com/frikky/kin-openapi v0.41.0/go.mod h1:ev9OZAw7Bv5p0w93j91++6a1ElPzGcCofst+kmrWsj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -161,7 +194,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
@@ -181,8 +213,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
@@ -195,7 +228,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
@@ -206,8 +238,10 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -221,10 +255,14 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -233,21 +271,27 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/libgit2/git2go/v34 v34.0.0/go.mod h1:blVco2jDAw6YTXkErMMqzHLcAjKkwF0aWIRHBqiJkZ0=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -259,6 +303,46 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
|
||||
github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
|
||||
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
|
||||
github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
|
||||
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
|
||||
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||
github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
|
||||
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
||||
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||
@@ -269,45 +353,53 @@ github.com/opensearch-project/opensearch-go/v2 v2.3.0 h1:nQIEMr+A92CkhHrZgUhcfsr
|
||||
github.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shuffle/shuffle-shared v0.4.17 h1:56ll366bdmIJu/7GFqNC2XTjjl0SGBf430PSq+EB6Ro=
|
||||
github.com/shuffle/shuffle-shared v0.4.17/go.mod h1:jQrYySmvp/0De5ftrAaY6xwwr7TMfqBmBxQ2AX9yrjQ=
|
||||
github.com/shuffle/shuffle-shared v0.4.50 h1:fJLfhWIJ5mYap4JwHnD/B5aaLyIULwylFSl3FoWlajM=
|
||||
github.com/shuffle/shuffle-shared v0.4.50/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.4.57 h1:o+mMPRY4ourkE3R0qdi80jg6RlCtvAJ/VVrPk4y75Hk=
|
||||
github.com/shuffle/shuffle-shared v0.4.57/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.29 h1:n4vThl7v3mFVXbrIW71XREFdmZZo7mOBAWxnsdiNjDk=
|
||||
github.com/shuffle/shuffle-shared v0.5.29/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/shuffle/shuffle-shared v0.5.31 h1:OV4IIfKWWFW66WjGvyXOmmsSz3p8pW9L1ge1mDo8ftM=
|
||||
github.com/shuffle/shuffle-shared v0.5.31/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
@@ -319,17 +411,25 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8=
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -363,13 +463,18 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -390,6 +495,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
@@ -400,15 +506,26 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -418,8 +535,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210113160501-8b1d76fa0423/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -431,9 +546,16 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -441,7 +563,11 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -462,23 +588,49 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -488,15 +640,17 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -512,6 +666,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@@ -547,15 +702,21 @@ golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4X
|
||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -662,23 +823,31 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||
@@ -703,6 +872,7 @@ k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4Va
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
|
||||
Executable → Regular
+97
-28
@@ -52,7 +52,8 @@ var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP"))
|
||||
var swarmNetworkName = os.Getenv("SHUFFLE_SWARM_NETWORK_NAME")
|
||||
var dockerApiVersion = strings.ToLower(os.Getenv("DOCKER_API_VERSION"))
|
||||
|
||||
var baseimagename = "frikky/shuffle"
|
||||
//var baseimagename = "frikky/shuffle"
|
||||
var baseimagename = os.Getenv("SHUFFLE_BASE_IMAGE_NAME")
|
||||
|
||||
// var baseimagename = "registry.hub.docker.com/frikky/shuffle"
|
||||
var registryName = "registry.hub.docker.com"
|
||||
@@ -120,7 +121,7 @@ func setWorkflowExecution(ctx context.Context, workflowExecution shuffle.Workflo
|
||||
}
|
||||
|
||||
//log.Printf("[DEBUG][%s] Setting with %d results (pre)", workflowExecution.ExecutionId, len(workflowExecution.Results))
|
||||
workflowExecution = shuffle.Fixexecution(ctx, workflowExecution)
|
||||
workflowExecution, _ = shuffle.Fixexecution(ctx, workflowExecution)
|
||||
cacheKey := fmt.Sprintf("workflowexecution_%s", workflowExecution.ExecutionId)
|
||||
|
||||
execData, err := json.Marshal(workflowExecution)
|
||||
@@ -354,7 +355,8 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
//log.Printf("[DEBUG][%s] All App Logs: %#v", workflowExecution.ExecutionId, allLogs)
|
||||
newresp, err := topClient.Do(req)
|
||||
client := shuffle.GetExternalClient(abortUrl)
|
||||
newresp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING][%s] Failed abort request: %s", workflowExecution.ExecutionId, err)
|
||||
} else {
|
||||
@@ -464,6 +466,9 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
|
||||
// Check action if subflow
|
||||
// Check if url is default (shuffle-backend)
|
||||
// If it doesn't exist, add it
|
||||
|
||||
// FIXME: This does NOT replace it in all cases as the data
|
||||
// is not saved in the database as the correct param.
|
||||
if action.AppName == "shuffle-subflow" {
|
||||
// Automatic replacement of URL
|
||||
for paramIndex, param := range action.Parameters {
|
||||
@@ -471,17 +476,19 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(param.Value, "shuffle-backend") {
|
||||
// Automatic replacement as this is default
|
||||
if len(os.Getenv("BASE_URL")) > 0 {
|
||||
action.Parameters[paramIndex].Value = os.Getenv("BASE_URL")
|
||||
log.Printf("[DEBUG][%s] Replaced backend_url with base_url %s", workflowExecution.ExecutionId, os.Getenv("BASE_URL"))
|
||||
}
|
||||
if !strings.Contains(param.Value, "shuffle-backend") {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(os.Getenv("SHUFFLE_CLOUDRUN_URL")) > 0 {
|
||||
action.Parameters[paramIndex].Value = os.Getenv("SHUFFLE_CLOUDRUN_URL")
|
||||
log.Printf("[DEBUG][%s] Replaced backend_url with cloudrun %s", workflowExecution.ExecutionId, os.Getenv("SHUFFLE_CLOUDRUN_URL"))
|
||||
}
|
||||
// Automatic replacement as this is default
|
||||
if len(os.Getenv("BASE_URL")) > 0 {
|
||||
action.Parameters[paramIndex].Value = os.Getenv("BASE_URL")
|
||||
log.Printf("[DEBUG][%s] Replaced backend_url with base_url %s", workflowExecution.ExecutionId, os.Getenv("BASE_URL"))
|
||||
}
|
||||
|
||||
if len(os.Getenv("SHUFFLE_CLOUDRUN_URL")) > 0 {
|
||||
action.Parameters[paramIndex].Value = os.Getenv("SHUFFLE_CLOUDRUN_URL")
|
||||
log.Printf("[DEBUG][%s] Replaced backend_url with cloudrun %s", workflowExecution.ExecutionId, os.Getenv("SHUFFLE_CLOUDRUN_URL"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,6 +752,8 @@ func removeContainer(containername string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
defer cli.Close()
|
||||
|
||||
// FIXME - ucnomment
|
||||
// containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
|
||||
// All: true,
|
||||
@@ -800,6 +809,8 @@ func getWorkerURLs() ([]string, error) {
|
||||
return workerUrls, err
|
||||
}
|
||||
|
||||
defer cli.Close()
|
||||
|
||||
// Specify the name of the service for which you want to list tasks
|
||||
serviceName := "shuffle-workers"
|
||||
|
||||
@@ -827,12 +838,19 @@ func askOtherWorkersToDownloadImage(image string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check environment SHUFFLE_AUTO_IMAGE_DOWNLOAD
|
||||
if os.Getenv("SHUFFLE_AUTO_IMAGE_DOWNLOAD") == "false" {
|
||||
log.Printf("[DEBUG] SHUFFLE_AUTO_IMAGE_DOWNLOAD is false. NOT distributing images %s", image)
|
||||
return
|
||||
}
|
||||
|
||||
urls, err := getWorkerURLs()
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Error in listing worker urls: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
httpClient := &http.Client{}
|
||||
for _, url := range urls {
|
||||
log.Printf("[DEBUG] Trying to speak to: %s", url)
|
||||
imagesRequest := ImageRequest{
|
||||
@@ -855,7 +873,6 @@ func askOtherWorkersToDownloadImage(image string) {
|
||||
continue
|
||||
}
|
||||
|
||||
httpClient := &http.Client{}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Error in making request to %s : %s", url, err)
|
||||
@@ -892,6 +909,8 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
|
||||
return
|
||||
}
|
||||
|
||||
defer dockercli.Close()
|
||||
|
||||
for _, action := range relevantActions {
|
||||
appname := action.AppName
|
||||
appversion := action.AppVersion
|
||||
@@ -1116,6 +1135,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
|
||||
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
|
||||
return
|
||||
} else {
|
||||
defer reader.Close()
|
||||
baseTag := strings.Split(image, ":")
|
||||
if len(baseTag) > 1 {
|
||||
tag := baseTag[1]
|
||||
@@ -1226,6 +1246,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) {
|
||||
shutdown(workflowExecution, action.ID, fmt.Sprintf("%s", err.Error()), true)
|
||||
return
|
||||
} else {
|
||||
defer reader.Close()
|
||||
baseTag := strings.Split(image, ":")
|
||||
if len(baseTag) > 1 {
|
||||
tag := baseTag[1]
|
||||
@@ -1481,6 +1502,8 @@ func executionInit(workflowExecution shuffle.WorkflowExecution) error {
|
||||
}
|
||||
|
||||
func handleSubflowPoller(ctx context.Context, workflowExecution shuffle.WorkflowExecution, streamResultUrl, subflowId string) error {
|
||||
// FIXME: If MEMCACHE is enabled, check in this order:
|
||||
|
||||
extra := 0
|
||||
for _, trigger := range workflowExecution.Workflow.Triggers {
|
||||
if trigger.AppName == "User Input" || trigger.AppName == "Shuffle Workflow" {
|
||||
@@ -1494,7 +1517,8 @@ func handleSubflowPoller(ctx context.Context, workflowExecution shuffle.Workflow
|
||||
bytes.NewBuffer([]byte(data)),
|
||||
)
|
||||
|
||||
newresp, err := topClient.Do(req)
|
||||
client := shuffle.GetExternalClient(streamResultUrl)
|
||||
newresp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Failed making request (1): %s", err)
|
||||
time.Sleep(time.Duration(sleepTime) * time.Second)
|
||||
@@ -2043,7 +2067,8 @@ func runWorkflowExecutionTransaction(ctx context.Context, attempts int64, workfl
|
||||
}
|
||||
|
||||
if setExecution || workflowExecution.Status == "FINISHED" || workflowExecution.Status == "ABORTED" || workflowExecution.Status == "FAILURE" {
|
||||
log.Printf("[DEBUG][%s] Running setexec with status %s and %d result(s)", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Results))
|
||||
log.Printf("[DEBUG][%s] Running setexec with status %s and %d/%d results", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Results), len(workflowExecution.Workflow.Actions))
|
||||
//result(s)", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Results))
|
||||
err = setWorkflowExecution(ctx, *workflowExecution, dbSave)
|
||||
if err != nil {
|
||||
resp.WriteHeader(401)
|
||||
@@ -2101,7 +2126,8 @@ func sendSelfRequest(actionResult shuffle.ActionResult) {
|
||||
return
|
||||
}
|
||||
|
||||
newresp, err := topClient.Do(req)
|
||||
client := shuffle.GetExternalClient(streamUrl)
|
||||
newresp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR][%s] Error running finishing request (2): %s", actionResult.ExecutionId, err)
|
||||
return
|
||||
@@ -2158,9 +2184,10 @@ func sendResult(workflowExecution shuffle.WorkflowExecution, data []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
newresp, err := topClient.Do(req)
|
||||
client := shuffle.GetExternalClient(streamUrl)
|
||||
newresp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR][%s] Error running finishing request: %s", workflowExecution.ExecutionId, err)
|
||||
log.Printf("[ERROR][%s] Error running finishing request (1): %s", workflowExecution.ExecutionId, err)
|
||||
log.Printf("[DEBUG][%s] Shutting down (23)", workflowExecution.ExecutionId)
|
||||
shutdown(workflowExecution, "", "", false)
|
||||
return
|
||||
@@ -2189,7 +2216,7 @@ func validateFinished(workflowExecution shuffle.WorkflowExecution) bool {
|
||||
}
|
||||
|
||||
//startAction, extra, children, parents, visited, executed, nextActions, environments := shuffle.GetExecutionVariables(ctx, workflowExecution.ExecutionId)
|
||||
workflowExecution = shuffle.Fixexecution(ctx, workflowExecution)
|
||||
workflowExecution, _ = shuffle.Fixexecution(ctx, workflowExecution)
|
||||
_, extra, _, _, _, _, _, environments := shuffle.GetExecutionVariables(ctx, workflowExecution.ExecutionId)
|
||||
|
||||
log.Printf("[INFO][%s] VALIDATION. Status: %s, shuffle.Actions: %d, Extra: %d, Results: %d. Parent: %#v", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Workflow.Actions), extra, len(workflowExecution.Results), workflowExecution.ExecutionParent)
|
||||
@@ -2337,6 +2364,8 @@ func webserverSetup(workflowExecution shuffle.WorkflowExecution) net.Listener {
|
||||
|
||||
|
||||
port := listener.Addr().(*net.TCPAddr).Port
|
||||
// Set the port environment variable
|
||||
os.Setenv("WORKER_PORT", fmt.Sprintf("%d", port))
|
||||
|
||||
log.Printf("[DEBUG] Starting webserver (2) on port %d with hostname: %s", port, hostname)
|
||||
appCallbackUrl = fmt.Sprintf("http://%s:%d", hostname, port)
|
||||
@@ -2348,6 +2377,12 @@ func webserverSetup(workflowExecution shuffle.WorkflowExecution) net.Listener {
|
||||
func downloadDockerImageBackend(client *http.Client, imageName string) error {
|
||||
log.Printf("[DEBUG] Trying to download image %s from backend %s as it doesn't exist. All images: %#v", imageName, baseUrl, downloadedImages)
|
||||
|
||||
// Check environment SHUFFLE_AUTO_IMAGE_DOWNLOAD
|
||||
if os.Getenv("SHUFFLE_AUTO_IMAGE_DOWNLOAD") == "false" {
|
||||
log.Printf("[DEBUG] SHUFFLE_AUTO_IMAGE_DOWNLOAD is false. Not downloading image %s", imageName)
|
||||
return nil
|
||||
}
|
||||
|
||||
if arrayContains(downloadedImages, imageName) {
|
||||
log.Printf("[DEBUG] Image %s already downloaded", imageName)
|
||||
return nil
|
||||
@@ -2407,12 +2442,15 @@ func downloadDockerImageBackend(client *http.Client, imageName string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
defer dockercli.Close()
|
||||
|
||||
imageLoadResponse, err := dockercli.ImageLoad(context.Background(), tar, true)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Error loading images: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer imageLoadResponse.Body.Close()
|
||||
body, err := ioutil.ReadAll(imageLoadResponse.Body)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Error reading: %s", err)
|
||||
@@ -2448,7 +2486,7 @@ func findActiveSwarmNodes(dockercli *dockerclient.Client) (int64, error) {
|
||||
ctx := context.Background()
|
||||
nodes, err := dockercli.NodeList(ctx, types.NodeListOptions{})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return 1, err
|
||||
}
|
||||
|
||||
nodeCount := int64(0)
|
||||
@@ -2459,6 +2497,20 @@ func findActiveSwarmNodes(dockercli *dockerclient.Client) (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for SHUFFLE_MAX_NODES
|
||||
maxNodesString := os.Getenv("SHUFFLE_MAX_SWARM_NODES")
|
||||
// Make it into a number and check if it's lower than nodeCount
|
||||
if len(maxNodesString) > 0 {
|
||||
maxNodes, err := strconv.ParseInt(maxNodesString, 10, 64)
|
||||
if err != nil {
|
||||
return nodeCount, err
|
||||
}
|
||||
|
||||
if nodeCount > maxNodes {
|
||||
nodeCount = maxNodes
|
||||
}
|
||||
}
|
||||
|
||||
return nodeCount, nil
|
||||
|
||||
/*
|
||||
@@ -2570,9 +2622,11 @@ func sendAppRequest(ctx context.Context, incomingUrl, appName string, port int,
|
||||
log.Printf("[DEBUG][%s] Adding %s to cache (%#v)", workflowExecution.ExecutionId, newExecId, action.Name)
|
||||
}
|
||||
|
||||
// FIXME: Add 5 tries
|
||||
client := shuffle.GetExternalClient(streamUrl)
|
||||
|
||||
newresp, err := topClient.Do(req)
|
||||
// Set client timeout to 5 seconds
|
||||
//client.Timeout = time.Duration(10) * time.Second
|
||||
newresp, err := client.Do(req)
|
||||
if err != nil {
|
||||
// Another timeout issue here somewhere
|
||||
// context deadline
|
||||
@@ -2630,6 +2684,8 @@ func baseDeploy() {
|
||||
return
|
||||
}
|
||||
|
||||
defer cli.Close()
|
||||
|
||||
for key, value := range autoDeploy {
|
||||
newNameSplit := strings.Split(key, ":")
|
||||
|
||||
@@ -2771,6 +2827,7 @@ func getStreamResultsWrapper(client *http.Client, req *http.Request, workflowExe
|
||||
log.Printf("[DEBUG] Environments: %s. Source: %s. 1 env = webserver, 0 or >1 = default. Subflow exists: %#v", environments, workflowExecution.ExecutionSource, subflowFound)
|
||||
if len(environments) == 1 && workflowExecution.ExecutionSource != "default" && !subflowFound {
|
||||
log.Printf("[DEBUG] Running OPTIMIZED execution (not manual)")
|
||||
os.Setenv("SHUFFLE_OPTIMIZED", "true")
|
||||
listener := webserverSetup(workflowExecution)
|
||||
err := executionInit(workflowExecution)
|
||||
if err != nil {
|
||||
@@ -2784,7 +2841,13 @@ func getStreamResultsWrapper(client *http.Client, req *http.Request, workflowExe
|
||||
handleExecutionResult(workflowExecution)
|
||||
}()
|
||||
|
||||
log.Printf("[DEBUG] Running with port %#v", os.Getenv("WORKER_PORT"))
|
||||
|
||||
runWebserver(listener)
|
||||
|
||||
// Set environment variable
|
||||
|
||||
|
||||
//log.Printf("Before wait")
|
||||
//wg := sync.WaitGroup{}
|
||||
//wg.Add(1)
|
||||
@@ -2846,6 +2909,12 @@ func main() {
|
||||
timezone = "Europe/Amsterdam"
|
||||
}
|
||||
|
||||
if baseimagename == "" {
|
||||
log.Printf("[DEBUG] Setting baseimagename")
|
||||
baseimagename = "frikky/shuffle" // Dockerhub
|
||||
//baseimagename = "shuffle" // Github (ghcr.io)
|
||||
}
|
||||
|
||||
topClient = client
|
||||
swarmConfig := os.Getenv("SHUFFLE_SWARM_CONFIG")
|
||||
log.Printf("[INFO] Running with timezone %s and swarm config %#v", timezone, swarmConfig)
|
||||
@@ -2897,7 +2966,6 @@ func main() {
|
||||
shutdown(workflowExecution, "", "", true)
|
||||
}
|
||||
|
||||
topClient = client
|
||||
firstRequest := true
|
||||
environments := []string{}
|
||||
for {
|
||||
@@ -3007,15 +3075,14 @@ func handleRunExecution(resp http.ResponseWriter, request *http.Request) {
|
||||
var workflowExecution shuffle.WorkflowExecution
|
||||
data = fmt.Sprintf(`{"execution_id": "%s", "authorization": "%s"}`, execRequest.ExecutionId, execRequest.Authorization)
|
||||
streamResultUrl := fmt.Sprintf("%s/api/v1/streams/results", baseUrl)
|
||||
topClient = shuffle.GetExternalClient(streamResultUrl)
|
||||
|
||||
req, err := http.NewRequest(
|
||||
"POST",
|
||||
streamResultUrl,
|
||||
bytes.NewBuffer([]byte(data)),
|
||||
)
|
||||
|
||||
newresp, err := topClient.Do(req)
|
||||
client := shuffle.GetExternalClient(streamResultUrl)
|
||||
newresp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Failed making request (2): %s", err)
|
||||
resp.WriteHeader(401)
|
||||
@@ -3145,6 +3212,8 @@ func handleDownloadImage(resp http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
defer client.Close()
|
||||
|
||||
// check if images are already downloaded
|
||||
// Retrieve a list of Docker images
|
||||
images, err := client.ImageList(context.Background(), types.ImageListOptions{})
|
||||
@@ -3155,6 +3224,7 @@ func handleDownloadImage(resp http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
for _, img := range images {
|
||||
for _, tag := range img.RepoTags {
|
||||
splitTag := strings.Split(tag, ":")
|
||||
@@ -3225,5 +3295,4 @@ func runWebserver(listener net.Listener) {
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Serve issue in worker: %#v", err)
|
||||
}
|
||||
log.Printf("[DEBUG] Do we see this?")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user