Merge branch '1.4.0' into pipelines
This commit is contained in:
@@ -58,3 +58,35 @@ code {
|
||||
color: white !important;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Style for checkbox */
|
||||
.ais-RefinementList-checkbox {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #595b5e;
|
||||
border-radius: 4px;
|
||||
background-color: #27292d;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ais-RefinementList-checkbox:checked {
|
||||
background-color: rgb(248, 103, 67) !important;
|
||||
border-color: rgb(248, 103, 67) !important;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.ais-RefinementList-checkbox:checked::before {
|
||||
content: "\2714";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -936,7 +936,7 @@ const AppFramework = (props) => {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
if (response.status !== 200 || response.status !== 202) {
|
||||
console.log("Failed to activate")
|
||||
}
|
||||
|
||||
@@ -944,7 +944,11 @@ const AppFramework = (props) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
toast("Failed to activate the app")
|
||||
var msgString = "Failed to activate the app"
|
||||
if (responseJson.reason !== undefined) {
|
||||
msgString += ": " + responseJson.reason
|
||||
}
|
||||
toast(msgString)
|
||||
} else {
|
||||
//toast("App activated for your organization! Refresh the page to use the app.")
|
||||
}
|
||||
|
||||
@@ -970,7 +970,7 @@ const Billing = (props) => {
|
||||
|
||||
const isChildOrg = userdata.active_org.creator_org !== "" && userdata.active_org.creator_org !== undefined && userdata.active_org.creator_org !== null
|
||||
return (
|
||||
<div style={{}}>
|
||||
<div style={{ width: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
|
||||
{addDealModal}
|
||||
<Typography variant="h4" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
Billing & Licensing
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
//import { useAlert
|
||||
|
||||
const Branding = (props) => {
|
||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props;
|
||||
const { globalUrl, userdata, serverside, billingInfo,clickedFromOrgTab, stripeKey, selectedOrganization, handleGetOrg, } = props;
|
||||
//const alert = useAlert();
|
||||
const [publishingInfo, setPublishingInfo] = useState("");
|
||||
const [publishRequirements, setPublishRequirements] = useState([])
|
||||
@@ -103,7 +103,7 @@ const Branding = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ width: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
|
||||
<h2>
|
||||
Branding
|
||||
</h2>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import theme from "../theme.jsx";
|
||||
import { toast } from 'react-toastify';
|
||||
import ReactJson from "react-json-view";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
import ReactJson from "react-json-view";
|
||||
|
||||
import {
|
||||
Typography,
|
||||
Typography,
|
||||
Tooltip,
|
||||
Divider,
|
||||
TextField,
|
||||
@@ -22,8 +22,8 @@ import {
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
Link as LinkIcon,
|
||||
AutoFixHigh as AutoFixHighIcon,
|
||||
Link as LinkIcon,
|
||||
AutoFixHigh as AutoFixHighIcon,
|
||||
Edit as EditIcon,
|
||||
FileCopy as FileCopyIcon,
|
||||
SelectAll as SelectAllIcon,
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
Visibility as VisibilityIcon,
|
||||
VisibilityOff as VisibilityOffIcon,
|
||||
} from "@mui/icons-material";
|
||||
import { validateJson, } from "../views/Workflows.jsx";
|
||||
import { validateJson, } from "../views/Workflows.jsx";
|
||||
|
||||
const scrollStyle1 = {
|
||||
height: 100,
|
||||
@@ -64,9 +64,9 @@ const scrollStyle2 = {
|
||||
overflow: "scroll",
|
||||
}
|
||||
|
||||
|
||||
|
||||
const CacheView = (props) => {
|
||||
const { globalUrl, userdata, serverside, orgId } = props;
|
||||
const { globalUrl, userdata, serverside, orgId, isSelectedDataStore } = props;
|
||||
const [orgCache, setOrgCache] = React.useState("");
|
||||
const [listCache, setListCache] = React.useState([]);
|
||||
const [addCache, setAddCache] = React.useState("");
|
||||
@@ -79,7 +79,7 @@ const CacheView = (props) => {
|
||||
const [dataValue, setDataValue] = React.useState({});
|
||||
const [editCache, setEditCache] = React.useState(false);
|
||||
const [show, setShow] = useState({});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
listOrgCache(orgId);
|
||||
}, []);
|
||||
@@ -155,22 +155,22 @@ const CacheView = (props) => {
|
||||
|
||||
const deleteCache = (orgId, key) => {
|
||||
toast("Attempting to delete Cache");
|
||||
|
||||
|
||||
// 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,
|
||||
}
|
||||
|
||||
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,
|
||||
method: method,
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(parsed),
|
||||
body: JSON.stringify(parsed),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
@@ -255,20 +255,20 @@ const CacheView = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const isValidJson = validateJson(value)
|
||||
const autoFixJson = (inputvalue) => {
|
||||
console.log("inputvalue: ", inputvalue)
|
||||
try {
|
||||
var parsedjson = JSON.parse(inputvalue)
|
||||
|
||||
// setValue() with the parsed json as string
|
||||
setValue(JSON.stringify(parsedjson, null, 2))
|
||||
} catch (e) {
|
||||
console.log("Error parsing JSON: ", e)
|
||||
//return JSON.stringify(inputvalue);
|
||||
}
|
||||
}
|
||||
|
||||
const isValidJson = validateJson(value)
|
||||
const autoFixJson = (inputvalue) => {
|
||||
console.log("inputvalue: ", inputvalue)
|
||||
try {
|
||||
var parsedjson = JSON.parse(inputvalue)
|
||||
|
||||
// setValue() with the parsed json as string
|
||||
setValue(JSON.stringify(parsedjson, null, 2))
|
||||
} catch (e) {
|
||||
console.log("Error parsing JSON: ", e)
|
||||
//return JSON.stringify(inputvalue);
|
||||
}
|
||||
}
|
||||
|
||||
const modalView = (
|
||||
// console.log("key:", dataValue.key),
|
||||
//console.log("value:",dataValue.value),
|
||||
@@ -316,21 +316,21 @@ const CacheView = (props) => {
|
||||
/>
|
||||
</div>
|
||||
<div style={{ paddingLeft: 30, paddingRight: 30 }}>
|
||||
<div style={{display: "flex", }}>
|
||||
<Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}>
|
||||
Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON)
|
||||
</Typography>
|
||||
<Tooltip title="Auto Fix JSON" placement="right">
|
||||
<IconButton
|
||||
style={{flex: 1, }}
|
||||
onClick={() => {
|
||||
autoFixJson(value)
|
||||
}}
|
||||
>
|
||||
<AutoFixHighIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div style={{display: "flex", }}>
|
||||
<Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}>
|
||||
Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON)
|
||||
</Typography>
|
||||
<Tooltip title="Auto Fix JSON" placement="right">
|
||||
<IconButton
|
||||
style={{flex: 1, }}
|
||||
onClick={() => {
|
||||
autoFixJson(value)
|
||||
}}
|
||||
>
|
||||
<AutoFixHighIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<TextField
|
||||
color="primary"
|
||||
style={{ backgroundColor: theme.palette.inputColor, marginTop: 0, }}
|
||||
@@ -347,22 +347,22 @@ const CacheView = (props) => {
|
||||
id="Valuefield"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
multiline
|
||||
minRows={4}
|
||||
maxRows={12}
|
||||
multiline
|
||||
minRows={4}
|
||||
maxRows={12}
|
||||
//defaultValue={editCache ? dataValue.value : ""}
|
||||
value={value}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<DialogActions style={{ paddingLeft: "30px", paddingRight: '30px' }}>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
setModalOpen(false)
|
||||
setValue("")
|
||||
setDataValue({})
|
||||
}}
|
||||
onClick={() => {
|
||||
setModalOpen(false)
|
||||
setValue("")
|
||||
setDataValue({})
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Cancel
|
||||
@@ -372,9 +372,9 @@ const CacheView = (props) => {
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
{editCache ? editOrgCache(orgId) : addOrgCache(orgId)}
|
||||
|
||||
setValue("")
|
||||
setDataValue({})
|
||||
|
||||
setValue("")
|
||||
setDataValue({})
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
@@ -386,51 +386,51 @@ const CacheView = (props) => {
|
||||
|
||||
return (
|
||||
|
||||
<div style={{paddingBottom: 250, }}>
|
||||
<div style={{paddingBottom: isSelectedDataStore?null:250, width: isSelectedDataStore?1030:null, padding:isSelectedDataStore?27:null, height: isSelectedDataStore?1200:null, color: isSelectedDataStore?'#ffffff':null, backgroundColor: isSelectedDataStore?'#212121':null, borderRadius: isSelectedDataStore?'16px':null, }}>
|
||||
{modalView}
|
||||
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
||||
<h2 style={{ display: "inline" }}>Shuffle Datastore</h2>
|
||||
<span style={{ marginLeft: 25 }}>
|
||||
Datastore is a permanent key-value database for storing data that can be used cross-workflow. You can store anything from lists of IPs to complex configurations.
|
||||
<div style={{ marginTop: isSelectedDataStore?null:20, marginBottom: 20 }}>
|
||||
<h2 style={{ display: isSelectedDataStore?null: "inline" }}>Shuffle Datastore</h2>
|
||||
<span style={{ marginLeft: isSelectedDataStore?null:25, color:isSelectedDataStore?"#9E9E9E":null}}>
|
||||
Datastore is a permanent key-value database for storing data that can be used cross-workflow. <br/>You can store anything from lists of IPs to complex configurations.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#datastore"
|
||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||
style={{ textDecoration: isSelectedDataStore?null:"none", color: isSelectedDataStore?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
style={{}}
|
||||
style={{backgroundColor: isSelectedDataStore?'rgba(255, 132, 68, 0.2)':null, color:isSelectedDataStore?"#FF8444":null, borderRadius:isSelectedDataStore?200:null, width:isSelectedDataStore?162:null, height:isSelectedDataStore?40:null}}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() =>{
|
||||
setEditCache(false)
|
||||
setModalOpen(true)
|
||||
|
||||
setValue("")
|
||||
}}
|
||||
|
||||
setValue("")
|
||||
}}
|
||||
>
|
||||
Add Cache
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 5, marginRight: 15 }}
|
||||
style={{ marginLeft: 5, marginRight: 15, backgroundColor: isSelectedDataStore?"#2F2F2F":null,borderRadius:isSelectedDataStore?200:null, width:isSelectedDataStore?81:null, height:isSelectedDataStore?40:null, }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => listOrgCache(orgId)}
|
||||
>
|
||||
<CachedIcon />
|
||||
</Button>
|
||||
<Divider
|
||||
{isSelectedDataStore? null :<Divider
|
||||
style={{
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
}}
|
||||
/>
|
||||
<List>
|
||||
<ListItem>
|
||||
/>}
|
||||
<List style={{borderRadius: isSelectedDataStore?8:null, border:isSelectedDataStore?"1px solid #494949":null, marginTop:isSelectedDataStore?24:null}}>
|
||||
<ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore?"1px solid #494949":null}}>
|
||||
<ListItemText
|
||||
primary="Key"
|
||||
style={{ minWidth: 250, maxWidth: 250, }}
|
||||
@@ -454,8 +454,8 @@ const CacheView = (props) => {
|
||||
if (index % 2 === 0) {
|
||||
bgColor = "#1f2023";
|
||||
}
|
||||
|
||||
const validate = validateJson(data.value);
|
||||
|
||||
const validate = validateJson(data.value);
|
||||
return (
|
||||
<ListItem key={index} style={{ backgroundColor: bgColor, maxHeight: 300, overflow: "auto", }}>
|
||||
<ListItemText
|
||||
@@ -467,35 +467,35 @@ const CacheView = (props) => {
|
||||
primary={data.key}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
minWidth: 400,
|
||||
maxWidth: 400,
|
||||
style={{
|
||||
minWidth: 400,
|
||||
maxWidth: 400,
|
||||
}}
|
||||
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
|
||||
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: 200,
|
||||
minWidth: 200,
|
||||
marginLeft: 50,
|
||||
marginLeft: 50,
|
||||
}}
|
||||
primary=<span style={{ display: "inline" }}>
|
||||
<Tooltip
|
||||
@@ -508,11 +508,11 @@ const CacheView = (props) => {
|
||||
style={{ padding: "6px" }}
|
||||
onClick={() => {
|
||||
setEditCache(true)
|
||||
setDataValue({
|
||||
"key": data.key,
|
||||
"value":data.value
|
||||
})
|
||||
setValue(data.value)
|
||||
setDataValue({
|
||||
"key": data.key,
|
||||
"value":data.value
|
||||
})
|
||||
setValue(data.value)
|
||||
setModalOpen(true)
|
||||
}}
|
||||
>
|
||||
@@ -525,18 +525,18 @@ const CacheView = (props) => {
|
||||
<Tooltip
|
||||
title={"Public URL (types: text, raw, json)"}
|
||||
style={{ marginLeft: 0, }}
|
||||
aria-label={"Public URL"}
|
||||
aria-label={"Public URL"}
|
||||
>
|
||||
<span>
|
||||
<IconButton
|
||||
style={{ padding: "6px" }}
|
||||
disabled={data.public_authorization === undefined || data.public_authorization === null || data.public_authorization === "" ? true : false}
|
||||
disabled={data.public_authorization === undefined || data.public_authorization === null || data.public_authorization === "" ? true : false}
|
||||
onClick={() => {
|
||||
window.open(`${globalUrl}/api/v1/orgs/${orgId}/cache/${data.key}?type=text&authorization=${data.public_authorization}`, "_blank");
|
||||
}}
|
||||
window.open(`${globalUrl}/api/v1/orgs/${orgId}/cache/${data.key}?type=text&authorization=${data.public_authorization}`, "_blank");
|
||||
}}
|
||||
>
|
||||
<LinkIcon
|
||||
/>
|
||||
<LinkIcon
|
||||
/>
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
@@ -603,10 +603,10 @@ const ConfigureWorkflow = (props) => {
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
if (responseJson.reason !== undefined) {
|
||||
toast("Failed to activate the app: "+responseJson.reason);
|
||||
} else {
|
||||
toast("Failed to activate the app");
|
||||
}
|
||||
toast("Failed to activate the app: "+responseJson.reason);
|
||||
} else {
|
||||
toast("Failed to activate the app");
|
||||
}
|
||||
} else {
|
||||
toast("App activated for your organization!");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import algoliasearch from 'algoliasearch';
|
||||
import theme from '../theme.jsx';
|
||||
import { InstantSearch, connectSearchBox, connectHits } from 'react-instantsearch-dom';
|
||||
import {
|
||||
Grid,
|
||||
Paper,
|
||||
TextField,
|
||||
Typography,
|
||||
Button,
|
||||
InputAdornment,
|
||||
Avatar,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
} from '@mui/material';
|
||||
import { Search as SearchIcon } from '@mui/icons-material';
|
||||
|
||||
|
||||
const searchClient = algoliasearch("JNSS5CFDZZ", "1e5f29b1550939855de5915eac3bf5f7");
|
||||
|
||||
const DiscordChat = props => {
|
||||
const { isMobile, globalUrl } = props
|
||||
const [value, setValue] = useState("");
|
||||
const [formMail, setFormMail] = React.useState("");
|
||||
const [message, setMessage] = React.useState("");
|
||||
const [formMessage, setFormMessage] = React.useState("");
|
||||
const buttonStyle = {borderRadius: 30, height: 50, width: 220, margin: isMobile ? "15px auto 15px auto" : 20, fontSize: 18,}
|
||||
|
||||
const borderRadius = 3
|
||||
|
||||
const submitContact = (email, message) => {
|
||||
const data = {
|
||||
"firstname": "",
|
||||
"lastname": "",
|
||||
"title": "",
|
||||
"companyname": "",
|
||||
"email": email,
|
||||
"phone": "",
|
||||
"message": message,
|
||||
}
|
||||
|
||||
const errorMessage = "Something went wrong. Please contact frikky@shuffler.io directly."
|
||||
|
||||
fetch(globalUrl+"/api/v1/contact", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(response => {
|
||||
if (response.success === true) {
|
||||
setFormMessage(response.reason)
|
||||
//toast("Thanks for submitting!")
|
||||
} else {
|
||||
setFormMessage(errorMessage)
|
||||
}
|
||||
|
||||
setFormMail("")
|
||||
setMessage("")
|
||||
})
|
||||
.catch(error => {
|
||||
setFormMessage(errorMessage)
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
|
||||
const SearchBox = ({ currentRefinement, refine }) => {
|
||||
return (
|
||||
<form noValidate action="" role="search">
|
||||
<TextField
|
||||
fullWidth
|
||||
value={currentRefinement}
|
||||
onChange={(event) => refine(event.currentTarget.value)}
|
||||
placeholder="Search Discord Chats"
|
||||
style={{ backgroundColor: theme.palette.inputColor, borderRadius: borderRadius, margin: 10, width: "100%", }}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
fontSize: "1em",
|
||||
height: 50,
|
||||
},
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon style={{ marginLeft: 5 }} />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
const highlightText = (text) => {
|
||||
if (!Array.isArray(text.matchedWords) || text.matchedWords.length === 0) {
|
||||
return text.value;
|
||||
}
|
||||
|
||||
let highlightedText = '';
|
||||
let currentIndex = 0;
|
||||
|
||||
text.matchedWords.forEach((word, index) => {
|
||||
const startIndex = text.value.toLowerCase().indexOf(word.toLowerCase(), currentIndex);
|
||||
const endIndex = startIndex + word.length;
|
||||
highlightedText += text.value.substring(currentIndex, startIndex);
|
||||
highlightedText += `<mark>${text.value.substring(startIndex, endIndex)}</mark>`;
|
||||
currentIndex = endIndex;
|
||||
});
|
||||
|
||||
highlightedText += text.value.substring(currentIndex);
|
||||
return <span dangerouslySetInnerHTML={{ __html: highlightedText }} />;
|
||||
};
|
||||
|
||||
const Hits = ({ hits }) => {
|
||||
const handleHitClick = (url) => {
|
||||
const modifiedUrl = url.replace('https://ptb.discord.com/', 'https://discord.com/');
|
||||
window.open(modifiedUrl, '_blank');
|
||||
};
|
||||
if (hits.length === 0) {
|
||||
return <Typography>No results found. Try refining your search.</Typography>;
|
||||
}
|
||||
return (
|
||||
<List>
|
||||
{hits.map((chat, index) => (
|
||||
<ListItem key={index} onClick={() => handleHitClick(chat.url)} style={{ cursor: "pointer", borderBottom: "1px solid rgba(255,255,255,0.4)" }}>
|
||||
<ListItemAvatar>
|
||||
<Avatar src="/discord-logo.png" />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={highlightText(chat._highlightResult.text)}
|
||||
secondary={`User: ${(chat.user)}`}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomSearchBox = connectSearchBox(SearchBox);
|
||||
const CustomHits = connectHits(Hits);
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", textAlign:"center", position: "relative", height: "100%", }}>
|
||||
<InstantSearch searchClient={searchClient} indexName="discord_chat">
|
||||
<div style={{ maxWidth: 450, margin: "auto", marginTop: 15, marginBottom: 5, }}>
|
||||
<CustomSearchBox />
|
||||
</div>
|
||||
<div style={{ width: "100%" }}>
|
||||
<CustomHits />
|
||||
</div>
|
||||
</InstantSearch>
|
||||
<div style={{paddingTop: 0, maxWidth: isMobile ? "100%" : "60%", margin: "auto"}}>
|
||||
<Typography variant="h6" style={{color: "white", marginTop: 50,}}>
|
||||
Can't find what you're looking for?
|
||||
</Typography>
|
||||
<div style={{flex: "1", display: "flex", flexDirection: "row", textAlign: "center",}}>
|
||||
<TextField
|
||||
required
|
||||
style={{flex: "1", marginRight: "15px", backgroundColor: theme.palette.inputColor}}
|
||||
InputProps={{
|
||||
style:{
|
||||
color: "#ffffff",
|
||||
},
|
||||
}}
|
||||
color="primary"
|
||||
fullWidth={true}
|
||||
placeholder="Email (optional)"
|
||||
type="email"
|
||||
id="email-handler"
|
||||
autoComplete="email"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
onChange={e => setFormMail(e.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
required
|
||||
style={{flex: "1", backgroundColor: theme.palette.inputColor}}
|
||||
InputProps={{
|
||||
style:{
|
||||
color: "#ffffff",
|
||||
},
|
||||
}}
|
||||
color="primary"
|
||||
fullWidth={true}
|
||||
placeholder="What are we missing?"
|
||||
type=""
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
autoComplete="off"
|
||||
onChange={e => setMessage(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={buttonStyle}
|
||||
disabled={message.length === 0}
|
||||
onClick={() => {
|
||||
submitContact(formMail, message)
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
<Typography style={{color: "white"}} variant="body2">{formMessage}</Typography>
|
||||
</div>
|
||||
<span style={{position: "absolute", display: "flex", textAlign: "right", float: "right", right: 0, bottom: 120, }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{}}>
|
||||
Search by
|
||||
</Typography>
|
||||
<a rel="noopener noreferrer" href="https://www.algolia.com/" target="_blank" style={{textDecoration: "none", color: "white"}}>
|
||||
<img src={"/images/logo-algolia-nebula-blue-full.svg"} alt="Algolia logo" style={{height: 17, marginLeft: 5, marginTop: 3,}} />
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DiscordChat;
|
||||
@@ -41,7 +41,7 @@ import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
||||
import theme from "../theme.jsx";
|
||||
|
||||
const Files = (props) => {
|
||||
const { globalUrl, userdata, serverside, selectedOrganization, isCloud, } = props;
|
||||
const { globalUrl, userdata, serverside, selectedOrganization, isCloud,isSelectedFiles } = props;
|
||||
|
||||
const [files, setFiles] = React.useState([]);
|
||||
const [selectedNamespace, setSelectedNamespace] = React.useState("default");
|
||||
@@ -59,7 +59,7 @@ const Files = (props) => {
|
||||
const [downloadFolder, setDownloadFolder] = React.useState("translation_standards");
|
||||
|
||||
//const alert = useAlert();
|
||||
const allowedFileTypes = ["txt", "py", "yaml", "yml","json", "html", "js", "csv", "log", "eml", "msg", "md", "xml", "sh", "bat", "ps1", "psm1", "psd1", "ps1xml", "pssc", "psc1"]
|
||||
const allowedFileTypes = ["txt", "py", "yaml", "yml","json", "html", "js", "csv", "log", "eml", "msg", "md", "xml", "sh", "bat", "ps1", "psm1", "psd1", "ps1xml", "pssc", "psc1", "response"]
|
||||
var upload = "";
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
@@ -395,8 +395,6 @@ const Files = (props) => {
|
||||
setTimeout(() => {
|
||||
getFiles();
|
||||
}, 1500);
|
||||
|
||||
console.log(responseJson);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
@@ -619,16 +617,16 @@ const Files = (props) => {
|
||||
style={{
|
||||
maxWidth: window.innerWidth > 1366 ? 1366 : 1200,
|
||||
margin: "auto",
|
||||
padding: 20,
|
||||
padding: isSelectedFiles ? null : 20,
|
||||
}}
|
||||
onDrop={uploadFile}
|
||||
>
|
||||
<div style={{position: "relative"}}>
|
||||
<div style={{position: "relative", width: isSelectedFiles? 1030: null, padding:isSelectedFiles?27:null, height: isSelectedFiles?1200:null, color: isSelectedFiles?'#ffffff':null, backgroundColor: isSelectedFiles?'#212121':null, borderRadius: isSelectedFiles?'16px':null,}}>
|
||||
|
||||
<Tooltip color="primary" title={"Import files to Shuffle from Git"} placement="top">
|
||||
<IconButton
|
||||
color="secondary"
|
||||
style={{position: "absolute", right: 0, top: 0, }}
|
||||
style={{position: "absolute", right: 0, top: isSelectedFiles?null:0, left: isSelectedFiles? 990:null }}
|
||||
variant="text"
|
||||
onClick={() => setLoadFileModalOpen(true)}
|
||||
>
|
||||
@@ -638,15 +636,15 @@ const Files = (props) => {
|
||||
|
||||
{fileDownloadModal}
|
||||
|
||||
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
||||
<h2 style={{ display: "inline" }}>Files</h2>
|
||||
<span style={{ marginLeft: 25 }}>
|
||||
<div style={{ marginTop: isSelectedFiles ? 2: 20, marginBottom:20 }}>
|
||||
<h2 style={{ display: isSelectedFiles ? null : "inline", marginTop: isSelectedFiles?0:null, marginBottom: isSelectedFiles?8:null }}>Files</h2>
|
||||
<span style={{ marginLeft: isSelectedFiles ? null : 25, color:isSelectedFiles?"#9E9E9E":null}}>
|
||||
Files from Workflows are a way to store as well as edit files.{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://shuffler.io/docs/organizations#files"
|
||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||
style={{ textDecoration: isSelectedFiles ? null:"none", color: isSelectedFiles? "#FF8444": "#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
@@ -661,6 +659,7 @@ const Files = (props) => {
|
||||
onClick={() => {
|
||||
upload.click();
|
||||
}}
|
||||
style={{backgroundColor: isSelectedFiles?'rgba(255, 132, 68, 0.2)':null, color:isSelectedFiles?"#FF8444":null, borderRadius:isSelectedFiles?200:null, width:isSelectedFiles?162:null, height:isSelectedFiles?40:null}}
|
||||
>
|
||||
<PublishIcon /> Upload files
|
||||
</Button>
|
||||
@@ -680,7 +679,7 @@ const Files = (props) => {
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
style={{ marginLeft: 5, marginRight: 15 }}
|
||||
style={{ marginLeft: 5, marginRight: 15, backgroundColor:isSelectedFiles?"#2F2F2F":null,borderRadius:isSelectedFiles?200:null, width:isSelectedFiles?81:null, height:isSelectedFiles?40:null, }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => getFiles()}
|
||||
@@ -759,21 +758,21 @@ const Files = (props) => {
|
||||
|
||||
|
||||
{renderTextBox && <TextField
|
||||
onKeyPress={(event)=>{
|
||||
handleKeyDown(event);
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
color="primary"
|
||||
placeholder="File category name"
|
||||
required
|
||||
margin="dense"
|
||||
defaultValue={""}
|
||||
autoFocus
|
||||
/>}</div>
|
||||
onKeyPress={(event)=>{
|
||||
handleKeyDown(event);
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
color="primary"
|
||||
placeholder="File category name"
|
||||
required
|
||||
margin="dense"
|
||||
defaultValue={""}
|
||||
autoFocus
|
||||
/>}</div>
|
||||
|
||||
<ShuffleCodeEditor
|
||||
isCloud={isCloud}
|
||||
@@ -785,20 +784,20 @@ const Files = (props) => {
|
||||
key = {fileContent} //https://reactjs.org/docs/reconciliation.html#recursing-on-children
|
||||
runUpdateText = {runUpdateText}
|
||||
/>
|
||||
|
||||
{isSelectedFiles?null:
|
||||
<Divider
|
||||
style={{
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
}}
|
||||
/>
|
||||
/>}
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<List style={{borderRadius: isSelectedFiles?8:null, border:isSelectedFiles?"1px solid #494949":null, marginTop:isSelectedFiles?24:null}}>
|
||||
<ListItem style={{width:isSelectedFiles?"100%":null, borderBottom:isSelectedFiles?"1px solid #494949":null}}>
|
||||
<ListItemText
|
||||
primary="Updated"
|
||||
style={{ maxWidth: 225, minWidth: 225 }}
|
||||
style={{ maxWidth: 185, minWidth: 185 }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Name"
|
||||
@@ -815,7 +814,7 @@ const Files = (props) => {
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Md5"
|
||||
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }}
|
||||
style={{ minWidth: 250, maxWidth: 250, overflow: "hidden" }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Status"
|
||||
|
||||
@@ -891,6 +891,11 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho
|
||||
const namesplit = regionsplit[0].split("/")
|
||||
|
||||
regiontag = namesplit[namesplit.length - 1]
|
||||
if (regiontag === "california") {
|
||||
regiontag = "us"
|
||||
} else if (regiontag === "frankfurt") {
|
||||
regiontag = "fr"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -551,10 +551,19 @@ const Header = (props) => {
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<BusinessIcon style={{ marginRight: 5 }} /> Admin
|
||||
<BusinessIcon style={{ marginRight: 5 }} /> Organisation
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Divider />
|
||||
<Link to="/settings" style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<SettingsIcon style={{ marginRight: 5 }} /> Account
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Divider style={{marginTop: 10, marginBottom: 10, }} />
|
||||
<Link to="/docs" style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
@@ -584,7 +593,6 @@ const Header = (props) => {
|
||||
<LightbulbIcon style={{ marginRight: 5 }} /> Use Cases
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Divider />
|
||||
<Link to={`/creators/${userdata.public_username}`} style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
@@ -594,16 +602,7 @@ const Header = (props) => {
|
||||
<EmojiObjectsIcon style={{ marginRight: 5 }} /> Creator page
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Link to="/settings" style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<SettingsIcon style={{ marginRight: 5 }} /> Settings
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Divider />
|
||||
<Divider style={{marginTop: 10, marginBottom: 10, }}/>
|
||||
<MenuItem
|
||||
style={{ color: "white" }}
|
||||
onClick={(event) => {
|
||||
@@ -617,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.3
|
||||
Version: 1.4.0
|
||||
</Typography>
|
||||
</Menu>
|
||||
</span>
|
||||
@@ -1052,6 +1051,12 @@ const Header = (props) => {
|
||||
const namesplit = regionsplit[0].split("/");
|
||||
|
||||
regiontag = namesplit[namesplit.length - 1];
|
||||
|
||||
if (regiontag === "california") {
|
||||
regiontag = "us"
|
||||
} else if (regiontag === "frankfurt") {
|
||||
regiontag = "fr"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,7 @@ const OrgHeader = (props) => {
|
||||
: theme.palette.inputColor,
|
||||
maxWidth: 174,
|
||||
maxHeight: 174,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
}}
|
||||
onClick={() => {
|
||||
upload.click();
|
||||
|
||||
@@ -164,6 +164,7 @@ const ParsedAction = (props) => {
|
||||
expansionModalOpen,
|
||||
setExpansionModalOpen,
|
||||
|
||||
apps,
|
||||
setEditorData,
|
||||
setcodedata,
|
||||
setAiQueryModalOpen,
|
||||
@@ -178,6 +179,8 @@ const ParsedAction = (props) => {
|
||||
|
||||
const [autoCompleting, setAutocompleting] = React.useState(false);
|
||||
|
||||
const isIntegration = selectedAction.app_id === "integration"
|
||||
|
||||
useEffect(() => {
|
||||
if (setLastSaved !== undefined) {
|
||||
setLastSaved(false)
|
||||
@@ -1087,29 +1090,113 @@ const ParsedAction = (props) => {
|
||||
var authWritten = false;
|
||||
return (
|
||||
<div style={{ marginTop: hideExtraTypes ? 10 : 30 }}>
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
title={"Click to learn more about this action"}
|
||||
placement="top"
|
||||
{isIntegration ?
|
||||
apps !== undefined && apps !== null && apps.length > 0 ?
|
||||
<div style={{display: "flex", }}>
|
||||
{apps.map((app, appIndex) => {
|
||||
if (app.categories === undefined || app.categories === null || app.categories.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
var found = false
|
||||
var actionname = selectedAction.name.toLowerCase()
|
||||
if (actionname === "email") {
|
||||
actionname = "communication"
|
||||
}
|
||||
|
||||
|
||||
for (var key in app.categories) {
|
||||
if (app.categories[key].toLowerCase() !== actionname) {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return null
|
||||
}
|
||||
|
||||
var isAppSelected = false
|
||||
const paramIndex = selectedAction.parameters.findIndex((param) => param.name === "app_name")
|
||||
if (paramIndex > -1) {
|
||||
// Check the actual value and if it's the same
|
||||
if (selectedAction.parameters[paramIndex].value === app.name) {
|
||||
isAppSelected = true
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div onClick={() => {
|
||||
selectedAction.large_image = app.large_image
|
||||
|
||||
/*
|
||||
if (cy !== undefined) {
|
||||
const foundnode = cy.getElementById(selectedAction.id)
|
||||
if (foundnode !== undefined && foundnode !== null) {
|
||||
foundnode.data("large_image", app.large_image)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (paramIndex === -1) {
|
||||
console.log("Couldn't find app_name parameter")
|
||||
selectedAction.parameters.push({
|
||||
name: "app_name",
|
||||
value: app.name,
|
||||
autocompleted: false,
|
||||
})
|
||||
} else {
|
||||
selectedAction.parameters[paramIndex].value = app.name
|
||||
}
|
||||
|
||||
setSelectedAction(selectedAction)
|
||||
setUpdate(Math.random())
|
||||
|
||||
}}>
|
||||
<Tooltip title={app.name.replace("_", " ", -1)} placement="top">
|
||||
<img
|
||||
src={app.large_image}
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35,
|
||||
marginRight: 5,
|
||||
borderRadius: 5,
|
||||
cursor: "pointer",
|
||||
border: isAppSelected ? "3px solid #86c142" : "2px solid rgba(255,255,255,0.6)",
|
||||
}} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
: null
|
||||
:
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
title={"Click to learn more about this action"}
|
||||
placement="top"
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
color="secondary"
|
||||
style={{justifyContent: "flex-start", textAlign: "left", textTransform: "none", width: "100%",}}
|
||||
fullWidth
|
||||
disabled={selectedAction.description === undefined || selectedAction.description === null || selectedAction.description.length === 0}
|
||||
onClick={() => {
|
||||
setHiddenDescription(!hiddenDescription)
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
color="secondary"
|
||||
style={{justifyContent: "flex-start", textAlign: "left", textTransform: "none", width: "100%",}}
|
||||
fullWidth
|
||||
disabled={selectedAction.description === undefined || selectedAction.description === null || selectedAction.description.length === 0}
|
||||
onClick={() => {
|
||||
setHiddenDescription(!hiddenDescription)
|
||||
}}
|
||||
>
|
||||
<b>Parameters</b>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{selectedAction.template === true && selectedAction.matching_actions !== undefined && selectedAction.matching_actions !== null && selectedAction.matching_actions.length > 0 ?
|
||||
<div>
|
||||
<Typography variant="body1">
|
||||
Select an app you want to use
|
||||
</Typography>
|
||||
<b>Parameters</b>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
{selectedAction.template === true && selectedAction.matching_actions !== undefined && selectedAction.matching_actions !== null && selectedAction.matching_actions.length > 0 ?
|
||||
<div>
|
||||
<Typography variant="body1">
|
||||
Select an app you want to use
|
||||
</Typography>
|
||||
<Autocomplete
|
||||
id="template_action_search"
|
||||
autoHighlight
|
||||
@@ -1235,11 +1322,16 @@ const ParsedAction = (props) => {
|
||||
</Typography>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{selectedActionParameters.map((data, count) => {
|
||||
if (data.variant === "") {
|
||||
data.variant = "STATIC_VALUE";
|
||||
}
|
||||
|
||||
if (isIntegration && data.name === "app_name") {
|
||||
return null
|
||||
}
|
||||
|
||||
// selectedAction.selectedAuthentication = e.target.value
|
||||
// selectedAction.authentication_id = e.target.value.id
|
||||
if (
|
||||
@@ -1288,7 +1380,7 @@ const ParsedAction = (props) => {
|
||||
var staticcolor = "inherit";
|
||||
var actioncolor = "inherit";
|
||||
var varcolor = "inherit";
|
||||
var multiline;
|
||||
var multiline
|
||||
if (
|
||||
data.multiline !== undefined &&
|
||||
data.multiline !== null &&
|
||||
@@ -1297,6 +1389,11 @@ const ParsedAction = (props) => {
|
||||
multiline = true;
|
||||
}
|
||||
|
||||
// make data.value from array to comma separated string if it is an array
|
||||
if (data.value !== undefined && data.value !== null && Array.isArray(data.value)) {
|
||||
data.value = data.value.join(",")
|
||||
}
|
||||
|
||||
if (
|
||||
data.value !== undefined &&
|
||||
data.value !== null &&
|
||||
@@ -2003,6 +2100,13 @@ const ParsedAction = (props) => {
|
||||
changeActionParameter(e, count, data);
|
||||
}
|
||||
|
||||
var multi = false
|
||||
if (selectedActionParameters[count].multiselect !== undefined && selectedActionParameters[count].multiselect !== null && selectedActionParameters[count].multiselect === true) {
|
||||
multi = true
|
||||
|
||||
selectedActionParameters[count].value = selectedActionParameters[count].value.split(",")
|
||||
}
|
||||
|
||||
datafield = (
|
||||
<Select
|
||||
MenuProps={{
|
||||
@@ -2012,10 +2116,13 @@ const ParsedAction = (props) => {
|
||||
style: {
|
||||
},
|
||||
}}
|
||||
multiple={multi}
|
||||
value={selectedActionParameters[count].value}
|
||||
fullWidth
|
||||
id={"rightside_field_" + count}
|
||||
onChange={(e) => {
|
||||
console.log("MULTI SELECT: ", multi, e.target.value)
|
||||
|
||||
changeActionParameter(e, count, data);
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
@@ -2029,11 +2136,13 @@ const ParsedAction = (props) => {
|
||||
{parsedoptions.map(
|
||||
(data, index) => {
|
||||
const split_data = data.split("||");
|
||||
var viewed_data = data;
|
||||
var viewed_data = data
|
||||
if (split_data.length > 1) {
|
||||
viewed_data = split_data[0];
|
||||
viewed_data = split_data[0]
|
||||
}
|
||||
|
||||
viewed_data = (viewed_data.charAt(0).toUpperCase() + viewed_data.slice(1)).replaceAll("_", " ")
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={data}
|
||||
@@ -2774,9 +2883,11 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
|
||||
// Gets the most important actions first
|
||||
const renderedActionOptions = deduplicateByName((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"))).sort(sortByCategoryLabel))
|
||||
|
||||
|
||||
const renderedActionOptions = deduplicateByName((
|
||||
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"))
|
||||
).sort(sortByCategoryLabel))
|
||||
|
||||
var baselabel = selectedAction.label;
|
||||
return (
|
||||
@@ -3000,16 +3111,16 @@ const ParsedAction = (props) => {
|
||||
</Tooltip>
|
||||
*/}
|
||||
{selectedApp.versions !== null &&
|
||||
selectedApp.versions !== undefined &&
|
||||
selectedApp.versions.length > 1 ? (
|
||||
selectedApp.versions !== undefined &&
|
||||
selectedApp.versions.length > 1 ? (
|
||||
<Select
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
defaultValue={selectedAction.app_version}
|
||||
onChange={(event) => {
|
||||
console.log("VAL: ", event.target.value)
|
||||
console.log("App: ", selectedApp)
|
||||
console.log("VAL: ", event.target.value)
|
||||
console.log("App: ", selectedApp)
|
||||
const newversion = selectedApp.versions.find(
|
||||
(tmpApp) => tmpApp.version == event.target.value
|
||||
);
|
||||
@@ -3051,15 +3162,6 @@ const ParsedAction = (props) => {
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<Divider
|
||||
style={{
|
||||
marginBottom: "10px",
|
||||
marginTop: "10px",
|
||||
height: "1px",
|
||||
width: "100%",
|
||||
backgroundColor: "rgb(91, 96, 100)",
|
||||
}}
|
||||
/>
|
||||
<div style={{display: "flex"}}>
|
||||
<div style={{flex: 5}}>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Name</Typography>
|
||||
@@ -3308,10 +3410,10 @@ const ParsedAction = (props) => {
|
||||
</span>
|
||||
)}
|
||||
{selectedApp.name !== undefined &&
|
||||
selectedAction.authentication !== null &&
|
||||
selectedAction.authentication !== undefined &&
|
||||
selectedAction.authentication.length === 0 &&
|
||||
requiresAuthentication ? (
|
||||
selectedAction.authentication !== null &&
|
||||
selectedAction.authentication !== undefined &&
|
||||
selectedAction.authentication.length === 0 &&
|
||||
requiresAuthentication ? (
|
||||
<div style={{ marginTop: 15 }}>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
@@ -3466,13 +3568,13 @@ const ParsedAction = (props) => {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showEnvironment !== undefined && showEnvironment && environments.length > 1 ? (
|
||||
{showEnvironment !== undefined && showEnvironment && environments.length > 1 && !isIntegration ? (
|
||||
<div style={{ marginTop: "20px" }}>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Environment</Typography>
|
||||
<Select
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
value={
|
||||
selectedActionEnvironment === undefined || selectedActionEnvironment === null ||
|
||||
selectedActionEnvironment.Name === undefined || selectedActionEnvironment.Name === null
|
||||
@@ -3629,7 +3731,6 @@ const ParsedAction = (props) => {
|
||||
return option.category_label !== undefined && option.category_label !== null && option.category_label.length > 0 ? "Most used" : "All Actions";
|
||||
}}
|
||||
renderGroup={(params) => {
|
||||
//return null
|
||||
|
||||
return (
|
||||
<li key={params.key}>
|
||||
@@ -3807,7 +3908,7 @@ const ParsedAction = (props) => {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
label="Find Actions"
|
||||
label={isIntegration ? "Choose a category" : "Find Actions"}
|
||||
variant="outlined"
|
||||
name={`disable_autocomplete_${Math.random()}`}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import Priority from "../components/Priority.jsx";
|
||||
//import { useAlert
|
||||
|
||||
const Priorities = (props) => {
|
||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, notifications, setNotifications, } = props;
|
||||
const { globalUrl, userdata,clickedFromOrgTab, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, notifications, setNotifications, } = props;
|
||||
const [showDismissed, setShowDismissed] = React.useState(false);
|
||||
const [showRead, setShowRead] = React.useState(false);
|
||||
const [appFramework, setAppFramework] = React.useState({});
|
||||
@@ -312,15 +312,15 @@ const Priorities = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{maxWidth: 1000, }}>
|
||||
<h2 style={{ display: "inline" }}>Suggestions</h2>
|
||||
<span style={{ marginLeft: 25 }}>
|
||||
Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. These range from simple configurations in Shuffle to Usecases you may have missed.
|
||||
<div style={{maxWidth: clickedFromOrgTab ? 1030:1000, padding: clickedFromOrgTab ? 27:null, height: clickedFromOrgTab ? "auto":null, backgroundColor: clickedFromOrgTab ? '#212121':null, borderRadius: clickedFromOrgTab ? '16px':null, }}>
|
||||
<h2 style={{ display: clickedFromOrgTab ?null:"inline", marginBottom: clickedFromOrgTab ? 8:null, marginTop: clickedFromOrgTab ?0:null, color: clickedFromOrgTab ?"#ffffff":null }}>Suggestions</h2>
|
||||
<span style={{ color: clickedFromOrgTab ?"#9E9E9E":null,marginLeft: clickedFromOrgTab ?null:25 }}>
|
||||
Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. <br/>These range from simple configurations in Shuffle to Usecases you may have missed.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#priorities"
|
||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||
style={{ textDecoration: clickedFromOrgTab ?null:"none", color: clickedFromOrgTab ?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
@@ -348,6 +348,7 @@ const Priorities = (props) => {
|
||||
globalUrl={globalUrl}
|
||||
priority={priority}
|
||||
checkLogin={checkLogin}
|
||||
clickedFromOrgTab={true}
|
||||
setAdminTab={setAdminTab}
|
||||
setCurTab={setCurTab}
|
||||
appFramework={appFramework}
|
||||
@@ -355,15 +356,15 @@ const Priorities = (props) => {
|
||||
)
|
||||
})
|
||||
}
|
||||
<Divider style={{marginTop: 50, marginBottom: 50, }} />
|
||||
<h2 style={{ display: "inline" }}>Notifications</h2>
|
||||
<span style={{ marginLeft: 25 }}>
|
||||
{clickedFromOrgTab?null:<Divider style={{marginTop: 50, marginBottom: 50, }} />}
|
||||
<h2 style={{ display: clickedFromOrgTab?null:"inline", marginBottom: clickedFromOrgTab? 8:null, marginTop: clickedFromOrgTab?40:null, color: clickedFromOrgTab?"#ffffff":null }}>Notifications</h2>
|
||||
<span style={{ marginLeft: clickedFromOrgTab?null:25, color: clickedFromOrgTab?"#9E9E9E":null, }}>
|
||||
Notifications help you find potential problems with your workflows and apps.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#notifications"
|
||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||
style={{ textDecoration: clickedFromOrgTab?null:"none", color: clickedFromOrgTab?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
//import { useAlert
|
||||
|
||||
const Priority = (props) => {
|
||||
const { globalUrl, userdata, serverside, priority, checkLogin, setAdminTab, setCurTab, appFramework, } = props;
|
||||
const { globalUrl, clickedFromOrgTab,userdata, serverside, priority, checkLogin, setAdminTab, setCurTab, appFramework, } = props;
|
||||
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
let navigate = useNavigate();
|
||||
@@ -114,7 +114,7 @@ const Priority = (props) => {
|
||||
const srcSize = realignedSrc ? 35 : 30
|
||||
const dstSize = realignedDst ? 35 : 30
|
||||
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", minHeight: isCloud ? 70 : 100, maxHeight: isCloud ? 70 : 100, textAlign: "left", backgroundColor: theme.palette.surfaceColor, display: "flex", }}>
|
||||
<div style={{border: priority.active === false ? "1px solid #000000" : priority.severity === 1 ? "1px solid #f85a3e" : clickedFromOrgTab ?null:"1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette.borderRadius, marginTop: 10, marginBottom: 10, padding: clickedFromOrgTab ? 24:15, textAlign: "center", minHeight: isCloud ? 70 : 100, maxHeight: isCloud ? 70 : 100, textAlign: "left", backgroundColor: clickedFromOrgTab ? "#1A1A1A": 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}
|
||||
@@ -147,7 +147,7 @@ const Priority = (props) => {
|
||||
}
|
||||
</div>
|
||||
<div style={{flex: 1, display: "flex", marginLeft: 30, }}>
|
||||
<Button style={{height: 50, borderRadius: 25, marginTop: 8, width: 175, marginRight: 10, color: priority.active === false ? "white" : "black", backgroundColor: priority.active === false ? theme.palette.inputColor : "rgba(255,255,255,0.8)", }} variant="contained" color="secondary" onClick={() => {
|
||||
<Button style={{height: 50, borderRadius: 25, marginTop: 8, width: 175, marginRight: 10, color: priority.active === false ? "white" :clickedFromOrgTab ?"#FF8444": "black", backgroundColor: priority.active === false ? theme.palette.inputColor :clickedFromOrgTab?"rgba(255, 132, 68, 0.2)":"rgba(255,255,255,0.8)", }} variant="contained" color="secondary" onClick={() => {
|
||||
|
||||
if (isCloud) {
|
||||
ReactGA.event({
|
||||
|
||||
@@ -38,6 +38,15 @@ import {
|
||||
} from '@mui/icons-material';
|
||||
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'
|
||||
import {
|
||||
Search as SearchIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import {
|
||||
InputAdornment,
|
||||
} from "@mui/material"
|
||||
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
notchedOutline: {
|
||||
@@ -150,7 +159,6 @@ const RuntimeDebugger = (props) => {
|
||||
|
||||
const submitSearch = (workflowId, status, startTime, endTime, cursor, limit) => {
|
||||
handleWorkflowUsageCount(workflows)
|
||||
|
||||
//setResultRows([])
|
||||
setSearchLoading(true)
|
||||
const fetchData = {
|
||||
@@ -294,7 +302,6 @@ const RuntimeDebugger = (props) => {
|
||||
toast(`Failed to force continue: ${error}`)
|
||||
})
|
||||
}
|
||||
|
||||
const imageSize = 30
|
||||
const timenowUnix = Math.floor(Date.now() / 1000)
|
||||
const columns: GridColDef[] = [
|
||||
@@ -696,11 +703,130 @@ const RuntimeDebugger = (props) => {
|
||||
});
|
||||
}
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [filteredRows, setFilteredRows] = useState([]);
|
||||
const [defaultRows, setDefaultRows] = useState([]);
|
||||
|
||||
const handleQueryChange = (e) => {
|
||||
const query = e.target.value.toLowerCase();
|
||||
setSearchQuery(query);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setDefaultRows(resultRows);
|
||||
}, [resultRows]);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchQuery.trim() === "") {
|
||||
setFilteredRows(defaultRows);
|
||||
} else {
|
||||
const filterRow = defaultRows.filter((data) => {
|
||||
|
||||
//Filter workflow base on the workflow status
|
||||
if (data.status.toLowerCase().includes(searchQuery)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Filter workflow base on workflow name
|
||||
if (data.workflow.name.toLowerCase().includes(searchQuery)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Filter the workflow base on execution argument
|
||||
if (data.execution_argument && data.execution_argument.length > 0) {
|
||||
if (data.execution_argument.toLowerCase().includes(searchQuery)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Filter the workflow base on the result
|
||||
if (data.results && data.results.length > 0) {
|
||||
for (let result of data.results) {
|
||||
if (result && result.result && result.result.toLowerCase().includes(searchQuery)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
setFilteredRows(filterRow);
|
||||
}
|
||||
}, [searchQuery, defaultRows]);
|
||||
|
||||
return (
|
||||
<div style={{minWidth: 1150, maxWidth: 1150, margin: "auto", }}>
|
||||
|
||||
<div style={{display: "flex", }}>
|
||||
<div style={{display: 'flex', flexDirection: 'column'}}>
|
||||
<h1 style={{flex: 3, }}>Workflow Run Debugger {totalCount !== 0 ? ` (~${totalCount})` : ""}</h1>
|
||||
<div style={{position: 'relative', right: 10, marginBottom: 10}}>
|
||||
<TextField
|
||||
fullWidth
|
||||
value={searchQuery}
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginTop: 20,
|
||||
marginLeft: 10,
|
||||
marginRight: 12,
|
||||
width: 693,
|
||||
height: 55,
|
||||
borderRadius: 8,
|
||||
fontSize: 16,
|
||||
marginBottom: 15,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
fontSize: "1em",
|
||||
height: 55,
|
||||
width: 693,
|
||||
borderRadius: 8,
|
||||
},
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon style={{ marginLeft: 5}} />
|
||||
</InputAdornment>
|
||||
),
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{searchQuery.length > 0 && (
|
||||
<ClearIcon
|
||||
style={{
|
||||
color: "white",
|
||||
cursor: "pointer",
|
||||
marginRight: 10
|
||||
}}
|
||||
onClick={() => setSearchQuery('')}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(to right, rgb(248, 106, 62), rgb(243, 64, 121))",
|
||||
color: "white",
|
||||
border: "none",
|
||||
padding: "10px 20px",
|
||||
width: 100,
|
||||
height: 35,
|
||||
borderRadius: 17.5,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</InputAdornment>
|
||||
),
|
||||
|
||||
}}
|
||||
onChange={(e)=>{handleQueryChange(e)}}
|
||||
color="primary"
|
||||
placeholder="Search Workflow Name, Status, Execution Argument, Results.."
|
||||
id="shuffle_search_field"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{selectedWorkflowExecutions.length > 0 ?
|
||||
<ButtonGroup>
|
||||
<Tooltip title="Reruns ALL selected workflows. This will make a new execution for them, and not continue the existing.">
|
||||
@@ -952,7 +1078,7 @@ const RuntimeDebugger = (props) => {
|
||||
</form>
|
||||
<div style={{height: 700, padding: "10px 0px 10px 0px", }}>
|
||||
<DataGrid
|
||||
rows={resultRows}
|
||||
rows={filteredRows}
|
||||
columns={columns}
|
||||
pageSize={rowsPerPage}
|
||||
rowsPerPageOptions={[10, 20, 50, 100]}
|
||||
|
||||
@@ -715,6 +715,64 @@ const SearchData = props => {
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
const DiscordHits = ({ hits }) => {
|
||||
const [mouseHoverIndex, setMouseHoverIndex] = useState(0);
|
||||
var tmp = searchOpen
|
||||
if (!searchOpen) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
const positionInfo = document.activeElement.getBoundingClientRect()
|
||||
const outerlistitemStyle = {
|
||||
width: "100%",
|
||||
overflowX: "hidden",
|
||||
overflowY: "hidden",
|
||||
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
||||
}
|
||||
|
||||
if (hits.length > 4) {
|
||||
hits = hits.slice(0, 4)
|
||||
}
|
||||
const type = "Discord Text"
|
||||
const handleHitClick = (url) => {
|
||||
const modifiedUrl = url.replace('https://ptb.discord.com/', 'https://discord.com/');
|
||||
window.open(modifiedUrl, '_blank');
|
||||
};
|
||||
return (
|
||||
<Card elevation={0} style={{ marginRight: 10, marginTop: 50, color: "white", zIndex: 1002, backgroundColor: theme.palette.inputColor, width: "100%", left: 470, boxShadows: "none", }}>
|
||||
<Typography variant="h6" style={{ margin: "10px 10px 0px 20px", color: "#FF8444", borderBottom: "1px solid", width: 152 }}>
|
||||
Discord Chat
|
||||
</Typography>
|
||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
||||
{hits.length === 0 ?
|
||||
<ListItem style={outerlistitemStyle}>
|
||||
<ListItemAvatar onClick={() => console.log(hits)}>
|
||||
<Avatar>
|
||||
<FolderIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={"No results found?"}
|
||||
secondary={"Try refining your search."}
|
||||
/>
|
||||
</ListItem>:
|
||||
hits.map((chat, index) => (
|
||||
<ListItem onClick={() => handleHitClick(chat.url)} key={index} style={{ cursor: "pointer", borderBottom: "1px solid rgba(255,255,255,0.4)" }} onMouseOver={() => setMouseHoverIndex(index)}>
|
||||
<ListItemAvatar>
|
||||
<Avatar src="/discord-logo.png" />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={chat.text}
|
||||
secondary={`User: ${(chat.user)}`}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
const gettingStartData = !searchOpen ? (
|
||||
<Grid
|
||||
container
|
||||
@@ -812,6 +870,7 @@ const SearchData = props => {
|
||||
const CustomAppHits = connectHits(AppHits)
|
||||
const CustomWorkflowHits = connectHits(WorkflowHits)
|
||||
const CustomDocHits = connectHits(DocHits)
|
||||
const CustomDiscordHits = connectHits(DiscordHits);
|
||||
|
||||
const modalView = (
|
||||
<div>
|
||||
@@ -831,6 +890,11 @@ const SearchData = props => {
|
||||
<CustomDocHits />
|
||||
</Index>
|
||||
</Grid>
|
||||
<Grid item xs="auto" style={{}}>
|
||||
<Index indexName="discord_chat">
|
||||
<CustomDiscordHits />
|
||||
</Index>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -54,12 +54,14 @@ import { tags as t } from '@lezer/highlight';
|
||||
|
||||
|
||||
import AceEditor from "react-ace";
|
||||
import ace from "ace-builds";
|
||||
import 'ace-builds/src-noconflict/mode-python';
|
||||
//import 'ace-builds/src-noconflict/theme-twilight';
|
||||
//import 'ace-builds/src-noconflict/theme-solarized_dark';
|
||||
import 'ace-builds/src-noconflict/theme-gruvbox';
|
||||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
import ace from "ace-builds";
|
||||
|
||||
import "ace-builds/src-noconflict/ext-searchbox";
|
||||
|
||||
const liquidFilters = [
|
||||
{"name": "Default", "value": `default: []`, "example": `{{ "" | default: "no input" }}`},
|
||||
@@ -1033,7 +1035,7 @@ const CodeEditor = (props) => {
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
>
|
||||
File Editor
|
||||
File Editor ({localcodedata.length})
|
||||
</DialogTitle>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1174,6 +1176,7 @@ const CodeEditor = (props) => {
|
||||
</Menu>
|
||||
</div>
|
||||
}
|
||||
|
||||
<Button
|
||||
id="basic-button"
|
||||
aria-haspopup="true"
|
||||
@@ -1443,132 +1446,129 @@ const CodeEditor = (props) => {
|
||||
})}
|
||||
</Menu>
|
||||
</div>
|
||||
}
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: isMobile ? "80%" : 30,
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
onClick={() => {
|
||||
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Test Liquid in the playground"}
|
||||
placement="top"
|
||||
>
|
||||
<a
|
||||
href="https://pwwang.github.io/liquidpy/playground/"
|
||||
rel="norefferer"
|
||||
target="_blank"
|
||||
>
|
||||
<ExtensionIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
style={{
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
disabled={isAiLoading}
|
||||
onClick={() => {
|
||||
autoFormat(localcodedata)
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Auto format data"}
|
||||
placement="top"
|
||||
>
|
||||
{isAiLoading ?
|
||||
<CircularProgress style={{height: 20, width: 20, color: "rgba(255,255,255,0.7)"}}/>
|
||||
:
|
||||
<AutoFixHighIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
}
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/*
|
||||
<div ref={editorRef}></div>
|
||||
*/}
|
||||
|
||||
<div style={{
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
position: "relative",
|
||||
paddingTop: 0,
|
||||
// minHeight: 548,
|
||||
// overflow: "hidden",
|
||||
}}>
|
||||
{availableVariables !== undefined && availableVariables !== null && availableVariables.length > 0 &&
|
||||
<AceEditor
|
||||
value={localcodedata}
|
||||
mode={selectedAction.name === "execute_python" ? "python" : ""}
|
||||
theme="gruvbox"
|
||||
height={isFileEditor ? 450 : 550}
|
||||
width={isFileEditor ? 650 : "100%"}
|
||||
|
||||
markers={markers}
|
||||
highlightActiveLine={false}
|
||||
|
||||
enableBasicAutocompletion={true}
|
||||
completers={[customCompleter]}
|
||||
|
||||
style={{
|
||||
wordBreak: "break-word",
|
||||
marginTop: 0,
|
||||
paddingBottom: 10,
|
||||
overflowY: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
wordWrap: "break-word",
|
||||
backgroundColor: "rgba(40,40,40,1)",
|
||||
}}
|
||||
onLoad={(editor) => {
|
||||
highlight_variables(localcodedata)
|
||||
}}
|
||||
onCursorChange={(cursorPosition, editor, value) => {
|
||||
setCurrentCharacter(cursorPosition.column)
|
||||
setCurrentLine(cursorPosition.row)
|
||||
findIndex(cursorPosition.row, cursorPosition.column)
|
||||
|
||||
highlight_variables(localcodedata)
|
||||
//console.log("VALUE CURSOR: ", value)
|
||||
}}
|
||||
onChange={(value, editor) => {
|
||||
// setlocalcodedata(value)
|
||||
// expectedOutput(value)
|
||||
// highlight_variables(value,editor)
|
||||
setlocalcodedata(value)
|
||||
expectedOutput(value)
|
||||
highlight_variables(value)
|
||||
}}
|
||||
setOptions={{
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
showLineNumbers: true,
|
||||
tabSize: 2,
|
||||
wrap: true,
|
||||
|
||||
useWorker: false,
|
||||
enableBasicAutocompletion: [customCompleter],
|
||||
}}
|
||||
// options={options}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: isMobile ? "80%" : 30,
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
onClick={() => {
|
||||
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Test Liquid in the playground"}
|
||||
placement="top"
|
||||
>
|
||||
<a
|
||||
href="https://pwwang.github.io/liquidpy/playground/"
|
||||
rel="norefferer"
|
||||
target="_blank"
|
||||
>
|
||||
<ExtensionIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
style={{
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
disabled={isAiLoading}
|
||||
onClick={() => {
|
||||
autoFormat(localcodedata)
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Auto format data"}
|
||||
placement="top"
|
||||
>
|
||||
{isAiLoading ?
|
||||
<CircularProgress style={{height: 20, width: 20, color: "rgba(255,255,255,0.7)"}}/>
|
||||
:
|
||||
<AutoFixHighIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
}
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div style={{
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
position: "relative",
|
||||
paddingTop: 0,
|
||||
// minHeight: 548,
|
||||
// overflow: "hidden",
|
||||
}}>
|
||||
{(availableVariables !== undefined && availableVariables !== null && availableVariables.length > 0) || isFileEditor ? (
|
||||
<AceEditor
|
||||
value={localcodedata}
|
||||
mode={selectedAction === undefined ? "" : selectedAction.name === "execute_python" ? "python" : ""}
|
||||
theme="gruvbox"
|
||||
height={isFileEditor ? 450 : 550}
|
||||
width={isFileEditor ? 650 : "100%"}
|
||||
|
||||
markers={markers}
|
||||
highlightActiveLine={false}
|
||||
|
||||
enableBasicAutocompletion={true}
|
||||
completers={[customCompleter]}
|
||||
|
||||
style={{
|
||||
wordBreak: "break-word",
|
||||
marginTop: 0,
|
||||
paddingBottom: 10,
|
||||
overflowY: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
wordWrap: "break-word",
|
||||
backgroundColor: "rgba(40,40,40,1)",
|
||||
}}
|
||||
onLoad={(editor) => {
|
||||
highlight_variables(localcodedata)
|
||||
}}
|
||||
onCursorChange={(cursorPosition, editor, value) => {
|
||||
setCurrentCharacter(cursorPosition.column)
|
||||
setCurrentLine(cursorPosition.row)
|
||||
findIndex(cursorPosition.row, cursorPosition.column)
|
||||
|
||||
highlight_variables(localcodedata)
|
||||
//console.log("VALUE CURSOR: ", value)
|
||||
}}
|
||||
onChange={(value, editor) => {
|
||||
// setlocalcodedata(value)
|
||||
// expectedOutput(value)
|
||||
// highlight_variables(value,editor)
|
||||
setlocalcodedata(value)
|
||||
expectedOutput(value)
|
||||
highlight_variables(value)
|
||||
}}
|
||||
setOptions={{
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
showLineNumbers: true,
|
||||
tabSize: 2,
|
||||
wrap: true,
|
||||
|
||||
useWorker: false,
|
||||
enableBasicAutocompletion: [customCompleter],
|
||||
}}
|
||||
// options={options}
|
||||
/>
|
||||
): null}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isFileEditor ? null :
|
||||
<div style={{flex: 1, marginLeft: 5, borderLeft: "1px solid rgba(255,255,255,0.3)", paddingLeft: 5, }}>
|
||||
|
||||
@@ -1261,15 +1261,15 @@ const UsecaseSearch = (props) => {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Failed to activate")
|
||||
}
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
toast("Failed to activate the app")
|
||||
var msgString = "Failed to activate the app"
|
||||
if (responseJson.reason !== undefined) {
|
||||
msgString += ": " + responseJson.reason
|
||||
}
|
||||
toast(msgString)
|
||||
} else {
|
||||
//toast("App activated for your organization! Refresh the page to use the app.")
|
||||
}
|
||||
|
||||
@@ -28,10 +28,11 @@ const theme = createTheme(adaptV4Theme({
|
||||
defaultBorder: "1px solid rgba(255,255,255,0.3)",
|
||||
jsonTheme: "brewer",
|
||||
reactJsonStyle: {
|
||||
borderRadius: 5,
|
||||
border: "1px solid rgba(255,255,255,0.7)",
|
||||
padding: 5,
|
||||
width: "100%",
|
||||
borderRadius: 5,
|
||||
border: "1px solid rgba(255,255,255,0.7)",
|
||||
overflowX: "auto",
|
||||
},
|
||||
textFieldStyle: {
|
||||
backgroundColor: "#383B40",
|
||||
|
||||
+2670
-1917
File diff suppressed because it is too large
Load Diff
@@ -235,8 +235,7 @@ export const triggers = [
|
||||
long_description: "Controls a pipeline to run things",
|
||||
},
|
||||
];
|
||||
// is_valid: cloudSyncEnabled || isCloud ? true : false,
|
||||
|
||||
|
||||
// http://apps.cytoscape.org/apps/yfileslayoutalgorithms
|
||||
cytoscape.use(edgehandles);
|
||||
//cytoscape.use(clipboard);
|
||||
@@ -549,7 +548,89 @@ const AngularWorkflow = (defaultprops) => {
|
||||
},
|
||||
"open": false,
|
||||
"attachedTo": "",
|
||||
});
|
||||
})
|
||||
|
||||
// New for generated stuff
|
||||
const integrationApps = [{
|
||||
"id": "integration",
|
||||
"name": "Integration Framework",
|
||||
"type": "ACTION",
|
||||
"app_version": "1.0.0",
|
||||
"loop_versions": ["1.0.0"],
|
||||
"authentication": {
|
||||
"type": "",
|
||||
},
|
||||
"description": "Support-use only",
|
||||
"actions": [{
|
||||
"name": "Cases",
|
||||
"description": "Available actions for case management",
|
||||
"label": "Cases",
|
||||
"parameters": [{
|
||||
"name": "action",
|
||||
"value": "list_tickets",
|
||||
"options": [
|
||||
"list_tickets",
|
||||
"get_ticket",
|
||||
"create_ticket",
|
||||
],
|
||||
"required": true,
|
||||
},
|
||||
{
|
||||
"name": "fields",
|
||||
"value": "",
|
||||
"required": false,
|
||||
"multiline": true,
|
||||
},
|
||||
/*{
|
||||
"name": "options",
|
||||
"value": "deduplicate,enrich",
|
||||
"required": false,
|
||||
"multiselect": true,
|
||||
"options": [
|
||||
"deduplicate",
|
||||
"enrich",
|
||||
]
|
||||
}*/
|
||||
]
|
||||
},{
|
||||
"name": "Communication",
|
||||
"description": "Available actions for communication",
|
||||
"label": "Communication",
|
||||
"parameters": [{
|
||||
"name": "action",
|
||||
"value": "list_messages",
|
||||
"options": [
|
||||
"list_messages",
|
||||
"send_message",
|
||||
],
|
||||
"required": true,
|
||||
},
|
||||
{
|
||||
"name": "fields",
|
||||
"value": "",
|
||||
"required": false,
|
||||
"multiline": true,
|
||||
}]
|
||||
},
|
||||
]
|
||||
}]
|
||||
|
||||
/*
|
||||
{
|
||||
"name": "Email",
|
||||
"label": "Email",
|
||||
"parameters": [{
|
||||
"name": "action",
|
||||
"value": "list_email",
|
||||
"options": [
|
||||
"list_email",
|
||||
"send_mail",
|
||||
],
|
||||
"required": true,
|
||||
}],
|
||||
}]
|
||||
}]
|
||||
*/
|
||||
|
||||
// For code editor
|
||||
const [codeEditorModalOpen, setCodeEditorModalOpen] = React.useState(false);
|
||||
@@ -577,8 +658,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Checking to update app with useeffect.")
|
||||
|
||||
for (let appkey in apps) {
|
||||
const curapp = apps[appkey]
|
||||
if (curapp.name !== selectedApp.name) {
|
||||
@@ -610,6 +689,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
setSelectedApp(curapp)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1539,34 +1619,38 @@ const AngularWorkflow = (defaultprops) => {
|
||||
curworkflowAction.position = cyelements[cyelementsKey].position();
|
||||
|
||||
// workaround to fix some edgecases
|
||||
if (
|
||||
curworkflowAction.parameters === "" ||
|
||||
curworkflowAction.parameters === null
|
||||
) {
|
||||
curworkflowAction.parameters = [];
|
||||
}
|
||||
if (
|
||||
curworkflowAction.parameters === "" ||
|
||||
curworkflowAction.parameters === null
|
||||
) {
|
||||
curworkflowAction.parameters = [];
|
||||
}
|
||||
|
||||
if (
|
||||
curworkflowAction.example === undefined ||
|
||||
curworkflowAction.example === "" ||
|
||||
curworkflowAction.example === null
|
||||
) {
|
||||
if (cyelements[cyelementsKey].data().example !== undefined) {
|
||||
curworkflowAction.example = cyelements[cyelementsKey].data().example;
|
||||
}
|
||||
}
|
||||
if (
|
||||
curworkflowAction.example === undefined ||
|
||||
curworkflowAction.example === "" ||
|
||||
curworkflowAction.example === null
|
||||
) {
|
||||
if (cyelements[cyelementsKey].data().example !== undefined) {
|
||||
curworkflowAction.example = cyelements[cyelementsKey].data().example;
|
||||
}
|
||||
}
|
||||
|
||||
// Override just in this place
|
||||
curworkflowAction.errors = [];
|
||||
curworkflowAction.isValid = true;
|
||||
|
||||
// Cleans up OpenAPI items
|
||||
var newparams = [];
|
||||
for (let parametersKey in curworkflowAction.parameters) {
|
||||
const thisitem = curworkflowAction.parameters[parametersKey];
|
||||
if (thisitem.name.startsWith("${") && thisitem.name.endsWith("}")) {
|
||||
continue;
|
||||
}
|
||||
// Cleans up OpenAPI items
|
||||
var newparams = [];
|
||||
for (let parametersKey in curworkflowAction.parameters) {
|
||||
const thisitem = curworkflowAction.parameters[parametersKey];
|
||||
if (thisitem.name.startsWith("${") && thisitem.name.endsWith("}")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thisitem.value !== undefined && thisitem.value !== null && Array.isArray(thisitem.value)) {
|
||||
thisitem.value = thisitem.value.join(",")
|
||||
}
|
||||
|
||||
newparams.push(thisitem);
|
||||
}
|
||||
@@ -1578,17 +1662,17 @@ const AngularWorkflow = (defaultprops) => {
|
||||
useworkflow.triggers = [];
|
||||
}
|
||||
|
||||
var curworkflowTrigger = useworkflow.triggers.find(
|
||||
(a) => a.id === cyelements[cyelementsKey].data()["id"]
|
||||
);
|
||||
if (curworkflowTrigger === undefined) {
|
||||
curworkflowTrigger = cyelements[cyelementsKey].data();
|
||||
}
|
||||
var curworkflowTrigger = useworkflow.triggers.find(
|
||||
(a) => a.id === cyelements[cyelementsKey].data()["id"]
|
||||
);
|
||||
if (curworkflowTrigger === undefined) {
|
||||
curworkflowTrigger = cyelements[cyelementsKey].data();
|
||||
}
|
||||
|
||||
curworkflowTrigger.position = cyelements[cyelementsKey].position();
|
||||
if (curworkflowTrigger.canConnect === false) {
|
||||
continue
|
||||
}
|
||||
curworkflowTrigger.position = cyelements[cyelementsKey].position();
|
||||
if (curworkflowTrigger.canConnect === false) {
|
||||
continue
|
||||
}
|
||||
|
||||
newTriggers.push(curworkflowTrigger);
|
||||
} else if (type === "COMMENT") {
|
||||
@@ -2087,6 +2171,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const pretend_apps = [{
|
||||
"name": "TBD",
|
||||
"id": "TBD",
|
||||
"app_name": "TBD",
|
||||
"app_version": "TBD",
|
||||
"description": "TBD",
|
||||
@@ -2113,6 +2198,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
console.log("No response")
|
||||
const pretend_apps = [{
|
||||
"name": "TBD",
|
||||
"id": "TBD",
|
||||
"app_name": "TBD",
|
||||
"app_version": "TBD",
|
||||
"description": "TBD",
|
||||
@@ -2131,42 +2217,53 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
// Used for e.g. Liquid testing
|
||||
// Used for e.g. Liquid testing
|
||||
const foundTools = responseJson.find((app) => app.name === "Shuffle Tools")
|
||||
if (foundTools !== undefined && foundTools !== null) {
|
||||
setToolsApp(foundTools)
|
||||
}
|
||||
|
||||
setApps(responseJson);
|
||||
// Set localstorage for the apps in the "apps" key
|
||||
if (responseJson !== undefined && responseJson !== null && responseJson.length > 0) {
|
||||
try {
|
||||
localStorage.setItem("apps", JSON.stringify(responseJson))
|
||||
} catch (e) {
|
||||
console.log("Failed to set apps in localstorage: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
var handledPrioritizedApps = responseJson.filter((app) => internalIds.includes(app.name.toLowerCase()));
|
||||
handledPrioritizedApps = [].concat(integrationApps, handledPrioritizedApps)
|
||||
|
||||
if (isCloud) {
|
||||
setFilteredApps(responseJson.filter((app) => !internalIds.includes(app.name.toLowerCase())));
|
||||
setPrioritizedApps(responseJson.filter((app) => internalIds.includes(app.name.toLowerCase())));
|
||||
setPrioritizedApps(handledPrioritizedApps)
|
||||
|
||||
} else {
|
||||
var tmpFiltered = responseJson.filter((app) => !internalIds.includes(app.name.toLowerCase()))
|
||||
setFilteredApps(tmpFiltered)
|
||||
setPrioritizedApps(responseJson.filter((app) => internalIds.includes(app.name.toLowerCase())));
|
||||
setPrioritizedApps(handledPrioritizedApps)
|
||||
}
|
||||
|
||||
setAppsLoaded(true)
|
||||
|
||||
// Remove all cytoscape triggers first?
|
||||
if (cy !== undefined && cy !== null) {
|
||||
cy.removeListener("select");
|
||||
cy.removeListener("select")
|
||||
}
|
||||
|
||||
// Re-adding cytoscape triggers
|
||||
if (cy !== undefined && cy !== null) {
|
||||
cy.on("select", "node", (e) => {
|
||||
onNodeSelect(e, appAuthentication);
|
||||
});
|
||||
onNodeSelect(e, appAuthentication)
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("App loading error: " + error.toString());
|
||||
console.log("App loading error: " + error.toString())
|
||||
setAppsLoaded(true)
|
||||
//toast("App loading error: "+error.toString());
|
||||
//toast("App loading error: "+error.toString())
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2575,7 +2672,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const node = cy.getElementById(chunkJson.id)
|
||||
if (node !== undefined && node !== null) {
|
||||
console.log("Node already exists: ", node)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3455,9 +3551,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
cy.add(decoratorNode).unselectify();
|
||||
} else {
|
||||
console.log("Node already exists - don't add descriptor node");
|
||||
//console.log("Node already exists - don't add descriptor node");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
originalLocation = {
|
||||
@@ -4014,7 +4110,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
)
|
||||
|
||||
if (curapp === undefined || curapp === null) {
|
||||
console.log("Couldn't find ID - checking with name & version")
|
||||
console.log("Couldn't find app with that ID - checking with name & version")
|
||||
|
||||
curapp = newapps.find((a) =>
|
||||
a.name === curaction.app_name &&
|
||||
@@ -4024,34 +4120,60 @@ const AngularWorkflow = (defaultprops) => {
|
||||
)
|
||||
}
|
||||
|
||||
if (curapp === undefined || curapp === null) {
|
||||
curapp = integrationApps.find((a) =>
|
||||
a.name === curaction.app_name &&
|
||||
(a.app_version === curaction.app_version ||
|
||||
(a.loop_versions !== null &&
|
||||
a.loop_versions.includes(curaction.app_version)))
|
||||
)
|
||||
}
|
||||
|
||||
if (curaction.template === true && curaction.name !== undefined) {
|
||||
//newapps.
|
||||
const parsedname = curaction.name.replaceAll(" ", "_").toLowerCase()
|
||||
console.log("FIND AN ACTION AMONG THE APPS THAT MATCHES NAME: ", parsedname)
|
||||
|
||||
curaction.matching_actions = []
|
||||
for (var newAppskey in newapps) {
|
||||
for (let actionsSubkey in newapps[newAppskey].actions) {
|
||||
const tmpaction = newapps[newAppskey].actions[actionsSubkey]
|
||||
if (tmpaction.name.replaceAll(" ", "_").toLowerCase() === parsedname) {
|
||||
console.log("MATCH!: ", newapps[newAppskey])
|
||||
curaction.matching_actions.push({
|
||||
"app_name": newapps[newAppskey].name,
|
||||
"app_version": newapps[newAppskey].app_version,
|
||||
"app_id": newapps[newAppskey].id,
|
||||
"action": tmpaction,
|
||||
"large_image": newapps[newAppskey].large_image,
|
||||
"app_index": newAppskey,
|
||||
"action_index": actionsSubkey,
|
||||
})
|
||||
}
|
||||
curaction.matching_actions = []
|
||||
for (var newAppskey in newapps) {
|
||||
for (let actionsSubkey in newapps[newAppskey].actions) {
|
||||
const tmpaction = newapps[newAppskey].actions[actionsSubkey]
|
||||
if (tmpaction.name.replaceAll(" ", "_").toLowerCase() === parsedname) {
|
||||
console.log("MATCH!: ", newapps[newAppskey])
|
||||
curaction.matching_actions.push({
|
||||
"app_name": newapps[newAppskey].name,
|
||||
"app_version": newapps[newAppskey].app_version,
|
||||
"app_id": newapps[newAppskey].id,
|
||||
"action": tmpaction,
|
||||
"large_image": newapps[newAppskey].large_image,
|
||||
"app_index": newAppskey,
|
||||
"action_index": actionsSubkey,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!curapp || curapp === undefined) {
|
||||
// Check local storage has it
|
||||
const foundapps = localStorage.getItem("apps")
|
||||
if (foundapps !== null && foundapps !== undefined) {
|
||||
const parsedapps = JSON.parse(foundapps)
|
||||
if (parsedapps !== null && parsedapps !== undefined && parsedapps.length > 0) {
|
||||
for (let appkey in parsedapps) {
|
||||
if (parsedapps[appkey].name === curaction.app_name) {
|
||||
curapp = parsedapps[appkey]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!curapp || curapp === undefined) {
|
||||
console.log("APPS - couldn't find it: ", newapps)
|
||||
} else {
|
||||
console.log("No apps found in local storage")
|
||||
}
|
||||
}
|
||||
|
||||
if (!curapp || curapp === undefined) {
|
||||
const tmpapp = {
|
||||
name: curaction.app_name,
|
||||
app_name: curaction.app_name,
|
||||
@@ -4361,7 +4483,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
} else {
|
||||
if (refresh === true) {
|
||||
setHighlightedApp(appid)
|
||||
//toast("App activated for your organization! Refresh the page to use the app.")
|
||||
//toast("App activated for your organisation! Refresh the page to use the app.")
|
||||
getApps()
|
||||
|
||||
}
|
||||
@@ -6037,7 +6159,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
currentNode.data.isDescriptor
|
||||
) {
|
||||
found = true;
|
||||
console.log("FOUND THE NODE!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -8075,6 +8196,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const AppView = (props) => {
|
||||
const { allApps, prioritizedApps, filteredApps, extraApps } = props;
|
||||
|
||||
//extraApps,
|
||||
const [visibleApps, setVisibleApps] = React.useState(
|
||||
Array.prototype.concat.apply(
|
||||
@@ -8090,9 +8212,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const app = props.app;
|
||||
const [hover, setHover] = React.useState(false);
|
||||
|
||||
if (app.id === "" || app.name === "") {
|
||||
return null
|
||||
}
|
||||
if (app.id === "" || app.name === "") {
|
||||
return null
|
||||
}
|
||||
|
||||
const maxlen = 24;
|
||||
var newAppname = app.name;
|
||||
@@ -8103,9 +8225,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
newAppname = newAppname.replaceAll("_", " ");
|
||||
|
||||
if (app.large_image === undefined || app.large_image === null || app.large_image === "") {
|
||||
app.large_image = theme.palette.defaultImage
|
||||
}
|
||||
if (app.large_image === undefined || app.large_image === null || app.large_image === "") {
|
||||
app.large_image = theme.palette.defaultImage
|
||||
}
|
||||
|
||||
const image = app.large_image !== undefined && app.large_image !== null && app.large_image !== "" ? app.large_image : theme.palette.defaultImage
|
||||
|
||||
@@ -8611,11 +8733,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
event.target.blur(event);
|
||||
}
|
||||
}}
|
||||
onChange={(event) => {
|
||||
runSearch(event.target.value)
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
|
||||
//navigate(`?q=${event.target.value}`)
|
||||
|
||||
runSearch(event.target.value);
|
||||
//runSearch(event.target.value)
|
||||
}}
|
||||
/>
|
||||
{visibleApps.length > extraApps.length ? (
|
||||
@@ -8625,6 +8750,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (app.id === "integration" && userdata.support !== true) {
|
||||
return null
|
||||
}
|
||||
|
||||
var extraMessage = ""
|
||||
if (index == 2) {
|
||||
extraMessage = <div style={{ marginTop: 5 }} />
|
||||
@@ -8655,7 +8784,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Click one of the relevant public apps below to Activate it for your organization.
|
||||
Click one of the relevant public apps below to Activate it for your organisation.
|
||||
</Typography>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||
console.log("CLICKED")
|
||||
@@ -8667,19 +8796,22 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</InstantSearch>
|
||||
</div>
|
||||
:
|
||||
<div
|
||||
style={{marginTop: 100, }}
|
||||
/>}
|
||||
<div style={{marginLeft: 10, marginTop: 10, marginBottom: 100, }}>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Apps need to be activated before they can be used. Search from our 2500+ apps to activate them for your organisation.
|
||||
</Typography>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
) : apps.length > 0 ? (
|
||||
<div
|
||||
style={{ textAlign: "center", width: leftBarSize, marginTop: 10 }}
|
||||
style={{ textAlign: "center", width: leftBarSize, marginTop: 10, marginLeft: 5, marginRight: 5, }}
|
||||
onLoad={() => {
|
||||
console.log("Should load in extra apps?")
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Couldn't find the apps you were looking for? Searching unactivated apps. Click one of the below apps to Activate it for your organization.
|
||||
Couldn't find the apps you were looking for? Searching unactivated apps. Click one of these apps to Activate it for your organisation.
|
||||
</Typography>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||
console.log("CLICKED")
|
||||
@@ -8741,12 +8873,20 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
console.log("action input: ", e)
|
||||
if (selectedApp.actions.length === 1) {
|
||||
// Find if there's a new app
|
||||
const newApp = apps.find((app) => (app.name === selectedApp.name && app.app_version !== selectedApp.app_version) || app.id == selectedApp.id)
|
||||
if (newApp !== undefined && newApp !== null) {
|
||||
|
||||
const newaction = selectedApp.actions.find(
|
||||
(a) => a.name === e.target.value
|
||||
);
|
||||
if (selectedApp.actions !== undefined && selectedApp.actions !== null && selectedApp.actions.length > 1) {
|
||||
setSelectedApp(newApp)
|
||||
}
|
||||
|
||||
selectedApp.actions = newApp.actions
|
||||
}
|
||||
}
|
||||
|
||||
const newaction = selectedApp.actions.find((a) => a.name === e.target.value)
|
||||
if (newaction === undefined || newaction === null) {
|
||||
toast("Failed to find the action you selected. Please try again or contact support@shuffler.io if it persists.");
|
||||
return;
|
||||
@@ -8833,7 +8973,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
if (newSelectedAction.app_name === "Shuffle Tools") {
|
||||
const iconInfo = GetIconInfo(newSelectedAction);
|
||||
console.log("ICONINFO: ", iconInfo);
|
||||
const svg_pin = `<svg width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} ${svgSize}" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="${iconInfo.icon}" fill="${iconInfo.iconColor}"></path></svg>`;
|
||||
const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin);
|
||||
newSelectedAction.large_image = svgpin_Url;
|
||||
@@ -8860,8 +8999,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// Further checks if those fields are already set in a previously used action
|
||||
newSelectedAction = RunAutocompleter(newSelectedAction);
|
||||
|
||||
console.log("newaction: ", newaction)
|
||||
|
||||
if (
|
||||
newaction.return !== undefined &&
|
||||
newaction.return !== null &&
|
||||
@@ -13927,6 +14064,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return null
|
||||
}
|
||||
|
||||
if (userdata.active_org === undefined || userdata.active_org === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isCorrectOrg = workflow.public === true || userdata.active_org.id === undefined || userdata.active_org.id === null || workflow.org_id === null || workflow.org_id === undefined || workflow.org_id.length === 0 || userdata.active_org.id === workflow.org_id
|
||||
|
||||
return (
|
||||
@@ -13959,7 +14100,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
<b>Warning</b>: Change <span
|
||||
style={{color: "#f85a3e", cursor: "pointer"}}
|
||||
onClick={() => {
|
||||
toast("Changing to correct organization. Please wait a few seconds.")
|
||||
toast("Changing to correct organisation. Please wait a few seconds.")
|
||||
|
||||
localStorage.setItem("globalUrl", "");
|
||||
localStorage.setItem("getting_started_sidebar", "open");
|
||||
@@ -13994,7 +14135,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
|
||||
toast("Successfully changed active organization - refreshing!");
|
||||
toast("Successfully changed active organisation - refreshing!");
|
||||
} else {
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
||||
toast(responseJson.reason);
|
||||
@@ -14316,7 +14457,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
)
|
||||
}
|
||||
|
||||
const shownErrors = !isMobile && !workflow.public && workflow.errors !== undefined && workflow.errors !== null && workflow.errors.length > 0 && showErrors ?
|
||||
const shownErrors = !isMobile && workflow.errors !== undefined && workflow.errors !== null && workflow.errors.length > 0 && showErrors && (!workflow.public || userdata.support === true) ?
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid rgba(255,255,255,0.1)",
|
||||
@@ -14348,8 +14489,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
<Typography variant="body22">
|
||||
{/*<WarningIcon style={{marginRight: 5, height: 15, width: 15, }} />*/}
|
||||
|
||||
|
||||
<b>Workflow Issues:</b> {workflow.errors.length}
|
||||
</Typography>
|
||||
<Typography
|
||||
@@ -14573,7 +14712,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</Tooltip>
|
||||
)}
|
||||
{/*userdata.avatar === creatorProfile.github_avatar ? null :*/}
|
||||
<Tooltip color="primary" title={workflow.public === true ? "Use this Workflow in your organization" : "Save Workflow"} placement="top">
|
||||
<Tooltip color="primary" title={workflow.public === true ? "Use this Workflow in your organisation" : "Save Workflow"} placement="top">
|
||||
<span>
|
||||
<Button
|
||||
disabled={savingState !== 0}
|
||||
@@ -14778,6 +14917,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
console.log("SHOW EDIT VIEW!")
|
||||
|
||||
setEditWorkflowModalOpen(true)
|
||||
setLastSaved(false)
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
@@ -14922,6 +15062,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
lastSaved={lastSaved}
|
||||
aiSubmit={aiSubmit}
|
||||
|
||||
apps={apps}
|
||||
expansionModalOpen={codeEditorModalOpen}
|
||||
setExpansionModalOpen={setCodeEditorModalOpen}
|
||||
setEditorData={setEditorData}
|
||||
@@ -14938,8 +15079,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
defaultReturn = null
|
||||
} else if (selectedTrigger.trigger_type === "SUBFLOW") {
|
||||
defaultReturn = <SubflowSidebar />
|
||||
// } else if (selectedTrigger.trigger_type === "PIPELINE") {
|
||||
// defaultReturn = <PipelineSidebar />
|
||||
} else if (selectedTrigger.trigger_type === "EMAIL") {
|
||||
defaultReturn = <EmailSidebar />
|
||||
} else if (selectedTrigger.trigger_type === "USERINPUT") {
|
||||
@@ -16498,8 +16637,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
width: imgsize,
|
||||
height: imgsize,
|
||||
border: `2px solid ${statusColor}`,
|
||||
borderRadius:
|
||||
executionData.start === data.action.id ? 25 : 5,
|
||||
borderRadius: executionData.start === data.action.id ? 25 : 5,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -16529,8 +16667,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
width: imgsize,
|
||||
height: imgsize,
|
||||
border: `2px solid ${statusColor}`,
|
||||
borderRadius:
|
||||
executionData.start === data.action.id ? 25 : 5,
|
||||
borderRadius: executionData.start === data.action.id ? 25 : 5,
|
||||
background: `linear-gradient(to right, ${nodedata.fillGradient})`,
|
||||
};
|
||||
|
||||
@@ -16888,15 +17025,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
style={{}}
|
||||
>
|
||||
<b>{data.name}</b>
|
||||
{checked.valid ?
|
||||
<Chip
|
||||
style={{marginLeft: 10, padding: 0, cursor: "pointer",}}
|
||||
label={"JSON"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/>
|
||||
: null}
|
||||
{showVariable ? data.value : null}
|
||||
{checked.valid ?
|
||||
<Chip
|
||||
style={{marginLeft: 10, padding: 0, cursor: "pointer",}}
|
||||
label={"JSON"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/>
|
||||
: null}
|
||||
{showVariable ? data.value : null}
|
||||
</Typography>
|
||||
</IconButton>
|
||||
:
|
||||
@@ -16908,25 +17045,25 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</Typography>
|
||||
}
|
||||
{open ?
|
||||
checked.valid ?
|
||||
<ReactJson
|
||||
src={checked.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={data.value.length < 10000 ? false : true}
|
||||
displayDataTypes={false}
|
||||
name={"Parsed data for variable " + data.name}
|
||||
/>
|
||||
:
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{
|
||||
whiteSpace: 'pre-line',
|
||||
}}
|
||||
color="textSecondary"
|
||||
>
|
||||
{data.value}
|
||||
</Typography>
|
||||
checked.valid ?
|
||||
<ReactJson
|
||||
src={checked.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={data.value.length < 10000 ? false : true}
|
||||
displayDataTypes={false}
|
||||
name={"Parsed data for variable " + data.name}
|
||||
/>
|
||||
:
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{
|
||||
whiteSpace: 'pre-line',
|
||||
}}
|
||||
color="textSecondary"
|
||||
>
|
||||
{data.value}
|
||||
</Typography>
|
||||
: null}
|
||||
</div>
|
||||
)
|
||||
@@ -17006,6 +17143,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return "You can't use localhost in apps. Use the external ip or url of the server instead"
|
||||
}
|
||||
|
||||
if (stringjson.includes("manifest unknown")) {
|
||||
return "The app's Docker Image is not available in the environment yet. Re-run the app to force a re-download of the app. If the problem persists, contact support"
|
||||
}
|
||||
|
||||
if (result.status !== 200 && stringjson.includes("192.168") || stringjson.includes("172.16") || stringjson.includes("10.0")) {
|
||||
return "Consider whether your Orborus environment can connect to a local IP or not."
|
||||
}
|
||||
@@ -17027,6 +17168,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return "Run this workflow in a local environment to increase the timeout. Go to https://shuffler.io/admin?tab=environments to create an environment to connect to"
|
||||
}
|
||||
|
||||
if (stringjson.toLowerCase().includes("invalid header")) {
|
||||
return "A header or authentication token in the app is invalid. Check the app's configuration"
|
||||
}
|
||||
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -17241,7 +17386,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
width: imgsize,
|
||||
height: imgsize,
|
||||
border: `2px solid ${statusColor}`,
|
||||
filter: curapp === undefined ? "grayscale(100%)" : null,
|
||||
filter: curapp === undefined ? "grayscale(100%)" : null,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -19079,6 +19224,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</div>
|
||||
|
||||
const changeActionParameterCodeMirror = (event, count, data, actionlist) => {
|
||||
// Check if event.target.value is an array. If it is, split with comma
|
||||
|
||||
if (data.startsWith("${") && data.endsWith("}")) {
|
||||
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
||||
const paramcheck = selectedAction.parameters.find(param => param.name === "body")
|
||||
|
||||
@@ -1037,55 +1037,41 @@ const AppCreator = (defaultprops) => {
|
||||
"schema"
|
||||
] !== null
|
||||
) {
|
||||
try {
|
||||
if (
|
||||
methodvalue["requestBody"]["content"]["application/xml"][
|
||||
"schema"
|
||||
]["properties"] !== undefined
|
||||
) {
|
||||
var tmpobject = {};
|
||||
for (let [prop, propvalue] of Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["properties"])) {
|
||||
|
||||
tmpobject[prop] = `\$\{${prop}\}`;
|
||||
}
|
||||
try {
|
||||
if (
|
||||
methodvalue["requestBody"]["content"]["application/xml"][
|
||||
"schema"
|
||||
]["properties"] !== undefined
|
||||
) {
|
||||
var tmpobject = {};
|
||||
for (let [prop, propvalue] of Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["properties"])) {
|
||||
|
||||
tmpobject[prop] = `\$\{${prop}\}`;
|
||||
}
|
||||
|
||||
for (let [subkey,subkeyval] in Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["required"])) {
|
||||
const tmpitem =
|
||||
methodvalue["requestBody"]["content"][
|
||||
"application/xml"
|
||||
]["schema"]["required"][subkey];
|
||||
tmpobject[tmpitem] = `\$\{${tmpitem}\}`;
|
||||
}
|
||||
for (let [subkey,subkeyval] in Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["required"])) {
|
||||
const tmpitem =
|
||||
methodvalue["requestBody"]["content"][
|
||||
"application/xml"
|
||||
]["schema"]["required"][subkey];
|
||||
tmpobject[tmpitem] = `\$\{${tmpitem}\}`;
|
||||
}
|
||||
|
||||
//console.log("OBJ XML: ", tmpobject)
|
||||
//newaction["body"] = XML.stringify(tmpobject, null, 2)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("RequestBody xml error: ", e, path)
|
||||
}
|
||||
//console.log("OBJ XML: ", tmpobject)
|
||||
//newaction["body"] = XML.stringify(tmpobject, null, 2)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("RequestBody xml error: ", e, path)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
methodvalue["requestBody"]["content"]["example"] !== undefined
|
||||
) {
|
||||
if (
|
||||
methodvalue["requestBody"]["content"]["example"][
|
||||
"example"
|
||||
] !== undefined
|
||||
) {
|
||||
newaction["body"] =
|
||||
methodvalue["requestBody"]["content"]["example"][
|
||||
"example"
|
||||
];
|
||||
//JSON.stringify(tmpobject, null, 2)
|
||||
if (methodvalue["requestBody"]["content"]["example"] !== undefined) {
|
||||
if (methodvalue["requestBody"]["content"]["example"]["example"] !== undefined) {
|
||||
newaction["body"] = methodvalue["requestBody"]["content"]["example"]["example"]
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
methodvalue["requestBody"]["content"][
|
||||
"multipart/form-data"
|
||||
] !== undefined
|
||||
) {
|
||||
|
||||
if (methodvalue["requestBody"]["content"]["multipart/form-data"] !== undefined) {
|
||||
if (
|
||||
methodvalue["requestBody"]["content"][
|
||||
"multipart/form-data"
|
||||
@@ -1553,8 +1539,10 @@ const AppCreator = (defaultprops) => {
|
||||
} else if (parameter.in === "body") {
|
||||
// FIXME: Add tracking for components
|
||||
// E.G: https://raw.githubusercontent.com/owentl/Shuffle/master/gosecure.yaml
|
||||
if (parameter.example !== undefined) {
|
||||
newaction.body = parameter.example;
|
||||
if (parameter.example !== undefined && parameter.example !== null) {
|
||||
if (newaction.body === undefined || newaction.body === null || newaction.body.length < 5) {
|
||||
newaction.body = parameter.example
|
||||
}
|
||||
}
|
||||
} else if (parameter.in === "header") {
|
||||
newaction.headers += `${parameter.name}=${parameter.example}\n`;
|
||||
@@ -1566,6 +1554,13 @@ const AppCreator = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if body is valid JSON.
|
||||
if (newaction.body !== undefined && newaction.body !== null && newaction.body.length > 0) {
|
||||
// Trim starting / ending newlines, spaces and tabs
|
||||
newaction.body = newaction.body.trim()
|
||||
}
|
||||
|
||||
|
||||
if (newaction.name === "" || newaction.name === undefined) {
|
||||
// Find a unique part of the string
|
||||
// FIXME: Looks for length between /, find the one where they differ
|
||||
@@ -1920,11 +1915,11 @@ const AppCreator = (defaultprops) => {
|
||||
|
||||
setProjectCategories(all_categories);
|
||||
|
||||
// Rearrange them by which has action_label
|
||||
const firstActions = newActions.filter(data => data.action_label !== undefined && data.action_label !== null && data.action_label !== "No Label")
|
||||
console.log("First actions: ", firstActions)
|
||||
const secondActions = newActions.filter(data => data.action_label === undefined || data.action_label === null || data.action_label === "No Label")
|
||||
newActions = firstActions.concat(secondActions)
|
||||
// Rearrange them by which has action_label
|
||||
const firstActions = newActions.filter(data => data.action_label !== undefined && data.action_label !== null && data.action_label !== "No Label")
|
||||
console.log("First actions: ", firstActions)
|
||||
const secondActions = newActions.filter(data => data.action_label === undefined || data.action_label === null || data.action_label === "No Label")
|
||||
newActions = firstActions.concat(secondActions)
|
||||
setActions(newActions);
|
||||
//data.paths[item.url][item.method.toLowerCase()]["x-label"] = item.action_label
|
||||
|
||||
@@ -2073,7 +2068,7 @@ const AppCreator = (defaultprops) => {
|
||||
};
|
||||
|
||||
if (item.action_label !== undefined && item.action_label !== "" && item.action_label !== "No Label") {
|
||||
console.log("Action label: ", item.action_label)
|
||||
//console.log("Action label: ", item.action_label)
|
||||
data.paths[item.url][item.method.toLowerCase()]["x-label"] = item.action_label
|
||||
}
|
||||
|
||||
@@ -3078,7 +3073,10 @@ const AppCreator = (defaultprops) => {
|
||||
Refresh-token URL for Oauth2 (Optional)
|
||||
</Typography>
|
||||
<TextField
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
style={{
|
||||
margin: 0, flex: "1", backgroundColor: inputColor,
|
||||
border: !refreshUrl.startsWith("http") || refreshUrl.includes("//shuffler.") ? "2px solid red" : "inherit",
|
||||
}}
|
||||
fullWidth={true}
|
||||
placeholder="The URL to retrieve refresh-tokens at"
|
||||
type="name"
|
||||
@@ -3086,8 +3084,9 @@ const AppCreator = (defaultprops) => {
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
value={refreshUrl}
|
||||
helperText={!refreshUrl.startsWith("http") || refreshUrl.includes("//shuffler.")? "Must start with http(s):// and can not contain shuffler.io" : ""}
|
||||
onChange={(e) => setRefreshUrl(e.target.value)}
|
||||
onBlur={(event) => {
|
||||
onBlur={(event) => {
|
||||
var tmpstring = event.target.value.trim();
|
||||
|
||||
if (
|
||||
@@ -3153,7 +3152,7 @@ const AppCreator = (defaultprops) => {
|
||||
</Typography>
|
||||
<div style={{display: "flex", marginTop: 10, }}>
|
||||
<div style={{flex: 4,}}>
|
||||
Key
|
||||
Key
|
||||
<TextField
|
||||
required
|
||||
style={{ marginTop: 0, backgroundColor: inputColor }}
|
||||
@@ -3166,12 +3165,17 @@ const AppCreator = (defaultprops) => {
|
||||
value={parameterName}
|
||||
helperText={
|
||||
<span style={{ color: "white", marginBottom: "2px" }}>
|
||||
Can't be empty or contain any of the following: !#$%&'^"+-._~|]+$
|
||||
Can't be empty or contain any of the following: !#$%&'^"+-._~|]+$:=
|
||||
</span>
|
||||
}
|
||||
onChange={(e) => {
|
||||
setParameterName(e.target.value);
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
var tmpstring = event.target.value.trim()
|
||||
|
||||
// Check if tmpstring has any of the illegal characters in it
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
|
||||
@@ -82,11 +82,16 @@ const chipStyle = {
|
||||
// Fixes names by making them uppercase and such
|
||||
// Used for labels. A lot of places don't use this yet
|
||||
export const FixName = (name) => {
|
||||
if (name === undefined || name === null) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const newAppname = (
|
||||
name.charAt(0).toUpperCase() + name.substring(1)
|
||||
).replaceAll("_", " ");
|
||||
return newAppname;
|
||||
};
|
||||
).replaceAll("_", " ")
|
||||
|
||||
return newAppname
|
||||
}
|
||||
|
||||
|
||||
// Takes input of e.g. $node.data.#.asd and a matching value from a json blob
|
||||
@@ -1832,7 +1837,11 @@ const Apps = (props) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === false) {
|
||||
toast("Failed to activate the app")
|
||||
if (responseJson.reason !== undefined) {
|
||||
toast("Failed to activate the app: "+responseJson.reason);
|
||||
} else {
|
||||
toast("Failed to activate the app");
|
||||
}
|
||||
} else {
|
||||
//toast("App activated for your organization! Refresh the page to use the app.")
|
||||
if (appExists) {
|
||||
@@ -2052,7 +2061,7 @@ const Apps = (props) => {
|
||||
to={`/apps/edit/${selectedApp.id}`}
|
||||
style={{ textDecoration: "none", color: "inherit" }}
|
||||
>
|
||||
<Typography variant="h6">{selectedApp.name}</Typography>
|
||||
<Typography variant="h6">{FixName(selectedApp.name)}</Typography>
|
||||
</Link>
|
||||
) : null}
|
||||
</Breadcrumbs>
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import theme from '../theme.jsx';
|
||||
import {isMobile} from "react-device-detect";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import AppGrid from "../components/AppGrid.jsx"
|
||||
import WorkflowGrid from "../components/WorkflowGrid.jsx"
|
||||
import CreatorGrid from "../components/CreatorGrid.jsx"
|
||||
import DocsGrid from "../components/DocsGrid.jsx"
|
||||
import DiscordChat from "../components/DiscordChat.jsx";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import {
|
||||
Tabs,
|
||||
Tab,
|
||||
import {
|
||||
Tabs,
|
||||
Tab,
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
Apps as AppsIcon,
|
||||
Code as CodeIcon,
|
||||
Chat as ChatIcon,
|
||||
EmojiObjects as EmojiObjectsIcon,
|
||||
Description as DescriptionIcon,
|
||||
Description as DescriptionIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
|
||||
// Should be different if logged in :|
|
||||
const Search = (props) => {
|
||||
const { globalUrl, isLoaded, serverside, userdata, hidemargins, isHeader} = props;
|
||||
const { globalUrl, isLoaded, serverside, userdata, hidemargins, isHeader } = props;
|
||||
let navigate = useNavigate();
|
||||
|
||||
const [curTab, setCurTab] = useState(0);
|
||||
const iconStyle = { marginRight: isHeader ? null : 10 };
|
||||
const [curTab, setCurTab] = useState(0);
|
||||
const iconStyle = { marginRight: isHeader ? null : 10 };
|
||||
|
||||
useEffect(() => {
|
||||
if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
|
||||
@@ -56,7 +58,7 @@ const Search = (props) => {
|
||||
maxWidth: 1024,
|
||||
scrollX: "hidden",
|
||||
overflowX: "hidden",
|
||||
justifyContent: isHeader ? "center" : null,
|
||||
justifyContent: isHeader ? "center" : null,
|
||||
}
|
||||
|
||||
const boxStyle = {
|
||||
@@ -68,49 +70,52 @@ const Search = (props) => {
|
||||
paddingRight: isHeader ? null : 30,
|
||||
paddingBottom: isHeader ? null : 30,
|
||||
paddingTop: hidemargins === true ? 0 : isHeader ? null : 30,
|
||||
display: "flex",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflowX: "hidden",
|
||||
minHeight: 400,
|
||||
}
|
||||
|
||||
const views = {
|
||||
0: "apps",
|
||||
1: "workflows",
|
||||
2: "docs",
|
||||
3: "creators",
|
||||
}
|
||||
0: "apps",
|
||||
1: "workflows",
|
||||
2: "docs",
|
||||
3: "creators",
|
||||
4: "discord",
|
||||
}
|
||||
|
||||
const setConfig = (event, inputValue) => {
|
||||
const newValue = parseInt(inputValue)
|
||||
|
||||
setCurTab(newValue)
|
||||
if (newValue === 0) {
|
||||
document.title = "Shuffle - search - apps";
|
||||
} else if (newValue === 1) {
|
||||
document.title = "Shuffle - search - workflows";
|
||||
} else if (newValue === 2) {
|
||||
document.title = "Shuffle - search - documentation";
|
||||
} else if (newValue === 3) {
|
||||
document.title = "Shuffle - search - creators";
|
||||
} else {
|
||||
document.title = "Shuffle - search";
|
||||
}
|
||||
setCurTab(newValue)
|
||||
if (newValue === 0) {
|
||||
document.title = "Shuffle - search - apps";
|
||||
} else if (newValue === 1) {
|
||||
document.title = "Shuffle - search - workflows";
|
||||
} else if (newValue === 2) {
|
||||
document.title = "Shuffle - search - documentation";
|
||||
} else if (newValue === 3) {
|
||||
document.title = "Shuffle - search - creators";
|
||||
} else if (newValue === 4) {
|
||||
document.title = "Shuffle - search - Discord Chat";
|
||||
}else {
|
||||
document.title = "Shuffle - search";
|
||||
}
|
||||
|
||||
|
||||
|
||||
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||
const params = Object.fromEntries(urlSearchParams.entries())
|
||||
const foundQuery = params["q"]
|
||||
var extraQ = ""
|
||||
if (foundQuery !== null && foundQuery !== undefined) {
|
||||
extraQ = "&q="+foundQuery
|
||||
extraQ = "&q=" + foundQuery
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((serverside === false || serverside === undefined) && window.location.pathname.includes("/search")) {
|
||||
navigate(`/search?tab=${views[newValue]}`+extraQ)
|
||||
navigate(`/search?tab=${views[newValue]}` + extraQ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoaded === false) {
|
||||
return null
|
||||
@@ -118,18 +123,18 @@ const Search = (props) => {
|
||||
|
||||
|
||||
// Random names for type & autoComplete. Didn't research :^)
|
||||
const landingpageDataBrowser =
|
||||
<div style={{paddingBottom: hidemargins === true ? 0 : 100, color: "white", }}>
|
||||
const landingpageDataBrowser =
|
||||
<div style={{ paddingBottom: hidemargins === true ? 0 : 100, color: "white", }}>
|
||||
<div style={boxStyle}>
|
||||
<Tabs
|
||||
style={{width: isHeader ? 765 : 610, margin: isHeader? null :"auto", marginTop: hidemargins === true ? 0 : isHeader ? null : 25, }}
|
||||
style={{ width: isHeader ? 765 : 610, margin: isHeader ? null : "auto", marginTop: hidemargins === true ? 0 : isHeader ? null : 25, }}
|
||||
value={curTab}
|
||||
indicatorColor="primary"
|
||||
textColor="secondary"
|
||||
onChange={setConfig}
|
||||
aria-label="disabled tabs example"
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
scrollButtons="auto"
|
||||
>
|
||||
<Tab
|
||||
label=<span>
|
||||
@@ -143,36 +148,46 @@ const Search = (props) => {
|
||||
/>
|
||||
<Tab
|
||||
label=<span>
|
||||
<DescriptionIcon style={iconStyle} /> Docs
|
||||
<DescriptionIcon style={iconStyle} /> Docs
|
||||
</span>
|
||||
/>
|
||||
<Tab
|
||||
label=<span>
|
||||
<EmojiObjectsIcon style={iconStyle} /> Creators
|
||||
<EmojiObjectsIcon style={iconStyle} /> Creators
|
||||
</span>
|
||||
/>
|
||||
<Tab
|
||||
label=<span>
|
||||
<ChatIcon style={iconStyle} /> Discord Chat
|
||||
</span>
|
||||
/>
|
||||
|
||||
</Tabs>
|
||||
{curTab === 0 ?
|
||||
{curTab === 0 ?
|
||||
<AppGrid maxRows={3} isHeader={true} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
curTab === 1 ?
|
||||
window.location.pathname === "/search" ?
|
||||
<WorkflowGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
curTab === 1 ?
|
||||
window.location.pathname === "/search" ?
|
||||
<WorkflowGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
<WorkflowGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
<WorkflowGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
curTab === 2 ?
|
||||
<DocsGrid maxRows={6} parsedXs={12} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
curTab === 3 ?
|
||||
<CreatorGrid parsedXs={4} isHeader={true} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
null}
|
||||
curTab === 2 ?
|
||||
<DocsGrid maxRows={6} parsedXs={12} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
curTab === 3 ?
|
||||
<CreatorGrid parsedXs={4} isHeader={true} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||
:
|
||||
curTab === 4 ?
|
||||
<DiscordChat isMobile={isMobile} />
|
||||
:
|
||||
|
||||
null}
|
||||
</div>
|
||||
</div>
|
||||
//{/*alternativeView={true} />*/}
|
||||
|
||||
const loadedCheck = isLoaded ?
|
||||
const loadedCheck = isLoaded ?
|
||||
<div>
|
||||
<div style={bodyDivStyle}>{landingpageDataBrowser}</div>
|
||||
</div>
|
||||
@@ -181,7 +196,7 @@ const Search = (props) => {
|
||||
</div>
|
||||
|
||||
// #1f2023?
|
||||
return(
|
||||
return (
|
||||
<div style={{}}>
|
||||
{loadedCheck}
|
||||
</div>
|
||||
|
||||
@@ -9,14 +9,16 @@ import {
|
||||
Button,
|
||||
Divider,
|
||||
TextField,
|
||||
Modal,
|
||||
} from "@mui/material";
|
||||
//import { useAlert
|
||||
import { ToastContainer, toast } from "react-toastify"
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
import "../codeeditor-index.css";
|
||||
|
||||
import { FileCopy, Visibility, VisibilityOff } from "@mui/icons-material";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import { Tooltip } from "@mui/material";
|
||||
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
const Settings = (props) => {
|
||||
const { globalUrl, isLoaded, userdata, setUserData } = props;
|
||||
@@ -44,14 +46,13 @@ const Settings = (props) => {
|
||||
|
||||
// Used for error messages etc
|
||||
const [passwordFormMessage, setPasswordFormMessage] = useState("");
|
||||
|
||||
const [firstrequest, setFirstRequest] = useState(true);
|
||||
|
||||
const [userSettings, setUserSettings] = useState({});
|
||||
|
||||
const [showApiKey, setShowApiKey] = useState(false);
|
||||
const [apiKeyCopied, setApiKeyCopied] = useState(false);
|
||||
|
||||
const [accountDeleteButtonClicked, setAccountDeleteButtonClicked] = useState(false);
|
||||
|
||||
const handleCopyApiKey = () => {
|
||||
navigator.clipboard.writeText(userSettings.apikey);
|
||||
setApiKeyCopied(true);
|
||||
@@ -135,6 +136,241 @@ const Settings = (props) => {
|
||||
return currentOwner;
|
||||
};
|
||||
|
||||
const handleAccountDelete = () => {
|
||||
setAccountDeleteButtonClicked(true);
|
||||
};
|
||||
|
||||
const DeleteAccountPopUp = () => {
|
||||
const [userDeleteAccepted, setUserDeleteAccepted] = useState(false);
|
||||
const [password, setPassword] = useState("");
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [disabled, setDisabled] = useState(true);
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
const boxStyling = {
|
||||
position: "relative",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: "9999",
|
||||
backgroundColor: "#1a1a1a",
|
||||
color: "white",
|
||||
padding: 20,
|
||||
borderRadius: 5,
|
||||
boxShadow: "0 0 10px rgba(0, 0, 0, 0.3)",
|
||||
width: 430,
|
||||
height: 430,
|
||||
};
|
||||
|
||||
const closeIconButtonStyling = {
|
||||
color: "white",
|
||||
border: "none",
|
||||
backgroundColor: "transparent",
|
||||
marginLeft: "90%",
|
||||
width: 20,
|
||||
height: 20,
|
||||
cursor: "pointer",
|
||||
};
|
||||
|
||||
const handlePasswordVisibility = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
const buttonStyle = {
|
||||
marginTop: 20,
|
||||
height: 50,
|
||||
border: "none",
|
||||
width: "100%",
|
||||
fontSize: 16,
|
||||
backgroundColor: disabled ? "gray" : "red",
|
||||
color: "white",
|
||||
cursor: disabled === false && "pointer",
|
||||
};
|
||||
const checkboxStyle = {
|
||||
position: "relative",
|
||||
cursor: "pointer",
|
||||
display: "inline-block",
|
||||
width: 20,
|
||||
height: 20,
|
||||
backgroundColor: "#ccc",
|
||||
borderRadius: 4,
|
||||
};
|
||||
|
||||
const checkmarkStyle = {
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
content: "",
|
||||
width: 10,
|
||||
height: 10,
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 2,
|
||||
display: "none",
|
||||
};
|
||||
|
||||
|
||||
const handlePasswordChange = (e) => {
|
||||
setPassword(e.target.value);
|
||||
};
|
||||
|
||||
const handleCheckBoxEvent = () => {
|
||||
setUserDeleteAccepted(!userDeleteAccepted);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (password.length > 8 && userDeleteAccepted) {
|
||||
setDisabled(false);
|
||||
} else {
|
||||
setDisabled(true);
|
||||
}
|
||||
}, [password, userDeleteAccepted]);
|
||||
|
||||
function removeAllCookies() {
|
||||
|
||||
var cookies = document.cookie.split(";");
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = cookies[i];
|
||||
var eqPos = cookie.indexOf("=");
|
||||
var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
|
||||
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteAccount = () => {
|
||||
const baseURL = globalUrl;
|
||||
const userID = userdata.id;
|
||||
|
||||
const url = `${baseURL}/api/v1/users/${userID}/remove`;
|
||||
|
||||
fetch(url, {
|
||||
mode: "cors",
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({ password }),
|
||||
credentials: "include",
|
||||
crossDomain: true,
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
toast.success(
|
||||
"Your account delete successfully! redirecting in 3 sec.."
|
||||
);
|
||||
removeAllCookies();
|
||||
|
||||
window.location.pathname = "/";
|
||||
} else {
|
||||
toast.error(`${data.reason}`);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
"There was a problem with your fetch operation:",
|
||||
error
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal open= {open} >
|
||||
<div style={boxStyling}>
|
||||
<button
|
||||
style={closeIconButtonStyling}
|
||||
onClick={() => setAccountDeleteButtonClicked(false)}
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
<h1 style={{textAlign:"center", margin : "0 0 20px 0"}}>Account</h1>
|
||||
{/* <div style={{paddingLeft: 15}} > */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
textAlign: "left",
|
||||
// paddingLeft: 15
|
||||
// marginLeft: 20
|
||||
}}
|
||||
>
|
||||
<label>If you delete your account then:</label>
|
||||
<ul style={{ textAlign: "left" }}>
|
||||
<li>
|
||||
<label>
|
||||
Your Account information will be removed from our Database
|
||||
permanently.
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label>This action cannot be reversed.</label>
|
||||
</li>
|
||||
</ul>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
<input
|
||||
checked={userDeleteAccepted}
|
||||
type="checkbox"
|
||||
className="ais-RefinementList-checkbox"
|
||||
onClick={handleCheckBoxEvent}
|
||||
/>
|
||||
<label style={{ fontSize: "16px", color: "white" }}>
|
||||
I have read the above information and I agree to it completely
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
marginTop: 20,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<label>Enter password to delete your account</label>
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
flex: "1",
|
||||
}}
|
||||
type={showPassword ? "text" : "password"}
|
||||
value={password}
|
||||
onChange={handlePasswordChange}
|
||||
required
|
||||
placeholder="Password"
|
||||
id="standard-required"
|
||||
autoComplete="off"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={handlePasswordVisibility}
|
||||
style={{color:"white"}}
|
||||
>
|
||||
{showPassword ? <VisibilityOff /> : <Visibility />}
|
||||
</IconButton>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
style={buttonStyle}
|
||||
disabled={disabled}
|
||||
onClick={handleDeleteAccount}
|
||||
>
|
||||
Delete Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const onPasswordChange = () => {
|
||||
const data = {
|
||||
username: userSettings.username,
|
||||
@@ -727,7 +963,8 @@ const Settings = (props) => {
|
||||
>
|
||||
Submit password change
|
||||
</Button>
|
||||
<h3>{passwordFormMessage}</h3>
|
||||
<h3>{passwordFormMessage}</h3>
|
||||
|
||||
{isCloud && (
|
||||
<>
|
||||
<Divider style={{ marginTop: "40px" }} />
|
||||
@@ -820,6 +1057,22 @@ const Settings = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Danger Area</h2>
|
||||
<Button
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "60px",
|
||||
marginTop: "10px",
|
||||
backgroundColor: "#d52b2b",
|
||||
color: "white",
|
||||
}}
|
||||
// variant="contained"
|
||||
// color="primary"
|
||||
onClick={handleAccountDelete}
|
||||
>
|
||||
Delete Account
|
||||
</Button>
|
||||
|
||||
{loadedValidationWorkflows !== undefined &&
|
||||
loadedValidationWorkflows !== null
|
||||
? loadedValidationWorkflows.map((data, index) => {
|
||||
@@ -831,6 +1084,7 @@ const Settings = (props) => {
|
||||
})
|
||||
: null}
|
||||
</Paper>
|
||||
{accountDeleteButtonClicked && <DeleteAccountPopUp/>}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -888,47 +1142,47 @@ const Settings = (props) => {
|
||||
|
||||
console.log("redirect: ", redirectUri)
|
||||
|
||||
const client_id = "3d272b1b782b100b1e61"
|
||||
const username = userdata.id;
|
||||
const scopes = "read:user";
|
||||
const client_id = "3d272b1b782b100b1e61"
|
||||
const username = userdata.id;
|
||||
const scopes = "read:user";
|
||||
|
||||
const url = `https://github.com/login/oauth/authorize?access_type=offline&prompt=consent&client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${scopes}&state=username%3D${username}%26type%3Dgithub`
|
||||
const url = `https://github.com/login/oauth/authorize?access_type=offline&prompt=consent&client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${scopes}&state=username%3D${username}%26type%3Dgithub`
|
||||
|
||||
console.log("URL: ", url);
|
||||
console.log("URL: ", url);
|
||||
|
||||
var newwin = window.open(url, "", "width=800,height=600");
|
||||
var newwin = window.open(url, "", "width=800,height=600");
|
||||
|
||||
// Check whether we got a callback somewhere
|
||||
//var id = setInterval(function () {
|
||||
// fetch(
|
||||
// globalUrl + "/api/v1/triggers/gmail/" + selectedTrigger.id,
|
||||
// {
|
||||
// method: "GET",
|
||||
// headers: { "content-type": "application/json" },
|
||||
// credentials: "include",
|
||||
// }
|
||||
// )
|
||||
// .then((response) => {
|
||||
// if (response.status !== 200) {
|
||||
// throw new Error("No trigger info :o!");
|
||||
// }
|
||||
// Check whether we got a callback somewhere
|
||||
//var id = setInterval(function () {
|
||||
// fetch(
|
||||
// globalUrl + "/api/v1/triggers/gmail/" + selectedTrigger.id,
|
||||
// {
|
||||
// method: "GET",
|
||||
// headers: { "content-type": "application/json" },
|
||||
// credentials: "include",
|
||||
// }
|
||||
// )
|
||||
// .then((response) => {
|
||||
// if (response.status !== 200) {
|
||||
// throw new Error("No trigger info :o!");
|
||||
// }
|
||||
|
||||
// return response.json();
|
||||
// })
|
||||
// .then((responseJson) => {
|
||||
// console.log("RESPONSE: ");
|
||||
// setTriggerAuthentication(responseJson);
|
||||
// clearInterval(id);
|
||||
// newwin.close();
|
||||
// setGmailFolders();
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.log(error.toString());
|
||||
// });
|
||||
//}, 2500);
|
||||
// return response.json();
|
||||
// })
|
||||
// .then((responseJson) => {
|
||||
// console.log("RESPONSE: ");
|
||||
// setTriggerAuthentication(responseJson);
|
||||
// clearInterval(id);
|
||||
// newwin.close();
|
||||
// setGmailFolders();
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.log(error.toString());
|
||||
// });
|
||||
//}, 2500);
|
||||
|
||||
//saveWorkflow(workflow);
|
||||
}
|
||||
//saveWorkflow(workflow);
|
||||
}
|
||||
|
||||
const loadedCheck =
|
||||
isLoaded && !firstrequest ? (
|
||||
|
||||
@@ -128,6 +128,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
export const GetIconInfo = (action) => {
|
||||
// Finds the icon based on the action. Should be verbs.
|
||||
const iconList = [
|
||||
{ key: "cases", values: ["cases"] },
|
||||
{ key: "cache_add", values: ["set_cache"] },
|
||||
{ key: "cache_get", values: ["get_cache"] },
|
||||
{ key: "filter", values: ["filter"] },
|
||||
@@ -222,6 +223,13 @@ export const GetIconInfo = (action) => {
|
||||
const defaultColor = "#f76b1c";
|
||||
const defaultGradient = ["#fad961", "#f76b1c"];
|
||||
const parsedIcons = {
|
||||
cases: {
|
||||
icon: "M11 3C6.58 3 3 4.79 3 7C3 9.21 6.58 11 11 11C15.42 11 19 9.21 19 7C19 4.79 15.42 3 11 3ZM3 9V12C3 14.21 6.58 16 11 16C15.42 16 19 14.21 19 12V9C19 11.21 15.42 13 11 13C6.58 13 3 11.21 3 9ZM3 14V17C3 19.21 6.58 21 11 21C12.41 21 13.79 20.81 15 20.46V17.46C13.79 17.81 12.41 18 11 18C6.58 18 3 16.21 3 14ZM20 14V17H17V19H20V22H22V19H25V17H22V14",
|
||||
iconColor: "white",
|
||||
iconBackgroundColor: "#8acc3f",
|
||||
originalIcon: "",
|
||||
fillGradient: ["#8acc3f", "#459622"],
|
||||
},
|
||||
cache_add: {
|
||||
icon: "M11 3C6.58 3 3 4.79 3 7C3 9.21 6.58 11 11 11C15.42 11 19 9.21 19 7C19 4.79 15.42 3 11 3ZM3 9V12C3 14.21 6.58 16 11 16C15.42 16 19 14.21 19 12V9C19 11.21 15.42 13 11 13C6.58 13 3 11.21 3 9ZM3 14V17C3 19.21 6.58 21 11 21C12.41 21 13.79 20.81 15 20.46V17.46C13.79 17.81 12.41 18 11 18C6.58 18 3 16.21 3 14ZM20 14V17H17V19H20V22H22V19H25V17H22V14",
|
||||
iconColor: "white",
|
||||
|
||||
Reference in New Issue
Block a user