Merge branch '1.3.0'
This commit is contained in:
@@ -70,7 +70,18 @@ http {
|
|||||||
try_files $uri /index.html;
|
try_files $uri /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ /api/v(1|2) {
|
location /api/v1 {
|
||||||
|
proxy_pass http://{{ getenv "BACKEND_HOSTNAME" "shuffle-backend" }}:5001;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
proxy_connect_timeout 900;
|
||||||
|
proxy_send_timeout 900;
|
||||||
|
proxy_read_timeout 900;
|
||||||
|
send_timeout 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2 {
|
||||||
proxy_pass http://{{ getenv "BACKEND_HOSTNAME" "shuffle-backend" }}:5001;
|
proxy_pass http://{{ getenv "BACKEND_HOSTNAME" "shuffle-backend" }}:5001;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ cytoscape.use(edgehandles);
|
|||||||
|
|
||||||
export const findSpecificApp = (framework, inputcategory) => {
|
export const findSpecificApp = (framework, inputcategory) => {
|
||||||
// Get the frameworkinfo for the org and fill in
|
// Get the frameworkinfo for the org and fill in
|
||||||
//
|
|
||||||
if (framework === undefined || framework === null) {
|
if (framework === undefined || framework === null) {
|
||||||
console.log("findSpecificApp: framework is null")
|
console.log("findSpecificApp: framework is null")
|
||||||
return null
|
return null
|
||||||
@@ -52,7 +51,7 @@ export const findSpecificApp = (framework, inputcategory) => {
|
|||||||
|
|
||||||
const category = inputcategory.toLowerCase().split(":")[0].trim()
|
const category = inputcategory.toLowerCase().split(":")[0].trim()
|
||||||
|
|
||||||
console.log("findSpecificApp: ", category, framework)
|
//console.log("findSpecificApp: ", category, framework)
|
||||||
if (category === "edr" || category === "eradication" || category === "edr & av") {
|
if (category === "edr" || category === "eradication" || category === "edr & av") {
|
||||||
if (framework["EDR & AV"] !== undefined && framework["EDR & AV"].name !== undefined) {
|
if (framework["EDR & AV"] !== undefined && framework["EDR & AV"].name !== undefined) {
|
||||||
return framework["EDR & AV"]
|
return framework["EDR & AV"]
|
||||||
@@ -65,7 +64,7 @@ export const findSpecificApp = (framework, inputcategory) => {
|
|||||||
description: "",
|
description: "",
|
||||||
id: "",
|
id: "",
|
||||||
}
|
}
|
||||||
} else if (category === "communication") {
|
} else if (category === "communication" || category === "comms") {
|
||||||
if (framework["Comms"] !== undefined && framework["Comms"].name !== undefined) {
|
if (framework["Comms"] !== undefined && framework["Comms"].name !== undefined) {
|
||||||
return framework["Comms"]
|
return framework["Comms"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||||
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
||||||
const AppGrid = props => {
|
const AppGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, isHeader } = props
|
||||||
|
|
||||||
const isCloud =
|
const isCloud =
|
||||||
window.location.host === "localhost:3002" ||
|
window.location.host === "localhost:3002" ||
|
||||||
@@ -167,7 +167,7 @@ const AppGrid = props => {
|
|||||||
backgroundColor: index === mouseHoverIndex ? "rgba(255,255,255,0.8)" : theme.palette.inputColor,
|
backgroundColor: index === mouseHoverIndex ? "rgba(255,255,255,0.8)" : theme.palette.inputColor,
|
||||||
color: index === mouseHoverIndex ? theme.palette.inputColor : "rgba(255,255,255,0.8)",
|
color: index === mouseHoverIndex ? theme.palette.inputColor : "rgba(255,255,255,0.8)",
|
||||||
border: `1px solid ${innerColor}`,
|
border: `1px solid ${innerColor}`,
|
||||||
padding: 15,
|
padding: isHeader ? null : 15,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
minHeight: 116,
|
minHeight: 116,
|
||||||
|
|||||||
@@ -3,25 +3,26 @@ import theme from '../theme.jsx';
|
|||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { useNavigate, Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon, Close as CloseIcon, Folder as FolderIcon, LibraryBooks as LibraryBooksIcon } from '@mui/icons-material';
|
import { Search as Searchicon, CloudQueue as CloudQueueicon, Code as Codeicon, Close as Closeicon, Folder as Foldericon, LibraryBooks as LibraryBooksicon, Delete as DeleteIcon, Close as CloseIcon, } from '@mui/icons-material';
|
||||||
import aa from 'search-insights'
|
import aa from 'search-insights'
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import Deleteicon from '@mui/icons-material/Delete';
|
||||||
import ShowChartIcon from '@mui/icons-material/ShowChart';
|
import ShowCharticon from '@mui/icons-material/ShowChart';
|
||||||
import ExploreIcon from '@mui/icons-material/Explore';
|
import Exploreicon from '@mui/icons-material/Explore';
|
||||||
import LightbulbIcon from "@mui/icons-material/Lightbulb";
|
import Lightbulbicon from "@mui/icons-material/Lightbulb";
|
||||||
import NewReleasesIcon from "@mui/icons-material/NewReleases";
|
import NewReleasesicon from "@mui/icons-material/NewReleases";
|
||||||
import ExtensionIcon from "@mui/icons-material/Extension";
|
import Extensionicon from "@mui/icons-material/Extension";
|
||||||
import EmailIcon from "@mui/icons-material/Email";
|
import Emailicon from "@mui/icons-material/Email";
|
||||||
import FingerprintIcon from '@mui/icons-material/Fingerprint';
|
import Fingerprinticon from '@mui/icons-material/Fingerprint';
|
||||||
import AppSearch from "../components/Appsearch.jsx";
|
import AppSearch from "../components/Appsearch.jsx";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { findSpecificApp } from "../components/AppFramework.jsx";
|
||||||
import {
|
import {
|
||||||
Zoom,
|
Zoom,
|
||||||
Grid,
|
Grid,
|
||||||
Paper,
|
Paper,
|
||||||
TextField,
|
TextField,
|
||||||
Collapse,
|
Collapse,
|
||||||
IconButton,
|
iconButton,
|
||||||
Avatar,
|
Avatar,
|
||||||
ButtonBase,
|
ButtonBase,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
@@ -32,370 +33,261 @@ import {
|
|||||||
ListItem,
|
ListItem,
|
||||||
ListItemAvatar,
|
ListItemAvatar,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
|
IconButton,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
const AppSearchButtons = (props) => {
|
const AppSearchButtons = (props) => {
|
||||||
const { userdata, globalUrl, appFramework, defaultSearch, finishedApps, onNodeSelect, setDiscoveryData, appName, AppImage, setDefaultSearch, discoveryData } = props
|
const { userdata, globalUrl, appFramework, finishedApps, appType, totalApps, index, onNodeSelect, setDiscoveryData, appName, AppImage, setDefaultSearch, discoveryData, checkLogin, setMissing, } = props
|
||||||
|
|
||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
const [moreButton, setMoreButton] = useState(false);
|
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
const sizing = moreButton ? 510 : 480;
|
const [isHover, setIsHover] = useState(false);
|
||||||
|
const [localSearchOpen, setLocalSearchOpen] = useState(false)
|
||||||
|
const [newSelectedApp, setNewSelectedApp] = useState(undefined)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("AppSearchButtons: newSelectedApp: " + JSON.stringify(newSelectedApp))
|
||||||
|
|
||||||
|
if (newSelectedApp !== undefined && setMissing != undefined) {
|
||||||
|
console.log("AppSearchButtons: setMissing is defined!")
|
||||||
|
|
||||||
|
const submitAppFramework = {
|
||||||
|
"description": newSelectedApp.description,
|
||||||
|
"id": newSelectedApp.objectID,
|
||||||
|
"name": newSelectedApp.name,
|
||||||
|
"type": appType,
|
||||||
|
"large_image": newSelectedApp.image_url,
|
||||||
|
}
|
||||||
|
|
||||||
|
setFrameworkItem(submitAppFramework)
|
||||||
|
setMissing(newSelectedApp)
|
||||||
|
}
|
||||||
|
}, [newSelectedApp])
|
||||||
|
|
||||||
|
if (appType === undefined) {
|
||||||
|
console.log("Apptype is required in AppSearchButtons")
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const buttonWidth = 450;
|
const buttonWidth = 450;
|
||||||
const buttonMargin = 10;
|
const buttonMargin = 10;
|
||||||
const bottomButtonStyle = {
|
|
||||||
borderRadius: 200,
|
|
||||||
marginTop: moreButton ? 44 : "",
|
|
||||||
height: 51,
|
|
||||||
width: 510,
|
|
||||||
fontSize: 16,
|
|
||||||
// background: "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)",
|
|
||||||
background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)",
|
|
||||||
padding: "16px 24px",
|
|
||||||
// top: 20,
|
|
||||||
// margin: "auto",
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
itemAlign: "center",
|
|
||||||
// marginTop: 25
|
|
||||||
// marginLeft: "65px",
|
|
||||||
};
|
|
||||||
const buttonStyle = {
|
|
||||||
flex: 1,
|
|
||||||
width: 224,
|
|
||||||
padding: 25,
|
|
||||||
margin: buttonMargin,
|
|
||||||
color: "var(--White-text, #F1F1F1)",
|
|
||||||
fontWeight: 400,
|
|
||||||
fontSize: 17,
|
|
||||||
background: "rgba(33, 33, 33, 1)",
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
border: "1px solid rgba(33, 33, 33, 1)",
|
|
||||||
borderRadius: 8,
|
|
||||||
marginRight: 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
const handleMouseEnter = () => {
|
||||||
|
setIsHover(true);
|
||||||
|
};
|
||||||
|
|
||||||
const mouseOver = (e) => {
|
const handleMouseLeave = () => {
|
||||||
e.target.style.border = "1px solid #f85a3e";
|
setIsHover(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const foundApp = findSpecificApp(appFramework, appType)
|
||||||
|
if (foundApp === undefined || foundApp === null) {
|
||||||
|
console.log("AppSearchButtons: App not found in appFramework: " + appType)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const setFrameworkItem = (data) => {
|
||||||
|
|
||||||
|
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Status not 200 for framework!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkLogin !== undefined) {
|
||||||
|
checkLogin()
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
if (responseJson.success === false) {
|
||||||
|
if (responseJson.reason !== undefined) {
|
||||||
|
toast("Failed updating: " + responseJson.reason)
|
||||||
|
} else {
|
||||||
|
toast("Failed to update framework for your org.")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//setFrameworkLoaded(true)
|
||||||
|
//setFrameworkData(responseJson)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (checkLogin !== undefined) {
|
||||||
|
checkLogin()
|
||||||
|
}
|
||||||
|
|
||||||
|
toast(error.toString());
|
||||||
|
//setFrameworkLoaded(true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const mouseOut = (e) => {
|
|
||||||
e.target.style.border = "1px solid rgb(33, 33, 33)";
|
const icon = foundApp.large_image
|
||||||
|
let xsValue = 12;
|
||||||
|
if (index !== undefined && index !== 0) {
|
||||||
|
xsValue = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === totalApps - 4 && totalApps % 2 === 1) {
|
||||||
|
xsValue = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === totalApps - 1 || index === totalApps - 2 || index === totalApps - 3) {
|
||||||
|
xsValue = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid item xs={11} style={{ display: "flex" }}>
|
<Grid item xs={xsValue} style={{ alignItems: "center", marginTop: 5, }}
|
||||||
|
onMouseEnter={handleMouseEnter}
|
||||||
{/*<FormLabel style={{ color: "#B9B9BA" }}>Find your integrations!</FormLabel>*/}
|
onMouseLeave={handleMouseLeave}
|
||||||
{/* <div style={{ display: "flex", width: 510, height:100 }}>
|
>
|
||||||
<Button
|
{localSearchOpen ? (
|
||||||
disabled={finishedApps.includes("CASES")}
|
<div
|
||||||
variant={
|
style={{
|
||||||
defaultSearch === "CASES" ? "contained" : "outlined"
|
width: 319,
|
||||||
}
|
height: 395,
|
||||||
color="secondary"
|
flexShrink: 0,
|
||||||
style={{
|
marginLeft: 70,
|
||||||
flex: 1,
|
marginTop: 68,
|
||||||
width: "100%",
|
position: "absolute",
|
||||||
padding: 25,
|
zIndex: 100,
|
||||||
margin: buttonMargin,
|
borderRadius: 6,
|
||||||
fontSize: 18,
|
border: "1px solid var(--Container-Stroke, #494949)",
|
||||||
color: "var(--White-text, #F1F1F1)",
|
background: "var(--Container, #212121)",
|
||||||
fontWeight: 400,
|
boxShadow: "8px 8px 32px 24px rgba(0, 0, 0, 0.16)",
|
||||||
background: "rgba(33, 33, 33, 1)",
|
}}
|
||||||
borderRadius: 8,
|
>
|
||||||
textTransform: 'capitalize',
|
<div style={{ display: "flex" }}>
|
||||||
border: "1px solid rgba(33, 33, 33, 1)" ,
|
<div style={{ display: "flex", textAlign: "center", textTransform: "capitalize" }}>
|
||||||
}}
|
<Typography style={{ padding: 16, color: "#FFFFFF", textTransform: "capitalize" }}> {discoveryData} </Typography>
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
// startIcon = {defaultSearch === "CASES" ? newSelectedApp.image_url : <LightbulbIcon/>}
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("CASES");
|
|
||||||
setDefaultSearch(discoveryData.label)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.cases === undefined || appFramework.cases.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.cases === null || appFramework.cases.large_image === null || appFramework.cases.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<LightbulbIcon style={{ marginTop: 6 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={AppImage} />}
|
|
||||||
<div style={{marginLeft: 8, }}>
|
|
||||||
<Typography style={{display:"flex",border:"none"}} >Case Management</Typography>
|
|
||||||
{appFramework === undefined || appFramework.cases === undefined || appFramework.cases.name === undefined ||
|
|
||||||
appFramework === null || appFramework.cases === null || appFramework.cases.name === null || appFramework.cases.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 12, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{AppName}</Typography>}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", width: 510, height: 100 }}>
|
|
||||||
<Button
|
|
||||||
disabled={finishedApps.includes("SIEM")}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "SIEM" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
style={buttonStyle}
|
|
||||||
// startIcon={<SearchIcon />}
|
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
color="secondary"
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("SIEM");
|
|
||||||
setDefaultSearch(discoveryData.label)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.siem === undefined || appFramework.siem.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.siem === null || appFramework.siem.large_image === null || appFramework.siem.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<SearchIcon style={{ marginTop: 6 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.siem.large_image} />}
|
|
||||||
<div style={{marginLeft: 8,}}>
|
|
||||||
<Typography style={{display:"flex",}}>SIEM</Typography>
|
|
||||||
{appFramework === undefined || appFramework.siem === undefined || appFramework.siem.name === undefined ||
|
|
||||||
appFramework === null || appFramework.siem === null || appFramework.siem.name === null || appFramework.siem.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 12, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.siem.name.split('_').join(' ')}</Typography>}
|
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
<div style={{ display: "flex" }}>
|
||||||
<Button
|
<Tooltip
|
||||||
disabled={
|
title="Close"
|
||||||
finishedApps.includes("EDR & AV") ||
|
placement="top"
|
||||||
finishedApps.includes("ERADICATION")
|
style={{ zIndex: 10011 }}
|
||||||
}
|
>
|
||||||
onMouseOver={mouseOver}
|
<IconButton
|
||||||
onMouseOut={mouseOut}
|
style={{
|
||||||
variant={
|
flex: 1,
|
||||||
defaultSearch === "Eradication" ? "contained" : "outlined"
|
// width: 224,
|
||||||
}
|
marginLeft: discoveryData === ("communication") ? 112 : 200,
|
||||||
style={buttonStyle}
|
width: "100%",
|
||||||
// startIcon={<NewReleasesIcon />}
|
marginBottom: 23,
|
||||||
color="secondary"
|
fontSize: 16,
|
||||||
onClick={(event) => {
|
background: "rgba(33, 33, 33, 1)",
|
||||||
onNodeSelect("ERADICATION");
|
borderColor: "rgba(33, 33, 33, 1)",
|
||||||
}}
|
borderRadius: 8,
|
||||||
>
|
}}
|
||||||
{appFramework === undefined || appFramework.edr === undefined || appFramework.edr.large_image === undefined ||
|
onClick={() => {
|
||||||
appFramework === null || appFramework.edr === null || appFramework.edr.large_image === null || appFramework.edr.large_image.length === 0 ?
|
setLocalSearchOpen(false)
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
}}
|
||||||
<NewReleasesIcon style={{marginTop: 8 }} />
|
>
|
||||||
</div>
|
<Closeicon style={{ width: 16 }} />
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.edr.large_image} />}
|
</IconButton>
|
||||||
<div style={{marginLeft: 8,}}>
|
</Tooltip>
|
||||||
<Typography style={{display:"flex",}}>Endpoint</Typography>
|
<Tooltip
|
||||||
{appFramework === undefined || appFramework.edr === undefined || appFramework.edr.name === undefined ||
|
title="Delete app"
|
||||||
appFramework === null || appFramework.edr === null || appFramework.edr.name === null || appFramework.edr.name.length === 0 ?
|
placement="bottom"
|
||||||
"":<Typography style={{fontSize: 12, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.edr.name.split('_').join(' ')}</Typography>}
|
style={{ zIndex: 10011 }}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
style={{ zIndex: 12501, position: "absolute", top: 32, right: 16 }}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setLocalSearchOpen(false)
|
||||||
|
setDefaultSearch("")
|
||||||
|
const submitDeletedApp = {
|
||||||
|
"description": "",
|
||||||
|
"id": "remove",
|
||||||
|
"name": "",
|
||||||
|
"type": discoveryData
|
||||||
|
}
|
||||||
|
setFrameworkItem(submitDeletedApp)
|
||||||
|
setNewSelectedApp({})
|
||||||
|
setTimeout(() => {
|
||||||
|
setDiscoveryData({})
|
||||||
|
setFrameworkItem(submitDeletedApp)
|
||||||
|
//setNewSelectedApp({})
|
||||||
|
}, 1000)
|
||||||
|
//setAppName(discoveryData.cases.name)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteIcon style={{ color: "white", height: 15, width: 15, }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", width: 510, height: 100 }}>
|
|
||||||
<Button
|
|
||||||
disabled={finishedApps.includes("INTEL")}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "INTEL" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
style={buttonStyle}
|
|
||||||
// startIcon={<ExtensionIcon />}
|
|
||||||
color="secondary"
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("INTEL");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.intel === undefined || appFramework.intel.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.intel === null || appFramework.intel.large_image === null || appFramework.intel.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<ExtensionIcon style={{ marginTop: 8 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.intel.large_image} />}
|
|
||||||
<div style={{marginLeft: 8,}}>
|
|
||||||
<Typography style={{display:"flex",}}>Intel</Typography>
|
|
||||||
{appFramework === undefined || appFramework.intel === undefined || appFramework.intel.name === undefined ||
|
|
||||||
appFramework === null || appFramework.intel === null || appFramework.intel.name === null || appFramework.intel.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 12, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.intel.name.split('_').join(' ')}</Typography>}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
finishedApps.includes("COMMS") ||
|
|
||||||
finishedApps.includes("EMAIL")
|
|
||||||
}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "EMAIL" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
style={buttonStyle}
|
|
||||||
// startIcon={<EmailIcon />}
|
|
||||||
color="secondary"
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("EMAIL");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.communication === undefined || appFramework.communication.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.communication === null || appFramework.communication.large_image === null || appFramework.communication.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<EmailIcon style={{ marginTop: 8 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.communication.large_image} />}
|
|
||||||
<div style={{marginLeft: 8,}}>
|
|
||||||
<Typography style={{display:"flex",}}>Email</Typography>
|
|
||||||
{appFramework === undefined || appFramework.communication === undefined || appFramework.communication.name === undefined ||
|
|
||||||
appFramework === null || appFramework.communication === null || appFramework.communication.name === null || appFramework.communication.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 12, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.communication.name.split('_').join(' ')}</Typography>}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{moreButton ? (
|
|
||||||
<div style={{ display: "flex", width: 510, height: 100, marginBottom: 20 }}>
|
|
||||||
<Button
|
|
||||||
disabled={finishedApps.includes("NETWORK")}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "NETWORK" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
style={buttonStyle}
|
|
||||||
// startIcon={<ExtensionIcon />}
|
|
||||||
color="secondary"
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("NETWORK");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.network === undefined || appFramework.network.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.network === null || appFramework.network.large_image === null || appFramework.network.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<ShowChartIcon style={{ marginTop: 8 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.network.large_image} />}
|
|
||||||
<div style={{marginLeft: 8,}}>
|
|
||||||
<Typography style={{display:"flex",}}>Network</Typography>
|
|
||||||
{appFramework === undefined || appFramework.network === undefined || appFramework.network.name === undefined ||
|
|
||||||
appFramework === null || appFramework.network === null || appFramework.network.name === null || appFramework.network.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 10, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.network.name}</Typography>}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
finishedApps.includes("ASSETS")
|
|
||||||
}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "ASSETS" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
style={buttonStyle}
|
|
||||||
// startIcon={<EmailIcon />}
|
|
||||||
color="secondary"
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("ASSETS");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.assets === undefined || appFramework.assets.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.assets === null || appFramework.assets.large_image === null || appFramework.assets.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<ExploreIcon style={{ marginTop: 8 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.assets.large_image} />}
|
|
||||||
<div style={{marginLeft: 8,}}>
|
|
||||||
<Typography style={{display:"flex",}}>Assets</Typography>
|
|
||||||
{appFramework === undefined || appFramework.assets === undefined || appFramework.assets.name === undefined ||
|
|
||||||
appFramework === null || appFramework.assets === null || appFramework.assets.name === null || appFramework.assets.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 10, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.assets.name}</Typography>}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
finishedApps.includes("IAM")
|
|
||||||
}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "IAM" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
onMouseOver={mouseOver}
|
|
||||||
onMouseOut={mouseOut}
|
|
||||||
style={buttonStyle}
|
|
||||||
// startIcon={<EmailIcon />}
|
|
||||||
color="secondary"
|
|
||||||
onClick={(event) => {
|
|
||||||
onNodeSelect("IAM");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{appFramework === undefined || appFramework.iam === undefined || appFramework.iam.large_image === undefined ||
|
|
||||||
appFramework === null || appFramework.iam === null || appFramework.iam.large_image === null || appFramework.iam.large_image.length === 0 ?
|
|
||||||
<div style={{width: 40, border: "1px solid rgba(33, 33, 33, 1) !importent", height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign:"center"}}>
|
|
||||||
<FingerprintIcon style={{ marginTop: 8 }} />
|
|
||||||
</div>
|
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={appFramework.iam.large_image} />}
|
|
||||||
<div style={{marginLeft: 8,}}>
|
|
||||||
<Typography style={{display:"flex",}}>IAM</Typography>
|
|
||||||
{appFramework === undefined || appFramework.iam === undefined || appFramework.iam.name === undefined ||
|
|
||||||
appFramework === null || appFramework.iam === null || appFramework.iam.name === null || appFramework.iam.name.length === 0 ?
|
|
||||||
"":<Typography style={{fontSize: 8, textAlign:"left", color:"var(--label-grey-text, #9E9E9E)" }} >{appFramework.iam.name}</Typography>}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
<div
|
||||||
:
|
style={{ width: "100%", border: "1px #494949 solid" }}
|
||||||
<div style={{ display: "flex", width: 510, paddingLeft: 165, }}>
|
/>
|
||||||
<Button
|
<AppSearch
|
||||||
style={{ color: "#f86a3e", textTransform: 'capitalize', border: 2, backgroundColor: "var(--Background-color, #1A1A1A)" }}
|
defaultSearch={appType}
|
||||||
className="btn btn-primary"
|
userdata={userdata}
|
||||||
onClick={(event) => {
|
newSelectedApp={newSelectedApp}
|
||||||
setMoreButton(true);
|
setNewSelectedApp={setNewSelectedApp}
|
||||||
}}
|
/>
|
||||||
>
|
</div>
|
||||||
<Typography style={{ textDecorationLine: 'underline', }}>
|
) : null}
|
||||||
See more Categories
|
<div style={{ display: "flex", height: 70, border: isHover ? "1px solid #f85a3e" : "var(--Container, #212121)", borderRadius: 8, background: isHover ? "var(--Container, #212121)":"var(--Container, #212121)",
|
||||||
</Typography>
|
alignItems: "center", justifyContent: "center",}}
|
||||||
</Button>
|
|
||||||
</div>} */}
|
|
||||||
<div style={{ display: "flex", width: 510, height: 64, borderRadius: 8, background: "var(--Container, #212121)" }}
|
|
||||||
>
|
>
|
||||||
<div
|
<Button
|
||||||
onMouseOver={mouseOver}
|
fullWidth
|
||||||
onMouseOut={mouseOut}
|
|
||||||
disabled={finishedApps.includes("CASES")}
|
|
||||||
variant={
|
|
||||||
defaultSearch === "CASES" ? "contained" : "outlined"
|
|
||||||
}
|
|
||||||
color="secondary"
|
color="secondary"
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
height:"100%",
|
||||||
width: "100%",
|
width:"100%",
|
||||||
margin: buttonMargin,
|
display:"grid"
|
||||||
fontSize: 18,
|
|
||||||
color: "var(--White-text, #F1F1F1)",
|
|
||||||
fontWeight: 400,
|
|
||||||
background: "rgba(33, 33, 33, 1)",
|
|
||||||
borderRadius: 8,
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
}}
|
}}
|
||||||
// startIcon = {defaultSearch === "CASES" ? newSelectedApp.image_url : <LightbulbIcon/>}
|
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
onNodeSelect("CASES");
|
if (onNodeSelect !== undefined) {
|
||||||
setDefaultSearch(discoveryData.label)
|
onNodeSelect(appType);
|
||||||
|
} else {
|
||||||
|
setLocalSearchOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setDefaultSearch !== undefined) {
|
||||||
|
setDefaultSearch(appType)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{marginLeft: 20, display:"flex", textAlign:"center", alignItems:"center", marginLeft: 100, width: 320, marginRight: "auto" }}>
|
<div style={{ display:"flex", textAlign:"center", justifyContent: "center", alignItems:"center", marginRight: "auto" }}>
|
||||||
{AppImage === undefined || AppImage === undefined ||
|
{AppImage === undefined || AppImage === null || AppImage.length === 0 ?
|
||||||
AppImage === null || AppImage === null || AppImage.length === 0 ?
|
|
||||||
<div style={{ width: 40, height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign: "center" }}>
|
<div style={{ width: 40, height: 40, borderRadius: 9999, backgroundColor: "#2F2F2F", textAlign: "center" }}>
|
||||||
<LightbulbIcon style={{ marginTop: 6 }} />
|
<img style={{paddingLeft: 11, paddingTop: 11, width: 40, height: 40, flexShrink: 0, }} src={icon} />
|
||||||
</div>
|
</div>
|
||||||
: <img style={{ marginRight: 8, width: 40, height: 40, flexShrink: 0, borderRadius: 40, }} src={AppImage} />}
|
:
|
||||||
|
<img style={{ marginRight: 8, width: 35, height: 35, flexShrink: 0, borderRadius: 40, }} src={AppImage} />
|
||||||
|
}
|
||||||
<div style={{ marginLeft: 8, }}>
|
<div style={{ marginLeft: 8, }}>
|
||||||
<Typography style={{ display: "flex", border: "none" }} >Case Management</Typography>
|
<Typography style={{
|
||||||
|
display: "flex",
|
||||||
|
border: "none",
|
||||||
|
fontSize: 16,
|
||||||
|
textTransform: ["siem", "edr", "iam"].includes(appType.toLowerCase()) ? "uppercase" : 'capitalize'
|
||||||
|
}} >
|
||||||
|
{appType}
|
||||||
|
</Typography>
|
||||||
{appName === undefined || appName === undefined ||
|
{appName === undefined || appName === undefined ||
|
||||||
appName === null || appName === null || appName.length === 0 ?
|
appName === null || appName === null || appName.length === 0 ?
|
||||||
""
|
""
|
||||||
:
|
:
|
||||||
<Typography style={{ fontSize: 12, textAlign: "left", color: "var(--label-grey-text, #9E9E9E)" }} >{appName}</Typography>}
|
<Typography style={{ fontSize: 12, textAlign: "left", color: "var(--label-grey-text, #9E9E9E)", textTransform: "lowercase" }} >{appName.split('_').join(' ')}</Typography>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from "react";
|
|||||||
import theme from '../theme.jsx';
|
import theme from '../theme.jsx';
|
||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { useNavigate, Link } from 'react-router-dom';
|
||||||
|
import {isMobile} from "react-device-detect";
|
||||||
import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon, Close as CloseIcon, Folder as FolderIcon, LibraryBooks as LibraryBooksIcon } from '@mui/icons-material';
|
import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon, Close as CloseIcon, Folder as FolderIcon, LibraryBooks as LibraryBooksIcon } from '@mui/icons-material';
|
||||||
import aa from 'search-insights'
|
import aa from 'search-insights'
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
@@ -50,6 +50,7 @@ const AppSelection = props => {
|
|||||||
const [newSelectedApp, setNewSelectedApp] = React.useState({})
|
const [newSelectedApp, setNewSelectedApp] = React.useState({})
|
||||||
const [finishedApps, setFinishedApps] = React.useState([])
|
const [finishedApps, setFinishedApps] = React.useState([])
|
||||||
const [appButtons, setAppButtons] = useState([])
|
const [appButtons, setAppButtons] = useState([])
|
||||||
|
const [lastPosted, setLastPosted] = useState([])
|
||||||
const [apps, setApps] = useState([])
|
const [apps, setApps] = useState([])
|
||||||
const [appName, setAppName] = React.useState();
|
const [appName, setAppName] = React.useState();
|
||||||
const [moreButton, setMoreButton] = useState(false);
|
const [moreButton, setMoreButton] = useState(false);
|
||||||
@@ -59,6 +60,117 @@ const AppSelection = props => {
|
|||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (newSelectedApp === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitNewApp = {
|
||||||
|
description: newSelectedApp.description,
|
||||||
|
id: newSelectedApp.objectID,
|
||||||
|
large_image: newSelectedApp.image_url,
|
||||||
|
name: newSelectedApp.name,
|
||||||
|
type: discoveryData
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discoveryData === "CASES") {
|
||||||
|
appFramework.cases = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "SIEM") {
|
||||||
|
appFramework.siem = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "ERADICATION") {
|
||||||
|
appFramework.edr = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "INTEL") {
|
||||||
|
appFramework.intel = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "EMAIL") {
|
||||||
|
appFramework.communication = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "NETWORK") {
|
||||||
|
appFramework.network = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "ASSETS") {
|
||||||
|
appFramework.assets = submitNewApp
|
||||||
|
}
|
||||||
|
else if (discoveryData === "IAM") {
|
||||||
|
appFramework.iam = submitNewApp
|
||||||
|
}
|
||||||
|
setFrameworkItem(submitNewApp);
|
||||||
|
setSelectionOpen(false);
|
||||||
|
console.log("Selected app changed (effect)");
|
||||||
|
}, [newSelectedApp]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
var tempApps = []
|
||||||
|
if (tempApps.length === 0) {
|
||||||
|
// Object.entries(appFramework).forEach(([key, value]) => {
|
||||||
|
// value.type = key;
|
||||||
|
// tempApps.push(value);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Define the custom sorting order
|
||||||
|
// const customSortingOrder = ["CASES", "SIEM", "ENDPOINT", "INTEL", "EMAIL"];
|
||||||
|
|
||||||
|
const lastApps = {}
|
||||||
|
let endTypes = ["network", "assets", "iam"]
|
||||||
|
|
||||||
|
if (appFramework === undefined || appFramework === null || Object.keys(appFramework).length === 0) {
|
||||||
|
//window.location.href = "/welcome"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Object.entries(appFramework).forEach(([key, value]) => {
|
||||||
|
if (key.toLowerCase() === "other" || key.toLowerCase() === "communication") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
value.type = key;
|
||||||
|
|
||||||
|
if (endTypes.includes(value.type.toLowerCase())) {
|
||||||
|
lastApps[value.type] = value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPosted.type === value.type) {
|
||||||
|
value = lastPosted
|
||||||
|
}
|
||||||
|
|
||||||
|
tempApps.push(JSON.parse(JSON.stringify(value)));
|
||||||
|
});
|
||||||
|
|
||||||
|
tempApps.sort((a, b) => {
|
||||||
|
if (a.type.length > b.type.length) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.type.length < b.type.length) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let lastType = lastPosted.type === undefined ? "" : lastPosted.type.toLowerCase()
|
||||||
|
|
||||||
|
if (endTypes.includes(lastType)) {
|
||||||
|
lastApps[lastPosted.type] = lastPosted
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moreButton) {
|
||||||
|
tempApps.push(JSON.parse(JSON.stringify(lastApps["network"])))
|
||||||
|
tempApps.push(JSON.parse(JSON.stringify(lastApps["assets"])))
|
||||||
|
tempApps.push(JSON.parse(JSON.stringify(lastApps["iam"])))
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppButtons(tempApps)
|
||||||
|
console.log("Updated appButtons: ", appButtons)
|
||||||
|
GetApps()
|
||||||
|
}
|
||||||
|
}, [lastPosted, moreButton])
|
||||||
|
|
||||||
|
if (appFramework === undefined || appFramework === null || Object.keys(appFramework).length === 0) {
|
||||||
|
//window.location.href = "/welcome"
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const setFrameworkItem = (data) => {
|
const setFrameworkItem = (data) => {
|
||||||
console.log("Setting framework item: ", data, isCloud)
|
console.log("Setting framework item: ", data, isCloud)
|
||||||
@@ -75,7 +187,7 @@ const AppSelection = props => {
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(async (response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for framework!");
|
console.log("Status not 200 for framework!");
|
||||||
}
|
}
|
||||||
@@ -84,7 +196,13 @@ const AppSelection = props => {
|
|||||||
checkLogin()
|
checkLogin()
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json();
|
let resp = response.json();
|
||||||
|
let respAwaited = await resp;
|
||||||
|
|
||||||
|
if (respAwaited.success === true) {
|
||||||
|
setLastPosted(data)
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
@@ -150,10 +268,6 @@ const AppSelection = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onNodeSelect = (label) => {
|
const onNodeSelect = (label) => {
|
||||||
// if (setDiscoveryWrapper !== undefined) {
|
|
||||||
// setDiscoveryWrapper({ id: label });
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (isCloud) {
|
if (isCloud) {
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
category: "welcome",
|
category: "welcome",
|
||||||
@@ -161,130 +275,49 @@ const AppSelection = props => {
|
|||||||
label: "",
|
label: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("NODESELECT: ", label)
|
||||||
|
|
||||||
setDiscoveryData(label)
|
setDiscoveryData(label)
|
||||||
setSelectionOpen(true)
|
setSelectionOpen(true)
|
||||||
setNewSelectedApp({})
|
|
||||||
setDefaultSearch(label.charAt(0).toUpperCase() + (label.substring(1)).toLowerCase())
|
setDefaultSearch(label.charAt(0).toUpperCase() + (label.substring(1)).toLowerCase())
|
||||||
|
|
||||||
|
setNewSelectedApp(undefined)
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
var tempApps = []
|
|
||||||
if (tempApps.length === 0) {
|
|
||||||
const tempApps =
|
|
||||||
[{
|
|
||||||
"description": newSelectedApp.description,
|
|
||||||
"id": newSelectedApp.objectID,
|
|
||||||
"large_image": newSelectedApp.image_url,
|
|
||||||
"name": newSelectedApp.name,
|
|
||||||
"type": discoveryData
|
|
||||||
},
|
|
||||||
//{
|
|
||||||
// // description: newSelectedApp.siem.description,
|
|
||||||
// id: newSelectedApp.siem.objectID,
|
|
||||||
// large_image: newSelectedApp.siem.image_url,
|
|
||||||
// name: newSelectedApp.siem.name,
|
|
||||||
// type: discoveryData.siem
|
|
||||||
// },{
|
|
||||||
// // description: newSelectedApp.edr.description,
|
|
||||||
// id: newSelectedApp.edr.objectID,
|
|
||||||
// large_image: newSelectedApp.edr.image_url,
|
|
||||||
// name: newSelectedApp.edr.name,
|
|
||||||
// type: discoveryData.edr
|
|
||||||
// }
|
|
||||||
]
|
|
||||||
setAppButtons(tempApps)
|
|
||||||
GetApps()
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (newSelectedApp.objectID === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const submitNewApp = {
|
|
||||||
description: newSelectedApp.description,
|
|
||||||
id: newSelectedApp.objectID,
|
|
||||||
large_image: newSelectedApp.image_url,
|
|
||||||
name: newSelectedApp.name,
|
|
||||||
type: discoveryData
|
|
||||||
}
|
|
||||||
if (discoveryData === "CASES") {
|
|
||||||
appFramework.cases = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "SIEM") {
|
|
||||||
appFramework.siem = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "ERADICATION") {
|
|
||||||
appFramework.edr = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "INTEL") {
|
|
||||||
appFramework.intel = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "EMAIL") {
|
|
||||||
appFramework.communication = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "NETWORK") {
|
|
||||||
appFramework.network = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "ASSETS") {
|
|
||||||
appFramework.assets = submitNewApp
|
|
||||||
}
|
|
||||||
else if (discoveryData === "IAM") {
|
|
||||||
appFramework.iam = submitNewApp
|
|
||||||
}
|
|
||||||
setFrameworkItem(submitNewApp);
|
|
||||||
setSelectionOpen(false);
|
|
||||||
console.log("Selected app changed (effect)");
|
|
||||||
}, [newSelectedApp]);
|
|
||||||
|
|
||||||
const sizing = moreButton ? 510 : 480;
|
// const sizing = moreButton ? 510 : 480;
|
||||||
const buttonWidth = 450;
|
const buttonWidth = 450;
|
||||||
const buttonMargin = 10;
|
const buttonMargin = 10;
|
||||||
const bottomButtonStyle = {
|
const bottomButtonStyle = {
|
||||||
borderRadius: 200,
|
borderRadius: 200,
|
||||||
marginTop: moreButton ? 44 : "",
|
marginTop: moreButton ? 44 : "",
|
||||||
height: 51,
|
height: 51,
|
||||||
width: 510,
|
width: isMobile ? 250 : 500,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
// background: "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)",
|
|
||||||
background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)",
|
background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)",
|
||||||
padding: "16px 24px",
|
padding: "16px 24px",
|
||||||
// top: 20,
|
|
||||||
// margin: "auto",
|
|
||||||
textTransform: 'capitalize',
|
textTransform: 'capitalize',
|
||||||
itemAlign: "center",
|
itemAlign: "center",
|
||||||
// marginTop: 25
|
|
||||||
// marginLeft: "65px",
|
|
||||||
};
|
};
|
||||||
const buttonStyle = {
|
|
||||||
flex: 1,
|
|
||||||
width: 224,
|
|
||||||
padding: 25,
|
|
||||||
margin: buttonMargin,
|
|
||||||
color: "var(--White-text, #F1F1F1)",
|
|
||||||
fontWeight: 400,
|
|
||||||
fontSize: 17,
|
|
||||||
background: "rgba(33, 33, 33, 1)",
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
border: "1px solid rgba(33, 33, 33, 1)",
|
|
||||||
borderRadius: 8,
|
|
||||||
marginRight: 8,
|
|
||||||
};
|
|
||||||
// console.log("appFramework",appFramework.cases.name)
|
|
||||||
return (
|
return (
|
||||||
<Collapse in={true}>
|
<Collapse in={true}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
minHeight: sizing,
|
// minHeight: sizing,
|
||||||
maxHeight: sizing,
|
// maxHeight: sizing,
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
width: 500,
|
width: isMobile ? 380 : 500,
|
||||||
|
marginBottom: 25,
|
||||||
|
textAlign: isMobile ? "center" : null,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectionOpen ? (
|
{selectionOpen ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 319,
|
width: isMobile ? 225 : 319,
|
||||||
height: 395,
|
height: 395,
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
marginLeft: 70,
|
marginLeft: 70,
|
||||||
@@ -311,7 +344,7 @@ const AppSelection = props => {
|
|||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
// width: 224,
|
// width: 224,
|
||||||
marginLeft: discoveryData === ('ERADICATION') ? 120 : 177,
|
marginLeft: discoveryData === ("communication") ? 112 : 200,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
marginBottom: 23,
|
marginBottom: 23,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -374,7 +407,7 @@ const AppSelection = props => {
|
|||||||
variant="h4"
|
variant="h4"
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
marginTop: 40,
|
marginTop: isMobile ? null : 40,
|
||||||
marginRight: 30,
|
marginRight: 30,
|
||||||
marginBottom: 0,
|
marginBottom: 0,
|
||||||
}}
|
}}
|
||||||
@@ -394,31 +427,60 @@ const AppSelection = props => {
|
|||||||
>
|
>
|
||||||
Select the apps you work with and we will connect them for you.
|
Select the apps you work with and we will connect them for you.
|
||||||
</Typography>
|
</Typography>
|
||||||
{appButtons.map((appData, index) => {
|
<Grid rowSpacing={1} columnSpacing={2} container >
|
||||||
|
{appButtons.map((appData, index) => {
|
||||||
|
// This is here due to a memory issue with setting apps properly
|
||||||
|
if (appData.id === "remove") {
|
||||||
|
console.log("Removed as appdata is overridden: ", appData)
|
||||||
|
|
||||||
const appName = appData.name
|
appData = {
|
||||||
const AppImage = appData.large_image
|
"count": 0,
|
||||||
const appType = appData.type
|
"description": "",
|
||||||
|
"id": "",
|
||||||
|
"large_image": "",
|
||||||
|
"name": "",
|
||||||
|
"type": appData.type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
const appName = appData.name
|
||||||
|
const AppImage = appData.large_image
|
||||||
|
const appType = appData.type
|
||||||
|
|
||||||
<AppSearchButtons
|
return (
|
||||||
appFramework={appFramework}
|
<AppSearchButtons
|
||||||
appName={appName}
|
appFramework={appFramework}
|
||||||
appType = {appType}
|
index={index}
|
||||||
AppImage={AppImage}
|
totalApps={appButtons.length}
|
||||||
defaultSearch={defaultSearch}
|
appName={appName}
|
||||||
finishedApps={finishedApps}
|
appType={appType}
|
||||||
onNodeSelect={onNodeSelect}
|
AppImage={AppImage}
|
||||||
discoveryData={discoveryData}
|
defaultSearch={defaultSearch}
|
||||||
setDiscoveryData={setDiscoveryData}
|
finishedApps={finishedApps}
|
||||||
setDefaultSearch={setDefaultSearch}
|
onNodeSelect={onNodeSelect}
|
||||||
apps={apps}
|
discoveryData={discoveryData}
|
||||||
/>
|
setDiscoveryData={setDiscoveryData}
|
||||||
)
|
setDefaultSearch={setDefaultSearch}
|
||||||
})}
|
apps={apps}
|
||||||
|
setMoreButton={setMoreButton}
|
||||||
|
moreButton={moreButton}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flexDirection: "row", }}>
|
{!moreButton ? (
|
||||||
|
<div style={{width: "100%", marginLeft: isMobile ? 100 : 200, marginBottom: 20, textAlign: isMobile ? "center" : null}}>
|
||||||
|
<Link style={{color:"#FF8444"}} onClick={()=>{
|
||||||
|
setMoreButton(true)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate("/welcome?tab=2")
|
||||||
|
}, 250)
|
||||||
|
}}
|
||||||
|
>See More Apps</Link>
|
||||||
|
</div>): ""}
|
||||||
|
<div style={{ flexDirection: "row", width: isMobile ? 380 : null, textAlign: isMobile ? "center" : null}}>
|
||||||
<Button variant="contained" type="submit" fullWidth style={bottomButtonStyle} onClick={() => {
|
<Button variant="contained" type="submit" fullWidth style={bottomButtonStyle} onClick={() => {
|
||||||
navigate("/welcome?tab=3")
|
navigate("/welcome?tab=3")
|
||||||
setActiveStep(2)
|
setActiveStep(2)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e52
|
|||||||
const Appsearch = props => {
|
const Appsearch = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props
|
||||||
|
|
||||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs
|
const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs
|
||||||
//const theme = useTheme();
|
//const theme = useTheme();
|
||||||
@@ -112,31 +112,11 @@ const Appsearch = props => {
|
|||||||
|
|
||||||
counted += 1
|
counted += 1
|
||||||
var parsedname = data.name.valueOf()
|
var parsedname = data.name.valueOf()
|
||||||
//for (var key = 0; key < data.name.length; key++) {
|
|
||||||
// var character = data.name.charAt(key)
|
|
||||||
// if (character === character.toUpperCase()) {
|
|
||||||
// //console.log(data.name[key], data.name[key+1])
|
|
||||||
// if (data.name.charAt(key+1) !== undefined && data.name.charAt(key+1) === data.name.charAt(key+1).toUpperCase()) {
|
|
||||||
// } else {
|
|
||||||
// parsedname += " "
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// parsedname += character
|
|
||||||
//}
|
|
||||||
|
|
||||||
parsedname = (parsedname.charAt(0).toUpperCase()+parsedname.substring(1)).replaceAll("_", " ")
|
parsedname = (parsedname.charAt(0).toUpperCase()+parsedname.substring(1)).replaceAll("_", " ")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper key={index} elevation={0} style={paperStyle} onMouseOver={() => {
|
<Paper key={index} elevation={0} style={paperStyle} onMouseOver={() => {
|
||||||
setMouseHoverIndex(index)
|
setMouseHoverIndex(index)
|
||||||
/*
|
|
||||||
ReactGA.event({
|
|
||||||
category: "app_grid_view",
|
|
||||||
action: `search_bar_click`,
|
|
||||||
label: "",
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}} onMouseOut={() => {
|
}} onMouseOut={() => {
|
||||||
setMouseHoverIndex(-1)
|
setMouseHoverIndex(-1)
|
||||||
}} onClick={() => {
|
}} onClick={() => {
|
||||||
@@ -201,13 +181,8 @@ const Appsearch = props => {
|
|||||||
const CustomHits = connectHits(InputHits)
|
const CustomHits = connectHits(InputHits)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{width: 287, height: 295, padding: "16px 16px 267px 16px", alignItems: "center", gap: 138,}}>
|
<div style={{width: isMobile ? null : 287, height: 295, padding: "16px 16px 267px 16px", alignItems: "center", gap: 138,}}>
|
||||||
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
||||||
{/* showSearch === false ? null :
|
|
||||||
<div style={{maxWidth: 450, margin: "auto", }}>
|
|
||||||
<CustomSearchBox />
|
|
||||||
</div>
|
|
||||||
*/}
|
|
||||||
<div style={{maxWidth: 450, margin: "auto", }}>
|
<div style={{maxWidth: 450, margin: "auto", }}>
|
||||||
<CustomSearchBox />
|
<CustomSearchBox />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import countries from "../components/Countries.jsx";
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
Divider,
|
Divider,
|
||||||
Button,
|
Button,
|
||||||
Grid,
|
Grid,
|
||||||
@@ -19,6 +19,10 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
TextField,
|
TextField,
|
||||||
|
InputAdornment,
|
||||||
|
IconButton,
|
||||||
|
Checkbox,
|
||||||
|
Tooltip,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import { useNavigate, Link } from "react-router-dom";
|
import { useNavigate, Link } from "react-router-dom";
|
||||||
@@ -27,6 +31,9 @@ import { toast } from "react-toastify"
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Cached as CachedIcon,
|
Cached as CachedIcon,
|
||||||
|
ContentCopy as ContentCopyIcon,
|
||||||
|
Draw as DrawIcon,
|
||||||
|
Close as CloseIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
//import { useAlert
|
//import { useAlert
|
||||||
@@ -228,10 +235,44 @@ const Billing = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const SubscriptionObject = (props) => {
|
const sendSignatureRequest = (subscription) => {
|
||||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, subscription, highlight, } = props;
|
const url = `${globalUrl}/api/v1/orgs/${selectedOrganization.id}`;
|
||||||
|
|
||||||
var top_text = "Base Access"
|
fetch(url, {
|
||||||
|
body: JSON.stringify({
|
||||||
|
org_id: selectedOrganization.id,
|
||||||
|
subscription: subscription,
|
||||||
|
}),
|
||||||
|
mode: "cors",
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
crossDomain: true,
|
||||||
|
withCredentials: true,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Error in response");
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
console.log("Response from signature request: ", responseJson);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Error: ", error);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubscriptionObject = (props) => {
|
||||||
|
const { globalUrl, index, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, subscription, highlight, } = props;
|
||||||
|
|
||||||
|
const [signatureOpen, setSignatureOpen] = React.useState(false);
|
||||||
|
const [tosChecked, setTosChecked] = React.useState(subscription.eula_signed)
|
||||||
|
|
||||||
|
var top_text = "Base Cloud Access"
|
||||||
if (subscription.limit === undefined && subscription.level === undefined || subscription.level === null || subscription.level === 0) {
|
if (subscription.limit === undefined && subscription.level === undefined || subscription.level === null || subscription.level === 0) {
|
||||||
subscription.name = "Enterprise"
|
subscription.name = "Enterprise"
|
||||||
subscription.currency_text = "$"
|
subscription.currency_text = "$"
|
||||||
@@ -280,10 +321,109 @@ const Billing = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper style={newPaperstyle}>
|
<Paper style={newPaperstyle}>
|
||||||
|
<Dialog
|
||||||
|
open={signatureOpen}
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
pointerEvents: "auto",
|
||||||
|
color: "white",
|
||||||
|
minWidth: 750,
|
||||||
|
padding: 30,
|
||||||
|
maxHeight: 700,
|
||||||
|
overflowY: "auto",
|
||||||
|
overflowX: "hidden",
|
||||||
|
zIndex: 10012,
|
||||||
|
border: theme.palette.defaultBorder,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
title="Close window"
|
||||||
|
placement="top"
|
||||||
|
style={{ zIndex: 10011 }}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
style={{ zIndex: 5000, position: "absolute", top: 34, right: 34 }}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setSignatureOpen(false);
|
||||||
|
setTosChecked(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CloseIcon style={{ color: "white" }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<DialogTitle id="form-dialog-title">Read and Accept the EULA</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<TextField
|
||||||
|
rows={17}
|
||||||
|
multiline
|
||||||
|
fullWidth
|
||||||
|
InputProps={{
|
||||||
|
readOnly: true,
|
||||||
|
style: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: "rgba(255, 255, 255, 0.6)",
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={subscription.eula}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
disabled={subscription.eula_signed}
|
||||||
|
checked={tosChecked}
|
||||||
|
onChange={(e) => {
|
||||||
|
setTosChecked(e.target.checked)
|
||||||
|
}}
|
||||||
|
inputProps={{ 'aria-label': 'primary checkbox' }}
|
||||||
|
/>
|
||||||
|
<Typography variant="body1" style={{display: "inline-block", marginLeft: 10, marginTop: 25, cursor: "pointer", }} onClick={() => {
|
||||||
|
setTosChecked(!tosChecked)
|
||||||
|
}}>
|
||||||
|
Accept
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" style={{display: "inline-block", marginLeft: 10, }} color="textSecondary">
|
||||||
|
By clicking the “accept” button, you are signing the document, electronically agreeing that it has the same legal validity and effects as a handwritten signature, and that you have the competent authority to represent and sign on behalf an entity. Need support or have questions? Contact us at support@shuffler.io.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<div style={{display: "flex", marginTop: 25, }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
style={{ marginLeft: "auto", }}
|
||||||
|
disabled={!tosChecked || subscription.eula_signed}
|
||||||
|
onClick={() => {
|
||||||
|
setSignatureOpen(false)
|
||||||
|
subscription.eula_signed = true
|
||||||
|
sendSignatureRequest(subscription)
|
||||||
|
}}
|
||||||
|
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
<div style={{display: "flex"}}>
|
<div style={{display: "flex"}}>
|
||||||
<Typography variant="h6" style={{ marginTop: 10, marginBottom: 10 }}>
|
<Typography variant="h6" style={{ marginTop: 10, marginBottom: 10, flex: 5, }}>
|
||||||
{top_text}
|
{top_text}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{isCloud && highlight === true ?
|
||||||
|
<Tooltip
|
||||||
|
title="Sign EULA"
|
||||||
|
placement="top"
|
||||||
|
style={{ zIndex: 10011 }}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
disabled={subscription.eula_signed}
|
||||||
|
style={{ marginLeft: "auto", marginTop: 10, marginBottom: 10, flex: 1, }}
|
||||||
|
onClick={() => {
|
||||||
|
setSignatureOpen(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DrawIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<div>
|
<div>
|
||||||
@@ -320,15 +460,61 @@ const Billing = (props) => {
|
|||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feature.includes("Licensed Worker: ")) {
|
if (feature.includes("Worker License: ")) {
|
||||||
|
const fieldId = "webhook_uri_field_"+index
|
||||||
parsedFeature =
|
parsedFeature =
|
||||||
<a
|
<span style={{marginTop: 10, }}>
|
||||||
href={feature.split("Licensed Worker: ")[1]}
|
<Typography
|
||||||
target="_blank"
|
variant="body2"
|
||||||
style={{ textDecoration: "none", color: "#f85a3e",}}
|
>
|
||||||
>
|
Use the {feature.split("Worker License: ")[0]} Worker
|
||||||
Download the licensed worker
|
</Typography>
|
||||||
</a>
|
<TextField
|
||||||
|
value={feature.split("Worker License: ")[1]}
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
borderRadius: theme.palette.borderRadius,
|
||||||
|
}}
|
||||||
|
id={fieldId}
|
||||||
|
onClick={() => {}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment:
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="Copy webhook"
|
||||||
|
onClick={() => {
|
||||||
|
var copyText = document.getElementById(fieldId);
|
||||||
|
if (copyText !== undefined && copyText !== null) {
|
||||||
|
console.log("NAVIGATOR: ", navigator);
|
||||||
|
const clipboard = navigator.clipboard;
|
||||||
|
if (clipboard === undefined) {
|
||||||
|
toast("Can only copy over HTTPS (port 3443)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(copyText.value);
|
||||||
|
copyText.select();
|
||||||
|
copyText.setSelectionRange(
|
||||||
|
0,
|
||||||
|
99999
|
||||||
|
); /* For mobile devices */
|
||||||
|
|
||||||
|
/* Copy the text inside the text field */
|
||||||
|
document.execCommand("copy");
|
||||||
|
toast("Copied Webhook URL");
|
||||||
|
} else {
|
||||||
|
console.log("Couldn't find webhook URI field: ", copyText);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
<ContentCopyIcon />
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -342,7 +528,7 @@ const Billing = (props) => {
|
|||||||
: null}
|
: null}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{(highlight === true && subscription.name === "Pay as you go" && subscription.limit <= 10000) || subscription.name.includes("Scale") ?
|
{(highlight === true && (subscription.name === "Pay as you go" && subscription.limit <= 10000) || subscription.name === "Open Source") ?
|
||||||
<span>
|
<span>
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||||
{subscription.name.includes("Scale") ?
|
{subscription.name.includes("Scale") ?
|
||||||
@@ -351,6 +537,18 @@ const Billing = (props) => {
|
|||||||
"You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit."
|
"You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit."
|
||||||
}
|
}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{/*isCloud ?
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
style={{ marginTop: 20, marginBottom: 10, }}
|
||||||
|
onClick={() => {
|
||||||
|
window.open("https://checkout.stripe.com/c/pay/ppage_1O8UttDzMUgUjxHSBh3krC6Y#fidkdWxOYHwnPyd1blpxYHZxWkBhfWJOY3RoVEJdXDBPSW9hR3RxcG1GcjU1R01nbE5PQUcnKSdobGF2Jz9%2BJ2JwbGEnPydjY2M3MjA0NyhnYzcyKDFkMTQoPWFmPSgwYDI9MTA0NGAyZDNhPWZhNmcnKSdocGxhJz8nNWYwMjNnZGMoZGdgPCgxPDxhKD1kNjUoMjZmPTcxYzw9NjBjYzZmMGRnJykndmxhJz8nZGYxYWZhY2MoZ2FjNygxPDA2KDxhZ2MoZjY1PWM8NGcxYzUxMjJkYTRmJ3gpJ2dgcWR2Jz9eWCknaWR8anBxUXx1YCc%2FJ3Zsa2JpYFpscWBoJyknd2BjYHd3YHdKd2xibGsnPydtcXF1PyoqaWpmZGltanZxPzY1NTcnKSdpamZkaWAnP2twaWl4JSUl")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Payment Method
|
||||||
|
</Button>
|
||||||
|
: null*/}
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -363,7 +561,7 @@ const Billing = (props) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Upgrade Now
|
Upgrade now
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
: null}
|
: null}
|
||||||
@@ -692,6 +890,7 @@ const Billing = (props) => {
|
|||||||
<div style={{display: "flex", maxWidth: 768, minWidth: 768, }}>
|
<div style={{display: "flex", maxWidth: 768, minWidth: 768, }}>
|
||||||
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ?
|
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ?
|
||||||
<SubscriptionObject
|
<SubscriptionObject
|
||||||
|
index={0}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
serverside={serverside}
|
serverside={serverside}
|
||||||
@@ -704,6 +903,7 @@ const Billing = (props) => {
|
|||||||
: !isCloud ?
|
: !isCloud ?
|
||||||
<span style={{display: "flex", }}>
|
<span style={{display: "flex", }}>
|
||||||
<SubscriptionObject
|
<SubscriptionObject
|
||||||
|
index={0}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
serverside={false}
|
serverside={false}
|
||||||
@@ -722,6 +922,7 @@ const Billing = (props) => {
|
|||||||
highlight={true}
|
highlight={true}
|
||||||
/>
|
/>
|
||||||
<SubscriptionObject
|
<SubscriptionObject
|
||||||
|
index={1}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
serverside={false}
|
serverside={false}
|
||||||
@@ -751,6 +952,7 @@ const Billing = (props) => {
|
|||||||
.map((sub, index) => {
|
.map((sub, index) => {
|
||||||
return (
|
return (
|
||||||
<SubscriptionObject
|
<SubscriptionObject
|
||||||
|
index={index+1}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
serverside={serverside}
|
serverside={serverside}
|
||||||
@@ -758,6 +960,7 @@ const Billing = (props) => {
|
|||||||
stripeKey={stripeKey}
|
stripeKey={stripeKey}
|
||||||
selectedOrganization={selectedOrganization}
|
selectedOrganization={selectedOrganization}
|
||||||
subscription={sub}
|
subscription={sub}
|
||||||
|
highlight={true}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useInterval } from "react-powerhooks";
|
import { useInterval } from "react-powerhooks";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import theme from "../theme.jsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
@@ -41,7 +42,6 @@ import aa from 'search-insights'
|
|||||||
const ConfigureWorkflow = (props) => {
|
const ConfigureWorkflow = (props) => {
|
||||||
const {
|
const {
|
||||||
apps,
|
apps,
|
||||||
theme,
|
|
||||||
isCloud,
|
isCloud,
|
||||||
workflow,
|
workflow,
|
||||||
userdata,
|
userdata,
|
||||||
@@ -1235,12 +1235,8 @@ const ConfigureWorkflow = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const topColor = "#f86a3e, #fc3922"
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{setConfigureWorkflowModalOpen !== undefined ?
|
|
||||||
<div style={{height: 75, width: "100%", background: `linear-gradient(to right, ${topColor}`, position: "relative",}} />
|
|
||||||
: null}
|
|
||||||
<div style={{margin: setConfigureWorkflowModalOpen !== undefined ? "0px 50px 0px 50px" : "35px 0px 0px", maxHeight: 475, }}>
|
<div style={{margin: setConfigureWorkflowModalOpen !== undefined ? "0px 50px 0px 50px" : "35px 0px 0px", maxHeight: 475, }}>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import {
|
|||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||||
const CreatorGrid = props => {
|
const CreatorGrid = props => {
|
||||||
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs } = props
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, isHeader } = props
|
||||||
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
const xs = parsedXs === undefined || parsedXs === null ? isMobile ? 6 : 4 : parsedXs
|
const xs = parsedXs === undefined || parsedXs === null ? isMobile ? 6 : 4 : parsedXs
|
||||||
//const [apps, setApps] = React.useState([]);
|
//const [apps, setApps] = React.useState([]);
|
||||||
@@ -165,7 +165,7 @@ const CreatorGrid = props => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Zoom key={index} in={true} style={{}}>
|
<Zoom key={index} in={true} style={{}}>
|
||||||
<Grid item xs={xs} style={{ padding: "12px 10px 12px 10px", }}>
|
<Grid item xs={xs} style={{ padding: isHeader ? null : "12px 10px 12px 10px", }}>
|
||||||
<Card style={{border: "1px solid rgba(255,255,255,0.3)", minHeight: 177, maxHeight: 177,}}>
|
<Card style={{border: "1px solid rgba(255,255,255,0.3)", minHeight: 177, maxHeight: 177,}}>
|
||||||
<a href={creatorUrl} rel="noopener noreferrer" target={isCloud ? "" : "_blank"} style={{textDecoration: "none", color: "inherit",}}>
|
<a href={creatorUrl} rel="noopener noreferrer" target={isCloud ? "" : "_blank"} style={{textDecoration: "none", color: "inherit",}}>
|
||||||
<CardActionArea style={{padding: "5px 10px 5px 10px", minHeight: 177, maxHeight: 177,}}>
|
<CardActionArea style={{padding: "5px 10px 5px 10px", minHeight: 177, maxHeight: 177,}}>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import ReactGA from 'react-ga4';
|
|||||||
import 'react-alice-carousel/lib/alice-carousel.css';
|
import 'react-alice-carousel/lib/alice-carousel.css';
|
||||||
import TrendingFlatIcon from '@mui/icons-material/TrendingFlat';
|
import TrendingFlatIcon from '@mui/icons-material/TrendingFlat';
|
||||||
import theme from '../theme.jsx';
|
import theme from '../theme.jsx';
|
||||||
|
import {isMobile} from "react-device-detect";
|
||||||
import CheckBoxSharpIcon from '@mui/icons-material/CheckBoxSharp';
|
import CheckBoxSharpIcon from '@mui/icons-material/CheckBoxSharp';
|
||||||
import { findSpecificApp } from "../components/AppFramework.jsx"
|
import { findSpecificApp } from "../components/AppFramework.jsx"
|
||||||
import {
|
import {
|
||||||
@@ -40,7 +41,7 @@ import { useNavigate, Link } from "react-router-dom";
|
|||||||
import WorkflowTemplatePopup from "../components/WorkflowTemplatePopup.jsx";
|
import WorkflowTemplatePopup from "../components/WorkflowTemplatePopup.jsx";
|
||||||
|
|
||||||
const ExploreWorkflow = (props) => {
|
const ExploreWorkflow = (props) => {
|
||||||
const { userdata, globalUrl, appFramework } = props
|
const { userdata, globalUrl, appFramework, isLoggedIn, } = props
|
||||||
const [activeUsecases, setActiveUsecases] = useState(0);
|
const [activeUsecases, setActiveUsecases] = useState(0);
|
||||||
const [modalOpen, setModalOpen] = React.useState(false);
|
const [modalOpen, setModalOpen] = React.useState(false);
|
||||||
const [suggestedUsecases, setSuggestedUsecases] = useState([])
|
const [suggestedUsecases, setSuggestedUsecases] = useState([])
|
||||||
@@ -291,7 +292,7 @@ const ExploreWorkflow = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div style={{ marginTop: 0, margin: "auto", minHeight: sizing, maxHeight: sizing, }}>
|
<div style={{ marginTop: 0, margin: "auto", minHeight: sizing, maxHeight: sizing, }}>
|
||||||
{modalView}
|
{modalView}
|
||||||
<Typography variant="h4" style={{ marginLeft: 8, marginTop: 40, marginRight: 30, marginBottom: 0, }} color="rgba(241, 241, 241, 1)">
|
<Typography variant="h4" style={{ marginLeft: 8, marginTop: isMobile ? null : 40, marginRight: 30, marginBottom: 0, }} color="rgba(241, 241, 241, 1)">
|
||||||
Start using workflows
|
Start using workflows
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" style={{ marginLeft: 8, marginTop: 10, marginRight: 30, marginBottom: 40, }} color="rgba(158, 158, 158, 1)">
|
<Typography variant="body2" style={{ marginLeft: 8, marginTop: 10, marginRight: 30, marginBottom: 40, }} color="rgba(158, 158, 158, 1)">
|
||||||
@@ -300,7 +301,7 @@ const ExploreWorkflow = (props) => {
|
|||||||
|
|
||||||
<div style={{ marginTop: 0, }}>
|
<div style={{ marginTop: 0, }}>
|
||||||
<div className="thumbs" style={{ display: "flex" }}>
|
<div className="thumbs" style={{ display: "flex" }}>
|
||||||
<div style={{ minWidth: 554, maxWidth: 554, borderRadius: theme.palette.borderRadius, }}>
|
<div style={{ minWidth: isMobile ? 300 : 554, maxWidth: isMobile ? 300 : 554, borderRadius: theme.palette.borderRadius, }}>
|
||||||
<Grid item xs={11} style={{}}>
|
<Grid item xs={11} style={{}}>
|
||||||
{suggestedUsecases.length === 0 && usecasesSet ?
|
{suggestedUsecases.length === 0 && usecasesSet ?
|
||||||
<Typography variant="h6" style={{ marginTop: 30, marginBottom: 50, }} color="rgba(158, 158, 158, 1)">
|
<Typography variant="h6" style={{ marginTop: 30, marginBottom: 50, }} color="rgba(158, 158, 158, 1)">
|
||||||
@@ -330,7 +331,10 @@ const ExploreWorkflow = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowTemplatePopup
|
<WorkflowTemplatePopup
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
|
appFramework={appFramework}
|
||||||
|
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
img1={image1}
|
img1={image1}
|
||||||
srcapp={srcapp}
|
srcapp={srcapp}
|
||||||
@@ -351,7 +355,7 @@ const ExploreWorkflow = (props) => {
|
|||||||
fullWidth style={{
|
fullWidth style={{
|
||||||
borderRadius: 200,
|
borderRadius: 200,
|
||||||
height: 51,
|
height: 51,
|
||||||
width: 464,
|
width: isMobile? null : 464,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
padding: "16px 24px",
|
padding: "16px 24px",
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
@@ -368,7 +372,7 @@ const ExploreWorkflow = (props) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="body2" style={{ fontSize: 16, marginTop: 24 }} color="rgba(158, 158, 158, 1)">
|
<Typography variant="body2" style={{ fontSize: 16, marginTop: 24 }} color="rgba(158, 158, 158, 1)">
|
||||||
<Link style={{ color: "#f86a3e", marginLeft: 145 }} to="/usecases" className="btn btn-primary">
|
<Link style={{ color: "#f86a3e", marginLeft: isMobile ? null : 145 }} to="/usecases" className="btn btn-primary">
|
||||||
Explore usecases
|
Explore usecases
|
||||||
</Link>
|
</Link>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const Newsletter = (props) => {
|
|||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [msg, setMsg] = useState("");
|
const [msg, setMsg] = useState("");
|
||||||
const [buttonActive, setButtonActive] = useState(true);
|
const [buttonActive, setButtonActive] = useState(true);
|
||||||
const buttonStyle = {minWidth: 300, borderRadius: 30, height: 60, width: 140, margin: isMobile ? "15px auto 15px auto" : "20px 20px 20px 10px", fontSize: 18,}
|
const buttonStyle = {width: 176, marginTop:16, height: 45, paddingLeft: 24, paddingRight: 24, paddingTop: 16, paddingBottom: 16, background: 'linear-gradient(90deg, #FF8444 0%, #FB47A0 100%)', borderRadius: 200, justifyContent: 'center', alignItems: 'center', gap: 10, display: 'inline-flex', fontSize: 16, fontStyle: "normal", fontWeight: 600}
|
||||||
|
|
||||||
const newsletterSignup = (inemail) => {
|
const newsletterSignup = (inemail) => {
|
||||||
if (inemail.length < 4) {
|
if (inemail.length < 4) {
|
||||||
@@ -52,20 +52,20 @@ const Newsletter = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{margin: "auto", color: "white", textAlign: "center",}}>
|
<div style={{margin: "auto", height:isMobile? 375 :286, color: "white", textAlign: isMobile? "cenetr":"Left", marginTop:24, marginLeft: 24, marginRight: 24}}>
|
||||||
<Typography variant="h4" style={{marginTop: 35,}}>
|
<Typography variant="h4" style={{ fontWeight:700, textTransform: 'capitalize', fontSize:32 }}>
|
||||||
Security Automation Newsletter
|
Security authentication<br/> newsletter
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6" style={{color: "#7d7f82", marginTop: 20, }}>
|
<Typography variant="h6" style={{color: "#7d7f82", marginTop: 8, fontSize: 16,}}>
|
||||||
Defensive security is 99% noise. Join us to sift through it.
|
Defensive security is 99% noise, join us to sift through it!<br/> Enter your email below:
|
||||||
</Typography>
|
</Typography>
|
||||||
<div style={{}}>
|
<div style={{ justifyContent:"center",}}>
|
||||||
<TextField
|
<TextField
|
||||||
style={{minWidth: isMobile ? "90%" : 450, backgroundColor: theme.palette.inputColor, marginTop: 20, borderRadius: 10, }}
|
style={{minWidth: isMobile ? "90%" : 450, height: 45, backgroundColor: theme.palette.inputColor, marginTop: 8, borderRadius: 10, }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style:{
|
style:{
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
height: 60,
|
height: 45,
|
||||||
color: "white",
|
color: "white",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -79,7 +79,6 @@ const Newsletter = (props) => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -96,6 +95,8 @@ const Newsletter = (props) => {
|
|||||||
>
|
>
|
||||||
Sign up
|
Sign up
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
</div>
|
||||||
<div/>
|
<div/>
|
||||||
{msg}
|
{msg}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,11 +18,49 @@ const Priorities = (props) => {
|
|||||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, } = props;
|
const { globalUrl, userdata, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, } = 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({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getFramework()
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (userdata === undefined || userdata === null) {
|
if (userdata === undefined || userdata === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getFramework = () => {
|
||||||
|
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Status not 200 for framework!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
if (responseJson.success === false) {
|
||||||
|
setAppFramework({})
|
||||||
|
if (responseJson.reason !== undefined) {
|
||||||
|
//toast("Failed loading: " + responseJson.reason)
|
||||||
|
} else {
|
||||||
|
//toast("Failed to load framework for your org.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setAppFramework(responseJson)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("err in framework: ", error.toString());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{maxWidth: 1000, }}>
|
<div style={{maxWidth: 1000, }}>
|
||||||
<h2 style={{ display: "inline" }}>Suggestions</h2>
|
<h2 style={{ display: "inline" }}>Suggestions</h2>
|
||||||
@@ -62,6 +100,7 @@ const Priorities = (props) => {
|
|||||||
checkLogin={checkLogin}
|
checkLogin={checkLogin}
|
||||||
setAdminTab={setAdminTab}
|
setAdminTab={setAdminTab}
|
||||||
setCurTab={setCurTab}
|
setCurTab={setCurTab}
|
||||||
|
appFramework={appFramework}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,31 +27,42 @@ const Priority = (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();
|
||||||
|
|
||||||
var realigned = false
|
var realignedSrc = false
|
||||||
|
var realignedDst = false
|
||||||
let newdescription = priority.description
|
let newdescription = priority.description
|
||||||
const descsplit = priority.description.split("&")
|
const descsplit = priority.description.split("&")
|
||||||
if (appFramework !== undefined && descsplit.length === 5 && priority.description.includes(":default")) {
|
if (appFramework !== undefined && descsplit.length === 5 && priority.description.includes(":default")) {
|
||||||
console.log("descsplit: ", descsplit)
|
console.log("descsplit: ", descsplit)
|
||||||
if (descsplit[1] === "") {
|
if (descsplit[1] === "") {
|
||||||
const item = findSpecificApp(appFramework, descsplit[0])
|
const item = findSpecificApp(appFramework, descsplit[0])
|
||||||
console.log("item: ", item)
|
|
||||||
if (item !== null) {
|
if (item !== null) {
|
||||||
descsplit[1] = item.large_image
|
descsplit[1] = item.large_image
|
||||||
|
|
||||||
|
console.log("DESCSPLIT name: ", descsplit[0])
|
||||||
|
|
||||||
|
if (descsplit[0].includes(":default")) {
|
||||||
|
realignedSrc = true
|
||||||
|
}
|
||||||
|
|
||||||
descsplit[0] = descsplit[0].split(":")[0]
|
descsplit[0] = descsplit[0].split(":")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
realigned = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descsplit[3] === "") {
|
if (descsplit[3] === "") {
|
||||||
const item = findSpecificApp(appFramework, descsplit[2])
|
const item = findSpecificApp(appFramework, descsplit[2])
|
||||||
console.log("item: ", item)
|
//console.log("item: ", item)
|
||||||
|
realignedDst = true
|
||||||
if (item !== null) {
|
if (item !== null) {
|
||||||
descsplit[3] = item.large_image
|
descsplit[3] = item.large_image
|
||||||
|
|
||||||
|
if (descsplit[2].includes(":default")) {
|
||||||
|
realignedDst = true
|
||||||
|
}
|
||||||
|
|
||||||
descsplit[2] = descsplit[2].split(":")[0]
|
descsplit[2] = descsplit[2].split(":")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
realigned = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newdescription = descsplit.join("&")
|
newdescription = descsplit.join("&")
|
||||||
@@ -101,6 +112,8 @@ const Priority = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const srcSize = realignedSrc ? 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" : "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={{flex: 2, overflow: "hidden",}}>
|
<div style={{flex: 2, overflow: "hidden",}}>
|
||||||
@@ -112,7 +125,7 @@ const Priority = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
{priority.type === "usecase" && priority.description.includes("&") ?
|
{priority.type === "usecase" && priority.description.includes("&") ?
|
||||||
<span style={{display: "flex", marginTop: 10, }}>
|
<span style={{display: "flex", marginTop: 10, }}>
|
||||||
<img src={newdescription.split("&")[1]} alt={priority.name} style={{height: "auto", width: 30, marginRight: realigned ? -10 : 10, borderRadius: theme.palette.borderRadius, marginTop: realigned ? 5 : 0 }} />
|
<img src={newdescription.split("&")[1]} alt={priority.name} style={{height: srcSize, width: srcSize, marginRight: realignedSrc ? isCloud ? 0 : -10 : 10, borderRadius: theme.palette.borderRadius-3, marginTop: realignedSrc ? 5 : 0 }} />
|
||||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 3, }}>
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 3, }}>
|
||||||
{newdescription.split("&")[0]}
|
{newdescription.split("&")[0]}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -120,7 +133,7 @@ const Priority = (props) => {
|
|||||||
{newdescription.split("&").length > 3 ?
|
{newdescription.split("&").length > 3 ?
|
||||||
<span style={{display: "flex", }}>
|
<span style={{display: "flex", }}>
|
||||||
<ArrowForwardIcon style={{marginLeft: 15, marginRight: 15, }}/>
|
<ArrowForwardIcon style={{marginLeft: 15, marginRight: 15, }}/>
|
||||||
<img src={newdescription.split("&")[3]} alt={priority.name+"2"} style={{height: "auto", width: 30, marginRight: realigned ? -10 : 10, borderRadius: theme.palette.borderRadius, marginTop: realigned ? 5 : 0 }} />
|
<img src={newdescription.split("&")[3]} alt={priority.name+"2"} style={{height: dstSize, width: dstSize, marginRight: realignedDst ? -5 : 10, borderRadius: theme.palette.borderRadius-3, marginTop: realignedDst ? 5 : 0 }} />
|
||||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 3}}>
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 3}}>
|
||||||
{newdescription.split("&")[2]}
|
{newdescription.split("&")[2]}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Checkbox from "@mui/material/Checkbox";
|
|||||||
|
|
||||||
import AliceCarousel from "react-alice-carousel";
|
import AliceCarousel from "react-alice-carousel";
|
||||||
import "react-alice-carousel/lib/alice-carousel.css";
|
import "react-alice-carousel/lib/alice-carousel.css";
|
||||||
|
import {isMobile} from "react-device-detect";
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
import EmailIcon from "@mui/icons-material/Email";
|
import EmailIcon from "@mui/icons-material/Email";
|
||||||
import NewReleasesIcon from "@mui/icons-material/NewReleases";
|
import NewReleasesIcon from "@mui/icons-material/NewReleases";
|
||||||
@@ -79,6 +79,7 @@ const WelcomeForm = (props) => {
|
|||||||
selectionOpen,
|
selectionOpen,
|
||||||
setSelectionOpen,
|
setSelectionOpen,
|
||||||
checkLogin,
|
checkLogin,
|
||||||
|
isLoggedIn,
|
||||||
} = props;
|
} = props;
|
||||||
const [moreButton, setMoreButton] = useState(false);
|
const [moreButton, setMoreButton] = useState(false);
|
||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
@@ -449,19 +450,6 @@ const WelcomeForm = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSkip = () => {
|
|
||||||
setclickdiff(240);
|
|
||||||
if (!isStepOptional(activeStep)) {
|
|
||||||
throw new Error("You can't skip a step that isn't optional.");
|
|
||||||
}
|
|
||||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
|
||||||
setSkipped((prevSkipped) => {
|
|
||||||
const newSkipped = new Set(prevSkipped.values());
|
|
||||||
newSkipped.add(activeStep);
|
|
||||||
return newSkipped;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setActiveStep(0);
|
setActiveStep(0);
|
||||||
};
|
};
|
||||||
@@ -652,6 +640,7 @@ const WelcomeForm = (props) => {
|
|||||||
);
|
);
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return (
|
||||||
|
appFramework === undefined || appFramework === null ? null :
|
||||||
<AppSelection
|
<AppSelection
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
@@ -667,13 +656,14 @@ const WelcomeForm = (props) => {
|
|||||||
case 2:
|
case 2:
|
||||||
return (
|
return (
|
||||||
<Collapse in={true}>
|
<Collapse in={true}>
|
||||||
<div style={{ marginTop: 0, maxWidth: 700, minWidth: 700, margin: "auto", minHeight: sizing, maxHeight: sizing, }}>
|
<div style={{ marginTop: 0, maxWidth: isMobile ? 300 : 700, minWidth: isMobile ? 300 : 700, textAlign: isMobile ? "center" : null, margin: "auto", minHeight: sizing, maxHeight: sizing, }}>
|
||||||
|
|
||||||
<div style={{ marginTop: 0, }}>
|
<div style={{ marginTop: 0, }}>
|
||||||
<div className="thumbs" style={{ display: "flex" }}>
|
<div className="thumbs" style={{ display: "flex" }}>
|
||||||
<div style={{ minWidth: 554, maxWidth: 554, borderRadius: theme.palette.borderRadius, }}>
|
<div style={{ minWidth: isMobile ? 300 : 554, maxWidth: isMobile ? 300 : 554, borderRadius: theme.palette.borderRadius, }}>
|
||||||
<ExploreWorkflow
|
<ExploreWorkflow
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
appFramework={appFramework}
|
appFramework={appFramework}
|
||||||
/>
|
/>
|
||||||
@@ -692,13 +682,6 @@ const WelcomeForm = (props) => {
|
|||||||
const extraHeight = isCloud ? -7 : 0;
|
const extraHeight = isCloud ? -7 : 0;
|
||||||
return (
|
return (
|
||||||
<div style={{}}>
|
<div style={{}}>
|
||||||
{/*selectionOpen ?
|
|
||||||
<WorkflowSearch
|
|
||||||
defaultSearch={defaultSearch}
|
|
||||||
newSelectedApp={newSelectedApp}
|
|
||||||
setNewSelectedApp={setNewSelectedApp}
|
|
||||||
/>
|
|
||||||
: null*/}
|
|
||||||
<div>
|
<div>
|
||||||
{activeStep === steps.length ? (
|
{activeStep === steps.length ? (
|
||||||
<div paddingTop="20px">
|
<div paddingTop="20px">
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
import theme from '../theme.jsx';
|
import theme from '../theme.jsx';
|
||||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||||
|
import AppSearchButtons from "../components/AppSearchButtons.jsx";
|
||||||
|
import { isMobile } from "react-device-detect";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -26,7 +28,7 @@ import WorkflowTemplatePopup2 from "./WorkflowTemplatePopup.jsx";
|
|||||||
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
||||||
|
|
||||||
const WorkflowTemplatePopup = (props) => {
|
const WorkflowTemplatePopup = (props) => {
|
||||||
const { userdata, globalUrl, img1, srcapp, img2, dstapp, title, description, visualOnly, apps } = props;
|
const { userdata, appFramework, globalUrl, img1, srcapp, img2, dstapp, title, description, visualOnly, apps, isLoggedIn, isHomePage } = props;
|
||||||
|
|
||||||
const [isActive, setIsActive] = useState(false);
|
const [isActive, setIsActive] = useState(false);
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
@@ -36,14 +38,21 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
const [workflow, setWorkflow] = useState({});
|
const [workflow, setWorkflow] = useState({});
|
||||||
const [appAuthentication, setAppAuthentication] = React.useState(undefined);
|
const [appAuthentication, setAppAuthentication] = React.useState(undefined);
|
||||||
|
|
||||||
|
const [missingSource, setMissingSource] = React.useState(undefined)
|
||||||
|
const [missingDestination, setMissingDestination] = React.useState(undefined);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("Source & Dest check:", missingSource, missingDestination)
|
||||||
|
}, [missingSource, missingDestination])
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
const imagestyleWrapper = {
|
const imagestyleWrapper = {
|
||||||
height: 40,
|
height: 40,
|
||||||
width: 40,
|
width: 40,
|
||||||
borderRadius: 40,
|
borderRadius: 40,
|
||||||
border: "1px solid rgba(255,255,255,0.3)",
|
border: isHomePage ? null : "1px solid rgba(255,255,255,0.3)",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
}
|
}
|
||||||
@@ -52,7 +61,7 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
height: 40,
|
height: 40,
|
||||||
width: 40,
|
width: 40,
|
||||||
borderRadius: 40,
|
borderRadius: 40,
|
||||||
border: "1px solid rgba(255,255,255,0.3)",
|
border: isHomePage ? null : "1px solid rgba(255,255,255,0.3)",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
}
|
}
|
||||||
@@ -61,13 +70,13 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
height: 40,
|
height: 40,
|
||||||
width: 40,
|
width: 40,
|
||||||
borderRadius: 40,
|
borderRadius: 40,
|
||||||
border: "1px solid rgba(255,255,255,0.3)",
|
border: isHomePage ? null : "1px solid rgba(255,255,255,0.3)",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}
|
}
|
||||||
|
|
||||||
const imagestyleDefault = {
|
const imagestyleDefault = {
|
||||||
display: "block",
|
display: "block",
|
||||||
marginLeft: 11,
|
marginLeft: 12,
|
||||||
marginTop: 11,
|
marginTop: 11,
|
||||||
height: 35,
|
height: 35,
|
||||||
width: "auto",
|
width: "auto",
|
||||||
@@ -108,8 +117,10 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadAppAuth = () => {
|
const loadAppAuth = () => {
|
||||||
if (userdata === undefined || userdata === null) {
|
// Check if it exists, and has keys
|
||||||
|
if (userdata === undefined || userdata === null || Object.keys(userdata).length === 0) {
|
||||||
setErrorMessage("You need to be logged in to try usecases. Redirecting in 5 seconds...")
|
setErrorMessage("You need to be logged in to try usecases. Redirecting in 5 seconds...")
|
||||||
|
|
||||||
// Send the user to the login screen after 3 seconds
|
// Send the user to the login screen after 3 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Make it cancel if the state modalOpen changes
|
// Make it cancel if the state modalOpen changes
|
||||||
@@ -162,6 +173,7 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const getGeneratedWorkflow = () => {
|
const getGeneratedWorkflow = () => {
|
||||||
// POST
|
// POST
|
||||||
// https://shuffler.io/api/v1/workflows/merge
|
// https://shuffler.io/api/v1/workflows/merge
|
||||||
@@ -174,12 +186,24 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
|
|
||||||
if (srcapp.includes(":default") || dstapp.includes(":default")) {
|
if (srcapp.includes(":default") || dstapp.includes(":default")) {
|
||||||
toast("You need to select both a source and destination app before generating this workflow.")
|
toast("You need to select both a source and destination app before generating this workflow.")
|
||||||
|
|
||||||
|
if (srcapp.includes(":default")) {
|
||||||
|
setMissingSource({
|
||||||
|
"type": srcapp.split(":")[0],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstapp.includes(":default")) {
|
||||||
|
setMissingDestination({
|
||||||
|
"type": dstapp.split(":")[0],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setWorkflowLoading(true)
|
setWorkflowLoading(true)
|
||||||
|
|
||||||
// FIXME: Remove hardcoding here after testing, and user srcapp/dstapp
|
|
||||||
const newsrcapp = srcapp
|
const newsrcapp = srcapp
|
||||||
const newdstapp = dstapp
|
const newdstapp = dstapp
|
||||||
|
|
||||||
@@ -207,15 +231,21 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for framework!");
|
//console.log("Status not 200 for framework!");
|
||||||
}
|
}
|
||||||
|
|
||||||
setWorkflowLoading(false)
|
setWorkflowLoading(false)
|
||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
|
if (responseJson.id !== undefined && responseJson.id !== null && responseJson.id !== "" && responseJson.name !== undefined && responseJson.name !== null && responseJson.name !== "") {
|
||||||
|
console.log("Success in workflow template (prebuilt): ", responseJson);
|
||||||
|
setWorkflow(responseJson)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
console.log("Error in workflow template: ", responseJson.error);
|
//console.log("Error in workflow template: ", responseJson.error);
|
||||||
|
|
||||||
setErrorMessage("Failed to generate workflow for these tools - the Shuffle team has been notified. Click out of this window to continue. Contact support@shuffler.io for further assistance.")
|
setErrorMessage("Failed to generate workflow for these tools - the Shuffle team has been notified. Click out of this window to continue. Contact support@shuffler.io for further assistance.")
|
||||||
|
|
||||||
@@ -269,9 +299,9 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
style: {
|
style: {
|
||||||
backgroundColor: "black",
|
backgroundColor: "black",
|
||||||
color: "white",
|
color: "white",
|
||||||
minWidth: 700,
|
minWidth: isHomePage ? null : isMobile ? 300 : 700,
|
||||||
maxWidth: 700,
|
maxWidth: isHomePage ? null : isMobile ? 300 : 700,
|
||||||
paddingTop: 75,
|
paddingTop: isMobile ? null : 75,
|
||||||
itemAlign: "center",
|
itemAlign: "center",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -290,8 +320,8 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent style={{marginTop: 0, marginLeft: 75, maxWidth: 470, }}>
|
<DialogContent style={{marginTop: 0, marginLeft: isHomePage ? null : isMobile ? null : 75, maxWidth: 470, }}>
|
||||||
<Typography variant="h4">
|
<Typography variant="h4" style={{ fontSize: isMobile ? 20 : null}}>
|
||||||
<b>Configure Workflow</b>
|
<b>Configure Workflow</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 25, }}>
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 25, }}>
|
||||||
@@ -322,6 +352,41 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{isLoggedIn && (missingSource !== undefined || missingDestination !== undefined) ?
|
||||||
|
<Typography variant="body1" style={{marginTop: 75, }}>
|
||||||
|
{"The following app category is required generate this workflow: "}
|
||||||
|
</Typography>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{(missingSource !== undefined) ?
|
||||||
|
<div style={{}}>
|
||||||
|
<AppSearchButtons
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
appFramework={appFramework}
|
||||||
|
|
||||||
|
appType={missingSource.type}
|
||||||
|
appImage={missingSource.image}
|
||||||
|
|
||||||
|
setMissing={setMissingSource}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{(missingDestination !== undefined) ?
|
||||||
|
<div style={{}}>
|
||||||
|
<AppSearchButtons
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
appFramework={appFramework}
|
||||||
|
|
||||||
|
appType={missingDestination.type}
|
||||||
|
appImage={missingDestination.image}
|
||||||
|
|
||||||
|
setMissing={setMissingDestination}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
<ConfigureWorkflow
|
<ConfigureWorkflow
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
@@ -352,26 +417,26 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
if (title.length > maxlength) {
|
if (title.length > maxlength) {
|
||||||
parsedTitle = title.substring(0, maxlength) + "..."
|
parsedTitle = title.substring(0, maxlength) + "..."
|
||||||
}
|
}
|
||||||
|
console.log("isHomePage", isHomePage)
|
||||||
parsedTitle = parsedTitle.replaceAll("_", " ")
|
parsedTitle = parsedTitle.replaceAll("_", " ")
|
||||||
|
|
||||||
const parsedDescription = description !== undefined && description !== null ? description.replaceAll("_", " ") : ""
|
const parsedDescription = description !== undefined && description !== null ? description.replaceAll("_", " ") : ""
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", maxWidth: isCloud ? 470 : 450, minWidth: isCloud ? 470 : 450, height: 78, borderRadius: 8 }}>
|
<div style={{ display: "flex", maxWidth: isCloud ? 470 : isMobile? null: 450, minWidth: isCloud ? 470 : isMobile? null: 450, height: 78, borderRadius: 8, }}>
|
||||||
<ModalView />
|
<ModalView />
|
||||||
<div
|
<div
|
||||||
// variant={isActive === 1 ? "contained" : "outlined"}
|
// variant={isActive === 1 ? "contained" : "outlined"}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
disabled={visualOnly === true}
|
disabled={visualOnly === true}
|
||||||
style={{
|
style={{
|
||||||
margin: 4,
|
margin: isHomePage ? isMobile ? null : 4 : 4 ,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: isHomePage ? null : theme.palette.inputColor,
|
||||||
border: isActive ? errorMessage !== "" ? "1px solid red" : `2px solid ${theme.palette.green}` : isHovered ? "1px solid #f85a3e" : "1px solid rgba(33, 33, 33, 1)",
|
border: isHomePage ? null : isActive ? errorMessage !== "" ? "1px solid red" : `2px solid ${theme.palette.green}` : isHovered ? "1px solid #f85a3e" : "1px solid rgba(33, 33, 33, 1)",
|
||||||
cursor: isActive ? errorMessage !== "" ? "not-allowed" : "pointer" : "pointer",
|
cursor: isActive ? errorMessage !== "" ? "not-allowed" : "pointer" : "pointer",
|
||||||
padding: "10px 20px 10px 20px",
|
padding: "10px 20px 10px 20px",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
@@ -434,10 +499,10 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 3, marginLeft: 20, }}>
|
<div style={{ flex: 3, marginLeft: 20, }}>
|
||||||
<Typography variant="body1" style={{ marginTop: parsedDescription.length === 0 ? 10 : 0, }} color="rgba(241, 241, 241, 1)">
|
<Typography variant="body1" style={{ marginTop: parsedDescription.length === 0 ? 10 : 0, fontSize: isMobile ? 13 : 16,fontWeight: isHomePage? 600 : null,textTransform: 'capitalize', color: isHomePage ? "var(--White-text, #F1F1F1)" :"rgba(241, 241, 241, 1)"}} >
|
||||||
{parsedTitle}
|
{parsedTitle}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 0, marginRight: 0, maxHeight: 16, overflow: "hidden",}} color="rgba(158, 158, 158, 1)">
|
<Typography variant="body2" color="textSecondary" style={{ fontSize: isMobile ? 10: 16, fontWeight: isHomePage ? 400 : null, textTransform: 'capitalize', marginTop: 0, overflow: "hidden",}} color="rgba(158, 158, 158, 1)">
|
||||||
{parsedDescription}
|
{parsedDescription}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -980,6 +980,22 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
leads.push("customer")
|
leads.push("customer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (responseJson.lead_info.old_customer) {
|
||||||
|
leads.push("old customer")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseJson.lead_info.tech_partner) {
|
||||||
|
leads.push("tech partner")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseJson.lead_info.creator) {
|
||||||
|
leads.push("creator")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseJson.lead_info.opensource) {
|
||||||
|
leads.push("open source")
|
||||||
|
}
|
||||||
|
|
||||||
if (responseJson.lead_info.demo_done) {
|
if (responseJson.lead_info.demo_done) {
|
||||||
leads.push("demo done")
|
leads.push("demo done")
|
||||||
}
|
}
|
||||||
@@ -2412,7 +2428,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
renderValue={(selected) => selected.join(', ')}
|
renderValue={(selected) => selected.join(', ')}
|
||||||
MenuProps={MenuProps}
|
MenuProps={MenuProps}
|
||||||
>
|
>
|
||||||
{["contacted", "lead", "pov", "demo done", "customer", "student", "internal"].map((name) => (
|
{["contacted", "lead", "demo done", "pov", "customer", "open source", "student", "internal", "old customer", "creator", "tech partner"].map((name) => (
|
||||||
<MenuItem key={name} value={name}>
|
<MenuItem key={name} value={name}>
|
||||||
<Checkbox checked={selectedStatus.indexOf(name) > -1} />
|
<Checkbox checked={selectedStatus.indexOf(name) > -1} />
|
||||||
<ListItemText primary={name} />
|
<ListItemText primary={name} />
|
||||||
@@ -2528,7 +2544,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
label=<span>
|
label=<span>
|
||||||
Licensing (Beta)
|
Licensing
|
||||||
</span>
|
</span>
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
@@ -3000,7 +3016,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
curTab === 1 ? (
|
curTab === 1 ? (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
<div style={{ marginTop: 20, marginBottom: 20 }}>
|
||||||
<h2 style={{ display: "inline" }}>User management</h2>
|
<h2 style={{ display: "inline" }}>User Management</h2>
|
||||||
<span style={{ marginLeft: 25 }}>
|
<span style={{ marginLeft: 25 }}>
|
||||||
Add, edit, block or change passwords.{" "}
|
Add, edit, block or change passwords.{" "}
|
||||||
<a
|
<a
|
||||||
@@ -3080,7 +3096,11 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
) : null}
|
) : null}
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary="Actions"
|
primary="Actions"
|
||||||
style={{ minWidth: 180, maxWidth: 180 }}
|
style={{ minWidth: 100, maxWidth: 100, }}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary="Last Login"
|
||||||
|
style={{ minWidth: 150, maxWidth: 150, }}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{users === undefined || users === null
|
{users === undefined || users === null
|
||||||
@@ -3091,6 +3111,24 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
bgColor = "#1f2023";
|
bgColor = "#1f2023";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timeNow = new Date().getTime();
|
||||||
|
|
||||||
|
// Get the highest timestamp in data.login_info
|
||||||
|
var lastLogin = "N/A"
|
||||||
|
if (data.login_info !== undefined && data.login_info !== null) {
|
||||||
|
var loginInfo = 0
|
||||||
|
for (var i = 0; i < data.login_info.length; i++) {
|
||||||
|
if (data.login_info[i].timestamp > loginInfo) {
|
||||||
|
loginInfo = data.login_info[i].timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loginInfo > 0) {
|
||||||
|
console.log("SETTING LAST LOGIN: " + loginInfo)
|
||||||
|
lastLogin = new Date(loginInfo * 1000).toISOString().slice(0, 10) + " (" + data.login_info.length + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem key={index} style={{ backgroundColor: bgColor }}>
|
<ListItem key={index} style={{ backgroundColor: bgColor }}>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
@@ -3242,7 +3280,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<ListItemText style={{ display: "flex" }}>
|
<ListItemText style={{ display: "flex", minWidth: 100, maxWidth: 100, }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedUserModalOpen(true);
|
setSelectedUserModalOpen(true);
|
||||||
@@ -3300,6 +3338,11 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
|||||||
New apikey
|
New apikey
|
||||||
</Button>*/}
|
</Button>*/}
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
|
<ListItemText
|
||||||
|
style={{ minWidth: 150, maxWidth: 150, }}
|
||||||
|
primary={lastLogin}
|
||||||
|
><span/>
|
||||||
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -977,14 +977,17 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
tmpView = execution_id;
|
tmpView = execution_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("TMPVIEW: ", tmpView);
|
||||||
|
|
||||||
// Compare with currently selected item
|
// Compare with currently selected item
|
||||||
if (tmpView !== undefined && tmpView !== null && tmpView.length > 0) {
|
if (tmpView !== undefined && tmpView !== null && tmpView.length > 0) {
|
||||||
// Don't clean up if it's already open
|
// Don't clean up if it's already open
|
||||||
if (executionModalOpen === true) {
|
if (executionModalOpen === true) {
|
||||||
|
console.log("Execution modal already open, not cleaning up")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const execution = responseJson.find((data) => data.execution_id === tmpView);
|
const execution = responseJson.executions.find((data) => data.execution_id === tmpView);
|
||||||
|
|
||||||
setExecutionModalOpen(true)
|
setExecutionModalOpen(true)
|
||||||
if (execution !== null && execution !== undefined) {
|
if (execution !== null && execution !== undefined) {
|
||||||
@@ -16678,28 +16681,29 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<ConfigureWorkflow
|
<div style={{height: 75, width: "100%", background: `linear-gradient(to right, #f86a3e, #fc3922)`, position: "relative",}} />
|
||||||
userdata={userdata}
|
<div style={{ padding: "50px 0px 50px 0px", }}>
|
||||||
alert={alert}
|
<ConfigureWorkflow
|
||||||
theme={theme}
|
workflow={workflow}
|
||||||
setAuthenticationType={setAuthenticationType}
|
userdata={userdata}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
workflow={workflow}
|
apps={apps}
|
||||||
setSelectedAction={setSelectedAction}
|
setAuthenticationType={setAuthenticationType}
|
||||||
setSelectedApp={setSelectedApp}
|
setSelectedAction={setSelectedAction}
|
||||||
setAuthenticationModalOpen={setAuthenticationModalOpen}
|
setSelectedApp={setSelectedApp}
|
||||||
appAuthentication={appAuthentication}
|
setAuthenticationModalOpen={setAuthenticationModalOpen}
|
||||||
selectedAction={selectedAction}
|
appAuthentication={appAuthentication}
|
||||||
apps={apps}
|
selectedAction={selectedAction}
|
||||||
setConfigureWorkflowModalOpen={setConfigureWorkflowModalOpen}
|
setConfigureWorkflowModalOpen={setConfigureWorkflowModalOpen}
|
||||||
saveWorkflow={saveWorkflow}
|
saveWorkflow={saveWorkflow}
|
||||||
newWebhook={newWebhook}
|
newWebhook={newWebhook}
|
||||||
submitSchedule={submitSchedule}
|
submitSchedule={submitSchedule}
|
||||||
referenceUrl={referenceUrl}
|
referenceUrl={referenceUrl}
|
||||||
workflowExecutions={workflowExecutions}
|
workflowExecutions={workflowExecutions}
|
||||||
getWorkflowExecution={getWorkflowExecution}
|
getWorkflowExecution={getWorkflowExecution}
|
||||||
isCloud={isCloud}
|
isCloud={isCloud}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
|
|||||||
@@ -929,9 +929,9 @@ const AppCreator = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path === "/files/{file_id}/content") {
|
if (path === "/files/{file_id}/content") {
|
||||||
//console.log("FILE DOWNLOAD Method: ", path, method, methodvalue)
|
//console.log("FILE DOWNLOAD Method: ", path, method, methodvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Typescript? I think not ;)
|
// Typescript? I think not ;)
|
||||||
@@ -2137,7 +2137,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (queryitem.name.toLowerCase() == "file_id") {
|
if (queryitem.name.toLowerCase() == "file_id") {
|
||||||
item.queries[querykey].name = "fileid"
|
item.queries[querykey].name = "fileid"
|
||||||
continue;
|
continue;
|
||||||
//skipped = true
|
//skipped = true
|
||||||
//break
|
//break
|
||||||
@@ -2525,8 +2525,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
for (let authkey in extraAuth) {
|
for (let authkey in extraAuth) {
|
||||||
const curauth = extraAuth[authkey];
|
const curauth = extraAuth[authkey];
|
||||||
|
|
||||||
if (curauth.name.toLowerCase() == "url") {
|
if (curauth.name.length === 0 || curauth.name.toLowerCase() == "url") {
|
||||||
toast("Can't add extra auth with Name URL");
|
toast("Can't add extra auth with empty name or Name URL");
|
||||||
setAppBuilding(false);
|
setAppBuilding(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1660,7 +1660,6 @@ const Apps = (props) => {
|
|||||||
|
|
||||||
refine(event.currentTarget.value)
|
refine(event.currentTarget.value)
|
||||||
}}
|
}}
|
||||||
limit={5}
|
|
||||||
/>
|
/>
|
||||||
{/*isSearchStalled ? 'My search is stalled' : ''*/}
|
{/*isSearchStalled ? 'My search is stalled' : ''*/}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ const useStyles = makeStyles({
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData, isLoggedIn, workflows, setWorkflows}) => {
|
const UsecaseListComponent = (props) => {
|
||||||
|
const { keys, userdata, isCloud, globalUrl, frameworkData, isLoggedIn, workflows, setWorkflows, } = props
|
||||||
|
|
||||||
const [expandedIndex, setExpandedIndex] = useState(-1);
|
const [expandedIndex, setExpandedIndex] = useState(-1);
|
||||||
const [expandedItem, setExpandedItem] = useState(-1);
|
const [expandedItem, setExpandedItem] = useState(-1);
|
||||||
const [inputUsecase, setInputUsecase] = useState({});
|
const [inputUsecase, setInputUsecase] = useState({});
|
||||||
@@ -165,13 +167,10 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
|
|
||||||
|
|
||||||
const parseUsecase = (subcase) => {
|
const parseUsecase = (subcase) => {
|
||||||
console.log("parseUsecase: ", subcase)
|
//console.log("parseUsecase: ", subcase)
|
||||||
const srcdata = findSpecificApp(frameworkData, subcase.type)
|
const srcdata = findSpecificApp(frameworkData, subcase.type)
|
||||||
const dstdata = findSpecificApp(frameworkData, subcase.last)
|
const dstdata = findSpecificApp(frameworkData, subcase.last)
|
||||||
|
|
||||||
console.log("srcdata: ", srcdata)
|
|
||||||
console.log("dstdata: ", dstdata)
|
|
||||||
|
|
||||||
if (srcdata !== undefined && srcdata !== null) {
|
if (srcdata !== undefined && srcdata !== null) {
|
||||||
subcase.srcimg = srcdata.large_image
|
subcase.srcimg = srcdata.large_image
|
||||||
subcase.srcapp = srcdata.name
|
subcase.srcapp = srcdata.name
|
||||||
@@ -185,13 +184,14 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
return subcase
|
return subcase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const getUsecase = (subcase, index, subindex) => {
|
const getUsecase = (subcase, index, subindex) => {
|
||||||
subcase = parseUsecase(subcase)
|
subcase = parseUsecase(subcase)
|
||||||
|
|
||||||
// Timeout 50ms to delay it slightly
|
// Timeout 50ms to delay it slightly
|
||||||
setTimeout(() => {
|
//setTimeout(() => {
|
||||||
setInputUsecase(subcase)
|
// setInputUsecase(subcase)
|
||||||
}, 50)
|
//}, 50)
|
||||||
|
|
||||||
fetch(`${globalUrl}/api/v1/workflows/usecases/${escape(subcase.name.replaceAll(" ", "_"))}`, {
|
fetch(`${globalUrl}/api/v1/workflows/usecases/${escape(subcase.name.replaceAll(" ", "_"))}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -209,12 +209,13 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
console.log("In responseJson for usecase: ", responseJson)
|
|
||||||
var parsedUsecase = responseJson
|
var parsedUsecase = responseJson
|
||||||
|
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
parsedUsecase = subcase
|
parsedUsecase = subcase
|
||||||
} else {
|
} else {
|
||||||
|
console.log("FOUND: ", JSON.parse(JSON.stringify(responseJson)))
|
||||||
|
|
||||||
parsedUsecase = responseJson
|
parsedUsecase = responseJson
|
||||||
|
|
||||||
parsedUsecase.srcimg = subcase.srcimg
|
parsedUsecase.srcimg = subcase.srcimg
|
||||||
@@ -229,19 +230,21 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
setExpandedItem(subindex)
|
setExpandedItem(subindex)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
//console.log("Scroll!")
|
|
||||||
const found = document.getElementById("selected_box");
|
const found = document.getElementById("selected_box");
|
||||||
if (found !== undefined && found !== null) {
|
if (found !== undefined && found !== null) {
|
||||||
//console.log("FOUND!!")
|
//console.log("FOUND!!")
|
||||||
found.scrollTo({
|
|
||||||
top: 100,
|
//found.scrollTo({
|
||||||
behavior: "smooth",
|
// top: 100,
|
||||||
})
|
// behavior: "smooth",
|
||||||
|
//})
|
||||||
|
} else {
|
||||||
|
//console.log("NOT FOUND!!")
|
||||||
}
|
}
|
||||||
|
|
||||||
setFirstLoad(true)
|
setFirstLoad(true)
|
||||||
setSelectedWorkflows([])
|
setSelectedWorkflows([])
|
||||||
}, 100);
|
}, 100)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
//toast(error.toString());
|
//toast(error.toString());
|
||||||
@@ -412,7 +415,7 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
const fixedName = subcase.name.toLowerCase().replace("_", " ")
|
const fixedName = subcase.name.toLowerCase().replace("_", " ")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid id={fixedName} item xs={selectedItem ? 12 : 4} key={subindex} style={{minHeight: 110,}} onClick={() => {
|
<Grid id={fixedName} item xs={selectedItem ? 12 : 4} key={subindex} style={{minHeight: 110,}} onClick={() => {
|
||||||
|
|
||||||
//setSelectedWorkflows([])
|
//setSelectedWorkflows([])
|
||||||
if (selectedItem) {
|
if (selectedItem) {
|
||||||
@@ -784,7 +787,6 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
borderRadius: theme.palette.borderRadius,
|
borderRadius: theme.palette.borderRadius,
|
||||||
}}
|
}}
|
||||||
onChange={(event, newValue) => {
|
onChange={(event, newValue) => {
|
||||||
console.log("CLICK: ", newValue)
|
|
||||||
//handleWorkflowSelectionUpdate({ target: { value: newValue} })
|
//handleWorkflowSelectionUpdate({ target: { value: newValue} })
|
||||||
//setSelectedWorkflows=
|
//setSelectedWorkflows=
|
||||||
//var newvalue = []
|
//var newvalue = []
|
||||||
@@ -801,7 +803,6 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
if (workflows[key]["usecase_ids"] !== undefined && workflows[key]["usecase_ids"] !== null && workflows[key]["usecase_ids"].includes(subcase.name)) {
|
if (workflows[key]["usecase_ids"] !== undefined && workflows[key]["usecase_ids"] !== null && workflows[key]["usecase_ids"].includes(subcase.name)) {
|
||||||
const filtered = workflows[key]["usecase_ids"].filter(data => data !== subcase.name)
|
const filtered = workflows[key]["usecase_ids"].filter(data => data !== subcase.name)
|
||||||
if (filtered !== undefined && filtered !== null) {
|
if (filtered !== undefined && filtered !== null) {
|
||||||
//console.log("Removing: ", workflows[key].name, workflows[key])
|
|
||||||
workflows[key]["usecase_ids"] = filtered
|
workflows[key]["usecase_ids"] = filtered
|
||||||
|
|
||||||
setWorkflow(workflows[key])
|
setWorkflow(workflows[key])
|
||||||
@@ -813,19 +814,16 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
|
|
||||||
if (workflows[key]["usecase_ids"] === undefined || workflows[key]["usecase_ids"] === null) {
|
if (workflows[key]["usecase_ids"] === undefined || workflows[key]["usecase_ids"] === null) {
|
||||||
workflows[key]["usecase_ids"] = [subcase.name]
|
workflows[key]["usecase_ids"] = [subcase.name]
|
||||||
console.log("Setting: ", workflows[key].name)
|
|
||||||
setWorkflow(workflows[key])
|
setWorkflow(workflows[key])
|
||||||
|
|
||||||
} else if (!workflows[key]["usecase_ids"].includes(subcase.name)) {
|
} else if (!workflows[key]["usecase_ids"].includes(subcase.name)) {
|
||||||
workflows[key]["usecase_ids"].push(subcase.name)
|
workflows[key]["usecase_ids"].push(subcase.name)
|
||||||
console.log("Adding: ", workflows[key].name)
|
|
||||||
setWorkflow(workflows[key])
|
setWorkflow(workflows[key])
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setWorkflows(workflows)
|
setWorkflows(workflows)
|
||||||
console.log("New: ", newValue)
|
|
||||||
setSelectedWorkflows(newValue)
|
setSelectedWorkflows(newValue)
|
||||||
//setUpdate(Math.random())
|
//setUpdate(Math.random())
|
||||||
}}
|
}}
|
||||||
@@ -887,19 +885,23 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
|||||||
>
|
>
|
||||||
Try it out:
|
Try it out:
|
||||||
</Typography>
|
</Typography>
|
||||||
<WorkflowTemplatePopup
|
{frameworkData !== undefined && frameworkData !== null && Object.keys(frameworkData).length > 0 ?
|
||||||
userdata={userdata}
|
<WorkflowTemplatePopup
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
appFramework={frameworkData}
|
||||||
|
userdata={userdata}
|
||||||
|
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
img1={inputUsecase.srcimg}
|
img1={inputUsecase.srcimg}
|
||||||
srcapp={inputUsecase.srcapp}
|
srcapp={inputUsecase.srcapp}
|
||||||
img2={inputUsecase.dstimg}
|
img2={inputUsecase.dstimg}
|
||||||
dstapp={inputUsecase.dstapp}
|
dstapp={inputUsecase.dstapp}
|
||||||
title={inputUsecase.name}
|
title={inputUsecase.name}
|
||||||
description={inputUsecase.description}
|
description={inputUsecase.description}
|
||||||
|
|
||||||
apps={apps}
|
apps={apps}
|
||||||
/>
|
/>
|
||||||
|
: null}
|
||||||
</span>
|
</span>
|
||||||
{/*
|
{/*
|
||||||
|
|
||||||
@@ -1125,7 +1127,7 @@ const RadialChart = ({keys, setSelectedCategory}) => {
|
|||||||
// This is the start of a dashboard that can be used.
|
// This is the start of a dashboard that can be used.
|
||||||
// What data do we fill in here? Idk
|
// What data do we fill in here? Idk
|
||||||
const Dashboard = (props) => {
|
const Dashboard = (props) => {
|
||||||
const { globalUrl, isLoggedIn } = props;
|
const { globalUrl, isLoggedIn, userdata } = props;
|
||||||
//const alert = useAlert();
|
//const alert = useAlert();
|
||||||
const [bigChartData, setBgChartData] = useState("data1");
|
const [bigChartData, setBgChartData] = useState("data1");
|
||||||
const [dayAmount, setDayAmount] = useState(7);
|
const [dayAmount, setDayAmount] = useState(7);
|
||||||
@@ -1176,7 +1178,7 @@ const Dashboard = (props) => {
|
|||||||
|
|
||||||
const foundQuery2 = params["selected_object"]
|
const foundQuery2 = params["selected_object"]
|
||||||
if (foundQuery2 !== null && foundQuery2 !== undefined) {
|
if (foundQuery2 !== null && foundQuery2 !== undefined) {
|
||||||
console.log("Got selected_object: ", foundQuery2)
|
//console.log("Got selected_object: ", foundQuery2)
|
||||||
|
|
||||||
const queryName = foundQuery2.toLowerCase().replaceAll("_", " ")
|
const queryName = foundQuery2.toLowerCase().replaceAll("_", " ")
|
||||||
// Waiting a bit for it to render
|
// Waiting a bit for it to render
|
||||||
@@ -1184,6 +1186,15 @@ const Dashboard = (props) => {
|
|||||||
const foundItem = document.getElementById(queryName)
|
const foundItem = document.getElementById(queryName)
|
||||||
if (foundItem !== undefined && foundItem !== null) {
|
if (foundItem !== undefined && foundItem !== null) {
|
||||||
foundItem.click()
|
foundItem.click()
|
||||||
|
// Scroll to it
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
foundItem.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "center",
|
||||||
|
inline: "center"
|
||||||
|
})
|
||||||
|
}, 100)
|
||||||
} else {
|
} else {
|
||||||
//console.log("Couldn't find item with name ", queryName)
|
//console.log("Couldn't find item with name ", queryName)
|
||||||
}
|
}
|
||||||
@@ -1194,12 +1205,12 @@ const Dashboard = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (usecases.length > 0) {
|
if (usecases.length > 0) {
|
||||||
console.log(usecases)
|
//console.log(usecases)
|
||||||
checkSelectedParams()
|
checkSelectedParams()
|
||||||
}
|
}
|
||||||
}, [usecases])
|
}, [usecases])
|
||||||
|
|
||||||
const getFramework = () => {
|
const getFramework = () => {
|
||||||
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -1216,20 +1227,29 @@ const Dashboard = (props) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
if (responseJson.reason !== undefined) {
|
const preparedData = {
|
||||||
//toast("Failed loading: " + responseJson.reason)
|
"siem": findSpecificApp({}, "SIEM"),
|
||||||
} else {
|
"communication": findSpecificApp({}, "COMMUNICATION"),
|
||||||
//toast("Failed to load framework for your org.")
|
"assets": findSpecificApp({}, "ASSETS"),
|
||||||
}
|
"cases": findSpecificApp({}, "CASES"),
|
||||||
} else {
|
"network": findSpecificApp({}, "NETWORK"),
|
||||||
setFrameworkData(responseJson)
|
"intel": findSpecificApp({}, "INTEL"),
|
||||||
|
"edr": findSpecificApp({}, "EDR"),
|
||||||
|
"iam": findSpecificApp({}, "IAM"),
|
||||||
|
"email": findSpecificApp({}, "EMAIL"),
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
console.log("Got error for framework! ", preparedData)
|
||||||
|
setFrameworkData(preparedData)
|
||||||
|
} else {
|
||||||
|
setFrameworkData(responseJson)
|
||||||
|
}
|
||||||
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast(error.toString());
|
toast(error.toString());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAvailableWorkflows = () => {
|
const getAvailableWorkflows = () => {
|
||||||
fetch(globalUrl + "/api/v1/workflows", {
|
fetch(globalUrl + "/api/v1/workflows", {
|
||||||
@@ -1659,6 +1679,7 @@ const Dashboard = (props) => {
|
|||||||
: null}
|
: null}
|
||||||
|
|
||||||
<UsecaseListComponent
|
<UsecaseListComponent
|
||||||
|
userdata={userdata}
|
||||||
isLoggedIn={isLoggedIn}
|
isLoggedIn={isLoggedIn}
|
||||||
frameworkData={frameworkData}
|
frameworkData={frameworkData}
|
||||||
keys={selectedUsecases}
|
keys={selectedUsecases}
|
||||||
|
|||||||
@@ -21,20 +21,13 @@ import {
|
|||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
|
|
||||||
const bodyDivStyle = {
|
|
||||||
margin: "auto",
|
|
||||||
maxWidth: 1024,
|
|
||||||
scrollX: "hidden",
|
|
||||||
overflowX: "hidden",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be different if logged in :|
|
// Should be different if logged in :|
|
||||||
const Search = (props) => {
|
const Search = (props) => {
|
||||||
const { globalUrl, isLoaded, serverside, userdata, hidemargins, } = props;
|
const { globalUrl, isLoaded, serverside, userdata, hidemargins, isHeader} = props;
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
const [curTab, setCurTab] = useState(0);
|
const [curTab, setCurTab] = useState(0);
|
||||||
const iconStyle = { marginRight: 10 };
|
const iconStyle = { marginRight: isHeader ? null : 10 };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
|
if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
|
||||||
@@ -58,15 +51,23 @@ const Search = (props) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bodyDivStyle = {
|
||||||
|
margin: "auto",
|
||||||
|
maxWidth: 1024,
|
||||||
|
scrollX: "hidden",
|
||||||
|
overflowX: "hidden",
|
||||||
|
justifyContent: isHeader ? "center" : null,
|
||||||
|
}
|
||||||
|
|
||||||
const boxStyle = {
|
const boxStyle = {
|
||||||
color: "white",
|
color: "white",
|
||||||
flex: "1",
|
flex: "1",
|
||||||
marginLeft: 10,
|
marginLeft: isHeader ? null : 10,
|
||||||
marginRight: 10,
|
marginRight: isHeader ? null : 10,
|
||||||
paddingLeft: 30,
|
paddingLeft: isHeader ? null : 30,
|
||||||
paddingRight: 30,
|
paddingRight: isHeader ? null : 30,
|
||||||
paddingBottom: 30,
|
paddingBottom: isHeader ? null : 30,
|
||||||
paddingTop: hidemargins === true ? 0 : 30,
|
paddingTop: hidemargins === true ? 0 : isHeader ? null : 30,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
@@ -121,7 +122,7 @@ const Search = (props) => {
|
|||||||
<div style={{paddingBottom: hidemargins === true ? 0 : 100, color: "white", }}>
|
<div style={{paddingBottom: hidemargins === true ? 0 : 100, color: "white", }}>
|
||||||
<div style={boxStyle}>
|
<div style={boxStyle}>
|
||||||
<Tabs
|
<Tabs
|
||||||
style={{width: 610, margin: "auto", marginTop: hidemargins === true ? 0 : 25, }}
|
style={{width: isHeader ? 765 : 610, margin: isHeader? null :"auto", marginTop: hidemargins === true ? 0 : isHeader ? null : 25, }}
|
||||||
value={curTab}
|
value={curTab}
|
||||||
indicatorColor="primary"
|
indicatorColor="primary"
|
||||||
textColor="secondary"
|
textColor="secondary"
|
||||||
@@ -152,7 +153,7 @@ const Search = (props) => {
|
|||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{curTab === 0 ?
|
{curTab === 0 ?
|
||||||
<AppGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
<AppGrid maxRows={3} isHeader={true} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
:
|
:
|
||||||
curTab === 1 ?
|
curTab === 1 ?
|
||||||
window.location.pathname === "/search" ?
|
window.location.pathname === "/search" ?
|
||||||
@@ -164,7 +165,7 @@ const Search = (props) => {
|
|||||||
<DocsGrid maxRows={6} parsedXs={12} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
<DocsGrid maxRows={6} parsedXs={12} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
:
|
:
|
||||||
curTab === 3 ?
|
curTab === 3 ?
|
||||||
<CreatorGrid parsedXs={4} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
<CreatorGrid parsedXs={4} isHeader={true} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
:
|
:
|
||||||
null}
|
null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import ReactGA from 'react-ga4';
|
import ReactGA from 'react-ga4';
|
||||||
import WelcomeForm2 from "../components/WelcomeForm2.jsx";
|
import WelcomeForm2 from "../components/WelcomeForm2.jsx";
|
||||||
import AppFramework from "../components/AppFramework.jsx";
|
import AppFramework from "../components/AppFramework.jsx";
|
||||||
|
import {isMobile} from "react-device-detect";
|
||||||
import {
|
import {
|
||||||
ArrorForwardIos as ArrowForwardIosIcon,
|
ArrorForwardIos as ArrowForwardIosIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
@@ -47,10 +47,7 @@ const Welcome = (props) => {
|
|||||||
}
|
}
|
||||||
}, [activeStep])
|
}, [activeStep])
|
||||||
|
|
||||||
const isCloud =
|
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||||
window.location.host === "localhost:3002" ||
|
|
||||||
window.location.host === "shuffler.io";
|
|
||||||
|
|
||||||
const [steps, setSteps] = useState([
|
const [steps, setSteps] = useState([
|
||||||
"Help us get to know you",
|
"Help us get to know you",
|
||||||
"Find your Apps",
|
"Find your Apps",
|
||||||
@@ -272,22 +269,22 @@ const Welcome = (props) => {
|
|||||||
getApps()
|
getApps()
|
||||||
getAvailableWorkflows()
|
getAvailableWorkflows()
|
||||||
|
|
||||||
if (
|
if (window.location.search !== undefined && window.location.search !== null) {
|
||||||
window.location.search !== undefined &&
|
|
||||||
window.location.search !== null
|
|
||||||
) {
|
|
||||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
const params = Object.fromEntries(urlSearchParams.entries());
|
const params = Object.fromEntries(urlSearchParams.entries());
|
||||||
const foundTab = params["tab"];
|
const foundTab = params["tab"];
|
||||||
|
|
||||||
|
// Make foundtab into a number
|
||||||
|
console.log("foundTab: ", foundTab, activeStep+1)
|
||||||
if (foundTab !== null && foundTab !== undefined && !isNaN(foundTab) && foundTab >= 1 && foundTab <= 3) {
|
if (foundTab !== null && foundTab !== undefined && !isNaN(foundTab) && foundTab >= 1 && foundTab <= 3) {
|
||||||
|
console.log("SETTING TAB TO: ", foundTab)
|
||||||
|
|
||||||
setShowWelcome(true)
|
setShowWelcome(true)
|
||||||
if (foundTab === 3 || foundTab === "3") {
|
if (foundTab === 3 || foundTab === "3") {
|
||||||
handleSetSearch(usecaseButtons[0].name, usecaseButtons[0].usecase)
|
handleSetSearch(usecaseButtons[0].name, usecaseButtons[0].usecase)
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveStep(foundTab-1)
|
setActiveStep(foundTab-1)
|
||||||
} else {
|
|
||||||
navigate(`/welcome?tab=2`)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
@@ -300,8 +297,8 @@ const Welcome = (props) => {
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
maxWidth: 275,
|
maxWidth: isMobile ? null : 275,
|
||||||
minWidth: 275,
|
minWidth: isMobile ? null : 275,
|
||||||
backgroundColor: theme.palette.surfaceColor,
|
backgroundColor: theme.palette.surfaceColor,
|
||||||
color: "white",
|
color: "white",
|
||||||
borderRadius: theme.palette.borderRadius,
|
borderRadius: theme.palette.borderRadius,
|
||||||
@@ -326,7 +323,7 @@ const Welcome = (props) => {
|
|||||||
const buttonStyle = {
|
const buttonStyle = {
|
||||||
borderRadius: 200,
|
borderRadius: 200,
|
||||||
height: 51,
|
height: 51,
|
||||||
width: 464,
|
width: isMobile ? 300 : 464,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
// background: "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)",
|
// background: "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)",
|
||||||
background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)",
|
background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)",
|
||||||
@@ -334,7 +331,7 @@ const Welcome = (props) => {
|
|||||||
top: 105,
|
top: 105,
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
itemAlign: "center",
|
itemAlign: "center",
|
||||||
marginLeft: "65px",
|
marginLeft: isMobile? null : "65px",
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultImage = "/images/experienced.png"
|
const defaultImage = "/images/experienced.png"
|
||||||
@@ -382,7 +379,7 @@ const Welcome = (props) => {
|
|||||||
})}
|
})}
|
||||||
</Stepper>
|
</Stepper>
|
||||||
</div> */}
|
</div> */}
|
||||||
<Grid container spacing={1} style={{ padding: 0, maxWidth: 500, minWidth: 500, marginRight : "auto" , marginLeft: "auto" }}>
|
<Grid container spacing={1} style={{ padding: isMobile ? 10 : 0, maxWidth: isMobile ? null : 500, minWidth: isMobile ? null : 500, marginRight : "auto" , marginLeft: "auto" }}>
|
||||||
<Grid item xs={window.location.href.includes("tab=2") ? 6 : 12}>
|
<Grid item xs={window.location.href.includes("tab=2") ? 6 : 12}>
|
||||||
<div>
|
<div>
|
||||||
{/*
|
{/*
|
||||||
@@ -394,6 +391,7 @@ const Welcome = (props) => {
|
|||||||
/>
|
/>
|
||||||
*/}
|
*/}
|
||||||
<WelcomeForm2
|
<WelcomeForm2
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
checkLogin={checkLogin}
|
checkLogin={checkLogin}
|
||||||
userdata={userdata}
|
userdata={userdata}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
@@ -417,49 +415,11 @@ const Welcome = (props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/* {frameworkData === undefined || window.location.href.includes("tab=1") || window.location.href.includes("tab=3") ? null :
|
|
||||||
<div style={{marginTop: 25, }}>
|
|
||||||
<Typography variant="h6" style={{textAlign: "center", marginBottom: 25, }}>
|
|
||||||
App Framework
|
|
||||||
</Typography>
|
|
||||||
<Fade>
|
|
||||||
<AppFramework
|
|
||||||
inputUsecase={inputUsecase}
|
|
||||||
frameworkData={frameworkData}
|
|
||||||
setFrameworkData={setFrameworkData}
|
|
||||||
selectedOption={"Draw"}
|
|
||||||
showOptions={false}
|
|
||||||
isLoaded={true}
|
|
||||||
isLoggedIn={true}
|
|
||||||
globalUrl={globalUrl}
|
|
||||||
size={0.78}
|
|
||||||
color={theme.palette.backgroundColor}
|
|
||||||
discoveryWrapper={discoveryWrapper}
|
|
||||||
setDiscoveryWrapper={setDiscoveryWrapper}
|
|
||||||
apps={apps}
|
|
||||||
inputUsecases={usecases}
|
|
||||||
setInputUsecases={setUsecases}
|
|
||||||
/>
|
|
||||||
</Fade>
|
|
||||||
</div>
|
|
||||||
} */}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<Fade in={true}>
|
<Fade in={true}>
|
||||||
<div style={{maxWidth: 590, margin: "auto", marginTop: 50, }}>
|
<div style={{maxWidth: isMobile ? null : 590, margin: "auto", marginTop: 50, }}>
|
||||||
|
|
||||||
{/* <div style={{display:"flex"}}>
|
|
||||||
<ArrowBackIosIcon style={{color: "#9E9E9E", width: "16px",}} onClick={() => {
|
|
||||||
navigate("/workflows")
|
|
||||||
}}/>
|
|
||||||
<Typography variant="h8" style={{color: "#9E9E9E",textAlign: "center", marginBottom: 20, paddingRight: "366px"}} onClick={() => {
|
|
||||||
navigate("/workflows")
|
|
||||||
}}>
|
|
||||||
Back
|
|
||||||
</Typography>
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
<Typography variant="h4" style={{color: "#F1F1F1", marginTop: 50, fontSize: 32}}>
|
<Typography variant="h4" style={{color: "#F1F1F1", marginTop: 50, fontSize: 32}}>
|
||||||
Help us get to know you
|
Help us get to know you
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -469,7 +429,7 @@ const Welcome = (props) => {
|
|||||||
{/* <Typography variant="body1" style={{color: "#9E9E9E", marginTop: 12 ,marginBottom: 50, fontSize: 16}}>
|
{/* <Typography variant="body1" style={{color: "#9E9E9E", marginTop: 12 ,marginBottom: 50, fontSize: 16}}>
|
||||||
We will use this information to personalize your automation
|
We will use this information to personalize your automation
|
||||||
</Typography> */}
|
</Typography> */}
|
||||||
<div style={{display: "flex", marginTop: 70, width: 700, margin: "auto",}}>
|
<div style={{display: isMobile ? null : "flex", marginTop: 70, width: isMobile ? 280 : 700, margin: "auto",}}>
|
||||||
<div style={{border: "2px solid #806BFF", borderRadius: theme.palette.borderRadius, }}>
|
<div style={{border: "2px solid #806BFF", borderRadius: theme.palette.borderRadius, }}>
|
||||||
<Card style={paperObject} onClick={() => {
|
<Card style={paperObject} onClick={() => {
|
||||||
if (isCloud) {
|
if (isCloud) {
|
||||||
@@ -482,6 +442,7 @@ const Welcome = (props) => {
|
|||||||
//setActiveStep(1)
|
//setActiveStep(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
navigate("/welcome?tab=2")
|
||||||
setShowWelcome(true)
|
setShowWelcome(true)
|
||||||
}}>
|
}}>
|
||||||
<CardActionArea style={actionObject}>
|
<CardActionArea style={actionObject}>
|
||||||
@@ -490,12 +451,13 @@ const Welcome = (props) => {
|
|||||||
New to Shuffle
|
New to Shuffle
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" style={{marginTop: 10, color: "rgba(255,255,255,0.8)"}}>
|
<Typography variant="body1" style={{marginTop: 10, color: "rgba(255,255,255,0.8)"}}>
|
||||||
Let us guide you for an easier experience
|
Let us guide you for an easier experience
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardActionArea>
|
</CardActionArea>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div style={{marginLeft: 25, marginRight: 25, }}>
|
<div style={{marginLeft: 25, marginRight: 25,
|
||||||
|
marginTop: isMobile ? 30 : null, }}>
|
||||||
{/* <Typography style={{marginTop: 200, }}>
|
{/* <Typography style={{marginTop: 200, }}>
|
||||||
OR
|
OR
|
||||||
</Typography> */}
|
</Typography> */}
|
||||||
@@ -512,7 +474,7 @@ const Welcome = (props) => {
|
|||||||
navigate("/workflows?message=Skipped intro")
|
navigate("/workflows?message=Skipped intro")
|
||||||
}}>
|
}}>
|
||||||
<CardActionArea style={actionObject}>
|
<CardActionArea style={actionObject}>
|
||||||
<img src={experienced_image} style={{padding: experienced_image === defaultImage ? 2 : 10, objectFit: "scale-down", minHeight: experienced_image === defaultImage ? 40 : 70, maxHeight: experienced_image === defaultImage ? 40 : 70, bordeRadius: theme.palette.borderRadius, marginBottom: experienced_image === defaultImage ? 24 : 2 }} />
|
<img src={experienced_image} style={{padding: experienced_image === defaultImage ? 2 : 10, objectFit: "scale-down", minHeight: experienced_image === defaultImage ? 40 : 70, maxHeight: experienced_image === defaultImage ? 40 : 70, bordeRadius: theme.palette.borderRadius*2, marginBottom: experienced_image === defaultImage ? 24 : 2 }} />
|
||||||
<Typography variant="h4" style={{color: "#F1F1F1"}}>
|
<Typography variant="h4" style={{color: "#F1F1F1"}}>
|
||||||
Experienced
|
Experienced
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -524,10 +486,11 @@ const Welcome = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div style={{ flexDirection: "row", }}>
|
<div style={{ flexDirection: "row", textAlign: isMobile ? "center" : null, margin: isMobile ? "auto" : null }}>
|
||||||
<Button variant="contained" type="submit" fullWidth style={buttonStyle} onClick={() => {
|
<Button variant="contained" type="submit" fullWidth style={buttonStyle} onClick={() => {
|
||||||
navigate(`/welcome?tab=2`)
|
navigate(`/welcome?tab=2`)
|
||||||
setActiveStep(1)
|
setActiveStep(1)
|
||||||
|
setShowWelcome(true)
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
category: "welcome",
|
category: "welcome",
|
||||||
action: "click_welcome_continue",
|
action: "click_welcome_continue",
|
||||||
@@ -537,20 +500,6 @@ const Welcome = (props) => {
|
|||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* <div style={{margin: "auto", borderRadius: theme.palette.borderRadius, marginTop: 50, width: 200, overflow: "wrap", padding: 25, cursor: "pointer", }} onClick={() => {
|
|
||||||
if (window.drift !== undefined) {
|
|
||||||
window.drift.api.startInteraction({ interactionId: 340045 })
|
|
||||||
} else {
|
|
||||||
console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift)
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Typography variant="body1" style={{margin: "auto", textAlign: "center"}}>
|
|
||||||
Want a demo instead?
|
|
||||||
</Typography>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</Fade>
|
</Fade>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -530,6 +530,7 @@ export const validateJson = (showResult) => {
|
|||||||
|
|
||||||
const Workflows = (props) => {
|
const Workflows = (props) => {
|
||||||
const { globalUrl, isLoggedIn, isLoaded, userdata, checkLogin } = props;
|
const { globalUrl, isLoggedIn, isLoaded, userdata, checkLogin } = props;
|
||||||
|
|
||||||
document.title = "Shuffle - Workflows";
|
document.title = "Shuffle - Workflows";
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
@@ -3419,11 +3420,11 @@ const Workflows = (props) => {
|
|||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
style={{
|
style={{
|
||||||
height: imgSize+4,
|
height: isCloud ? imgSize : imgSize+4,
|
||||||
width: imgSize+4,
|
width: isCloud ? imgSize : imgSize+4,
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: -2,
|
top: isCloud ? -1 : -2,
|
||||||
left: -2,
|
left: isCloud ? -1 : -2,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
zIndex: 99,
|
zIndex: 99,
|
||||||
border: "2px solid rgba(255,255,255,0.7)",
|
border: "2px solid rgba(255,255,255,0.7)",
|
||||||
@@ -3488,6 +3489,7 @@ const Workflows = (props) => {
|
|||||||
{foundPriority != null && workflows.length < 6 ?
|
{foundPriority != null && workflows.length < 6 ?
|
||||||
<Priority
|
<Priority
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
|
userdata={userdata}
|
||||||
priority={foundPriority}
|
priority={foundPriority}
|
||||||
checkLogin={checkLogin}
|
checkLogin={checkLogin}
|
||||||
appFramework={appFramework}
|
appFramework={appFramework}
|
||||||
|
|||||||
@@ -406,6 +406,17 @@ func deployServiceWorkers(image string) {
|
|||||||
cnt = 1
|
cnt = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appReplicas := os.Getenv("SHUFFLE_APP_REPLICAS")
|
||||||
|
appReplicaCnt := 1
|
||||||
|
if len(appReplicas) > 0 {
|
||||||
|
newCnt, err := strconv.Atoi(appReplicas)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] %s is not a valid number for SHUFFLE_APP_REPLICAS", appReplicas)
|
||||||
|
} else {
|
||||||
|
appReplicaCnt = newCnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] Found %d node(s) to replicate over. Defaulting to 1 IF we can't auto-discover them.", cnt)
|
log.Printf("[DEBUG] Found %d node(s) to replicate over. Defaulting to 1 IF we can't auto-discover them.", cnt)
|
||||||
replicatedJobs := uint64(replicas * nodeCount)
|
replicatedJobs := uint64(replicas * nodeCount)
|
||||||
|
|
||||||
@@ -462,8 +473,7 @@ func deployServiceWorkers(image string) {
|
|||||||
Env: []string{
|
Env: []string{
|
||||||
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
|
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
|
||||||
fmt.Sprintf("SHUFFLE_SWARM_NETWORK_NAME=%s", networkName),
|
fmt.Sprintf("SHUFFLE_SWARM_NETWORK_NAME=%s", networkName),
|
||||||
fmt.Sprintf("SHUFFLE_APP_REPLICAS=%d", cnt),
|
fmt.Sprintf("SHUFFLE_APP_REPLICAS=%d", appReplicaCnt),
|
||||||
fmt.Sprintf("TZ=%s", timezone),
|
|
||||||
fmt.Sprintf("SHUFFLE_LOGS_DISABLED=%s", os.Getenv("SHUFFLE_LOGS_DISABLED")),
|
fmt.Sprintf("SHUFFLE_LOGS_DISABLED=%s", os.Getenv("SHUFFLE_LOGS_DISABLED")),
|
||||||
fmt.Sprintf("DEBUG_MEMORY=%s", os.Getenv("DEBUG_MEMORY")),
|
fmt.Sprintf("DEBUG_MEMORY=%s", os.Getenv("DEBUG_MEMORY")),
|
||||||
fmt.Sprintf("SHUFFLE_APP_SDK_TIMEOUT=%s", os.Getenv("SHUFFLE_APP_SDK_TIMEOUT")),
|
fmt.Sprintf("SHUFFLE_APP_SDK_TIMEOUT=%s", os.Getenv("SHUFFLE_APP_SDK_TIMEOUT")),
|
||||||
@@ -1411,6 +1421,7 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//defer newresp.Body.Close()
|
||||||
if newresp.StatusCode == 405 {
|
if newresp.StatusCode == 405 {
|
||||||
log.Printf("[WARNING] Received 405 from %s. This is likely due to a misconfigured base URL. Automatically swapping to GET request (backwards compatibility)", fullUrl)
|
log.Printf("[WARNING] Received 405 from %s. This is likely due to a misconfigured base URL. Automatically swapping to GET request (backwards compatibility)", fullUrl)
|
||||||
|
|
||||||
@@ -1555,6 +1566,14 @@ func main() {
|
|||||||
env = append(env, fmt.Sprintf("SHUFFLE_CLOUDRUN_URL=%s", os.Getenv("SHUFFLE_CLOUDRUN_URL")))
|
env = append(env, fmt.Sprintf("SHUFFLE_CLOUDRUN_URL=%s", os.Getenv("SHUFFLE_CLOUDRUN_URL")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(os.Getenv("SHUFFLE_SKIPSSL_VERIFY")) > 0 {
|
||||||
|
env = append(env, fmt.Sprintf("SHUFFLE_SKIPSSL_VERIFY=%s", os.Getenv("SHUFFLE_SKIPSSL_VERIFY")))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(os.Getenv("SHUFFLE_DEBUG_MEMORY")) > 0 {
|
||||||
|
env = append(env, fmt.Sprintf("SHUFFLE_DEBUG_MEMORY=%s", os.Getenv("SHUFFLE_DEBUG_MEMORY")))
|
||||||
|
}
|
||||||
|
|
||||||
err = deployWorker(workerImage, containerName, env, execution)
|
err = deployWorker(workerImage, containerName, env, execution)
|
||||||
zombiecounter += 1
|
zombiecounter += 1
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -1612,6 +1631,7 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer resultResp.Body.Close()
|
||||||
body, err := ioutil.ReadAll(resultResp.Body)
|
body, err := ioutil.ReadAll(resultResp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed reading confirm body: %s", err)
|
log.Printf("[ERROR] Failed reading confirm body: %s", err)
|
||||||
@@ -1906,6 +1926,7 @@ func sendWorkerRequest(workflowExecution shuffle.ExecutionRequest) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer newresp.Body.Close()
|
||||||
body, err := ioutil.ReadAll(newresp.Body)
|
body, err := ioutil.ReadAll(newresp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed reading body in worker request body to worker on %s: %s", streamUrl, err)
|
log.Printf("[ERROR] Failed reading body in worker request body to worker on %s: %s", streamUrl, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user