Added further admin panel fixes
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import os
|
||||
import ast
|
||||
import copy
|
||||
import sys
|
||||
import re
|
||||
import copy
|
||||
import time
|
||||
import base64
|
||||
import json
|
||||
import random
|
||||
import liquid
|
||||
import logging
|
||||
import urllib3
|
||||
@@ -504,10 +505,12 @@ class AppBase:
|
||||
except Exception as e:
|
||||
print(f"[WARNING] Failed adding parameter for logs: {e}")
|
||||
|
||||
# FIXME: Adding retries here.
|
||||
try:
|
||||
finished = False
|
||||
for i in range (0, 10):
|
||||
# Random sleeptime between 0 and 1 second, with 0.1 increments
|
||||
sleeptime = float(random.randint(0, 10) / 10)
|
||||
|
||||
try:
|
||||
ret = requests.post(url, headers=headers, json=action_result, timeout=10, verify=False)
|
||||
|
||||
@@ -516,29 +519,29 @@ class AppBase:
|
||||
finished = True
|
||||
break
|
||||
else:
|
||||
self.logger.info(f"[ERROR] RESP: {ret.text}")
|
||||
self.logger.info(f"[ERROR] Bad resp {ret.status_code}: {ret.text}")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.logger.info(f"[DEBUG] Request problem: {e}")
|
||||
time.sleep(0.1)
|
||||
time.sleep(sleeptime)
|
||||
|
||||
#time.sleep(5)
|
||||
continue
|
||||
except TimeoutError as e:
|
||||
self.logger.info(f"[DEBUG] Timeout or request: {e}")
|
||||
time.sleep(0.1)
|
||||
time.sleep(sleeptime)
|
||||
|
||||
#time.sleep(5)
|
||||
continue
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
self.logger.info(f"[DEBUG] Connectionerror: {e}")
|
||||
time.sleep(0.1)
|
||||
time.sleep(sleeptime)
|
||||
|
||||
#time.sleep(5)
|
||||
continue
|
||||
except http.client.RemoteDisconnected as e:
|
||||
self.logger.info(f"[DEBUG] Remote: {e}")
|
||||
time.sleep(0.1)
|
||||
time.sleep(sleeptime)
|
||||
|
||||
#time.sleep(5)
|
||||
continue
|
||||
@@ -555,8 +558,11 @@ class AppBase:
|
||||
# Not sure why this would work tho :)
|
||||
action_result["status"] = "FAILURE"
|
||||
action_result["result"] = json.dumps({"success": False, "reason": "POST error: Failed connecting to %s over 10 retries to the backend" % url})
|
||||
self.logger.info(f"[DEBUG] Before typeerror stream result - NOT finished after 10 requests")
|
||||
ret = requests.post("%s%s" % (self.base_url, stream_path), headers=headers, json=action_result, verify=False)
|
||||
self.logger.info(f"[ERROR] Before typeerror stream result - NOT finished after 10 requests")
|
||||
|
||||
#ret = requests.post("%s%s" % (self.base_url, stream_path), headers=headers, json=action_result, verify=False)
|
||||
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:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module shuffle-shared
|
||||
|
||||
replace github.com/shuffle/shuffle-shared => ../../../../git/shuffle-shared
|
||||
//replace github.com/shuffle/shuffle-shared => ../../../../git/shuffle-shared
|
||||
|
||||
go 1.19
|
||||
|
||||
@@ -19,7 +19,7 @@ require (
|
||||
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.4.41
|
||||
github.com/shuffle/shuffle-shared v0.4.47
|
||||
golang.org/x/crypto v0.9.0
|
||||
google.golang.org/api v0.125.0
|
||||
google.golang.org/appengine v1.6.7
|
||||
|
||||
@@ -22,10 +22,9 @@ import {
|
||||
import aa from 'search-insights'
|
||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||
const Appsearch = props => {
|
||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList} = props
|
||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
||||
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
//const alert = useAlert();
|
||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||
const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs
|
||||
//const theme = useTheme();
|
||||
@@ -41,45 +40,6 @@ const Appsearch = props => {
|
||||
const borderRadius = 3
|
||||
window.title = "Shuffle | Apps | Find and integration any app"
|
||||
|
||||
const setUserSpecialzedApp = (user, data) => {
|
||||
// var data = newfields]
|
||||
console.log("data value", data)
|
||||
const appData = {"user_id":user,"specialized_apps":[{}]}
|
||||
console.log("User Check for appdata:", user)
|
||||
appData["specialized_apps"][0]["name"] = data["name"]
|
||||
appData["specialized_apps"][0]["image"] = data["image_url"]
|
||||
appData["specialized_apps"][0]["category"] = data["categories"].toString()
|
||||
console.log("AppData:",appData)
|
||||
console.log("setActionImageList",setActionImageList)
|
||||
console.log("actionImageList",actionImageList)
|
||||
|
||||
const finalData = actionImageList.concat(appData["specialized_apps"])
|
||||
appData["specialized_apps"]=finalData
|
||||
fetch(globalUrl + "/api/v1/users/updateuser", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(appData),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for set creator :O!");
|
||||
}
|
||||
toast("Sucessfully updated specialzed app.")
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (!responseJson.success && responseJson.reason !== undefined) {
|
||||
toast("Failed updating user: " + responseJson.reason);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
// value={currentRefinement}
|
||||
const SearchBox = ({currentRefinement, refine, isSearchStalled} ) => {
|
||||
@@ -180,13 +140,8 @@ const Appsearch = props => {
|
||||
setMouseHoverIndex(-1)
|
||||
}} onClick={() => {
|
||||
if(isCreatorPage === true){
|
||||
console.log("data:",data)
|
||||
console.log("userdata.id",userdata.id)
|
||||
console.log("is creator", isCreatorPage)
|
||||
if (setNewSelectedApp !== undefined) {
|
||||
// setUserSpecialzedApp = data
|
||||
if (setNewSelectedApp !== undefined && setUserSpecialzedApp !== undefined) {
|
||||
setUserSpecialzedApp(userdata.id, data)
|
||||
//setActionImageList(userdata.id, data)
|
||||
}
|
||||
}
|
||||
if (setNewSelectedApp !== undefined) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import ReactGA from 'react-ga4';
|
||||
import theme from "../theme.jsx";
|
||||
import { ToastContainer, toast } from "react-toastify"
|
||||
|
||||
import {
|
||||
Paper,
|
||||
@@ -14,22 +15,87 @@ import {
|
||||
//import { useAlert
|
||||
|
||||
const Branding = (props) => {
|
||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props;
|
||||
//const alert = useAlert();
|
||||
const [publishingInfo, setPublishingInfo] = useState("");
|
||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props;
|
||||
//const alert = useAlert();
|
||||
const [publishingInfo, setPublishingInfo] = useState("");
|
||||
const [publishRequirements, setPublishRequirements] = useState([])
|
||||
|
||||
// Should enable / disable org branding
|
||||
const handleChangePublishing = () => {
|
||||
console.log("Handle change publishing");
|
||||
}
|
||||
|
||||
const handleEditOrg = (joinStatus) => {
|
||||
const data = {
|
||||
"org_id": selectedOrganization.id,
|
||||
"creator_config": joinStatus,
|
||||
};
|
||||
|
||||
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 {
|
||||
if (joinStatus == "join") {
|
||||
setPublishingInfo("Your organization is now part of the Creator Incentive Program. You can now create and publish content to your organization's page. You can also create a creator account to manage your organization's content.")
|
||||
} else {
|
||||
setPublishingInfo("Your organization is no longer part of the Creator Incentive Program. You can still create a creator account to manage your organization's content.")
|
||||
}
|
||||
handleGetOrg(selectedOrganization.id);
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
toast("Err: " + error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
// Should enable / disable org branding
|
||||
const handleChangePublishing = () => {
|
||||
console.log("Handle change publishing");
|
||||
|
||||
if (selectedOrganization.creator_id == "") {
|
||||
handleEditOrg("join")
|
||||
} else {
|
||||
handleEditOrg("leave")
|
||||
}
|
||||
}
|
||||
|
||||
const isOrganizationReady = () => {
|
||||
console.log("Is organization ready?")
|
||||
|
||||
// A simple checklist to ensure the button shows up properly
|
||||
if (selectedOrganization.name === selectedOrganization.org) {
|
||||
const comment = "Change the name of your organization"
|
||||
if (!publishRequirements.includes(comment)) {
|
||||
setPublishRequirements([...publishRequirements, comment])
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a suborg
|
||||
if (selectedOrganization.creator_org !== "") {
|
||||
const comment = "Child orgs can't become creators"
|
||||
if (!publishRequirements.includes(comment)) {
|
||||
setPublishRequirements([...publishRequirements, comment])
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedOrganization.large_image === "" || selectedOrganization.large_image === theme.palette.defaultImage) {
|
||||
const comment = "Add a logo for your organization"
|
||||
if (!publishRequirements.includes(comment)) {
|
||||
setPublishRequirements([...publishRequirements, comment])
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -38,40 +104,58 @@ const Branding = (props) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography variant="h6" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
Branding
|
||||
</Typography>
|
||||
<h2>
|
||||
Branding
|
||||
</h2>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
You can customize your organization's branding by uploading a logo, changing the color scheme and a lot more.
|
||||
</Typography>
|
||||
|
||||
<Divider style={{marginTop: 50, marginBottom: 50, }} />
|
||||
<h2>
|
||||
Creator Network
|
||||
Creator Incentive Program
|
||||
</h2>
|
||||
<div style={{ display: "flex", width: 700, }}>
|
||||
<div style={{ display: "flex", width: 900, }}>
|
||||
<div>
|
||||
<span>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be turned into a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. Support: support@shuffler.io
|
||||
|
||||
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization is reversible.<div/>Support: <a href="mailto:support@shuffler.io"target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>support@shuffler.io</a>
|
||||
</Typography>
|
||||
{selectedOrganization.creator_id == "" ?
|
||||
<Typography variant="h6" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
||||
|
||||
</Typography>
|
||||
:
|
||||
<Typography variant="h6" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
||||
|
||||
<a href={`/creators/${selectedOrganization.creator_id}`} target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Modify your creator organization</a>
|
||||
</Typography>
|
||||
}
|
||||
|
||||
<Button
|
||||
style={{ height: 40, marginTop: 10, width: 300, }}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
disabled={() => {
|
||||
return isOrganizationReady()
|
||||
}}
|
||||
variant={selectedOrganization.creator_id == "" ? "contained" : "outlined"}
|
||||
color={selectedOrganization.creator_id == "" ? "primary" : "secondary"}
|
||||
disabled={!isOrganizationReady()}
|
||||
onClick={() => {
|
||||
handleChangePublishing();
|
||||
}}
|
||||
>
|
||||
Join Creator Network
|
||||
{selectedOrganization.creator_id == "" ? "Join" : "Leave"} Creators
|
||||
|
||||
</Button>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "white", }}>
|
||||
{publishingInfo}
|
||||
</Typography>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
||||
{publishRequirements.map((item) => {
|
||||
return (
|
||||
<div>
|
||||
Required: {item}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Typography>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -823,7 +823,6 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho
|
||||
color: "white",
|
||||
height: 45,
|
||||
width: 85,
|
||||
zIndex: 14999,
|
||||
}}
|
||||
|
||||
value={userdata.active_org.id}
|
||||
|
||||
@@ -70,7 +70,7 @@ const Priority = (props) => {
|
||||
|
||||
|
||||
return (
|
||||
<div style={{border: priority.active === false ? "1px solid #000000" : priority.severity === 1 ? "1px solid #f85a3e" : "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette.borderRadius, marginTop: 10, marginBottom: 10, padding: 15, textAlign: "center", height: 95, textAlign: "left", backgroundColor: theme.palette.surfaceColor, display: "flex", }}>
|
||||
<div style={{border: priority.active === false ? "1px solid #000000" : priority.severity === 1 ? "1px solid #f85a3e" : "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette.borderRadius, marginTop: 10, marginBottom: 10, padding: 15, textAlign: "center", minHeight: 70, maxHeight: 70, textAlign: "left", backgroundColor: theme.palette.surfaceColor, display: "flex", }}>
|
||||
<div style={{flex: 2, overflow: "hidden",}}>
|
||||
<span style={{display: "flex", }}>
|
||||
{priority.type === "usecase" || priority.type == "apps" ? <AutoFixHighIcon style={{height: 19, width: 19, marginLeft: 3, marginRight: 10, }}/> : null}
|
||||
|
||||
@@ -749,7 +749,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
image: image,
|
||||
defaults: defaults,
|
||||
sso_config: sso_config,
|
||||
lead_info: lead_info,
|
||||
lead_info: lead_info,
|
||||
};
|
||||
|
||||
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
|
||||
@@ -2371,7 +2371,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
*/}
|
||||
|
||||
{userdata.support === true ?
|
||||
<span style={{display: "flex", top: -10, right: 50, position: "absolute"}}>
|
||||
<span style={{display: "flex", top: -10, right: -50, position: "absolute"}}>
|
||||
{/*<a href={mailsendingButton(selectedOrganization)} target="_blank" rel="noopener noreferrer" style={{textDecoration: "none"}} disabled={selectedStatus.length !== 0}>*/}
|
||||
<Button
|
||||
variant="outlined"
|
||||
@@ -2468,8 +2468,8 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
setSelectedOrganization={setSelectedOrganization}
|
||||
globalUrl={globalUrl}
|
||||
selectedOrganization={selectedOrganization}
|
||||
adminTab={adminTab}
|
||||
handleEditOrg={handleEditOrg}
|
||||
adminTab={adminTab}
|
||||
handleEditOrg={handleEditOrg}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
@@ -2517,13 +2517,13 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
<Tab
|
||||
disabled={!isCloud}
|
||||
label=<span>
|
||||
Billing (Beta)
|
||||
Billing
|
||||
</span>
|
||||
/>
|
||||
<Tab
|
||||
disabled={!isCloud || true}
|
||||
disabled={!isCloud}
|
||||
label=<span>
|
||||
Branding
|
||||
Branding (Beta)
|
||||
</span>
|
||||
/>
|
||||
</Tabs>
|
||||
@@ -2798,7 +2798,6 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
globalUrl={globalUrl}
|
||||
handleGetOrg={handleGetOrg}
|
||||
selectedOrganization={selectedOrganization}
|
||||
selectedOrganization={selectedOrganization}
|
||||
setSelectedOrganization={setSelectedOrganization}
|
||||
/>
|
||||
: null
|
||||
@@ -2995,7 +2994,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
Add, edit, block or change passwords.{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#user_management"
|
||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||
>
|
||||
|
||||
@@ -22,9 +22,11 @@ import {
|
||||
Breadcrumbs,
|
||||
CircularProgress,
|
||||
Chip,
|
||||
IconButton,
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
Publish as PublishIcon,
|
||||
LockOpen as LockOpenIcon,
|
||||
FileCopy as FileCopyIcon,
|
||||
Delete as DeleteIcon,
|
||||
@@ -40,10 +42,11 @@ import {
|
||||
ZoomOutOutlined as ZoomOutOutlinedIcon,
|
||||
Loop as LoopIcon,
|
||||
AddPhotoAlternate as AddPhotoAlternateIcon,
|
||||
CallMerge as CallMergeIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||
import YAML from "yaml";
|
||||
import { MuiChipsInput } from "mui-chips-input";
|
||||
//import { useAlert
|
||||
@@ -360,6 +363,8 @@ const AppCreator = (defaultprops) => {
|
||||
props.match.params = params
|
||||
|
||||
var upload = "";
|
||||
let navigate = useNavigate();
|
||||
|
||||
const increaseAmount = 50;
|
||||
const actionNonBodyRequest = ["GET", "HEAD", "DELETE", "CONNECT"];
|
||||
const actionBodyRequest = ["POST", "PUT", "PATCH"];
|
||||
@@ -422,6 +427,109 @@ const AppCreator = (defaultprops) => {
|
||||
// and make categories + labels modifyable.
|
||||
// Categories are the main categories in the App Framework
|
||||
const [categories, setCategories] = useState(appCategories)
|
||||
|
||||
|
||||
|
||||
const redirectOpenApi = () => {
|
||||
navigate(`/apps/new?id=${appValidation}`)
|
||||
}
|
||||
|
||||
const newUpload = React.useRef(null);
|
||||
const [openApiError, setOpenApiError] = React.useState("");
|
||||
const [validation, setValidation] = React.useState("");
|
||||
const [appValidation, setAppValidation] = React.useState("");
|
||||
const [openApi, setOpenApi] = React.useState("");
|
||||
const [openApiData, setOpenApiData] = React.useState("");
|
||||
const [openApiModal, setOpenApiModal] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("In useEffect for openApiData: ", openApiData)
|
||||
}, [openApiData]);
|
||||
|
||||
const uploadFile = (e) => {
|
||||
console.log("In uploadFile")
|
||||
const isDropzone =
|
||||
e.dataTransfer === undefined ? false : e.dataTransfer.files.length > 0;
|
||||
const files = isDropzone ? e.dataTransfer.files : e.target.files;
|
||||
const reader = new FileReader();
|
||||
|
||||
try {
|
||||
reader.addEventListener("load", (e) => {
|
||||
const content = e.target.result;
|
||||
console.log("set openapi data! ", content)
|
||||
setOpenApiData(content);
|
||||
setOpenApiModal(true);
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Error in dropzone: ", e);
|
||||
}
|
||||
|
||||
try {
|
||||
reader.readAsText(files[0]);
|
||||
} catch (error) {
|
||||
toast("Failed to read file");
|
||||
}
|
||||
}
|
||||
|
||||
const escapeApiData = (apidata) => {
|
||||
//console.log(apidata)
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(apidata));
|
||||
} catch (error) {
|
||||
console.log("JSON DECODE ERROR - TRY YAML");
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = YAML.parse(YAML.stringify(apidata));
|
||||
//const parsed = YAML.parse(apidata))
|
||||
return YAML.stringify(parsed);
|
||||
} catch (error) {
|
||||
console.log("YAML DECODE ERROR - TRY SOMETHING ELSE?: " + error);
|
||||
setOpenApiError("Local error: " + error.toString());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const validateOpenApi = (openApidata) => {
|
||||
var newApidata = escapeApiData(openApidata);
|
||||
if (newApidata === "") {
|
||||
// Used to return here
|
||||
newApidata = openApidata;
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log(newApidata)
|
||||
|
||||
setValidation(true);
|
||||
fetch(globalUrl + "/api/v1/validate_openapi", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: openApidata,
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
setValidation(false);
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success) {
|
||||
setAppValidation(responseJson.id);
|
||||
} else {
|
||||
if (responseJson.reason !== undefined) {
|
||||
setOpenApiError(responseJson.reason);
|
||||
}
|
||||
toast("An error occurred in the response");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setValidation(false);
|
||||
toast(error.toString());
|
||||
setOpenApiError(error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
@@ -2084,9 +2192,9 @@ const AppCreator = (defaultprops) => {
|
||||
},
|
||||
};
|
||||
|
||||
if (queryitem.example !== undefined) {
|
||||
newitem.example = queryitem.example
|
||||
}
|
||||
if (queryitem.example !== undefined) {
|
||||
newitem.example = queryitem.example
|
||||
}
|
||||
|
||||
if (queryitem.description !== undefined) {
|
||||
newitem.description = queryitem.description;
|
||||
@@ -2936,18 +3044,6 @@ const AppCreator = (defaultprops) => {
|
||||
setOauth2Scopes(chips)
|
||||
setUpdate(Math.random())
|
||||
}}
|
||||
onAdd={(chip) => {
|
||||
oauth2Scopes.push(chip);
|
||||
console.log(oauth2Scopes);
|
||||
setOauth2Scopes(oauth2Scopes);
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
onDelete={(chip, index) => {
|
||||
oauth2Scopes.splice(index, 1);
|
||||
console.log(oauth2Scopes);
|
||||
setOauth2Scopes(oauth2Scopes);
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
@@ -4408,16 +4504,7 @@ const AppCreator = (defaultprops) => {
|
||||
setNewWorkflowTags(chips)
|
||||
setUpdate("added "+chips)
|
||||
}}
|
||||
onAdd={(chip) => {
|
||||
newWorkflowTags.push(chip);
|
||||
setNewWorkflowTags(newWorkflowTags);
|
||||
setUpdate("added" + chip);
|
||||
}}
|
||||
onDelete={(chip, index) => {
|
||||
newWorkflowTags.splice(index, 1);
|
||||
setNewWorkflowTags(newWorkflowTags);
|
||||
setUpdate("delete " + chip);
|
||||
}}
|
||||
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -5360,6 +5447,167 @@ const AppCreator = (defaultprops) => {
|
||||
</Dialog>
|
||||
) : null;
|
||||
|
||||
const validateRemote = () => {
|
||||
setValidation(true);
|
||||
|
||||
fetch(globalUrl + "/api/v1/get_openapi_uri", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(openApi),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
setValidation(false);
|
||||
if (response.status !== 200) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
return response.text();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (typeof responseJson !== "string" && !responseJson.success) {
|
||||
console.log(responseJson.reason);
|
||||
if (responseJson.reason !== undefined) {
|
||||
setOpenApiError(responseJson.reason);
|
||||
} else {
|
||||
setOpenApiError("Undefined issue with OpenAPI validation");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Validating response!");
|
||||
validateOpenApi(responseJson);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
setOpenApiError(error.toString());
|
||||
});
|
||||
}
|
||||
|
||||
const circularLoader = validation ? (
|
||||
<CircularProgress color="primary" />
|
||||
) : null;
|
||||
|
||||
const newApimodalView = openApiModal ?
|
||||
<Dialog
|
||||
open={openApiModal}
|
||||
onClose={() => {
|
||||
setOpenApiModal(false)
|
||||
}}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: surfaceColor,
|
||||
color: "white",
|
||||
minWidth: "800px",
|
||||
minHeight: "320px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<FormControl>
|
||||
<DialogTitle>
|
||||
<div style={{ color: "rgba(255,255,255,0.9)" }}>
|
||||
Merge with another OpenAPI document. You will get to choose Actions before they are merged.
|
||||
</div>
|
||||
</DialogTitle>
|
||||
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
|
||||
Paste in the URI for the OpenAPI
|
||||
<TextField
|
||||
style={{ backgroundColor: inputColor }}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
height: "50px",
|
||||
fontSize: "1em",
|
||||
},
|
||||
endAdornment: (
|
||||
<Button
|
||||
style={{
|
||||
borderRadius: "0px",
|
||||
marginTop: "0px",
|
||||
height: "50px",
|
||||
}}
|
||||
variant="contained"
|
||||
disabled={openApi.length === 0 || appValidation.length > 0}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setOpenApiError("");
|
||||
validateRemote();
|
||||
}}
|
||||
>
|
||||
Validate
|
||||
</Button>
|
||||
),
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setOpenApi(e.target.value);
|
||||
}}
|
||||
helperText={
|
||||
<span style={{ color: "white", marginBottom: "2px" }}>
|
||||
Must point to a version 2 or 3 OpenAPI specification.
|
||||
</span>
|
||||
}
|
||||
placeholder="OpenAPI URI"
|
||||
fullWidth
|
||||
/>
|
||||
{/*
|
||||
<div style={{marginTop: "15px"}}/>
|
||||
Example:
|
||||
<div />
|
||||
https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/uber.json
|
||||
*/}
|
||||
<p>Or upload a YAML/JSON specification</p>
|
||||
<input
|
||||
hidden
|
||||
type="file"
|
||||
ref={newUpload}
|
||||
accept="application/JSON,application/YAML,application/yaml,text/yaml,text/x-yaml,application/x-yaml,application/vnd.yaml,.yml,.yaml"
|
||||
multiple={false}
|
||||
onChange={uploadFile}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => newUpload.current.click()}
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
{errorText}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{circularLoader}
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
setOpenApiModal(false);
|
||||
setAppValidation("");
|
||||
setOpenApiError("");
|
||||
setOpenApi("");
|
||||
setOpenApiData("");
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{ borderRadius: "0px" }}
|
||||
disabled={appValidation.length === 0}
|
||||
onClick={() => {
|
||||
redirectOpenApi();
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</FormControl>
|
||||
</Dialog>
|
||||
: null
|
||||
|
||||
// Random names for type & autoComplete. Didn't research :^)
|
||||
const landingpageDataBrowser = (
|
||||
<div style={{ paddingBottom: 100, color: "white" }}>
|
||||
@@ -5391,9 +5639,30 @@ const AppCreator = (defaultprops) => {
|
||||
onChange={editHeaderImage}
|
||||
/>
|
||||
<Paper style={boxStyle}>
|
||||
<h2 style={{ marginBottom: "10px", color: "white" }}>
|
||||
General information
|
||||
</h2>
|
||||
<div style={{display: "flex", }}>
|
||||
<div style={{flex: 1, }}>
|
||||
<h2 style={{ marginBottom: "10px", color: "white" }}>
|
||||
General information
|
||||
</h2>
|
||||
</div>
|
||||
<div style={{flex: 1, itemAlign: "right", textAlign: "right",}}>
|
||||
<Tooltip title="Merge with another API (coming soon)" placement="bottom">
|
||||
<IconButton
|
||||
disabled
|
||||
onClick={() => {
|
||||
setOpenApiModal(true)
|
||||
}}
|
||||
>
|
||||
<CallMergeIcon
|
||||
style={{}}
|
||||
onClick={() => {
|
||||
setOpenApiModal(true)
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://shuffler.io/docs/app_creation#app-creator-instructions"
|
||||
@@ -5706,6 +5975,7 @@ const AppCreator = (defaultprops) => {
|
||||
isLoaded && isAppLoaded ? (
|
||||
<div>
|
||||
<div style={bodyDivStyle}>{landingpageDataBrowser}</div>
|
||||
{newApimodalView}
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
|
||||
@@ -1354,7 +1354,7 @@ const Apps = (props) => {
|
||||
border: hover ? "1px solid #f85a3e" : "1px solid rgba(255,255,255,0.3)",
|
||||
cursor: hover ? "pointer" : "default",
|
||||
textAlign: "center",
|
||||
height: 150,
|
||||
height: 125,
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
@@ -2556,6 +2556,7 @@ const Apps = (props) => {
|
||||
const circularLoader = validation ? (
|
||||
<CircularProgress color="primary" />
|
||||
) : null;
|
||||
|
||||
const appsModalLoad = loadAppsModalOpen ? (
|
||||
<Dialog
|
||||
open={loadAppsModalOpen}
|
||||
|
||||
@@ -730,28 +730,28 @@ const Settings = (props) => {
|
||||
</Button>
|
||||
<h3>{passwordFormMessage}</h3>
|
||||
<Divider style={{ marginTop: "40px" }} />
|
||||
<h2>Platform Earnings</h2>
|
||||
<h2>Creator Incentive Program</h2>
|
||||
<div style={{ display: runFlex ? "flex" : "", width: "100%" }}>
|
||||
<div>
|
||||
{isCloud ?
|
||||
<span>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
By connecting your Github account, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your non-sensitive data will be turned into a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. This enables you to earn a passive income from Shuffle. This IS reversible. Support: support@shuffler.io
|
||||
</Typography>
|
||||
<Button
|
||||
style={{ height: 40, marginTop: 10 }}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
fullWidth={true}
|
||||
onClick={() => {
|
||||
handleGithubConnection();
|
||||
}}
|
||||
>
|
||||
Connect to Github
|
||||
</Button>
|
||||
</span>
|
||||
: null}
|
||||
</div>
|
||||
<div>
|
||||
{isCloud ?
|
||||
<span>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
By <a href="/creators" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>joining the Creator Incentive Program</a> and connecting your Github account, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your non-sensitive data will be turned into a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. This enables you to earn a passive income from Shuffle. This IS reversible. Support: support@shuffler.io
|
||||
</Typography>
|
||||
<Button
|
||||
style={{ height: 40, marginTop: 10 }}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
fullWidth={true}
|
||||
onClick={() => {
|
||||
handleGithubConnection();
|
||||
}}
|
||||
>
|
||||
Connect to Github
|
||||
</Button>
|
||||
</span>
|
||||
: null}
|
||||
</div>
|
||||
<div style={{ flex: 1, display: "flex" }}>
|
||||
<div>
|
||||
{userdata.eth_info !== undefined &&
|
||||
|
||||
@@ -638,7 +638,7 @@ const Workflows = (props) => {
|
||||
window.location.host === "shuffler.io";
|
||||
|
||||
const findWorkflow = (filters) => {
|
||||
console.log("Using filters: ", filters)
|
||||
console.log("Using filters: ", filters)
|
||||
if (filters.length === 0) {
|
||||
setFilteredWorkflows(workflows);
|
||||
handleKeysetting(allUsecases, workflows)
|
||||
@@ -656,6 +656,12 @@ const Workflows = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (curWorkflow.tags !== undefined && curWorkflow.tags !== null && curWorkflow.tags.length > 0) {
|
||||
// Make them all lowercase
|
||||
curWorkflow.tags = curWorkflow.tags.map((tag) => tag.toLowerCase())
|
||||
}
|
||||
|
||||
|
||||
if (found.every((v) => v !== true)) {
|
||||
found = filters.map((filter) => {
|
||||
if (filter === undefined || filter === null) {
|
||||
@@ -666,7 +672,7 @@ const Workflows = (props) => {
|
||||
|
||||
if (curWorkflow.name.toLowerCase().includes(filter.toLowerCase())) {
|
||||
return true;
|
||||
} else if (curWorkflow.tags !== undefined && curWorkflow.tags !== null && curWorkflow.tags.includes(filter)) {
|
||||
} else if (curWorkflow.tags !== undefined && curWorkflow.tags !== null && curWorkflow.tags.includes(filter.toLowerCase())) {
|
||||
return true;
|
||||
} else if (curWorkflow.owner === filter) {
|
||||
return true;
|
||||
@@ -674,17 +680,17 @@ const Workflows = (props) => {
|
||||
return true;
|
||||
} else if (curWorkflow.usecase_ids !== undefined && curWorkflow.usecase_ids !== null && curWorkflow.usecase_ids.length > 0) {
|
||||
// Check if the usecase is the right category
|
||||
for (var key in usecases) {
|
||||
if (usecases[key].name.toLowerCase() !== newfilter) {
|
||||
continue
|
||||
}
|
||||
for (var key in usecases) {
|
||||
if (usecases[key].name.toLowerCase() !== newfilter) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (var subkey in usecases[key].list) {
|
||||
if (curWorkflow.usecase_ids.includes(usecases[key].list[subkey].name)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for (var subkey in usecases[key].list) {
|
||||
if (curWorkflow.usecase_ids.includes(usecases[key].list[subkey].name)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
curWorkflow.actions !== null &&
|
||||
curWorkflow.actions !== undefined
|
||||
|
||||
@@ -224,7 +224,7 @@ func deployServiceWorkers(image string) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Failed to convert the default MTU to int: %s. Using 1500 instead", err)
|
||||
log.Printf("[DEBUG] Failed to convert the default MTU to int: %s. Using 1500 instead", err)
|
||||
mtu = 1500
|
||||
}
|
||||
|
||||
@@ -1601,6 +1601,6 @@ func sendWorkerRequest(workflowExecution shuffle.ExecutionRequest) error {
|
||||
|
||||
_ = body
|
||||
|
||||
log.Printf("[DEBUG] Ran worker from request with execution ID: %s. Worker URL: %s. DEBUGGING: docker service logs shuffle-workers 2&>1 | grep %s", workflowExecution.ExecutionId, streamUrl, workflowExecution.ExecutionId)
|
||||
log.Printf("[DEBUG] Ran worker from request with execution ID: %s. Worker URL: %s. DEBUGGING: docker service logs shuffle-workers 2>&1 | grep %s", workflowExecution.ExecutionId, streamUrl, workflowExecution.ExecutionId)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user