This commit is contained in:
Frikky
2024-12-20 21:56:33 +02:00
parent 75fdbb4ffc
commit 376a6d5173
18 changed files with 1867 additions and 926 deletions
+42 -22
View File
@@ -57,7 +57,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
: hover : hover
? "" ? ""
: "1px solid rgba(255,255,255,0.3)", : "1px solid rgba(255,255,255,0.3)",
borderImage: makeFancy ? "linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1" : "none", borderImage: makeFancy ? "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1" : "none",
transition: 'all 0.2s ease-in-out', transition: 'all 0.2s ease-in-out',
} }
@@ -340,7 +340,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
const circularLoader = validation ? <CircularProgress color="primary" /> : null const circularLoader = validation ? <CircularProgress color="primary" /> : null
const errorText = openApiError?.length > 0 ? <div style={{ marginTop: 10 }}>Error: {openApiError}</div> : null const errorText = openApiError?.length > 0 ? <div style={{ marginTop: 15, color: '#fd4c62' }}>Error: {openApiError}</div> : null
// Common dialog styles // Common dialog styles
const dialogStyle = { const dialogStyle = {
@@ -400,7 +400,13 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
Create New App Create New App
</Typography> </Typography>
<IconButton <IconButton
onClick={onClose} onClick={() => {
setOpenApi("")
setOpenApiError("")
setAppValidation("")
setValidation(false)
onClose()
}}
sx={{ sx={{
color: 'rgba(255, 255, 255, 0.7)', color: 'rgba(255, 255, 255, 0.7)',
'&:hover': { bgcolor: 'rgba(255, 255, 255, 0.1)' } '&:hover': { bgcolor: 'rgba(255, 255, 255, 0.1)' }
@@ -477,7 +483,14 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
Create New App from Open API or Swagger Create New App from Open API or Swagger
</Typography> </Typography>
<IconButton <IconButton
onClick={() => setOpenApiModal(false)} onClick={() => {
setOpenApiModal(false)
setGenerateAppModal(false)
setOpenApi("")
setOpenApiError("")
setAppValidation("")
setValidation(false)
}}
sx={{ sx={{
color: 'rgba(255,255,255,0.7)', color: 'rgba(255,255,255,0.7)',
'&:hover': { bgcolor: 'rgba(255,255,255,0.1)' } '&:hover': { bgcolor: 'rgba(255,255,255,0.1)' }
@@ -487,14 +500,16 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
</IconButton> </IconButton>
</DialogTitle> </DialogTitle>
<DialogContent sx={{ px: 4, py: 3 }}> <DialogContent sx={{ px: 4, py: 3 }}>
<div style={{ display: "flex", fontSize: '14px', gap: '5px', alignItems: 'center', marginBottom: '10px', fontFamily: theme?.typography?.fontFamily }}> <div style={{ display: "flex", fontSize: '14px', gap: '5px', alignItems: 'center', marginBottom: '10px', fontFamily: theme?.typography?.fontFamily, marginTop: '15px' }}>
<Typography sx={{ color: 'rgba(255,255,255,0.85)', fontSize: '14px' }}> <Typography sx={{ color: 'rgba(255,255,255,0.85)', fontSize: '16px' }}>
Paste in the URI for the OpenAPI or find out Paste in the URI for the OpenAPI or find out
</Typography> </Typography>
<Link style={{ <Link style={{
color: '#ff8544', color: '#ff8544',
textDecoration: 'none', textDecoration: 'none',
textDecoration: 'underline', textDecoration: 'underline',
fontSize: '16px',
fontFamily: theme?.typography?.fontFamily
}}> }}>
How to find URI for openAPI? How to find URI for openAPI?
</Link> </Link>
@@ -506,12 +521,13 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
fullWidth fullWidth
variant="outlined" variant="outlined"
placeholder="Open API URI" placeholder="Open API URI"
style={{ fontFamily: theme?.typography?.fontFamily, fontSize: '16px' }}
sx={{ sx={{
'& .MuiOutlinedInput-root': { '& .MuiOutlinedInput-root': {
height: '40px' height: '40px',
}, },
'& .MuiOutlinedInput-input::placeholder': { '& .MuiOutlinedInput-input::placeholder': {
fontSize: '14px' fontSize: '16px'
} }
}} }}
onChange={(e) => setOpenApi(e.target.value)} onChange={(e) => setOpenApi(e.target.value)}
@@ -526,7 +542,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
px: 3, px: 3,
textTransform: 'none', textTransform: 'none',
height: '40px', height: '40px',
fontSize: '14px', fontSize: '16px',
fontFamily: theme?.typography?.fontFamily, fontFamily: theme?.typography?.fontFamily,
cursor: 'pointer' cursor: 'pointer'
}} }}
@@ -562,7 +578,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
sx={{ sx={{
color: '#FF8544', color: '#FF8544',
borderColor: '#FF8544', borderColor: '#FF8544',
px: 3, px: 5,
py: 1, py: 1,
'&:hover': { '&:hover': {
borderColor: '#FF8544', borderColor: '#FF8544',
@@ -570,7 +586,8 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
}, },
textTransform: 'none', textTransform: 'none',
fontSize: '14px', fontSize: '14px',
fontFamily: theme?.typography?.fontFamily fontFamily: theme?.typography?.fontFamily,
height: '40px'
}} }}
> >
Upload Upload
@@ -605,7 +622,8 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
}, },
textTransform: 'none', textTransform: 'none',
py: 1.5, py: 1.5,
fontSize: '14px', mb: 1.5,
fontSize: '16px',
fontWeight: 500, fontWeight: 500,
width: '100%', width: '100%',
maxWidth: '300px', maxWidth: '300px',
@@ -648,7 +666,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
<Typography variant="h6" sx={{ <Typography variant="h6" sx={{
color: '#F1F1F1', color: '#F1F1F1',
fontWeight: 500, fontWeight: 500,
fontFamily: theme?.typography?.fontFamily fontFamily: theme?.typography?.fontFamily,
}}> }}>
Generate an app based on documentation (beta) Generate an app based on documentation (beta)
</Typography> </Typography>
@@ -656,6 +674,10 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
onClick={() => { onClick={() => {
setGenerateAppModal(false) setGenerateAppModal(false)
setOpenApiModal(false) setOpenApiModal(false)
setOpenApi("")
setOpenApiError("")
setAppValidation("")
setValidation(false)
}} }}
sx={{ sx={{
color: 'rgba(255,255,255,0.7)', color: 'rgba(255,255,255,0.7)',
@@ -668,9 +690,9 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
<DialogContent sx={{ px: 4, py: 3, pt: 0 }}> <DialogContent sx={{ px: 4, py: 3, pt: 0 }}>
<Typography sx={{ <Typography sx={{
color: 'rgba(255,255,255,0.85)', color: 'rgba(255,255,255,0.85)',
mb: 3, mb: 2,
fontSize: '14px', fontSize: '14px',
mt:4, mt: 2,
fontFamily: theme?.typography?.fontFamily fontFamily: theme?.typography?.fontFamily
}}> }}>
Paste in a URL, and we will make it into an app for you. Paste in a URL, and we will make it into an app for you.
@@ -689,18 +711,15 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
color: 'white', color: 'white',
'& fieldset': { '& fieldset': {
borderWidth: '1px', borderWidth: '1px',
borderImage: 'linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1', borderImage: "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1",
borderImageSlice: 1,
}, },
'&:hover fieldset': { '&:hover fieldset': {
borderWidth: '1px', borderWidth: '1px',
borderImage: 'linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1', borderImage: "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1",
borderImageSlice: 1,
}, },
'&.Mui-focused fieldset': { '&.Mui-focused fieldset': {
borderWidth: '2px', borderWidth: '2px',
borderImage: 'linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1', borderImage: "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1",
borderImageSlice: 1,
} }
}, },
'& .MuiOutlinedInput-input::placeholder': { '& .MuiOutlinedInput-input::placeholder': {
@@ -727,6 +746,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
</DialogContent> </DialogContent>
<DialogActions sx={{ <DialogActions sx={{
py: 2, py: 2,
pt: 1,
px: 3, px: 3,
gap: 2, gap: 2,
display: 'flex', display: 'flex',
@@ -736,7 +756,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => {
{circularLoader} {circularLoader}
{ {
!validation && !validation &&
<Typography sx={{ color: 'rgba(255,255,255,0.85)', fontSize: '14px', fontFamily: theme?.typography?.fontFamily, pt: 2 }}> <Typography sx={{ color: '#c5c5c5', fontSize: '14px', fontFamily: theme?.typography?.fontFamily, }}>
This may take multiple minutes based on the size of the documentation. This may take multiple minutes based on the size of the documentation.
</Typography> </Typography>
} }
+20 -23
View File
@@ -22,8 +22,8 @@ import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import LaunchIcon from '@mui/icons-material/Launch'; import LaunchIcon from '@mui/icons-material/Launch';
import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import { CloudDownloadOutlined } from '@mui/icons-material'; import { CloudDownloadOutlined } from '@mui/icons-material';
import { findSpecificApp } from './AppFramework'; import { findSpecificApp } from '../components/AppFramework.jsx';
import theme from "../theme"; import theme from "../theme.jsx";
import YAML from 'yaml'; import YAML from 'yaml';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@@ -433,7 +433,7 @@ const AppModal = ({ open, onClose, app, globalUrl }) => {
fontFamily: theme?.typography?.fontFamily fontFamily: theme?.typography?.fontFamily
}} }}
> >
<Typography component="div" sx={{ fontWeight: 500, color: "#F1F1F1", fontSize: "22px" }}> <Typography component="div" sx={{ fontWeight: 500, color: "#F1F1F1", fontSize: "20px" }}>
About {app?.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())} About {app?.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())}
</Typography> </Typography>
<IconButton <IconButton
@@ -464,31 +464,28 @@ const AppModal = ({ open, onClose, app, globalUrl }) => {
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.2)" boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.2)"
}} }}
/> />
<div style={{ display: "flex", flexDirection: "column", justifyContent: "center", paddingLeft: 8 }}> <div style={{ display: "flex", flexDirection: "column", justifyContent: "center", paddingLeft: 8, }}>
<div style={{ <div style={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
alignItems: "center",
}}> }}>
<Typography variant="h5" component="div" sx={{ fontWeight: 600 }}> <Typography variant="h5" component="div" sx={{ fontWeight: 600 }}>
{newAppname} {newAppname}
</Typography> </Typography>
{ <Link
isCloud && ( to={"/apps/" + (app?.id || app?.objectID)}
<Link style={{ textDecoration: "none", color: "#f85a3e", marginTop: "-2px" }}
to={"/apps/" + (app?.id || app?.objectID)} >
style={{ textDecoration: "none", color: "#f85a3e", marginTop: "-2px" }} <IconButton
> style={{
<IconButton color: "#f85a3e",
style={{ fontSize: 16,
color: "#f85a3e", }}
fontSize: 20, >
}} <OpenInNewIcon />
> </IconButton>
<OpenInNewIcon /> </Link>
</IconButton>
</Link>
)
}
</div> </div>
<Typography <Typography
variant="body2" variant="body2"
@@ -547,7 +544,7 @@ const AppModal = ({ open, onClose, app, globalUrl }) => {
if (canEditApp) { if (canEditApp) {
const editUrl = "/apps/edit/" + (app?.id || app?.objectID); const editUrl = "/apps/edit/" + (app?.id || app?.objectID);
navigate(editUrl) navigate(editUrl)
}else{ } else {
const forkUrl = "/apps/new?id=" + (app?.id || app?.objectID); const forkUrl = "/apps/new?id=" + (app?.id || app?.objectID);
navigate(forkUrl) navigate(forkUrl)
} }
@@ -735,7 +732,7 @@ const AppModal = ({ open, onClose, app, globalUrl }) => {
bgcolor: '#FF8544', bgcolor: '#FF8544',
'&:hover': { bgcolor: '#FF8544' }, '&:hover': { bgcolor: '#FF8544' },
textTransform: 'none', textTransform: 'none',
borderRadius: 1, borderRadius: "4px",
py: 1, py: 1,
px: 7, px: 7,
fontSize: "14px", fontSize: "14px",
+6 -4
View File
@@ -466,14 +466,16 @@ const AppSelection = props => {
fontSize: 16, fontSize: 16,
color: "rgba(158, 158, 158, 1)", color: "rgba(158, 158, 158, 1)",
fontFamily: theme?.typography?.fontFamily, fontFamily: theme?.typography?.fontFamily,
lineHeight: "24px"
}} }}
> >
Your organization has no apps yet, select your starting apps here {`${window.location.pathname.includes("my_apps") || window.location.search.includes("my_apps") ? "You have no apps yet, select your starting apps here" : "Your organization has no apps yet, select your starting apps here"}
or discover more apps using the <span or discover more apps using the`}
<span
onClick={() => { onClick={() => {
navigate("/apps2?tab=all_apps") navigate("/apps?tab=all_apps")
}} }}
style={{ color: "#FF8444", fontWeight: "medium", fontSize: 16, cursor:"pointer" }}>App Library</span> style={{ color: "#FF8444", fontWeight: "medium", fontSize: 16, cursor:"pointer", marginLeft: 6 }}>App Library</span>
</span> </span>
</div> </div>
) )
+248 -124
View File
@@ -51,11 +51,13 @@ import BillingStats from "./BillingStats.jsx";
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx" import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import { Context } from "../context/ContextApi.jsx"; import { Context } from "../context/ContextApi.jsx";
import LicencePopup from "./LicencePopup.jsx";
const Billing = memo((props) => { const Billing = memo((props) => {
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props; const { globalUrl, userdata, serverside, billingInfo, stripeKey,isLoaded, selectedOrganization, handleGetOrg, clickedFromOrgTab, removeCookie} = props;
//const alert = useAlert(); //const alert = useAlert();
let navigate = useNavigate(); let navigate = useNavigate();
const [isLoggedIn, setIsLoggedIn] = useState(false)
const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false); const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false);
const [dealList, setDealList] = React.useState([]); const [dealList, setDealList] = React.useState([]);
const [dealName, setDealName] = React.useState(""); const [dealName, setDealName] = React.useState("");
@@ -73,14 +75,17 @@ const Billing = memo((props) => {
const [currentAppRunsInNumber, setCurrentAppRunsInNumber] = useState(0); const [currentAppRunsInNumber, setCurrentAppRunsInNumber] = useState(0);
const [alertThresholds, setAlertThresholds] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.AlertThreshold !== undefined && selectedOrganization.Billing.AlertThreshold !== null ? selectedOrganization.Billing.AlertThreshold : [{ percentage: '', count: '', Email_send: false }]); const [alertThresholds, setAlertThresholds] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.AlertThreshold !== undefined && selectedOrganization.Billing.AlertThreshold !== null ? selectedOrganization.Billing.AlertThreshold : [{ percentage: '', count: '', Email_send: false }]);
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
const [deleteAlertIndex, setDeleteAlertIndex] = useState(-1);
const [deleteAlertVerification, setDeleteAlertVerification] = useState(false); const [deleteAlertVerification, setDeleteAlertVerification] = useState(false);
useEffect(() => { useEffect(() => {
if (userdata.app_execution_limit !== undefined && userdata.app_execution_usage !== undefined) { if (userdata.app_execution_limit !== undefined && userdata.app_execution_usage !== undefined) {
const percentage = (userdata.app_execution_usage / userdata.app_execution_limit) * 100; const percentage = (userdata.app_execution_usage / userdata.app_execution_limit) * 100;
setCurrentAppRunsInPercentage(Math.round(percentage)); setCurrentAppRunsInPercentage(Math.round(percentage));
setCurrentAppRunsInNumber(userdata.app_execution_limit - userdata.app_execution_usage); setCurrentAppRunsInNumber(userdata.app_execution_limit - userdata.app_execution_usage);
} }
if (userdata?.id?.length > 0 && isLoggedIn === false){
setIsLoggedIn(true)
}
}, [userdata]); }, [userdata]);
const [BillingEmail, setBillingEmail] = useState(selectedOrganization?.Billing?.Email); const [BillingEmail, setBillingEmail] = useState(selectedOrganization?.Billing?.Email);
@@ -182,7 +187,8 @@ const Billing = memo((props) => {
const isCloud = const isCloud =
window.location.host === "localhost:3002" || window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io"; window.location.host === "shuffler.io" ||
window.location.host === "sandbox.shuffler.io";
billingInfo.subscription = { billingInfo.subscription = {
"active": true, "active": true,
@@ -419,8 +425,16 @@ const Billing = memo((props) => {
const data = { const data = {
org_id: orgId, org_id: orgId,
email: newBillingEmail, email: newBillingEmail,
name: selectedOrganization.name,
description: selectedOrganization.description,
image: selectedOrganization.image,
defaults: selectedOrganization.defaults,
sso_config: selectedOrganization.sso_config,
mfa_required: selectedOrganization.mfa_required,
billing: { billing: {
email: newBillingEmail, email: newBillingEmail,
AlertThreshold: selectedOrganization?.Billing?.AlertThreshold,
Consultation: selectedOrganization?.Billing?.Consultation,
}, },
}; };
@@ -747,13 +761,21 @@ const Billing = memo((props) => {
open={openChangeEmailBox} open={openChangeEmailBox}
onClose={handleCloseChangeEmailBox} onClose={handleCloseChangeEmailBox}
PaperProps={{ PaperProps={{
style: { sx: {
padding: '20px', borderRadius: theme?.palette?.DialogStyle?.borderRadius,
borderRadius: '8px', border: theme?.palette?.DialogStyle?.border,
maxWidth: '500px', minWidth: '440px',
width: '100%' fontFamily: theme?.typography?.fontFamily,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
zIndex: 1000,
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
} }
}} }}
> >
<DialogTitle style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Change Billing Email</DialogTitle> <DialogTitle style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Change Billing Email</DialogTitle>
<DialogContent> <DialogContent>
@@ -810,7 +832,7 @@ const Billing = memo((props) => {
color="primary" color="primary"
style={{ style={{
marginTop: !userdata.has_card_available ? 20 : 10, marginTop: !userdata.has_card_available ? 20 : 10,
borderRadius: 8, borderRadius: 4,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: userdata.has_card_available ? "#ff8544" : "#1a1a1a", color: userdata.has_card_available ? "#ff8544" : "#1a1a1a",
@@ -843,7 +865,7 @@ const Billing = memo((props) => {
color="primary" color="primary"
style={{ style={{
marginTop: 10, marginTop: 10,
borderRadius: 8, borderRadius: 4,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "#1a1a1a", color: "#1a1a1a",
@@ -933,11 +955,19 @@ const Billing = memo((props) => {
const url = `${globalUrl}/api/v1/orgs/${selectedOrganization.id}`; const url = `${globalUrl}/api/v1/orgs/${selectedOrganization.id}`;
const data = { const data = {
org_id: selectedOrganization.id, org_id: selectedOrganization.id,
name: selectedOrganization.name,
description: selectedOrganization.description,
image: selectedOrganization.image,
defaults: selectedOrganization.defaults,
sso_config: selectedOrganization.sso_config,
mfa_required: selectedOrganization.mfa_required,
Billing: { Billing: {
Consultation: { Consultation: {
hours: String(inputHour), hours: String(inputHour),
minutes: String(inputMinutes), minutes: String(inputMinutes),
}, },
AlertThreshold: selectedOrganization.Billing.AlertThreshold,
email: selectedOrganization.Billing.email,
} }
}; };
@@ -1030,9 +1060,9 @@ const Billing = memo((props) => {
<div style={{ <div style={{
padding: 20, padding: 20,
// maxWidth: 400, // maxWidth: 400,
width: 340, width: "100%",
height: 480, height: 480,
backgroundColor: hovered ? "#2b2b2b" : theme.palette.backgroundColor, backgroundColor: hovered ? "#2b2b2b" : "#1e1e1e",
borderRadius: theme.palette?.borderRadius * 2, borderRadius: theme.palette?.borderRadius * 2,
border: "1px solid rgba(255,255,255,0.3)", border: "1px solid rgba(255,255,255,0.3)",
marginRight: 10, marginRight: 10,
@@ -1123,7 +1153,7 @@ const Billing = memo((props) => {
color="primary" color="primary"
style={{ style={{
marginTop: userdata.support ? 0 : 10, marginTop: userdata.support ? 0 : 10,
borderRadius: 8, borderRadius: 4,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "#1A1A1A", color: "#1A1A1A",
@@ -1142,8 +1172,23 @@ const Billing = memo((props) => {
> >
Buy Buy
</Button> </Button>
<Dialog open={clickOnBuy} onClose={() => { setClickOnBuy(false) }} PaperProps={{style: {backgroundColor: "rgb(26, 26, 26)"}}}> <Dialog open={clickOnBuy} onClose={() => { setClickOnBuy(false) }} PaperProps={{
<Typography variant="body1" style={{ marginTop: 10, textAlign: 'center', padding: 20, fontSize: 18 }}> sx: {
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
border: theme?.palette?.DialogStyle?.border,
minWidth: '440px',
fontFamily: theme?.typography?.fontFamily,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
zIndex: 1000,
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
}
}}>
<Typography variant="body1" style={{ paddingTop: 10, textAlign: 'center', padding: 20, fontSize: 18, backgroundColor: theme?.palette?.DialogStyle?.backgroundColor }}>
You will be taken to Stripe to book professional service hours. You can adjust the number of hours on the left side of the Stripe page. You will be taken to Stripe to book professional service hours. You can adjust the number of hours on the left side of the Stripe page.
</Typography> </Typography>
<DialogContent> <DialogContent>
@@ -1178,10 +1223,9 @@ const Billing = memo((props) => {
color="primary" color="primary"
style={{ style={{
marginTop: userdata.support ? 5 : 10, marginTop: userdata.support ? 5 : 10,
borderRadius: 8, borderRadius: 4,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "#ff8544",
textTransform: 'none', textTransform: 'none',
cursor: getProfessionalServices ? 'pointer' : 'not-allowed', cursor: getProfessionalServices ? 'pointer' : 'not-allowed',
opacity: getProfessionalServices ? 1 : 0.6, opacity: getProfessionalServices ? 1 : 0.6,
@@ -1202,13 +1246,23 @@ const Billing = memo((props) => {
fullWidth fullWidth
style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }} style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
PaperProps={{ PaperProps={{
style: { sx: {
width: 500, borderRadius: theme?.palette?.DialogStyle?.borderRadius,
margin: 0, border: theme?.palette?.DialogStyle?.border,
minWidth: '440px',
fontFamily: theme?.typography?.fontFamily,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
zIndex: 1000,
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
} }
}} }}
> >
<DialogTitle style={{ marginTop: 10, textAlign: 'center', fontWeight: 'bold' }}> <DialogTitle style={{ paddingTop: 10, textAlign: 'center', fontWeight: 'bold' }}>
Upgrade Consultation Plan Upgrade Consultation Plan
</DialogTitle> </DialogTitle>
<DialogContent style={{ padding: '24px', }}> <DialogContent style={{ padding: '24px', }}>
@@ -1244,7 +1298,7 @@ const Billing = memo((props) => {
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
style={{ marginTop: '24px', display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none' }} style={{ marginTop: '24px', borderRadius: 4, color: "#1a1a1a", backgroundColor: "#ff8544",fontSize: 16, display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none' }}
onClick={handleUpgradeConsultation} onClick={handleUpgradeConsultation}
> >
Submit Request for {consultationHours} hours Submit Request for {consultationHours} hours
@@ -1305,8 +1359,8 @@ const Billing = memo((props) => {
padding: 20, padding: 20,
height: 480, height: 480,
// maxWidth: 400, // maxWidth: 400,
width: 340, width: "100%",
backgroundColor: hovered ? "#2b2b2b" : theme.palette.backgroundColor, backgroundColor: hovered ? "#2b2b2b" : "#1e1e1e",
borderRadius: theme.palette?.borderRadius * 2, borderRadius: theme.palette?.borderRadius * 2,
border: "1px solid rgba(255,255,255,0.3)", border: "1px solid rgba(255,255,255,0.3)",
marginRight: 10, marginRight: 10,
@@ -1354,7 +1408,7 @@ const Billing = memo((props) => {
</li> </li>
</ul> </ul>
</div> </div>
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', marginTop: 30, width: 340 }}> <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', marginTop: 30, }}>
<Button <Button
fullWidth fullWidth
disabled={false} disabled={false}
@@ -1362,12 +1416,13 @@ const Billing = memo((props) => {
color="primary" color="primary"
style={{ style={{
marginTop: 10, marginTop: 10,
borderRadius: 8, borderRadius: 4,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "#1A1A1A", color: "#1A1A1A",
textTransform: 'none', textTransform: 'none',
backgroundColor: "#FF8544" backgroundColor: "#FF8544",
width: "100%",
}} }}
onClick={() => { onClick={() => {
if (Cloud) { if (Cloud) {
@@ -1390,12 +1445,11 @@ const Billing = memo((props) => {
color="primary" color="primary"
style={{ style={{
marginTop: 10, marginTop: 10,
borderRadius: 8, borderRadius: 4,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
textTransform: 'none', textTransform: 'none',
color: "#FF8544", width: "100%",
backgroundColor: "#1a1a1a",
}} }}
onClick={() => { onClick={() => {
if (Cloud) { if (Cloud) {
@@ -1417,14 +1471,23 @@ const Billing = memo((props) => {
fullWidth fullWidth
style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }} style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
PaperProps={{ PaperProps={{
style: { sx: {
width: 500, borderRadius: theme?.palette?.DialogStyle?.borderRadius,
margin: 0, border: theme?.palette?.DialogStyle?.border,
backgroundColor: "rgb(26, 26, 26)", minWidth: '440px',
fontFamily: theme?.typography?.fontFamily,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
zIndex: 1000,
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
} }
}} }}
> >
<DialogTitle style={{ marginTop: 10, textAlign: 'center', fontWeight: 'bold' }}> <DialogTitle style={{ paddingTop: 10, textAlign: 'center', fontWeight: 'bold' }}>
Private Training Private Training
</DialogTitle> </DialogTitle>
<DialogContent style={{ padding: '24px', }}> <DialogContent style={{ padding: '24px', }}>
@@ -1460,7 +1523,7 @@ const Billing = memo((props) => {
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
style={{ marginTop: '24px', display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none', color: "#1a1a1a", backgroundColor: "#ff8544" }} style={{ marginTop: '24px', fontSize: 16, display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none', color: "#1a1a1a", backgroundColor: "#ff8544" }}
onClick={handlePrivateTraining} onClick={handlePrivateTraining}
> >
Submit Request Submit Request
@@ -1819,7 +1882,6 @@ const Billing = memo((props) => {
setCurrentIndex(findCurrentIndex ? newAlertThresholds.findIndex(threshold => threshold.Email_send === false) : - 1); setCurrentIndex(findCurrentIndex ? newAlertThresholds.findIndex(threshold => threshold.Email_send === false) : - 1);
toast.info("Alert Threshold deleted successfully. Don't forget to save your changes."); toast.info("Alert Threshold deleted successfully. Don't forget to save your changes.");
}; };
const HandleEditOrgForAlertThreshold = (orgId) => { const HandleEditOrgForAlertThreshold = (orgId) => {
// Use the `some` method to check for invalid counts // Use the `some` method to check for invalid counts
@@ -1840,6 +1902,12 @@ const Billing = memo((props) => {
const data = { const data = {
org_id: orgId, org_id: orgId,
name: selectedOrganization?.name,
description: selectedOrganization?.description,
image: selectedOrganization?.image,
defaults: selectedOrganization?.defaults,
sso_config: selectedOrganization?.sso_config,
mfa_required: selectedOrganization?.mfa_required,
billing: { billing: {
email: BillingEmail, email: BillingEmail,
AlertThreshold: alertThresholds.map(threshold => ({ AlertThreshold: alertThresholds.map(threshold => ({
@@ -1847,6 +1915,7 @@ const Billing = memo((props) => {
percentage: parseInt(threshold.percentage, 10), percentage: parseInt(threshold.percentage, 10),
count: parseInt(threshold.count, 10), count: parseInt(threshold.count, 10),
})), })),
Consultation: selectedOrganization?.billing?.Consultation,
}, },
}; };
@@ -1901,12 +1970,12 @@ const Billing = memo((props) => {
Billing & Licensing Billing & Licensing
</Typography>} </Typography>}
{clickedFromOrgTab ? {clickedFromOrgTab ?
<span style={{ color: "#9E9E9E" }}>{isCloud ? <span style={{ color: "#9E9E9E", fontSize: 16 }}>{isCloud ?
"Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below." "Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below."
: :
"Shuffle is an Open Source automation platform, and no license is required. We do however offer a Scale license with HA guarantees, along with support hours. By buying a license on https://shuffler.io, you can get access to the license immediately, and if Cloud Syncronisation is enabled, the UI in your local instance will also update." "Shuffle is an Open Source automation platform, and no license is required. We do however offer a Scale license with HA guarantees, along with support hours. By buying a license on https://shuffler.io, you can get access to the license immediately, and if Cloud Syncronisation is enabled, the UI in your local instance will also update."
}</span> : }</span> :
<Typography variant="body1" color="textSecondary" style={{ marginTop: 0, marginBottom: 10 }}> <Typography variant="body1" color="textSecondary" style={{ marginTop: 0, marginBottom: 10, fontSize: 16 }}>
{isCloud ? {isCloud ?
"Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below." "Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below."
: :
@@ -1917,19 +1986,19 @@ const Billing = memo((props) => {
{userdata.support === true ? {userdata.support === true ?
<div style={{ marginBottom: 10, marginTop: clickedFromOrgTab ? 16 : null, color: clickedFromOrgTab ? "#F1F1F1" : null }}> <div style={{ marginBottom: 10, marginTop: clickedFromOrgTab ? 16 : null, color: clickedFromOrgTab ? "#F1F1F1" : null }}>
For sales: Create&nbsp; For sales: Create&nbsp;
<a href={"https://docs.google.com/document/d/1N-ZJNn8lWaqiXITrqYcnTt53oXGLNYFEzc5PU-tdAps/copy"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}> <a href={"https://docs.google.com/document/d/1N-ZJNn8lWaqiXITrqYcnTt53oXGLNYFEzc5PU-tdAps/copy"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#FF8444" }}>
EU contract EU contract
</a> </a>
&nbsp;or&nbsp; &nbsp;or&nbsp;
<a href={"https://docs.google.com/document/d/1cF-Cwxt1TcahlLrpl1GH2hFZO4gxppLeYjHW6QB0EzQ/copy"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}> <a href={"https://docs.google.com/document/d/1cF-Cwxt1TcahlLrpl1GH2hFZO4gxppLeYjHW6QB0EzQ/copy"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#FF8444" }}>
NOT EU contract NOT EU contract
</a> </a>
&nbsp; - &nbsp; &nbsp; - &nbsp;
<a href={"https://drive.google.com/drive/folders/1zVvwwkbQXW3p-DJYa0GBDzFo_ZnV_I_5"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}> <a href={"https://drive.google.com/drive/folders/1zVvwwkbQXW3p-DJYa0GBDzFo_ZnV_I_5"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#FF8444" }}>
Google Drive Link Google Drive Link
</a> </a>
&nbsp; - &nbsp; &nbsp; - &nbsp;
<a href={"https://github.com/Shuffle/Shuffle-docs/tree/master/handbook/Sales"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}> <a href={"https://github.com/Shuffle/Shuffle-docs/tree/master/handbook/Sales"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#FF8444" }}>
Sales Process (old) Sales Process (old)
</a> </a>
</div> </div>
@@ -1944,22 +2013,24 @@ const Billing = memo((props) => {
</Typography> </Typography>
: null} : null}
<div style={{ display: "flex", width: clickedFromOrgTab ? 1030 : "auto", overflowX: 'auto', overflowY: 'hidden', scrollbarWidth: 'thin', scrollbarColor: '#494949 #2f2f2f', height: isChildOrg ? 0 : 580 }} > <div style={{ display: "flex", width: clickedFromOrgTab ? "100%" : "auto", overflowX: 'auto', overflowY: 'hidden', scrollbarWidth: 'thin', scrollbarColor: '#494949 #2f2f2f', height: isChildOrg ? 0 : "100%", maxWidth: 860, marginTop: 20}} >
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? isChildOrg ? null : {isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? isChildOrg ? null :
<SubscriptionObject <LicencePopup
index={0} serverside={serverside}
globalUrl={globalUrl} removeCookie={removeCookie}
userdata={userdata} isLoaded={isLoaded}
serverside={serverside} isLoggedIn={isLoggedIn}
billingInfo={billingInfo} globalUrl={globalUrl}
stripeKey={stripeKey} selectedOrganization={selectedOrganization}
selectedOrganization={selectedOrganization} billingInfo={billingInfo}
subscription={billingInfo.subscription} isCloud={isCloud}
highlight={selectedOrganization.subscriptions === undefined || selectedOrganization.subscriptions === null || selectedOrganization.subscriptions.length === 0} userdata={userdata}
stripeKey={stripeKey}
{...props}
/> />
: !isCloud ? : !isCloud ?
<span style={{ display: "flex", }}> <span style={{ display: "flex", }}>
<SubscriptionObject {/* <SubscriptionObject
index={0} index={0}
globalUrl={globalUrl} globalUrl={globalUrl}
userdata={userdata} userdata={userdata}
@@ -1977,8 +2048,22 @@ const Billing = memo((props) => {
], ],
}} }}
highlight={true} highlight={true}
/> */}
<LicencePopup
{...props}
serverside={serverside}
removeCookie={removeCookie}
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
selectedOrganization={selectedOrganization}
billingInfo={billingInfo}
isCloud={isCloud}
userdata={userdata}
stripeKey={stripeKey}
/> />
<SubscriptionObject
{/* <SubscriptionObject
index={1} index={1}
globalUrl={globalUrl} globalUrl={globalUrl}
userdata={userdata} userdata={userdata}
@@ -1996,7 +2081,7 @@ const Billing = memo((props) => {
], ],
}} }}
highlight={false} highlight={false}
/> /> */}
</span> </span>
: null} : null}
@@ -2255,14 +2340,14 @@ const Billing = memo((props) => {
</div> </div>
) : null*/} ) : null*/}
{!isChildOrg && isCloud && ( {!isChildOrg && isCloud && (
<div style={{ display: 'flex', flexDirection: 'column', marginTop: 10 }}> <div style={{ display: 'flex', flexDirection: 'column', marginTop: 50, maxWidth: 860 }}>
<Typography style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}> <Typography style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}>
Professional Services Professional Services
</Typography> </Typography>
<Typography color="textSecondary" style={{fontSize: 16,}}> <Typography color="textSecondary" style={{fontSize: 16,}}>
We offer priority support through consultations and training to help you make the most of our product. If you have any questions, please reach out to us at support@shuffler.io. We offer priority support through consultations and training to help you make the most of our product. If you have any questions, please reach out to us at support@shuffler.io.
</Typography> </Typography>
<div style={{ display: 'flex', flexDirection: 'row', marginTop: 5 }}> <div style={{ display: 'flex', flexDirection: 'row', marginTop: 5, }}>
{billingInfo.subscription !== undefined && billingInfo.subscription !== null ? ( {billingInfo.subscription !== undefined && billingInfo.subscription !== null ? (
isChildOrg ? null : ( isChildOrg ? null : (
<ConsultationManagement <ConsultationManagement
@@ -2276,7 +2361,7 @@ const Billing = memo((props) => {
</div> </div>
</div> </div>
)} )}
<div style={{ marginTop: isCloud && 40, marginLeft: 10 }}> <div style={{ marginTop: 40, marginLeft: 10 }}>
<Typography <Typography
style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }} style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}
> >
@@ -2323,43 +2408,51 @@ const Billing = memo((props) => {
<div style={{ marginTop: 15 }}> <div style={{ marginTop: 15 }}>
{alertThresholds.map((threshold, index) => ( {alertThresholds.map((threshold, index) => (
<div key={index} style={{ display: 'flex', alignItems: 'center' }}> <div key={index} style={{ display: 'flex', alignItems: 'center' }}>
<TextField
style={{
marginTop: 10,
backgroundColor: "#212121",
width: 250,
height: 50,
}}
InputProps={{
style: {
height: 50,
color: 'white',
},
endAdornment: '%',
}}
InputLabelProps={{
shrink: undefined,
}}
color="primary"
fullWidth
label="Alert threshold (%)"
type="number"
value={threshold.percentage}
onChange={(e) => updateAlertThreshold(index, 'percentage', e.target.value)}
margin="normal"
variant="outlined"
inputProps={{
max: 100,
}}
/>
<TextField <TextField
style={{ style={{
marginTop: 10, marginTop: 10,
backgroundColor: "#212121", height: 50,
width: 250, backgroundColor: "#212121",
width: 250,
marginLeft: 15,
}} }}
InputProps={{ InputProps={{
style: { style: {
height: 50, height: 50,
color: 'white', color: 'white',
}, },
endAdornment: '%',
}} }}
color="primary" InputLabelProps={{
fullWidth shrink: undefined,
label="Alert threshold (%)"
type="number"
value={threshold.percentage}
onChange={(e) => updateAlertThreshold(index, 'percentage', e.target.value)}
margin="normal"
variant="outlined"
inputProps={{
max: 100,
}}
/>
<TextField
style={{
marginTop: 10,
backgroundColor: "#212121",
width: 250,
marginLeft: 15,
}}
InputProps={{
style: {
height: 50,
color: 'white',
},
}} }}
color="primary" color="primary"
fullWidth fullWidth
@@ -2370,34 +2463,67 @@ const Billing = memo((props) => {
margin="normal" margin="normal"
variant="outlined" variant="outlined"
/> />
<span style={{ marginLeft: alertThresholds[index].Email_send === true ? 10 : 35, color: 'green' }}>{alertThresholds[index].Email_send === true && <Tooltip title="We have already sent alert for this threshold."><CheckCircle /></Tooltip>}</span> <span
{ style={{
alertThresholds.length > 1 && marginLeft: alertThresholds[index].Email_send === true ? 10 : 35,
( color: 'green',
<Button }}
disableRipple >
disableElevation {alertThresholds[index].Email_send === true && (
sx={{ <Tooltip title="We have already sent alert for this threshold.">
padding: 0, <CheckCircle />
'&:hover': { </Tooltip>
backgroundColor: 'transparent', )}
}, </span>
}} {alertThresholds.length > 1 && (
<Button
disableRipple
disableElevation
sx={{
padding: 0,
'&:hover': {
backgroundColor: 'transparent',
},
}}
onClick={() => {
setDeleteAlertVerification(true);
setDeleteAlertIndex(index);
}}
>
<DeleteIcon sx={{ color: theme.palette.secondary.main }} />
</Button>
)}
<Dialog
open={deleteAlertVerification}
onClose={() => setDeleteAlertVerification(false)}
sx={{
'& .MuiBackdrop-root': { backgroundColor: 'rgba(0, 0, 0, 0.3)' },
}}
>
<DialogTitle>Are you sure you want to delete this threshold?</DialogTitle>
<DialogActions>
<Button
style={{ textTransform: 'none', fontSize: 16 }}
color="primary"
onClick={() => setDeleteAlertVerification(false)}
>
Cancel
</Button>
<Button
style={{ textTransform: 'none', fontSize: 16 }}
color="secondary"
onClick={() => {
handleDeleteAlertThreshold(deleteAlertIndex);
setDeleteAlertVerification(false);
}}
>
Delete
</Button>
</DialogActions>
</Dialog>
</div>
onClick={() => { setDeleteAlertVerification(true) }}
>
<DeleteIcon sx={{ color: theme.palette.secondary.main }} />
</Button>
)
}
<Dialog open={deleteAlertVerification} onClose={() => setDeleteAlertVerification(false)} sx={{ '& .MuiBackdrop-root': { backgroundColor: 'rgba(0, 0, 0, 0.3)', }, }}>
<DialogTitle>Are you sure you want to delete this threshold?</DialogTitle>
<DialogActions>
<Button style={{ textTransform: 'none', fontSize: 16 }} color="primary" onClick={() => setDeleteAlertVerification(false)}>Cancel</Button>
<Button style={{ textTransform: 'none', fontSize: 16 }} color="secondary" onClick={() => { handleDeleteAlertThreshold(index); setDeleteAlertVerification(false) }} >Delete</Button>
</DialogActions>
</Dialog>
</div>
))} ))}
</div> </div>
</div> </div>
@@ -2449,10 +2575,8 @@ const PaddingWrapper = memo(({ clickedFromOrgTab, children }) => {
: "auto", : "auto",
padding: "27px 10px 19px 27px", padding: "27px 10px 19px 27px",
backgroundColor: '#212121', backgroundColor: '#212121',
borderRadius: '16px',
height: '100%', height: '100%',
boxSizing: 'border-box', boxSizing: 'border-box',
borderLeft: '1px solid #494949',
overflow: 'hidden', overflow: 'hidden',
maxHeight: "1700px", overflowY: "auto",scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin' maxHeight: "1700px", overflowY: "auto",scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'
}), [clickedFromOrgTab]); }), [clickedFromOrgTab]);
+123 -29
View File
@@ -648,12 +648,13 @@ const AppStats = (defaultprops) => {
All shown statistics are gathered from <a All shown statistics are gathered from <a
href={`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`} href={`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`}
target="_blank" target="_blank"
style={{ textDecoration: "none", color: "#f85a3e",}} style={{ textDecoration: "none", color: "#FF8444",}}
>Your Organisation Statistics. </a> >Your Organisation Statistics. </a>
It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b> It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
</Typography> </Typography>
<div style={{display: "flex", textAlign: "center",}}> <div style={{display: "flex", flexDirection: "column", textAlign: "center",}}>
<div style={{flexDirection: "row", }}>
{filteredStatistics !== undefined ? {filteredStatistics !== undefined ?
<div style={{flex: 1, display: "flex", textAlign: "center",}}> <div style={{flex: 1, display: "flex", textAlign: "center",}}>
<Tooltip title={ <Tooltip title={
@@ -726,40 +727,135 @@ const AppStats = (defaultprops) => {
</Tooltip> </Tooltip>
</div> </div>
: null} : null}
</div>
{clickedFromOrgTab? ( {clickedFromOrgTab? (
<LocalizationProvider dateAdapter={AdapterDayjs} style={{ flex: 1 }}> <LocalizationProvider dateAdapter={AdapterDayjs} style={{ flex: 1 }}>
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}> <div style={{ display: "flex", flexDirection: "row", width: "100%", gap: "10px", justifyContent: 'center', alignItems: 'center', paddingTop: 10 }}>
<div style={{ flex: 1, maxWidth: "200px", }}> <div
style={{
display: "flex",
flexDirection: "row",
flex: 1,
alignItems: "center",
}}
>
<Typography
style={{
marginLeft: 10,
marginRight: 10,
fontSize: 16,
whiteSpace: "nowrap",
}}
color="textSecondary"
>
Search from
</Typography>
<DateTimePicker <DateTimePicker
sx={{ slotProps={{
marginTop: 1, textField: {
marginLeft: 1, sx: {
}} "& .MuiOutlinedInput-root": {
ampm={false} "& fieldset": {
label="Search from" borderColor: "#494949 !important",
format="YYYY-MM-DD HH:mm:ss" borderWidth: "1px !important",
value={startTime} },
onChange={handleStartTimeChange} "&:hover fieldset": {
renderInput={(params) => <TextField {...params} />} borderColor: "#FFFFFF !important",
},
"&.Mui-focused fieldset": {
borderColor: "#FFFFFF !important",
},
height: "35px",
fontSize: 16,
color: "#c8c8c8",
},
},
},
}}
sx={{
"& .MuiInputBase-root": {
height: "35px",
minHeight: "35px",
},
"& .MuiInputBase-input": {
height: "35px",
padding: "0 14px",
boxSizing: "border-box",
color: "#c8c8c8",
fontSize: 16,
}
}}
ampm={false}
format="YYYY-MM-DD HH:mm:ss"
value={startTime}
onChange={handleStartTimeChange}
/> />
</div> </div>
<div style={{ flex: 1, maxWidth: "200px",}}> <div
style={{
display: "flex",
flexDirection: "row",
flex: 1,
alignItems: "center",
}}
>
<Typography
style={{
marginLeft: 10,
marginRight: 10,
fontSize: 16,
whiteSpace: "nowrap",
}}
color="textSecondary"
>
Search until
</Typography>
<DateTimePicker <DateTimePicker
sx={{ slotProps={{
textField: {
sx: {
"& .MuiOutlinedInput-root": {
"& fieldset": {
borderColor: "#494949 !important",
borderWidth: "1px !important",
},
"&:hover fieldset": {
borderColor: "#FFFFFF !important",
},
"&.Mui-focused fieldset": {
borderColor: "#FFFFFF !important",
},
height: "35px",
fontSize: 16,
color: "#c8c8c8",
},
},
},
}}
sx={{
marginTop: 1, marginTop: 1,
marginLeft: 1, "& .MuiInputBase-root": {
}} height: "35px",
ampm={false} minHeight: "35px",
label="Search until" },
format="YYYY-MM-DD HH:mm:ss" "& .MuiInputBase-input": {
value={endTime} height: "35px",
onChange={handleEndTimeChange} padding: "0 14px",
renderInput={(params) => <TextField {...params} />} boxSizing: "border-box",
color: "#c8c8c8",
fontSize: 16,
}
}}
ampm={false}
format="YYYY-MM-DD HH:mm:ss"
value={endTime}
onChange={handleEndTimeChange}
/> />
</div> </div>
</div> </div>
</LocalizationProvider> </LocalizationProvider>
):( ):(
<LocalizationProvider dateAdapter={AdapterDayjs} style={{flex: 1, }}> <LocalizationProvider dateAdapter={AdapterDayjs} style={{flex: 1, }}>
<div style={{display: "flex", flexDirection: "column", }}> <div style={{display: "flex", flexDirection: "column", }}>
@@ -794,8 +890,6 @@ const AppStats = (defaultprops) => {
</div> </div>
</LocalizationProvider> </LocalizationProvider>
)} )}
</div> </div>
{appRuns === undefined ? {appRuns === undefined ?
+13 -12
View File
@@ -303,7 +303,7 @@ const CacheView = memo((props) => {
Key Key
<TextField <TextField
color="primary" color="primary"
style={{ backgroundColor: theme.palette.inputColor }} style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor }}
autoFocus autoFocus
InputProps={{ InputProps={{
style: { style: {
@@ -341,7 +341,7 @@ const CacheView = memo((props) => {
</div> </div>
<TextField <TextField
color="primary" color="primary"
style={{ backgroundColor: theme.palette.inputColor, marginTop: 0, }} style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor, marginTop: 0, }}
InputProps={{ InputProps={{
style: { style: {
color: "white", color: "white",
@@ -412,7 +412,7 @@ const CacheView = memo((props) => {
</span> </span>
</div> </div>
<Button <Button
style={{backgroundColor: isSelectedDataStore? "#ff8544":null, fontSize: 16, boxShadow: isSelectedDataStore ? "none":null,textTransform: isSelectedDataStore ? 'capitalize':null, color:isSelectedDataStore?"#1a1a1a":null, borderRadius:isSelectedDataStore?8:null, width:isSelectedDataStore?162:null, height:isSelectedDataStore?40:null}} style={{backgroundColor: isSelectedDataStore? "#ff8544":null, fontSize: 16, boxShadow: isSelectedDataStore ? "none":null,textTransform: isSelectedDataStore ? 'capitalize':null, color:isSelectedDataStore?"#1a1a1a":null, borderRadius:isSelectedDataStore?4:null, width:isSelectedDataStore?162:null, height:isSelectedDataStore?40:null}}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() =>{ onClick={() =>{
@@ -425,7 +425,7 @@ const CacheView = memo((props) => {
Add Cache Add Cache
</Button> </Button>
<Button <Button
style={{ marginLeft: 5, marginRight: 15, backgroundColor: isSelectedDataStore?"#2F2F2F":null, boxShadow: isSelectedDataStore ? "none":null,textTransform: isSelectedDataStore ? 'capitalize':null,borderRadius:isSelectedDataStore?8:null, width:isSelectedDataStore?81:null, height:isSelectedDataStore?40:null, }} style={{ marginLeft: 16, marginRight: 15, backgroundColor: isSelectedDataStore?"#2F2F2F":null, boxShadow: isSelectedDataStore ? "none":null,textTransform: isSelectedDataStore ? 'capitalize':null,borderRadius:isSelectedDataStore?4:null, width:isSelectedDataStore?81:null, height:isSelectedDataStore?40:null, }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => listOrgCache(orgId)} onClick={() => listOrgCache(orgId)}
@@ -440,7 +440,7 @@ const CacheView = memo((props) => {
/>} />}
<div <div
style={{ style={{
borderRadius: 8, borderRadius: 4,
marginTop: 24, marginTop: 24,
border: "1px solid #494949", border: "1px solid #494949",
width: "100%", width: "100%",
@@ -450,7 +450,7 @@ const CacheView = memo((props) => {
> >
<List <List
style={{ style={{
borderRadius: 8, borderRadius: 4,
paddingBottom: 0, paddingBottom: 0,
tableLayout: "auto", tableLayout: "auto",
display: "table", display: "table",
@@ -465,7 +465,7 @@ const CacheView = memo((props) => {
primary={header} primary={header}
style={{ style={{
display: "table-cell", display: "table-cell",
padding: "0px 8px 8px 8px", padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
whiteSpace: "nowrap", whiteSpace: "nowrap",
overflow: "hidden", overflow: "hidden",
textOverflow: "ellipsis", textOverflow: "ellipsis",
@@ -518,13 +518,13 @@ const CacheView = memo((props) => {
const validate = validateJson(data.value); const validate = validateJson(data.value);
return ( return (
<ListItem key={index} style={{display:'table-row', backgroundColor: bgColor, maxHeight: 300, overflow: "auto", borderBottomLeftRadius: listCache?.length - 1 === index ? 8 : 0, borderBottomRightRadius: listCache?.length - 1 === index ? 8 : 0}}> <ListItem key={index} style={{display:'table-row', backgroundColor: bgColor, maxHeight: 300, overflow: "auto", borderBottomLeftRadius: listCache?.length - 1 === index ? 8 : 0, borderBottomRightRadius: listCache?.length - 1 === index ? 8 : 0,}}>
<ListItemText <ListItemText
style={{ style={{
display: "table-cell", display: "table-cell",
overflow: "hidden", overflow: "hidden",
padding: 8,
verticalAlign: "middle", verticalAlign: "middle",
padding: "8px 8px 8px 15px"
}} }}
primary={data.key} primary={data.key}
/> />
@@ -533,9 +533,8 @@ const CacheView = memo((props) => {
display: "table-cell", display: "table-cell",
overflowY: "auto", overflowY: "auto",
overflowX: "auto", overflowX: "auto",
border: "1px solid rgba(255,255,255,0.7)", borderRadius: 4,
borderRadius: 6, padding: "15px 5px",
backgroundColor: "#151515",
maxHeight: 300, maxHeight: 300,
verticalAlign: "middle", verticalAlign: "middle",
}} }}
@@ -547,6 +546,8 @@ const CacheView = memo((props) => {
padding: 5, padding: 5,
maxHeight: 300, maxHeight: 300,
overflowY: "auto", overflowY: "auto",
backgroundColor: "#151515",
border: "1px solid rgba(255,255,255,0.7)",
}} }}
collapsed={true} collapsed={true}
enableClipboard={(copy) => { enableClipboard={(copy) => {
+2 -2
View File
@@ -1149,7 +1149,7 @@ const EditWorkflow = (props) => {
</div> </div>
: null} : null}
{/* {!isEditing ? <> {!isEditing ? <>
<div style={{ marginTop: 20, }}> <div style={{ marginTop: 20, }}>
<FormControlLabel <FormControlLabel
control={<Checkbox />} control={<Checkbox />}
@@ -1164,7 +1164,7 @@ const EditWorkflow = (props) => {
/> />
</div> </div>
</> : null} */} </> : null}
<Tooltip color="primary" title={"Add more details"} placement="top"> <Tooltip color="primary" title={"Add more details"} placement="top">
<Button <Button
+67 -45
View File
@@ -280,7 +280,7 @@ const Files = memo((props) => {
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}> <DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
Repository URL (supported: github, gitlab, bitbucket) Repository URL (supported: github, gitlab, bitbucket)
<TextField <TextField
style={{ backgroundColor: theme.palette.inputColor }} style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor }}
variant="outlined" variant="outlined"
margin="normal" margin="normal"
defaultValue={downloadUrl} defaultValue={downloadUrl}
@@ -301,7 +301,7 @@ const Files = memo((props) => {
Branch (default value is "main"): Branch (default value is "main"):
</span> </span>
<TextField <TextField
style={{ backgroundColor: theme.palette.inputColor }} style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor }}
variant="outlined" variant="outlined"
margin="normal" margin="normal"
defaultValue={downloadBranch} defaultValue={downloadBranch}
@@ -322,7 +322,7 @@ const Files = memo((props) => {
Folder (can use / for subfolders): Folder (can use / for subfolders):
</span> </span>
<TextField <TextField
style={{ backgroundColor: theme.palette.inputColor }} style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor }}
variant="outlined" variant="outlined"
margin="normal" margin="normal"
defaultValue={downloadFolder} defaultValue={downloadFolder}
@@ -344,7 +344,7 @@ const Files = memo((props) => {
</span> </span>
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<TextField <TextField
style={{ flex: 1, backgroundColor: theme.palette.inputColor }} style={{ flex: 1, backgroundColor: theme.palette.textFieldStyle.backgroundColork }}
variant="outlined" variant="outlined"
margin="normal" margin="normal"
InputProps={{ InputProps={{
@@ -360,7 +360,7 @@ const Files = memo((props) => {
fullWidth fullWidth
/> />
<TextField <TextField
style={{ flex: 1, backgroundColor: theme.palette.inputColor }} style={{ flex: 1, backgroundColor: theme.palette.textFieldStyle.backgroundColor }}
variant="outlined" variant="outlined"
margin="normal" margin="normal"
InputProps={{ InputProps={{
@@ -668,7 +668,7 @@ const Files = memo((props) => {
{fileDownloadModal} {fileDownloadModal}
<div style={{ marginTop: isSelectedFiles ? 2: 20, marginBottom:20 }}> <div style={{ marginTop: isSelectedFiles ? 2: 20, marginBottom:20 }}>
<h2 style={{ display: isSelectedFiles ? null : "inline", marginTop: isSelectedFiles?0:null, marginBottom: isSelectedFiles?8:null }}>Files</h2> <h2 style={{ display: isSelectedFiles ? null : "inline", marginTop: isSelectedFiles?0:null, marginBottom: isSelectedFiles?8:null, color: "#FFFFFF"}}>Files</h2>
<span style={{ marginLeft: isSelectedFiles ? null : 25, color:isSelectedFiles?"#9E9E9E":null}}> <span style={{ marginLeft: isSelectedFiles ? null : 25, color:isSelectedFiles?"#9E9E9E":null}}>
Files from Workflows are a way to store as well as edit files.{" "} Files from Workflows are a way to store as well as edit files.{" "}
<a <a
@@ -690,7 +690,7 @@ const Files = memo((props) => {
onClick={() => { onClick={() => {
upload.click(); upload.click();
}} }}
style={{backgroundColor: isSelectedFiles?'#ff8544':null, color:isSelectedFiles?"#212121":null, textTransform: 'none',fontSize: 16, borderRadius:isSelectedFiles?8:null, width:isSelectedFiles?143:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null,}} style={{backgroundColor: isSelectedFiles?'#ff8544':null, color:isSelectedFiles?"#212121":null, textTransform: 'none',fontSize: 16, borderRadius:isSelectedFiles?4:null, width:isSelectedFiles?143:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null,}}
> >
Upload files Upload files
</Button> </Button>
@@ -711,7 +711,7 @@ const Files = memo((props) => {
}} }}
/> />
<Button <Button
style={{ marginLeft: 16, marginRight: 15, backgroundColor:isSelectedFiles?"#2F2F2F":null,borderRadius:isSelectedFiles?8:null, width:isSelectedFiles?81:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null, }} style={{ marginLeft: 16, marginRight: 15, backgroundColor:isSelectedFiles?"#2F2F2F":null,borderRadius:isSelectedFiles?4:null, width:isSelectedFiles?81:null, height:isSelectedFiles?35:null, boxShadow: isSelectedFiles?'none':null, }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => getFiles(selectedCategory)} onClick={() => getFiles(selectedCategory)}
@@ -788,7 +788,7 @@ const Files = memo((props) => {
: :
<Tooltip title={"Add new file category"} style={{}} aria-label={""}> <Tooltip title={"Add new file category"} style={{}} aria-label={""}>
<Button <Button
style={{ marginLeft: 5, marginRight: 15, width: 169, height: 35, backgroundColor: "#494949", textTransform: 'none', fontSize: 16, color: "#f1f1f1" }} style={{ marginLeft: 5, marginRight: 15, width: 169, height: 35, borderRadius: 4, backgroundColor: "#494949", textTransform: 'none', fontSize: 16, color: "#f1f1f1" }}
color="primary" color="primary"
onClick={() => { onClick={() => {
setRenderTextBox(true); setRenderTextBox(true);
@@ -833,12 +833,12 @@ const Files = memo((props) => {
style={{ style={{
marginTop: 20, marginTop: 20,
marginBottom: 20, marginBottom: 20,
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.textFieldStyle.backgroundColor,
}} }}
/>} />}
<div <div
style={{ style={{
borderRadius: 8, borderRadius: 4,
marginTop: 24, marginTop: 24,
border: "1px solid #494949", border: "1px solid #494949",
width: "100%", width: "100%",
@@ -862,7 +862,7 @@ const Files = memo((props) => {
primary={header} primary={header}
style={{ style={{
display: "table-cell", display: "table-cell",
padding: "0px 8px 8px 8px", padding: index === 0 ? "0px 8px 8px 15px": "0px 8px 8px 8px",
whiteSpace: "nowrap", whiteSpace: "nowrap",
textOverflow: "ellipsis", textOverflow: "ellipsis",
borderBottom: "1px solid #494949", borderBottom: "1px solid #494949",
@@ -870,7 +870,7 @@ const Files = memo((props) => {
}} }}
primaryTypographyProps={{ primaryTypographyProps={{
style: { style: {
paddingLeft: index === 3 ? 80 : 10, paddingLeft: 10,
} }
}} }}
/> />
@@ -956,15 +956,13 @@ const Files = memo((props) => {
<ListItemText <ListItemText
primaryTypographyProps={{ primaryTypographyProps={{
style: { style: {
display: 'table-cell',
maxWidth: "170px", maxWidth: "170px",
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
overflow: 'hidden', overflow: 'hidden',
padding: 8 padding: "8px 8px 8px 20px"
}, }
}} }}
primary={file.filename} primary={file.filename}
/> />
<ListItemText <ListItemText
@@ -1005,6 +1003,7 @@ const Files = memo((props) => {
> >
<OpenInNewIcon <OpenInNewIcon
style={{ style={{
width: 24, height: 24,
color: color:
file.workflow_id !== "global" file.workflow_id !== "global"
? "#FF8444" ? "#FF8444"
@@ -1044,7 +1043,7 @@ const Files = memo((props) => {
style={{ style={{
display: 'table-cell', display: 'table-cell',
overflow: "hidden", overflow: "hidden",
textAlign:isSelectedFiles?"left":null, textAlign:isSelectedFiles?"center":null,
color: file.status === "active" ? "#2BC07E" : "#FD4C62" color: file.status === "active" ? "#2BC07E" : "#FD4C62"
}} }}
/> />
@@ -1074,7 +1073,7 @@ const Files = memo((props) => {
}} }}
> >
<img src="/icons/editIcon.svg" alt="edit icon" <img src="/icons/editIcon.svg" alt="edit icon"
style={{color: iseditable ? "white" : "grey",}} style={{color: iseditable ? "white" : "grey", width: 24, height: 24}}
/> />
</IconButton> </IconButton>
</span> </span>
@@ -1120,6 +1119,7 @@ const Files = memo((props) => {
> >
<img src="/icons/downloadIcon.svg" alt="download icon" <img src="/icons/downloadIcon.svg" alt="download icon"
style={{ style={{
width: 24, height: 24,
color: color:
file.status === "active" file.status === "active"
? "white" ? "white"
@@ -1144,7 +1144,7 @@ const Files = memo((props) => {
toast(file.id + " copied to clipboard"); toast(file.id + " copied to clipboard");
}} }}
> >
<img src="/icons/copyIcon.svg" alt="copy icon" style={{ color: "white" }} /> <img src="/icons/copyIcon.svg" alt="copy icon" style={{ color: "white", width: 24, height: 24 }} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
@@ -1155,21 +1155,35 @@ const Files = memo((props) => {
<span> <span>
<IconButton <IconButton
disabled={file.status !== "active"} disabled={file.status !== "active"}
style = {{padding: "6px"}} style={{ padding: "6px" }}
onClick={() => { onClick={() => {
deleteFile(file) deleteFile(file);
}} }}
> >
<img src="/icons/deleteIcon.svg" alt="delete icon" <svg
style={{ width="24"
color: height="24"
file.status === "active" viewBox="0 0 24 24"
? "white" xmlns="http://www.w3.org/2000/svg"
: "grey", style={{
}} stroke: file.status === "active" ? "#fd4c62" : "#c8c8c8",
}}
>
<path
d="M5 7.20001H6.6H19.4"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
/> />
<path
d="M17.7996 7.2V18.4C17.7996 18.8243 17.631 19.2313 17.331 19.5314C17.0309 19.8314 16.624 20 16.1996 20H8.19961C7.77526 20 7.3683 19.8314 7.06824 19.5314C6.76818 19.2313 6.59961 18.8243 6.59961 18.4V7.2M8.99961 7.2V5.6C8.99961 5.17565 9.16818 4.76869 9.46824 4.46863C9.7683 4.16857 10.1753 4 10.5996 4H13.7996C14.224 4 14.6309 4.16857 14.931 4.46863C15.231 4.76869 15.3996 5.17565 15.3996 5.6V7.2"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
/>
</svg>
</IconButton> </IconButton>
</span> </span>
</Tooltip> </Tooltip>
</span> </span>
style={{ style={{
@@ -1195,20 +1209,28 @@ const Files = memo((props) => {
export default memo(Files); export default memo(Files);
const DownloadFileIcon = memo(({ setLoadFileModalOpen, isSelectedFiles, }) => { const DownloadFileIcon = memo(({ setLoadFileModalOpen, isSelectedFiles }) => {
const { leftSideBarOpenByClick } = useContext(Context) return (
<Tooltip color="primary" title={"Import files to Shuffle from Git"} placement="top">
return( <IconButton
<Tooltip color="primary" title={"Import files to Shuffle from Git"} placement="top"> color="secondary"
<IconButton onClick={() => setLoadFileModalOpen(true)}
color="secondary" sx={{
style={{position: "absolute", right: 0, top: isSelectedFiles?null:0, left: isSelectedFiles? leftSideBarOpenByClick ? "90%": "85%":null, transition: "left 0.3s ease" }} position: "absolute",
variant="text" right: 0,
onClick={() => setLoadFileModalOpen(true)} top: isSelectedFiles ? null : 0,
> left: isSelectedFiles
<CloudDownloadIcon /> ? "93%"
</IconButton> : null,
transition: "left 0.3s ease",
width: 48,
height: 48,
borderRadius: "50%",
}}
>
<CloudDownloadIcon />
</IconButton>
</Tooltip> </Tooltip>
) );
}) });
+50 -45
View File
@@ -229,7 +229,7 @@ useEffect(() => {
setOpenautomateTab(false); setOpenautomateTab(false);
setOpenSecurityTab(true); setOpenSecurityTab(true);
setCurrentOpenTab("security"); setCurrentOpenTab("security");
} else if ((lastTabOpenByUser === "usecases" && currentPath.includes("/usecases2")) || currentPath.includes("/usecases2")) { } else if ((lastTabOpenByUser === "usecases" && currentPath.includes("/usecases")) || currentPath.includes("/usecases")) {
setOpenautomateTab(true); setOpenautomateTab(true);
setOpenSecurityTab(false); setOpenSecurityTab(false);
setCurrentOpenTab("usecases"); setCurrentOpenTab("usecases");
@@ -466,6 +466,7 @@ useEffect(() => {
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
}} }}
style={{fontSize: 18}}
> >
<BusinessIcon style={{ marginRight: 5 }} /> Organization <BusinessIcon style={{ marginRight: 5 }} /> Organization
</MenuItem> </MenuItem>
@@ -475,6 +476,7 @@ useEffect(() => {
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
}} }}
style={{fontSize: 18}}
> >
<SettingsIcon style={{ marginRight: 5 }} /> Account <SettingsIcon style={{ marginRight: 5 }} /> Account
</MenuItem> </MenuItem>
@@ -486,6 +488,7 @@ useEffect(() => {
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
}} }}
style={{fontSize: 18}}
> >
<NotificationsIcon style={{ marginRight: 5 }} /> Notifications ({ <NotificationsIcon style={{ marginRight: 5 }} /> Notifications ({
notifications === undefined || notifications === null ? 0 : notifications === undefined || notifications === null ? 0 :
@@ -498,6 +501,7 @@ useEffect(() => {
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
}} }}
style={{fontSize: 18}}
> >
<LightbulbIcon style={{ marginRight: 5 }} /> Use Cases <LightbulbIcon style={{ marginRight: 5 }} /> Use Cases
</MenuItem> </MenuItem>
@@ -510,24 +514,26 @@ useEffect(() => {
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
}} }}
style={{fontSize: 18}}
> >
<HelpOutlineIcon style={{ marginRight: 5 }} /> About <HelpOutlineIcon style={{ marginRight: 5 }} /> About
</MenuItem> </MenuItem>
</Link> </Link>
<MenuItem <MenuItem
style={{ color: "white" }} style={{ color: "white", fontSize: 18 }}
onClick={(event) => { onClick={(event) => {
handleClickLogout(); handleClickLogout();
event.preventDefault(); event.preventDefault();
handleClose(); handleClose();
}} }}
> >
<MeetingRoomIcon style={{ marginRight: 5 }} /> &nbsp;Logout <MeetingRoomIcon style={{ marginRight: 5 }} /> &nbsp;Logout
</MenuItem> </MenuItem>
<Divider style={{ marginBottom: 10, }} /> <Divider style={{ marginBottom: 10, }} />
<Typography variant="body2" color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, }}> <Typography color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, fontSize: 18 }}>
Version: 2.0.0-beta Version: 2.0.0-rc
</Typography> </Typography>
</Menu> </Menu>
</span> </span>
@@ -717,6 +723,7 @@ useEffect(() => {
width: expandLeftNav ? "100%" : 30, width: expandLeftNav ? "100%" : 30,
padding: 0, padding: 0,
}, },
fontSize: 18
}; };
const modalView = ( const modalView = (
@@ -898,7 +905,7 @@ useEffect(() => {
whiteSpace: "nowrap", whiteSpace: "nowrap",
}} }}
> >
<kbd>Ctrl</kbd>/<kbd>Cmd</kbd>+<kbd>K</kbd> <kbd>Ctrl</kbd>+<kbd>K</kbd>
</span> </span>
), ),
disableUnderline: true, disableUnderline: true,
@@ -936,6 +943,7 @@ useEffect(() => {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
padding: expandLeftNav ? "0 16px" : "0px 8px", padding: expandLeftNav ? "0 16px" : "0px 8px",
gap: 1.2,
}} }}
> >
<Box sx={{ display: "flex", flexDirection: "row", marginTop: 2.5, width: expandLeftNav ? "100%" : 48, padding: "0px", }}> <Box sx={{ display: "flex", flexDirection: "row", marginTop: 2.5, width: expandLeftNav ? "100%" : 48, padding: "0px", }}>
@@ -950,18 +958,18 @@ useEffect(() => {
variant="text" variant="text"
style={{ style={{
...ButtonStyle, ...ButtonStyle,
backgroundColor: ((currentOpenTab === "automate" && currentPath.includes("/dashboards/automate"))|| (!expandLeftNav && (currentPath === "/workflows" || currentPath === "/usecases2" || currentPath.includes("/search"))))? "#2f2f2f": "transparent", backgroundColor: ((currentOpenTab === "automate" && currentPath.includes("/dashboards/automate"))|| (!expandLeftNav && (currentPath === "/workflows" || currentPath === "/usecases" || currentPath.includes("/search"))))? "#2f2f2f": "transparent",
}} }}
onMouseOver={(event)=>{ onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f"; event.currentTarget.style.backgroundColor = "#2f2f2f";
}} }}
onMouseOut={(event)=>{ onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = ((currentOpenTab === "automate" && currentPath.includes("/dashboards/automate"))|| (!expandLeftNav && (currentPath === "/workflows" || currentPath === "/usecases2" || currentPath.includes("/search"))))? "#2f2f2f": "transparent"; event.currentTarget.style.backgroundColor = ((currentOpenTab === "automate" && currentPath.includes("/dashboards/automate"))|| (!expandLeftNav && (currentPath === "/workflows" || currentPath === "/usecases" || currentPath.includes("/search"))))? "#2f2f2f": "transparent";
}} }}
> >
<img <img
src={detectionIcon} src={detectionIcon}
style={{ width: 16, height: 16, marginRight: expandLeftNav ? 10 : 0 }} style={{ width: 18, height: 18, marginRight: expandLeftNav ? 10 : 0 }}
alt="Automate Icon" alt="Automate Icon"
/> />
<span <span
@@ -1020,7 +1028,7 @@ useEffect(() => {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
paddingLeft: 16, paddingLeft: 16,
gap: 4, gap: 10,
}} }}
> >
<Link to="/usecases" style={hrefStyle}> <Link to="/usecases" style={hrefStyle}>
@@ -1032,8 +1040,9 @@ useEffect(() => {
style={{ style={{
width: "100%", width: "100%",
height: 35, height: 35,
color: "#C8C8C8", color: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases") ? "#FFFFFF" : "#C8C8C8",
justifyContent: "flex-start", justifyContent: "flex-start",
fontSize: 18,
textTransform: "none", textTransform: "none",
backgroundColor: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases")? "#2f2f2f": "transparent", backgroundColor: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases")? "#2f2f2f": "transparent",
marginLeft: 16 marginLeft: 16
@@ -1046,13 +1055,13 @@ useEffect(() => {
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
> >
<span style={{display: expandLeftNav ? "inline" : "none",opacity: expandLeftNav ? 1 : 0, transition: "opacity 0.3s ease", position: 'relative', left: !expandLeftNav ? 10: 0, marginRight: 10, fontSize: 16 }}></span>{" "} <span style={{display: expandLeftNav ? "inline" : "none",opacity: expandLeftNav ? 1 : 0, transition: "opacity 0.3s ease", position: 'relative', left: !expandLeftNav ? 10: 0, marginRight: 10, fontSize: 18 }}></span>{" "}
<span <span
style={{ style={{
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
opacity: expandLeftNav ? 1 : 0, opacity: expandLeftNav ? 1 : 0,
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
color: currentOpenTab === "usecases" && currentPath.includes("/usecases3") ? "#F1F1F1" : "#C8C8C8", color: currentOpenTab === "usecases" && currentPath.includes("/usecases") ? "#FFFFFF" : "#C8C8C8",
}} }}
> >
Usecases Usecases
@@ -1068,11 +1077,12 @@ useEffect(() => {
style={{ style={{
width: "100%", width: "100%",
height: 35, height: 35,
color: "#C8C8C8", color: currentOpenTab === "workflows" && currentPath === "/workflows" ? "#FFFFFF" : "#C8C8C8",
justifyContent: "flex-start", justifyContent: "flex-start",
textTransform: "none", textTransform: "none",
backgroundColor: currentOpenTab === "workflows" && currentPath === "/workflows" && expandLeftNav? "#2f2f2f": "transparent", backgroundColor: currentOpenTab === "workflows" && currentPath === "/workflows" && expandLeftNav? "#2f2f2f": "transparent",
marginLeft: 16 marginLeft: 16,
fontSize: 18
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
onMouseOver={(event)=>{ onMouseOver={(event)=>{
@@ -1082,13 +1092,13 @@ useEffect(() => {
event.currentTarget.style.backgroundColor = currentOpenTab === "workflows" && currentPath === "/workflows" && expandLeftNav? "#2f2f2f": "transparent"; event.currentTarget.style.backgroundColor = currentOpenTab === "workflows" && currentPath === "/workflows" && expandLeftNav? "#2f2f2f": "transparent";
}} }}
> >
<span style={{display: expandLeftNav ? "inline" : "none", opacity: expandLeftNav ? 1 : 0, transition: "opacity 0.3s ease", position: 'relative', left: !expandLeftNav ? 10: 0, marginRight: 10, fontSize: 16 }}></span>{" "} <span style={{display: expandLeftNav ? "inline" : "none", opacity: expandLeftNav ? 1 : 0, transition: "opacity 0.3s ease", position: 'relative', left: !expandLeftNav ? 10: 0, marginRight: 10, fontSize: 18 }}></span>{" "}
<span <span
style={{ style={{
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
opacity: expandLeftNav ? 1 : 0, opacity: expandLeftNav ? 1 : 0,
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
color: currentOpenTab === "workflows" && currentPath === "/workflows" ? "#F1F1F1" : "#C8C8C8", color: currentOpenTab === "workflows" && currentPath === "/workflows" ? "#FFFFFF" : "#C8C8C8",
}} }}
> >
Workflows Workflows
@@ -1104,11 +1114,12 @@ useEffect(() => {
style={{ style={{
width: "100%", width: "100%",
height: 35, height: 35,
color: "#C8C8C8", color: currentOpenTab === "apps" && currentPath.includes("/apps") ? "#FFFFFF" : "#C8C8C8",
justifyContent: "flex-start", justifyContent: "flex-start",
textTransform: "none", textTransform: "none",
backgroundColor: currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/apps2") ? "#2f2f2f": "transparent", backgroundColor: currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/apps2") ? "#2f2f2f": "transparent",
marginLeft: 16 marginLeft: 16,
fontSize: 18
}} }}
onMouseOver={(event)=>{ onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f"; event.currentTarget.style.backgroundColor = "#2f2f2f";
@@ -1118,13 +1129,13 @@ useEffect(() => {
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
> >
<span style={{display: expandLeftNav ? "inline" : "none",opacity: expandLeftNav ? 1 : 0, transition: "opacity 0.3s ease", position: 'relative', left: !expandLeftNav ? 10: 0, marginRight: 10, fontSize: 16 }}></span>{" "} <span style={{display: expandLeftNav ? "inline" : "none",opacity: expandLeftNav ? 1 : 0, transition: "opacity 0.3s ease", position: 'relative', left: !expandLeftNav ? 10: 0, marginRight: 10, fontSize: 18 }}></span>{" "}
<span <span
style={{ style={{
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
opacity: expandLeftNav ? 1 : 0, opacity: expandLeftNav ? 1 : 0,
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
color: currentOpenTab === "apps" && currentPath.includes("/apps2") ? "#F1F1F1" : "#C8C8C8", color: currentOpenTab === "apps" && currentPath.includes("/apps") ? "#FFFFFF" : "#C8C8C8",
}} }}
> >
Apps Apps
@@ -1142,17 +1153,14 @@ useEffect(() => {
> >
<span style={{ display: "inline-block", width: "100%" }}> <span style={{ display: "inline-block", width: "100%" }}>
<Link <Link
to={userdata?.support ? "/dashboards/security" : "#"} to={"#"}
style={{ style={{
...hrefStyle, ...hrefStyle,
pointerEvents: userdata?.support ? "auto" : "none", pointerEvents: "auto",
cursor: "not-allowed",
}} }}
> >
<Button <Button
disabled={true}
onClick={(event) => { onClick={(event) => {
if (!userdata?.support) return;
setOpenSecurityTab(true); setOpenSecurityTab(true);
setOpenautomateTab(false); setOpenautomateTab(false);
setCurrentOpenTab("security"); setCurrentOpenTab("security");
@@ -1161,29 +1169,23 @@ useEffect(() => {
style={{ style={{
...ButtonStyle, ...ButtonStyle,
backgroundColor: backgroundColor:
((currentOpenTab === "security" && currentPath.includes("/security")) || currentOpenTab === "security"
(!expandLeftNav &&
(currentPath.includes("detections") || currentPath.includes("response"))))
? "#2f2f2f" ? "#2f2f2f"
: "transparent", : "transparent",
cursor: userdata?.support ? "pointer" : "not-allowed",
}} }}
onMouseOver={(event)=>{ onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f"; event.currentTarget.style.backgroundColor = "#2f2f2f";
}} }}
onMouseOut={(event)=>{ onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = ((currentOpenTab === "security" && currentPath.includes("/security")) || event.currentTarget.style.backgroundColor = currentOpenTab === "security"
(!expandLeftNav &&
(currentPath.includes("detections") || currentPath.includes("response"))))
? "#2f2f2f" ? "#2f2f2f"
: "transparent"; : "transparent";
}} }}
disabled={!userdata?.support}
> >
<ShieldOutlinedIcon <ShieldOutlinedIcon
style={{ style={{
width: 16, width: 18,
height: 16, height: 18,
marginRight: expandLeftNav ? 10 : 0, marginRight: expandLeftNav ? 10 : 0,
color: userdata?.support ? "inherit" : "#6F6F6F", color: userdata?.support ? "inherit" : "#6F6F6F",
}} }}
@@ -1192,14 +1194,13 @@ useEffect(() => {
style={{ style={{
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
marginRight: "auto", marginRight: "auto",
color: userdata?.support fontSize: 18,
? currentOpenTab === "security" && currentPath.includes("/security") color: currentOpenTab === "security"
? "#F1F1F1" ? "#F1F1F1"
: "#C8C8C8" : "#C8C8C8"
: "#6F6F6F",
}} }}
> >
Content Discover
</span> </span>
</Button> </Button>
</Link> </Link>
@@ -1278,7 +1279,7 @@ useEffect(() => {
}} }}
disabled={userdata?.support === false} disabled={userdata?.support === false}
> >
<span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 16 }}> <span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 18 }}>
</span> </span>
<span <span
@@ -1286,6 +1287,7 @@ useEffect(() => {
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
opacity: expandLeftNav ? 1 : 0, opacity: expandLeftNav ? 1 : 0,
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
fontSize: 18,
color: color:
userdata?.support && currentOpenTab === "detection" && currentPath.includes("/detection") userdata?.support && currentOpenTab === "detection" && currentPath.includes("/detection")
? "#F1F1F1" ? "#F1F1F1"
@@ -1329,7 +1331,7 @@ useEffect(() => {
cursor: userdata?.support ? "pointer" : "not-allowed", cursor: userdata?.support ? "pointer" : "not-allowed",
}} }}
> >
<span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 16 }}> <span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 18 }}>
</span> </span>
<span <span
@@ -1337,6 +1339,7 @@ useEffect(() => {
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
opacity: expandLeftNav ? 1 : 0, opacity: expandLeftNav ? 1 : 0,
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
fontSize: 18,
color: color:
userdata?.support && currentOpenTab === "response" && currentPath.includes("/response") userdata?.support && currentOpenTab === "response" && currentPath.includes("/response")
? "#F1F1F1" ? "#F1F1F1"
@@ -1380,7 +1383,7 @@ useEffect(() => {
cursor: userdata?.support ? "pointer" : "not-allowed", cursor: userdata?.support ? "pointer" : "not-allowed",
}} }}
> >
<span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 16 }}> <span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 18 }}>
</span> </span>
<span <span
@@ -1388,6 +1391,7 @@ useEffect(() => {
display: expandLeftNav ? "inline" : "none", display: expandLeftNav ? "inline" : "none",
opacity: expandLeftNav ? 1 : 0, opacity: expandLeftNav ? 1 : 0,
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
fontSize: 18,
color: color:
userdata?.support && currentOpenTab === "response" && currentPath.includes("/response") userdata?.support && currentOpenTab === "response" && currentPath.includes("/response")
? "#F1F1F1" ? "#F1F1F1"
@@ -1458,7 +1462,7 @@ useEffect(() => {
<Typography <Typography
style={{ style={{
color: "#CDCDCD", color: "#CDCDCD",
fontSize: 14, fontSize: 18,
padding: "8px 8px", padding: "8px 8px",
marginBottom: 10, marginBottom: 10,
}} }}
@@ -1688,7 +1692,7 @@ useEffect(() => {
}, },
transition: "opacity 0.3s ease", transition: "opacity 0.3s ease",
textTransform: "none", textTransform: "none",
fontSize: 16, fontSize: 18,
}} }}
disableElevation disableElevation
disableRipple disableRipple
@@ -1718,13 +1722,14 @@ useEffect(() => {
style={{ style={{
color: "#CDCDCD", color: "#CDCDCD",
margin: "0 5px", margin: "0 5px",
fontSize: 16, fontSize: 18,
whiteSpace: "nowrap", whiteSpace: "nowrap",
overflow: "hidden", overflow: "hidden",
textOverflow: "ellipsis", textOverflow: "ellipsis",
maxWidth: 150, maxWidth: 150,
textAlign: "center", textAlign: "center",
marginLeft: 10, marginLeft: 10,
}} }}
> >
{userdata?.username} {userdata?.username}
+212 -32
View File
@@ -24,6 +24,7 @@ import {
DialogActions, DialogActions,
CardContent, CardContent,
ButtonGroup, ButtonGroup,
DialogContentText,
} from "@mui/material"; } from "@mui/material";
import { useNavigate, Link } from "react-router-dom"; import { useNavigate, Link } from "react-router-dom";
@@ -42,19 +43,17 @@ import {
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx"; import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx" import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
import Billing from "./Billing.jsx";
const LicencePopup = (props) => { const LicencePopup = (props) => {
const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isLoggedIn, isMobile } = props; const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isLoggedIn, isMobile, selectedOrganization, isCloud } = props;
//const alert = useAlert(); //const alert = useAlert();
let navigate = useNavigate(); let navigate = useNavigate();
const isCloud = typeof window === 'undefined' || window === undefined || window.location === undefined ? true : window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false); const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false);
const [dealList, setDealList] = React.useState([]); const [dealList, setDealList] = React.useState([]);
const [dealName, setDealName] = React.useState(""); const [dealName, setDealName] = React.useState("");
const [dealAddress, setDealAddress] = React.useState(""); const [dealAddress, setDealAddress] = React.useState("");
const [dealType, setDealType] = React.useState("MSSP"); const [dealType, setDealType] = React.useState("MSSP");
const [selectedOrganization, setSelectedOrganization] = React.useState({});
const [dealCountry, setDealCountry] = React.useState("United States"); const [dealCountry, setDealCountry] = React.useState("United States");
const [dealCurrency, setDealCurrency] = React.useState("USD"); const [dealCurrency, setDealCurrency] = React.useState("USD");
const [dealStatus, setDealStatus] = React.useState("initiated"); const [dealStatus, setDealStatus] = React.useState("initiated");
@@ -63,8 +62,8 @@ const LicencePopup = (props) => {
const [dealerror, setDealerror] = React.useState(""); const [dealerror, setDealerror] = React.useState("");
const [variant, setVariant] = useState(0) const [variant, setVariant] = useState(0)
const [shuffleVariant, setShuffleVariant] = useState(isCloud ? 0 : 1) const [shuffleVariant, setShuffleVariant] = useState(isCloud ? 0 : 1)
const [BillingEmail, setBillingEmail] = useState(selectedOrganization?.Billing?.Email);
const [openChangeEmailBox, setOpenChangeEmailBox] = useState(false);
// const parsedFields = maxFields === undefined ? 300 : maxFields // const parsedFields = maxFields === undefined ? 300 : maxFields
const initialShuffleVariant = isCloud ? 0 : 1; const initialShuffleVariant = isCloud ? 0 : 1;
const [paymentType, setPaymentType] = useState(0) const [paymentType, setPaymentType] = useState(0)
@@ -78,6 +77,12 @@ const LicencePopup = (props) => {
const [calculatedCost, setCalculatedCost] = useState("$600") const [calculatedCost, setCalculatedCost] = useState("$600")
const [selectedValue, setSelectedValue] = useState(100) const [selectedValue, setSelectedValue] = useState(100)
useEffect(() => {
if(selectedOrganization?.Billing?.Email !== BillingEmail) {
setBillingEmail(selectedOrganization?.Billing?.Email);
}
}, [selectedOrganization])
// Onprem // Onprem
const [calculatedCores, setCalculatedCores] = useState('600') const [calculatedCores, setCalculatedCores] = useState('600')
const [onpremSelectedValue, setOnpremSelectedValue] = useState(8) const [onpremSelectedValue, setOnpremSelectedValue] = useState(8)
@@ -88,7 +93,7 @@ const LicencePopup = (props) => {
const paperStyle = { const paperStyle = {
padding: 20, padding: 20,
borderRadius: theme.palette?.borderRadius, borderRadius: theme.palette?.borderRadius,
height: "100%", height: "100%"
} }
billingInfo.subscription = { billingInfo.subscription = {
@@ -101,7 +106,8 @@ const LicencePopup = (props) => {
"description": "Pay as you go", "description": "Pay as you go",
"features": [ "features": [
"Basic Support", "Basic Support",
"Limited App Runs (10.000)", "Includes 10.000 app run/month for free. ",
"Pay for what you use with no minimum commitment and cancel anytime."
], ],
"limit": 10000, "limit": 10000,
} }
@@ -137,13 +143,14 @@ const LicencePopup = (props) => {
}) })
} }
const SubscriptionObject = (props) => { const SubscriptionObject = (props) => {
const { globalUrl, index, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, subscription, highlight, } = props; const { globalUrl, index, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, subscription, highlight, } = props;
const [signatureOpen, setSignatureOpen] = React.useState(false); const [signatureOpen, setSignatureOpen] = React.useState(false);
const [tosChecked, setTosChecked] = React.useState(subscription.eula_signed) const [tosChecked, setTosChecked] = React.useState(subscription.eula_signed)
const [hovered, setHovered] = React.useState(false) const [hovered, setHovered] = React.useState(false)
const [newBillingEmail, setNewBillingEmail] = useState('');
var top_text = "Base Cloud Access" 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"
@@ -191,6 +198,58 @@ const LicencePopup = (props) => {
// newPaperstyle.border = "1px solid #f85a3e" // newPaperstyle.border = "1px solid #f85a3e"
} }
const handleClickOpen = () => {
setOpenChangeEmailBox(true);
};
const HandleChangeBillingEmail = (orgId) => {
const email = newBillingEmail;
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
if (!emailPattern.test(email)) {
toast("Please enter a valid email address");
return;
} else {
setNewBillingEmail(email);
}
toast("Updating billing email. Please Wait")
const data = {
org_id: orgId,
email: newBillingEmail,
billing: {
email: newBillingEmail,
},
};
const url = `${globalUrl}/api/v1/orgs/${orgId}/billing`;
fetch(url, {
method: "POST",
body: JSON.stringify(data),
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status !== 200) {
console.log("Bad status code in get org:", response.status);
}
return response.json();
}).then((responseJson) => {
if (responseJson.success === true) {
toast.success("Successfully updated billing email");
setBillingEmail(newBillingEmail);
setOpenChangeEmailBox(false);
} else {
toast.error("Failed to update billing email. Please try again.");
}
})
.catch((error) => {
console.log("Error getting org:", error);
});
}
return ( return (
<Tooltip <Tooltip
style={{ borderRadius: theme.palette?.borderRadius, }} style={{ borderRadius: theme.palette?.borderRadius, }}
@@ -308,7 +367,7 @@ const LicencePopup = (props) => {
color="primary" color="primary"
/> />
: null} : null}
<Typography variant="h6" style={{ marginTop: 10, marginBottom: 10, flex: 5, }}> <Typography variant="h6" style={{ marginTop: 10, marginBottom: 10, flex: 5, whiteSpace: 'nowrap' }}>
{top_text} {top_text}
</Typography> </Typography>
@@ -343,7 +402,7 @@ const LicencePopup = (props) => {
</div> </div>
<Divider /> <Divider />
<div> <div>
<Typography variant="body1" style={{ marginTop: 20, }}> <Typography variant="body1" style={{ marginTop: 20,whiteSpace: 'nowrap' }}>
{subscription.name} {subscription.name}
</Typography> </Typography>
@@ -443,21 +502,142 @@ const LicencePopup = (props) => {
}) })
: null} : null}
</ul> </ul>
{isCloud ? <Typography variant="body2" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
<span>Billing email: {selectedOrganization.org}</span> {subscription.name.includes("Scale") ?
""
:
userdata.has_card_available === true ?
"While you have a card attached to your account, Shuffle will no longer prevent workflows from running. Billing will occur at the start of each month."
:
isCloud ?
`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, open source plan. This plan has no enforced limits, but scale issues may occur due to CPU congestion.`
}
</Typography>
{isCloud && (userdata.has_card_available === true || selectedOrganization?.Billing?.Email?.length > 0 )?
<div>
<span>Billing email: {BillingEmail}</span>
<Button
variant="contained"
onClick={handleClickOpen}
style={{
width: 'auto',
height: 20,
textTransform: 'none',
marginLeft: 'auto',
backgroundColor: 'transparent',
color: '#FF8544',
boxShadow: 'none',
border: 'none',
cursor: 'pointer',
transition: 'background-color 0.3s, color 0.3s',
}}
>
Change
</Button>
<Dialog
open={openChangeEmailBox}
onClose={()=> {setOpenChangeEmailBox(false)}}
PaperProps={{
sx: {
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
border: theme?.palette?.DialogStyle?.border,
minWidth: '440px',
fontFamily: theme?.typography?.fontFamily,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
zIndex: 1000,
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogActions-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
}
}}
>
<DialogTitle style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Change Billing Email</DialogTitle>
<DialogContent>
<DialogContentText style={{ marginBottom: '20px', fontSize: 16, }}>
Enter the new billing email address.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="email"
label="New Billing Email"
type="email"
fullWidth
value={newBillingEmail}
onKeyPress={(event) => { if (event.key === 'Enter') HandleChangeBillingEmail(selectedOrganization.id) }}
onChange={(e) => setNewBillingEmail(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button
onClick={()=> {setOpenChangeEmailBox(false)}}
color="primary"
style={{ textTransform: 'none', marginRight: '10px' }}
>
Cancel
</Button>
<Button
style={{ textTransform: 'none', backgroundColor: "#ff8544", color: "#1a1a1a" }}
onClick={(event) => HandleChangeBillingEmail(selectedOrganization.id)}
>
Save
</Button>
</DialogActions>
</Dialog>
</div>
: null} : null}
</div> </div>
{isCloud ? (
<Button
fullWidth
disabled={false}
color="primary"
style={{
marginTop: !userdata.has_card_available ? 20 : 10,
borderRadius: 4,
height: 40,
fontSize: 16,
color: "#1a1a1a",
backgroundColor: "#ff8544",
// backgroundImage: userdata.has_card_available ? null : "linear-gradient(to right, #f86a3e, #f34079)",
textTransform: "none",
<Button }}
onClick={() => {
if (isCloud) {
handlePayasyougo(userdata, selectedOrganization, BillingEmail)
//navigate("/pricing?tab=cloud&highlight=true")
} else {
//window.open("https://shuffler.io/pricing?tab=onprem&highlight=true", "_blank")
handlePayasyougo()
}
}}
>
{userdata.has_card_available === true ?
"Manage Card Details"
:
"Add Card Details"
}
</Button> ) : null}
<Button
variant="outlined"
style={{ style={{
marginLeft: 115, marginTop: isCloud? 10 : 30,
marginTop: 50, borderRadius: 4,
borderRadius: 20, width: "100%",
width: 120,
color: "#FFFFFF",
cursor: "pointer", cursor: "pointer",
textTransform: "capitalize", textTransform: "capitalize",
backgroundColor: "transparent", backgroundColor: "transparent",
fontSize: 16,
position: "relative", // Required for positioning tooltip position: "relative", // Required for positioning tooltip
}} }}
title="Click to book a call" title="Click to book a call"
@@ -476,7 +656,7 @@ const LicencePopup = (props) => {
// } // }
}} }}
> >
<span style={{color: "#f85a3e",}}> <span>
Book a call Book a call
</span> </span>
<span <span
@@ -499,7 +679,6 @@ const LicencePopup = (props) => {
</span> </span>
</Button> </Button>
</Paper> </Paper>
{/* {/*
<div style={{ paddingRight: 150, display: "flex", alignItems: "baseline" }}> <div style={{ paddingRight: 150, display: "flex", alignItems: "baseline" }}>
@@ -547,14 +726,13 @@ const LicencePopup = (props) => {
} }
const handleChange = (event, newValue) => { const handleChange = (event, newValue) => {
console.log("Event, value: ", event.target, newValue)
if (shuffleVariant === 1) { if (shuffleVariant === 1) {
setSelectedValue(newValue) setSelectedValue(newValue)
if (newValue === 32) { if (newValue === 32) {
setCalculatedCost(`Get A Quote`) setCalculatedCost(`Get A Quote`)
} else { } else {
setCalculatedCost(`$${newValue * 75}`) setCalculatedCost(`$${newValue * 120}`)
} }
} else { } else {
setSelectedValue(newValue) setSelectedValue(newValue)
@@ -736,7 +914,7 @@ const LicencePopup = (props) => {
return ( return (
<div> <div>
<Grid container spacing={2} columns={16} style={{ flexDirection: "row", flexWrap: "nowrap", borderRadius: '16px', display: "flex" }}> <Grid container spacing={2} columns={16} style={{ flexDirection: "row", flexWrap: "nowrap", borderRadius: '16px', display: "flex", }}>
<Grid item xs={8}> <Grid item xs={8}>
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? {isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ?
<SubscriptionObject <SubscriptionObject
@@ -895,13 +1073,11 @@ const LicencePopup = (props) => {
</div> </div>
</div> </div>
<div style={{ marginTop: 20, }} /> <div style={{ marginTop: 20, }} />
</Card> <DialogActions style={{ marginTop: 15 }} >
</Grid> <div style={{display: 'flex', flexDirection: 'column', width: "100%", justifyContent: 'space-between', gap: "10px"}}>
</Grid>
</Grid>
<DialogActions style={{ marginTop: 15 }} >
<Button <Button
style={{ borderRadius: "0px", textTransform: "capitalize" }} style={{ borderRadius: "4px", textTransform: "capitalize", width: "100%", fontSize: 16}}
variant="outlined"
onClick={() => { onClick={() => {
if (isCloud) { if (isCloud) {
ReactGA.event({ ReactGA.event({
@@ -914,7 +1090,6 @@ const LicencePopup = (props) => {
} else { } else {
window.open("https://shuffler.io/pricing?tab=onprem", "_blank") window.open("https://shuffler.io/pricing?tab=onprem", "_blank")
} }
setModalOpen(false)
}} }}
color="primary" color="primary"
> >
@@ -922,7 +1097,7 @@ const LicencePopup = (props) => {
</Button> </Button>
<Button <Button
variant="contained" variant="contained"
style={{ borderRadius: 20, width: 120, textTransform: "capitalize" }} style={{ borderRadius: 4, textTransform: "capitalize", color: "#1a1a1a", backgroundColor: "#ff8544", width: "100%", fontSize: 16}}
onClick={() => { onClick={() => {
if (isCloud) { if (isCloud) {
ReactGA.event({ ReactGA.event({
@@ -948,7 +1123,12 @@ const LicencePopup = (props) => {
> >
Upgrade Upgrade
</Button> </Button>
</div>
</DialogActions> </DialogActions>
</Card>
</Grid>
</Grid>
</Grid>
</div> </div>
) )
} }
+40 -4
View File
@@ -141,6 +141,7 @@ const Header = (props) => {
const [subAnchorEl, setSubAnchorEl] = React.useState(null); const [subAnchorEl, setSubAnchorEl] = React.useState(null);
const [upgradeHovered, setUpgradeHovered] = React.useState(false); const [upgradeHovered, setUpgradeHovered] = React.useState(false);
const [showTopbar, setShowTopbar] = useState(false) // Set to true to show top bar const [showTopbar, setShowTopbar] = useState(false) // Set to true to show top bar
const [selectedOrganization, setSelectedOrganization] = useState({});
const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO" const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO"
let navigate = useNavigate(); let navigate = useNavigate();
const classes = useStyles(); const classes = useStyles();
@@ -222,10 +223,45 @@ const Header = (props) => {
window.location.host === "shuffler.io" || window.location.host === "shuffler.io" ||
window.location.host === "localhost:5002"; window.location.host === "localhost:5002";
const curpath = (typeof window !== "undefined" && window.location && typeof window.location.pathname === "string") const curpath = (typeof window !== "undefined" && window.location && typeof window.location.pathname === "string")
? window.location.pathname ? window.location.pathname
: ""; : "";
const handleGetOrg = (orgId) => {
fetch(`${globalUrl}/api/v1/orgs/${orgId}`, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status === 401) {
}
return response.json();
})
.then((responseJson) => {
if (responseJson["success"] === false) {
console.log("Error getting org: ", responseJson);
} else {
setSelectedOrganization(responseJson);
}
})
.catch((error) => {
console.log("Error getting org: ", error);
});
};
useEffect(() => {
if (isLoggedIn && userdata?.active_org?.id?.length > 0) {
handleGetOrg(userdata.active_org.id);
}
}, [isLoggedIn]);
// DEBUG HERE // DEBUG HERE
const handleClickLogout = () => { const handleClickLogout = () => {
console.log("SHOULD LOG OUT"); console.log("SHOULD LOG OUT");
@@ -441,7 +477,7 @@ const Header = (props) => {
}) })
</MenuItem> </MenuItem>
</Link> </Link>
<Link to="/usecases2" style={hrefStyle}> <Link to="/usecases" style={hrefStyle}>
<MenuItem <MenuItem
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
@@ -537,9 +573,9 @@ const Header = (props) => {
isLoaded={isLoaded} isLoaded={isLoaded}
isLoggedIn={isLoggedIn} isLoggedIn={isLoggedIn}
globalUrl={globalUrl} globalUrl={globalUrl}
selectedOrganization={selectedOrganization}
billingInfo={billingInfo} billingInfo={billingInfo}
isCloud={isCloud}
userdata={userdata} userdata={userdata}
stripeKey={stripeKey} stripeKey={stripeKey}
setModalOpen={setModalOpen} setModalOpen={setModalOpen}
@@ -590,7 +626,7 @@ const Header = (props) => {
</List> </List>
<List className={classes.menuList} component="nav"> <List className={classes.menuList} component="nav">
<ListItem style={{ textAlign: "center", marginLeft: "0px" }}> <ListItem style={{ textAlign: "center", marginLeft: "0px" }}>
<Link to="/usecases2" style={hrefStyle}> <Link to="/usecases" style={hrefStyle}>
<Button <Button
variant="text" variant="text"
color="secondary" color="secondary"
+111 -56
View File
@@ -255,7 +255,7 @@ const Priorities = memo((props) => {
onClick={() => { onClick={() => {
clearNotifications() clearNotifications()
}} }}
style={{marginLeft: 50, }} style={{marginLeft: 50, textTransform: "none", fontSize: 16}}
> >
Mark all as read Mark all as read
</Button> </Button>
@@ -265,7 +265,7 @@ const Priorities = memo((props) => {
{clickedFromOrgTab? null : <Divider style={{marginTop: 50, marginBottom: 50, }} />} {clickedFromOrgTab? null : <Divider style={{marginTop: 50, marginBottom: 50, }} />}
<h2 style={{ display: clickedFromOrgTab ? null:"inline", marginBottom: clickedFromOrgTab ? 8:null, marginTop: clickedFromOrgTab ? 30 :null, color: clickedFromOrgTab ? "#ffffff" : null }}>Suggestions</h2> <h2 style={{ display: clickedFromOrgTab ? null:"inline", marginBottom: clickedFromOrgTab ? 8:null, marginTop: clickedFromOrgTab ? 30 :null, color: clickedFromOrgTab ? "#ffffff" : null }}>Suggestions</h2>
<span style={{ fontSize: 16, color: clickedFromOrgTab ?"#9E9E9E":null,marginLeft: clickedFromOrgTab ?null:25 }}> <span style={{ fontSize: 16, color: clickedFromOrgTab ?"#9E9E9E":null,marginLeft: clickedFromOrgTab ?null:25, }}>
Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. <br/>These range from simple configurations in Shuffle to Usecases you may have missed.&nbsp; Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. <br/>These range from simple configurations in Shuffle to Usecases you may have missed.&nbsp;
<a <a
target="_blank" target="_blank"
@@ -409,8 +409,8 @@ const NotificationItem = memo((props) => {
{data.read === false ? {data.read === false ?
<Chip <Chip
label={"Unread"} label={"Unread"}
variant="outlined" variant="contained"
color="primary" color="secondary"
style={{marginRight: 15, height: 25, }} style={{marginRight: 15, height: 25, }}
/> />
: :
@@ -431,64 +431,119 @@ const NotificationItem = memo((props) => {
: :
null null
} }
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", wordWrap: "break-word" }}> <Typography variant="body2" color="textSecondary" style={{ marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", wordWrap: "break-word", fontSize: 16 }}>
{data.description} {data.description}
</Typography > </Typography >
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<ButtonGroup> <ButtonGroup style={{marginTop: 15, minHeight: 50, maxHeight: 50, }}>
<Button <Button
color="secondary" style={{
variant="outlined" textTransform: "none",
style={{ marginTop: 15 }} border: "1px solid #ff8544",
disabled={data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0} color: "#ff8544",
onClick={() => { opacity: data.reference_url ? 1 : 0.5,
window.open(data.reference_url, "_blank") cursor: data.reference_url ? "pointer" : "not-allowed",
}} }}
> disabled={
Explore !data.reference_url || data.reference_url.length === 0
</Button> }
{data.read === false ? ( onClick={() => {
<Button window.open(data.reference_url, "_blank");
color="secondary" }}
variant="outlined" >
style={{ marginTop: 15 }} Explore
onClick={() => { </Button>
dismissNotification(data.id);
}}
>
Dismiss
</Button>
) : null}
<Tooltip title="Disabling a notification makes it so similar notifications to this one will NOT be re-opened. It will NOT forward notifications to your notification workflow, but WILL still keep counting." placement="top">
<Button
color="secondary"
variant={data.ignored === true ? "contained" : "outlined"}
style={{ marginTop: 15, }}
onClick={() => {
if (data.ignored === true) {
dismissNotification(data.id, false)
} else {
dismissNotification(data.id, true)
}
}}
>
{data.ignored === true ? "Re-enable" : "Disable"}
</Button>
</Tooltip>
</ButtonGroup>
<Typography variant="body2" color="textSecondary" style={{ marginLeft: 20, marginTop: 20, wordWrap: "break-word", overflow: "hidden", textOverflow: "ellipsis" }}> {data.read === false ? (
<b>First seen</b>: {new Date(data.created_at * 1000).toISOString().slice(0, 19)} <Button
</Typography > variant="outlined"
color="secondary"
style={{
height: 50,
}}
onClick={() => {
dismissNotification(data.id);
}}
>
Mark Read
</Button>
) : null}
<Typography variant="body2" color="textSecondary" style={{ marginLeft: 20, marginTop: 20, wordWrap: "break-word", overflow: "hidden", textOverflow: "ellipsis" }}> <Tooltip
<b>Last seen</b>: {new Date(data.updated_at * 1000).toISOString().slice(0, 19)} title="Disabling a notification makes it so similar notifications to this one will NOT be re-opened. It will NOT forward notifications to your notification workflow, but WILL still keep counting."
</Typography > placement="top"
>
<Button
variant="outlined"
color="secondary"
style={{
textTransform: "none",
opacity: data.ignored || data.dismissable ? 1 : 0.5,
cursor: data.dismissable ? "pointer" : "not-allowed",
}}
disabled={!data.dismissable}
onClick={() => {
if (data.ignored) {
dismissNotification(data.id, false);
} else {
dismissNotification(data.id, true);
}
}}
>
{data.ignored ? "Re-enable" : "Disable"}
</Button>
</Tooltip>
</ButtonGroup>
<Typography
variant="body2"
color="textSecondary"
style={{
marginLeft: 20,
marginTop: 20,
wordWrap: "break-word",
overflow: "hidden",
textOverflow: "ellipsis",
fontSize: 16,
}}
>
<b>First seen</b>:{" "}
{new Date(data.created_at * 1000).toISOString().slice(0, 19)}
</Typography>
<Typography
variant="body2"
color="textSecondary"
style={{
marginLeft: 20,
marginTop: 20,
wordWrap: "break-word",
overflow: "hidden",
textOverflow: "ellipsis",
fontSize: 16,
}}
>
<b>Last seen</b>:{" "}
{new Date(data.updated_at * 1000).toISOString().slice(0, 19)}
</Typography>
<Typography
variant="body2"
color="textSecondary"
style={{
marginLeft: 20,
marginTop: 20,
wordWrap: "break-word",
overflow: "hidden",
textOverflow: "ellipsis",
fontSize: 16,
}}
>
<b>Times seen</b>: {data.amount}
</Typography>
</div>
<Typography variant="body2" color="textSecondary" style={{ marginLeft: 20, marginTop: 20, wordWrap: "break-word", overflow: "hidden", textOverflow: "ellipsis" }}>
<b>Times seen</b>: {data.amount}
</Typography >
</div>
</Paper> </Paper>
); );
}) })
+1 -1
View File
@@ -154,7 +154,7 @@ const Priority = (props) => {
} }
</div> </div>
<div style={{flex: 1, display: "flex", marginLeft: 30, }}> <div style={{flex: 1, display: "flex", marginLeft: 30, }}>
<Button style={{height: 50, borderRadius: 25, fontSize:16, boxShadow: clickedFromOrgTab ? "none":null,textTransform: clickedFromOrgTab ? 'capitalize':null, marginTop: 8, width: 175, marginRight: 10, color: priority.active === false ? "white" :clickedFromOrgTab ?"#FF8444": "black", backgroundColor: priority.active === false ? theme.palette.inputColor :clickedFromOrgTab?"rgba(255, 132, 68, 0.2)":"rgba(255,255,255,0.8)", }} variant="contained" color="secondary" onClick={() => { <Button style={{height: 50, borderRadius: 4, fontSize:16, boxShadow: clickedFromOrgTab ? "none":null,textTransform: clickedFromOrgTab ? 'capitalize':null, marginTop: 8, width: 175, marginRight: 10, color: priority.active === false ? "white" :clickedFromOrgTab ?"#ff8544": "black", backgroundColor: priority.active === false ? theme.palette.inputColor :clickedFromOrgTab?"transparent":"rgba(255,255,255,0.8)", border: "1px solid #ff8544"}} variant="contained" color="secondary" onClick={() => {
if (isCloud) { if (isCloud) {
ReactGA.event({ ReactGA.event({
+3 -2
View File
@@ -238,7 +238,7 @@ const Admin2 = (props) => {
const data = { const data = {
name: name, name: name,
description: description, description: description,
org_id: orgId, org_id: orgId?.length > 0 ? orgId : selectedOrganization?.id,
image: image, image: image,
defaults: defaults, defaults: defaults,
sso_config: sso_config, sso_config: sso_config,
@@ -263,6 +263,7 @@ const Admin2 = (props) => {
if (responseJson["success"] === false) { if (responseJson["success"] === false) {
toast("Failed updating org: ", responseJson.reason); toast("Failed updating org: ", responseJson.reason);
} else { } else {
handleGetOrg(selectedOrganization?.id);
if ( if (
lead_info === undefined || lead_info === undefined ||
lead_info === null || lead_info === null ||
@@ -329,7 +330,7 @@ const Admin2 = (props) => {
} }
return ( return (
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 0.8, }}> <div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 0.9}}>
<AdminNavBar userdata={userdata} isLoaded={isLoaded} selectedStatus={selectedStatus} setSelectedStatus={setSelectedStatus} selectedTab={selectedTab} orgId={selectedOrganization.id} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} setNotifications={setNotifications} stripeKey={stripeKey} notifications={notifications} checkLogin={checkLogin} globalUrl={globalUrl} isCloud={isCloud} serverside={serverside} /> <AdminNavBar userdata={userdata} isLoaded={isLoaded} selectedStatus={selectedStatus} setSelectedStatus={setSelectedStatus} selectedTab={selectedTab} orgId={selectedOrganization.id} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization} setNotifications={setNotifications} stripeKey={stripeKey} notifications={notifications} checkLogin={checkLogin} globalUrl={globalUrl} isCloud={isCloud} serverside={serverside} />
</div> </div>
); );
+50 -37
View File
@@ -4859,7 +4859,7 @@ const releaseToConnectLabel = "Release to Connect"
// This causes memory referencing to become a nightmare // This causes memory referencing to become a nightmare
const data = event.target.data() const data = event.target.data()
if (data.app_name === "Shuffle Workflow") { if (data.app_name === "Shuffle Workflow") {
if ((data.parameters !== undefined) && (data.parameters.length > 0)) { if ((data?.parameters !== undefined) && (data?.parameters?.length > 0)) {
getWorkflowApps(data.parameters[0].value) getWorkflowApps(data.parameters[0].value)
} }
} }
@@ -10657,7 +10657,7 @@ const releaseToConnectLabel = "Release to Connect"
return( return(
<div style={{marginLeft: index !== 0 ? 5 : 0, }}> <div key={index} style={{marginLeft: index !== 0 ? 5 : 0, }}>
<ParsedAppPaper small={true} action={trigger.name} app={JSON.parse(JSON.stringify(trigger))} /> <ParsedAppPaper small={true} action={trigger.name} app={JSON.parse(JSON.stringify(trigger))} />
</div> </div>
) )
@@ -11200,7 +11200,7 @@ const releaseToConnectLabel = "Release to Connect"
const minSize = 370 const minSize = 370
var rightsidebarStyle = { var rightsidebarStyle = {
position: "fixed", position: "fixed",
top: appBarSize - 35, top: workflow?.public && !isLoggedIn ? 100 : showWorkflowRevisions ? 100 : appBarSize - 35,
right: 25, right: 25,
height: "90vh", height: "90vh",
maxWidth: 600, maxWidth: 600,
@@ -13218,7 +13218,7 @@ const releaseToConnectLabel = "Release to Connect"
}; };
if (Object.getOwnPropertyNames(selectedTrigger).length > 0) { if (Object.getOwnPropertyNames(selectedTrigger)?.length > 0) {
if (workflow.triggers[selectedTriggerIndex] === undefined) { if (workflow.triggers[selectedTriggerIndex] === undefined) {
return null; return null;
} }
@@ -14378,7 +14378,7 @@ const releaseToConnectLabel = "Release to Connect"
// Special SCHEDULE handler // Special SCHEDULE handler
var trigger_header_auth = "" var trigger_header_auth = ""
if (Object.getOwnPropertyNames(selectedTrigger).length > 0 && workflow.triggers !== null && workflow.triggers !== undefined && workflow.triggers.length >= selectedTriggerIndex && workflow.triggers[selectedTriggerIndex] !== undefined ) { if (Object.getOwnPropertyNames(selectedTrigger)?.length > 0 && workflow?.triggers !== null && workflow?.triggers !== undefined && workflow?.triggers?.length >= selectedTriggerIndex && workflow?.triggers[selectedTriggerIndex] !== undefined ) {
if (selectedTrigger.trigger_type === "SCHEDULE" && workflow.triggers[selectedTriggerIndex].parameters === undefined || workflow.triggers[selectedTriggerIndex].parameters === null) { if (selectedTrigger.trigger_type === "SCHEDULE" && workflow.triggers[selectedTriggerIndex].parameters === undefined || workflow.triggers[selectedTriggerIndex].parameters === null) {
console.log("Autofixing schedule") console.log("Autofixing schedule")
@@ -14447,7 +14447,7 @@ const releaseToConnectLabel = "Release to Connect"
if ( if (
workflow.triggers[selectedTriggerIndex].parameters === undefined || workflow.triggers[selectedTriggerIndex].parameters === undefined ||
workflow.triggers[selectedTriggerIndex].parameters === null || workflow.triggers[selectedTriggerIndex].parameters === null ||
workflow.triggers[selectedTriggerIndex].parameters.length === 0 workflow?.triggers[selectedTriggerIndex]?.parameters?.length === 0
) { ) {
workflow.triggers[selectedTriggerIndex].parameters = []; workflow.triggers[selectedTriggerIndex].parameters = [];
workflow.triggers[selectedTriggerIndex].parameters[0] = { workflow.triggers[selectedTriggerIndex].parameters[0] = {
@@ -14485,7 +14485,7 @@ const releaseToConnectLabel = "Release to Connect"
} }
} }
const WebhookSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined || selectedTrigger.trigger_type !== "WEBHOOK" ? null : const WebhookSidebar =!selectedTrigger || Object.getOwnPropertyNames(selectedTrigger)?.length === 0 || !workflow?.triggers || workflow?.triggers[selectedTriggerIndex] === undefined || selectedTrigger?.trigger_type !== "WEBHOOK" ? null :
<div style={appApiViewStyle}> <div style={appApiViewStyle}>
<h3 style={{ marginBottom: "5px" }}> <h3 style={{ marginBottom: "5px" }}>
{selectedTrigger.app_name}: {selectedTrigger.status} {selectedTrigger.app_name}: {selectedTrigger.status}
@@ -14752,8 +14752,8 @@ const releaseToConnectLabel = "Release to Connect"
</div> </div>
<TextField <TextField
style={{ style={{
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.textFieldStyle.backgroundColor,
borderRadius: theme.palette?.borderRadius, borderRadius: theme.palette.textFieldStyle.borderRadius,
}} }}
id="webhook_uri_field" id="webhook_uri_field"
onClick={() => { onClick={() => {
@@ -15217,7 +15217,7 @@ const releaseToConnectLabel = "Release to Connect"
}) })
} }
const UserinputSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined || selectedTrigger.trigger_type !== "USERINPUT" ? null : const UserinputSidebar = !selectedTrigger || Object.getOwnPropertyNames(selectedTrigger)?.length === 0 || !workflow?.triggers || !workflow?.triggers[selectedTriggerIndex] || !selectedTrigger.trigger_type || selectedTrigger.trigger_type !== "USERINPUT" ? null :
<div style={appApiViewStyle}> <div style={appApiViewStyle}>
<h3 style={{ marginBottom: "5px" }}> <h3 style={{ marginBottom: "5px" }}>
{selectedTrigger.app_name} {selectedTrigger.app_name}
@@ -15378,7 +15378,13 @@ const releaseToConnectLabel = "Release to Connect"
label={<div style={{ color: "white" }}>SMS</div>} label={<div style={{ color: "white" }}>SMS</div>}
/> />
</FormGroup> </FormGroup>
{workflow.triggers[selectedTriggerIndex].parameters[2] !== undefined && workflow.triggers[selectedTriggerIndex].parameters[2].value.includes("subflow") ? ( {workflow?.triggers &&
workflow?.triggers[selectedTriggerIndex] &&
workflow?.triggers[selectedTriggerIndex].parameters &&
workflow?.triggers[selectedTriggerIndex].parameters[2] &&
workflow?.triggers[selectedTriggerIndex].parameters[2].value &&
workflow?.triggers[selectedTriggerIndex].parameters[2].value.includes("subflow")
? (
<div style={{ }}> <div style={{ }}>
{workflows === undefined || {workflows === undefined ||
workflows === null || workflows === null ||
@@ -15506,9 +15512,13 @@ const releaseToConnectLabel = "Release to Connect"
</div> </div>
) : null} ) : null}
{workflow.triggers[selectedTriggerIndex].parameters[2] !== {workflow?.triggers &&
undefined && workflow?.triggers[selectedTriggerIndex] &&
workflow.triggers[selectedTriggerIndex].parameters[2].value.includes("email") ? ( workflow?.triggers[selectedTriggerIndex].parameters &&
workflow?.triggers[selectedTriggerIndex].parameters[2] &&
workflow?.triggers[selectedTriggerIndex].parameters[2].value &&
workflow?.triggers[selectedTriggerIndex].parameters[2].value.includes("email")
? (
<TextField <TextField
style={{ style={{
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.inputColor,
@@ -15538,11 +15548,15 @@ const releaseToConnectLabel = "Release to Connect"
/> />
) : null} ) : null}
{workflow.triggers[selectedTriggerIndex].parameters[2] !== {workflow?.triggers &&
undefined && workflow?.triggers[selectedTriggerIndex] &&
workflow.triggers[ workflow?.triggers[selectedTriggerIndex].parameters &&
selectedTriggerIndex workflow?.triggers[selectedTriggerIndex].parameters[2] &&
].parameters[2].value.includes("sms") ? ( workflow?.triggers[selectedTriggerIndex].parameters[2].value &&
(
workflow?.triggers[selectedTriggerIndex].parameters[2].value.includes("email") ||
workflow?.triggers[selectedTriggerIndex].parameters[2].value.includes("sms")
) ? (
<TextField <TextField
style={{ style={{
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.inputColor,
@@ -15639,7 +15653,7 @@ const releaseToConnectLabel = "Release to Connect"
selectedTrigger.environment = defaultEnvironment.Name selectedTrigger.environment = defaultEnvironment.Name
setSelectedTrigger(selectedTrigger) } setSelectedTrigger(selectedTrigger) }
const PipelineSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined && selectedTrigger.trigger_type !== "SCHEDULE" ? null : const PipelineSidebar = !selectedTrigger || Object.getOwnPropertyNames(selectedTrigger)?.length === 0 || !workflow?.triggers || !workflow?.triggers[selectedTriggerIndex] || !selectedTrigger.trigger_type || selectedTrigger.trigger_type !== "SCHEDULE" ? null :
<div style={appApiViewStyle}> <div style={appApiViewStyle}>
<h3 style={{ marginBottom: "5px" }}> <h3 style={{ marginBottom: "5px" }}>
{selectedTrigger.app_name}: {selectedTrigger.status} {selectedTrigger.app_name}: {selectedTrigger.status}
@@ -15901,7 +15915,7 @@ const releaseToConnectLabel = "Release to Connect"
</div> </div>
</div> </div>
const ScheduleSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined && selectedTrigger.trigger_type !== "SCHEDULE" ? null : const ScheduleSidebar = !selectedTrigger || Object.getOwnPropertyNames(selectedTrigger)?.length === 0 || !workflow?.triggers || !workflow?.triggers[selectedTriggerIndex] && (!selectedTrigger.trigger_type || selectedTrigger.trigger_type !== "SCHEDULE") ? null :
<div style={appApiViewStyle}> <div style={appApiViewStyle}>
<h3 style={{ marginBottom: "5px" }}> <h3 style={{ marginBottom: "5px" }}>
{selectedTrigger.app_name}: {selectedTrigger.status} {selectedTrigger.app_name}: {selectedTrigger.status}
@@ -16158,9 +16172,8 @@ const releaseToConnectLabel = "Release to Connect"
position: "absolute", position: "absolute",
top: isMobile ? 30 : 25, top: isMobile ? 30 : 25,
left: isMobile ? 20 : leftSideBarOpenByClick ? leftBarSize + 275 : leftBarSize+135, transform: isMobile ? "translateX(20px)" : `translateX(${leftBarSize}px)`,
transition: "all 0.3s ease",
transition: "left 0.3s ease",
zoom: 0.9, zoom: 0.9,
} }
@@ -16922,7 +16935,7 @@ const releaseToConnectLabel = "Release to Connect"
border: "1px solid rgba(255,255,255,0.1)", border: "1px solid rgba(255,255,255,0.1)",
position: "absolute", position: "absolute",
bottom: 100, bottom: 100,
left: leftSideBarOpenByClick ? leftBarSize+300 : leftBarSize+115, left: leftSideBarOpenByClick ? leftBarSize+270 : leftBarSize+115,
color: "white", color: "white",
padding: 10, padding: 10,
@@ -17374,8 +17387,8 @@ const releaseToConnectLabel = "Release to Connect"
color="secondary" color="secondary"
variant="text" variant="text"
style={{ style={{
height: workflow.public ? 100 : buttonHeights, height: buttonHeights,
width: workflow.public ? 100 : 64, width: 64,
}} }}
variant={ variant={
lastSaved && !workflow.public ? "text" : "contained" lastSaved && !workflow.public ? "text" : "contained"
@@ -17619,7 +17632,7 @@ const releaseToConnectLabel = "Release to Connect"
defaultReturn = <CommentSidebar /> defaultReturn = <CommentSidebar />
} else if (Object.getOwnPropertyNames(selectedTrigger).length > 0) { } else if (Object.getOwnPropertyNames(selectedTrigger).length > 0) {
if (selectedTrigger.trigger_type === undefined) { if (selectedTrigger.trigger_type === undefined) {
//defaultReturn = <UserinputSidebar /> // defaultReturn = <UserinputSidebar />
return null; return null;
} else { } else {
/* /*
@@ -17776,7 +17789,7 @@ const releaseToConnectLabel = "Release to Connect"
<Typography variant="body1" style={{ marginRight: 10, }}> <Typography variant="body1" style={{ marginRight: 10, }}>
Tags Tags
</Typography> </Typography>
<div style={{ display: "flex" }}> <div style={{ display: "flex", flexWrap: 'wrap', gap: 5, }}>
{workflow.tags.map((tag, index) => { {workflow.tags.map((tag, index) => {
if (index >= 3) { if (index >= 3) {
return null; return null;
@@ -17958,9 +17971,8 @@ const releaseToConnectLabel = "Release to Connect"
</Typography> </Typography>
<Button <Button
color="primary" color="primary"
variant="contained"
fullWidth fullWidth
style={{ marginTop: 15, }} style={{ marginTop: 15, backgroundColor: "#ff8544", color: "#1a1a1a", fontSize: 16, textTransform: "none" }}
onClick={() => { onClick={() => {
// Further checks are being done on the backend // Further checks are being done on the backend
// Even if the user can "edit" a workflow on the frontend, // Even if the user can "edit" a workflow on the frontend,
@@ -17990,7 +18002,7 @@ const releaseToConnectLabel = "Release to Connect"
variant="outlined" variant="outlined"
disabled={workflow.public !== true} disabled={workflow.public !== true}
fullWidth fullWidth
style={{ marginTop: 15, }} style={{ marginTop: 15, textTransform: "none", fontSize: 16}}
onClick={() => { onClick={() => {
// setEditWorkflowDetails(true) // setEditWorkflowDetails(true)
// workflow.public = false // workflow.public = false
@@ -20554,7 +20566,7 @@ const releaseToConnectLabel = "Release to Connect"
); );
const newView = ( const newView = (
<div style={{ color: "white", marginLeft: leftSideBarOpenByClick ? 280 : 100, transition: "margin-left 0.3s ease", }}> <div style={{ color: "white", marginLeft: leftSideBarOpenByClick ? workflow?.public ? 210 : 250 : workflow?.public ? isLoggedIn ? 60 : 0 : isLoggedIn ? 100 : 0, transition: "margin-left 0.3s ease", overflow: 'hidden' }}>
<div <div
style={{ display: "flex", borderTop: "0px solid rgba(91, 96, 100, 1)" }} style={{ display: "flex", borderTop: "0px solid rgba(91, 96, 100, 1)" }}
> >
@@ -20590,8 +20602,8 @@ const releaseToConnectLabel = "Release to Connect"
maxZoom={2.0} maxZoom={2.0}
wheelSensitivity={0.25} wheelSensitivity={0.25}
style={{ style={{
width: cytoscapeWidth, width: workflow?.public && !isLoggedIn ? cytoscapeWidth + 50 : cytoscapeWidth ,
height: bodyHeight - 5, height: workflow?.public && !isLoggedIn ? (bodyHeight - 50) : bodyHeight - 2,
backgroundColor: theme.palette.surfaceColor, backgroundColor: theme.palette.surfaceColor,
}} }}
stylesheet={cystyle} stylesheet={cystyle}
@@ -20678,7 +20690,7 @@ const releaseToConnectLabel = "Release to Connect"
{/* Most important: Actions. But these are a lot more complex */} {/* Most important: Actions. But these are a lot more complex */}
{rightSideBarOpen && (selectedTrigger.trigger_type === "SCHEDULE" || selectedTrigger.trigger_type === "WEBHOOK" || selectedTrigger.trigger_type === "PIPELINE" || selectedTrigger.trigger_type === "USERINPUT") ? {rightSideBarOpen && (selectedTrigger.trigger_type === "SCHEDULE" || selectedTrigger.trigger_type === "WEBHOOK" || selectedTrigger.trigger_type === "PIPELINE" || selectedTrigger.trigger_type === "USERINPUT") ?
<div id="rightside_actions" style={rightsidebarStyle}> <div id="rightside_actions" style={rightsidebarStyle}>
{Object.getOwnPropertyNames(selectedTrigger).length > 0 ? {Object.getOwnPropertyNames(selectedTrigger)?.length > 0 ?
selectedTrigger.trigger_type === "SCHEDULE" ? selectedTrigger.trigger_type === "SCHEDULE" ?
ScheduleSidebar ScheduleSidebar
: selectedTrigger.trigger_type === "PIPELINE" ? : selectedTrigger.trigger_type === "PIPELINE" ?
@@ -20693,7 +20705,7 @@ const releaseToConnectLabel = "Release to Connect"
: null} : null}
{ {
rightSideBarOpen && selectedTrigger.trigger_type === "SUBFLOW"&& Object.getOwnPropertyNames(selectedTrigger).length > 0 ? rightSideBarOpen && selectedTrigger?.trigger_type === "SUBFLOW"&& Object.getOwnPropertyNames(selectedTrigger)?.length > 0 ?
<div id="rightside_actions" style={rightsidebarStyle}> <div id="rightside_actions" style={rightsidebarStyle}>
<SubflowSidebar/> <SubflowSidebar/>
</div> : null </div> : null
@@ -22033,6 +22045,7 @@ const releaseToConnectLabel = "Release to Connect"
<Paper <Paper
style={{padding: "15px 15px 15px 25px", minHeight: 105, maxHeight: 105, cursor: "pointer", backgroundColor: newrevision.edited === selectedVersion.edited ? "rgba(255,255,255,0.3)" : theme.palette.surfaceColor, border: showBorder === true ? `1px solid ${green}` : "1px solid rgba(255,255,255,0.3)", marginBottom: 10, style={{padding: "15px 15px 15px 25px", minHeight: 105, maxHeight: 105, cursor: "pointer", backgroundColor: newrevision.edited === selectedVersion.edited ? "rgba(255,255,255,0.3)" : theme.palette.surfaceColor, border: showBorder === true ? `1px solid ${green}` : "1px solid rgba(255,255,255,0.3)", marginBottom: 10,
}} onClick={(e) => { }} onClick={(e) => {
setRightSideBarOpen(false)
if (newrevision.edited === selectedVersion.edited) { if (newrevision.edited === selectedVersion.edited) {
console.log("Same revision! No setting.") console.log("Same revision! No setting.")
return return
+7 -4
View File
@@ -64,6 +64,7 @@ const inputColor = "#383B40";
const bodyDivStyle = { const bodyDivStyle = {
margin: "auto", margin: "auto",
width: "900px", width: "900px",
zoom: 0.8,
}; };
const actionListStyle = { const actionListStyle = {
@@ -72,10 +73,11 @@ const actionListStyle = {
paddingBottom: "10px", paddingBottom: "10px",
paddingTop: "10px", paddingTop: "10px",
marginTop: "5px", marginTop: "5px",
backgroundColor: inputColor,
display: "flex", display: "flex",
color: "white", color: "white",
position: "relative", position: "relative",
backgroundColor: theme.palette.platformColor,
}; };
const boxStyle = { const boxStyle = {
@@ -89,7 +91,8 @@ const boxStyle = {
paddingTop: "30px", paddingTop: "30px",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
backgroundColor: surfaceColor,
backgroundColor: theme.palette.backgroundColor,
}; };
const dividerStyle = { const dividerStyle = {
@@ -6191,7 +6194,7 @@ const AppCreator = (defaultprops) => {
{testView} {testView}
*/} */}
<div style={{height: 50, padding: 25, display: "flex", marginTop: 35, position: "fixed", bottom: 0, left: 0, width: "100%", backgroundColor: theme.palette?.backgroundColor, borderTop: "1px solid rgba(255,255,255,0.3)",}}> <div style={{height: 50, padding: 15, display: "flex", marginTop: 35, position: "fixed", bottom: 0, left: 0, width: "100%", backgroundColor: theme.palette?.backgroundColor, borderTop: "1px solid rgba(255,255,255,0.3)",}}>
<div style={{width: 450, margin: "auto", display: "flex", textAlign: "center", }}> <div style={{width: 450, margin: "auto", display: "flex", textAlign: "center", }}>
{appDownloadData.length > 0 ? {appDownloadData.length > 0 ?
<Tooltip title="Download the OpenAPI specification for the App" placement="bottom"> <Tooltip title="Download the OpenAPI specification for the App" placement="bottom">
+141 -83
View File
@@ -20,14 +20,18 @@ import {
IconButton, IconButton,
} from "@mui/material"; } from "@mui/material";
import { Context } from "../context/ContextApi.jsx"; import { Context } from "../context/ContextApi.jsx";
import Add from '@mui/icons-material/Add';
import CachedIcon from '@mui/icons-material/Cached'; import {
import CloudDownloadIcon from '@mui/icons-material/CloudDownload'; Add as AddIcon,
import EditIcon from '@mui/icons-material/Edit'; Edit as EditIcon,
Search as SearchIcon,
Clear as ClearIcon,
Close as CloseIcon,
Cached as CachedIcon,
CloudDownload as CloudDownloadIcon,
} from "@mui/icons-material";
import InputAdornment from '@mui/material/InputAdornment'; import InputAdornment from '@mui/material/InputAdornment';
import Search from '@mui/icons-material/Search';
import ClearIcon from '@mui/icons-material/Clear';
import CloseIcon from '@mui/icons-material/Close';
import { ClearRefinements, connectHits, connectSearchBox, connectStateResults, InstantSearch, RefinementList, connectRefinementList, Configure } from "react-instantsearch-dom"; import { ClearRefinements, connectHits, connectSearchBox, connectStateResults, InstantSearch, RefinementList, connectRefinementList, Configure } from "react-instantsearch-dom";
import { removeQuery } from "../components/ScrollToTop.jsx"; import { removeQuery } from "../components/ScrollToTop.jsx";
@@ -45,7 +49,7 @@ const searchClient = algoliasearch(
); );
// AppCard Component // AppCard Component
const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata }) => { const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata, fetchApps }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000"; const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000";
const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`; const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`;
@@ -117,9 +121,17 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
fontWeight: 600, fontWeight: 600,
whiteSpace: "nowrap", whiteSpace: "nowrap",
marginLeft: 8, marginLeft: 8,
maxWidth: "90%",
gap: 8 gap: 8
}}> }}>
{data.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())} <div style={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
color: '#F1F1F1'
}}>
{data.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())}
</div>
</div> </div>
<div style={{ <div style={{
overflow: "hidden", overflow: "hidden",
@@ -182,12 +194,13 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
<Button <Button
className="deactivate-button" className="deactivate-button"
sx={{ sx={{
width: 102, width: 110,
height: 35, height: 35,
borderRadius: 0.75, borderRadius: 0.75,
bgcolor: "rgba(73, 73, 73, 1)", bgcolor: "rgba(73, 73, 73, 1)",
color: "rgba(241, 241, 241, 1)", color: "rgba(241, 241, 241, 1)",
textTransform: "none", textTransform: "none",
fontSize: 16,
fontFamily: theme?.typography?.fontFamily, fontFamily: theme?.typography?.fontFamily,
transition: "background-color 0.3s ease", transition: "background-color 0.3s ease",
"&:hover": { "&:hover": {
@@ -213,6 +226,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
toast.error(responseJson.reason); toast.error(responseJson.reason);
} else { } else {
toast.success("App Deactivated Successfully."); toast.success("App Deactivated Successfully.");
fetchApps();
} }
}) })
.catch(error => { .catch(error => {
@@ -445,13 +459,21 @@ const Hits = ({
overflow: "hidden", overflow: "hidden",
gap: 8, gap: 8,
fontWeight: 600, fontWeight: 600,
maxWidth: "90%",
textOverflow: "ellipsis", textOverflow: "ellipsis",
whiteSpace: "nowrap", whiteSpace: "nowrap",
color: '#F1F1F1' color: '#F1F1F1'
}} }}
> >
{(allActivatedAppIds && allActivatedAppIds.includes(data.objectID)) && <Box sx={{ width: 8, height: 8, backgroundColor: "#02CB70", borderRadius: '50%' }} />} {(allActivatedAppIds && allActivatedAppIds.includes(data.objectID)) && <Box sx={{ width: 8, height: 8, backgroundColor: "#02CB70", borderRadius: '50%' }} />}
{normalizedString(data.name)} <div style={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
color: '#F1F1F1'
}}>
{normalizedString(data.name)}
</div>
</div> </div>
<div <div
@@ -535,18 +557,19 @@ const Hits = ({
paddingRight: 10, paddingRight: 10,
minWidth: 110 minWidth: 110
}}> }}>
{hoverEffect === index && isCloud && ( {hoverEffect === index && (
<div> <div>
{allActivatedAppIds && allActivatedAppIds.includes(data.objectID) ? ( {allActivatedAppIds && allActivatedAppIds.includes(data.objectID) ? (
<Button <Button
style={{ style={{
width: 102, width: 110,
height: 35, height: 35,
borderRadius: 3, borderRadius: 4,
backgroundColor: "rgba(73, 73, 73, 1)", backgroundColor: "rgba(73, 73, 73, 1)",
color: "rgba(241, 241, 241, 1)", color: "rgba(241, 241, 241, 1)",
textTransform: "none", textTransform: "none",
fontFamily: theme?.typography?.fontFamily, fontFamily: theme?.typography?.fontFamily,
fontSize: 16,
}} }}
onClick={(event) => { onClick={(event) => {
handleActivateButton(event, data, "deactivate"); handleActivateButton(event, data, "deactivate");
@@ -560,9 +583,10 @@ const Hits = ({
color: "black", color: "black",
width: 102, width: 102,
height: 35, height: 35,
borderRadius: 3, borderRadius: 4,
textTransform: "none", textTransform: "none",
fontFamily: theme?.typography?.fontFamily, fontFamily: theme?.typography?.fontFamily,
fontSize: 16
}} }}
onClick={(event) => { onClick={(event) => {
handleActivateButton(event, data, "activate"); handleActivateButton(event, data, "activate");
@@ -655,15 +679,15 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
event.preventDefault(); event.preventDefault();
} }
}} }}
style={{ borderRadius: 8, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }} style={{ borderRadius: 4, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }}
InputProps={{ InputProps={{
style: { style: {
borderRadius: 8, borderRadius: 4,
height: 45 height: 45
}, },
endAdornment: ( endAdornment: (
<InputAdornment position="end"> <InputAdornment position="end">
{localQuery?.length === 0 ? <Search /> : ( {localQuery?.length === 0 ? <SearchIcon /> : (
<ClearIcon <ClearIcon
style={{ style={{
cursor: "pointer", cursor: "pointer",
@@ -703,7 +727,7 @@ const CategoryDropdown = ({ items, currentRefinement, refine }) => {
onChange={handleChange} onChange={handleChange}
displayEmpty displayEmpty
multiple multiple
style={{ borderRadius: 8, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }} style={{ borderRadius: 4, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }}
renderValue={(selected) => { renderValue={(selected) => {
if (selected.length === 0) return 'All Categories'; if (selected.length === 0) return 'All Categories';
return ( return (
@@ -764,7 +788,7 @@ const LabelDropdown = ({ items, currentRefinement, refine }) => {
onChange={handleChange} onChange={handleChange}
displayEmpty displayEmpty
multiple multiple
style={{ borderRadius: 8, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }} style={{ borderRadius: 4, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }}
renderValue={(selected) => { renderValue={(selected) => {
if (selected.length === 0) return 'All Labels'; if (selected.length === 0) return 'All Labels';
return ( return (
@@ -855,7 +879,7 @@ const AppSkeleton = () => {
backgroundColor: "#212121", backgroundColor: "#212121",
width: "100%", width: "100%",
height: 120, height: 120,
borderRadius: 8, borderRadius: 4,
}}> }}>
<div style={{ <div style={{
display: "flex", display: "flex",
@@ -868,7 +892,7 @@ const AppSkeleton = () => {
width={100} width={100}
height={90} height={90}
style={{ style={{
borderRadius: 6, borderRadius: 4,
backgroundColor: "rgba(255, 255, 255, 0.1)" backgroundColor: "rgba(255, 255, 255, 0.1)"
}} }}
/> />
@@ -1024,43 +1048,43 @@ const Apps2 = (props) => {
}, []); }, []);
// Fetch apps based on the current tab : 0 -> org_apps, 1 -> my_apps, 2 -> all_apps // Fetch apps based on the current tab : 0 -> org_apps, 1 -> my_apps, 2 -> all_apps
useEffect(() => { const fetchApps = async () => {
const fetchApps = async () => { const baseUrl = globalUrl;
const baseUrl = globalUrl; let url;
let url; setIsLoading(true);
setIsLoading(true); const userId = userdata?.id;
const userId = userdata?.id; if (currTab === 1 && userId) {
if (currTab === 1 && userId) { url = `${baseUrl}/api/v1/users/${userId}/apps`;
url = `${baseUrl}/api/v1/users/${userId}/apps`; } else if (currTab === 0) {
url = `${baseUrl}/api/v1/apps`;
}
try {
const response = await fetch(url, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
if (currTab === 1) {
setAppsToShow(data);
setUserApps(data);
} else if (currTab === 0) { } else if (currTab === 0) {
url = `${baseUrl}/api/v1/apps`; setAppsToShow(data);
setOrgApps(data);
// For testing the empty state
// setAppsToShow([]);
// setOrgApps([]);
} }
try { setIsLoading(false);
const response = await fetch(url, { } catch (err) {
method: "GET", console.error("Error fetching apps:", err);
credentials: "include", setIsLoading(false);
headers: { }
"Content-Type": "application/json", };
},
});
const data = await response.json();
if (currTab === 1) {
setAppsToShow(data);
setUserApps(data);
} else if (currTab === 0) {
setAppsToShow(data);
setOrgApps(data);
// For testing the empty state
// setAppsToShow([]);
// setOrgApps([]);
}
setIsLoading(false);
} catch (err) {
console.error("Error fetching apps:", err);
setIsLoading(false);
}
};
useEffect(() => {
// Only fetch if we have required data // Only fetch if we have required data
if (globalUrl && (currTab === 0 || (currTab === 1 && userdata?.id))) { if (globalUrl && (currTab === 0 || (currTab === 1 && userdata?.id))) {
@@ -1164,15 +1188,16 @@ const Apps2 = (props) => {
return response.json(); return response.json();
}) })
.then((responseJson) => { .then((responseJson) => {
//responseJson = sortByKey(responseJson, "large_image")
//responseJson = sortByKey(responseJson, "is_valid")
//setFilteredApps(responseJson.filter(app => !internalIds.includes(app.name) && !(!app.activated && app.generated)))
console.log("responseJson: from getApps ", responseJson)
var privateapps = []; var privateapps = [];
var valid = []; var valid = [];
var invalid = []; var invalid = [];
for (var key in responseJson) { for (var key in responseJson) {
const app = responseJson[key]; const app = responseJson[key];
if (app.categories !== undefined && app.categories !== null && app?.categories.includes("Eradication")) {
app.categories = ["EDR"]
}
if (app.is_valid && !(!app.activated && app.generated)) { if (app.is_valid && !(!app.activated && app.generated)) {
privateapps.push(app); privateapps.push(app);
} else if ( } else if (
@@ -1185,21 +1210,13 @@ const Apps2 = (props) => {
} }
} }
//console.log(privateapps)
//console.log(valid)
//console.log(invalid)
//console.log(privateapps)
//privateapps.reverse()
privateapps.push(...valid); privateapps.push(...valid);
privateapps.push(...invalid); privateapps.push(...invalid);
console.log("privateapps: setting apps ", privateapps) console.log("privateapps: setting apps ", privateapps)
setAppsToShow(privateapps); setAppsToShow(privateapps);
setOrgApps(privateapps); setOrgApps(privateapps);
setApps(privateapps); setApps(privateapps);
// setCursearch("");
//handleSearchChange(event.target.value)
//setCursearch(event.target.value)
// setFilteredApps(privateapps); // setFilteredApps(privateapps);
if (privateapps.length > 0) { if (privateapps.length > 0) {
if (selectedApp.id === undefined || selectedApp.id === null) { if (selectedApp.id === undefined || selectedApp.id === null) {
@@ -1707,8 +1724,24 @@ const Apps2 = (props) => {
setOpenModal(false) setOpenModal(false)
} }
const tabStyle = {
textTransform: 'none',
marginRight: 20,
fontFamily: theme?.typography?.fontFamily,
fontSize: 16,
borderBottom: "5px solid transparent",
minHeight: "48px",
padding: "12px 16px",
}
const tabActive = {
borderBottom: "5px solid #FF8544",
borderRadius: "2px",
color: "#FF8544"
}
return ( return (
<div style={{ paddingTop: 70, paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease", backgroundColor: "#1A1A1A", fontFamily: theme?.typography?.fontFamily, zoom: 0.8, }}> <div style={{ paddingTop: 70, paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease", backgroundColor: "#1A1A1A", fontFamily: theme?.typography?.fontFamily, zoom: 0.7, }}>
<InstantSearch searchClient={searchClient} indexName="appsearch"> <InstantSearch searchClient={searchClient} indexName="appsearch">
<AppModal <AppModal
open={openModal} open={openModal}
@@ -1728,7 +1761,7 @@ const Apps2 = (props) => {
<div style={boxStyle}> <div style={boxStyle}>
<div style={{ display: "flex", flexDirection: "row", width: "100%", justifyContent: "space-between" }}> <div style={{ display: "flex", flexDirection: "row", width: "100%", justifyContent: "space-between" }}>
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: theme?.typography?.fontFamily }}> <Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: theme?.typography?.fontFamily }}>
Apps {currTab === 0 ? "Org" : currTab === 1 ? "Your" : "Discover"} Apps
</Typography> </Typography>
{isCloud ? null : ( {isCloud ? null : (
<span style={{ display: "flex", gap: 15 }}> <span style={{ display: "flex", gap: 15 }}>
@@ -1755,7 +1788,7 @@ const Apps2 = (props) => {
height: 45, height: 45,
minWidth: 45, minWidth: 45,
backgroundColor: "#2F2F2F", backgroundColor: "#2F2F2F",
borderRadius: 8, borderRadius: 4,
padding: "8px 16px", padding: "8px 16px",
}} }}
disabled={isLoading} disabled={isLoading}
@@ -1795,7 +1828,7 @@ const Apps2 = (props) => {
height: 45, height: 45,
minWidth: 45, minWidth: 45,
backgroundColor: "#2F2F2F", backgroundColor: "#2F2F2F",
borderRadius: 8, borderRadius: 4,
padding: "8px 16px", padding: "8px 16px",
}} }}
disabled={isLoading} disabled={isLoading}
@@ -1820,12 +1853,35 @@ const Apps2 = (props) => {
<Tabs <Tabs
value={currTab} value={currTab}
onChange={(event, newTab) => handleTabChange(event, newTab)} onChange={(event, newTab) => handleTabChange(event, newTab)}
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10, backgroundColor: "#FF8544" } }} style={{
style={{ fontFamily: theme?.typography?.fontFamily }} fontFamily: theme?.typography?.fontFamily,
fontSize: 16,
marginBottom: "-2px"
}}
TabIndicatorProps={{ style: { display: 'none' } }}
> >
<Tab label="Organization Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: theme?.typography?.fontFamily }} /> <Tab
<Tab label="My Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: theme?.typography?.fontFamily }} /> label="Organization Apps"
<Tab label="Discover Apps" style={{ textTransform: 'none', fontFamily: theme?.typography?.fontFamily }} /> style={{
...tabStyle,
...(currTab === 0 ? tabActive : {})
}}
/>
<Tab
label="My Apps"
style={{
...tabStyle,
...(currTab === 1 ? tabActive : {})
}}
/>
<Tab
label="Discover Apps"
style={{
...tabStyle,
marginRight: 0,
...(currTab === 2 ? tabActive : {})
}}
/>
</Tabs> </Tabs>
</div> </div>
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45, paddingRight: 25 }}> <div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45, paddingRight: 25 }}>
@@ -1850,12 +1906,12 @@ const Apps2 = (props) => {
limit={5} limit={5}
InputProps={{ InputProps={{
style: { style: {
borderRadius: 8, borderRadius: 4,
height: 45 height: 45
}, },
endAdornment: ( endAdornment: (
<InputAdornment position="end"> <InputAdornment position="end">
{searchQuery.length === 0 ? <Search /> : ( {searchQuery.length === 0 ? <SearchIcon /> : (
<ClearIcon <ClearIcon
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
onClick={() => { onClick={() => {
@@ -1892,7 +1948,7 @@ const Apps2 = (props) => {
displayEmpty displayEmpty
multiple multiple
style={{ style={{
borderRadius: 8, borderRadius: 4,
height: 45, height: 45,
fontFamily: theme?.typography?.fontFamily fontFamily: theme?.typography?.fontFamily
}} }}
@@ -1956,7 +2012,7 @@ const Apps2 = (props) => {
displayEmpty displayEmpty
multiple multiple
style={{ style={{
borderRadius: 8, borderRadius: 4,
height: 45, height: 45,
fontFamily: theme?.typography?.fontFamily fontFamily: theme?.typography?.fontFamily
}} }}
@@ -2014,7 +2070,7 @@ const Apps2 = (props) => {
style={{ style={{
height: "100%", height: "100%",
width: '100%', width: '100%',
borderRadius: '7px', borderRadius: '4px',
textTransform: 'none', textTransform: 'none',
backgroundColor: "#FF8544", backgroundColor: "#FF8544",
color: "#1A1A1A", color: "#1A1A1A",
@@ -2022,7 +2078,7 @@ const Apps2 = (props) => {
fontSize: 16, fontSize: 16,
fontWeight: 500 fontWeight: 500
}} }}
startIcon={<Add style={{ color: "#1A1A1A" }} />} startIcon={<AddIcon style={{ color: "#1A1A1A" }} />}
> >
Create an App Create an App
</Button> </Button>
@@ -2062,6 +2118,7 @@ const Apps2 = (props) => {
handleAppClick={handleAppClick} handleAppClick={handleAppClick}
leftSideBarOpenByClick={leftSideBarOpenByClick} leftSideBarOpenByClick={leftSideBarOpenByClick}
userdata={userdata} userdata={userdata}
fetchApps={fetchApps}
/> />
))} ))}
</div> </div>
@@ -2106,6 +2163,7 @@ const Apps2 = (props) => {
{appsToShow.map((data, index) => ( {appsToShow.map((data, index) => (
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} userdata={userdata} <AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} userdata={userdata}
handleAppClick={handleAppClick} leftSideBarOpenByClick={leftSideBarOpenByClick} handleAppClick={handleAppClick} leftSideBarOpenByClick={leftSideBarOpenByClick}
fetchApps={fetchApps}
/> />
))} ))}
</div> </div>
File diff suppressed because it is too large Load Diff