Synced over a lot of sidebar changes

This commit is contained in:
Frikky
2024-12-04 17:01:33 +01:00
parent 32264ad5fa
commit 24a8c18eb5
30 changed files with 2811 additions and 1831 deletions
+16 -14
View File
@@ -92,7 +92,7 @@ const RequestMethods = [
}, },
]; ];
const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, selectedAppData, ConfigurationTab }) => { const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, selectedAppData, ConfigurationTab, isLoggedIn, isLoaded }) => {
const [actions, setActions] = useState([]); const [actions, setActions] = useState([]);
const [info, setInfo] = useState({}); const [info, setInfo] = useState({});
const [serverurl, setServerUrl] = useState(""); const [serverurl, setServerUrl] = useState("");
@@ -1265,12 +1265,12 @@ const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, se
style={{ style={{
display: "flex", display: "flex",
flexDirection: 'row', flexDirection: 'row',
height: userdata?.support ? "auto" : "calc(100vh - 80px)", height: (isLoggedIn && isLoaded) ? "auto" : "calc(100vh - 80px)",
}} }}
> >
<ActionsList info={info} openapi={openapi} userdata={userdata} actions={actions} filteredActions={filteredActions} setFilteredActions={setFilteredActions} selectedActionIndex={selectedActionIndex} setSelectedActionIndex={setSelectedActionIndex} setExampleBody={setExampleBody }/> <ActionsList info={info} openapi={openapi} isLoggedIn={isLoggedIn} isLoaded={isLoaded} userdata={userdata} actions={actions} filteredActions={filteredActions} setFilteredActions={setFilteredActions} selectedActionIndex={selectedActionIndex} setSelectedActionIndex={setSelectedActionIndex} setExampleBody={setExampleBody }/>
<ActionResponseAndRequest ConfigurationTab={ConfigurationTab} selectedAppData={selectedAppData} HandleApiExecution={HandleApiExecution} userdata={userdata} info={info} filteredActions={filteredActions} setFilteredActions={setFilteredActions} actions={actions} selectedActionIndex={selectedActionIndex} ExampleBody={ExampleBody} setExampleBody={setExampleBody} openapi={openapi} serverurl={serverurl} globalUrl={globalUrl} setSelectedActionIndex={setSelectedActionIndex}/> <ActionResponseAndRequest isLoaded={isLoaded} isLoggedIn={isLoggedIn} ConfigurationTab={ConfigurationTab} selectedAppData={selectedAppData} HandleApiExecution={HandleApiExecution} userdata={userdata} info={info} filteredActions={filteredActions} setFilteredActions={setFilteredActions} actions={actions} selectedActionIndex={selectedActionIndex} ExampleBody={ExampleBody} setExampleBody={setExampleBody} openapi={openapi} serverurl={serverurl} globalUrl={globalUrl} setSelectedActionIndex={setSelectedActionIndex}/>
</div> </div>
); );
@@ -1279,7 +1279,7 @@ const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, se
export default ApiExplorer; export default ApiExplorer;
const ActionResponseAndRequest = memo(({ConfigurationTab, selectedAppData,actions, info, HandleApiExecution, userdata, filteredActions, setFilteredActions, serverurl, globalUrl, setSelectedActionIndex, ExampleBody, setExampleBody, selectedActionIndex}) => { const ActionResponseAndRequest = memo(({ isLoggedIn, isLoaded, ConfigurationTab, selectedAppData,actions, info, HandleApiExecution, userdata, filteredActions, setFilteredActions, serverurl, globalUrl, setSelectedActionIndex, ExampleBody, setExampleBody, selectedActionIndex}) => {
const [apiResponse, setApiResponse] = useState({}); const [apiResponse, setApiResponse] = useState({});
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const loadAction = 10; const loadAction = 10;
@@ -1366,7 +1366,7 @@ const ActionResponseAndRequest = memo(({ConfigurationTab, selectedAppData,action
))} ))}
</div> </div>
<ActionResponse userdata={userdata} apiResponse={apiResponse} ExampleBody={ExampleBody}/> <ActionResponse isLoaded={isLoaded} isLoggedIn={isLoggedIn} apiResponse={apiResponse} ExampleBody={ExampleBody}/>
</div> </div>
)}) )})
@@ -1381,6 +1381,8 @@ const ActionsList = memo(({
userdata, userdata,
info, info,
openapi, openapi,
isLoggedIn,
isLoaded
}) => { }) => {
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
@@ -1436,7 +1438,7 @@ const ActionsList = memo(({
} }
}; };
return ( return (
<div style={{ maxWidth: '350px', width: "25%", overflow: 'hidden', marginLeft: !userdata.support ? 5 : 0}}> <div style={{ maxWidth: '350px', width: "25%", overflow: 'hidden', marginLeft: !(isLoggedIn || isLoaded) ? 5 : 0}}>
<div style={{ borderBottom: '1px solid #494949', paddingTop: 10, paddingBottom: 10}}> <div style={{ borderBottom: '1px solid #494949', paddingTop: 10, paddingBottom: 10}}>
<div> <div>
{info?.title ? ( {info?.title ? (
@@ -1487,7 +1489,7 @@ const ActionsList = memo(({
marginTop: 15, marginTop: 15,
backgroundColor: "#1a1a1a", backgroundColor: "#1a1a1a",
overflowY: "auto", overflowY: "auto",
height: userdata?.support ? "calc(100vh - 190px)" : "calc(100vh - 260px)", height: (isLoaded && isLoggedIn) ? "calc(100vh - 190px)" : "calc(100vh - 260px)",
paddingRight: 5, paddingRight: 5,
}} }}
> >
@@ -2776,7 +2778,7 @@ const Action = memo((
); );
}) })
const ActionResponse = memo(({ apiResponse, ExampleBody, userdata }) => { const ActionResponse = memo(({ apiResponse, ExampleBody, isLoggedIn, isLoaded }) => {
const [height, setHeight] = useState("14vh") const [height, setHeight] = useState("14vh")
const [responseTabIndex, setResponseTabIndex] = useState(0) const [responseTabIndex, setResponseTabIndex] = useState(0)
const [oldResponse, setOldResponse] = useState(apiResponse) const [oldResponse, setOldResponse] = useState(apiResponse)
@@ -2897,7 +2899,7 @@ const ActionResponse = memo(({ apiResponse, ExampleBody, userdata }) => {
}, []); }, []);
return ( return (
<ApiResponseWrapper userdata={userdata}> <ApiResponseWrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
<div <div
style={{ style={{
width: '100%', width: '100%',
@@ -3016,12 +3018,12 @@ const ResponseTabWrapper = memo(({ apiResponse }) => {
/> />
)}) )})
const PaddingWrapper = memo(({ userdata, children }) => { const PaddingWrapper = memo(({ isLoggedIn, isLoaded, children }) => {
const { leftSideBarOpenByClick, windowWidth } = useContext(Context); const { leftSideBarOpenByClick, windowWidth } = useContext(Context);
return ( return (
<div <div
style={{ style={{
width: userdata?.support width: (isLoggedIn && isLoaded)
? leftSideBarOpenByClick ? leftSideBarOpenByClick
? windowWidth >= 1920 ? "calc(100% - 630px)" : "calc(100% - 570px)" ? windowWidth >= 1920 ? "calc(100% - 630px)" : "calc(100% - 570px)"
: windowWidth >= 1920 ? "calc(100vw - 460px)": "calc(100% - 410px)" : windowWidth >= 1920 ? "calc(100vw - 460px)": "calc(100% - 410px)"
@@ -3042,9 +3044,9 @@ const PaddingWrapper = memo(({ userdata, children }) => {
); );
}); });
const ApiResponseWrapper = memo(({ children, userdata }) => { const ApiResponseWrapper = memo(({ children, isLoaded, isLoggedIn }) => {
return ( return (
<PaddingWrapper userdata={userdata}> <PaddingWrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
{children} {children}
</PaddingWrapper> </PaddingWrapper>
); );
+202 -57
View File
@@ -1,4 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router';
import { import {
Dialog, Dialog,
DialogTitle, DialogTitle,
@@ -21,17 +23,22 @@ 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 './AppFramework';
import theme from "../theme";
import YAML from 'yaml';
import { toast } from 'react-toastify';
import { Link } from 'react-router-dom';
const AppModal = ({ open, onClose, app, userdata, globalUrl }) => { const AppModal = ({ open, onClose, app, globalUrl }) => {
const [frameworkData, setFrameworkData] = useState({}) const [frameworkData, setFrameworkData] = useState({})
const [userdata, setUserdata] = useState({})
const [usecases, setUsecases] = useState([]) const [usecases, setUsecases] = useState([])
const [workflows, setWorkflows] = useState([]) const [workflows, setWorkflows] = useState([])
const [prevSubcase, setPrevSubcase] = useState({}) const [prevSubcase, setPrevSubcase] = useState({})
const [inputUsecase, setInputUsecase] = useState({}) const [inputUsecase, setInputUsecase] = useState({})
const [latestUsecase, setLatestUsecase] = useState([]) const [latestUsecase, setLatestUsecase] = useState([])
const [foundAppUsecase, setFoundAppUsecase] = useState({}) const [foundAppUsecase, setFoundAppUsecase] = useState({})
const navigate = useNavigate();
const parseUsecase = (subcase) => { const parseUsecase = (subcase) => {
const srcdata = findSpecificApp(frameworkData, subcase.type) const srcdata = findSpecificApp(frameworkData, subcase.type)
const dstdata = findSpecificApp(frameworkData, subcase.last) const dstdata = findSpecificApp(frameworkData, subcase.last)
@@ -48,6 +55,25 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
return subcase return subcase
} }
useEffect(() => {
var baseurl = globalUrl;
fetch(baseurl + "/api/v1/me", {
credentials: "include",
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(responseJson => {
if (responseJson.success) {
setUserdata(responseJson)
}
})
.catch(error => {
console.log("Failed login check: ", error);
});
}, [app]);
const getFramework = () => { const getFramework = () => {
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", { fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
@@ -266,6 +292,89 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
setFoundAppUsecase(foundSubcase); setFoundAppUsecase(foundSubcase);
}, [latestUsecase]) }, [latestUsecase])
const downloadApp = (inputdata) => {
const id = inputdata.id;
toast("Downloading..");
fetch(globalUrl + "/api/v1/apps/" + id + "/config", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
window.location.pathname = "/apps";
}
return response.json();
})
.then((responseJson) => {
if (!responseJson.success) {
toast("Failed to download file");
} else {
console.log(responseJson);
const basedata = atob(responseJson.openapi);
console.log("BASE: ", basedata);
var inputdata = JSON.parse(basedata);
console.log("POST INPUT: ", inputdata);
inputdata = JSON.parse(inputdata.body);
const newpaths = {};
if (inputdata["paths"] !== undefined) {
Object.keys(inputdata["paths"]).forEach(function (key) {
newpaths[key.split("?")[0]] = inputdata.paths[key];
});
}
inputdata.paths = newpaths;
console.log("INPUT: ", inputdata);
var name = inputdata.info.title;
name = name.replace(/ /g, "_", -1);
name = name.toLowerCase();
delete inputdata.id;
delete inputdata.editing;
const data = YAML.stringify(inputdata);
var blob = new Blob([data], {
type: "application/octet-stream",
});
var url = URL.createObjectURL(blob);
var link = document.createElement("a");
link.setAttribute("href", url);
link.setAttribute("download", `${name}.yaml`);
var event = document.createEvent("MouseEvents");
event.initMouseEvent(
"click",
true,
true,
window,
1,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
link.dispatchEvent(event);
//link.parentNode.removeChild(link)
}
})
.catch((error) => {
console.log(error);
toast(error.toString());
});
};
const isCloud = const isCloud =
window.location.host === "localhost:3002" || window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io" || window.location.host === "localhost:3000" window.location.host === "shuffler.io" || window.location.host === "localhost:3000"
@@ -280,7 +389,8 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
newAppname = newAppname?.replaceAll("_", " "); newAppname = newAppname?.replaceAll("_", " ");
} }
var canEditApp = userdata.admin === "true" || userdata.id === app?.owner || app?.owner === "" || (userdata.admin === "true" && userdata.active_org.id === app?.reference_org) || !app?.generated var canEditApp = userdata.admin === "true" || userdata?.id === app?.owner || app?.owner === "" || (userdata.admin === "true" && userdata.active_org.id === app?.reference_org) || !app?.generated
return ( return (
@@ -294,7 +404,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
borderRadius: 2, borderRadius: 2,
border: "1px solid #494949", border: "1px solid #494949",
minWidth: '440px', minWidth: '440px',
fontFamily: "Inter", fontFamily: theme?.typography?.fontFamily,
backgroundColor: "#212121", backgroundColor: "#212121",
'& .MuiDialogContent-root': { '& .MuiDialogContent-root': {
backgroundColor: "#212121", backgroundColor: "#212121",
@@ -303,10 +413,10 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
backgroundColor: "#212121", backgroundColor: "#212121",
}, },
'& .MuiTypography-root': { '& .MuiTypography-root': {
fontFamily: 'Inter, sans-serif', fontFamily: theme?.typography?.fontFamily,
}, },
'& .MuiButton-root': { '& .MuiButton-root': {
fontFamily: 'Inter, sans-serif', fontFamily: theme?.typography?.fontFamily,
}, },
} }
}} }}
@@ -320,7 +430,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
pt: 2, pt: 2,
pl: 3, pl: 3,
pr: 2, pr: 2,
fontFamily: "Inter" fontFamily: theme?.typography?.fontFamily
}} }}
> >
<Typography component="div" sx={{ fontWeight: 500, color: "#F1F1F1", fontSize: "22px" }}> <Typography component="div" sx={{ fontWeight: 500, color: "#F1F1F1", fontSize: "22px" }}>
@@ -340,7 +450,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
<DialogContent sx={{ py: 3, px: 3 }}> <DialogContent sx={{ py: 3, px: 3 }}>
<Box sx={{ display: 'flex', alignItems: 'space-between', justifyContent: 'space-between' }}> <Box sx={{ display: 'flex', alignItems: 'space-between', justifyContent: 'space-between' }}>
<div style={{ display: "flex", flexDirection: "row", gap: 10, fontFamily: "Inter" }}> <div style={{ display: "flex", flexDirection: "row", gap: 10, fontFamily: theme?.typography?.fontFamily }}>
<img <img
alt={app?.name} alt={app?.name}
src={app?.large_image || app?.image_url} src={app?.large_image || app?.image_url}
@@ -364,11 +474,9 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
</Typography> </Typography>
{ {
isCloud && ( isCloud && (
<a <Link
rel="noopener noreferrer" to={"/apps/" + (app?.id || app?.objectID)}
href={"https://shuffler.io/apps/" + app?.id}
style={{ textDecoration: "none", color: "#f85a3e", marginTop: "-2px" }} style={{ textDecoration: "none", color: "#f85a3e", marginTop: "-2px" }}
target="_blank"
> >
<IconButton <IconButton
style={{ style={{
@@ -378,7 +486,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
> >
<OpenInNewIcon /> <OpenInNewIcon />
</IconButton> </IconButton>
</a> </Link>
) )
} }
</div> </div>
@@ -391,23 +499,33 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
</div> </div>
</div> </div>
<div style={{ display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center", gap: 10 }}> <div style={{ display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center", gap: 10 }}>
<Button
variant="contained" {app?.activated &&
sx={{ app?.private_id !== undefined &&
bgcolor: '#494949', app?.private_id?.length > 0 &&
'&:hover': { bgcolor: '#494949' }, app?.generated ? (
textTransform: 'none', <Button
borderRadius: 1, variant="contained"
minWidth: '45px', sx={{
width: '45px', bgcolor: '#494949',
height: '40px', '&:hover': { bgcolor: '#494949' },
padding: 2, textTransform: 'none',
color: "#fff", borderRadius: 1,
fontFamily: "Inter" minWidth: '45px',
}} width: '45px',
> height: '40px',
<CloudDownloadOutlined /> padding: 2,
</Button> color: "#fff",
fontFamily: theme?.typography?.fontFamily
}}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
downloadApp(app);
}}
>
<CloudDownloadOutlined />
</Button>) : null}
<Button <Button
variant="contained" variant="contained"
sx={{ sx={{
@@ -419,9 +537,21 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
px: 3, px: 3,
height: '40px', height: '40px',
color: "#fff", color: "#fff",
fontFamily: "Inter" fontFamily: theme?.typography?.fontFamily
}}
startIcon={canEditApp ? <EditIcon /> :
(app?.generated && app?.activated && userdata?.id !== app?.owner && isCloud ?
<ForkRightIcon /> : null
)}
onClick={() => {
if (canEditApp) {
const editUrl = "/apps/edit/" + (app?.id || app?.objectID);
navigate(editUrl)
}else{
const forkUrl = "/apps/new?id=" + (app?.id || app?.objectID);
navigate(forkUrl)
}
}} }}
startIcon={canEditApp ? <EditIcon /> : <ForkRightIcon />}
> >
{canEditApp ? "Edit" : "Fork"} {canEditApp ? "Edit" : "Fork"}
</Button> </Button>
@@ -431,17 +561,17 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
<div style={{ <div style={{
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
fontFamily: "Inter", fontFamily: theme?.typography?.fontFamily,
padding: "26px 0px" padding: "26px 0px"
}}> }}>
<div style={{ <div style={{
textAlign: "start", textAlign: "start",
flex: 1, flex: 1,
}}> }}>
<Typography <Typography
variant="h6" variant="h6"
sx={{ sx={{
fontFamily: 'Inter, sans-serif', fontFamily: theme?.typography?.fontFamily,
fontSize: '24px', fontSize: '24px',
fontWeight: 600, fontWeight: 600,
mb: 0.3, mb: 0.3,
@@ -450,11 +580,11 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
> >
20 20
</Typography> </Typography>
<Typography <Typography
variant="body2" variant="body2"
sx={{ sx={{
color: 'rgba(255, 255, 255, 0.7)', color: 'rgba(255, 255, 255, 0.7)',
fontFamily: 'Inter, sans-serif', fontFamily: theme?.typography?.fontFamily,
fontSize: '14px' fontSize: '14px'
}} }}
> >
@@ -468,12 +598,12 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
paddingLeft: "10px", paddingLeft: "10px",
height: "100%", height: "100%",
}}> }}>
<Typography variant="h6" <Typography variant="h6"
sx={{ sx={{
fontWeight: 600, fontWeight: 600,
mb: 0.3, mb: 0.3,
color: '#fff' color: '#fff'
}}> }}>
{Array.isArray(app?.actions) ? app.actions.length : app?.actions} {Array.isArray(app?.actions) ? app.actions.length : app?.actions}
</Typography> </Typography>
<Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)' }}> <Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)' }}>
@@ -486,7 +616,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
paddingLeft: "10px", paddingLeft: "10px",
paddingTop: "5px" paddingTop: "5px"
}}> }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '4px', marginBottom: "5px", fontFamily: "Inter", fontSize: "14px", fontWeight: 600 }}> <div style={{ display: 'flex', alignItems: 'center', gap: '4px', marginBottom: "5px", fontFamily: theme?.typography?.fontFamily, fontSize: "14px", fontWeight: 600, color: 'white' }}>
{ {
app?.collection ? ( app?.collection ? (
<> <>
@@ -494,13 +624,25 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
<Typography variant="body1" sx={{ <Typography variant="body1" sx={{
fontWeight: 500, fontWeight: 500,
color: '#fff', color: '#fff',
marginTop: "1px" marginTop: "1px",
fontFamily: theme?.typography?.fontFamily,
fontSize: "16px"
}}> }}>
app.collection app.collection
</Typography> </Typography>
</> </>
) : "No collection yet" ) : (
<Typography sx={{
fontSize: "16px",
fontWeight: 500,
marginTop: "1px",
color: 'rgba(255, 255, 255, 0.7)',
fontFamily: theme?.typography?.fontFamily
}}>
No collection yet
</Typography>
)
} }
</div> </div>
@@ -517,7 +659,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
width: "100%" width: "100%"
}}> }}>
<div style={{ <div style={{
fontFamily: "Inter", fontFamily: theme?.typography?.fontFamily,
fontSize: "16px", fontSize: "16px",
color: "#fff", color: "#fff",
marginBottom: "16px", marginBottom: "16px",
@@ -544,7 +686,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
{ {
foundAppUsecase === undefined ? ( foundAppUsecase === undefined ? (
<Avatar sx={{ width: 32, height: 32, bgcolor: 'background.paper', border: 1, borderColor: 'divider' }}> <Avatar sx={{ width: 32, height: 32, bgcolor: 'background.paper', border: 1, borderColor: 'divider' }}>
<Search sx={{ color: 'text.primary', zIndex: 10, fontSize: 18}} /> <Search sx={{ color: 'text.primary', zIndex: 10, fontSize: 18 }} />
</Avatar> </Avatar>
) : ( ) : (
<Avatar <Avatar
@@ -560,10 +702,10 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
/> />
) )
} }
{ {
foundAppUsecase === undefined ? ( foundAppUsecase === undefined ? (
<Avatar sx={{ width: 32, height: 32, bgcolor: 'background.paper', border: 1, borderColor: 'divider' }}> <Avatar sx={{ width: 32, height: 32, bgcolor: 'background.paper', border: 1, borderColor: 'divider' }}>
<AddIcon sx={{ color: 'text.primary', zIndex: 10, fontSize: 18}} /> <AddIcon sx={{ color: 'text.primary', zIndex: 10, fontSize: 18 }} />
</Avatar> </Avatar>
) : ( ) : (
<Avatar <Avatar
@@ -586,7 +728,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
</Box> </Box>
</div> </div>
<div style={{ display: "flex", justifyContent: "center", fontFamily: "Inter" }}> <div style={{ display: "flex", justifyContent: "center", fontFamily: theme?.typography?.fontFamily }}>
<Button <Button
variant="contained" variant="contained"
sx={{ sx={{
@@ -599,11 +741,14 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
fontSize: "14px", fontSize: "14px",
letterSpacing: "0.5px", letterSpacing: "0.5px",
color: "black", color: "black",
fontFamily: "Inter", fontFamily: theme?.typography?.fontFamily,
minWidth: '200px' minWidth: '200px'
}} }}
onClick={() => {
navigate("/usecases2")
}}
> >
Create a Usecase Find a Usecase
</Button> </Button>
</div> </div>
</DialogContent> </DialogContent>
@@ -611,4 +756,4 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
); );
}; };
export default AppModal; export default AppModal;
+1 -1
View File
@@ -465,7 +465,7 @@ const AppSelection = props => {
style={{ style={{
fontSize: 16, fontSize: 16,
color: "rgba(158, 158, 158, 1)", color: "rgba(158, 158, 158, 1)",
fontFamily: "Inter", fontFamily: theme?.typography?.fontFamily,
}} }}
> >
Your organization has no apps yet, select your starting apps here Your organization has no apps yet, select your starting apps here
+104 -75
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useContext, memo, useMemo } from "react";
import ReactGA from 'react-ga4'; import ReactGA from 'react-ga4';
import theme from "../theme.jsx"; import theme from "../theme.jsx";
@@ -41,7 +41,8 @@ import {
Delete, Delete,
RestaurantRounded, RestaurantRounded,
Cloud, Cloud,
CheckCircle CheckCircle,
Padding,
} from "@mui/icons-material"; } from "@mui/icons-material";
//import { useAlert //import { useAlert
@@ -49,8 +50,9 @@ import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
import BillingStats from "./BillingStats.jsx"; 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";
const Billing = (props) => { const Billing = memo((props) => {
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props; const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props;
//const alert = useAlert(); //const alert = useAlert();
let navigate = useNavigate(); let navigate = useNavigate();
@@ -72,7 +74,7 @@ const Billing = (props) => {
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 [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;
@@ -81,18 +83,12 @@ const Billing = (props) => {
} }
}, [userdata]); }, [userdata]);
const [BillingEmail, setBillingEmail] = useState(selectedOrganization?.Billing?.Email);
const [BillingEmail, setBillingEmail] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.Email !== undefined && selectedOrganization.Billing.Email != null && selectedOrganization.Billing.Email.length > 0 ? selectedOrganization.Billing.Email : selectedOrganization.org); useEffect(() => {
if (BillingEmail !== selectedOrganization?.Billing?.Email) {
useState(() => { setBillingEmail(selectedOrganization?.Billing?.Email);
// Set the billing email }
setBillingEmail(
selectedOrganization.Billing !== undefined &&
selectedOrganization.Billing.Email !== undefined &&
selectedOrganization.Billing.Email.length > 0
? selectedOrganization.Billing.Email
: selectedOrganization.org
);
// Set and sort the alert thresholds // Set and sort the alert thresholds
const alertThresholds = selectedOrganization.Billing !== undefined && const alertThresholds = selectedOrganization.Billing !== undefined &&
@@ -126,7 +122,6 @@ const Billing = (props) => {
]; ];
const handleGetDeals = (orgId) => { const handleGetDeals = (orgId) => {
console.log("Get deals!");
if (orgId.length === 0) { if (orgId.length === 0) {
toast( toast(
@@ -178,7 +173,7 @@ const Billing = (props) => {
width: 340, width: 340,
height: 480, height: 480,
// width: "100%", // width: "100%",
backgroundColor: theme.palette.platformColor, backgroundColor: theme.palette.backgroundColor,
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,
@@ -384,7 +379,7 @@ const Billing = (props) => {
} }
if (hovered) { if (hovered) {
newPaperstyle.backgroundColor = theme.palette.surfaceColor newPaperstyle.backgroundColor = "#2b2b2b"
} }
const handleClickOpen = () => { const handleClickOpen = () => {
@@ -412,7 +407,6 @@ const Billing = (props) => {
const HandleChangeBillingEmail = (orgId) => { const HandleChangeBillingEmail = (orgId) => {
const email = newBillingEmail; const email = newBillingEmail;
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/; const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
console.log("Pattern matches: ", emailPattern.test(email));
if (!emailPattern.test(email)) { if (!emailPattern.test(email)) {
toast("Please enter a valid email address"); toast("Please enter a valid email address");
return; return;
@@ -445,7 +439,6 @@ const Billing = (props) => {
} }
return response.json(); return response.json();
}).then((responseJson) => { }).then((responseJson) => {
console.log("Got org:", responseJson);
if (responseJson.success === true) { if (responseJson.success === true) {
toast.success("Successfully updated billing email"); toast.success("Successfully updated billing email");
setBillingEmail(newBillingEmail); setBillingEmail(newBillingEmail);
@@ -460,7 +453,7 @@ const Billing = (props) => {
} }
return ( return (
<Paper <div
style={newPaperstyle} style={newPaperstyle}
onMouseEnter={() => setHovered(true)} onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)} onMouseLeave={() => setHovered(false)}
@@ -726,7 +719,7 @@ const Billing = (props) => {
</Typography> </Typography>
<div style={{ display: 'flex', flexDirection: 'row' }}> <div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography variant="body2" style={{ marginTop: !userdata.has_card_available ? 5 : 0 }}> <Typography variant="body2" style={{ marginTop: !userdata.has_card_available ? 5 : 0 }}>
Billing email: {BillingEmail} {BillingEmail?.length > 0 ? `Billing email: ${BillingEmail}` : null}
</Typography> </Typography>
{userdata.has_card_available === true && ( {userdata.has_card_available === true && (
<Button <Button
@@ -817,11 +810,11 @@ const Billing = (props) => {
color="primary" color="primary"
style={{ style={{
marginTop: !userdata.has_card_available ? 20 : 10, marginTop: !userdata.has_card_available ? 20 : 10,
borderRadius: 25, borderRadius: 8,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "white", color: userdata.has_card_available ? "#ff8544" : "#1a1a1a",
backgroundColor: userdata.has_card_available ? null : "#f86743", backgroundColor: userdata.has_card_available ? null : "#ff8544",
// backgroundImage: userdata.has_card_available ? null : "linear-gradient(to right, #f86a3e, #f34079)", // backgroundImage: userdata.has_card_available ? null : "linear-gradient(to right, #f86a3e, #f34079)",
textTransform: "none", textTransform: "none",
@@ -850,11 +843,11 @@ const Billing = (props) => {
color="primary" color="primary"
style={{ style={{
marginTop: 10, marginTop: 10,
borderRadius: 25, borderRadius: 8,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "white", color: "#1a1a1a",
backgroundColor: "#f86743", backgroundColor: "#ff8544",
textTransform: 'none' textTransform: 'none'
}} }}
onClick={() => { onClick={() => {
@@ -873,7 +866,6 @@ const Billing = (props) => {
: null} : null}
{showSupport ? {showSupport ?
<Button variant="outlined" color="primary" style={{ marginTop: 20, marginBottom: 10, }} onClick={() => { <Button variant="outlined" color="primary" style={{ marginTop: 20, marginBottom: 10, }} onClick={() => {
console.log("Support click")
if (window.drift !== undefined) { if (window.drift !== undefined) {
//window.drift.api.startInteraction({ interactionId: 340045 }) //window.drift.api.startInteraction({ interactionId: 340045 })
window.drift.api.startInteraction({ interactionId: 340043 }) window.drift.api.startInteraction({ interactionId: 340043 })
@@ -884,7 +876,7 @@ const Billing = (props) => {
Get Support Get Support
</Button> </Button>
: null} : null}
</Paper> </div>
) )
} }
const ConsultationManagement = (props) => { const ConsultationManagement = (props) => {
@@ -1035,12 +1027,12 @@ const Billing = (props) => {
}) })
return ( return (
<Paper style={{ <div style={{
padding: 20, padding: 20,
// maxWidth: 400, // maxWidth: 400,
width: 340, width: 340,
height: 480, height: 480,
backgroundColor: hovered ? "#232427" : theme.palette.platformColor, backgroundColor: hovered ? "#2b2b2b" : theme.palette.backgroundColor,
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,
@@ -1131,11 +1123,11 @@ const Billing = (props) => {
color="primary" color="primary"
style={{ style={{
marginTop: userdata.support ? 0 : 10, marginTop: userdata.support ? 0 : 10,
borderRadius: 25, borderRadius: 8,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "white", color: "#1A1A1A",
backgroundColor: "#f86743", backgroundColor: "#FF8544",
textTransform: 'none', textTransform: 'none',
}} }}
onClick={() => { onClick={() => {
@@ -1150,7 +1142,7 @@ const Billing = (props) => {
> >
Buy Buy
</Button> </Button>
<Dialog open={clickOnBuy} onClose={() => { setClickOnBuy(false) }}> <Dialog open={clickOnBuy} onClose={() => { setClickOnBuy(false) }} PaperProps={{style: {backgroundColor: "rgb(26, 26, 26)"}}}>
<Typography variant="body1" style={{ marginTop: 10, textAlign: 'center', padding: 20, fontSize: 18 }}> <Typography variant="body1" style={{ marginTop: 10, textAlign: 'center', padding: 20, fontSize: 18 }}>
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>
@@ -1158,7 +1150,7 @@ const Billing = (props) => {
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
style={{ display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none', fontSize: 16 }} style={{ display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none', fontSize: 16, color: "#1a1a1a", backgroundColor: "#ff8544" }}
onClick={() => { onClick={() => {
if (Cloud) { if (Cloud) {
ReactGA.event({ ReactGA.event({
@@ -1186,10 +1178,10 @@ const Billing = (props) => {
color="primary" color="primary"
style={{ style={{
marginTop: userdata.support ? 5 : 10, marginTop: userdata.support ? 5 : 10,
borderRadius: 25, borderRadius: 8,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "white", 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,
@@ -1259,7 +1251,7 @@ const Billing = (props) => {
</Button> </Button>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</Paper > </div >
) )
} }
@@ -1308,13 +1300,13 @@ const Billing = (props) => {
} }
return ( return (
<Paper <div
style={{ style={{
padding: 20, padding: 20,
height: 480, height: 480,
// maxWidth: 400, // maxWidth: 400,
width: 340, width: 340,
backgroundColor: hovered ? "#232427" : theme.palette.platformColor, backgroundColor: hovered ? "#2b2b2b" : theme.palette.backgroundColor,
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,
@@ -1370,11 +1362,12 @@ const Billing = (props) => {
color="primary" color="primary"
style={{ style={{
marginTop: 10, marginTop: 10,
borderRadius: 25, borderRadius: 8,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
color: "white", color: "#1A1A1A",
textTransform: 'none' textTransform: 'none',
backgroundColor: "#FF8544"
}} }}
onClick={() => { onClick={() => {
if (Cloud) { if (Cloud) {
@@ -1397,10 +1390,12 @@ const Billing = (props) => {
color="primary" color="primary"
style={{ style={{
marginTop: 10, marginTop: 10,
borderRadius: 25, borderRadius: 8,
height: 40, height: 40,
fontSize: 16, fontSize: 16,
textTransform: 'none' textTransform: 'none',
color: "#FF8544",
backgroundColor: "#1a1a1a",
}} }}
onClick={() => { onClick={() => {
if (Cloud) { if (Cloud) {
@@ -1425,6 +1420,7 @@ const Billing = (props) => {
style: { style: {
width: 500, width: 500,
margin: 0, margin: 0,
backgroundColor: "rgb(26, 26, 26)",
} }
}} }}
> >
@@ -1464,7 +1460,7 @@ const Billing = (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', display: 'block', marginLeft: 'auto', marginRight: 'auto', padding: '12px 24px', textTransform: 'none', color: "#1a1a1a", backgroundColor: "#ff8544" }}
onClick={handlePrivateTraining} onClick={handlePrivateTraining}
> >
Submit Request Submit Request
@@ -1472,7 +1468,7 @@ const Billing = (props) => {
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div> </div>
</Paper> </div>
) )
} }
@@ -1892,13 +1888,15 @@ const Billing = (props) => {
} }
}; };
const isChildOrg = userdata?.active_org?.creator_org !== "" && userdata?.active_org?.creator_org !== undefined && userdata?.active_org?.creator_org !== null
const isChildOrg = userdata.active_org.creator_org !== "" && userdata.active_org.creator_org !== undefined && userdata.active_org.creator_org !== null
return ( return (
<div style={{ width: clickedFromOrgTab ? 1030 : "auto", padding: 27, backgroundColor: '#212121', borderRadius: '16px', }}> <Wrapper clickedFromOrgTab={clickedFromOrgTab}>
{addDealModal} <div style={{ height: "100%", width: "100%"}}>
<div style={{ width: "100%",}}>
{addDealModal}
{clickedFromOrgTab ? {clickedFromOrgTab ?
<h2 style={{ marginBottom: 8, marginTop: 0, color: "#ffffff" }}>Billing & Licensing</h2> : <Typography style={{fontSize: 24, fontWeight: "bold", marginBottom: 8, marginTop: 0, color: "#ffffff" }}>Billing & Licensing</Typography> :
<Typography variant="h4" style={{ marginTop: 20, marginBottom: 10 }}> <Typography variant="h4" style={{ marginTop: 20, marginBottom: 10 }}>
Billing & Licensing Billing & Licensing
</Typography>} </Typography>}
@@ -1942,11 +1940,11 @@ const Billing = (props) => {
{isChildOrg ? {isChildOrg ?
<Typography variant="h6" style={{ marginBottom: 50, }}> <Typography variant="h6" style={{ marginBottom: 50, }}>
Billing is handled by your parent organisation. Reach out to support@shuffler.io if you have questions about this. Licensing is handled by your parent organisation. Reach out to support@shuffler.io if you have questions about this.
</Typography> </Typography>
: null} : null}
<div style={{ display: "flex", width: 1180, overflowX: 'auto', overflowY: 'hidden', scrollbarWidth: 'thin', scrollbarColor: '#494949 #2f2f2f', height: 580 }} > <div style={{ display: "flex", width: clickedFromOrgTab ? 1030 : "auto", overflowX: 'auto', overflowY: 'hidden', scrollbarWidth: 'thin', scrollbarColor: '#494949 #2f2f2f', height: isChildOrg ? 0 : 580 }} >
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? isChildOrg ? null : {isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? isChildOrg ? null :
<SubscriptionObject <SubscriptionObject
index={0} index={0}
@@ -2258,10 +2256,10 @@ const Billing = (props) => {
) : null*/} ) : null*/}
{!isChildOrg && isCloud && ( {!isChildOrg && isCloud && (
<div style={{ display: 'flex', flexDirection: 'column', marginTop: 10 }}> <div style={{ display: 'flex', flexDirection: 'column', marginTop: 10 }}>
<Typography style={{ marginBottom: 5 }} variant="h4"> <Typography style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}>
Professional Services Professional Services
</Typography> </Typography>
<Typography color="textSecondary"> <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 }}>
@@ -2280,15 +2278,14 @@ const Billing = (props) => {
)} )}
<div style={{ marginTop: isCloud && 40, marginLeft: 10 }}> <div style={{ marginTop: isCloud && 40, marginLeft: 10 }}>
<Typography <Typography
style={{ marginBottom: 5 }} style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}
variant="h4"
> >
Manage Billing Manage Billing
</Typography> </Typography>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 0, marginBottom: 10 }}> <Typography color="textSecondary" style={{ marginTop: 10, marginBottom: 10, fontSize: 16, }}>
Manage your billing and licensing information below. When you reach the certain thresholds of your subscription limit, you will be notified by email. Manage your billing and licensing information below. When you reach the certain thresholds of your subscription limit, you will be notified by email.
</Typography> </Typography>
<Typography variant="body1">Current Usage:</Typography> <Typography style={{fontSize: 18, marginTop: 10}}>Current Usage:</Typography>
<LinearProgress <LinearProgress
variant="determinate" variant="determinate"
value={currentAppRunsInPercentage} value={currentAppRunsInPercentage}
@@ -2300,15 +2297,15 @@ const Billing = (props) => {
marginBottom: 10, marginBottom: 10,
}} }}
/> />
<Typography variant="body1" color="textSecondary"> <Typography style={{marginTop: 10, fontSize: 16,}} color="textSecondary">
You have used <strong>{currentAppRunsInPercentage}%</strong> of total app execution limit or <strong>{userdata.app_execution_usage}</strong> app runs out of <strong>{userdata.app_execution_limit}</strong> app runs. You have used <strong>{currentAppRunsInPercentage}%</strong> of total app execution limit or <strong>{userdata.app_execution_usage}</strong> app runs out of <strong>{userdata.app_execution_limit}</strong> app runs.
</Typography> </Typography>
<div> <div>
<Typography variant="body1" style={{ marginTop: 20 }}> <Typography style={{ marginTop: 20, fontSize: 18 }}>
Set email alert thresholds for app runs Set email alert thresholds for app runs
</Typography> </Typography>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10 }}> <Typography color="textSecondary" style={{ marginTop: 10, fontSize: 16 }}>
You will be notified by email when you reach the You will be notified by email when you reach the
{currentIndex !== -1 {currentIndex !== -1
? " " + getSafeValue(alertThresholds[currentIndex].percentage) + '%' + " " ? " " + getSafeValue(alertThresholds[currentIndex].percentage) + '%' + " "
@@ -2320,8 +2317,8 @@ const Billing = (props) => {
: " " + 0 + " "} : " " + 0 + " "}
app runs. app runs.
</Typography> </Typography>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10 }}> <Typography color="textSecondary" style={{ fontSize: 16 }}>
Please note: Once your app runs reach the set alert threshold, all admins in the organization will receive an email notification. <span style={{fontWeight: 'bold'}}>Please note</span>: Once your app runs reach the set alert threshold, all admins in the organization will receive an email notification.
</Typography> </Typography>
<div style={{ marginTop: 15 }}> <div style={{ marginTop: 15 }}>
{alertThresholds.map((threshold, index) => ( {alertThresholds.map((threshold, index) => (
@@ -2329,7 +2326,7 @@ const Billing = (props) => {
<TextField <TextField
style={{ style={{
marginTop: 10, marginTop: 10,
backgroundColor: theme.palette.inputColor, backgroundColor: "#212121",
width: 250, width: 250,
}} }}
InputProps={{ InputProps={{
@@ -2354,7 +2351,7 @@ const Billing = (props) => {
<TextField <TextField
style={{ style={{
marginTop: 10, marginTop: 10,
backgroundColor: theme.palette.inputColor, backgroundColor: "#212121",
width: 250, width: 250,
marginLeft: 15, marginLeft: 15,
}} }}
@@ -2421,11 +2418,11 @@ const Billing = (props) => {
Save Save
</Button> </Button>
</div>
</div> </div>
<div style={{ marginTop: 40, display: 'flex', flexDirection: 'column' }}> <div style={{ marginTop: 40, display: 'flex', flexDirection: 'column' }}>
<Typography <Typography
style={{ marginTop: 10, marginLeft: 10, marginBottom: 5 }} style={{ marginTop: 10, marginLeft: 10, marginBottom: 5, fontSize: 24, fontWeight: "bold" }}
variant="h4"
> >
Utilization & Stats Utilization & Stats
</Typography> </Typography>
@@ -2436,9 +2433,41 @@ const Billing = (props) => {
globalUrl={globalUrl} globalUrl={globalUrl}
selectedOrganization={selectedOrganization} selectedOrganization={selectedOrganization}
userdata={userdata} userdata={userdata}
/> />
</div> </div>
</Wrapper>
) )
} })
export default Billing; export default memo(Billing);
const PaddingWrapper = memo(({ clickedFromOrgTab, children }) => {
const wrapperStyle = useMemo(() => ({
width: clickedFromOrgTab
? "100%"
: "auto",
padding: "27px 10px 19px 27px",
backgroundColor: '#212121',
borderRadius: '16px',
height: '100%',
boxSizing: 'border-box',
borderLeft: '1px solid #494949',
overflow: 'hidden',
maxHeight: "1700px", overflowY: "auto",scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'
}), [clickedFromOrgTab]);
return (
<div style={wrapperStyle}>
{children}
</div>
);
});
const Wrapper = memo(({ children, clickedFromOrgTab }) => {
return (
<PaddingWrapper clickedFromOrgTab={clickedFromOrgTab}>
{children}
</PaddingWrapper>
);
});
+52 -11
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useContext, memo, useMemo } from 'react';
import theme from '../theme.jsx'; import theme from '../theme.jsx';
import classNames from "classnames"; import classNames from "classnames";
@@ -37,6 +37,7 @@ import {
} from 'reaviz'; } from 'reaviz';
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx"; import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
import { Context } from '../context/ContextApi.jsx';
const LineChartWrapper = ({keys, inputname, height, width}) => { const LineChartWrapper = ({keys, inputname, height, width}) => {
const [hovered, setHovered] = useState(""); const [hovered, setHovered] = useState("");
@@ -82,8 +83,8 @@ const AppStats = (defaultprops) => {
const [workflows, setWorkflows] = useState(inputWorkflows === undefined ? [] : inputWorkflows) const [workflows, setWorkflows] = useState(inputWorkflows === undefined ? [] : inputWorkflows)
const [resultRows, setResultRows] = useState([]) const [resultRows, setResultRows] = useState([])
const [resultLoading, setResultLoading] = useState(true) const [resultLoading, setResultLoading] = useState(true)
const includedExecutions = selectedOrganization.sync_features.app_executions !== undefined ? selectedOrganization.sync_features.app_executions.limit : 0 const includedExecutions = selectedOrganization?.sync_features?.app_executions !== undefined ? selectedOrganization?.sync_features?.app_executions?.limit : 0
useEffect(() => { useEffect(() => {
if (workflows === undefined || workflows === null || workflows.length === 0) { if (workflows === undefined || workflows === null || workflows.length === 0) {
@@ -92,7 +93,6 @@ const AppStats = (defaultprops) => {
}, []) }, [])
const getWorkflowStats = async (workflow, startTime, endTime) => { const getWorkflowStats = async (workflow, startTime, endTime) => {
if (!userdata.support) { if (!userdata.support) {
return workflow return workflow
@@ -162,8 +162,6 @@ const AppStats = (defaultprops) => {
const loadWorkflowStats = (foundWorkflows, startTime, endTime) => { const loadWorkflowStats = (foundWorkflows, startTime, endTime) => {
if (!userdata.support) { if (!userdata.support) {
console.log("Not support")
return return
} }
@@ -488,8 +486,13 @@ const AppStats = (defaultprops) => {
setApprunCosts(appcostRuns) setApprunCosts(appcostRuns)
} }
const getStats = () => { const getStats = (orgid) => {
fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`, {
if (orgid === undefined || orgid === null) {
return
}
fetch(`${globalUrl}/api/v1/orgs/${orgid}/stats`, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -519,8 +522,10 @@ const AppStats = (defaultprops) => {
} }
useEffect(() => { useEffect(() => {
getStats() if(selectedOrganization?.id?.length > 0) {
}, []) getStats(selectedOrganization.id)
}
}, [selectedOrganization])
const paperStyle = { const paperStyle = {
textAlign: "center", textAlign: "center",
@@ -639,7 +644,7 @@ const AppStats = (defaultprops) => {
const data = ( const data = (
<div className="content" style={{width: "100%", margin: "auto", }}> <div className="content" style={{width: "100%", margin: "auto", }}>
<Typography variant="body1" style={{margin: "auto", marginLeft: 10, marginBottom: 20, }} color="textSecondary"> <Typography style={{margin: "auto", marginLeft: 10, marginBottom: 20, fontSize: 16}} color="textSecondary">
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"
@@ -722,6 +727,40 @@ const AppStats = (defaultprops) => {
</div> </div>
: null} : null}
{clickedFromOrgTab? (
<LocalizationProvider dateAdapter={AdapterDayjs} style={{ flex: 1 }}>
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
<div style={{ flex: 1, maxWidth: "200px", }}>
<DateTimePicker
sx={{
marginTop: 1,
marginLeft: 1,
}}
ampm={false}
label="Search from"
format="YYYY-MM-DD HH:mm:ss"
value={startTime}
onChange={handleStartTimeChange}
renderInput={(params) => <TextField {...params} />}
/>
</div>
<div style={{ flex: 1, maxWidth: "200px",}}>
<DateTimePicker
sx={{
marginTop: 1,
marginLeft: 1,
}}
ampm={false}
label="Search until"
format="YYYY-MM-DD HH:mm:ss"
value={endTime}
onChange={handleEndTimeChange}
renderInput={(params) => <TextField {...params} />}
/>
</div>
</div>
</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", }}>
<DateTimePicker <DateTimePicker
@@ -754,6 +793,8 @@ const AppStats = (defaultprops) => {
/> />
</div> </div>
</LocalizationProvider> </LocalizationProvider>
)}
</div> </div>
+53 -25
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useContext } from "react";
import ReactGA from 'react-ga4'; import ReactGA from 'react-ga4';
import theme from "../theme.jsx"; import theme from "../theme.jsx";
import { ToastContainer, toast } from "react-toastify" import { ToastContainer, toast } from "react-toastify"
@@ -21,6 +21,7 @@ import {
red, red,
green, green,
} from "../views/AngularWorkflow.jsx" } from "../views/AngularWorkflow.jsx"
import { Context } from "../context/ContextApi.jsx";
//import { useAlert //import { useAlert
@@ -30,7 +31,8 @@ const Branding = (props) => {
const [publishingInfo, setPublishingInfo] = useState(""); const [publishingInfo, setPublishingInfo] = useState("");
const [publishRequirements, setPublishRequirements] = useState([]) const [publishRequirements, setPublishRequirements] = useState([])
const { leftSideBarOpenByClick } = useContext(Context)
const handleEditOrg = (joinStatus) => { const handleEditOrg = (joinStatus) => {
const data = { const data = {
"org_id": selectedOrganization.id, "org_id": selectedOrganization.id,
@@ -115,48 +117,73 @@ const Branding = (props) => {
const leadinfo = selectedOrganization.lead_info === undefined || selectedOrganization.lead_info === null || selectedOrganization.lead_info === "" ? "" : JSON.stringify(selectedOrganization.lead_info) const leadinfo = selectedOrganization.lead_info === undefined || selectedOrganization.lead_info === null || selectedOrganization.lead_info === "" ? "" : JSON.stringify(selectedOrganization.lead_info)
const isPartner = leadinfo.includes("partner") const isPartner = leadinfo.includes("partner")
console.log("LEADINFO: ", leadinfo)
console.log("SELECTEDORGANIZATION: ", selectedOrganization)
return ( return (
<div style={{ width: clickedFromOrgTab? 1030: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}> <div style={{ width: clickedFromOrgTab? "100%": "auto", height: "100%", minHeight: 1100, boxSizing: 'border-box', transition: "width 0.3s ease", padding: "27px 10px 19px 27px", height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
<h2 style={{marginTop: clickedFromOrgTab ?0:null,}}> <div style={{height: 843, overflowY: "auto",}}>
<div style={{width: "100%", overflowX: 'hidden', }}>
<Typography style={{fontSize: 24, fontWeight: "bold", marginTop: clickedFromOrgTab ?0:null,}}>
Partner Status & Branding Partner Status & Branding
</h2> </Typography>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}> <Typography variant="body1" color="textSecondary" style={{ marginTop: 10, marginBottom: 10, fontSize: 16 }}>
You can customize your organization's branding by uploading a logo, changing the color scheme and a lot more. You can customize your organization's branding by uploading a logo, changing the color scheme and a lot more.
</Typography> </Typography>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}> <Typography variant="body1" color="textSecondary" style={{display: 'flex', marginTop: 20, marginBottom: 10 }}>
{isPublished ? <CheckCircleIcon style={{color: red, }} /> : <CheckCircleIcon style={{color: green, }} />} {isPublished ? <CheckCircleIcon style={{color: red, }} /> : <CheckCircleIcon style={{color: green, }} />}
<span style={{marginLeft: 10, color: isPublished ? red : green, }}>{isPublished ? "Not Published" : "Published"}</span> <span style={{marginLeft: 10, color: isPublished ? red : green, fontSize: 16 }}>{isPublished ? "Not Published" : "Published"}</span>
</Typography> </Typography>
<a href="https://shuffler.io/partners" target="_blank" style={{ textDecoration: "none", }}> <a href="https://shuffler.io/partners" target="_blank" style={{ textDecoration: "none", }}>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}> <Typography variant="body1" color="textSecondary" style={{display: 'flex', marginTop: 20, marginBottom: 10 }}>
{!isPartner ? <CheckCircleIcon style={{color: red, }} /> : <CheckCircleIcon style={{color: green, }} />} {!isPartner ? <CheckCircleIcon style={{color: red, }} /> : <CheckCircleIcon style={{color: green, }} />}
<Tooltip title="Official Partner Program (manual verification)" placement="top" arrow> <Tooltip title="Official Partner Program (manual verification)" placement="top" arrow>
<span style={{marginLeft: 10, color: !isPartner ? red : green, }}>{!isPartner? "Not Officially Partnered" : "Officially Partnered"}</span> <span style={{marginLeft: 10, color: !isPartner ? red : green, fontSize: 16}}>{!isPartner? "Not Officially Partnered" : "Officially Partnered"}</span>
</Tooltip> </Tooltip>
</Typography> </Typography>
</a> </a>
<a href={`/partners/${selectedOrganization.creator_id}/edit`} target="_blank"> {!isPublished ? (
<Button disabled={isPublished} variant="contained" style={{ marginTop: 20, marginBottom: 10, }} onClick={() => { <a
}}> href={`/partners/${selectedOrganization.creator_id}/edit`}
Modify Public Partner Details target="_blank"
</Button> style={{ textDecoration: "none" }} // Optional: remove underline
</a> >
<Button
variant="contained"
style={{
marginTop: 20,
marginBottom: 10,
textTransform: 'none',
fontSize: 16
}}
>
Modify Public Partner Details
</Button>
</a>
) : (
<Button
disabled
variant="contained"
style={{
marginTop: 20,
marginBottom: 10,
textTransform: 'none',
fontSize: 16
}}
>
Modify Public Partner Details
</Button>
)}
<Divider style={{marginTop: 50, marginBottom: 50, }} /> <Divider style={{marginTop: 50, marginBottom: 50, }} />
<h2> <Typography style={{fontSize: 24, fontWeight: "bold"}}>
Partner Program Partner Program
</h2> </Typography>
<div style={{ display: "flex", width: 900, }}> <div style={{ display: "flex", width: 900, marginTop: 10}}>
<div> <div>
<span> <span>
<Typography variant="body1" color="textSecondary"> <Typography variant="body1" color="textSecondary" style={{fontSize: 16}}>
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization IS reversible.<div/>Support: <a href="mailto:support@shuffler.io"target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>support@shuffler.io</a> By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization IS reversible.<div/>Support: <a href="mailto:support@shuffler.io"target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>support@shuffler.io</a>
</Typography> </Typography>
{selectedOrganization.creator_id == "" ? {selectedOrganization.creator_id == "" ?
@@ -167,9 +194,8 @@ const Branding = (props) => {
null null
} }
<Button <Button
style={{ height: 40, marginTop: 10, width: 300, }} style={{ height: 40, marginTop: 10, width: 300, textTransform: 'none', fontSize: 18, backgroundColor: "#ff8544", color: "#1a1a1a" }}
variant={selectedOrganization.creator_id == "" ? "contained" : "outlined"} variant={selectedOrganization.creator_id == "" ? "contained" : "outlined"}
color={selectedOrganization.creator_id == "" ? "primary" : "secondary"} color={selectedOrganization.creator_id == "" ? "primary" : "secondary"}
disabled={!isOrganizationReady()} disabled={!isOrganizationReady()}
@@ -195,6 +221,8 @@ const Branding = (props) => {
</span> </span>
</div> </div>
</div> </div>
</div>
</div>
</div> </div>
) )
} }
+186 -77
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useContext, memo } from "react";
import theme from "../theme.jsx"; import theme from "../theme.jsx";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import ReactJson from "react-json-view-ssr"; import ReactJson from "react-json-view-ssr";
@@ -19,6 +19,7 @@ import {
Dialog, Dialog,
DialogTitle, DialogTitle,
DialogActions, DialogActions,
Skeleton,
} from "@mui/material"; } from "@mui/material";
import { import {
@@ -47,6 +48,7 @@ import {
VisibilityOff as VisibilityOffIcon, VisibilityOff as VisibilityOffIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { validateJson, } from "../views/Workflows.jsx"; import { validateJson, } from "../views/Workflows.jsx";
import { Context } from "../context/ContextApi.jsx";
const scrollStyle1 = { const scrollStyle1 = {
height: 100, height: 100,
@@ -65,7 +67,7 @@ const scrollStyle2 = {
} }
const CacheView = (props) => { const CacheView = memo((props) => {
const { globalUrl, userdata, serverside, orgId, isSelectedDataStore } = props; const { globalUrl, userdata, serverside, orgId, isSelectedDataStore } = props;
const [orgCache, setOrgCache] = React.useState(""); const [orgCache, setOrgCache] = React.useState("");
const [listCache, setListCache] = React.useState([]); const [listCache, setListCache] = React.useState([]);
@@ -78,11 +80,13 @@ const CacheView = (props) => {
const [cacheCursor, setCacheCursor] = React.useState(""); const [cacheCursor, setCacheCursor] = React.useState("");
const [dataValue, setDataValue] = React.useState({}); const [dataValue, setDataValue] = React.useState({});
const [editCache, setEditCache] = React.useState(false); const [editCache, setEditCache] = React.useState(false);
const [cachedLoaded, setCachedLoaded] = React.useState(false);
const [show, setShow] = useState({}); const [show, setShow] = useState({});
useEffect(() => { useEffect(() => {
listOrgCache(orgId); if(orgId?.length >0){
}, []); listOrgCache(orgId);
}
}, [orgId]);
const listOrgCache = (orgId) => { const listOrgCache = (orgId) => {
fetch(globalUrl + `/api/v1/orgs/${orgId}/list_cache`, { fetch(globalUrl + `/api/v1/orgs/${orgId}/list_cache`, {
@@ -104,6 +108,7 @@ const CacheView = (props) => {
.then((responseJson) => { .then((responseJson) => {
if (responseJson.success === true) { if (responseJson.success === true) {
setListCache(responseJson.keys); setListCache(responseJson.keys);
setCachedLoaded(true);
} }
if (responseJson.cursor !== undefined && responseJson.cursor !== null && responseJson.cursor !== "") { if (responseJson.cursor !== undefined && responseJson.cursor !== null && responseJson.cursor !== "") {
@@ -232,6 +237,34 @@ const CacheView = (props) => {
} }
} }
const handleReactJsonClipboard = (copy) => {
const elementName = "copy_element_shuffle";
let copyText = document.getElementById(elementName);
if (copyText) {
if (copy.namespace && copy.name && copy.src) {
copy = copy.src;
}
const clipboard = navigator.clipboard;
if (!clipboard) {
toast("Can only copy over HTTPS (port 3443)");
return;
}
let stringified = JSON.stringify(copy);
if (stringified.startsWith('"') && stringified.endsWith('"')) {
stringified = stringified.slice(1, -1);
}
navigator.clipboard.writeText(stringified);
toast("Copied value to clipboard, NOT json path.");
} else {
console.log("Failed to copy from " + elementName + ": ", copyText);
}
};
const modalView = ( const modalView = (
// console.log("key:", dataValue.key), // console.log("key:", dataValue.key),
//console.log("value:",dataValue.value), //console.log("value:",dataValue.value),
@@ -241,11 +274,23 @@ const CacheView = (props) => {
setModalOpen(false); setModalOpen(false);
}} }}
PaperProps={{ PaperProps={{
style: { sx: {
backgroundColor: theme.palette.surfaceColor, borderRadius: theme?.palette?.DialogStyle?.borderRadius,
color: "white", border: theme?.palette?.DialogStyle?.border,
minWidth: "800px", minWidth: "800px",
minHeight: "320px", minHeight: "320px",
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,
},
}, },
}} }}
> >
@@ -254,7 +299,7 @@ const CacheView = (props) => {
{ editCache ? "Edit Cache" : "Add Cache" } { editCache ? "Edit Cache" : "Add Cache" }
</span> </span>
</DialogTitle> </DialogTitle>
<div style={{ paddingLeft: "30px", paddingRight: '30px' }}> <div style={{ paddingLeft: "30px", paddingRight: '30px', backgroundColor: "#212121", }}>
Key Key
<TextField <TextField
color="primary" color="primary"
@@ -278,7 +323,7 @@ const CacheView = (props) => {
onChange={(e) => setKey(e.target.value)} onChange={(e) => setKey(e.target.value)}
/> />
</div> </div>
<div style={{ paddingLeft: 30, paddingRight: 30 }}> <div style={{ paddingLeft: 30, paddingRight: 30, backgroundColor: "#212121" }}>
<div style={{display: "flex", }}> <div style={{display: "flex", }}>
<Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}> <Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}>
Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON) Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON)
@@ -320,7 +365,7 @@ const CacheView = (props) => {
</div> </div>
<DialogActions style={{ paddingLeft: "30px", paddingRight: '30px' }}> <DialogActions style={{ paddingLeft: "30px", paddingRight: '30px' }}>
<Button <Button
style={{ borderRadius: "0px" }} style={{ borderRadius: "2px", fontSize: 16, color: "#ff8544", textTransform:"none" }}
onClick={() => { onClick={() => {
setModalOpen(false) setModalOpen(false)
setValue("") setValue("")
@@ -332,7 +377,7 @@ const CacheView = (props) => {
</Button> </Button>
<Button <Button
variant="contained" variant="contained"
style={{ borderRadius: "0px" }} style={{ borderRadius: "2px", backgroundColor: "#ff8544",color: "#1a1a1a", textTransform:"none" }}
onClick={() => { onClick={() => {
{editCache ? editOrgCache(orgId) : addOrgCache(orgId)} {editCache ? editOrgCache(orgId) : addOrgCache(orgId)}
@@ -348,10 +393,11 @@ const CacheView = (props) => {
); );
return ( return (
<div style={{paddingBottom: isSelectedDataStore?null:250, minHeight: 1000, boxSizing: "border-box", width: isSelectedDataStore? "100%" :null, transition: "width 0.3s ease", padding:isSelectedDataStore?"27px 10px 27px 27px":null, height: isSelectedDataStore?"100%":null, color: isSelectedDataStore?'#ffffff':null, backgroundColor: isSelectedDataStore?'#212121':null, borderTopRightRadius: isSelectedDataStore?'8px':null, borderBottomRightRadius: isSelectedDataStore?'8px':null, borderLeft: "1px solid #494949" }}>
<div style={{paddingBottom: isSelectedDataStore?null:250, width: isSelectedDataStore?1030:null, padding:isSelectedDataStore?27:null, height: isSelectedDataStore?"auto":null, color: isSelectedDataStore?'#ffffff':null, backgroundColor: isSelectedDataStore?'#212121':null, borderRadius: isSelectedDataStore?'16px':null, }}>
{modalView} {modalView}
<div style={{ marginTop: isSelectedDataStore?null:20, marginBottom: 20 }}> <div style={{height: "100%", maxHeight: 1700, overflowY: "auto", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin' }}>
<div style={{ marginTop: isSelectedDataStore?null:20, marginBottom: 20 }}>
<h2 style={{ display: isSelectedDataStore?null: "inline" }}>Shuffle Datastore</h2> <h2 style={{ display: isSelectedDataStore?null: "inline" }}>Shuffle Datastore</h2>
<span style={{ marginLeft: isSelectedDataStore?null:25, color:isSelectedDataStore?"#9E9E9E":null}}> <span style={{ marginLeft: isSelectedDataStore?null:25, color:isSelectedDataStore?"#9E9E9E":null}}>
Datastore is a permanent key-value database for storing data that can be used cross-workflow. <br/>You can store anything from lists of IPs to complex configurations.&nbsp; Datastore is a permanent key-value database for storing data that can be used cross-workflow. <br/>You can store anything from lists of IPs to complex configurations.&nbsp;
@@ -366,7 +412,7 @@ const CacheView = (props) => {
</span> </span>
</div> </div>
<Button <Button
style={{backgroundColor: isSelectedDataStore?'rgba(255, 132, 68, 0.2)':null, boxShadow: isSelectedDataStore ? "none":null,textTransform: isSelectedDataStore ? 'capitalize':null, color:isSelectedDataStore?"#FF8444":null, borderRadius:isSelectedDataStore?200: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?8:null, width:isSelectedDataStore?162:null, height:isSelectedDataStore?40:null}}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() =>{ onClick={() =>{
@@ -379,7 +425,7 @@ const CacheView = (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?200:null, width:isSelectedDataStore?81:null, height:isSelectedDataStore?40:null, }} 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, }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => listOrgCache(orgId)} onClick={() => listOrgCache(orgId)}
@@ -392,28 +438,79 @@ const CacheView = (props) => {
marginBottom: 20, marginBottom: 20,
}} }}
/>} />}
<List style={{borderRadius: isSelectedDataStore?8:null, border:isSelectedDataStore?"1px solid #494949":null, marginTop:isSelectedDataStore?24:null}}> <div
<ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore?"1px solid #494949":null}}> style={{
<ListItemText borderRadius: 8,
primary="Key" marginTop: 24,
style={{ minWidth: isSelectedDataStore?200:250, maxWidth: isSelectedDataStore?200:250, }} border: "1px solid #494949",
/> width: "100%",
<ListItemText overflowX: "auto",
primary="Value" paddingBottom: 0,
style={{ minWidth: isSelectedDataStore?300:400, maxWidth: isSelectedDataStore?300:400, overflowX: "auto", overflowY: "hidden", }} }}
/> >
<ListItemText <List
primary="Actions" style={{
style={{ minWidth: 150, maxWidth: 150, marginLeft: isSelectedDataStore?80:null,}} borderRadius: 8,
/> paddingBottom: 0,
<ListItemText tableLayout: "auto",
style={{textAlign:isSelectedDataStore?"center":null}} display: "table",
primary="Updated" width: '100%',
/> minWidth: 800,
overflowX: "auto",
}}>
<ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore?"1px solid #494949":null, display: "table-row"}}>
{["Key", "Value", "Actions", "Updated"].map((header, index) => (
<ListItemText
key={index}
primary={header}
style={{
display: "table-cell",
padding: "0px 8px 8px 8px",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
borderBottom: "1px solid #494949"
}}
/>
))}
</ListItem> </ListItem>
{listCache === undefined || listCache === null {cachedLoaded === false
? null ? [...Array(6)].map((_, rowIndex) => (
: listCache.map((data, index) => { <ListItem
key={rowIndex}
style={{
display: "table-row",
backgroundColor: "#212121",
}}
>
{Array(4)
.fill()
.map((_, colIndex) => (
<ListItemText
key={colIndex}
style={{
display: "table-cell",
padding: "8px",
}}
>
<Skeleton
variant="text"
animation="wave"
sx={{
backgroundColor: "#1a1a1a",
height: "20px",
borderRadius: "4px",
}}
/>
</ListItemText>
))}
</ListItem>
))
: listCache?.length === 0 ? (
<Typography style={{ textAlign: "center", marginTop: 20, marginBottom: 20, minWidth: 1000, }}>
No Keys Found
</Typography>
): listCache?.map((data, index) => {
var bgColor = isSelectedDataStore? "#212121":"#27292d"; var bgColor = isSelectedDataStore? "#212121":"#27292d";
if (index % 2 === 0) { if (index % 2 === 0) {
bgColor = isSelectedDataStore? "#1A1A1A":"#1f2023"; bgColor = isSelectedDataStore? "#1A1A1A":"#1f2023";
@@ -421,49 +518,61 @@ const CacheView = (props) => {
const validate = validateJson(data.value); const validate = validateJson(data.value);
return ( return (
<ListItem key={index} style={{ backgroundColor: bgColor, maxHeight: 300, overflow: "auto", }}> <ListItem key={index} style={{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={{
maxWidth: 200, display: "table-cell",
minWidth: 200,
overflow: "hidden", overflow: "hidden",
padding: 8,
verticalAlign: "middle",
}} }}
primary={data.key} primary={data.key}
/> />
<ListItemText <ListItemText
style={{ style={{
minWidth: 300, display: "table-cell",
maxWidth: 300, overflowY: "auto",
// height:200, overflowX: "auto",
overflowX: "hidden", border: "1px solid rgba(255,255,255,0.7)",
borderRadius: 6,
backgroundColor: "#151515",
maxHeight: 300,
verticalAlign: "middle",
}} }}
primary={validate.valid ? primary={validate.valid ?
<ReactJson <ReactJson
src={validate.result} src={validate.result}
theme={theme.palette.jsonTheme} theme={theme.palette.jsonTheme}
style={theme.palette.reactJsonStyle} style={{
collapsed={true} padding: 5,
enableClipboard={(copy) => { maxHeight: 300,
//handleReactJsonClipboard(copy); overflowY: "auto",
}} }}
displayDataTypes={false} collapsed={true}
onSelect={(select) => { enableClipboard={(copy) => {
//HandleJsonCopy(showResult, select, data.action.label); // handleReactJsonClipboard(copy);
//console.log("SELECTED!: ", select); }}
}} collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
name={"value"} iconStyle={theme.palette.jsonIconStyle}
/> displayDataTypes={false}
onSelect={(select) => {
// HandleJsonCopy(showResult, select, data.action.label);
console.log("SELECTED!: ", select);
}}
name={"value"}
/>
: :
data.value data.value
} }
/> />
<ListItemText <ListItemText
style={{ style={{
maxWidth: 200, display: "table-cell",
minWidth: 200, verticalAlign: "middle",
marginLeft: 50, padding: 8
}} }}
primary=<span style={{ display: "inline" }}> primary={(
<span style={{ display: "inline" }}>
<Tooltip <Tooltip
title="Edit item" title="Edit item"
style={{}} style={{}}
@@ -482,9 +591,7 @@ const CacheView = (props) => {
setModalOpen(true) setModalOpen(true)
}} }}
> >
<EditIcon <img src="/icons/editIcon.svg" alt="edit" />
style={{ color: "white" }}
/>
</IconButton> </IconButton>
</span> </span>
</Tooltip> </Tooltip>
@@ -508,7 +615,6 @@ const CacheView = (props) => {
</Tooltip> </Tooltip>
<Tooltip <Tooltip
title={"Delete item"} title={"Delete item"}
style={{ marginLeft: 25, }}
aria-label={"Delete"} aria-label={"Delete"}
> >
<span> <span>
@@ -519,18 +625,18 @@ const CacheView = (props) => {
//deleteFile(orgId); //deleteFile(orgId);
}} }}
> >
<DeleteIcon <img src="/icons/deleteIcon.svg" alt="delete" />
style={{ color: "white" }}
/>
</IconButton> </IconButton>
</span> </span>
</Tooltip> </Tooltip>
</span> </span>
)}
/> />
<ListItemText <ListItemText
style={{ style={{
maxWidth: 225, display: "table-cell",
minWidth: 225, verticalAlign: "middle",
padding: 8
}} }}
primary={new Date(data.edited * 1000).toISOString()} primary={new Date(data.edited * 1000).toISOString()}
/> />
@@ -538,8 +644,11 @@ const CacheView = (props) => {
); );
})} })}
</List> </List>
</div>
</div>
</div>
</div> </div>
); );
} });
export default CacheView;
export default memo(CacheView);
+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
+398 -330
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useContext, memo } from "react";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { import {
@@ -21,6 +21,7 @@ import {
DialogContent, DialogContent,
DialogActions, DialogActions,
Typography, Typography,
Skeleton,
} from "@mui/material"; } from "@mui/material";
import { import {
@@ -39,11 +40,13 @@ import {
import Dropzone from "../components/Dropzone.jsx"; import Dropzone from "../components/Dropzone.jsx";
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx"; import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
import theme from "../theme.jsx"; import theme from "../theme.jsx";
import { Context } from "../context/ContextApi.jsx";
const Files = (props) => { const Files = memo((props) => {
const { globalUrl, userdata, serverside, selectedOrganization, isCloud,isSelectedFiles } = props; const { globalUrl, userdata, serverside, selectedOrganization, isCloud,isSelectedFiles } = props;
const [files, setFiles] = React.useState([]); const [files, setFiles] = React.useState([]);
const [showLoader, setShowLoader] = useState(true)
const [selectedCategory, setSelectedCategory] = React.useState("default"); const [selectedCategory, setSelectedCategory] = React.useState("default");
const [openFileId, setOpenFileId] = React.useState(false); const [openFileId, setOpenFileId] = React.useState(false);
const [fileCategories, setFileCategories] = React.useState([]); const [fileCategories, setFileCategories] = React.useState([]);
@@ -58,16 +61,13 @@ const Files = (props) => {
const [downloadBranch, setDownloadBranch] = React.useState("main"); const [downloadBranch, setDownloadBranch] = React.useState("main");
const [downloadFolder, setDownloadFolder] = React.useState("translation_standards"); const [downloadFolder, setDownloadFolder] = React.useState("translation_standards");
const [contentLoading, setContentLoading] = React.useState(false) const [contentLoading, setContentLoading] = React.useState(false)
//const alert = useAlert(); //const alert = useAlert();
const allowedFileTypes = ["txt", "py", "yaml", "yml","json", "html", "js", "csv", "log", "eml", "msg", "md", "xml", "sh", "bat", "ps1", "psm1", "psd1", "ps1xml", "pssc", "psc1", "response"] const allowedFileTypes = ["txt", "py", "yaml", "yml","json", "html", "js", "csv", "log", "eml", "msg", "md", "xml", "sh", "bat", "ps1", "psm1", "psd1", "ps1xml", "pssc", "psc1", "response"]
var upload = ""; var upload = "";
const handleKeyDown = (event) => { const handleKeyDown = (event) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
console.log('do validate')
console.log("new namespace name->",event.target.value);
fileCategories.push(event.target.value); fileCategories.push(event.target.value);
setSelectedCategory(event.target.value); setSelectedCategory(event.target.value);
setRenderTextBox(false); setRenderTextBox(false);
@@ -136,6 +136,7 @@ const Files = (props) => {
.then((responseJson) => { .then((responseJson) => {
if (responseJson.files !== undefined && responseJson.files !== null) { if (responseJson.files !== undefined && responseJson.files !== null) {
setFiles(responseJson.files); setFiles(responseJson.files);
setShowLoader(false)
} else if (responseJson.list !== undefined && responseJson.list !== null) { } else if (responseJson.list !== undefined && responseJson.list !== null) {
// Set the "namespace" field in all items // Set the "namespace" field in all items
if (namespace !== undefined && namespace !== null) { if (namespace !== undefined && namespace !== null) {
@@ -147,8 +148,10 @@ const Files = (props) => {
} }
setFiles(responseJson.list); setFiles(responseJson.list);
setShowLoader(false)
} else { } else {
setFiles([]); setFiles([]);
setShowLoader(false)
} }
if (namespace === undefined || namespace === null || namespace === "default") { if (namespace === undefined || namespace === null || namespace === "default") {
@@ -244,15 +247,27 @@ const Files = (props) => {
const fileDownloadModal = loadFileModalOpen ? const fileDownloadModal = loadFileModalOpen ?
<Dialog <Dialog
open={loadFileModalOpen} open={loadFileModalOpen}
onClose={() => {}}
PaperProps={{ PaperProps={{
style: { sx: {
backgroundColor: theme.palette.surfaceColor, borderRadius: theme?.palette?.DialogStyle?.borderRadius,
color: "white", border: theme?.palette?.DialogStyle?.border,
minWidth: "800px", fontFamily: theme?.typography?.fontFamily,
minHeight: "320px", backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
}, zIndex: 1000,
}} minWidth: "800px",
minHeight: "320px",
overflow: "hidden",
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogActions-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
}
}}
> >
<DialogTitle> <DialogTitle>
<div style={{ color: "rgba(255,255,255,0.9)" }}> <div style={{ color: "rgba(255,255,255,0.9)" }}>
@@ -364,7 +379,7 @@ const Files = (props) => {
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button
style={{ borderRadius: "0px" }} style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#ff8544" }}
onClick={() => setLoadFileModalOpen(false)} onClick={() => setLoadFileModalOpen(false)}
color="primary" color="primary"
> >
@@ -372,7 +387,7 @@ const Files = (props) => {
</Button> </Button>
<Button <Button
variant="contained" variant="contained"
style={{ borderRadius: "0px" }} style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#1a1a1a", backgroundColor: "#ff8544" }}
disabled={downloadUrl.length === 0 || !downloadUrl.includes("http")} disabled={downloadUrl.length === 0 || !downloadUrl.includes("http")}
onClick={() => { onClick={() => {
handleGithubValidation(); handleGithubValidation();
@@ -637,24 +652,18 @@ const Files = (props) => {
return ( return (
<Dropzone <Dropzone
style={{ style={{
maxWidth: window.innerWidth > 1366 ? 1366 : 1200,
margin: "auto", margin: "auto",
padding: isSelectedFiles ? null : 20, padding: isSelectedFiles ? null : 20,
width: '100%',
height: "100%",
}} }}
onDrop={uploadFile} onDrop={uploadFile}
> >
<div style={{position: "relative", width: isSelectedFiles? 1030: null, padding:isSelectedFiles?27:null, height: isSelectedFiles?"auto":null, color: isSelectedFiles?'#ffffff':null, backgroundColor: isSelectedFiles?'#212121':null, borderRadius: isSelectedFiles?'16px':null,}}> <div style={{width: "100%", minHeight: 1100, boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: '#212121',borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: "1px solid #494949", }}>
<Tooltip color="primary" title={"Import files to Shuffle from Git"} placement="top"> <div style={{height: "100%", maxHeight: 1700,overflowY: 'auto', scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
<IconButton <div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin' }}>
color="secondary" <DownloadFileIcon setLoadFileModalOpen={setLoadFileModalOpen} isSelectedFiles={isSelectedFiles} />
style={{position: "absolute", right: 0, top: isSelectedFiles?null:0, left: isSelectedFiles? 990:null }}
variant="text"
onClick={() => setLoadFileModalOpen(true)}
>
<CloudDownloadIcon />
</IconButton>
</Tooltip>
{fileDownloadModal} {fileDownloadModal}
@@ -681,9 +690,9 @@ const Files = (props) => {
onClick={() => { onClick={() => {
upload.click(); upload.click();
}} }}
style={{backgroundColor: isSelectedFiles?'rgba(255, 132, 68, 0.2)':null, color:isSelectedFiles?"#FF8444":null, borderRadius:isSelectedFiles?200:null, width:isSelectedFiles?162:null, height:isSelectedFiles?40:null, boxShadow: isSelectedFiles?'none':null,}} 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,}}
> >
<PublishIcon /> Upload files Upload files
</Button> </Button>
{/* <FileCategoryInput {/* <FileCategoryInput
isSet={renderTextBox} /> */} isSet={renderTextBox} /> */}
@@ -702,7 +711,7 @@ const Files = (props) => {
}} }}
/> />
<Button <Button
style={{ marginLeft: 5, marginRight: 15, backgroundColor:isSelectedFiles?"#2F2F2F":null,borderRadius:isSelectedFiles?200:null, width:isSelectedFiles?81:null, height:isSelectedFiles?40:null, boxShadow: isSelectedFiles?'none':null, }} 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, }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => getFiles(selectedCategory)} onClick={() => getFiles(selectedCategory)}
@@ -710,21 +719,23 @@ const Files = (props) => {
<CachedIcon /> <CachedIcon />
</Button> </Button>
{/* <div style={{height: 35, width: 1, color: "#494949"}}></div> */}
{fileCategories !== undefined && {fileCategories !== undefined &&
fileCategories !== null && fileCategories !== null &&
fileCategories.length > 1 ? ( fileCategories.length > 1 ? (
<FormControl style={{ minWidth: 150, maxWidth: 150 }}> <FormControl style={{ minWidth: 150, maxWidth: 150 }}>
<InputLabel id="input-namespace-label">File Category</InputLabel>
<Select <Select
labelId="input-namespace-select-label" labelId="input-namespace-select-label"
id="input-namespace-select-id" id="input-namespace-select-id"
style={{ style={{
color: "white", color: "white",
minWidth: 150, minWidth: 122,
maxWidth: 150, maxWidth: 122,
height: 35,
float: "right", float: "right",
position: 'relative',
top: 8
}} }}
value={selectedCategory} value={selectedCategory}
onChange={(event) => { onChange={(event) => {
@@ -759,7 +770,7 @@ const Files = (props) => {
</Select> </Select>
</FormControl> </FormControl>
) : null} ) : null}
<div style={{display: "inline-flex", position:"relative"}}> <div style={{display: "inline-flex", position:"relative", top: 8}}>
{renderTextBox ? {renderTextBox ?
<Tooltip title={"Close"} style={{}} aria-label={""}> <Tooltip title={"Close"} style={{}} aria-label={""}>
@@ -777,13 +788,14 @@ const Files = (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 }} style={{ marginLeft: 5, marginRight: 15, width: 169, height: 35, backgroundColor: "#494949", textTransform: 'none', fontSize: 16, color: "#f1f1f1" }}
color="primary" color="primary"
onClick={() => { onClick={() => {
setRenderTextBox(true); setRenderTextBox(true);
}} }}
> >
<AddIcon/> <AddIcon/>
File Category
</Button> </Button>
</Tooltip> </Tooltip>
} }
@@ -824,323 +836,379 @@ const Files = (props) => {
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.inputColor,
}} }}
/>} />}
<div
<List style={{borderRadius: isSelectedFiles?8:null, border:isSelectedFiles?"1px solid #494949":null, marginTop:isSelectedFiles?24:null}}> style={{
<ListItem style={{width:isSelectedFiles?"100%":null, borderBottom:isSelectedFiles?"1px solid #494949":null}}> borderRadius: 8,
{/* marginTop: 24,
<ListItemText border: "1px solid #494949",
primary="Updated" width: "100%",
style={{ maxWidth: 185, minWidth: 185 }} overflowX: "auto",
/> paddingBottom: 0,
*/} }}
<ListItemText >
primary="Name" <List
style={{ style={{
maxWidth: 250, width: '100%',
minWidth: 250, tableLayout: "auto",
overflow: "hidden", display: "table",
marginLeft: 10, minWidth: 800,
overflowX: "auto"
}}
>
<ListItem style={{width:isSelectedFiles?"100%":null, borderBottom:isSelectedFiles?"1px solid #494949":null, display: 'table-row'}}>
{["Name", "Workflow", "Md5", "Status", "Filesize", "Actions"].map((header, index) => (
<ListItemText
key={index}
primary={header}
style={{
display: "table-cell",
padding: "0px 8px 8px 8px",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
borderBottom: "1px solid #494949",
verticalAlign: "middle"
}}
primaryTypographyProps={{
style: {
paddingLeft: index === 3 ? 80 : 10,
}
}} }}
/> />
<ListItemText ))}
primary="Workflow"
style={{ maxWidth: 100, minWidth: 100, overflow: "hidden" }}
/>
<ListItemText
primary="Md5"
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }}
/>
<ListItemText
primary="Status"
style={{ minWidth: 75, maxWidth: 75, marginLeft: 10 }}
/>
<ListItemText
primary="Filesize"
style={{ minWidth: 125, maxWidth: 125 }}
/>
<ListItemText primary="Actions" />
</ListItem> </ListItem>
{files === undefined || files === null || files.length === 0 ? null : {showLoader ?
files.map((file, index) => { [...Array(6)].map((_, rowIndex) => (
if (file.namespace === "") { <ListItem
file.namespace = "default"; key={rowIndex}
} style={{
display: "table-row",
if (file.namespace !== selectedCategory) { backgroundColor: "#212121",
return null; }}
} >
{Array(6)
var bgColor = isSelectedFiles ? "#212121":"#27292d"; .fill()
if (index % 2 === 0) { .map((_, colIndex) => (
bgColor = isSelectedFiles ? "#1A1A1A":"#1f2023"; <ListItemText
} key={colIndex}
style={{
const filenamesplit = file.filename.split(".") display: "table-cell",
const iseditable = file.filesize < 2000000 && file.status === "active" && allowedFileTypes.includes(filenamesplit[filenamesplit.length-1]) padding: "8px",
}}
return ( >
<ListItem <Skeleton
key={index} variant="text"
style={{ animation="wave"
backgroundColor: bgColor, sx={{
maxHeight: 100, backgroundColor: "#1a1a1a",
overflow: "hidden", height: "20px",
}} borderRadius: "4px",
> }}
{/* />
<ListItemText </ListItemText>
))}
</ListItem>
)):
files.length === 0 ? (
<div style={{textAlign: "center"}}>
<Typography style={{padding: 25, fontSize: 18, textAlign: 'center'}}>
No files found
</Typography>
</div>
):(
files?.map((file, index) => {
if (file.namespace === "") {
file.namespace = "default";
}
if (file.namespace !== selectedCategory) {
return null;
}
var bgColor = isSelectedFiles ? "#212121":"#27292d";
if (index % 2 === 0) {
bgColor = isSelectedFiles ? "#1A1A1A":"#1f2023";
}
const filenamesplit = file.filename.split(".")
const iseditable = file.filesize < 2000000 && file.status === "active" && allowedFileTypes.includes(filenamesplit[filenamesplit.length-1])
return (
<ListItem
key={index}
style={{ style={{
maxWidth: isSelectedFiles ? 170:225, display: 'table-row',
minWidth: isSelectedFiles ? 170:225, backgroundColor: bgColor,
maxHeight: 100,
overflow: "hidden", overflow: "hidden",
borderBottomLeftRadius: files?.length - 1 === index ? 8 : 0,
borderBottomRightRadius: files?.length - 1 === index ? 8 : 0,
}} }}
primary={new Date(file.updated_at * 1000).toISOString()} >
/> {/*
*/} <ListItemText
<ListItemText style={{
style={{ maxWidth: isSelectedFiles ? 170:225,
maxWidth: 250, minWidth: isSelectedFiles ? 170:225,
minWidth: 250, overflow: "hidden",
overflow: "hidden", }}
marginLeft: 10, primary={new Date(file.updated_at * 1000).toISOString()}
}} />
primary={file.filename} */}
/> <ListItemText
<ListItemText primaryTypographyProps={{
primary={ style: {
file.workflow_id === "global" || file.workflow_id === "" || file.workflow_id === null || file.workflow_id === undefined ? display: 'table-cell',
<IconButton maxWidth: "170px",
disabled={file.workflow_id === "global"} whiteSpace: 'nowrap',
> textOverflow: 'ellipsis',
<OpenInNewIcon overflow: 'hidden',
style={{ padding: 8
color: },
file.workflow_id !== "global" }}
? "white"
: "grey", primary={file.filename}
}} />
/> <ListItemText
</IconButton> primary={
: ( file.workflow_id === "global" || file.workflow_id === "" || file.workflow_id === null || file.workflow_id === undefined ?
<IconButton
disabled={file.workflow_id === "global"}
style={{marginLeft: 10}}
>
<OpenInNewIcon
style={{
color:
file.workflow_id !== "global"
? "#FF8444"
: "grey",
}}
/>
</IconButton>
: (
<Tooltip
title={"Go to workflow"}
style={{}}
aria-label={"Download"}
>
<span>
<a
rel="noopener noreferrer"
style={{
textDecoration: "none",
color: "#f85a3e",
}}
href={`/workflows/${file.workflow_id}`}
target="_blank"
>
<IconButton
disabled={file.workflow_id === "global"}
style={{marginLeft: 10}}
>
<OpenInNewIcon
style={{
color:
file.workflow_id !== "global"
? "#FF8444"
: "grey",
}}
/>
</IconButton>
</a>
</span>
</Tooltip>
)
}
style={{
display: 'table-cell',
overflow: "hidden",
}}
/>
<ListItemText
primary={(
<Tooltip title={file.md5_sum}>
{file.md5_sum}
</Tooltip>
)}
primaryTypographyProps={{
style:{
display: 'table-cell',
marginLeft:isSelectedFiles? 15:null,
overflow: "hidden",
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
maxWidth: 200,
}
}}
/>
<ListItemText
primary={file.status}
style={{
display: 'table-cell',
overflow: "hidden",
textAlign:isSelectedFiles?"left":null,
color: file.status === "active" ? "#2BC07E" : "#FD4C62"
}}
/>
<ListItemText
primary={file.filesize}
style={{
display: 'table-cell',
overflow: "hidden",
textAlign:'center'
}}
/>
<ListItemText
primary=<span style={{ display:"inline"}}>
<Tooltip <Tooltip
title={"Go to workflow"} title={`Edit File (${allowedFileTypes.join(", ")}). Max size 2MB`}
style={{}}
aria-label={"Edit"}
>
<span>
<IconButton
disabled={!iseditable}
style = {{padding: "6px", }}
onClick={() => {
setOpenEditor(true)
setOpenFileId(file.id)
readFileData(file)
}}
>
<img src="/icons/editIcon.svg" alt="edit icon"
style={{color: iseditable ? "white" : "grey",}}
/>
</IconButton>
</span>
</Tooltip>
{/*
<Tooltip
title={"Public URL"}
style={{}}
>
<span>
<IconButton
style = {{padding: "6px"}}
disabled={file.status !== "active"}
onClick={() => {
// Open the file, without downloading it
window.open(`${globalUrl}/api/v1/files/${file.id}/content?type=text&authorization=${file.public_authorization}`, "_blank noreferrer noopener")
}}
>
<LinkIcon
style={{
color:
file.status === "active"
? "white"
: "grey",
}}
/>
</IconButton>
</span>
</Tooltip>
*/}
<Tooltip
title={"Download file"}
style={{}} style={{}}
aria-label={"Download"} aria-label={"Download"}
> >
<span> <span>
<a <IconButton
rel="noopener noreferrer" style = {{padding: "6px"}}
style={{ disabled={file.status !== "active"}
textDecoration: "none", onClick={() => {
color: "#f85a3e", downloadFile(file);
}} }}
href={`/workflows/${file.workflow_id}`}
target="_blank"
> >
<IconButton <img src="/icons/downloadIcon.svg" alt="download icon"
disabled={file.workflow_id === "global"} style={{
> color:
<OpenInNewIcon file.status === "active"
style={{ ? "white"
color: : "grey",
file.workflow_id !== "global" }}
? "white" />
: "grey", </IconButton>
}}
/>
</IconButton>
</a>
</span> </span>
</Tooltip> </Tooltip>
) <Tooltip
} title={"Copy file ID"}
style={{ style={{}}
minWidth: 100, aria-label={"copy"}
maxWidth: 100,
overflow: "hidden",
textAlign: isSelectedFiles?"center":null
}}
/>
<ListItemText
primary={file.md5_sum}
style={{
minWidth: 300,
maxWidth: 300,
marginLeft:isSelectedFiles? 15:null,
overflow: isSelectedFiles?"auto":"hidden",
}}
/>
<ListItemText
primary={file.status}
style={{
minWidth: 75,
maxWidth: 75,
overflow: "hidden",
textAlign:isSelectedFiles?"center":null,
marginLeft: 10,
}}
/>
<ListItemText
primary={file.filesize}
style={{
minWidth: isSelectedFiles?80:125,
maxWidth: isSelectedFiles?80:125,
marginLeft: isSelectedFiles?15:null,
overflow: "hidden",
}}
/>
<ListItemText
primary=<span style={{ display:"inline"}}>
<Tooltip
title={`Edit File (${allowedFileTypes.join(", ")}). Max size 2MB`}
style={{}}
aria-label={"Edit"}
>
<span>
<IconButton
disabled={!iseditable}
style = {{padding: "6px"}}
onClick={() => {
setOpenEditor(true)
setOpenFileId(file.id)
readFileData(file)
}}
>
<EditIcon
style={{color: iseditable ? "white" : "grey",}}
/>
</IconButton>
</span>
</Tooltip>
{/*
<Tooltip
title={"Public URL"}
style={{}}
>
<span>
<IconButton
style = {{padding: "6px"}}
disabled={file.status !== "active"}
onClick={() => {
// Open the file, without downloading it
window.open(`${globalUrl}/api/v1/files/${file.id}/content?type=text&authorization=${file.public_authorization}`, "_blank noreferrer noopener")
}}
>
<LinkIcon
style={{
color:
file.status === "active"
? "white"
: "grey",
}}
/>
</IconButton>
</span>
</Tooltip>
*/}
<Tooltip
title={"Download file"}
style={{}}
aria-label={"Download"}
>
<span>
<IconButton
style = {{padding: "6px"}}
disabled={file.status !== "active"}
onClick={() => {
downloadFile(file);
}}
>
<CloudDownloadIcon
style={{
color:
file.status === "active"
? "white"
: "grey",
}}
/>
</IconButton>
</span>
</Tooltip>
<Tooltip
title={"Copy file ID"}
style={{}}
aria-label={"copy"}
>
<IconButton
style = {{padding: "6px"}}
onClick={() => {
const elementName = "copy_element_shuffle";
var copyText =
document.getElementById(elementName);
if (
copyText !== null &&
copyText !== undefined
) {
const clipboard = navigator.clipboard;
if (clipboard === undefined) {
toast(
"Can only copy over HTTPS (port 3443)"
);
return;
}
navigator.clipboard.writeText(file.id);
copyText.select();
copyText.setSelectionRange(
0,
99999
); /* For mobile devices */
/* Copy the text inside the text field */
document.execCommand("copy");
toast(file.id + " copied to clipboard");
}
}}
> >
<FileCopyIcon style={{ color: "white" }} />
</IconButton>
</Tooltip>
<Tooltip
title={"Delete file"}
style={{marginLeft: isSelectedFiles?5:15, }}
aria-label={"Delete"}
>
<span>
<IconButton <IconButton
disabled={file.status !== "active"}
style = {{padding: "6px"}} style = {{padding: "6px"}}
onClick={() => { onClick={() => {
deleteFile(file) console.log("file is : ", file)
navigator.clipboard.writeText(file.id);
document.execCommand("copy");
toast(file.id + " copied to clipboard");
}} }}
> >
<DeleteIcon <img src="/icons/copyIcon.svg" alt="copy icon" style={{ color: "white" }} />
style={{
color:
file.status === "active"
? "white"
: "grey",
}}
/>
</IconButton> </IconButton>
</span> </Tooltip>
</Tooltip> <Tooltip
</span> title={"Delete file"}
style={{ style={{marginLeft: isSelectedFiles?5:15, }}
minWidth: 250, aria-label={"Delete"}
maxWidth: 250, >
// overflow: "hidden", <span>
}} <IconButton
/> disabled={file.status !== "active"}
</ListItem> style = {{padding: "6px"}}
); onClick={() => {
}) deleteFile(file)
}}
>
<img src="/icons/deleteIcon.svg" alt="delete icon"
style={{
color:
file.status === "active"
? "white"
: "grey",
}}
/>
</IconButton>
</span>
</Tooltip>
</span>
style={{
display: 'table-cell',
textAlign:'center'
// overflow: "hidden",
}}
/>
</ListItem>
);
})
)
} }
</List> </List>
</div>
</div>
</div>
</div> </div>
</Dropzone> </Dropzone>
) )
} })
export default Files; export default memo(Files);
const DownloadFileIcon = memo(({ setLoadFileModalOpen, isSelectedFiles, }) => {
const { leftSideBarOpenByClick } = useContext(Context)
return(
<Tooltip color="primary" title={"Import files to Shuffle from Git"} placement="top">
<IconButton
color="secondary"
style={{position: "absolute", right: 0, top: isSelectedFiles?null:0, left: isSelectedFiles? leftSideBarOpenByClick ? "90%": "85%":null, transition: "left 0.3s ease" }}
variant="text"
onClick={() => setLoadFileModalOpen(true)}
>
<CloudDownloadIcon />
</IconButton>
</Tooltip>
)
})
+246 -89
View File
@@ -7,6 +7,7 @@ import {
Add as AddIcon, Add as AddIcon,
BorderColor, BorderColor,
Close as CloseIcon, Close as CloseIcon,
ConstructionOutlined,
} from "@mui/icons-material"; } from "@mui/icons-material";
import SearchBox from "./SearchData.jsx"; import SearchBox from "./SearchData.jsx";
import { import {
@@ -85,7 +86,21 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
return orgOptions.find((option) => option.name === selectedOrg); return orgOptions.find((option) => option.name === selectedOrg);
}, [selectedOrg, orgOptions]); }, [selectedOrg, orgOptions]);
//With this code it is opening search bar on google chrome search bar as well which is not required
useEffect(() => {
const handleKeyDown = (event) => {
if ((event.ctrlKey || event.metaKey) && event.key === "k") {
event.preventDefault();
setSearchBarModalOpen((prev)=> !prev);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [setSearchBarModalOpen]);
const CustomPopper = (props) => { const CustomPopper = (props) => {
return ( return (
@@ -141,7 +156,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
> >
{props.children} {props.children}
</Box> </Box>
<Link to="/admin2" style={hrefStyle}> <Link to="/admin?tab=tenants" style={hrefStyle}>
<Box <Box
sx={{ sx={{
width: "100%", width: "100%",
@@ -446,7 +461,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
}, },
}} }}
> >
<Link to="/admin2" style={hrefStyle}> <Link to="/admin" style={hrefStyle}>
<MenuItem <MenuItem
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
@@ -466,7 +481,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
</Link> </Link>
<Divider style={{ marginTop: 10, marginBottom: 10, }} /> <Divider style={{ marginTop: 10, marginBottom: 10, }} />
<Link to="/admin2?admin_tab=priorities" style={hrefStyle}> <Link to="/admin?admin_tab=notifications" style={hrefStyle}>
<MenuItem <MenuItem
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
@@ -478,7 +493,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
}) })
</MenuItem> </MenuItem>
</Link> </Link>
<Link to="/usecases2" style={hrefStyle}> <Link to="/usecases" style={hrefStyle}>
<MenuItem <MenuItem
onClick={(event) => { onClick={(event) => {
handleClose(); handleClose();
@@ -641,7 +656,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
}; };
const getRegionTag = (region_url) => { const getRegionTag = (region_url) => {
let regiontag = "eu"; let regiontag = "UK";
if ( if (
region_url !== undefined && region_url !== undefined &&
region_url !== null && region_url !== null &&
@@ -653,15 +668,25 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
regiontag = namesplit[namesplit.length - 1]; regiontag = namesplit[namesplit.length - 1];
if (regiontag === "california") { if (regiontag === "california") {
regiontag = "us"; regiontag = "US";
} else if (regiontag === "frankfurt") { } else if (regiontag === "frankfurt") {
regiontag = "fr"; regiontag = "EU";
} else if (regiontag === "ca"){
regiontag = "CA";
} }
} }
} }
return regiontag; return regiontag;
}; };
useEffect(() => {
if(activeOrgName !== userdata?.active_org?.name){
setActiveOrgName(userdata?.active_org?.name || "Select Organization");
}
}, [userdata]);
const CheckOrgStates = useCallback(() => { const CheckOrgStates = useCallback(() => {
setOrgOptions( setOrgOptions(
userdata?.orgs?.map((org) => ({ userdata?.orgs?.map((org) => ({
@@ -723,6 +748,20 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
</Dialog> </Dialog>
); );
const getRegionFlag = (region_url) => {
var region = "gb";
const regionMapping = {
"US": "us",
"EU": "eu",
"CA": "ca",
"UK": "gb"
};
region = regionMapping[region_url] || "gb";
return `https://flagcdn.com/48x36/${region}.png`;
};
return ( return (
<div <div
style={{ style={{
@@ -736,7 +775,8 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.2)" , boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.2)" ,
resize: 'both', resize: 'both',
height: "calc(100vh - 32px)", zoom: 0.8,
height: "calc((100vh - 32px)*1.2)",
}} }}
> >
{modalView} {modalView}
@@ -759,7 +799,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
alignItems: "center", // alignItems: "center",
justifyContent: "center", justifyContent: "center",
position: "relative", position: "relative",
right: !expandLeftNav && 8, right: !expandLeftNav && 8,
@@ -814,46 +854,62 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
{expandLeftNav ? ( {expandLeftNav ? (
<Fade in={expandLeftNav} timeout={500}> <Fade in={expandLeftNav} timeout={500}>
<TextField <TextField
id="sidebar-search" id="sidebar-search"
placeholder= "Search" placeholder="Search"
sx={{ sx={{
width: "100%", width: "100%",
maxWidth: 228, maxWidth: 228,
"& .MuiInputBase-root": { "& .MuiInputBase-root": {
height: 35, height: 35,
padding: 0, padding: 0,
}, },
"& .MuiOutlinedInput-root": { "& .MuiOutlinedInput-root": {
cursor: "pointer", cursor: "pointer",
width: 228, width: 228,
"& fieldset": { "& fieldset": {
borderColor: "#494949", borderColor: "#494949",
}, },
"&:hover fieldset": { "&:hover fieldset": {
borderColor: "#ffffff", borderColor: "#ffffff",
display: "block" display: "block",
}, },
"&.Mui-focused fieldset": { "&.Mui-focused fieldset": {
borderColor: "#A9A9A9", borderColor: "#A9A9A9",
}, },
}, },
"& input": { "& input": {
padding: "8px 14px", padding: "8px 14px",
fontSize: "14px", fontSize: "14px",
color: "#C8C8C8", color: "#C8C8C8",
}, },
backgroundColor: "transparent", backgroundColor: "transparent",
}} }}
variant="outlined" variant="outlined"
InputProps={{ InputProps={{
startAdornment: ( startAdornment: (
<SearchIcon style={{ color: "#CDCDCD", width: 24, height: 24, marginLeft: 16}} /> <SearchIcon style={{ color: "#CDCDCD", width: 24, height: 24, marginLeft: 16 }} />
), ),
disableUnderline: true, endAdornment: (
}} <span
onClick={()=>{setSearchBarModalOpen(true)}} style={{
onChange={()=> {setSearchBarModalOpen(true)}} color: "#C8C8C8",
/> fontSize: "12px",
marginRight: 16,
whiteSpace: "nowrap",
}}
>
<kbd>Ctrl</kbd>/<kbd>Cmd</kbd>+<kbd>K</kbd>
</span>
),
disableUnderline: true,
}}
onClick={() => {
setSearchBarModalOpen(true);
}}
onChange={() => {
setSearchBarModalOpen(true);
}}
/>
</Fade> </Fade>
):( ):(
<> <>
@@ -891,10 +947,16 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
setCurrentOpenTab("automate"); setCurrentOpenTab("automate");
localStorage.setItem("lastTabOpenByUser", "automate"); localStorage.setItem("lastTabOpenByUser", "automate");
}} }}
sx={{ variant="text"
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 === "/usecases2" || currentPath.includes("/search"))))? "#2f2f2f": "transparent",
"&:hover": { backgroundColor: "#2f2f2f" }, }}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = ((currentOpenTab === "automate" && currentPath.includes("/dashboards/automate"))|| (!expandLeftNav && (currentPath === "/workflows" || currentPath === "/usecases2" || currentPath.includes("/search"))))? "#2f2f2f": "transparent";
}} }}
> >
<img <img
@@ -920,8 +982,15 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
setOpenautomateTab((prev) => !prev); setOpenautomateTab((prev) => !prev);
setOpenSecurityTab(false); setOpenSecurityTab(false);
}} }}
sx={{ style={{
marginLeft: 0.625, color: "#FFFFFF",
marginLeft: 0.625,
}}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = "transparent";
}} }}
> >
{openautomatetab ? ( {openautomatetab ? (
@@ -952,23 +1021,28 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
flexDirection: "column", flexDirection: "column",
paddingLeft: 16, paddingLeft: 16,
gap: 4, gap: 4,
marginTop: expandLeftNav ? 16 : 0,
}} }}
> >
<Link to="/usecases2" style={hrefStyle}> <Link to="/usecases" style={hrefStyle}>
<Button <Button
onClick={(event) => { onClick={(event) => {
setCurrentOpenTab("usecases"); setCurrentOpenTab("usecases");
localStorage.setItem("lastTabOpenByUser", "usecases"); localStorage.setItem("lastTabOpenByUser", "usecases");
}} }}
sx={{ style={{
width: "100%", width: "100%",
height: 35, height: 35,
color: "#C8C8C8", color: "#C8C8C8",
justifyContent: "flex-start", justifyContent: "flex-start",
textTransform: "none", textTransform: "none",
backgroundColor: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases2")? "#2f2f2f": "transparent", backgroundColor: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases")? "#2f2f2f": "transparent",
"&:hover": { backgroundColor: "#2f2f2f" }, marginLeft: 16
}}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases")? "#2f2f2f": "transparent";
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
> >
@@ -985,22 +1059,28 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
</span> </span>
</Button> </Button>
</Link> </Link>
<Link to="/workflows2" style={hrefStyle}> <Link to="/workflows" style={hrefStyle}>
<Button <Button
onClick={(event) => { onClick={(event) => {
setCurrentOpenTab("workflows"); setCurrentOpenTab("workflows");
localStorage.setItem("lastTabOpenByUser", "workflows"); localStorage.setItem("lastTabOpenByUser", "workflows");
}} }}
sx={{ style={{
width: "100%", width: "100%",
height: 35, height: 35,
color: "#C8C8C8", color: "#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",
"&:hover": { backgroundColor: "#2f2f2f" }, marginLeft: 16
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
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: 16 }}></span>{" "}
<span <span
@@ -1015,20 +1095,26 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
</span> </span>
</Button> </Button>
</Link> </Link>
<Link to="/apps2" style={hrefStyle}> <Link to="/apps" style={hrefStyle}>
<Button <Button
onClick={(event) => { onClick={(event) => {
setCurrentOpenTab("apps"); setCurrentOpenTab("apps");
localStorage.setItem("lastTabOpenByUser", "apps"); localStorage.setItem("lastTabOpenByUser", "apps");
}} }}
sx={{ style={{
width: "100%", width: "100%",
height: 35, height: 35,
color: "#C8C8C8", color: "#C8C8C8",
justifyContent: "flex-start", justifyContent: "flex-start",
textTransform: "none", textTransform: "none",
backgroundColor: currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/search") ? "#2f2f2f": "transparent", backgroundColor: currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/apps2") ? "#2f2f2f": "transparent",
"&:hover": { backgroundColor: "#2f2f2f" }, marginLeft: 16
}}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/search") ? "#2f2f2f": "transparent";
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
> >
@@ -1038,7 +1124,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
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("/search") ? "#F1F1F1" : "#C8C8C8", color: currentOpenTab === "apps" && currentPath.includes("/apps2") ? "#F1F1F1" : "#C8C8C8",
}} }}
> >
Apps Apps
@@ -1051,7 +1137,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
marginTop: 2.5, marginTop: 1
}} }}
> >
<span style={{ display: "inline-block", width: "100%" }}> <span style={{ display: "inline-block", width: "100%" }}>
@@ -1072,7 +1158,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
setCurrentOpenTab("security"); setCurrentOpenTab("security");
localStorage.setItem("lastTabOpenByUser", "security"); localStorage.setItem("lastTabOpenByUser", "security");
}} }}
sx={{ style={{
...ButtonStyle, ...ButtonStyle,
backgroundColor: backgroundColor:
((currentOpenTab === "security" && currentPath.includes("/security")) || ((currentOpenTab === "security" && currentPath.includes("/security")) ||
@@ -1080,11 +1166,19 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
(currentPath.includes("detections") || currentPath.includes("response")))) (currentPath.includes("detections") || currentPath.includes("response"))))
? "#2f2f2f" ? "#2f2f2f"
: "transparent", : "transparent",
"&:hover": {
backgroundColor: userdata?.support ? "#2f2f2f" : "transparent",
},
cursor: userdata?.support ? "pointer" : "not-allowed", cursor: userdata?.support ? "pointer" : "not-allowed",
}} }}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = ((currentOpenTab === "security" && currentPath.includes("/security")) ||
(!expandLeftNav &&
(currentPath.includes("detections") || currentPath.includes("response"))))
? "#2f2f2f"
: "transparent";
}}
disabled={!userdata?.support}
> >
<ShieldOutlinedIcon <ShieldOutlinedIcon
style={{ style={{
@@ -1105,19 +1199,25 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
: "#6F6F6F", : "#6F6F6F",
}} }}
> >
Security Content
</span> </span>
</Button> </Button>
</Link> </Link>
</span> </span>
<IconButton <IconButton
disabled={true}
onClick={() => { onClick={() => {
setOpenSecurityTab((prev) => !prev); setOpenSecurityTab((prev) => !prev);
setOpenautomateTab(false); setOpenautomateTab(false);
}} }}
sx={{ style={{
marginLeft: 0.625, marginLeft: 0.625,
color: "#FFFFFF",
}}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = "transparent";
}} }}
> >
{openSecurityTab ? ( {openSecurityTab ? (
@@ -1144,14 +1244,12 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
paddingLeft: 16, paddingLeft: 16,
gap: 4,
marginTop: expandLeftNav ? 16 : 0,
}} }}
disableRipple={expandLeftNav ? false : true} disableRipple={expandLeftNav ? false : true}
> >
<span style={{ display: "inline-block", width: "100%" }}> <span style={{ display: "inline-block", width: "100%" }}>
<Link <Link
to={userdata?.support ? "/detections" : "#"} to={"/forms"}
style={{ style={{
...hrefStyle, ...hrefStyle,
pointerEvents: userdata?.support ? "auto" : "none", pointerEvents: userdata?.support ? "auto" : "none",
@@ -1196,14 +1294,14 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
: "#6F6F6F", : "#6F6F6F",
}} }}
> >
Detection Forms
</span> </span>
</Button> </Button>
</Link> </Link>
</span> </span>
<span style={{ display: "inline-block", width: "100%" }}> <span style={{ display: "inline-block", width: "100%" }}>
<Link <Link
to={userdata?.support ? "/response" : "#"} to={"/admin?tab=datastore"}
style={{ style={{
...hrefStyle, ...hrefStyle,
pointerEvents: userdata?.support ? "auto" : "none", pointerEvents: userdata?.support ? "auto" : "none",
@@ -1230,7 +1328,6 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
}, },
cursor: userdata?.support ? "pointer" : "not-allowed", cursor: userdata?.support ? "pointer" : "not-allowed",
}} }}
disabled={!userdata?.support}
> >
<span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 16 }}> <span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 16 }}>
@@ -1248,26 +1345,81 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
: "#6F6F6F", : "#6F6F6F",
}} }}
> >
Response Datastore
</span>
</Button>
</Link>
</span>
<span style={{ display: "inline-block", width: "100%" }}>
<Link
to={"/admin?tab=files"}
style={{
...hrefStyle,
pointerEvents: userdata?.support ? "auto" : "none",
}}
>
<Button
onClick={(event) => {
if (!userdata?.support) return;
setCurrentOpenTab("response");
localStorage.setItem("lastTabOpenByUser", "response");
}}
sx={{
width: "100%",
height: 35,
color: userdata?.support ? "#C8C8C8" : "#6F6F6F",
justifyContent: "flex-start",
textTransform: "none",
backgroundColor:
currentOpenTab === "response" && currentPath.includes("/response")
? "#2f2f2f"
: "transparent",
"&:hover": {
backgroundColor: userdata?.support ? "#2f2f2f" : "transparent",
},
cursor: userdata?.support ? "pointer" : "not-allowed",
}}
>
<span style={{ 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",
color:
userdata?.support && currentOpenTab === "response" && currentPath.includes("/response")
? "#F1F1F1"
: userdata?.support
? "#C8C8C8"
: "#6F6F6F",
}}
>
Files
</span> </span>
</Button> </Button>
</Link> </Link>
</span> </span>
</Box> </Box>
</Collapse> </Collapse>
<Link to="/docs" style={hrefStyle}> <Link to="/docs" style={hrefStyle}>
<Button <Button
onClick={(event) => { onClick={(event) => {
setCurrentOpenTab("docs"); setCurrentOpenTab("docs");
localStorage.setItem("lastTabOpenByUser", "docs"); localStorage.setItem("lastTabOpenByUser", "docs");
}} }}
sx={{ style={{
...ButtonStyle, ...ButtonStyle,
marginTop: 2, marginTop: 8,
marginTop: 8,
backgroundColor: currentOpenTab === "docs" && currentPath.includes("/docs") ? "#2f2f2f": "transparent", backgroundColor: currentOpenTab === "docs" && currentPath.includes("/docs") ? "#2f2f2f": "transparent",
"&:hover": { backgroundColor: "#2f2f2f" }, }}
onMouseOver={(event)=>{
event.currentTarget.style.backgroundColor = "#2f2f2f";
}}
onMouseOut={(event)=>{
event.currentTarget.style.backgroundColor = currentOpenTab === "docs" && currentPath.includes("/docs") ? "#2f2f2f": "transparent";
}} }}
> >
<img <img
@@ -1385,15 +1537,20 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
> >
{ {
isCloud ? ( isCloud ? (
<span <span
style={{ style={{
color: "#bbb", color: "#bbb",
fontSize: "16px", fontSize: "16px",
marginRight: 12, marginRight: 12,
display: "flex",
alignItems: "center",
justifyContent: "center",
}} }}
> >
<img src={getRegionFlag(option.region_url)} alt={option.region_url} style={{ width: 24, height: 24, marginRight: 12, borderRadius: "50%" }} />
{option.region_url} {option.region_url}
</span>) : null </span>
) : null
} }
<img <img
src={option.image ? option.image : "/images/no_image.png"} src={option.image ? option.image : "/images/no_image.png"}
+1 -1
View File
@@ -127,7 +127,7 @@ const MFASetup = ({ isLoaded, globalUrl, setCookie }) => {
}; };
return ( return (
<div style={{ margin: "50px auto", width: "500px" }}> <div style={{ paddingTop: 50, margin: "0px auto", width: "500px" }}>
<Paper elevation={3} style={{ padding: "30px", backgroundColor: "#212121" }}> <Paper elevation={3} style={{ padding: "30px", backgroundColor: "#212121" }}>
<Typography variant="h5" style={{ color: "white", marginBottom: 10, textAlign: "center" }}> <Typography variant="h5" style={{ color: "white", marginBottom: 10, textAlign: "center" }}>
Multi-Factor Authentication Setup Multi-Factor Authentication Setup
+24 -2
View File
@@ -110,8 +110,30 @@ const OrgHeader = (props) => {
orgDescription, orgDescription,
selectedOrganization.id, selectedOrganization.id,
selectedOrganization.image, selectedOrganization.image,
{}, {
{}, app_download_repo: selectedOrganization?.defaults?.app_download_repo,
app_download_branch: selectedOrganization?.defaults?.app_download_branch,
workflow_download_repo: selectedOrganization?.defaults?.workflow_download_repo,
workflow_download_branch: selectedOrganization?.defaults?.workflow_download_branch,
notification_workflow: selectedOrganization?.defaults?.notification_workflow,
documentation_reference: selectedOrganization?.defaults?.documentation_reference,
workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo,
workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch,
workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username,
workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token,
newsletter: selectedOrganization?.defaults?.newsletter,
weekly_recommendations: selectedOrganization?.defaults?.weekly_recommendations,
},
{
sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint,
sso_certificate: selectedOrganization?.sso_config?.sso_certificate,
client_id: selectedOrganization?.sso_config?.client_id,
client_secret: selectedOrganization?.sso_config?.client_secret,
openid_authorization: selectedOrganization?.sso_config?.openid_authorization,
openid_token: selectedOrganization?.sso_config?.openid_token,
SSORequired: selectedOrganization?.sso_config?.SSORequired,
auto_provision: selectedOrganization?.sso_config?.auto_provision,
},
[], [],
) )
} }
@@ -227,7 +227,7 @@ const OrgHeaderexpanded = (props) => {
defaults, defaults,
sso_config sso_config
) => { ) => {
console.log("defatult in handleEditOrg", defaults)
const data = { const data = {
name: name, name: name,
description: description, description: description,
@@ -309,6 +309,7 @@ const OrgHeaderexpanded = (props) => {
openid_authorization: openidAuthorization, openid_authorization: openidAuthorization,
openid_token: openidToken, openid_token: openidToken,
SSORequired: SSORequired, SSORequired: SSORequired,
auto_provision: selectedOrganization?.sso_config?.auto_provision,
} }
) )
} }
@@ -485,6 +486,7 @@ const OrgHeaderexpanded = (props) => {
value={data} value={data}
onClick={(e) => { onClick={(e) => {
var parsedinput = { target: { value: data } } var parsedinput = { target: { value: data } }
console.log("Parsed input: ", parsedinput)
handleWorkflowSelectionUpdate(parsedinput) handleWorkflowSelectionUpdate(parsedinput)
}} }}
> >
@@ -753,7 +755,7 @@ const OrgHeaderexpanded = (props) => {
{SSORequired ? "Required" : "Optional"} {SSORequired ? "Required" : "Optional"}
</div> </div>
</div> </div>
<div {/* <div
style={{ style={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
@@ -800,7 +802,7 @@ const OrgHeaderexpanded = (props) => {
</Button> </Button>
</span> </span>
</Tooltip> </Tooltip>
</div> </div> */}
<div></div> <div></div>
<Grid item xs={12} style={{}}> <Grid item xs={12} style={{}}>
<Typography variant="h6" style={{ textAlign: "center" }}> <Typography variant="h6" style={{ textAlign: "center" }}>
+34 -31
View File
@@ -53,6 +53,7 @@ import {
import { import {
HelpOutline as HelpOutlineIcon, HelpOutline as HelpOutlineIcon,
OpenInFull as OpenInFullIcon,
Description as DescriptionIcon, Description as DescriptionIcon,
GetApp as GetAppIcon, GetApp as GetAppIcon,
Search as SearchIcon, Search as SearchIcon,
@@ -2090,7 +2091,7 @@ const ParsedAction = (props) => {
{data?.validation?.valid === true ? {data?.validation?.valid === true ?
<Tooltip title="Authentication has been validated" placement="top"> <Tooltip title="Authentication has been validated" placement="top">
<Chip <Chip
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer", borderColor: green, }} style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer", borderColor: green, maxHeight: 25, }}
label={"Valid"} label={"Valid"}
variant="outlined" variant="outlined"
color="secondary" color="secondary"
@@ -2099,7 +2100,7 @@ const ParsedAction = (props) => {
: null } : null }
{data?.last_modified === true ? {data?.last_modified === true ?
<Chip <Chip
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}} style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer", maxHeight: 25, }}
label={"Latest"} label={"Latest"}
variant="outlined" variant="outlined"
color="secondary" color="secondary"
@@ -2139,7 +2140,7 @@ const ParsedAction = (props) => {
> >
<IconButton <IconButton
color="primary" color="primary"
variant="outlined" variant="outlined"
style={{}} style={{}}
onClick={() => { onClick={() => {
setAuthenticationModalOpen(true); setAuthenticationModalOpen(true);
@@ -3452,36 +3453,10 @@ const ParsedAction = (props) => {
disableUnderline: true, disableUnderline: true,
endAdornment: hideExtraTypes ? null : ( endAdornment: hideExtraTypes ? null : (
<InputAdornment position="end"> <InputAdornment position="end">
<ButtonGroup orientation={multiline ? "vertical" : "horizontal"}> <ButtonGroup color="secondary" orientation={multiline ? "vertical" : "horizontal"}>
<Tooltip title="Expand window" placement="top">
<AspectRatioIcon
style={{ cursor: "pointer", margin: multiline ? 5 : 0 ,}}
onClick={(event) => {
event.preventDefault()
setFieldCount(count)
setExpansionModalOpen(true)
setActiveDialog("codeeditor")
//setcodedata(data.value)
var parsedvalue = data.value
if (parsedvalue === undefined || parsedvalue === null) {
parsedvalue = ""
}
setEditorData({
"name": data.name,
"value": parsedvalue,
"field_number": count,
"actionlist": actionlist,
"field_id": clickedFieldId,
"example": selectedActionParameters[count].example,
})
}}
/>
</Tooltip>
<Tooltip title="Autocomplete text" placement="bottom"> <Tooltip title="Autocomplete text" placement="bottom">
<AddCircleOutlineIcon <AddCircleOutlineIcon
style={{ cursor: "pointer", margin: multiline ? 5 : 0, }} style={{ color: "rgba(255,255,255,0.7)", cursor: "pointer", margin: multiline ? 5 : 0, }}
onClick={(event) => { onClick={(event) => {
event.preventDefault() event.preventDefault()
@@ -4355,6 +4330,34 @@ const ParsedAction = (props) => {
{tmpitem} <span style={{color: theme.palette.main}}>{selectedActionParameters[count].required || selectedActionParameters[count].configuration ? "*" : ""}</span> {tmpitem} <span style={{color: theme.palette.main}}>{selectedActionParameters[count].required || selectedActionParameters[count].configuration ? "*" : ""}</span>
</div> </div>
<Tooltip title="Expand editor window" placement="top">
<OpenInFullIcon
style={{ color: "rgba(255,255,255,0.7)", cursor: "pointer", margin: multiline ? 5 : 0, height: 20, width: 20, }}
onClick={(event) => {
event.preventDefault()
setFieldCount(count)
setExpansionModalOpen(true)
setActiveDialog("codeeditor")
//setcodedata(data.value)
var parsedvalue = data.value
if (parsedvalue === undefined || parsedvalue === null) {
parsedvalue = ""
}
setEditorData({
"name": data.name,
"value": parsedvalue,
"field_number": count,
"actionlist": actionlist,
"field_id": clickedFieldId,
"example": selectedActionParameters[count].example,
})
}}
/>
</Tooltip>
</div> </div>
{datafield} {datafield}
{/*shufflecode*/} {/*shufflecode*/}
+241 -200
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useContext, memo } from "react";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import theme from "../theme.jsx"; import theme from "../theme.jsx";
@@ -13,22 +13,25 @@ import {
Card, Card,
Chip, Chip,
Switch, Switch,
Skeleton,
} from "@mui/material"; } from "@mui/material";
import { Context } from "../context/ContextApi.jsx";
import { useNavigate, Link } from "react-router-dom"; import { useNavigate, Link } from "react-router-dom";
import Priority from "../components/Priority.jsx"; import Priority from "../components/Priority.jsx";
import { constrainMatrix } from "reaviz";
//import { useAlert //import { useAlert
const Priorities = (props) => { const Priorities = memo((props) => {
const { globalUrl, userdata,clickedFromOrgTab, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, notifications, setNotifications, } = props; const { globalUrl, userdata,clickedFromOrgTab, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, notifications, setNotifications, } = props;
const [showDismissed, setShowDismissed] = React.useState(false); const [showDismissed, setShowDismissed] = React.useState(false);
const [showRead, setShowRead] = React.useState(false); const [showRead, setShowRead] = React.useState(false);
const [appFramework, setAppFramework] = React.useState({}); const [appFramework, setAppFramework] = React.useState({});
const [selectedWorkflow, setSelectedWorkflow] = React.useState("NO HIGHLIGHT"); const [selectedWorkflow, setSelectedWorkflow] = React.useState("NO HIGHLIGHT");
const [selectedExecutionId, setSelectedExecutionId] = React.useState("NO HIGHLIGHT"); const [selectedExecutionId, setSelectedExecutionId] = React.useState("NO HIGHLIGHT");
const [highlightKMS, setHighlightKMS] = React.useState(false) const [highlightKMS, setHighlightKMS] = React.useState(false)
let navigate = useNavigate(); let navigate = useNavigate();
useEffect(() => { useEffect(() => {
getFramework() getFramework()
@@ -216,188 +219,16 @@ const Priorities = (props) => {
const notificationWidth = "100%" const notificationWidth = "100%"
const imagesize = 22 const imagesize = 22
const boxColor = "#86c142" const boxColor = "#86c142"
const NotificationItem = (props) => {
const {data} = props
var image = "";
var orgName = "";
var orgId = "";
var highlighted = selectedExecutionId === "" && selectedWorkflow === "" ? false : data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow)
if (!highlighted && highlightKMS) {
if (data.title !== undefined && data.title !== null && data.title.toLowerCase().includes("kms")) {
highlighted = true
} else if (data.description !== undefined && data.description !== null && data.description.toLowerCase().includes("kms")) {
highlighted = true
}
}
if (userdata.orgs !== undefined) {
const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]);
if (foundOrg !== undefined && foundOrg !== null) {
//position: "absolute", bottom: 5, right: -5,
const imageStyle = {
width: imagesize,
height: imagesize,
pointerEvents: "none",
marginLeft:
data.creator_org !== undefined && data.creator_org.length > 0
? 20
: 0,
borderRadius: 10,
border:
foundOrg.id === userdata.active_org.id
? `3px solid ${boxColor}`
: null,
cursor: "pointer",
marginRight: 10,
};
image =
foundOrg.image === "" ? (
<img
alt={foundOrg.name}
src={theme.palette.defaultImage}
style={imageStyle}
/>
) : (
<img
alt={foundOrg.name}
src={foundOrg.image}
style={imageStyle}
onClick={() => {}}
/>
);
orgName = foundOrg.name;
orgId = foundOrg.id;
}
}
return (
<Paper
style={{
backgroundColor: theme.palette.platformColor,
width: clickedFromOrgTab ? null :notificationWidth,
padding: 30,
borderBottom: "1px solid rgba(255,255,255,0.4)",
marginBottom: 20,
border: highlighted ? "2px solid #f85a3e" : null,
borderRadius: theme.palette?.borderRadius,
}}
>
<div style={{display: "flex", }}>
{data.amount === 1 && data.read === false ?
<Chip
label={"First seen"}
variant="contained"
color="primary"
style={{marginRight: 15, height: 25, }}
/>
: null}
{data.ignored === true ?
<Chip
label={"Disabled"}
variant="outlined"
color="primary"
style={{marginRight: 15, height: 25, }}
/>
: null}
{data.read === false ?
<Chip
label={"Unread"}
variant="outlined"
color="primary"
style={{marginRight: 15, height: 25, }}
/>
:
<Chip
label={"Read"}
variant="outlined"
color="secondary"
style={{marginRight: 15, height: 25, }}
/>
}
<Typography variant="body1" color="textPrimary">
{data.title}
</Typography >
</div>
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
<img alt={data.title} src={data.image} style={{height: 100, width: 100, }} />
:
null
}
<Typography variant="body2" color="textSecondary" style={{marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", }}>
{data.description}
</Typography >
<div style={{ display: "flex" }}>
<ButtonGroup>
<Button
color="secondary"
variant="outlined"
style={{ marginTop: 15 }}
disabled={data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0}
onClick={() => {
window.open(data.reference_url, "_blank")
}}
>
Explore
</Button>
{data.read === false ? (
<Button
color="secondary"
variant="outlined"
style={{ marginTop: 15 }}
onClick={() => {
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, }}>
<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, }}>
<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, }}>
<b>Times seen</b>: {data.amount}
</Typography >
</div>
</Paper>
);
}
return ( return (
<div style={{width: clickedFromOrgTab ? 1030:1000, padding: clickedFromOrgTab ? 27:null, height: clickedFromOrgTab ? "auto":null, backgroundColor: clickedFromOrgTab ? '#212121':null, borderRadius: clickedFromOrgTab ? '16px':null, }}> <div style={{width: "100%", height: "100%", boxSizing: 'border-box', transition: 'width 0.3s ease', padding: clickedFromOrgTab ? "27px 10px 19px 27px":null, height: clickedFromOrgTab ? "auto":null, minHeight: 843, backgroundColor: clickedFromOrgTab ? '#212121':null, borderRadius: clickedFromOrgTab ? '16px':null, }}>
<h2 style={{ display: clickedFromOrgTab?null:"inline", marginBottom: clickedFromOrgTab? 8:null, marginTop: clickedFromOrgTab?40:null, color: clickedFromOrgTab?"#ffffff":null }}>Notifications ({ <div style={{ maxHeight: 1700, overflowY: "auto", width: '100%', scrollbarColor: '#494949 transparent', scrollbarWidth: 'thin'}}>
<div style={{maxWidth: "calc(100% - 20px)"}}>
<Typography style={{ fontSize: 24, fontWeight: 'bold', display: clickedFromOrgTab?null:"inline", marginBottom: clickedFromOrgTab? 8:null, color: clickedFromOrgTab?"#ffffff":null }}>Notifications ({
notifications?.filter((notification) => showRead === true || notification.read === false).length notifications?.filter((notification) => showRead === true || notification.read === false).length
})</h2> })</Typography>
<span style={{ marginLeft: clickedFromOrgTab?null:25, color: clickedFromOrgTab?"#9E9E9E":null, }}> <span style={{ fontSize: 16, marginLeft: clickedFromOrgTab?null:25, color: clickedFromOrgTab?"#9E9E9E":null, }}>
Notifications help you find potential problems with your workflows and apps.&nbsp; Notifications help you find potential problems with your workflows and apps.&nbsp;
<a <a
target="_blank" target="_blank"
@@ -430,24 +261,11 @@ const Priorities = (props) => {
</Button> </Button>
) : null} ) : null}
</div> </div>
{notifications === null || notifications === undefined || notifications.length === 0 ? null : <NotificationComponent notifications={notifications} showRead={showRead} selectedExecutionId={selectedExecutionId} selectedWorkflow={selectedWorkflow} highlightKMS={highlightKMS} userdata={userdata} imagesize={imagesize} boxColor={boxColor} clickedFromOrgTab={clickedFromOrgTab} notificationWidth={notificationWidth} dismissNotification={dismissNotification}/>
<div>
{notifications.map((notification, index) => {
if (showRead === false && notification.read === true) {
return null
}
return (
<NotificationItem data={notification} key={index} />
)
})}
</div>
}
{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 ?0:null, color: clickedFromOrgTab ? "#ffffff" : null }}>Suggestions</h2> <span style={{ fontSize: 16, color: clickedFromOrgTab ?"#9E9E9E":null,marginLeft: clickedFromOrgTab ?null:25 }}>
<span style={{ color: clickedFromOrgTab ?"#9E9E9E":null,marginLeft: clickedFromOrgTab ?null:25 }}>
Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. <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"
@@ -489,9 +307,232 @@ const Priorities = (props) => {
) )
}) })
} }
</div>
</div>
</div> </div>
) )
} })
export default Priorities; export default Priorities;
const NotificationItem = memo((props) => {
const {data, selectedExecutionId, selectedWorkflow, highlightKMS, userdata, imagesize, boxColor, clickedFromOrgTab, notificationWidth, dismissNotification} = props
var image = "";
var orgName = "";
var orgId = "";
var highlighted = selectedExecutionId === "" && selectedWorkflow === "" ? false : data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow)
if (!highlighted && highlightKMS) {
if (data.title !== undefined && data.title !== null && data.title.toLowerCase().includes("kms")) {
highlighted = true
} else if (data.description !== undefined && data.description !== null && data.description.toLowerCase().includes("kms")) {
highlighted = true
}
}
if (userdata.orgs !== undefined) {
const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]);
if (foundOrg !== undefined && foundOrg !== null) {
//position: "absolute", bottom: 5, right: -5,
const imageStyle = {
width: imagesize,
height: imagesize,
pointerEvents: "none",
marginLeft:
data.creator_org !== undefined && data.creator_org.length > 0
? 20
: 0,
borderRadius: 10,
border:
foundOrg.id === userdata.active_org.id
? `3px solid ${boxColor}`
: null,
cursor: "pointer",
marginRight: 10,
};
image =
foundOrg.image === "" ? (
<img
alt={foundOrg.name}
src={theme.palette.defaultImage}
style={imageStyle}
/>
) : (
<img
alt={foundOrg.name}
src={foundOrg.image}
style={imageStyle}
onClick={() => {}}
/>
);
orgName = foundOrg.name;
orgId = foundOrg.id;
}
}
return (
<Paper
style={{
backgroundColor: theme.palette.inputColor.backgroundColor,
width: clickedFromOrgTab ? null :notificationWidth,
padding: 30,
borderBottom: "1px solid rgba(255,255,255,0.4)",
marginBottom: 20,
border: highlighted ? "2px solid #f85a3e" : null,
borderRadius: theme.palette?.borderRadius,
}}
>
<div style={{display: "flex", }}>
{data.amount === 1 && data.read === false ?
<Chip
label={"First seen"}
variant="contained"
color="primary"
style={{marginRight: 15, height: 25, }}
/>
: null}
{data.ignored === true ?
<Chip
label={"Disabled"}
variant="outlined"
color="primary"
style={{marginRight: 15, height: 25, }}
/>
: null}
{data.read === false ?
<Chip
label={"Unread"}
variant="outlined"
color="primary"
style={{marginRight: 15, height: 25, }}
/>
:
<Chip
label={"Read"}
variant="outlined"
color="secondary"
style={{marginRight: 15, height: 25, }}
/>
}
<Typography variant="body1" color="textPrimary" style={{ wordWrap: "break-word", overflow: "hidden", textOverflow: "ellipsis" }}>
{data.title}
</Typography >
</div>
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
<img alt={data.title} src={data.image} style={{height: 100, width: 100, }} />
:
null
}
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", wordWrap: "break-word" }}>
{data.description}
</Typography >
<div style={{ display: "flex" }}>
<ButtonGroup>
<Button
color="secondary"
variant="outlined"
style={{ marginTop: 15 }}
disabled={data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0}
onClick={() => {
window.open(data.reference_url, "_blank")
}}
>
Explore
</Button>
{data.read === false ? (
<Button
color="secondary"
variant="outlined"
style={{ marginTop: 15 }}
onClick={() => {
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" }}>
<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" }}>
<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" }}>
<b>Times seen</b>: {data.amount}
</Typography >
</div>
</Paper>
);
})
const NotificationComponent = memo(({notifications, showRead, selectedExecutionId, selectedWorkflow, highlightKMS, userdata, imagesize, boxColor, clickedFromOrgTab, notificationWidth, dismissNotification}) => {
return(
<div>
{notifications === null || notifications === undefined || notifications?.length === 0 ? (
null
) :
<div>
{notifications?.map((notification, index) => {
if (showRead === false && notification.read === true) {
return null
}
return (
<NotificationItem data={notification} key={index} selectedExecutionId={selectedExecutionId} selectedWorkflow={selectedWorkflow} highlightKMS={highlightKMS} userdata={userdata} imagesize={imagesize} boxColor={boxColor} clickedFromOrgTab={clickedFromOrgTab} notificationWidth={notificationWidth} dismissNotification={dismissNotification} />
)
})}
</div>
}
</div>
)
})
// const PaddingWrapper = memo(({children, clickedFromOrgTab}) => {
// const { leftSideBarOpenByClick } = useContext(Context)
// return(
// <div style={{width: leftSideBarOpenByClick ? 950 : 1030,transition: 'width 0.3s ease', padding: clickedFromOrgTab ? "27px 10px 19px 27px":null, height: clickedFromOrgTab ? "auto":null, minHeight: 843, backgroundColor: clickedFromOrgTab ? '#212121':null, borderRadius: clickedFromOrgTab ? '16px':null, }}>
// {children}
// </div>
// )
// })
// const Wrapper = memo(({children, clickedFromOrgTab}) => {
// return(
// <PaddingWrapper clickedFromOrgTab={clickedFromOrgTab}>
// {children}
// </PaddingWrapper>
// )
// })
@@ -1084,6 +1084,8 @@ const CodeEditor = (props) => {
maxHeight: isMobile ? "100%" : 700, maxHeight: isMobile ? "100%" : 700,
border: theme.palette.defaultBorder, border: theme.palette.defaultBorder,
padding: isMobile ? "25px 10px 25px 10px" : 25, padding: isMobile ? "25px 10px 25px 10px" : 25,
zoom: 0.8,
backgroundColor: "black",
}, },
}} }}
> >
+1 -1
View File
@@ -382,7 +382,7 @@ const data = [
css: { css: {
"background-color": "#f85a3e", "background-color": "#f85a3e",
"border-color": "#f85a3e", "border-color": "#f85a3e",
"border-width": "12px", "border-width": "7px",
"transition-property": "border-width", "transition-property": "border-width",
"transition-duration": "0.25s", "transition-duration": "0.25s",
label: "data(label)", label: "data(label)",
+6
View File
@@ -50,6 +50,12 @@ const theme = createTheme(adaptV4Theme({
borderRadius: 5, borderRadius: 5,
height: 40, height: 40,
}, },
DialogStyle: {
backgroundColor: "#212121",
borderRadius: 2,
boxShadow: "0px 0px 10px 0px rgba(0,0,0,0.75)",
border: "1px solid #494949",
},
innerTextfieldStyle: { innerTextfieldStyle: {
height: 40, height: 40,
fontSize: 16, fontSize: 16,
+109 -14
View File
@@ -4,13 +4,13 @@ import { toast } from "react-toastify";
const Admin2 = (props) => { const Admin2 = (props) => {
// Destructure props if needed // Destructure props if needed
const { userdata, globalUrl, isCloud, serverside, checkLogin, notifications, setNotifications, stripeKey } = props; const { userdata, globalUrl, serverside, checkLogin, notifications, setNotifications, stripeKey, isLoaded, isLoggedIn} = props;
const [selectedTab, setSelectedTab] = useState('editdetails'); const [selectedTab, setSelectedTab] = useState('editdetails');
const [selectedStatus, setSelectedStatus] = React.useState([]); const [selectedStatus, setSelectedStatus] = React.useState([]);
const [selectedOrganization, setSelectedOrganization] = useState({}); const [selectedOrganization, setSelectedOrganization] = useState({});
const [organizationFeatures, setOrganizationFeatures] = useState({}); const [organizationFeatures, setOrganizationFeatures] = useState({});
const [orgRequest, setOrgRequest] = React.useState(true); const [orgRequest, setOrgRequest] = React.useState(true);
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
const handleGetOrg = (orgId) => { const handleGetOrg = (orgId) => {
if ( if (
serverside !== true && serverside !== true &&
@@ -51,8 +51,11 @@ const Admin2 = (props) => {
.then((responseJson) => { .then((responseJson) => {
if (responseJson["success"] === false) { if (responseJson["success"] === false) {
toast( toast(
"Failed getting your org. If this persists, please contact support.", "Failed getting your org. If this persists, please contact support. Redirecting to workflows...",
); );
setTimeout(() => {
window.location.href = "/workflows";
}, 3000);
} else { } else {
if ( if (
responseJson.sync_features === undefined || responseJson.sync_features === undefined ||
@@ -151,6 +154,77 @@ const Admin2 = (props) => {
}); });
}; };
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const foundOrgID = params["org_id"]
useEffect(() => {
if(foundOrgID !== null && foundOrgID !== undefined && userdata?.support && foundOrgID?.length > 0) {
handleClickChangeOrg(foundOrgID)
}
}, [foundOrgID]);
const handleClickChangeOrg = (orgId) => {
// Don't really care about the logout
//name: org.name,
//orgId = "asd"
const data = {
org_id: orgId,
};
localStorage.setItem("globalUrl", "");
localStorage.setItem("getting_started_sidebar", "open");
fetch(`${globalUrl}/api/v1/orgs/${orgId}/change`, {
mode: "cors",
credentials: "include",
crossDomain: true,
method: "POST",
body: JSON.stringify(data),
withCredentials: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then(function (response) {
if (response.status !== 200) {
console.log("Error in response");
} else {
localStorage.removeItem("apps")
localStorage.removeItem("workflows")
localStorage.removeItem("userinfo")
}
return response.json();
})
.then(function (responseJson) {
if (responseJson.success === true) {
if (responseJson.region_url !== undefined && responseJson.region_url !== null && responseJson.region_url.length > 0) {
localStorage.setItem("globalUrl", responseJson.region_url)
//globalUrl = responseJson.region_url
}
setTimeout(() => {
window.location.reload()
}, 3000);
toast("Successfully changed active organization - refreshing!");
} else {
if (responseJson.reason !== undefined && responseJson.reason !== null) {
if (!responseJson.reason.includes("already")) {
toast("Failed changing org: " + responseJson.reason);
}
} else {
toast("Failed changing org")
}
}
})
.catch((error) => {
console.log("error changing: ", error);
//removeCookie("session_token", {path: "/"})
});
};
const handleEditOrg = ( const handleEditOrg = (
name, name,
description, description,
@@ -159,6 +233,7 @@ const Admin2 = (props) => {
defaults, defaults,
sso_config, sso_config,
lead_info, lead_info,
{ mfa_required } = {}
) => { ) => {
const data = { const data = {
name: name, name: name,
@@ -168,6 +243,7 @@ const Admin2 = (props) => {
defaults: defaults, defaults: defaults,
sso_config: sso_config, sso_config: sso_config,
lead_info: lead_info, lead_info: lead_info,
mfa_required: mfa_required !== undefined ? mfa_required : selectedOrganization?.mfa_required,
}; };
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`; const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
@@ -202,21 +278,40 @@ const Admin2 = (props) => {
}); });
}; };
// useEffect(() => {
// handleGetOrg();
// }, []);
const handleStatusChange = (event) => { const handleStatusChange = (event) => {
const { value } = event.target; const { value } = event.target;
setSelectedStatus(value); setSelectedStatus(value);
handleEditOrg( handleEditOrg(
"", selectedOrganization?.name,
"", selectedOrganization?.description,
selectedOrganization.id, selectedOrganization.id,
"", selectedOrganization?.image,
{}, {
{}, app_download_repo: selectedOrganization?.defaults?.app_download_repo,
app_download_branch: selectedOrganization?.defaults?.app_download_branch,
workflow_download_repo: selectedOrganization?.defaults?.workflow_download_repo,
workflow_download_branch: selectedOrganization?.defaults?.workflow_download_branch,
notification_workflow: selectedOrganization?.defaults?.notification_workflow,
documentation_reference: selectedOrganization?.defaults?.documentation_reference,
workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo,
workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch,
workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username,
workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token,
newsletter: !selectedOrganization?.defaults?.newsletter,
weekly_recommendations: selectedOrganization?.defaults?.weekly_recommendations,
},
{
sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint,
sso_certificate: selectedOrganization?.sso_config?.sso_certificate,
client_id: selectedOrganization?.sso_config?.client_id,
client_secret: selectedOrganization?.sso_config?.client_secret,
openid_authorization: selectedOrganization?.sso_config?.openid_authorization,
openid_token: selectedOrganization?.sso_config?.openid_token,
SSORequired: selectedOrganization?.sso_config?.SSORequired,
auto_provision: selectedOrganization?.sso_config?.auto_provision,
},
value.length === 0 ? ["none"] : value, value.length === 0 ? ["none"] : value,
); );
}; };
@@ -228,14 +323,14 @@ const Admin2 = (props) => {
orgRequest orgRequest
) { ) {
const orgId = userdata.active_org.id const orgId = userdata.active_org.id
console.log("orgID", orgId)
setOrgRequest(false); setOrgRequest(false);
handleGetOrg(orgId); handleGetOrg(orgId);
} }
return ( return (
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 30 }}> <div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 0.8, }}>
<AdminNavBar userdata={userdata} 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>
); );
}; };
+112 -67
View File
@@ -422,7 +422,7 @@ const AngularWorkflow = (defaultprops) => {
const [subworkflow, setSubworkflow] = React.useState({}); const [subworkflow, setSubworkflow] = React.useState({});
const [subworkflowStartnode, setSubworkflowStartnode] = React.useState(""); const [subworkflowStartnode, setSubworkflowStartnode] = React.useState("");
const [leftViewOpen, setLeftViewOpen] = React.useState(isMobile ? false : true); const [leftViewOpen, setLeftViewOpen] = React.useState(isMobile ? false : true);
const [leftBarSize, setLeftBarSize] = React.useState(isMobile ? 0 : 255) const [leftBarSize, setLeftBarSize] = React.useState(isMobile ? 0 : 235)
const [creatorProfile, setCreatorProfile] = React.useState({}); const [creatorProfile, setCreatorProfile] = React.useState({});
const [usecases, setUsecases] = React.useState([]); const [usecases, setUsecases] = React.useState([]);
const [files, setFiles] = React.useState({ const [files, setFiles] = React.useState({
@@ -3813,7 +3813,7 @@ const releaseToConnectLabel = "Release to Connect"
}); });
} }
cy.fit(null, 100); cy.fit(null, 400);
cy.on("add", "node", (e) => onNodeAdded(e)); cy.on("add", "node", (e) => onNodeAdded(e));
cy.on("add", "edge", (e) => onEdgeAdded(e)); cy.on("add", "edge", (e) => onEdgeAdded(e));
} else { } else {
@@ -4052,7 +4052,7 @@ const releaseToConnectLabel = "Release to Connect"
.then(() => { .then(() => {
console.log("DONE: ", workflow_id); console.log("DONE: ", workflow_id);
getWorkflow(workflow_id.value, nodedata); getWorkflow(workflow_id.value, nodedata);
cy.fit(null, 50); cy.fit(null, 300);
}); });
} }
}; };
@@ -4180,7 +4180,7 @@ const releaseToConnectLabel = "Release to Connect"
if (nodedata.app_name === "Webhook" || nodedata.app_name === "Schedule" || nodedata.app_name === "Gmail" || nodedata.app_name === "Office365") { if (nodedata.app_name === "Webhook" || nodedata.app_name === "Schedule" || nodedata.app_name === "Gmail" || nodedata.app_name === "Office365") {
if (!found) { if (!found) {
console.log("Find amount of executions for the specific nodetype: ", nodedata.app_name, "Executions: ", workflowExecutions) //console.log("Find amount of executions for the specific nodetype: ", nodedata.app_name, "Executions: ", workflowExecutions)
// Find how many executions it has // Find how many executions it has
var executions = 0 var executions = 0
const matchingExecutions = workflowExecutions.filter((execution => execution.execution_source === nodedata.app_name.toLowerCase())) const matchingExecutions = workflowExecutions.filter((execution => execution.execution_source === nodedata.app_name.toLowerCase()))
@@ -6121,7 +6121,7 @@ const releaseToConnectLabel = "Release to Connect"
event.target.remove() event.target.remove()
//console.log("Found branch already!") //console.log("Found branch already!")
toast.error("Triggers can have exactly one target node") toast.error("Triggers can point to exactly one start node")
return return
@@ -7782,7 +7782,7 @@ const releaseToConnectLabel = "Release to Connect"
const item = typeIds[idkey] const item = typeIds[idkey]
if (item.data.id === nodedata.id) { if (item.data.id === nodedata.id) {
//console.log("items: ", item.data.id, nodedata.id) //console.log("items: ", item.data.id, nodedata.id)
parsedStyle["border-width"] = "12px" parsedStyle["border-width"] = "7px"
break break
} }
} }
@@ -8391,7 +8391,7 @@ const releaseToConnectLabel = "Release to Connect"
// Reset view for cytoscape // Reset view for cytoscape
if (cy !== undefined && cy !== null) { if (cy !== undefined && cy !== null) {
cy.add(insertedNodes); cy.add(insertedNodes);
cy.fit(null, 200); cy.fit(null, 400);
} else { } else {
setElements(insertedNodes); setElements(insertedNodes);
} }
@@ -8772,7 +8772,7 @@ const releaseToConnectLabel = "Release to Connect"
} }
// preview: true, // preview: true,
cy.fit(null, 200); cy.fit(null, 400)
cy.on("boxselect", "node", (e) => { cy.on("boxselect", "node", (e) => {
if (e.target.data("isButton") || e.target.data("isDescriptor") || e.target.data("isSuggestion")) { if (e.target.data("isButton") || e.target.data("isDescriptor") || e.target.data("isSuggestion")) {
@@ -9380,7 +9380,9 @@ const releaseToConnectLabel = "Release to Connect"
onChange={handleSetTab} onChange={handleSetTab}
aria-label="Left sidebar tab" aria-label="Left sidebar tab"
orientation={isMobile ? "vertical" : "horizontal"} orientation={isMobile ? "vertical" : "horizontal"}
style={{}} style={{
display: "flex",
}}
> >
<Tab <Tab
value={0} value={0}
@@ -9421,7 +9423,7 @@ const releaseToConnectLabel = "Release to Connect"
<Grid item> <Grid item>
<FavoriteBorderIcon style={iconStyle} /> <FavoriteBorderIcon style={iconStyle} />
</Grid> </Grid>
{isMobile ? null : <Grid item>Variables</Grid>} {isMobile ? null : <Grid item>Vars</Grid>}
</Grid> </Grid>
} }
style={tabStyle} style={tabStyle}
@@ -9776,11 +9778,13 @@ const releaseToConnectLabel = "Release to Connect"
const barHeight = bodyHeight - appBarSize - 50; const barHeight = bodyHeight - appBarSize - 50;
const appScrollStyle = { const appScrollStyle = {
overflow: "scroll", overflow: "scroll",
maxHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-300, maxHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-70,
minHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-300, minHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-70,
marginTop: 1, marginTop: 1,
overflowY: "auto", overflowY: "auto",
overflowX: "hidden", overflowX: "hidden",
zoom: 0.9,
} }
const handleAppDrag = (e, app) => { const handleAppDrag = (e, app) => {
@@ -10568,12 +10572,12 @@ const releaseToConnectLabel = "Release to Connect"
var viewedApps = [] var viewedApps = []
return ( return (
<div style={appViewStyle}> <div style={appViewStyle}>
<div style={{ flex: "1" }}> <div style={{ flex: "1", zoom: 0.9, }}>
<TextField <TextField
style={{ style={{
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.inputColor,
borderRadius: theme.palette?.borderRadius, borderRadius: theme.palette?.borderRadius,
marginTop: 5, marginTop: 10,
marginRight: 10, marginRight: 10,
height: 40, height: 40,
}} }}
@@ -11193,14 +11197,12 @@ const releaseToConnectLabel = "Release to Connect"
overflowAnchor: "none", overflowAnchor: "none",
}; };
const minSize = 370 const minSize = 370
var rightsidebarStyle = { var rightsidebarStyle = {
position: "fixed", position: "fixed",
top: appBarSize - 35, top: appBarSize - 35,
right: 25, right: 25,
height: "90vh", height: "90vh",
width: isMobile ? "100%" : minSize,
minWidth: minSize,
maxWidth: 600, maxWidth: 600,
maxHeight: "100vh", maxHeight: "100vh",
border: "1px solid rgb(91, 96, 100)", border: "1px solid rgb(91, 96, 100)",
@@ -11210,6 +11212,9 @@ const releaseToConnectLabel = "Release to Connect"
overflow: "auto", overflow: "auto",
overflowAnchor: "none", overflowAnchor: "none",
minWidth: minSize,
width: isMobile ? "100%" : minSize,
zoom: 0.9,
}; };
const setTriggerFolderWrapperMulti = (event) => { const setTriggerFolderWrapperMulti = (event) => {
@@ -16153,13 +16158,15 @@ const releaseToConnectLabel = "Release to Connect"
position: "absolute", position: "absolute",
top: isMobile ? 30 : 25, top: isMobile ? 30 : 25,
left: isMobile ? 20 : leftSideBarOpenByClick ? leftBarSize + 275 : leftBarSize+100, left: isMobile ? 20 : leftSideBarOpenByClick ? leftBarSize + 275 : leftBarSize+135,
transition: "left 0.3s ease", transition: "left 0.3s ease",
maxWidth: 500, zoom: 0.9,
} }
const TopCytoscapeBar = (props) => { const TopCytoscapeBar = (props) => {
const [hovered, setHovered] = useState(false)
if (workflow.public === true) { if (workflow.public === true) {
return null return null
} }
@@ -16174,12 +16181,30 @@ const releaseToConnectLabel = "Release to Connect"
<div style={topBarStyle}> <div style={topBarStyle}>
<div style={{ <div style={{
margin: "0px 10px 0px 35px", margin: "0px 10px 0px 35px",
maxWidth: 500,
}}> }}>
<Typography variant="h6" style={{ <Typography variant="h6" style={{
margin: 0, margin: 0,
}}> cursor: "pointer",
{workflow.name} display: "flex",
borderRadius: theme.palette.borderRadius,
border: hovered ? "1px solid rgba(255,255,255,0.3)" : "1px solid transparent",
paddingRight: 10,
paddingLeft: 10,
position: "relative",
}}
onMouseEnter={() => {
setHovered(true)
}}
onMouseLeave={() => {
setHovered(false)
}}
onClick={() => {
setEditWorkflowModalOpen(true)
setLastSaved(false)
}}
>
<EditIcon style={{position: "absolute", top: 7, height: 20, width: 20, }} />
<span style={{marginLeft: 30, }}>{workflow.name}</span>
</Typography> </Typography>
{workflowAsCode && ( {workflowAsCode && (
<Tooltip title="Switch to Code View"> <Tooltip title="Switch to Code View">
@@ -16204,7 +16229,7 @@ const releaseToConnectLabel = "Release to Connect"
{!distributedFromParent ? {!distributedFromParent ?
isCorrectOrg ? null : isCorrectOrg ? null :
<Typography variant="body1"> <Typography variant="body2">
<b>Warning</b>: Change <span <b>Warning</b>: Change <span
style={{color: "#FF8544", cursor: "pointer", pointerEvents: "auto", }} style={{color: "#FF8544", cursor: "pointer", pointerEvents: "auto", }}
onClick={() => { onClick={() => {
@@ -16275,7 +16300,7 @@ const releaseToConnectLabel = "Release to Connect"
>Active Organization</span> to edit this Workflow. >Active Organization</span> to edit this Workflow.
</Typography> </Typography>
: :
<Typography variant="body1"> <Typography variant="body2" color="textSecondary">
Warning: This workflow is controlled by your parent org and may not be editable. Warning: This workflow is controlled by your parent org and may not be editable.
</Typography> </Typography>
} }
@@ -16285,7 +16310,7 @@ const releaseToConnectLabel = "Release to Connect"
<InputLabel <InputLabel
id="suborg-changer" id="suborg-changer"
style={{ color: "white" }} style={{ color: "rgba(255,255,255,0.7)", }}
> >
Select an Org Select an Org
</InputLabel> </InputLabel>
@@ -16294,10 +16319,15 @@ const releaseToConnectLabel = "Release to Connect"
pointerEvents: "auto", pointerEvents: "auto",
backgroundColor: theme.palette.inputColor, backgroundColor: theme.palette.inputColor,
color: "white", color: "white",
height: 50,
maxWidth: 250, maxWidth: 250,
minWidth: 250, minWidth: 250,
borderRadius: theme.palette?.borderRadius, borderRadius: theme.palette?.borderRadius,
height: 40,
}}
InputProps={{
style: {
height: 40,
}
}} }}
labelId="suborg-changer" labelId="suborg-changer"
value={workflow.org_id} value={workflow.org_id}
@@ -16470,47 +16500,16 @@ const releaseToConnectLabel = "Release to Connect"
</Select> </Select>
</FormControl> </FormControl>
} }
</div>
</div>
<div style={{display: "flex", marginLeft: 10, maxWidth: 250, pointerEvents: "auto", }}>
{parentWorkflows.slice(0,5).map((wf, index) => {
return (
<a href={`/workflows/${wf.id}`} target="_blank" rel="noopener noreferrer" key={index}>
<Tooltip arrow placement="left" title={
<span style={{}}>
{wf.image !== undefined && wf.image !== null && wf.image.length > 0 ?
<img
src={wf.image}
alt={wf.name}
style={{ backgroundColor: theme.palette.surfaceColor, maxHeight: 200, minHeigth: 200, borderRadius: theme.palette?.borderRadius, }}
/>
: null}
<Typography>
Parent workflow: '{wf.name}'
</Typography>
</span>
} placement="bottom">
<span onClick={() => {
console.log("Click: ", wf)
}}>
<img src={theme.palette.defaultImage} style={{height: 25, width: 25, cursor: "pointer", border: 15, marginRight: 5, marginTop: 5, filter: "grayscale(90%)", }} />
</span>
</Tooltip>
</a>
)
})}
</div>
{showEnvironment === true && environments.length > 1 && selectedActionEnvironment !== undefined && selectedActionEnvironment !== null && selectedActionEnvironment.Name !== undefined && selectedActionEnvironment.Name !== null ? {showEnvironment === true && environments.length > 1 && selectedActionEnvironment !== undefined && selectedActionEnvironment !== null && selectedActionEnvironment.Name !== undefined && selectedActionEnvironment.Name !== null ?
<FormControl fullWidth style={{marginTop: 15, marginleft: 10, pointerEvents: "auto", maxWidth: 250, }}> <FormControl fullWidth style={{marginTop: 15, pointerEvents: "auto", maxWidth: 250, }}>
<InputLabel <InputLabel
id="execution_location" id="execution_location"
style={{ color: "white" }} style={{ color: "rgba(255,255,255,0.7)", marginLeft: 40, }}
> >
Execution Location Location
</InputLabel> </InputLabel>
<Select <Select
labelId="execution_location" labelId="execution_location"
@@ -16523,6 +16522,11 @@ const releaseToConnectLabel = "Release to Connect"
style: { style: {
}, },
}} }}
InputProps={{
style: {
height: 40,
}
}}
onChange={(e) => { onChange={(e) => {
setLastSaved(false) setLastSaved(false)
const env = environments.find((a) => a.Name === e.target.value); const env = environments.find((a) => a.Name === e.target.value);
@@ -16539,13 +16543,14 @@ const releaseToConnectLabel = "Release to Connect"
}} }}
style={{ style={{
pointerEvents: "auto", pointerEvents: "auto",
backgroundColor: theme.palette.inputColor,
color: "white", color: "white",
height: 50,
maxWidth: 250, maxWidth: 250,
minWidth: 250, minWidth: 250,
borderRadius: theme.palette?.borderRadius, borderRadius: theme.palette?.borderRadius,
marginLeft: 10, marginLeft: 35,
backgroundColor: theme.palette.inputColor,
height: 40,
}} }}
> >
{environments.map((data, index) => { {environments.map((data, index) => {
@@ -16603,6 +16608,43 @@ const releaseToConnectLabel = "Release to Connect"
</FormControl> </FormControl>
: null} : null}
{parentWorkflows === undefined || parentWorkflows === null || parentWorkflows.length === 0 ? null :
<div style={{display: "flex", marginLeft: 40, maxWidth: 250, pointerEvents: "auto", marginTop: 5, }}>
<Typography variant="body2" color="textSecondary" style={{marginRight: 5, marginTop: 5, }}>
<b>Parent Workflows:</b>
</Typography>
{parentWorkflows.slice(0,5).map((wf, index) => {
return (
<a href={`/workflows/${wf.id}`} target="_blank" rel="noopener noreferrer" key={index}>
<Tooltip arrow placement="left" title={
<span style={{}}>
{wf.image !== undefined && wf.image !== null && wf.image.length > 0 ?
<img
src={wf.image}
alt={wf.name}
style={{ backgroundColor: theme.palette.surfaceColor, maxHeight: 200, minHeigth: 200, borderRadius: theme.palette?.borderRadius, }}
/>
: null}
<Typography>
Parent workflow: '{wf.name}'
</Typography>
</span>
} placement="bottom">
<span onClick={() => {
console.log("Click: ", wf)
}}>
<img src={theme.palette.defaultImage} style={{height: 25, width: 25, cursor: "pointer", border: 15, marginRight: 5, marginTop: 5, filter: "grayscale(90%)", }} />
</span>
</Tooltip>
</a>
)
})}
</div>
}
</div> </div>
); );
}; };
@@ -17210,7 +17252,7 @@ const releaseToConnectLabel = "Release to Connect"
<Tooltip color="primary" title="Stop execution" placement="top"> <Tooltip color="primary" title="Stop execution" placement="top">
<span> <span>
<Button <Button
style={{ height: boxSize, width: boxSize }} style={{ height: boxSize, width: boxSize+5 }}
color="secondary" color="secondary"
variant="contained" variant="contained"
onClick={() => { onClick={() => {
@@ -17228,7 +17270,7 @@ const releaseToConnectLabel = "Release to Connect"
workflow.public workflow.public
|| executionRequestStarted || executionRequestStarted
} }
style={{ height: boxSize, width: boxSize, backgroundColor: green, }} style={{ height: boxSize, width: boxSize+5, backgroundColor: green, }}
color="primary" color="primary"
variant="contained" variant="contained"
onClick={() => { onClick={() => {
@@ -17265,7 +17307,7 @@ const releaseToConnectLabel = "Release to Connect"
{executionButton} {executionButton}
<Tooltip <Tooltip
color="secondary" color="secondary"
title={`Show previous runs (${workflowExecutions.length}) (Ctrl + ')`} title={`Show previous workflow runs (${workflowExecutions.length}) (Ctrl + ')`}
placement="top-start" placement="top-start"
> >
<Button <Button
@@ -17492,6 +17534,8 @@ const releaseToConnectLabel = "Release to Connect"
workflow.configuration.exit_on_error !== undefined ? ( workflow.configuration.exit_on_error !== undefined ? (
<WorkflowMenu /> <WorkflowMenu />
) : null} ) : null}
{/*
<Tooltip <Tooltip
color="secondary" color="secondary"
title="Edit workflow details" title="Edit workflow details"
@@ -17514,6 +17558,7 @@ const releaseToConnectLabel = "Release to Connect"
</Button> </Button>
</span> </span>
</Tooltip> </Tooltip>
*/}
<Tooltip <Tooltip
color="secondary" color="secondary"
+7 -4
View File
@@ -1,3 +1,4 @@
import React, { memo, useCallback } from "react"; import React, { memo, useCallback } from "react";
import { useState, useEffect, useContext, Suspense } from "react"; import { useState, useEffect, useContext, Suspense } from "react";
import { useNavigate, Link, useLocation } from "react-router-dom"; import { useNavigate, Link, useLocation } from "react-router-dom";
@@ -57,7 +58,7 @@ const ApiExplorer = React.lazy(() => import("../components/ApiExplorer.jsx"));
const ApiExplorerWrapper = (props) => { const ApiExplorerWrapper = (props) => {
const { globalUrl, serverside, userdata, isLoggedIn} = props; const { globalUrl, serverside, userdata, isLoggedIn, isLoaded} = props;
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -1754,7 +1755,7 @@ const ApiExplorerWrapper = (props) => {
)}); )});
return ( return (
<Wrapper userdata={userdata}> <Wrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
<Suspense fallback={skeletonLoader}> <Suspense fallback={skeletonLoader}>
{authenticationModal} {authenticationModal}
<ApiExplorer <ApiExplorer
@@ -1765,6 +1766,8 @@ const ApiExplorerWrapper = (props) => {
HandleApiExecution={HandleApiExecution} HandleApiExecution={HandleApiExecution}
selectedAppData={selectedAppData} selectedAppData={selectedAppData}
ConfigurationTab={ConfigurationTab} ConfigurationTab={ConfigurationTab}
isLoggedIn={isLoggedIn}
isLoaded={isLoaded}
/> />
</Suspense> </Suspense>
</Wrapper> </Wrapper>
@@ -1774,13 +1777,13 @@ const ApiExplorerWrapper = (props) => {
export default ApiExplorerWrapper; export default ApiExplorerWrapper;
const Wrapper = ({children, userdata})=>{ const Wrapper = ({children, isLoaded,isLoggedIn})=>{
const { leftSideBarOpenByClick } = useContext(Context); const { leftSideBarOpenByClick } = useContext(Context);
return( return(
<div className="api-explorer-wrapper" style={{ paddingLeft: userdata?.support ? leftSideBarOpenByClick ? 280 : 100 : 0, transition: 'padding-left 0.3s ease' }}> <div className="api-explorer-wrapper" style={{ paddingLeft: (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 280 : 100 : 0, transition: 'padding-left 0.3s ease' }}>
{children} {children}
</div> </div>
) )
+3 -5
View File
@@ -3239,15 +3239,13 @@ const AppsWrapper = memo(({ appView, modalView, userdata, publishModal, generate
)); ));
const SidebarAdjustWrapper = memo(({ userdata, children }) => { const SidebarAdjustWrapper = memo(({ children }) => {
const {leftSideBarOpenByClick } = useContext(Context) const {leftSideBarOpenByClick } = useContext(Context)
const marginLeft = userdata?.support
? leftSideBarOpenByClick ? 250 : 80
: 0;
return ( return (
<div style={{ marginLeft, transition: 'margin-left 0.3s ease' }}> <div style={{ marginLeft: leftSideBarOpenByClick ? 250 : 80, transition: 'margin-left 0.3s ease' }}>
{children} {children}
</div> </div>
); );
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -274,7 +274,8 @@ const CodeWorkflow = (defaultprops) => {
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
height: '100vh', // Set to full viewport height height: '100vh', // Set to full viewport height
backgroundColor: '#252526' backgroundColor: '#252526',
marginLeft: '100px',
}}> }}>
{/* IDE-like toolbar */} {/* IDE-like toolbar */}
<Toolbar <Toolbar
+16 -4
View File
@@ -337,11 +337,23 @@ const Dashboard = (props) => {
const [, setUpdate] = useState(0); const [, setUpdate] = useState(0);
let navigate = useNavigate(); let navigate = useNavigate();
const isCloud = const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io"; const path = window.location.pathname
if (path !== undefined && path !== null) {
if (path.includes("/automate")) {
navigate("/usecases")
}
if (path.includes("/security")) {
navigate("/forms")
}
}
useEffect(() => { useEffect(() => {
// Look for the path. If it is automation, go to usecases
// Handles redirect
const widgetnames = ["app_executions_cloud"] const widgetnames = ["app_executions_cloud"]
for (let widgetkey in widgetnames) { for (let widgetkey in widgetnames) {
const widgetName = widgetnames[widgetkey] const widgetName = widgetnames[widgetkey]
@@ -859,7 +871,7 @@ const Dashboard = (props) => {
); );
const dataWrapper = ( const dataWrapper = (
<div style={{ maxWidth: 1366, margin: "auto" }}>{data}</div> <div style={{ maxWidth: 1366, margin: "auto", paddingTop: 10, }}>{data}</div>
); );
return dataWrapper; return dataWrapper;
+8 -8
View File
@@ -251,7 +251,7 @@ export const CodeHandler = (props) => {
} }
const Docs = (defaultprops) => { const Docs = (defaultprops) => {
const { globalUrl, selectedDoc, serverside, serverMobile, userdata } = defaultprops; const { globalUrl, selectedDoc, serverside, serverMobile, isLoggedIn, isLoaded } = defaultprops;
let navigate = useNavigate(); let navigate = useNavigate();
// Quickfix for react router 5 -> 6 // Quickfix for react router 5 -> 6
const params = useParams(); const params = useParams();
@@ -1266,7 +1266,7 @@ const Docs = (defaultprops) => {
// Padding and zIndex etc set because of footer in cloud. // Padding and zIndex etc set because of footer in cloud.
const loadedCheck = ( const loadedCheck = (
<DocsWrapper userdata={userdata}> <DocsWrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
<DocsContent postDataBrowser={postDataBrowser} postDataMobile={postDataMobile}/> <DocsContent postDataBrowser={postDataBrowser} postDataMobile={postDataMobile}/>
</DocsWrapper> </DocsWrapper>
); );
@@ -1285,18 +1285,18 @@ const DocsContent = memo(({postDataBrowser, postDataMobile}) => {
</div> </div>
)}) )})
const DocsWrapper = memo(({userdata, children })=>{ const DocsWrapper = memo(({isLoggedIn, isLoaded, children })=>{
const { leftSideBarOpenByClick, windowWidth } = useContext(Context); const { leftSideBarOpenByClick, windowWidth } = useContext(Context);
return ( return (
<div style={{ <div style={{
minHeight: 1000, zIndex: 1, minHeight: 1000, zIndex: 1,
maxWidth: Math.min(leftSideBarOpenByClick ? windowWidth - 300 : windowWidth - 200, 1920), maxWidth: Math.min(!(isLoggedIn && isLoaded) ? 1920 : leftSideBarOpenByClick ? windowWidth - 300 : windowWidth - 200, 1920),
minWidth: isMobile ? null : leftSideBarOpenByClick ? 800 : 900, margin: "auto", minWidth: isMobile ? null : (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 800 : 900 : null, margin: "auto",
position: leftSideBarOpenByClick ? "relative" : "static", position: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? "relative" : "static",
left: leftSideBarOpenByClick ? 120 : !leftSideBarOpenByClick ? 80 : 0, left: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? 120 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0,
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick ? 160 : !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%", marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? 160 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
transition: "left 0.3s ease-in-out, min-width 0.3s ease-in-out, max-width 0.3s ease-in-out, position 0.3s ease-in-out, margin 0.3s ease-in-out, margin-left 0.3s ease" transition: "left 0.3s ease-in-out, min-width 0.3s ease-in-out, max-width 0.3s ease-in-out, position 0.3s ease-in-out, margin 0.3s ease-in-out, margin-left 0.3s ease"
}}> }}>
{children} {children}
+14 -7
View File
@@ -108,7 +108,6 @@ const RunWorkflow = (defaultprops) => {
const boxStyle = { const boxStyle = {
color: "white", color: "white",
padding: "25px 50px 50px 50px", padding: "25px 50px 50px 50px",
backgroundColor: theme.palette.surfaceColor,
borderRadius: 25, borderRadius: 25,
minHeight: 500, minHeight: 500,
} }
@@ -1116,7 +1115,7 @@ const RunWorkflow = (defaultprops) => {
const ExplorerUi = () => { const ExplorerUi = () => {
return ( return (
<div style={{paddingTop: 50, marginTop: 50, width: 250, itemAlign: "center", textAlign: "center", margin: "auto", }}> <div style={{paddingTop: 50, marginTop: 50, width: 350, itemAlign: "center", textAlign: "center", margin: "auto", }}>
{forms !== undefined && forms !== null && forms.length > 0 ? {forms !== undefined && forms !== null && forms.length > 0 ?
<div> <div>
@@ -1126,9 +1125,14 @@ const RunWorkflow = (defaultprops) => {
<FormList /> <FormList />
</div> </div>
: :
<Typography variant="h6" style={{marginTop: 100, marginBottom: 20, }}> <div>
No Form Found <Typography variant="h4" style={{marginTop: 125, marginBottom: 25, }}>
</Typography> No Forms Found
</Typography>
<Typography variant="body1" color="textSecondary">
<b>Every</b> Workflow is a form, and can be accessed by going to /forms/{`{workflow_id}`}. You can control the form by editing the workflow details in the "Forms" section.
</Typography>
</div>
} }
</div> </div>
) )
@@ -1474,7 +1478,7 @@ const RunWorkflow = (defaultprops) => {
{workflowQuestion !== "" ? null : {workflowQuestion !== "" ? null :
<Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 10, }} > <Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 10, }} >
Forms are in late Beta. Form submission data includes your Organization's unique ID while logged in, or a unique identifier for your browser otherwise. Your input will be automatically sanitized. Form submission data includes your Organization's unique ID while logged in, or a unique identifier for your browser otherwise. Your input will be automatically sanitized.
</Typography> </Typography>
} }
</div> </div>
@@ -1482,7 +1486,7 @@ const RunWorkflow = (defaultprops) => {
// const isCorrectOrg = userdata.active_org.id === undefined || userdata.active_org.id === null || workflow.org_id === null || workflow.org_id === undefined || workflow.org_id.length === 0 || userdata.active_org.id === workflow.org_id // const isCorrectOrg = userdata.active_org.id === undefined || userdata.active_org.id === null || workflow.org_id === null || workflow.org_id === undefined || workflow.org_id.length === 0 || userdata.active_org.id === workflow.org_id
const loadedCheck = isLoaded ? const loadedCheck = isLoaded ?
<div style={{marginTop: 30, }}> <div style={{paddingTop: 60, }}>
{editWorkflowModalOpen === true ? {editWorkflowModalOpen === true ?
<EditWorkflow <EditWorkflow
saveWorkflow={saveWorkflow} saveWorkflow={saveWorkflow}
@@ -1570,6 +1574,7 @@ const RunWorkflow = (defaultprops) => {
<div style={{position: "fixed", top: 10, right: 20, }}> <div style={{position: "fixed", top: 10, right: 20, }}>
<Button <Button
disabled={workflow.id === undefined || workflow.id === null}
variant={"outlined"} variant={"outlined"}
color={"secondary"} color={"secondary"}
style={{marginRight: 10, }} style={{marginRight: 10, }}
@@ -1582,6 +1587,7 @@ const RunWorkflow = (defaultprops) => {
</Button> </Button>
<Button <Button
disabled={workflow.id === undefined || workflow.id === null}
variant={workflow.sharing === "form" ? "outlined" : "contained"} variant={workflow.sharing === "form" ? "outlined" : "contained"}
color={"secondary"} color={"secondary"}
style={{marginRight: 10, }} style={{marginRight: 10, }}
@@ -1603,6 +1609,7 @@ const RunWorkflow = (defaultprops) => {
</Button> </Button>
<Button <Button
disabled={workflow.id === undefined || workflow.id === null}
variant={"contained"} variant={"contained"}
color={"primary"} color={"primary"}
style={{}} style={{}}
+1 -1
View File
@@ -91,7 +91,7 @@ const Search = (props) => {
userdata={userdata} userdata={userdata}
/>, [curTab]); />, [curTab]);
const MemoizedDiscordChat = useMemo(() => <DiscordChat isMobile={isMobile} />) const MemoizedDiscordChat = useMemo(() => <DiscordChat isMobile={isMobile} />, [curTab])
const useStyles = makeStyles({ const useStyles = makeStyles({
hideIndicator: { hideIndicator: {
+2 -2
View File
@@ -1220,7 +1220,7 @@ const Usecases2 = (props) => {
) : null ) : null
const data = const data =
<div className="content" style={{width: isMobile ? "100%": leftSideBarOpenByClick ? 1200: 1000, margin: "auto", paddingBottom: 200, textAlign: "center", paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease, width 0.3s ease"}}> <div className="content" style={{width: isMobile ? "100%": leftSideBarOpenByClick ? 1000: 1200, margin: "auto", paddingBottom: 200, textAlign: "center", paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease, width 0.3s ease"}}>
<UsecaseListComponent <UsecaseListComponent
userdata={userdata} userdata={userdata}
@@ -1241,7 +1241,7 @@ const Usecases2 = (props) => {
const dataWrapper = const dataWrapper =
<Fade in={true} timeout={1250}> <Fade in={true} timeout={1250}>
<div style={{ maxWidth: 1366, margin: "auto", }}> <div style={{ maxWidth: 1366, margin: "auto", zoom: 0.8, }}>
{data} {data}
</div> </div>
</Fade> </Fade>
File diff suppressed because it is too large Load Diff