Loads of minor updates with cloud/onprem sync

This commit is contained in:
Frikky
2024-04-26 17:45:07 +02:00
parent e05e487db9
commit 9e34930718
9 changed files with 229 additions and 199 deletions
+1 -1
View File
@@ -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 const isChildOrg = userdata.active_org.creator_org !== "" && userdata.active_org.creator_org !== undefined && userdata.active_org.creator_org !== null
return ( return (
<div style={{}}> <div style={{ width: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
{addDealModal} {addDealModal}
<Typography variant="h4" style={{ marginTop: 20, marginBottom: 10 }}> <Typography variant="h4" style={{ marginTop: 20, marginBottom: 10 }}>
Billing & Licensing Billing & Licensing
+2 -2
View File
@@ -15,7 +15,7 @@ import {
//import { useAlert //import { useAlert
const Branding = (props) => { 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 alert = useAlert();
const [publishingInfo, setPublishingInfo] = useState(""); const [publishingInfo, setPublishingInfo] = useState("");
const [publishRequirements, setPublishRequirements] = useState([]) const [publishRequirements, setPublishRequirements] = useState([])
@@ -103,7 +103,7 @@ const Branding = (props) => {
} }
return ( return (
<div> <div style={{ width: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
<h2> <h2>
Branding Branding
</h2> </h2>
+112 -112
View File
@@ -1,10 +1,10 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import theme from "../theme.jsx"; import theme from "../theme.jsx";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import ReactJson from "react-json-view"; import ReactJson from "react-json-view";
import { import {
Typography, Typography,
Tooltip, Tooltip,
Divider, Divider,
TextField, TextField,
@@ -22,8 +22,8 @@ import {
} from "@mui/material"; } from "@mui/material";
import { import {
Link as LinkIcon, Link as LinkIcon,
AutoFixHigh as AutoFixHighIcon, AutoFixHigh as AutoFixHighIcon,
Edit as EditIcon, Edit as EditIcon,
FileCopy as FileCopyIcon, FileCopy as FileCopyIcon,
SelectAll as SelectAllIcon, SelectAll as SelectAllIcon,
@@ -46,7 +46,7 @@ import {
Visibility as VisibilityIcon, Visibility as VisibilityIcon,
VisibilityOff as VisibilityOffIcon, VisibilityOff as VisibilityOffIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { validateJson, } from "../views/Workflows.jsx"; import { validateJson, } from "../views/Workflows.jsx";
const scrollStyle1 = { const scrollStyle1 = {
height: 100, height: 100,
@@ -64,9 +64,9 @@ const scrollStyle2 = {
overflow: "scroll", overflow: "scroll",
} }
const CacheView = (props) => { const CacheView = (props) => {
const { globalUrl, userdata, serverside, orgId } = props; const { globalUrl, userdata, serverside, orgId, isSelectedDataStore } = props;
const [orgCache, setOrgCache] = React.useState(""); const [orgCache, setOrgCache] = React.useState("");
const [listCache, setListCache] = React.useState([]); const [listCache, setListCache] = React.useState([]);
const [addCache, setAddCache] = React.useState(""); const [addCache, setAddCache] = React.useState("");
@@ -79,7 +79,7 @@ const CacheView = (props) => {
const [dataValue, setDataValue] = React.useState({}); const [dataValue, setDataValue] = React.useState({});
const [editCache, setEditCache] = React.useState(false); const [editCache, setEditCache] = React.useState(false);
const [show, setShow] = useState({}); const [show, setShow] = useState({});
useEffect(() => { useEffect(() => {
listOrgCache(orgId); listOrgCache(orgId);
}, []); }, []);
@@ -155,22 +155,22 @@ const CacheView = (props) => {
const deleteCache = (orgId, key) => { const deleteCache = (orgId, key) => {
toast("Attempting to delete Cache"); toast("Attempting to delete Cache");
// method: "DELETE", // method: "DELETE",
const method = "POST" const method = "POST"
//const url = `${globalUrl}/api/v1/orgs/${orgId}/cache/${key}` //const url = `${globalUrl}/api/v1/orgs/${orgId}/cache/${key}`
const url = `${globalUrl}/api/v1/orgs/${orgId}/delete_cache` const url = `${globalUrl}/api/v1/orgs/${orgId}/delete_cache`
const parsed = { const parsed = {
"org_id": orgId, "org_id": orgId,
"key": key, "key": key,
} }
fetch(url, { fetch(url, {
method: method, method: method,
headers: { headers: {
Accept: "application/json", Accept: "application/json",
}, },
body: JSON.stringify(parsed), body: JSON.stringify(parsed),
credentials: "include", credentials: "include",
}) })
.then((response) => { .then((response) => {
@@ -255,20 +255,20 @@ const CacheView = (props) => {
}); });
}; };
const isValidJson = validateJson(value) const isValidJson = validateJson(value)
const autoFixJson = (inputvalue) => { const autoFixJson = (inputvalue) => {
console.log("inputvalue: ", inputvalue) console.log("inputvalue: ", inputvalue)
try { try {
var parsedjson = JSON.parse(inputvalue) var parsedjson = JSON.parse(inputvalue)
// setValue() with the parsed json as string // setValue() with the parsed json as string
setValue(JSON.stringify(parsedjson, null, 2)) setValue(JSON.stringify(parsedjson, null, 2))
} catch (e) { } catch (e) {
console.log("Error parsing JSON: ", e) console.log("Error parsing JSON: ", e)
//return JSON.stringify(inputvalue); //return JSON.stringify(inputvalue);
} }
} }
const modalView = ( const modalView = (
// console.log("key:", dataValue.key), // console.log("key:", dataValue.key),
//console.log("value:",dataValue.value), //console.log("value:",dataValue.value),
@@ -316,21 +316,21 @@ const CacheView = (props) => {
/> />
</div> </div>
<div style={{ paddingLeft: 30, paddingRight: 30 }}> <div style={{ paddingLeft: 30, paddingRight: 30 }}>
<div style={{display: "flex", }}> <div style={{display: "flex", }}>
<Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}> <Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}>
Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON) Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON)
</Typography> </Typography>
<Tooltip title="Auto Fix JSON" placement="right"> <Tooltip title="Auto Fix JSON" placement="right">
<IconButton <IconButton
style={{flex: 1, }} style={{flex: 1, }}
onClick={() => { onClick={() => {
autoFixJson(value) autoFixJson(value)
}} }}
> >
<AutoFixHighIcon /> <AutoFixHighIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</div> </div>
<TextField <TextField
color="primary" color="primary"
style={{ backgroundColor: theme.palette.inputColor, marginTop: 0, }} style={{ backgroundColor: theme.palette.inputColor, marginTop: 0, }}
@@ -347,22 +347,22 @@ const CacheView = (props) => {
id="Valuefield" id="Valuefield"
margin="normal" margin="normal"
variant="outlined" variant="outlined"
multiline multiline
minRows={4} minRows={4}
maxRows={12} maxRows={12}
//defaultValue={editCache ? dataValue.value : ""} //defaultValue={editCache ? dataValue.value : ""}
value={value} value={value}
onChange={(e) => setValue(e.target.value)} onChange={(e) => setValue(e.target.value)}
/> />
</div> </div>
<DialogActions style={{ paddingLeft: "30px", paddingRight: '30px' }}> <DialogActions style={{ paddingLeft: "30px", paddingRight: '30px' }}>
<Button <Button
style={{ borderRadius: "0px" }} style={{ borderRadius: "0px" }}
onClick={() => { onClick={() => {
setModalOpen(false) setModalOpen(false)
setValue("") setValue("")
setDataValue({}) setDataValue({})
}} }}
color="primary" color="primary"
> >
Cancel Cancel
@@ -372,9 +372,9 @@ const CacheView = (props) => {
style={{ borderRadius: "0px" }} style={{ borderRadius: "0px" }}
onClick={() => { onClick={() => {
{editCache ? editOrgCache(orgId) : addOrgCache(orgId)} {editCache ? editOrgCache(orgId) : addOrgCache(orgId)}
setValue("") setValue("")
setDataValue({}) setDataValue({})
}} }}
color="primary" color="primary"
> >
@@ -386,51 +386,51 @@ const CacheView = (props) => {
return ( 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} {modalView}
<div style={{ marginTop: 20, marginBottom: 20 }}> <div style={{ marginTop: isSelectedDataStore?null:20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>Shuffle Datastore</h2> <h2 style={{ display: isSelectedDataStore?null: "inline" }}>Shuffle Datastore</h2>
<span style={{ marginLeft: 25 }}> <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. You can store anything from lists of IPs to complex configurations.&nbsp; 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.&nbsp;
<a <a
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="/docs/organizations#datastore" href="/docs/organizations#datastore"
style={{ textDecoration: "none", color: "#f85a3e" }} style={{ textDecoration: isSelectedDataStore?null:"none", color: isSelectedDataStore?"#FF8444":"#f85a3e" }}
> >
Learn more Learn more
</a> </a>
</span> </span>
</div> </div>
<Button <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" variant="contained"
color="primary" color="primary"
onClick={() =>{ onClick={() =>{
setEditCache(false) setEditCache(false)
setModalOpen(true) setModalOpen(true)
setValue("") setValue("")
}} }}
> >
Add Cache Add Cache
</Button> </Button>
<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" variant="contained"
color="primary" color="primary"
onClick={() => listOrgCache(orgId)} onClick={() => listOrgCache(orgId)}
> >
<CachedIcon /> <CachedIcon />
</Button> </Button>
<Divider {isSelectedDataStore? null :<Divider
style={{ style={{
marginTop: 20, marginTop: 20,
marginBottom: 20, marginBottom: 20,
}} }}
/> />}
<List> <List style={{borderRadius: isSelectedDataStore?8:null, border:isSelectedDataStore?"1px solid #494949":null, marginTop:isSelectedDataStore?24:null}}>
<ListItem> <ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore?"1px solid #494949":null}}>
<ListItemText <ListItemText
primary="Key" primary="Key"
style={{ minWidth: 250, maxWidth: 250, }} style={{ minWidth: 250, maxWidth: 250, }}
@@ -454,8 +454,8 @@ const CacheView = (props) => {
if (index % 2 === 0) { if (index % 2 === 0) {
bgColor = "#1f2023"; bgColor = "#1f2023";
} }
const validate = validateJson(data.value); const validate = validateJson(data.value);
return ( return (
<ListItem key={index} style={{ backgroundColor: bgColor, maxHeight: 300, overflow: "auto", }}> <ListItem key={index} style={{ backgroundColor: bgColor, maxHeight: 300, overflow: "auto", }}>
<ListItemText <ListItemText
@@ -467,35 +467,35 @@ const CacheView = (props) => {
primary={data.key} primary={data.key}
/> />
<ListItemText <ListItemText
style={{ style={{
minWidth: 400, minWidth: 400,
maxWidth: 400, maxWidth: 400,
}} }}
primary={validate.valid ? primary={validate.valid ?
<ReactJson <ReactJson
src={validate.result} src={validate.result}
theme={theme.palette.jsonTheme} theme={theme.palette.jsonTheme}
style={theme.palette.reactJsonStyle} style={theme.palette.reactJsonStyle}
collapsed={true} collapsed={true}
enableClipboard={(copy) => { enableClipboard={(copy) => {
//handleReactJsonClipboard(copy); //handleReactJsonClipboard(copy);
}} }}
displayDataTypes={false} displayDataTypes={false}
onSelect={(select) => { onSelect={(select) => {
//HandleJsonCopy(showResult, select, data.action.label); //HandleJsonCopy(showResult, select, data.action.label);
//console.log("SELECTED!: ", select); //console.log("SELECTED!: ", select);
}} }}
name={"value"} name={"value"}
/> />
: :
data.value data.value
} }
/> />
<ListItemText <ListItemText
style={{ style={{
maxWidth: 200, maxWidth: 200,
minWidth: 200, minWidth: 200,
marginLeft: 50, marginLeft: 50,
}} }}
primary=<span style={{ display: "inline" }}> primary=<span style={{ display: "inline" }}>
<Tooltip <Tooltip
@@ -508,11 +508,11 @@ const CacheView = (props) => {
style={{ padding: "6px" }} style={{ padding: "6px" }}
onClick={() => { onClick={() => {
setEditCache(true) setEditCache(true)
setDataValue({ setDataValue({
"key": data.key, "key": data.key,
"value":data.value "value":data.value
}) })
setValue(data.value) setValue(data.value)
setModalOpen(true) setModalOpen(true)
}} }}
> >
@@ -525,18 +525,18 @@ const CacheView = (props) => {
<Tooltip <Tooltip
title={"Public URL (types: text, raw, json)"} title={"Public URL (types: text, raw, json)"}
style={{ marginLeft: 0, }} style={{ marginLeft: 0, }}
aria-label={"Public URL"} aria-label={"Public URL"}
> >
<span> <span>
<IconButton <IconButton
style={{ padding: "6px" }} 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={() => { 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> </IconButton>
</span> </span>
</Tooltip> </Tooltip>
+16 -15
View File
@@ -41,7 +41,7 @@ import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
import theme from "../theme.jsx"; import theme from "../theme.jsx";
const Files = (props) => { const Files = (props) => {
const { globalUrl, userdata, serverside, selectedOrganization, isCloud, } = props; const { globalUrl, userdata, serverside, selectedOrganization, isCloud,isSelectedFiles } = props;
const [files, setFiles] = React.useState([]); const [files, setFiles] = React.useState([]);
const [selectedNamespace, setSelectedNamespace] = React.useState("default"); const [selectedNamespace, setSelectedNamespace] = React.useState("default");
@@ -617,16 +617,16 @@ const Files = (props) => {
style={{ style={{
maxWidth: window.innerWidth > 1366 ? 1366 : 1200, maxWidth: window.innerWidth > 1366 ? 1366 : 1200,
margin: "auto", margin: "auto",
padding: 20, padding: isSelectedFiles ? null : 20,
}} }}
onDrop={uploadFile} 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"> <Tooltip color="primary" title={"Import files to Shuffle from Git"} placement="top">
<IconButton <IconButton
color="secondary" color="secondary"
style={{position: "absolute", right: 0, top: 0, }} style={{position: "absolute", right: 0, top: isSelectedFiles?null:0, left: isSelectedFiles? 990:null }}
variant="text" variant="text"
onClick={() => setLoadFileModalOpen(true)} onClick={() => setLoadFileModalOpen(true)}
> >
@@ -636,15 +636,15 @@ const Files = (props) => {
{fileDownloadModal} {fileDownloadModal}
<div style={{ marginTop: 20, marginBottom: 20 }}> <div style={{ marginTop: isSelectedFiles ? 2: 20, marginBottom:20 }}>
<h2 style={{ display: "inline" }}>Files</h2> <h2 style={{ display: isSelectedFiles ? null : "inline", marginTop: isSelectedFiles?0:null, marginBottom: isSelectedFiles?8:null }}>Files</h2>
<span style={{ marginLeft: 25 }}> <span style={{ marginLeft: isSelectedFiles ? null : 25, color:isSelectedFiles?"#9E9E9E":null}}>
Files from Workflows are a way to store as well as edit files.{" "} Files from Workflows are a way to store as well as edit files.{" "}
<a <a
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="https://shuffler.io/docs/organizations#files" href="https://shuffler.io/docs/organizations#files"
style={{ textDecoration: "none", color: "#f85a3e" }} style={{ textDecoration: isSelectedFiles ? null:"none", color: isSelectedFiles? "#FF8444": "#f85a3e" }}
> >
Learn more Learn more
</a> </a>
@@ -659,6 +659,7 @@ const Files = (props) => {
onClick={() => { onClick={() => {
upload.click(); 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 <PublishIcon /> Upload files
</Button> </Button>
@@ -678,7 +679,7 @@ const Files = (props) => {
}} }}
/> />
<Button <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" variant="contained"
color="primary" color="primary"
onClick={() => getFiles()} onClick={() => getFiles()}
@@ -783,20 +784,20 @@ const Files = (props) => {
key = {fileContent} //https://reactjs.org/docs/reconciliation.html#recursing-on-children key = {fileContent} //https://reactjs.org/docs/reconciliation.html#recursing-on-children
runUpdateText = {runUpdateText} runUpdateText = {runUpdateText}
/> />
{isSelectedFiles?null:
<Divider <Divider
style={{ style={{
marginTop: 20, marginTop: 20,
marginBottom: 20, marginBottom: 20,
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.inputColor,
}} }}
/> />}
<List> <List style={{borderRadius: isSelectedFiles?8:null, border:isSelectedFiles?"1px solid #494949":null, marginTop:isSelectedFiles?24:null}}>
<ListItem> <ListItem style={{width:isSelectedFiles?"100%":null, borderBottom:isSelectedFiles?"1px solid #494949":null}}>
<ListItemText <ListItemText
primary="Updated" primary="Updated"
style={{ maxWidth: 225, minWidth: 225 }} style={{ maxWidth: 185, minWidth: 185 }}
/> />
<ListItemText <ListItemText
primary="Name" primary="Name"
@@ -813,7 +814,7 @@ const Files = (props) => {
/> />
<ListItemText <ListItemText
primary="Md5" primary="Md5"
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }} style={{ minWidth: 250, maxWidth: 250, overflow: "hidden" }}
/> />
<ListItemText <ListItemText
primary="Status" primary="Status"
+1 -1
View File
@@ -616,7 +616,7 @@ const Header = (props) => {
<Divider style={{marginBottom: 10, }}/> <Divider style={{marginBottom: 10, }}/>
<Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 5, marginBottom: 5,}}> <Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 5, marginBottom: 5,}}>
Version: 1.3.4 Version: 1.4.0
</Typography> </Typography>
</Menu> </Menu>
</span> </span>
+11 -10
View File
@@ -20,7 +20,7 @@ import Priority from "../components/Priority.jsx";
//import { useAlert //import { useAlert
const Priorities = (props) => { 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 [showDismissed, setShowDismissed] = React.useState(false);
const [showRead, setShowRead] = React.useState(false); const [showRead, setShowRead] = React.useState(false);
const [appFramework, setAppFramework] = React.useState({}); const [appFramework, setAppFramework] = React.useState({});
@@ -312,15 +312,15 @@ const Priorities = (props) => {
} }
return ( return (
<div style={{maxWidth: 1000, }}> <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: "inline" }}>Suggestions</h2> <h2 style={{ display: clickedFromOrgTab ?null:"inline", marginBottom: clickedFromOrgTab ? 8:null, marginTop: clickedFromOrgTab ?0:null, color: clickedFromOrgTab ?"#ffffff":null }}>Suggestions</h2>
<span style={{ marginLeft: 25 }}> <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. These range from simple configurations in Shuffle to Usecases you may have missed.&nbsp; 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.&nbsp;
<a <a
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="/docs/organizations#priorities" href="/docs/organizations#priorities"
style={{ textDecoration: "none", color: "#f85a3e" }} style={{ textDecoration: clickedFromOrgTab ?null:"none", color: clickedFromOrgTab ?"#FF8444":"#f85a3e" }}
> >
Learn more Learn more
</a> </a>
@@ -348,6 +348,7 @@ const Priorities = (props) => {
globalUrl={globalUrl} globalUrl={globalUrl}
priority={priority} priority={priority}
checkLogin={checkLogin} checkLogin={checkLogin}
clickedFromOrgTab={true}
setAdminTab={setAdminTab} setAdminTab={setAdminTab}
setCurTab={setCurTab} setCurTab={setCurTab}
appFramework={appFramework} appFramework={appFramework}
@@ -355,15 +356,15 @@ const Priorities = (props) => {
) )
}) })
} }
<Divider style={{marginTop: 50, marginBottom: 50, }} /> {clickedFromOrgTab?null:<Divider style={{marginTop: 50, marginBottom: 50, }} />}
<h2 style={{ display: "inline" }}>Notifications</h2> <h2 style={{ display: clickedFromOrgTab?null:"inline", marginBottom: clickedFromOrgTab? 8:null, marginTop: clickedFromOrgTab?40:null, color: clickedFromOrgTab?"#ffffff":null }}>Notifications</h2>
<span style={{ marginLeft: 25 }}> <span style={{ marginLeft: clickedFromOrgTab?null:25, color: clickedFromOrgTab?"#9E9E9E":null, }}>
Notifications help you find potential problems with your workflows and apps.&nbsp; Notifications help you find potential problems with your workflows and apps.&nbsp;
<a <a
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="/docs/organizations#notifications" href="/docs/organizations#notifications"
style={{ textDecoration: "none", color: "#f85a3e" }} style={{ textDecoration: clickedFromOrgTab?null:"none", color: clickedFromOrgTab?"#FF8444":"#f85a3e" }}
> >
Learn more Learn more
</a> </a>
+3 -3
View File
@@ -22,7 +22,7 @@ import {
//import { useAlert //import { useAlert
const Priority = (props) => { 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"; const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
let navigate = useNavigate(); let navigate = useNavigate();
@@ -114,7 +114,7 @@ const Priority = (props) => {
const srcSize = realignedSrc ? 35 : 30 const srcSize = realignedSrc ? 35 : 30
const dstSize = realignedDst ? 35 : 30 const dstSize = realignedDst ? 35 : 30
return ( 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",}}> <div style={{flex: 2, overflow: "hidden",}}>
<span style={{display: "flex", }}> <span style={{display: "flex", }}>
{priority.type === "usecase" || priority.type == "apps" ? <AutoFixHighIcon style={{height: 19, width: 19, marginLeft: 3, marginRight: 10, }}/> : null} {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>
<div style={{flex: 1, display: "flex", marginLeft: 30, }}> <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) { if (isCloud) {
ReactGA.event({ ReactGA.event({
+25 -1
View File
@@ -592,7 +592,27 @@ const AngularWorkflow = (defaultprops) => {
] ]
}*/ }*/
] ]
}] },{
"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,
}]
},
]
}] }]
/* /*
@@ -17148,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" 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 "" return ""
} }
+58 -54
View File
@@ -1037,55 +1037,41 @@ const AppCreator = (defaultprops) => {
"schema" "schema"
] !== null ] !== null
) { ) {
try { try {
if ( if (
methodvalue["requestBody"]["content"]["application/xml"][ methodvalue["requestBody"]["content"]["application/xml"][
"schema" "schema"
]["properties"] !== undefined ]["properties"] !== undefined
) { ) {
var tmpobject = {}; var tmpobject = {};
for (let [prop, propvalue] of Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["properties"])) { for (let [prop, propvalue] of Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["properties"])) {
tmpobject[prop] = `\$\{${prop}\}`; tmpobject[prop] = `\$\{${prop}\}`;
} }
for (let [subkey,subkeyval] in Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["required"])) { for (let [subkey,subkeyval] in Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["required"])) {
const tmpitem = const tmpitem =
methodvalue["requestBody"]["content"][ methodvalue["requestBody"]["content"][
"application/xml" "application/xml"
]["schema"]["required"][subkey]; ]["schema"]["required"][subkey];
tmpobject[tmpitem] = `\$\{${tmpitem}\}`; tmpobject[tmpitem] = `\$\{${tmpitem}\}`;
} }
//console.log("OBJ XML: ", tmpobject) //console.log("OBJ XML: ", tmpobject)
//newaction["body"] = XML.stringify(tmpobject, null, 2) //newaction["body"] = XML.stringify(tmpobject, null, 2)
} }
} catch (e) { } catch (e) {
console.log("RequestBody xml error: ", e, path) console.log("RequestBody xml error: ", e, path)
} }
} }
} else { } else {
if ( if (methodvalue["requestBody"]["content"]["example"] !== undefined) {
methodvalue["requestBody"]["content"]["example"] !== undefined if (methodvalue["requestBody"]["content"]["example"]["example"] !== undefined) {
) { newaction["body"] = methodvalue["requestBody"]["content"]["example"]["example"]
if (
methodvalue["requestBody"]["content"]["example"][
"example"
] !== undefined
) {
newaction["body"] =
methodvalue["requestBody"]["content"]["example"][
"example"
];
//JSON.stringify(tmpobject, null, 2)
} }
} }
if ( if (methodvalue["requestBody"]["content"]["multipart/form-data"] !== undefined) {
methodvalue["requestBody"]["content"][
"multipart/form-data"
] !== undefined
) {
if ( if (
methodvalue["requestBody"]["content"][ methodvalue["requestBody"]["content"][
"multipart/form-data" "multipart/form-data"
@@ -1553,8 +1539,10 @@ const AppCreator = (defaultprops) => {
} else if (parameter.in === "body") { } else if (parameter.in === "body") {
// FIXME: Add tracking for components // FIXME: Add tracking for components
// E.G: https://raw.githubusercontent.com/owentl/Shuffle/master/gosecure.yaml // E.G: https://raw.githubusercontent.com/owentl/Shuffle/master/gosecure.yaml
if (parameter.example !== undefined) { if (parameter.example !== undefined && parameter.example !== null) {
newaction.body = parameter.example; if (newaction.body === undefined || newaction.body === null || newaction.body.length < 5) {
newaction.body = parameter.example
}
} }
} else if (parameter.in === "header") { } else if (parameter.in === "header") {
newaction.headers += `${parameter.name}=${parameter.example}\n`; 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) { if (newaction.name === "" || newaction.name === undefined) {
// Find a unique part of the string // Find a unique part of the string
// FIXME: Looks for length between /, find the one where they differ // FIXME: Looks for length between /, find the one where they differ
@@ -1920,11 +1915,11 @@ const AppCreator = (defaultprops) => {
setProjectCategories(all_categories); setProjectCategories(all_categories);
// Rearrange them by which has action_label // 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") const firstActions = newActions.filter(data => data.action_label !== undefined && data.action_label !== null && data.action_label !== "No Label")
console.log("First actions: ", firstActions) console.log("First actions: ", firstActions)
const secondActions = newActions.filter(data => data.action_label === undefined || data.action_label === null || data.action_label === "No Label") const secondActions = newActions.filter(data => data.action_label === undefined || data.action_label === null || data.action_label === "No Label")
newActions = firstActions.concat(secondActions) newActions = firstActions.concat(secondActions)
setActions(newActions); setActions(newActions);
//data.paths[item.url][item.method.toLowerCase()]["x-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) Refresh-token URL for Oauth2 (Optional)
</Typography> </Typography>
<TextField <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} fullWidth={true}
placeholder="The URL to retrieve refresh-tokens at" placeholder="The URL to retrieve refresh-tokens at"
type="name" type="name"
@@ -3086,8 +3084,9 @@ const AppCreator = (defaultprops) => {
margin="normal" margin="normal"
variant="outlined" variant="outlined"
value={refreshUrl} 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)} onChange={(e) => setRefreshUrl(e.target.value)}
onBlur={(event) => { onBlur={(event) => {
var tmpstring = event.target.value.trim(); var tmpstring = event.target.value.trim();
if ( if (
@@ -3153,7 +3152,7 @@ const AppCreator = (defaultprops) => {
</Typography> </Typography>
<div style={{display: "flex", marginTop: 10, }}> <div style={{display: "flex", marginTop: 10, }}>
<div style={{flex: 4,}}> <div style={{flex: 4,}}>
Key Key
<TextField <TextField
required required
style={{ marginTop: 0, backgroundColor: inputColor }} style={{ marginTop: 0, backgroundColor: inputColor }}
@@ -3166,12 +3165,17 @@ const AppCreator = (defaultprops) => {
value={parameterName} value={parameterName}
helperText={ helperText={
<span style={{ color: "white", marginBottom: "2px" }}> <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> </span>
} }
onChange={(e) => { onChange={(e) => {
setParameterName(e.target.value); setParameterName(e.target.value);
}} }}
onBlur={(event) => {
var tmpstring = event.target.value.trim()
// Check if tmpstring has any of the illegal characters in it
}}
InputProps={{ InputProps={{
classes: { classes: {
notchedOutline: classes.notchedOutline, notchedOutline: classes.notchedOutline,