A tons of minor fixes for the onboarding flow and search systems

This commit is contained in:
Frikky
2023-11-06 08:32:58 +01:00
parent 492c3c3258
commit cf4aa71f80
18 changed files with 799 additions and 367 deletions
+1 -1
View File
@@ -64,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"]
} }
+2 -2
View File
@@ -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,
+156 -3
View File
@@ -3,7 +3,7 @@ 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';
@@ -33,16 +33,37 @@ import {
ListItem, ListItem,
ListItemAvatar, ListItemAvatar,
ListItemText, ListItemText,
IconButton,
} from '@mui/material'; } from '@mui/material';
const AppSearchButtons = (props) => { const AppSearchButtons = (props) => {
const { userdata, globalUrl, appFramework, finishedApps, appType, totalApps, index, 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()
let navigate = useNavigate(); let navigate = useNavigate();
const [isHover, setIsHover] = useState(false); const [isHover, setIsHover] = useState(false);
const [localSearchOpen, setLocalSearchOpen] = 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) { if (appType === undefined) {
console.log("Apptype is required in AppSearchButtons") console.log("Apptype is required in AppSearchButtons")
@@ -63,10 +84,54 @@ const AppSearchButtons = (props) => {
const foundApp = findSpecificApp(appFramework, appType) const foundApp = findSpecificApp(appFramework, appType)
if (foundApp === undefined || foundApp === null) { if (foundApp === undefined || foundApp === null) {
console.log("AppSearchButtons: App not found in appFramework") console.log("AppSearchButtons: App not found in appFramework: " + appType)
return null 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 icon = foundApp.large_image const icon = foundApp.large_image
let xsValue = 12; let xsValue = 12;
if (index !== undefined && index !== 0) { if (index !== undefined && index !== 0) {
@@ -86,6 +151,94 @@ const AppSearchButtons = (props) => {
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
> >
{localSearchOpen ? (
<div
style={{
width: 319,
height: 395,
flexShrink: 0,
marginLeft: 70,
marginTop: 68,
position: "absolute",
zIndex: 100,
borderRadius: 6,
border: "1px solid var(--Container-Stroke, #494949)",
background: "var(--Container, #212121)",
boxShadow: "8px 8px 32px 24px rgba(0, 0, 0, 0.16)",
}}
>
<div style={{ display: "flex" }}>
<div style={{ display: "flex", textAlign: "center", textTransform: "capitalize" }}>
<Typography style={{ padding: 16, color: "#FFFFFF", textTransform: "capitalize" }}> {discoveryData} </Typography>
</div>
<div style={{ display: "flex" }}>
<Tooltip
title="Close"
placement="top"
style={{ zIndex: 10011 }}
>
<IconButton
style={{
flex: 1,
// width: 224,
marginLeft: discoveryData === ("communication") ? 112 : 200,
width: "100%",
marginBottom: 23,
fontSize: 16,
background: "rgba(33, 33, 33, 1)",
borderColor: "rgba(33, 33, 33, 1)",
borderRadius: 8,
}}
onClick={() => {
setLocalSearchOpen(false)
}}
>
<Closeicon style={{ width: 16 }} />
</IconButton>
</Tooltip>
<Tooltip
title="Delete app"
placement="bottom"
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>
<div
style={{ width: "100%", border: "1px #494949 solid" }}
/>
<AppSearch
defaultSearch={appType}
userdata={userdata}
newSelectedApp={newSelectedApp}
setNewSelectedApp={setNewSelectedApp}
/>
</div>
) : null}
<div style={{ display: "flex", height: 70, border: isHover ? "1px solid #f85a3e" : "var(--Container, #212121)", borderRadius: 8, background: isHover ? "var(--Container, #212121)":"var(--Container, #212121)", <div style={{ display: "flex", height: 70, border: isHover ? "1px solid #f85a3e" : "var(--Container, #212121)", borderRadius: 8, background: isHover ? "var(--Container, #212121)":"var(--Container, #212121)",
alignItems: "center", justifyContent: "center",}} alignItems: "center", justifyContent: "center",}}
> >
+166 -140
View File
@@ -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';
@@ -60,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)
@@ -157,9 +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",
@@ -168,116 +276,16 @@ const AppSelection = props => {
}); });
} }
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(() => {
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]);
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(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(lastApps["network"])
tempApps.push(lastApps["assets"])
tempApps.push(lastApps["iam"])
}
setAppButtons(tempApps)
console.log("Updated appButtons: ", appButtons)
GetApps()
}
}, [lastPosted, moreButton])
// const sizing = moreButton ? 510 : 480; // const sizing = moreButton ? 510 : 480;
const buttonWidth = 450; const buttonWidth = 450;
@@ -286,7 +294,7 @@ const AppSelection = props => {
borderRadius: 200, borderRadius: 200,
marginTop: moreButton ? 44 : "", marginTop: moreButton ? 44 : "",
height: 51, height: 51,
width: 500, width: isMobile ? 250 : 500,
fontSize: 16, fontSize: 16,
background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)", background: "linear-gradient(90deg, #F86744 0%, #F34475 100%)",
padding: "16px 24px", padding: "16px 24px",
@@ -301,14 +309,15 @@ const AppSelection = props => {
// minHeight: sizing, // minHeight: sizing,
// maxHeight: sizing, // maxHeight: sizing,
marginTop: 10, marginTop: 10,
width: 500, width: isMobile ? 380 : 500,
marginBottom: 25 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,
@@ -398,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,
}} }}
@@ -419,42 +428,59 @@ const AppSelection = props => {
Select the apps you work with and we will connect the for you. Select the apps you work with and we will connect the for you.
</Typography> </Typography>
<Grid rowSpacing={1} columnSpacing={2} container > <Grid rowSpacing={1} columnSpacing={2} container >
{appButtons.map((appData, index) => { {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
<AppSearchButtons const AppImage = appData.large_image
appFramework={appFramework} const appType = appData.type
index={index}
totalApps={appButtons.length} return (
appName={appName} <AppSearchButtons
appType={appType} appFramework={appFramework}
AppImage={AppImage} index={index}
defaultSearch={defaultSearch} totalApps={appButtons.length}
finishedApps={finishedApps} appName={appName}
onNodeSelect={onNodeSelect} appType={appType}
discoveryData={discoveryData} AppImage={AppImage}
setDiscoveryData={setDiscoveryData} defaultSearch={defaultSearch}
setDefaultSearch={setDefaultSearch} finishedApps={finishedApps}
apps={apps} onNodeSelect={onNodeSelect}
setMoreButton={setMoreButton} discoveryData={discoveryData}
moreButton={moreButton} setDiscoveryData={setDiscoveryData}
/> setDefaultSearch={setDefaultSearch}
) apps={apps}
})} setMoreButton={setMoreButton}
moreButton={moreButton}
/>
)
})}
</Grid> </Grid>
</div> </div>
{!moreButton ? ( {!moreButton ? (
<div style={{width: "100%", marginLeft: 200, marginBottom: 20}}> <div style={{width: "100%", marginLeft: isMobile ? 100 : 200, marginBottom: 20, textAlign: isMobile ? "center" : null}}>
<Link style={{color:"#FF8444"}} onClick={()=>{ <Link style={{color:"#FF8444"}} onClick={()=>{
setMoreButton(true) setMoreButton(true)
setTimeout(() => {
navigate("/welcome?tab=2")
}, 250)
}} }}
>See More Apps</Link> >See More Apps</Link>
</div>): ""} </div>): ""}
<div style={{ flexDirection: "row", }}> <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)
+2 -27
View File
@@ -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>
+218 -15
View File
@@ -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: 650,
padding: 30,
maxHeight: 600,
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">Sign EULA</DialogTitle>
<DialogContent>
<TextField
rows={13}
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}
/> />
) )
}) })
+2 -2
View File
@@ -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,}}>
+9 -5
View File
@@ -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>
+39
View File
@@ -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}
/> />
) )
}) })
+22 -9
View File
@@ -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>
+6 -23
View File
@@ -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">
@@ -4,6 +4,7 @@ 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 AppSearchButtons from "../components/AppSearchButtons.jsx";
import { isMobile } from "react-device-detect";
import { import {
Button, Button,
Typography, Typography,
@@ -27,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, appFramework, globalUrl, img1, srcapp, img2, dstapp, title, description, visualOnly, apps, isLoggedIn } = 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);
@@ -40,14 +41,18 @@ const WorkflowTemplatePopup = (props) => {
const [missingSource, setMissingSource] = React.useState(undefined) const [missingSource, setMissingSource] = React.useState(undefined)
const [missingDestination, setMissingDestination] = 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",
} }
@@ -56,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",
} }
@@ -65,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",
@@ -168,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
@@ -183,15 +189,13 @@ const WorkflowTemplatePopup = (props) => {
if (srcapp.includes(":default")) { if (srcapp.includes(":default")) {
setMissingSource({ setMissingSource({
"img": "https://shuffler.io/images/apps/" + srcapp + ".png",
"type": srcapp.split(":")[0], "type": srcapp.split(":")[0],
}) })
} }
if (dstapp.includes(":default")) { if (dstapp.includes(":default")) {
setMissingDestination({ setMissingDestination({
"name": dstapp, "type": dstapp.split(":")[0],
"img": "https://shuffler.io/images/apps/" + dstapp + ".png",
}) })
} }
@@ -200,7 +204,6 @@ const WorkflowTemplatePopup = (props) => {
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
@@ -228,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.")
@@ -290,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",
}, },
}} }}
@@ -311,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, }}>
@@ -343,16 +352,41 @@ const WorkflowTemplatePopup = (props) => {
</Typography> </Typography>
</div> </div>
} }
{!isLoggedIn || missingSource === undefined ? null :
<div style={{marginTop: 75, }}> {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 <AppSearchButtons
globalUrl={globalUrl}
appFramework={appFramework} appFramework={appFramework}
appType={missingSource.type} appType={missingSource.type}
appImage={missingSource.image} appImage={missingSource.image}
setMissing={setMissingSource}
/> />
</div> </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}
@@ -383,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",
@@ -465,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>
+47 -4
View File
@@ -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", "pov", "demo done", "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} />
@@ -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>
); );
})} })}
+4 -1
View File
@@ -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) {
+21 -21
View File
@@ -170,9 +170,6 @@ const UsecaseListComponent = (props) => {
//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
@@ -192,9 +189,9 @@ const UsecaseListComponent = (props) => {
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",
@@ -212,12 +209,13 @@ const UsecaseListComponent = (props) => {
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
@@ -417,7 +415,7 @@ const UsecaseListComponent = (props) => {
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) {
@@ -887,21 +885,23 @@ const UsecaseListComponent = (props) => {
> >
Try it out: Try it out:
</Typography> </Typography>
<WorkflowTemplatePopup {frameworkData !== undefined && frameworkData !== null && Object.keys(frameworkData).length > 0 ?
isLoggedIn={isLoggedIn} <WorkflowTemplatePopup
appFramework={frameworkData} isLoggedIn={isLoggedIn}
userdata={userdata} 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>
{/* {/*
+19 -18
View File
@@ -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>
+21 -69
View File
@@ -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';
@@ -269,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`)
} }
} }
}, []) }, [])
@@ -297,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,
@@ -323,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%)",
@@ -331,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"
@@ -379,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>
{/* {/*
@@ -391,6 +391,7 @@ const Welcome = (props) => {
/> />
*/} */}
<WelcomeForm2 <WelcomeForm2
isLoggedIn={isLoggedIn}
checkLogin={checkLogin} checkLogin={checkLogin}
userdata={userdata} userdata={userdata}
globalUrl={globalUrl} globalUrl={globalUrl}
@@ -414,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>
@@ -466,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) {
@@ -479,6 +442,7 @@ const Welcome = (props) => {
//setActiveStep(1) //setActiveStep(1)
} }
navigate("/welcome?tab=2")
setShowWelcome(true) setShowWelcome(true)
}}> }}>
<CardActionArea style={actionObject}> <CardActionArea style={actionObject}>
@@ -487,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> */}
@@ -521,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",
@@ -534,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>
} }
+3
View File
@@ -1410,6 +1410,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)
@@ -1619,6 +1620,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)
@@ -1913,6 +1915,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)