Merge branch '2.0.0' of github.com:Shuffle/Shuffle into 2.0.0
This commit is contained in:
@@ -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 [info, setInfo] = useState({});
|
||||
const [serverurl, setServerUrl] = useState("");
|
||||
@@ -1265,12 +1265,12 @@ const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, se
|
||||
style={{
|
||||
display: "flex",
|
||||
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>
|
||||
);
|
||||
@@ -1279,7 +1279,7 @@ const ApiExplorer = memo(({ openapi, globalUrl, userdata, HandleApiExecution, se
|
||||
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 [isLoading, setIsLoading] = useState(false);
|
||||
const loadAction = 10;
|
||||
@@ -1366,7 +1366,7 @@ const ActionResponseAndRequest = memo(({ConfigurationTab, selectedAppData,action
|
||||
))}
|
||||
</div>
|
||||
|
||||
<ActionResponse userdata={userdata} apiResponse={apiResponse} ExampleBody={ExampleBody}/>
|
||||
<ActionResponse isLoaded={isLoaded} isLoggedIn={isLoggedIn} apiResponse={apiResponse} ExampleBody={ExampleBody}/>
|
||||
</div>
|
||||
)})
|
||||
|
||||
@@ -1381,6 +1381,8 @@ const ActionsList = memo(({
|
||||
userdata,
|
||||
info,
|
||||
openapi,
|
||||
isLoggedIn,
|
||||
isLoaded
|
||||
}) => {
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
@@ -1436,7 +1438,7 @@ const ActionsList = memo(({
|
||||
}
|
||||
};
|
||||
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>
|
||||
{info?.title ? (
|
||||
@@ -1487,7 +1489,7 @@ const ActionsList = memo(({
|
||||
marginTop: 15,
|
||||
backgroundColor: "#1a1a1a",
|
||||
overflowY: "auto",
|
||||
height: userdata?.support ? "calc(100vh - 190px)" : "calc(100vh - 260px)",
|
||||
height: (isLoaded && isLoggedIn) ? "calc(100vh - 190px)" : "calc(100vh - 260px)",
|
||||
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 [responseTabIndex, setResponseTabIndex] = useState(0)
|
||||
const [oldResponse, setOldResponse] = useState(apiResponse)
|
||||
@@ -2897,7 +2899,7 @@ const ActionResponse = memo(({ apiResponse, ExampleBody, userdata }) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ApiResponseWrapper userdata={userdata}>
|
||||
<ApiResponseWrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
|
||||
<div
|
||||
style={{
|
||||
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);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: userdata?.support
|
||||
width: (isLoggedIn && isLoaded)
|
||||
? leftSideBarOpenByClick
|
||||
? windowWidth >= 1920 ? "calc(100% - 630px)" : "calc(100% - 570px)"
|
||||
: 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 (
|
||||
<PaddingWrapper userdata={userdata}>
|
||||
<PaddingWrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
|
||||
{children}
|
||||
</PaddingWrapper>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
@@ -21,17 +23,22 @@ import LaunchIcon from '@mui/icons-material/Launch';
|
||||
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||
import { CloudDownloadOutlined } from '@mui/icons-material';
|
||||
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 [userdata, setUserdata] = useState({})
|
||||
const [usecases, setUsecases] = useState([])
|
||||
const [workflows, setWorkflows] = useState([])
|
||||
const [prevSubcase, setPrevSubcase] = useState({})
|
||||
const [inputUsecase, setInputUsecase] = useState({})
|
||||
const [latestUsecase, setLatestUsecase] = useState([])
|
||||
const [foundAppUsecase, setFoundAppUsecase] = useState({})
|
||||
|
||||
const navigate = useNavigate();
|
||||
const parseUsecase = (subcase) => {
|
||||
const srcdata = findSpecificApp(frameworkData, subcase.type)
|
||||
const dstdata = findSpecificApp(frameworkData, subcase.last)
|
||||
@@ -48,6 +55,25 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
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 = () => {
|
||||
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||
@@ -266,6 +292,89 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
setFoundAppUsecase(foundSubcase);
|
||||
}, [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 =
|
||||
window.location.host === "localhost:3002" ||
|
||||
window.location.host === "shuffler.io" || window.location.host === "localhost:3000"
|
||||
@@ -280,7 +389,8 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
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 (
|
||||
@@ -294,7 +404,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
borderRadius: 2,
|
||||
border: "1px solid #494949",
|
||||
minWidth: '440px',
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
backgroundColor: "#212121",
|
||||
'& .MuiDialogContent-root': {
|
||||
backgroundColor: "#212121",
|
||||
@@ -303,10 +413,10 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
backgroundColor: "#212121",
|
||||
},
|
||||
'& .MuiTypography-root': {
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
},
|
||||
'& .MuiButton-root': {
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
},
|
||||
}
|
||||
}}
|
||||
@@ -320,7 +430,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
pt: 2,
|
||||
pl: 3,
|
||||
pr: 2,
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
>
|
||||
<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 }}>
|
||||
<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
|
||||
alt={app?.name}
|
||||
src={app?.large_image || app?.image_url}
|
||||
@@ -364,11 +474,9 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
</Typography>
|
||||
{
|
||||
isCloud && (
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
href={"https://shuffler.io/apps/" + app?.id}
|
||||
<Link
|
||||
to={"/apps/" + (app?.id || app?.objectID)}
|
||||
style={{ textDecoration: "none", color: "#f85a3e", marginTop: "-2px" }}
|
||||
target="_blank"
|
||||
>
|
||||
<IconButton
|
||||
style={{
|
||||
@@ -378,7 +486,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
>
|
||||
<OpenInNewIcon />
|
||||
</IconButton>
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
@@ -391,6 +499,11 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center", gap: 10 }}>
|
||||
|
||||
{app?.activated &&
|
||||
app?.private_id !== undefined &&
|
||||
app?.private_id?.length > 0 &&
|
||||
app?.generated ? (
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
@@ -403,11 +516,16 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
height: '40px',
|
||||
padding: 2,
|
||||
color: "#fff",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
downloadApp(app);
|
||||
}}
|
||||
>
|
||||
<CloudDownloadOutlined />
|
||||
</Button>
|
||||
</Button>) : null}
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
@@ -419,9 +537,21 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
px: 3,
|
||||
height: '40px',
|
||||
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"}
|
||||
</Button>
|
||||
@@ -431,7 +561,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
<div style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
padding: "26px 0px"
|
||||
}}>
|
||||
<div style={{
|
||||
@@ -441,7 +571,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: '24px',
|
||||
fontWeight: 600,
|
||||
mb: 0.3,
|
||||
@@ -454,7 +584,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
variant="body2"
|
||||
sx={{
|
||||
color: 'rgba(255, 255, 255, 0.7)',
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: '14px'
|
||||
}}
|
||||
>
|
||||
@@ -486,7 +616,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
paddingLeft: "10px",
|
||||
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 ? (
|
||||
<>
|
||||
@@ -494,13 +624,25 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
<Typography variant="body1" sx={{
|
||||
fontWeight: 500,
|
||||
color: '#fff',
|
||||
marginTop: "1px"
|
||||
marginTop: "1px",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: "16px"
|
||||
}}>
|
||||
app.collection
|
||||
|
||||
</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>
|
||||
@@ -517,7 +659,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
width: "100%"
|
||||
}}>
|
||||
<div style={{
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: "16px",
|
||||
color: "#fff",
|
||||
marginBottom: "16px",
|
||||
@@ -586,7 +728,7 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", justifyContent: "center", fontFamily: "Inter" }}>
|
||||
<div style={{ display: "flex", justifyContent: "center", fontFamily: theme?.typography?.fontFamily }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
@@ -599,11 +741,14 @@ const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
|
||||
fontSize: "14px",
|
||||
letterSpacing: "0.5px",
|
||||
color: "black",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
minWidth: '200px'
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate("/usecases2")
|
||||
}}
|
||||
>
|
||||
Create a Usecase
|
||||
Find a Usecase
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@@ -465,7 +465,7 @@ const AppSelection = props => {
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: "rgba(158, 158, 158, 1)",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}
|
||||
>
|
||||
Your organization has no apps yet, select your starting apps here
|
||||
|
||||
@@ -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 theme from "../theme.jsx";
|
||||
@@ -41,7 +41,8 @@ import {
|
||||
Delete,
|
||||
RestaurantRounded,
|
||||
Cloud,
|
||||
CheckCircle
|
||||
CheckCircle,
|
||||
Padding,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
//import { useAlert
|
||||
@@ -49,8 +50,9 @@ import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||
import BillingStats from "./BillingStats.jsx";
|
||||
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
|
||||
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 alert = useAlert();
|
||||
let navigate = useNavigate();
|
||||
@@ -81,18 +83,12 @@ const Billing = (props) => {
|
||||
}
|
||||
}, [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);
|
||||
|
||||
useState(() => {
|
||||
// Set the billing email
|
||||
setBillingEmail(
|
||||
selectedOrganization.Billing !== undefined &&
|
||||
selectedOrganization.Billing.Email !== undefined &&
|
||||
selectedOrganization.Billing.Email.length > 0
|
||||
? selectedOrganization.Billing.Email
|
||||
: selectedOrganization.org
|
||||
);
|
||||
useEffect(() => {
|
||||
if (BillingEmail !== selectedOrganization?.Billing?.Email) {
|
||||
setBillingEmail(selectedOrganization?.Billing?.Email);
|
||||
}
|
||||
|
||||
// Set and sort the alert thresholds
|
||||
const alertThresholds = selectedOrganization.Billing !== undefined &&
|
||||
@@ -126,7 +122,6 @@ const Billing = (props) => {
|
||||
];
|
||||
|
||||
const handleGetDeals = (orgId) => {
|
||||
console.log("Get deals!");
|
||||
|
||||
if (orgId.length === 0) {
|
||||
toast(
|
||||
@@ -178,7 +173,7 @@ const Billing = (props) => {
|
||||
width: 340,
|
||||
height: 480,
|
||||
// width: "100%",
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
backgroundColor: theme.palette.backgroundColor,
|
||||
borderRadius: theme.palette?.borderRadius * 2,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
marginRight: 10,
|
||||
@@ -384,7 +379,7 @@ const Billing = (props) => {
|
||||
}
|
||||
|
||||
if (hovered) {
|
||||
newPaperstyle.backgroundColor = theme.palette.surfaceColor
|
||||
newPaperstyle.backgroundColor = "#2b2b2b"
|
||||
}
|
||||
|
||||
const handleClickOpen = () => {
|
||||
@@ -412,7 +407,6 @@ const Billing = (props) => {
|
||||
const HandleChangeBillingEmail = (orgId) => {
|
||||
const email = newBillingEmail;
|
||||
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)) {
|
||||
toast("Please enter a valid email address");
|
||||
return;
|
||||
@@ -445,7 +439,6 @@ const Billing = (props) => {
|
||||
}
|
||||
return response.json();
|
||||
}).then((responseJson) => {
|
||||
console.log("Got org:", responseJson);
|
||||
if (responseJson.success === true) {
|
||||
toast.success("Successfully updated billing email");
|
||||
setBillingEmail(newBillingEmail);
|
||||
@@ -460,7 +453,7 @@ const Billing = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
<div
|
||||
style={newPaperstyle}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
@@ -726,7 +719,7 @@ const Billing = (props) => {
|
||||
</Typography>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Typography variant="body2" style={{ marginTop: !userdata.has_card_available ? 5 : 0 }}>
|
||||
Billing email: {BillingEmail}
|
||||
{BillingEmail?.length > 0 ? `Billing email: ${BillingEmail}` : null}
|
||||
</Typography>
|
||||
{userdata.has_card_available === true && (
|
||||
<Button
|
||||
@@ -817,11 +810,11 @@ const Billing = (props) => {
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: !userdata.has_card_available ? 20 : 10,
|
||||
borderRadius: 25,
|
||||
borderRadius: 8,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
color: "white",
|
||||
backgroundColor: userdata.has_card_available ? null : "#f86743",
|
||||
color: userdata.has_card_available ? "#ff8544" : "#1a1a1a",
|
||||
backgroundColor: userdata.has_card_available ? null : "#ff8544",
|
||||
// backgroundImage: userdata.has_card_available ? null : "linear-gradient(to right, #f86a3e, #f34079)",
|
||||
textTransform: "none",
|
||||
|
||||
@@ -850,11 +843,11 @@ const Billing = (props) => {
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: 10,
|
||||
borderRadius: 25,
|
||||
borderRadius: 8,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
color: "white",
|
||||
backgroundColor: "#f86743",
|
||||
color: "#1a1a1a",
|
||||
backgroundColor: "#ff8544",
|
||||
textTransform: 'none'
|
||||
}}
|
||||
onClick={() => {
|
||||
@@ -873,7 +866,6 @@ const Billing = (props) => {
|
||||
: null}
|
||||
{showSupport ?
|
||||
<Button variant="outlined" color="primary" style={{ marginTop: 20, marginBottom: 10, }} onClick={() => {
|
||||
console.log("Support click")
|
||||
if (window.drift !== undefined) {
|
||||
//window.drift.api.startInteraction({ interactionId: 340045 })
|
||||
window.drift.api.startInteraction({ interactionId: 340043 })
|
||||
@@ -884,7 +876,7 @@ const Billing = (props) => {
|
||||
Get Support
|
||||
</Button>
|
||||
: null}
|
||||
</Paper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const ConsultationManagement = (props) => {
|
||||
@@ -1035,12 +1027,12 @@ const Billing = (props) => {
|
||||
})
|
||||
|
||||
return (
|
||||
<Paper style={{
|
||||
<div style={{
|
||||
padding: 20,
|
||||
// maxWidth: 400,
|
||||
width: 340,
|
||||
height: 480,
|
||||
backgroundColor: hovered ? "#232427" : theme.palette.platformColor,
|
||||
backgroundColor: hovered ? "#2b2b2b" : theme.palette.backgroundColor,
|
||||
borderRadius: theme.palette?.borderRadius * 2,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
marginRight: 10,
|
||||
@@ -1131,11 +1123,11 @@ const Billing = (props) => {
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: userdata.support ? 0 : 10,
|
||||
borderRadius: 25,
|
||||
borderRadius: 8,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
color: "white",
|
||||
backgroundColor: "#f86743",
|
||||
color: "#1A1A1A",
|
||||
backgroundColor: "#FF8544",
|
||||
textTransform: 'none',
|
||||
}}
|
||||
onClick={() => {
|
||||
@@ -1150,7 +1142,7 @@ const Billing = (props) => {
|
||||
>
|
||||
Buy
|
||||
</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 }}>
|
||||
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>
|
||||
@@ -1158,7 +1150,7 @@ const Billing = (props) => {
|
||||
<Button
|
||||
variant="contained"
|
||||
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={() => {
|
||||
if (Cloud) {
|
||||
ReactGA.event({
|
||||
@@ -1186,10 +1178,10 @@ const Billing = (props) => {
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: userdata.support ? 5 : 10,
|
||||
borderRadius: 25,
|
||||
borderRadius: 8,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
color: "white",
|
||||
color: "#ff8544",
|
||||
textTransform: 'none',
|
||||
cursor: getProfessionalServices ? 'pointer' : 'not-allowed',
|
||||
opacity: getProfessionalServices ? 1 : 0.6,
|
||||
@@ -1259,7 +1251,7 @@ const Billing = (props) => {
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Paper >
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1308,13 +1300,13 @@ const Billing = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
<div
|
||||
style={{
|
||||
padding: 20,
|
||||
height: 480,
|
||||
// maxWidth: 400,
|
||||
width: 340,
|
||||
backgroundColor: hovered ? "#232427" : theme.palette.platformColor,
|
||||
backgroundColor: hovered ? "#2b2b2b" : theme.palette.backgroundColor,
|
||||
borderRadius: theme.palette?.borderRadius * 2,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
marginRight: 10,
|
||||
@@ -1370,11 +1362,12 @@ const Billing = (props) => {
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: 10,
|
||||
borderRadius: 25,
|
||||
borderRadius: 8,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
color: "white",
|
||||
textTransform: 'none'
|
||||
color: "#1A1A1A",
|
||||
textTransform: 'none',
|
||||
backgroundColor: "#FF8544"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (Cloud) {
|
||||
@@ -1397,10 +1390,12 @@ const Billing = (props) => {
|
||||
color="primary"
|
||||
style={{
|
||||
marginTop: 10,
|
||||
borderRadius: 25,
|
||||
borderRadius: 8,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
textTransform: 'none'
|
||||
textTransform: 'none',
|
||||
color: "#FF8544",
|
||||
backgroundColor: "#1a1a1a",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (Cloud) {
|
||||
@@ -1425,6 +1420,7 @@ const Billing = (props) => {
|
||||
style: {
|
||||
width: 500,
|
||||
margin: 0,
|
||||
backgroundColor: "rgb(26, 26, 26)",
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -1464,7 +1460,7 @@ const Billing = (props) => {
|
||||
<Button
|
||||
variant="contained"
|
||||
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}
|
||||
>
|
||||
Submit Request
|
||||
@@ -1472,7 +1468,7 @@ const Billing = (props) => {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</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 (
|
||||
<div style={{ width: clickedFromOrgTab ? 1030 : "auto", padding: 27, backgroundColor: '#212121', borderRadius: '16px', }}>
|
||||
<Wrapper clickedFromOrgTab={clickedFromOrgTab}>
|
||||
<div style={{ height: "100%", width: "100%"}}>
|
||||
<div style={{ width: "100%",}}>
|
||||
{addDealModal}
|
||||
{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 }}>
|
||||
Billing & Licensing
|
||||
</Typography>}
|
||||
@@ -1942,11 +1940,11 @@ const Billing = (props) => {
|
||||
|
||||
{isChildOrg ?
|
||||
<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>
|
||||
: 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 :
|
||||
<SubscriptionObject
|
||||
index={0}
|
||||
@@ -2258,10 +2256,10 @@ const Billing = (props) => {
|
||||
) : null*/}
|
||||
{!isChildOrg && isCloud && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', marginTop: 10 }}>
|
||||
<Typography style={{ marginBottom: 5 }} variant="h4">
|
||||
<Typography style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}>
|
||||
Professional Services
|
||||
</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.
|
||||
</Typography>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', marginTop: 5 }}>
|
||||
@@ -2280,15 +2278,14 @@ const Billing = (props) => {
|
||||
)}
|
||||
<div style={{ marginTop: isCloud && 40, marginLeft: 10 }}>
|
||||
<Typography
|
||||
style={{ marginBottom: 5 }}
|
||||
variant="h4"
|
||||
style={{ marginBottom: 5, fontSize: 24, fontWeight: "bold" }}
|
||||
>
|
||||
Manage Billing
|
||||
</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.
|
||||
</Typography>
|
||||
<Typography variant="body1">Current Usage:</Typography>
|
||||
<Typography style={{fontSize: 18, marginTop: 10}}>Current Usage:</Typography>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={currentAppRunsInPercentage}
|
||||
@@ -2300,15 +2297,15 @@ const Billing = (props) => {
|
||||
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.
|
||||
</Typography>
|
||||
|
||||
<div>
|
||||
<Typography variant="body1" style={{ marginTop: 20 }}>
|
||||
<Typography style={{ marginTop: 20, fontSize: 18 }}>
|
||||
Set email alert thresholds for app runs
|
||||
</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
|
||||
{currentIndex !== -1
|
||||
? " " + getSafeValue(alertThresholds[currentIndex].percentage) + '%' + " "
|
||||
@@ -2320,8 +2317,8 @@ const Billing = (props) => {
|
||||
: " " + 0 + " "}
|
||||
app runs.
|
||||
</Typography>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10 }}>
|
||||
Please note: Once your app runs reach the set alert threshold, all admins in the organization will receive an email notification.
|
||||
<Typography color="textSecondary" style={{ fontSize: 16 }}>
|
||||
<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>
|
||||
<div style={{ marginTop: 15 }}>
|
||||
{alertThresholds.map((threshold, index) => (
|
||||
@@ -2329,7 +2326,7 @@ const Billing = (props) => {
|
||||
<TextField
|
||||
style={{
|
||||
marginTop: 10,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: "#212121",
|
||||
width: 250,
|
||||
}}
|
||||
InputProps={{
|
||||
@@ -2354,7 +2351,7 @@ const Billing = (props) => {
|
||||
<TextField
|
||||
style={{
|
||||
marginTop: 10,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: "#212121",
|
||||
width: 250,
|
||||
marginLeft: 15,
|
||||
}}
|
||||
@@ -2421,11 +2418,11 @@ const Billing = (props) => {
|
||||
Save
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ marginTop: 40, display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography
|
||||
style={{ marginTop: 10, marginLeft: 10, marginBottom: 5 }}
|
||||
variant="h4"
|
||||
style={{ marginTop: 10, marginLeft: 10, marginBottom: 5, fontSize: 24, fontWeight: "bold" }}
|
||||
>
|
||||
Utilization & Stats
|
||||
</Typography>
|
||||
@@ -2438,7 +2435,39 @@ const Billing = (props) => {
|
||||
userdata={userdata}
|
||||
/>
|
||||
</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>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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 classNames from "classnames";
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
} from 'reaviz';
|
||||
|
||||
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||
import { Context } from '../context/ContextApi.jsx';
|
||||
|
||||
const LineChartWrapper = ({keys, inputname, height, width}) => {
|
||||
const [hovered, setHovered] = useState("");
|
||||
@@ -83,7 +84,7 @@ const AppStats = (defaultprops) => {
|
||||
const [resultRows, setResultRows] = useState([])
|
||||
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(() => {
|
||||
if (workflows === undefined || workflows === null || workflows.length === 0) {
|
||||
@@ -92,7 +93,6 @@ const AppStats = (defaultprops) => {
|
||||
}, [])
|
||||
|
||||
|
||||
|
||||
const getWorkflowStats = async (workflow, startTime, endTime) => {
|
||||
if (!userdata.support) {
|
||||
return workflow
|
||||
@@ -162,8 +162,6 @@ const AppStats = (defaultprops) => {
|
||||
|
||||
const loadWorkflowStats = (foundWorkflows, startTime, endTime) => {
|
||||
if (!userdata.support) {
|
||||
console.log("Not support")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -488,8 +486,13 @@ const AppStats = (defaultprops) => {
|
||||
setApprunCosts(appcostRuns)
|
||||
}
|
||||
|
||||
const getStats = () => {
|
||||
fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`, {
|
||||
const getStats = (orgid) => {
|
||||
|
||||
if (orgid === undefined || orgid === null) {
|
||||
return
|
||||
}
|
||||
|
||||
fetch(`${globalUrl}/api/v1/orgs/${orgid}/stats`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -519,8 +522,10 @@ const AppStats = (defaultprops) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getStats()
|
||||
}, [])
|
||||
if(selectedOrganization?.id?.length > 0) {
|
||||
getStats(selectedOrganization.id)
|
||||
}
|
||||
}, [selectedOrganization])
|
||||
|
||||
const paperStyle = {
|
||||
textAlign: "center",
|
||||
@@ -639,7 +644,7 @@ const AppStats = (defaultprops) => {
|
||||
|
||||
const data = (
|
||||
<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
|
||||
href={`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`}
|
||||
target="_blank"
|
||||
@@ -722,6 +727,40 @@ const AppStats = (defaultprops) => {
|
||||
</div>
|
||||
: 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, }}>
|
||||
<div style={{display: "flex", flexDirection: "column", }}>
|
||||
<DateTimePicker
|
||||
@@ -754,6 +793,8 @@ const AppStats = (defaultprops) => {
|
||||
/>
|
||||
</div>
|
||||
</LocalizationProvider>
|
||||
)}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useContext } from "react";
|
||||
import ReactGA from 'react-ga4';
|
||||
import theme from "../theme.jsx";
|
||||
import { ToastContainer, toast } from "react-toastify"
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
red,
|
||||
green,
|
||||
} from "../views/AngularWorkflow.jsx"
|
||||
import { Context } from "../context/ContextApi.jsx";
|
||||
|
||||
//import { useAlert
|
||||
|
||||
@@ -30,6 +31,7 @@ const Branding = (props) => {
|
||||
const [publishingInfo, setPublishingInfo] = useState("");
|
||||
const [publishRequirements, setPublishRequirements] = useState([])
|
||||
|
||||
const { leftSideBarOpenByClick } = useContext(Context)
|
||||
|
||||
const handleEditOrg = (joinStatus) => {
|
||||
const data = {
|
||||
@@ -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 isPartner = leadinfo.includes("partner")
|
||||
|
||||
console.log("LEADINFO: ", leadinfo)
|
||||
|
||||
console.log("SELECTEDORGANIZATION: ", selectedOrganization)
|
||||
|
||||
return (
|
||||
<div style={{ width: clickedFromOrgTab? 1030: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
|
||||
<h2 style={{marginTop: clickedFromOrgTab ?0:null,}}>
|
||||
<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', }}>
|
||||
<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
|
||||
</h2>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
</Typography>
|
||||
<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.
|
||||
</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, }} />}
|
||||
<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>
|
||||
|
||||
<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, }} />}
|
||||
<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>
|
||||
</Typography>
|
||||
</a>
|
||||
|
||||
<a href={`/partners/${selectedOrganization.creator_id}/edit`} target="_blank">
|
||||
<Button disabled={isPublished} variant="contained" style={{ marginTop: 20, marginBottom: 10, }} onClick={() => {
|
||||
}}>
|
||||
{!isPublished ? (
|
||||
<a
|
||||
href={`/partners/${selectedOrganization.creator_id}/edit`}
|
||||
target="_blank"
|
||||
style={{ textDecoration: "none" }} // Optional: remove underline
|
||||
>
|
||||
<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, }} />
|
||||
<h2>
|
||||
<Typography style={{fontSize: 24, fontWeight: "bold"}}>
|
||||
Partner Program
|
||||
</h2>
|
||||
<div style={{ display: "flex", width: 900, }}>
|
||||
</Typography>
|
||||
<div style={{ display: "flex", width: 900, marginTop: 10}}>
|
||||
<div>
|
||||
<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>
|
||||
</Typography>
|
||||
{selectedOrganization.creator_id == "" ?
|
||||
@@ -167,9 +194,8 @@ const Branding = (props) => {
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
<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"}
|
||||
color={selectedOrganization.creator_id == "" ? "primary" : "secondary"}
|
||||
disabled={!isOrganizationReady()}
|
||||
@@ -196,6 +222,8 @@ const Branding = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useContext, memo } from "react";
|
||||
import theme from "../theme.jsx";
|
||||
import { toast } from 'react-toastify';
|
||||
import ReactJson from "react-json-view-ssr";
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogActions,
|
||||
Skeleton,
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
@@ -47,6 +48,7 @@ import {
|
||||
VisibilityOff as VisibilityOffIcon,
|
||||
} from "@mui/icons-material";
|
||||
import { validateJson, } from "../views/Workflows.jsx";
|
||||
import { Context } from "../context/ContextApi.jsx";
|
||||
|
||||
const scrollStyle1 = {
|
||||
height: 100,
|
||||
@@ -65,7 +67,7 @@ const scrollStyle2 = {
|
||||
}
|
||||
|
||||
|
||||
const CacheView = (props) => {
|
||||
const CacheView = memo((props) => {
|
||||
const { globalUrl, userdata, serverside, orgId, isSelectedDataStore } = props;
|
||||
const [orgCache, setOrgCache] = React.useState("");
|
||||
const [listCache, setListCache] = React.useState([]);
|
||||
@@ -78,11 +80,13 @@ const CacheView = (props) => {
|
||||
const [cacheCursor, setCacheCursor] = React.useState("");
|
||||
const [dataValue, setDataValue] = React.useState({});
|
||||
const [editCache, setEditCache] = React.useState(false);
|
||||
const [cachedLoaded, setCachedLoaded] = React.useState(false);
|
||||
const [show, setShow] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
if(orgId?.length >0){
|
||||
listOrgCache(orgId);
|
||||
}, []);
|
||||
}
|
||||
}, [orgId]);
|
||||
|
||||
const listOrgCache = (orgId) => {
|
||||
fetch(globalUrl + `/api/v1/orgs/${orgId}/list_cache`, {
|
||||
@@ -104,6 +108,7 @@ const CacheView = (props) => {
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === true) {
|
||||
setListCache(responseJson.keys);
|
||||
setCachedLoaded(true);
|
||||
}
|
||||
|
||||
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 = (
|
||||
// console.log("key:", dataValue.key),
|
||||
//console.log("value:",dataValue.value),
|
||||
@@ -241,11 +274,23 @@ const CacheView = (props) => {
|
||||
setModalOpen(false);
|
||||
}}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
color: "white",
|
||||
sx: {
|
||||
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
|
||||
border: theme?.palette?.DialogStyle?.border,
|
||||
minWidth: "800px",
|
||||
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" }
|
||||
</span>
|
||||
</DialogTitle>
|
||||
<div style={{ paddingLeft: "30px", paddingRight: '30px' }}>
|
||||
<div style={{ paddingLeft: "30px", paddingRight: '30px', backgroundColor: "#212121", }}>
|
||||
Key
|
||||
<TextField
|
||||
color="primary"
|
||||
@@ -278,7 +323,7 @@ const CacheView = (props) => {
|
||||
onChange={(e) => setKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ paddingLeft: 30, paddingRight: 30 }}>
|
||||
<div style={{ paddingLeft: 30, paddingRight: 30, backgroundColor: "#212121" }}>
|
||||
<div style={{display: "flex", }}>
|
||||
<Typography style={{marginTop: 25, marginBottom: 0, flex: 20, }}>
|
||||
Value - ({isValidJson.valid === true ? "Valid" : "Invalid"} JSON)
|
||||
@@ -320,7 +365,7 @@ const CacheView = (props) => {
|
||||
</div>
|
||||
<DialogActions style={{ paddingLeft: "30px", paddingRight: '30px' }}>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
style={{ borderRadius: "2px", fontSize: 16, color: "#ff8544", textTransform:"none" }}
|
||||
onClick={() => {
|
||||
setModalOpen(false)
|
||||
setValue("")
|
||||
@@ -332,7 +377,7 @@ const CacheView = (props) => {
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{ borderRadius: "0px" }}
|
||||
style={{ borderRadius: "2px", backgroundColor: "#ff8544",color: "#1a1a1a", textTransform:"none" }}
|
||||
onClick={() => {
|
||||
{editCache ? editOrgCache(orgId) : addOrgCache(orgId)}
|
||||
|
||||
@@ -348,9 +393,10 @@ const CacheView = (props) => {
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
<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, }}>
|
||||
<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" }}>
|
||||
{modalView}
|
||||
<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>
|
||||
<span style={{ marginLeft: isSelectedDataStore?null:25, color:isSelectedDataStore?"#9E9E9E":null}}>
|
||||
@@ -366,7 +412,7 @@ const CacheView = (props) => {
|
||||
</span>
|
||||
</div>
|
||||
<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"
|
||||
color="primary"
|
||||
onClick={() =>{
|
||||
@@ -379,7 +425,7 @@ const CacheView = (props) => {
|
||||
Add Cache
|
||||
</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"
|
||||
color="primary"
|
||||
onClick={() => listOrgCache(orgId)}
|
||||
@@ -392,28 +438,79 @@ const CacheView = (props) => {
|
||||
marginBottom: 20,
|
||||
}}
|
||||
/>}
|
||||
<List style={{borderRadius: isSelectedDataStore?8:null, border:isSelectedDataStore?"1px solid #494949":null, marginTop:isSelectedDataStore?24:null}}>
|
||||
<ListItem style={{width: isSelectedDataStore?"100%":null, borderBottom:isSelectedDataStore?"1px solid #494949":null}}>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
marginTop: 24,
|
||||
border: "1px solid #494949",
|
||||
width: "100%",
|
||||
overflowX: "auto",
|
||||
paddingBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
paddingBottom: 0,
|
||||
tableLayout: "auto",
|
||||
display: "table",
|
||||
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
|
||||
primary="Key"
|
||||
style={{ minWidth: isSelectedDataStore?200:250, maxWidth: isSelectedDataStore?200:250, }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Value"
|
||||
style={{ minWidth: isSelectedDataStore?300:400, maxWidth: isSelectedDataStore?300:400, overflowX: "auto", overflowY: "hidden", }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Actions"
|
||||
style={{ minWidth: 150, maxWidth: 150, marginLeft: isSelectedDataStore?80:null,}}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{textAlign:isSelectedDataStore?"center":null}}
|
||||
primary="Updated"
|
||||
key={index}
|
||||
primary={header}
|
||||
style={{
|
||||
display: "table-cell",
|
||||
padding: "0px 8px 8px 8px",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
borderBottom: "1px solid #494949"
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</ListItem>
|
||||
{listCache === undefined || listCache === null
|
||||
? null
|
||||
: listCache.map((data, index) => {
|
||||
{cachedLoaded === false
|
||||
? [...Array(6)].map((_, rowIndex) => (
|
||||
<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";
|
||||
if (index % 2 === 0) {
|
||||
bgColor = isSelectedDataStore? "#1A1A1A":"#1f2023";
|
||||
@@ -421,35 +518,46 @@ const CacheView = (props) => {
|
||||
|
||||
const validate = validateJson(data.value);
|
||||
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
|
||||
style={{
|
||||
maxWidth: 200,
|
||||
minWidth: 200,
|
||||
display: "table-cell",
|
||||
overflow: "hidden",
|
||||
padding: 8,
|
||||
verticalAlign: "middle",
|
||||
}}
|
||||
primary={data.key}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
minWidth: 300,
|
||||
maxWidth: 300,
|
||||
// height:200,
|
||||
overflowX: "hidden",
|
||||
display: "table-cell",
|
||||
overflowY: "auto",
|
||||
overflowX: "auto",
|
||||
border: "1px solid rgba(255,255,255,0.7)",
|
||||
borderRadius: 6,
|
||||
backgroundColor: "#151515",
|
||||
maxHeight: 300,
|
||||
verticalAlign: "middle",
|
||||
}}
|
||||
primary={validate.valid ?
|
||||
<ReactJson
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
style={{
|
||||
padding: 5,
|
||||
maxHeight: 300,
|
||||
overflowY: "auto",
|
||||
}}
|
||||
collapsed={true}
|
||||
enableClipboard={(copy) => {
|
||||
// handleReactJsonClipboard(copy);
|
||||
}}
|
||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||
iconStyle={theme.palette.jsonIconStyle}
|
||||
displayDataTypes={false}
|
||||
onSelect={(select) => {
|
||||
// HandleJsonCopy(showResult, select, data.action.label);
|
||||
//console.log("SELECTED!: ", select);
|
||||
console.log("SELECTED!: ", select);
|
||||
}}
|
||||
name={"value"}
|
||||
/>
|
||||
@@ -459,11 +567,12 @@ const CacheView = (props) => {
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
maxWidth: 200,
|
||||
minWidth: 200,
|
||||
marginLeft: 50,
|
||||
display: "table-cell",
|
||||
verticalAlign: "middle",
|
||||
padding: 8
|
||||
}}
|
||||
primary=<span style={{ display: "inline" }}>
|
||||
primary={(
|
||||
<span style={{ display: "inline" }}>
|
||||
<Tooltip
|
||||
title="Edit item"
|
||||
style={{}}
|
||||
@@ -482,9 +591,7 @@ const CacheView = (props) => {
|
||||
setModalOpen(true)
|
||||
}}
|
||||
>
|
||||
<EditIcon
|
||||
style={{ color: "white" }}
|
||||
/>
|
||||
<img src="/icons/editIcon.svg" alt="edit" />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
@@ -508,7 +615,6 @@ const CacheView = (props) => {
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={"Delete item"}
|
||||
style={{ marginLeft: 25, }}
|
||||
aria-label={"Delete"}
|
||||
>
|
||||
<span>
|
||||
@@ -519,18 +625,18 @@ const CacheView = (props) => {
|
||||
//deleteFile(orgId);
|
||||
}}
|
||||
>
|
||||
<DeleteIcon
|
||||
style={{ color: "white" }}
|
||||
/>
|
||||
<img src="/icons/deleteIcon.svg" alt="delete" />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
<ListItemText
|
||||
style={{
|
||||
maxWidth: 225,
|
||||
minWidth: 225,
|
||||
display: "table-cell",
|
||||
verticalAlign: "middle",
|
||||
padding: 8
|
||||
}}
|
||||
primary={new Date(data.edited * 1000).toISOString()}
|
||||
/>
|
||||
@@ -539,7 +645,10 @@ const CacheView = (props) => {
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default CacheView;
|
||||
});
|
||||
|
||||
export default memo(CacheView);
|
||||
|
||||
@@ -1149,7 +1149,7 @@ const EditWorkflow = (props) => {
|
||||
</div>
|
||||
: null}
|
||||
|
||||
{/*!isEditing ? <>
|
||||
{!isEditing ? <>
|
||||
<div style={{ marginTop: 20, }}>
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
@@ -1164,7 +1164,7 @@ const EditWorkflow = (props) => {
|
||||
/>
|
||||
|
||||
</div>
|
||||
</> : null*/}
|
||||
</> : null}
|
||||
|
||||
<Tooltip color="primary" title={"Add more details"} placement="top">
|
||||
<Button
|
||||
|
||||
+189
-121
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useContext, memo } from "react";
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import {
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Typography,
|
||||
Skeleton,
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
@@ -39,11 +40,13 @@ import {
|
||||
import Dropzone from "../components/Dropzone.jsx";
|
||||
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.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 [files, setFiles] = React.useState([]);
|
||||
const [showLoader, setShowLoader] = useState(true)
|
||||
const [selectedCategory, setSelectedCategory] = React.useState("default");
|
||||
const [openFileId, setOpenFileId] = React.useState(false);
|
||||
const [fileCategories, setFileCategories] = React.useState([]);
|
||||
@@ -58,7 +61,6 @@ const Files = (props) => {
|
||||
const [downloadBranch, setDownloadBranch] = React.useState("main");
|
||||
const [downloadFolder, setDownloadFolder] = React.useState("translation_standards");
|
||||
const [contentLoading, setContentLoading] = React.useState(false)
|
||||
|
||||
//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"]
|
||||
var upload = "";
|
||||
@@ -66,8 +68,6 @@ const Files = (props) => {
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
|
||||
console.log('do validate')
|
||||
console.log("new namespace name->",event.target.value);
|
||||
fileCategories.push(event.target.value);
|
||||
setSelectedCategory(event.target.value);
|
||||
setRenderTextBox(false);
|
||||
@@ -136,6 +136,7 @@ const Files = (props) => {
|
||||
.then((responseJson) => {
|
||||
if (responseJson.files !== undefined && responseJson.files !== null) {
|
||||
setFiles(responseJson.files);
|
||||
setShowLoader(false)
|
||||
} else if (responseJson.list !== undefined && responseJson.list !== null) {
|
||||
// Set the "namespace" field in all items
|
||||
if (namespace !== undefined && namespace !== null) {
|
||||
@@ -147,8 +148,10 @@ const Files = (props) => {
|
||||
}
|
||||
|
||||
setFiles(responseJson.list);
|
||||
setShowLoader(false)
|
||||
} else {
|
||||
setFiles([]);
|
||||
setShowLoader(false)
|
||||
}
|
||||
|
||||
if (namespace === undefined || namespace === null || namespace === "default") {
|
||||
@@ -244,14 +247,26 @@ const Files = (props) => {
|
||||
const fileDownloadModal = loadFileModalOpen ?
|
||||
<Dialog
|
||||
open={loadFileModalOpen}
|
||||
onClose={() => {}}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
color: "white",
|
||||
sx: {
|
||||
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
|
||||
border: theme?.palette?.DialogStyle?.border,
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
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>
|
||||
@@ -364,7 +379,7 @@ const Files = (props) => {
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#ff8544" }}
|
||||
onClick={() => setLoadFileModalOpen(false)}
|
||||
color="primary"
|
||||
>
|
||||
@@ -372,7 +387,7 @@ const Files = (props) => {
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{ borderRadius: "0px" }}
|
||||
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: "#1a1a1a", backgroundColor: "#ff8544" }}
|
||||
disabled={downloadUrl.length === 0 || !downloadUrl.includes("http")}
|
||||
onClick={() => {
|
||||
handleGithubValidation();
|
||||
@@ -637,24 +652,18 @@ const Files = (props) => {
|
||||
return (
|
||||
<Dropzone
|
||||
style={{
|
||||
maxWidth: window.innerWidth > 1366 ? 1366 : 1200,
|
||||
margin: "auto",
|
||||
padding: isSelectedFiles ? null : 20,
|
||||
width: '100%',
|
||||
height: "100%",
|
||||
}}
|
||||
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">
|
||||
<IconButton
|
||||
color="secondary"
|
||||
style={{position: "absolute", right: 0, top: isSelectedFiles?null:0, left: isSelectedFiles? 990:null }}
|
||||
variant="text"
|
||||
onClick={() => setLoadFileModalOpen(true)}
|
||||
>
|
||||
<CloudDownloadIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<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' }}>
|
||||
<DownloadFileIcon setLoadFileModalOpen={setLoadFileModalOpen} isSelectedFiles={isSelectedFiles} />
|
||||
|
||||
{fileDownloadModal}
|
||||
|
||||
@@ -681,9 +690,9 @@ const Files = (props) => {
|
||||
onClick={() => {
|
||||
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>
|
||||
{/* <FileCategoryInput
|
||||
isSet={renderTextBox} /> */}
|
||||
@@ -702,7 +711,7 @@ const Files = (props) => {
|
||||
}}
|
||||
/>
|
||||
<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"
|
||||
color="primary"
|
||||
onClick={() => getFiles(selectedCategory)}
|
||||
@@ -710,21 +719,23 @@ const Files = (props) => {
|
||||
<CachedIcon />
|
||||
</Button>
|
||||
|
||||
|
||||
{/* <div style={{height: 35, width: 1, color: "#494949"}}></div> */}
|
||||
|
||||
{fileCategories !== undefined &&
|
||||
fileCategories !== null &&
|
||||
fileCategories.length > 1 ? (
|
||||
<FormControl style={{ minWidth: 150, maxWidth: 150 }}>
|
||||
<InputLabel id="input-namespace-label">File Category</InputLabel>
|
||||
<Select
|
||||
labelId="input-namespace-select-label"
|
||||
id="input-namespace-select-id"
|
||||
style={{
|
||||
color: "white",
|
||||
minWidth: 150,
|
||||
maxWidth: 150,
|
||||
minWidth: 122,
|
||||
maxWidth: 122,
|
||||
height: 35,
|
||||
float: "right",
|
||||
position: 'relative',
|
||||
top: 8
|
||||
}}
|
||||
value={selectedCategory}
|
||||
onChange={(event) => {
|
||||
@@ -759,7 +770,7 @@ const Files = (props) => {
|
||||
</Select>
|
||||
</FormControl>
|
||||
) : null}
|
||||
<div style={{display: "inline-flex", position:"relative"}}>
|
||||
<div style={{display: "inline-flex", position:"relative", top: 8}}>
|
||||
{renderTextBox ?
|
||||
|
||||
<Tooltip title={"Close"} style={{}} aria-label={""}>
|
||||
@@ -777,13 +788,14 @@ const Files = (props) => {
|
||||
:
|
||||
<Tooltip title={"Add new file category"} style={{}} aria-label={""}>
|
||||
<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"
|
||||
onClick={() => {
|
||||
setRenderTextBox(true);
|
||||
}}
|
||||
>
|
||||
<AddIcon/>
|
||||
File Category
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
@@ -824,44 +836,86 @@ const Files = (props) => {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
}}
|
||||
/>}
|
||||
|
||||
<List style={{borderRadius: isSelectedFiles?8:null, border:isSelectedFiles?"1px solid #494949":null, marginTop:isSelectedFiles?24:null}}>
|
||||
<ListItem style={{width:isSelectedFiles?"100%":null, borderBottom:isSelectedFiles?"1px solid #494949":null}}>
|
||||
{/*
|
||||
<ListItemText
|
||||
primary="Updated"
|
||||
style={{ maxWidth: 185, minWidth: 185 }}
|
||||
/>
|
||||
*/}
|
||||
<ListItemText
|
||||
primary="Name"
|
||||
<div
|
||||
style={{
|
||||
maxWidth: 250,
|
||||
minWidth: 250,
|
||||
overflow: "hidden",
|
||||
marginLeft: 10,
|
||||
borderRadius: 8,
|
||||
marginTop: 24,
|
||||
border: "1px solid #494949",
|
||||
width: "100%",
|
||||
overflowX: "auto",
|
||||
paddingBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List
|
||||
style={{
|
||||
width: '100%',
|
||||
tableLayout: "auto",
|
||||
display: "table",
|
||||
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>
|
||||
{files === undefined || files === null || files.length === 0 ? null :
|
||||
files.map((file, index) => {
|
||||
{showLoader ?
|
||||
[...Array(6)].map((_, rowIndex) => (
|
||||
<ListItem
|
||||
key={rowIndex}
|
||||
style={{
|
||||
display: "table-row",
|
||||
backgroundColor: "#212121",
|
||||
}}
|
||||
>
|
||||
{Array(6)
|
||||
.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>
|
||||
)):
|
||||
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";
|
||||
}
|
||||
@@ -877,14 +931,16 @@ const Files = (props) => {
|
||||
|
||||
const filenamesplit = file.filename.split(".")
|
||||
const iseditable = file.filesize < 2000000 && file.status === "active" && allowedFileTypes.includes(filenamesplit[filenamesplit.length-1])
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={index}
|
||||
style={{
|
||||
display: 'table-row',
|
||||
backgroundColor: bgColor,
|
||||
maxHeight: 100,
|
||||
overflow: "hidden",
|
||||
borderBottomLeftRadius: files?.length - 1 === index ? 8 : 0,
|
||||
borderBottomRightRadius: files?.length - 1 === index ? 8 : 0,
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
@@ -898,12 +954,17 @@ const Files = (props) => {
|
||||
/>
|
||||
*/}
|
||||
<ListItemText
|
||||
style={{
|
||||
maxWidth: 250,
|
||||
minWidth: 250,
|
||||
overflow: "hidden",
|
||||
marginLeft: 10,
|
||||
primaryTypographyProps={{
|
||||
style: {
|
||||
display: 'table-cell',
|
||||
maxWidth: "170px",
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
padding: 8
|
||||
},
|
||||
}}
|
||||
|
||||
primary={file.filename}
|
||||
/>
|
||||
<ListItemText
|
||||
@@ -911,12 +972,13 @@ const Files = (props) => {
|
||||
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"
|
||||
? "white"
|
||||
? "#FF8444"
|
||||
: "grey",
|
||||
}}
|
||||
/>
|
||||
@@ -939,12 +1001,13 @@ const Files = (props) => {
|
||||
>
|
||||
<IconButton
|
||||
disabled={file.workflow_id === "global"}
|
||||
style={{marginLeft: 10}}
|
||||
>
|
||||
<OpenInNewIcon
|
||||
style={{
|
||||
color:
|
||||
file.workflow_id !== "global"
|
||||
? "white"
|
||||
? "#FF8444"
|
||||
: "grey",
|
||||
}}
|
||||
/>
|
||||
@@ -955,38 +1018,42 @@ const Files = (props) => {
|
||||
)
|
||||
}
|
||||
style={{
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
display: 'table-cell',
|
||||
overflow: "hidden",
|
||||
textAlign: isSelectedFiles?"center":null
|
||||
}}
|
||||
/>
|
||||
<ListItemText
|
||||
primary={file.md5_sum}
|
||||
style={{
|
||||
minWidth: 300,
|
||||
maxWidth: 300,
|
||||
primary={(
|
||||
<Tooltip title={file.md5_sum}>
|
||||
{file.md5_sum}
|
||||
</Tooltip>
|
||||
)}
|
||||
primaryTypographyProps={{
|
||||
style:{
|
||||
display: 'table-cell',
|
||||
marginLeft:isSelectedFiles? 15:null,
|
||||
overflow: isSelectedFiles?"auto":"hidden",
|
||||
overflow: "hidden",
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: 200,
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<ListItemText
|
||||
primary={file.status}
|
||||
style={{
|
||||
minWidth: 75,
|
||||
maxWidth: 75,
|
||||
display: 'table-cell',
|
||||
overflow: "hidden",
|
||||
textAlign:isSelectedFiles?"center":null,
|
||||
marginLeft: 10,
|
||||
textAlign:isSelectedFiles?"left":null,
|
||||
color: file.status === "active" ? "#2BC07E" : "#FD4C62"
|
||||
}}
|
||||
/>
|
||||
<ListItemText
|
||||
primary={file.filesize}
|
||||
style={{
|
||||
minWidth: isSelectedFiles?80:125,
|
||||
maxWidth: isSelectedFiles?80:125,
|
||||
marginLeft: isSelectedFiles?15:null,
|
||||
display: 'table-cell',
|
||||
overflow: "hidden",
|
||||
textAlign:'center'
|
||||
}}
|
||||
/>
|
||||
<ListItemText
|
||||
@@ -999,14 +1066,14 @@ const Files = (props) => {
|
||||
<span>
|
||||
<IconButton
|
||||
disabled={!iseditable}
|
||||
style = {{padding: "6px"}}
|
||||
style = {{padding: "6px", }}
|
||||
onClick={() => {
|
||||
setOpenEditor(true)
|
||||
setOpenFileId(file.id)
|
||||
readFileData(file)
|
||||
}}
|
||||
>
|
||||
<EditIcon
|
||||
<img src="/icons/editIcon.svg" alt="edit icon"
|
||||
style={{color: iseditable ? "white" : "grey",}}
|
||||
/>
|
||||
</IconButton>
|
||||
@@ -1051,7 +1118,7 @@ const Files = (props) => {
|
||||
downloadFile(file);
|
||||
}}
|
||||
>
|
||||
<CloudDownloadIcon
|
||||
<img src="/icons/downloadIcon.svg" alt="download icon"
|
||||
style={{
|
||||
color:
|
||||
file.status === "active"
|
||||
@@ -1070,36 +1137,14 @@ const Files = (props) => {
|
||||
<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;
|
||||
}
|
||||
|
||||
console.log("file is : ", file)
|
||||
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" }} />
|
||||
<img src="/icons/copyIcon.svg" alt="copy icon" style={{ color: "white" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
@@ -1115,7 +1160,7 @@ const Files = (props) => {
|
||||
deleteFile(file)
|
||||
}}
|
||||
>
|
||||
<DeleteIcon
|
||||
<img src="/icons/deleteIcon.svg" alt="delete icon"
|
||||
style={{
|
||||
color:
|
||||
file.status === "active"
|
||||
@@ -1128,19 +1173,42 @@ const Files = (props) => {
|
||||
</Tooltip>
|
||||
</span>
|
||||
style={{
|
||||
minWidth: 250,
|
||||
maxWidth: 250,
|
||||
display: 'table-cell',
|
||||
textAlign:'center'
|
||||
// overflow: "hidden",
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
})
|
||||
)
|
||||
}
|
||||
</List>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Add as AddIcon,
|
||||
BorderColor,
|
||||
Close as CloseIcon,
|
||||
ConstructionOutlined,
|
||||
} from "@mui/icons-material";
|
||||
import SearchBox from "./SearchData.jsx";
|
||||
import {
|
||||
@@ -85,7 +86,21 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
return orgOptions.find((option) => option.name === selectedOrg);
|
||||
}, [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) => {
|
||||
return (
|
||||
@@ -141,7 +156,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
>
|
||||
{props.children}
|
||||
</Box>
|
||||
<Link to="/admin2" style={hrefStyle}>
|
||||
<Link to="/admin?tab=tenants" style={hrefStyle}>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
@@ -446,7 +461,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Link to="/admin2" style={hrefStyle}>
|
||||
<Link to="/admin" style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
handleClose();
|
||||
@@ -466,7 +481,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
</Link>
|
||||
|
||||
<Divider style={{ marginTop: 10, marginBottom: 10, }} />
|
||||
<Link to="/admin2?admin_tab=priorities" style={hrefStyle}>
|
||||
<Link to="/admin?admin_tab=notifications" style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
handleClose();
|
||||
@@ -478,7 +493,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
})
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Link to="/usecases2" style={hrefStyle}>
|
||||
<Link to="/usecases" style={hrefStyle}>
|
||||
<MenuItem
|
||||
onClick={(event) => {
|
||||
handleClose();
|
||||
@@ -641,7 +656,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
};
|
||||
|
||||
const getRegionTag = (region_url) => {
|
||||
let regiontag = "eu";
|
||||
let regiontag = "UK";
|
||||
if (
|
||||
region_url !== undefined &&
|
||||
region_url !== null &&
|
||||
@@ -653,15 +668,25 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
regiontag = namesplit[namesplit.length - 1];
|
||||
|
||||
if (regiontag === "california") {
|
||||
regiontag = "us";
|
||||
regiontag = "US";
|
||||
} else if (regiontag === "frankfurt") {
|
||||
regiontag = "fr";
|
||||
regiontag = "EU";
|
||||
} else if (regiontag === "ca"){
|
||||
regiontag = "CA";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return regiontag;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if(activeOrgName !== userdata?.active_org?.name){
|
||||
setActiveOrgName(userdata?.active_org?.name || "Select Organization");
|
||||
}
|
||||
}, [userdata]);
|
||||
|
||||
const CheckOrgStates = useCallback(() => {
|
||||
setOrgOptions(
|
||||
userdata?.orgs?.map((org) => ({
|
||||
@@ -723,6 +748,20 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
</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 (
|
||||
<div
|
||||
style={{
|
||||
@@ -736,7 +775,8 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.2)" ,
|
||||
resize: 'both',
|
||||
|
||||
height: "calc(100vh - 32px)",
|
||||
zoom: 0.8,
|
||||
height: "calc((100vh - 32px)*1.2)",
|
||||
}}
|
||||
>
|
||||
{modalView}
|
||||
@@ -759,7 +799,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
// alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
right: !expandLeftNav && 8,
|
||||
@@ -831,7 +871,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#ffffff",
|
||||
display: "block"
|
||||
display: "block",
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#A9A9A9",
|
||||
@@ -849,10 +889,26 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
startAdornment: (
|
||||
<SearchIcon style={{ color: "#CDCDCD", width: 24, height: 24, marginLeft: 16 }} />
|
||||
),
|
||||
endAdornment: (
|
||||
<span
|
||||
style={{
|
||||
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)}}
|
||||
onClick={() => {
|
||||
setSearchBarModalOpen(true);
|
||||
}}
|
||||
onChange={() => {
|
||||
setSearchBarModalOpen(true);
|
||||
}}
|
||||
/>
|
||||
</Fade>
|
||||
):(
|
||||
@@ -891,10 +947,16 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
setCurrentOpenTab("automate");
|
||||
localStorage.setItem("lastTabOpenByUser", "automate");
|
||||
}}
|
||||
sx={{
|
||||
variant="text"
|
||||
style={{
|
||||
...ButtonStyle,
|
||||
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
|
||||
@@ -920,9 +982,16 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
setOpenautomateTab((prev) => !prev);
|
||||
setOpenSecurityTab(false);
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
marginLeft: 0.625,
|
||||
}}
|
||||
onMouseOver={(event)=>{
|
||||
event.currentTarget.style.backgroundColor = "#2f2f2f";
|
||||
}}
|
||||
onMouseOut={(event)=>{
|
||||
event.currentTarget.style.backgroundColor = "transparent";
|
||||
}}
|
||||
>
|
||||
{openautomatetab ? (
|
||||
<ExpandLessIcon
|
||||
@@ -952,23 +1021,28 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
flexDirection: "column",
|
||||
paddingLeft: 16,
|
||||
gap: 4,
|
||||
marginTop: expandLeftNav ? 16 : 0,
|
||||
}}
|
||||
>
|
||||
<Link to="/usecases2" style={hrefStyle}>
|
||||
<Link to="/usecases" style={hrefStyle}>
|
||||
<Button
|
||||
onClick={(event) => {
|
||||
setCurrentOpenTab("usecases");
|
||||
localStorage.setItem("lastTabOpenByUser", "usecases");
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 35,
|
||||
color: "#C8C8C8",
|
||||
justifyContent: "flex-start",
|
||||
textTransform: "none",
|
||||
backgroundColor: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases2")? "#2f2f2f": "transparent",
|
||||
"&:hover": { backgroundColor: "#2f2f2f" },
|
||||
backgroundColor: currentOpenTab === "usecases" && expandLeftNav && currentPath.includes("/usecases")? "#2f2f2f": "transparent",
|
||||
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}
|
||||
>
|
||||
@@ -985,22 +1059,28 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to="/workflows2" style={hrefStyle}>
|
||||
<Link to="/workflows" style={hrefStyle}>
|
||||
<Button
|
||||
onClick={(event) => {
|
||||
setCurrentOpenTab("workflows");
|
||||
localStorage.setItem("lastTabOpenByUser", "workflows");
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 35,
|
||||
color: "#C8C8C8",
|
||||
justifyContent: "flex-start",
|
||||
textTransform: "none",
|
||||
backgroundColor: currentOpenTab === "workflows" && currentPath === "/workflows" && expandLeftNav? "#2f2f2f": "transparent",
|
||||
"&:hover": { backgroundColor: "#2f2f2f" },
|
||||
marginLeft: 16
|
||||
}}
|
||||
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
|
||||
@@ -1015,20 +1095,26 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to="/apps2" style={hrefStyle}>
|
||||
<Link to="/apps" style={hrefStyle}>
|
||||
<Button
|
||||
onClick={(event) => {
|
||||
setCurrentOpenTab("apps");
|
||||
localStorage.setItem("lastTabOpenByUser", "apps");
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 35,
|
||||
color: "#C8C8C8",
|
||||
justifyContent: "flex-start",
|
||||
textTransform: "none",
|
||||
backgroundColor: currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/search") ? "#2f2f2f": "transparent",
|
||||
"&:hover": { backgroundColor: "#2f2f2f" },
|
||||
backgroundColor: currentOpenTab === "apps" && expandLeftNav && currentPath.includes("/apps2") ? "#2f2f2f": "transparent",
|
||||
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}
|
||||
>
|
||||
@@ -1038,7 +1124,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
display: expandLeftNav ? "inline" : "none",
|
||||
opacity: expandLeftNav ? 1 : 0,
|
||||
transition: "opacity 0.3s ease",
|
||||
color: currentOpenTab === "apps" && currentPath.includes("/search") ? "#F1F1F1" : "#C8C8C8",
|
||||
color: currentOpenTab === "apps" && currentPath.includes("/apps2") ? "#F1F1F1" : "#C8C8C8",
|
||||
}}
|
||||
>
|
||||
Apps
|
||||
@@ -1051,7 +1137,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
marginTop: 2.5,
|
||||
marginTop: 1
|
||||
}}
|
||||
>
|
||||
<span style={{ display: "inline-block", width: "100%" }}>
|
||||
@@ -1072,7 +1158,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
setCurrentOpenTab("security");
|
||||
localStorage.setItem("lastTabOpenByUser", "security");
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
...ButtonStyle,
|
||||
backgroundColor:
|
||||
((currentOpenTab === "security" && currentPath.includes("/security")) ||
|
||||
@@ -1080,11 +1166,19 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
(currentPath.includes("detections") || currentPath.includes("response"))))
|
||||
? "#2f2f2f"
|
||||
: "transparent",
|
||||
"&:hover": {
|
||||
backgroundColor: userdata?.support ? "#2f2f2f" : "transparent",
|
||||
},
|
||||
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
|
||||
style={{
|
||||
@@ -1105,19 +1199,25 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
: "#6F6F6F",
|
||||
}}
|
||||
>
|
||||
Security
|
||||
Content
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
</span>
|
||||
<IconButton
|
||||
disabled={true}
|
||||
onClick={() => {
|
||||
setOpenSecurityTab((prev) => !prev);
|
||||
setOpenautomateTab(false);
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
marginLeft: 0.625,
|
||||
color: "#FFFFFF",
|
||||
}}
|
||||
onMouseOver={(event)=>{
|
||||
event.currentTarget.style.backgroundColor = "#2f2f2f";
|
||||
}}
|
||||
onMouseOut={(event)=>{
|
||||
event.currentTarget.style.backgroundColor = "transparent";
|
||||
}}
|
||||
>
|
||||
{openSecurityTab ? (
|
||||
@@ -1144,14 +1244,12 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
paddingLeft: 16,
|
||||
gap: 4,
|
||||
marginTop: expandLeftNav ? 16 : 0,
|
||||
}}
|
||||
disableRipple={expandLeftNav ? false : true}
|
||||
>
|
||||
<span style={{ display: "inline-block", width: "100%" }}>
|
||||
<Link
|
||||
to={userdata?.support ? "/detections" : "#"}
|
||||
to={"/forms"}
|
||||
style={{
|
||||
...hrefStyle,
|
||||
pointerEvents: userdata?.support ? "auto" : "none",
|
||||
@@ -1196,14 +1294,14 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
: "#6F6F6F",
|
||||
}}
|
||||
>
|
||||
Detection
|
||||
Forms
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
</span>
|
||||
<span style={{ display: "inline-block", width: "100%" }}>
|
||||
<Link
|
||||
to={userdata?.support ? "/response" : "#"}
|
||||
to={"/admin?tab=datastore"}
|
||||
style={{
|
||||
...hrefStyle,
|
||||
pointerEvents: userdata?.support ? "auto" : "none",
|
||||
@@ -1230,7 +1328,6 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
},
|
||||
cursor: userdata?.support ? "pointer" : "not-allowed",
|
||||
}}
|
||||
disabled={!userdata?.support}
|
||||
>
|
||||
<span style={{ position: "relative", left: !expandLeftNav ? 10 : 0, marginRight: 10, fontSize: 16 }}>
|
||||
•
|
||||
@@ -1248,26 +1345,81 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
: "#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>
|
||||
</Button>
|
||||
</Link>
|
||||
</span>
|
||||
</Box>
|
||||
</Collapse>
|
||||
|
||||
|
||||
<Link to="/docs" style={hrefStyle}>
|
||||
<Button
|
||||
onClick={(event) => {
|
||||
setCurrentOpenTab("docs");
|
||||
localStorage.setItem("lastTabOpenByUser", "docs");
|
||||
}}
|
||||
sx={{
|
||||
style={{
|
||||
...ButtonStyle,
|
||||
marginTop: 2,
|
||||
marginTop: 8,
|
||||
marginTop: 8,
|
||||
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
|
||||
@@ -1390,10 +1542,15 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
|
||||
color: "#bbb",
|
||||
fontSize: "16px",
|
||||
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}
|
||||
</span>) : null
|
||||
</span>
|
||||
) : null
|
||||
}
|
||||
<img
|
||||
src={option.image ? option.image : "/images/no_image.png"}
|
||||
|
||||
@@ -127,7 +127,7 @@ const MFASetup = ({ isLoaded, globalUrl, setCookie }) => {
|
||||
};
|
||||
|
||||
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" }}>
|
||||
<Typography variant="h5" style={{ color: "white", marginBottom: 10, textAlign: "center" }}>
|
||||
Multi-Factor Authentication Setup
|
||||
|
||||
@@ -110,8 +110,30 @@ const OrgHeader = (props) => {
|
||||
orgDescription,
|
||||
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,
|
||||
},
|
||||
[],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ const OrgHeaderexpanded = (props) => {
|
||||
defaults,
|
||||
sso_config
|
||||
) => {
|
||||
|
||||
console.log("defatult in handleEditOrg", defaults)
|
||||
const data = {
|
||||
name: name,
|
||||
description: description,
|
||||
@@ -309,6 +309,7 @@ const OrgHeaderexpanded = (props) => {
|
||||
openid_authorization: openidAuthorization,
|
||||
openid_token: openidToken,
|
||||
SSORequired: SSORequired,
|
||||
auto_provision: selectedOrganization?.sso_config?.auto_provision,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -485,6 +486,7 @@ const OrgHeaderexpanded = (props) => {
|
||||
value={data}
|
||||
onClick={(e) => {
|
||||
var parsedinput = { target: { value: data } }
|
||||
console.log("Parsed input: ", parsedinput)
|
||||
handleWorkflowSelectionUpdate(parsedinput)
|
||||
}}
|
||||
>
|
||||
@@ -753,7 +755,7 @@ const OrgHeaderexpanded = (props) => {
|
||||
{SSORequired ? "Required" : "Optional"}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
{/* <div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
@@ -800,7 +802,7 @@ const OrgHeaderexpanded = (props) => {
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div> */}
|
||||
<div></div>
|
||||
<Grid item xs={12} style={{}}>
|
||||
<Typography variant="h6" style={{ textAlign: "center" }}>
|
||||
|
||||
@@ -53,6 +53,7 @@ import {
|
||||
|
||||
import {
|
||||
HelpOutline as HelpOutlineIcon,
|
||||
OpenInFull as OpenInFullIcon,
|
||||
Description as DescriptionIcon,
|
||||
GetApp as GetAppIcon,
|
||||
Search as SearchIcon,
|
||||
@@ -2090,7 +2091,7 @@ const ParsedAction = (props) => {
|
||||
{data?.validation?.valid === true ?
|
||||
<Tooltip title="Authentication has been validated" placement="top">
|
||||
<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"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
@@ -2099,7 +2100,7 @@ const ParsedAction = (props) => {
|
||||
: null }
|
||||
{data?.last_modified === true ?
|
||||
<Chip
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer", maxHeight: 25, }}
|
||||
label={"Latest"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
@@ -3452,36 +3453,10 @@ const ParsedAction = (props) => {
|
||||
disableUnderline: true,
|
||||
endAdornment: hideExtraTypes ? null : (
|
||||
<InputAdornment position="end">
|
||||
<ButtonGroup 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>
|
||||
<ButtonGroup color="secondary" orientation={multiline ? "vertical" : "horizontal"}>
|
||||
<Tooltip title="Autocomplete text" placement="bottom">
|
||||
<AddCircleOutlineIcon
|
||||
style={{ cursor: "pointer", margin: multiline ? 5 : 0, }}
|
||||
style={{ color: "rgba(255,255,255,0.7)", cursor: "pointer", margin: multiline ? 5 : 0, }}
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
|
||||
@@ -4355,6 +4330,34 @@ const ParsedAction = (props) => {
|
||||
{tmpitem} <span style={{color: theme.palette.main}}>{selectedActionParameters[count].required || selectedActionParameters[count].configuration ? "*" : ""}</span>
|
||||
</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>
|
||||
{datafield}
|
||||
{/*shufflecode*/}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useContext, memo } from "react";
|
||||
|
||||
import { toast } from "react-toastify";
|
||||
import theme from "../theme.jsx";
|
||||
@@ -13,18 +13,21 @@ import {
|
||||
Card,
|
||||
Chip,
|
||||
Switch,
|
||||
Skeleton,
|
||||
} from "@mui/material";
|
||||
import { Context } from "../context/ContextApi.jsx";
|
||||
|
||||
import { useNavigate, Link } from "react-router-dom";
|
||||
import Priority from "../components/Priority.jsx";
|
||||
import { constrainMatrix } from "reaviz";
|
||||
//import { useAlert
|
||||
|
||||
const Priorities = (props) => {
|
||||
const Priorities = memo((props) => {
|
||||
const { globalUrl, userdata,clickedFromOrgTab, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, notifications, setNotifications, } = props;
|
||||
|
||||
const [showDismissed, setShowDismissed] = React.useState(false);
|
||||
const [showRead, setShowRead] = React.useState(false);
|
||||
const [appFramework, setAppFramework] = React.useState({});
|
||||
|
||||
const [selectedWorkflow, setSelectedWorkflow] = React.useState("NO HIGHLIGHT");
|
||||
const [selectedExecutionId, setSelectedExecutionId] = React.useState("NO HIGHLIGHT");
|
||||
const [highlightKMS, setHighlightKMS] = React.useState(false)
|
||||
@@ -216,8 +219,105 @@ const Priorities = (props) => {
|
||||
const notificationWidth = "100%"
|
||||
const imagesize = 22
|
||||
const boxColor = "#86c142"
|
||||
const NotificationItem = (props) => {
|
||||
const {data} = props
|
||||
|
||||
return (
|
||||
<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, }}>
|
||||
<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
|
||||
})</Typography>
|
||||
|
||||
<span style={{ fontSize: 16, marginLeft: clickedFromOrgTab?null:25, color: clickedFromOrgTab?"#9E9E9E":null, }}>
|
||||
Notifications help you find potential problems with your workflows and apps.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#notifications"
|
||||
style={{ textDecoration: clickedFromOrgTab?null:"none", color: clickedFromOrgTab?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</span>
|
||||
<div/>
|
||||
<div style={{display: "flex", marginTop: 10, marginBottom: 10, }}>
|
||||
<Switch
|
||||
checked={showRead}
|
||||
onChange={() => {
|
||||
setShowRead(!showRead);
|
||||
}}
|
||||
/><span style={{marginTop: 5, }}> Show read </span>
|
||||
{notifications !== undefined && notifications !== null && notifications.length > 1 ? (
|
||||
<Button
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
disabled={notifications.filter((data) => !data.read).length === 0}
|
||||
onClick={() => {
|
||||
clearNotifications()
|
||||
}}
|
||||
style={{marginLeft: 50, }}
|
||||
>
|
||||
Mark all as read
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
<NotificationComponent notifications={notifications} showRead={showRead} selectedExecutionId={selectedExecutionId} selectedWorkflow={selectedWorkflow} highlightKMS={highlightKMS} userdata={userdata} imagesize={imagesize} boxColor={boxColor} clickedFromOrgTab={clickedFromOrgTab} notificationWidth={notificationWidth} dismissNotification={dismissNotification}/>
|
||||
|
||||
{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>
|
||||
<span style={{ fontSize: 16, color: clickedFromOrgTab ?"#9E9E9E":null,marginLeft: clickedFromOrgTab ?null:25 }}>
|
||||
Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. <br/>These range from simple configurations in Shuffle to Usecases you may have missed.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#priorities"
|
||||
style={{ textDecoration: clickedFromOrgTab ?null:"none", color: clickedFromOrgTab ?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</span>
|
||||
<div style={{marginTop: 10, }}/>
|
||||
<Switch
|
||||
checked={showDismissed}
|
||||
onChange={() => {
|
||||
setShowDismissed(!showDismissed);
|
||||
}}
|
||||
/> Show dismissed
|
||||
{userdata.priorities === null || userdata.priorities === undefined || userdata.priorities.length === 0 ?
|
||||
<Typography variant="h4">
|
||||
No Suggestions found
|
||||
</Typography>
|
||||
:
|
||||
userdata.priorities.map((priority, index) => {
|
||||
if (showDismissed === false && priority.active === false) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Priority
|
||||
key={index}
|
||||
globalUrl={globalUrl}
|
||||
priority={priority}
|
||||
checkLogin={checkLogin}
|
||||
clickedFromOrgTab={true}
|
||||
setAdminTab={setAdminTab}
|
||||
setCurTab={setCurTab}
|
||||
appFramework={appFramework}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default Priorities;
|
||||
|
||||
|
||||
const NotificationItem = memo((props) => {
|
||||
const {data, selectedExecutionId, selectedWorkflow, highlightKMS, userdata, imagesize, boxColor, clickedFromOrgTab, notificationWidth, dismissNotification} = props
|
||||
|
||||
var image = "";
|
||||
var orgName = "";
|
||||
@@ -280,7 +380,7 @@ const Priorities = (props) => {
|
||||
return (
|
||||
<Paper
|
||||
style={{
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
backgroundColor: theme.palette.inputColor.backgroundColor,
|
||||
width: clickedFromOrgTab ? null :notificationWidth,
|
||||
padding: 30,
|
||||
borderBottom: "1px solid rgba(255,255,255,0.4)",
|
||||
@@ -321,7 +421,7 @@ const Priorities = (props) => {
|
||||
style={{marginRight: 15, height: 25, }}
|
||||
/>
|
||||
}
|
||||
<Typography variant="body1" color="textPrimary">
|
||||
<Typography variant="body1" color="textPrimary" style={{ wordWrap: "break-word", overflow: "hidden", textOverflow: "ellipsis" }}>
|
||||
{data.title}
|
||||
</Typography >
|
||||
</div>
|
||||
@@ -331,7 +431,7 @@ const Priorities = (props) => {
|
||||
:
|
||||
null
|
||||
}
|
||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", wordWrap: "break-word" }}>
|
||||
{data.description}
|
||||
</Typography >
|
||||
<div style={{ display: "flex" }}>
|
||||
@@ -377,121 +477,62 @@ const Priorities = (props) => {
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
|
||||
<Typography variant="body2" color="textSecondary" style={{marginLeft: 20, marginTop: 20, }}>
|
||||
<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, }}>
|
||||
|
||||
<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, }}>
|
||||
|
||||
<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 style={{width: clickedFromOrgTab ? 1030:1000, padding: clickedFromOrgTab ? 27:null, height: clickedFromOrgTab ? "auto":null, 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 ({
|
||||
notifications?.filter((notification) => showRead === true || notification.read === false).length
|
||||
})</h2>
|
||||
|
||||
<span style={{ marginLeft: clickedFromOrgTab?null:25, color: clickedFromOrgTab?"#9E9E9E":null, }}>
|
||||
Notifications help you find potential problems with your workflows and apps.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#notifications"
|
||||
style={{ textDecoration: clickedFromOrgTab?null:"none", color: clickedFromOrgTab?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</span>
|
||||
<div/>
|
||||
<div style={{display: "flex", marginTop: 10, marginBottom: 10, }}>
|
||||
<Switch
|
||||
checked={showRead}
|
||||
onChange={() => {
|
||||
setShowRead(!showRead);
|
||||
}}
|
||||
/><span style={{marginTop: 5, }}> Show read </span>
|
||||
{notifications !== undefined && notifications !== null && notifications.length > 1 ? (
|
||||
<Button
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
disabled={notifications.filter((data) => !data.read).length === 0}
|
||||
onClick={() => {
|
||||
clearNotifications()
|
||||
}}
|
||||
style={{marginLeft: 50, }}
|
||||
>
|
||||
Mark all as read
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
{notifications === null || notifications === undefined || notifications.length === 0 ? null :
|
||||
<div>
|
||||
{notifications.map((notification, index) => {
|
||||
{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} />
|
||||
<NotificationItem data={notification} key={index} selectedExecutionId={selectedExecutionId} selectedWorkflow={selectedWorkflow} highlightKMS={highlightKMS} userdata={userdata} imagesize={imagesize} boxColor={boxColor} clickedFromOrgTab={clickedFromOrgTab} notificationWidth={notificationWidth} dismissNotification={dismissNotification} />
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
|
||||
{clickedFromOrgTab? null : <Divider style={{marginTop: 50, marginBottom: 50, }} />}
|
||||
|
||||
<h2 style={{ display: clickedFromOrgTab ? null:"inline", marginBottom: clickedFromOrgTab ? 8:null, marginTop: clickedFromOrgTab ?0:null, color: clickedFromOrgTab ? "#ffffff" : null }}>Suggestions</h2>
|
||||
<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.
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="/docs/organizations#priorities"
|
||||
style={{ textDecoration: clickedFromOrgTab ?null:"none", color: clickedFromOrgTab ?"#FF8444":"#f85a3e" }}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</span>
|
||||
<div style={{marginTop: 10, }}/>
|
||||
<Switch
|
||||
checked={showDismissed}
|
||||
onChange={() => {
|
||||
setShowDismissed(!showDismissed);
|
||||
}}
|
||||
/> Show dismissed
|
||||
{userdata.priorities === null || userdata.priorities === undefined || userdata.priorities.length === 0 ?
|
||||
<Typography variant="h4">
|
||||
No Suggestions found
|
||||
</Typography>
|
||||
:
|
||||
userdata.priorities.map((priority, index) => {
|
||||
if (showDismissed === false && priority.active === false) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Priority
|
||||
key={index}
|
||||
globalUrl={globalUrl}
|
||||
priority={priority}
|
||||
checkLogin={checkLogin}
|
||||
clickedFromOrgTab={true}
|
||||
setAdminTab={setAdminTab}
|
||||
setCurTab={setCurTab}
|
||||
appFramework={appFramework}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default Priorities;
|
||||
// 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,
|
||||
border: theme.palette.defaultBorder,
|
||||
padding: isMobile ? "25px 10px 25px 10px" : 25,
|
||||
zoom: 0.8,
|
||||
backgroundColor: "black",
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -382,7 +382,7 @@ const data = [
|
||||
css: {
|
||||
"background-color": "#f85a3e",
|
||||
"border-color": "#f85a3e",
|
||||
"border-width": "12px",
|
||||
"border-width": "7px",
|
||||
"transition-property": "border-width",
|
||||
"transition-duration": "0.25s",
|
||||
label: "data(label)",
|
||||
|
||||
@@ -50,6 +50,12 @@ const theme = createTheme(adaptV4Theme({
|
||||
borderRadius: 5,
|
||||
height: 40,
|
||||
},
|
||||
DialogStyle: {
|
||||
backgroundColor: "#212121",
|
||||
borderRadius: 2,
|
||||
boxShadow: "0px 0px 10px 0px rgba(0,0,0,0.75)",
|
||||
border: "1px solid #494949",
|
||||
},
|
||||
innerTextfieldStyle: {
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
|
||||
+109
-14
@@ -4,13 +4,13 @@ import { toast } from "react-toastify";
|
||||
|
||||
const Admin2 = (props) => {
|
||||
// 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 [selectedStatus, setSelectedStatus] = React.useState([]);
|
||||
const [selectedOrganization, setSelectedOrganization] = useState({});
|
||||
const [organizationFeatures, setOrganizationFeatures] = useState({});
|
||||
const [orgRequest, setOrgRequest] = React.useState(true);
|
||||
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
const handleGetOrg = (orgId) => {
|
||||
if (
|
||||
serverside !== true &&
|
||||
@@ -51,8 +51,11 @@ const Admin2 = (props) => {
|
||||
.then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
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 {
|
||||
if (
|
||||
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 = (
|
||||
name,
|
||||
description,
|
||||
@@ -159,6 +233,7 @@ const Admin2 = (props) => {
|
||||
defaults,
|
||||
sso_config,
|
||||
lead_info,
|
||||
{ mfa_required } = {}
|
||||
) => {
|
||||
const data = {
|
||||
name: name,
|
||||
@@ -168,6 +243,7 @@ const Admin2 = (props) => {
|
||||
defaults: defaults,
|
||||
sso_config: sso_config,
|
||||
lead_info: lead_info,
|
||||
mfa_required: mfa_required !== undefined ? mfa_required : selectedOrganization?.mfa_required,
|
||||
};
|
||||
|
||||
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
|
||||
@@ -202,21 +278,40 @@ const Admin2 = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// handleGetOrg();
|
||||
// }, []);
|
||||
|
||||
const handleStatusChange = (event) => {
|
||||
const { value } = event.target;
|
||||
setSelectedStatus(value);
|
||||
|
||||
handleEditOrg(
|
||||
"",
|
||||
"",
|
||||
selectedOrganization?.name,
|
||||
selectedOrganization?.description,
|
||||
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,
|
||||
);
|
||||
};
|
||||
@@ -228,14 +323,14 @@ const Admin2 = (props) => {
|
||||
orgRequest
|
||||
) {
|
||||
const orgId = userdata.active_org.id
|
||||
console.log("orgID", orgId)
|
||||
|
||||
setOrgRequest(false);
|
||||
handleGetOrg(orgId);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 30 }}>
|
||||
<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} />
|
||||
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 29, zoom: 0.8, }}>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -422,7 +422,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [subworkflow, setSubworkflow] = React.useState({});
|
||||
const [subworkflowStartnode, setSubworkflowStartnode] = React.useState("");
|
||||
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 [usecases, setUsecases] = 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", "edge", (e) => onEdgeAdded(e));
|
||||
} else {
|
||||
@@ -4052,7 +4052,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
.then(() => {
|
||||
console.log("DONE: ", workflow_id);
|
||||
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 (!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
|
||||
var executions = 0
|
||||
const matchingExecutions = workflowExecutions.filter((execution => execution.execution_source === nodedata.app_name.toLowerCase()))
|
||||
@@ -6121,7 +6121,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
event.target.remove()
|
||||
|
||||
//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
|
||||
|
||||
|
||||
@@ -7782,7 +7782,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
const item = typeIds[idkey]
|
||||
if (item.data.id === nodedata.id) {
|
||||
//console.log("items: ", item.data.id, nodedata.id)
|
||||
parsedStyle["border-width"] = "12px"
|
||||
parsedStyle["border-width"] = "7px"
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -8391,7 +8391,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
// Reset view for cytoscape
|
||||
if (cy !== undefined && cy !== null) {
|
||||
cy.add(insertedNodes);
|
||||
cy.fit(null, 200);
|
||||
cy.fit(null, 400);
|
||||
} else {
|
||||
setElements(insertedNodes);
|
||||
}
|
||||
@@ -8772,7 +8772,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}
|
||||
// preview: true,
|
||||
|
||||
cy.fit(null, 200);
|
||||
cy.fit(null, 400)
|
||||
|
||||
cy.on("boxselect", "node", (e) => {
|
||||
if (e.target.data("isButton") || e.target.data("isDescriptor") || e.target.data("isSuggestion")) {
|
||||
@@ -9380,7 +9380,9 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
onChange={handleSetTab}
|
||||
aria-label="Left sidebar tab"
|
||||
orientation={isMobile ? "vertical" : "horizontal"}
|
||||
style={{}}
|
||||
style={{
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<Tab
|
||||
value={0}
|
||||
@@ -9421,7 +9423,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
<Grid item>
|
||||
<FavoriteBorderIcon style={iconStyle} />
|
||||
</Grid>
|
||||
{isMobile ? null : <Grid item>Variables</Grid>}
|
||||
{isMobile ? null : <Grid item>Vars</Grid>}
|
||||
</Grid>
|
||||
}
|
||||
style={tabStyle}
|
||||
@@ -9776,11 +9778,13 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
const barHeight = bodyHeight - appBarSize - 50;
|
||||
const appScrollStyle = {
|
||||
overflow: "scroll",
|
||||
maxHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-300,
|
||||
minHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-300,
|
||||
maxHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-70,
|
||||
minHeight: isMobile ? bodyHeight - appBarSize * 4 : barHeight-70,
|
||||
marginTop: 1,
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
|
||||
zoom: 0.9,
|
||||
}
|
||||
|
||||
const handleAppDrag = (e, app) => {
|
||||
@@ -10568,12 +10572,12 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
var viewedApps = []
|
||||
return (
|
||||
<div style={appViewStyle}>
|
||||
<div style={{ flex: "1" }}>
|
||||
<div style={{ flex: "1", zoom: 0.9, }}>
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
marginTop: 5,
|
||||
marginTop: 10,
|
||||
marginRight: 10,
|
||||
height: 40,
|
||||
}}
|
||||
@@ -11199,8 +11203,6 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
top: appBarSize - 35,
|
||||
right: 25,
|
||||
height: "90vh",
|
||||
width: isMobile ? "100%" : minSize,
|
||||
minWidth: minSize,
|
||||
maxWidth: 600,
|
||||
maxHeight: "100vh",
|
||||
border: "1px solid rgb(91, 96, 100)",
|
||||
@@ -11210,6 +11212,9 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
overflow: "auto",
|
||||
|
||||
overflowAnchor: "none",
|
||||
minWidth: minSize,
|
||||
width: isMobile ? "100%" : minSize,
|
||||
zoom: 0.9,
|
||||
};
|
||||
|
||||
const setTriggerFolderWrapperMulti = (event) => {
|
||||
@@ -16153,13 +16158,15 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
position: "absolute",
|
||||
|
||||
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",
|
||||
maxWidth: 500,
|
||||
zoom: 0.9,
|
||||
}
|
||||
|
||||
const TopCytoscapeBar = (props) => {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
|
||||
if (workflow.public === true) {
|
||||
return null
|
||||
}
|
||||
@@ -16174,12 +16181,30 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
<div style={topBarStyle}>
|
||||
<div style={{
|
||||
margin: "0px 10px 0px 35px",
|
||||
maxWidth: 500,
|
||||
}}>
|
||||
<Typography variant="h6" style={{
|
||||
margin: 0,
|
||||
}}>
|
||||
{workflow.name}
|
||||
cursor: "pointer",
|
||||
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>
|
||||
{workflowAsCode && (
|
||||
<Tooltip title="Switch to Code View">
|
||||
@@ -16204,7 +16229,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
|
||||
{!distributedFromParent ?
|
||||
isCorrectOrg ? null :
|
||||
<Typography variant="body1">
|
||||
<Typography variant="body2">
|
||||
<b>Warning</b>: Change <span
|
||||
style={{color: "#FF8544", cursor: "pointer", pointerEvents: "auto", }}
|
||||
onClick={() => {
|
||||
@@ -16275,7 +16300,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
>Active Organization</span> to edit this Workflow.
|
||||
</Typography>
|
||||
:
|
||||
<Typography variant="body1">
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
Warning: This workflow is controlled by your parent org and may not be editable.
|
||||
</Typography>
|
||||
}
|
||||
@@ -16285,7 +16310,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
|
||||
<InputLabel
|
||||
id="suborg-changer"
|
||||
style={{ color: "white" }}
|
||||
style={{ color: "rgba(255,255,255,0.7)", }}
|
||||
>
|
||||
Select an Org
|
||||
</InputLabel>
|
||||
@@ -16294,10 +16319,15 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
pointerEvents: "auto",
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
height: 50,
|
||||
maxWidth: 250,
|
||||
minWidth: 250,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
height: 40,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
height: 40,
|
||||
}
|
||||
}}
|
||||
labelId="suborg-changer"
|
||||
value={workflow.org_id}
|
||||
@@ -16470,47 +16500,16 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</Select>
|
||||
</FormControl>
|
||||
}
|
||||
|
||||
</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 ?
|
||||
<FormControl fullWidth style={{marginTop: 15, marginleft: 10, pointerEvents: "auto", maxWidth: 250, }}>
|
||||
<FormControl fullWidth style={{marginTop: 15, pointerEvents: "auto", maxWidth: 250, }}>
|
||||
|
||||
<InputLabel
|
||||
id="execution_location"
|
||||
style={{ color: "white" }}
|
||||
style={{ color: "rgba(255,255,255,0.7)", marginLeft: 40, }}
|
||||
>
|
||||
Execution Location
|
||||
Location
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="execution_location"
|
||||
@@ -16523,6 +16522,11 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
style: {
|
||||
},
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
height: 40,
|
||||
}
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setLastSaved(false)
|
||||
const env = environments.find((a) => a.Name === e.target.value);
|
||||
@@ -16539,13 +16543,14 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}}
|
||||
style={{
|
||||
pointerEvents: "auto",
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
height: 50,
|
||||
maxWidth: 250,
|
||||
minWidth: 250,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
marginLeft: 10,
|
||||
marginLeft: 35,
|
||||
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
height: 40,
|
||||
}}
|
||||
>
|
||||
{environments.map((data, index) => {
|
||||
@@ -16603,6 +16608,43 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</FormControl>
|
||||
: 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>
|
||||
);
|
||||
};
|
||||
@@ -17210,7 +17252,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
<Tooltip color="primary" title="Stop execution" placement="top">
|
||||
<span>
|
||||
<Button
|
||||
style={{ height: boxSize, width: boxSize }}
|
||||
style={{ height: boxSize, width: boxSize+5 }}
|
||||
color="secondary"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
@@ -17228,7 +17270,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
workflow.public
|
||||
|| executionRequestStarted
|
||||
}
|
||||
style={{ height: boxSize, width: boxSize, backgroundColor: green, }}
|
||||
style={{ height: boxSize, width: boxSize+5, backgroundColor: green, }}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
@@ -17265,7 +17307,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
{executionButton}
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
title={`Show previous runs (${workflowExecutions.length}) (Ctrl + ')`}
|
||||
title={`Show previous workflow runs (${workflowExecutions.length}) (Ctrl + ')`}
|
||||
placement="top-start"
|
||||
>
|
||||
<Button
|
||||
@@ -17492,6 +17534,8 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
workflow.configuration.exit_on_error !== undefined ? (
|
||||
<WorkflowMenu />
|
||||
) : null}
|
||||
|
||||
{/*
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
title="Edit workflow details"
|
||||
@@ -17514,6 +17558,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
*/}
|
||||
|
||||
<Tooltip
|
||||
color="secondary"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import React, { memo, useCallback } from "react";
|
||||
import { useState, useEffect, useContext, Suspense } from "react";
|
||||
import { useNavigate, Link, useLocation } from "react-router-dom";
|
||||
@@ -57,7 +58,7 @@ const ApiExplorer = React.lazy(() => import("../components/ApiExplorer.jsx"));
|
||||
|
||||
|
||||
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 location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
@@ -1754,7 +1755,7 @@ const ApiExplorerWrapper = (props) => {
|
||||
)});
|
||||
|
||||
return (
|
||||
<Wrapper userdata={userdata}>
|
||||
<Wrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
|
||||
<Suspense fallback={skeletonLoader}>
|
||||
{authenticationModal}
|
||||
<ApiExplorer
|
||||
@@ -1765,6 +1766,8 @@ const ApiExplorerWrapper = (props) => {
|
||||
HandleApiExecution={HandleApiExecution}
|
||||
selectedAppData={selectedAppData}
|
||||
ConfigurationTab={ConfigurationTab}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isLoaded={isLoaded}
|
||||
/>
|
||||
</Suspense>
|
||||
</Wrapper>
|
||||
@@ -1774,13 +1777,13 @@ const ApiExplorerWrapper = (props) => {
|
||||
export default ApiExplorerWrapper;
|
||||
|
||||
|
||||
const Wrapper = ({children, userdata})=>{
|
||||
const Wrapper = ({children, isLoaded,isLoggedIn})=>{
|
||||
|
||||
const { leftSideBarOpenByClick } = useContext(Context);
|
||||
|
||||
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}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -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 marginLeft = userdata?.support
|
||||
? leftSideBarOpenByClick ? 250 : 80
|
||||
: 0;
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ marginLeft, transition: 'margin-left 0.3s ease' }}>
|
||||
<div style={{ marginLeft: leftSideBarOpenByClick ? 250 : 80, transition: 'margin-left 0.3s ease' }}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
+287
-121
@@ -36,6 +36,7 @@ import algoliasearch from "algoliasearch/lite";
|
||||
import { debounce } from "lodash";
|
||||
import AppSelection from "../components/AppSelection.jsx";
|
||||
import AppModal from "../components/AppModal.jsx";
|
||||
import AppCreationModal from "../components/AppCreationModal.jsx";
|
||||
|
||||
|
||||
const searchClient = algoliasearch(
|
||||
@@ -45,6 +46,7 @@ const searchClient = algoliasearch(
|
||||
|
||||
// AppCard Component
|
||||
const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata }) => {
|
||||
const navigate = useNavigate();
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000";
|
||||
const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`;
|
||||
var canEditApp = userdata.admin === "true" || userdata.id === data?.owner || data?.owner === "" || (userdata.admin === "true" && userdata.active_org.id === data?.reference_org) || !data?.generated
|
||||
@@ -53,7 +55,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#212121",
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
cursor: "pointer",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
// position: "relative",
|
||||
width: "100%",
|
||||
height: 96,
|
||||
@@ -76,7 +78,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
fontSize: 16,
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
width: '100%',
|
||||
backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "#212121"
|
||||
}}
|
||||
@@ -105,7 +107,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
fontWeight: '400',
|
||||
overflow: "hidden",
|
||||
margin: "12px 0",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
@@ -138,8 +140,14 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
display: "flex",
|
||||
justifyContent: 'space-between',
|
||||
paddingRight: 15,
|
||||
height: 35,
|
||||
}}>
|
||||
<div style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
color: "rgba(158, 158, 158, 1)",
|
||||
}}>
|
||||
<div style={{ overflow: "hidden", textAlign: 'start' }}>
|
||||
{data.generated !== true && data.tags && data.tags.slice(0, 2).map((tag, tagIndex) => (
|
||||
<span key={tagIndex}>
|
||||
{tag}
|
||||
@@ -151,31 +159,46 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
{currTab === 0 && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && (
|
||||
<div style={{
|
||||
display: "flex",
|
||||
gap: 8
|
||||
gap: 8,
|
||||
alignItems: 'center',
|
||||
paddingRight: 20
|
||||
}}>
|
||||
{
|
||||
canEditApp && (
|
||||
<button style={{ backgroundColor: "rgba(73, 73, 73, 1)", border: "none", cursor: "pointer", color: "white", borderRadius: 3, display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||
<button style={{ backgroundColor: "rgba(73, 73, 73, 1)", border: "none", cursor: "pointer", color: "white", borderRadius: 3, display: "flex", alignItems: "center", justifyContent: "center", height: 35 }}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (canEditApp) {
|
||||
const editUrl = "/apps/edit/" + data?.id;
|
||||
navigate(editUrl)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
<Button
|
||||
className="deactivate-button"
|
||||
style={{
|
||||
// marginLeft: 15,
|
||||
sx={{
|
||||
width: 102,
|
||||
height: 35,
|
||||
borderRadius: 3,
|
||||
backgroundColor: "rgba(73, 73, 73, 1)",
|
||||
borderRadius: 0.75,
|
||||
bgcolor: "rgba(73, 73, 73, 1)",
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
textTransform: "none",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
transition: "background-color 0.3s ease",
|
||||
"&:hover": {
|
||||
bgcolor: "rgba(93, 93, 93, 1)",
|
||||
},
|
||||
}}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const url = `${globalUrl}/api/v1/apps/${data.id}/deactivate`;
|
||||
|
||||
toast("Deactivating app. Please wait...");
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@@ -189,7 +212,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
if (responseJson.success === false) {
|
||||
toast.error(responseJson.reason);
|
||||
} else {
|
||||
toast.success("App Deactivated Successfully. Reload UI to see updated changes.");
|
||||
toast.success("App Deactivated Successfully.");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -218,14 +241,35 @@ const Hits = ({
|
||||
setIsAnyAppActivated,
|
||||
searchQuery,
|
||||
globalUrl,
|
||||
isLoading,
|
||||
isLoggedIn,
|
||||
currTab,
|
||||
leftSideBarOpenByClick
|
||||
}) => {
|
||||
const [hoverEffect, setHoverEffect] = useState(-1);
|
||||
const [allActivatedAppIds, setAllActivatedAppIds] = useState(userdata?.active_apps);
|
||||
const [allActivatedAppIds, setAllActivatedAppIds] = useState([]);
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
const [deactivatedIndexes, setDeactivatedIndexes] = React.useState([]);
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
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) {
|
||||
setAllActivatedAppIds(responseJson.active_apps)
|
||||
}
|
||||
setIsLoading(false)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log("Failed login check: ", error);
|
||||
});
|
||||
}, [currTab]);
|
||||
|
||||
const normalizedString = (name) => {
|
||||
if (typeof name === 'string') {
|
||||
@@ -235,12 +279,20 @@ const Hits = ({
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (userdata && userdata.active_apps) {
|
||||
setAllActivatedAppIds(userdata.active_apps);
|
||||
}
|
||||
}, [currTab, window.location]);
|
||||
|
||||
|
||||
//Function for activation and deactivation of app
|
||||
const handleActivateButton = (event, data, type) => {
|
||||
|
||||
//use prevent default so it will stop redirection to the app page
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
toast.error("Please log in to your account to activate the app.")
|
||||
return;
|
||||
@@ -287,25 +339,15 @@ const Hits = ({
|
||||
let workflowDelay = 0;
|
||||
const isHeader = true;
|
||||
|
||||
const [showNoAppFound, setShowNoAppFound] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setShowNoAppFound(true);
|
||||
}, 1000);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!isLoading ? (
|
||||
{!isLoading ?
|
||||
(
|
||||
<div>
|
||||
{hits?.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
||||
<div style={{ marginTop: 100, fontSize: 20, fontWeight: 500, width: "100%", textAlign: "center" }}>
|
||||
<Typography variant="body1">No Apps Found</Typography>
|
||||
</div>
|
||||
{hits?.length === 0 && searchQuery.length >= 0 ? (
|
||||
<Typography>No apps found</Typography>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
@@ -314,9 +356,11 @@ const Hits = ({
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(365px, 1fr))",
|
||||
gap: "20px",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
padding: "0 10px"
|
||||
padding: "0 10px",
|
||||
paddingBottom: 40
|
||||
}}
|
||||
>
|
||||
{hits?.map((data, index) => {
|
||||
@@ -339,7 +383,7 @@ const Hits = ({
|
||||
backgroundColor: hoverEffect === index ? "rgba(26, 26, 26, 1)" : "#212121",
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
cursor: "pointer",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
// position: "relative",
|
||||
width: "100%",
|
||||
height: 96,
|
||||
@@ -360,11 +404,12 @@ const Hits = ({
|
||||
fontSize: 16,
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
fontFamily: "Inter",
|
||||
width: '100%',
|
||||
backgroundColor: hoverEffect === index ? "#2F2F2F" : "#212121"
|
||||
backgroundColor: hoverEffect === index ? "#2F2F2F" : "#212121",
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
onClick={() => {
|
||||
console.log("App modal", data)
|
||||
handleAppClick(data);
|
||||
}}
|
||||
>
|
||||
@@ -390,7 +435,7 @@ const Hits = ({
|
||||
fontWeight: '400',
|
||||
overflow: "hidden",
|
||||
margin: "12px 0",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -426,12 +471,16 @@ const Hits = ({
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: 'space-between',
|
||||
width: 230,
|
||||
width: "100%",
|
||||
textAlign: 'start',
|
||||
color: "rgba(158, 158, 158, 1)",
|
||||
height: 35,
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<div style={{ marginBottom: 15, }}>
|
||||
<div style={{
|
||||
flex: 1
|
||||
}}>
|
||||
{hoverEffect === index && isCloud ? (
|
||||
<div>
|
||||
{data.tags && (
|
||||
@@ -463,7 +512,12 @@ const Hits = ({
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ width: 230, textOverflow: "ellipsis", overflow: 'hidden', whiteSpace: 'nowrap', }}>
|
||||
<div style={{
|
||||
width: 230,
|
||||
textOverflow: "ellipsis",
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
}}>
|
||||
{data.tags &&
|
||||
data.tags.map((tag, tagIndex) => (
|
||||
<span key={tagIndex}>
|
||||
@@ -474,17 +528,25 @@ const Hits = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ position: 'relative', bottom: 5 }}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
paddingRight: 10,
|
||||
minWidth: 110
|
||||
}}>
|
||||
{hoverEffect === index && isCloud && (
|
||||
<div>
|
||||
{allActivatedAppIds && allActivatedAppIds.includes(data.objectID) ? (
|
||||
<Button style={{
|
||||
<Button
|
||||
style={{
|
||||
width: 102,
|
||||
height: 35,
|
||||
borderRadius: 200,
|
||||
borderRadius: 3,
|
||||
backgroundColor: "rgba(73, 73, 73, 1)",
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
textTransform: "none",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}
|
||||
onClick={(event) => {
|
||||
handleActivateButton(event, data, "deactivate");
|
||||
@@ -494,12 +556,13 @@ const Hits = ({
|
||||
) : (
|
||||
<Button
|
||||
style={{
|
||||
backgroundColor: "#FF8544",
|
||||
color: "black",
|
||||
width: 102,
|
||||
height: 35,
|
||||
borderRadius: 200,
|
||||
backgroundColor: "rgba(242, 101, 59, 1)",
|
||||
color: "rgba(255, 255, 255, 1)",
|
||||
borderRadius: 3,
|
||||
textTransform: "none",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}
|
||||
onClick={(event) => {
|
||||
handleActivateButton(event, data, "activate");
|
||||
@@ -535,7 +598,7 @@ const Hits = ({
|
||||
const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||
const inputRef = useRef(null);
|
||||
const [localQuery, setLocalQuery] = useState(searchQuery);
|
||||
|
||||
const location = useLocation();
|
||||
// Initialize search when component mounts or when switching to Discover tab
|
||||
useEffect(() => {
|
||||
if (searchQuery) {
|
||||
@@ -592,7 +655,7 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||
event.preventDefault();
|
||||
}
|
||||
}}
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }}
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }}
|
||||
InputProps={{
|
||||
style: {
|
||||
borderRadius: 8,
|
||||
@@ -608,6 +671,9 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||
onClick={() => {
|
||||
setLocalQuery('');
|
||||
debouncedRefine('');
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
queryParams.delete('q');
|
||||
window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -637,14 +703,26 @@ const CategoryDropdown = ({ items, currentRefinement, refine }) => {
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
multiple
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }}
|
||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) return 'All Categories';
|
||||
return (
|
||||
<div style={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '90%'
|
||||
}}>
|
||||
{selected.join(', ')}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem disabled value="" style={{ fontFamily: "Inter" }}>
|
||||
<MenuItem disabled value="" style={{ fontFamily: theme?.typography?.fontFamily }}>
|
||||
All Categories
|
||||
</MenuItem>
|
||||
{items.map(item => (
|
||||
<MenuItem key={item.label} value={item.label} style={{ fontFamily: "Inter", fontSize: 16 }}>
|
||||
<MenuItem key={item.label} value={item.label} style={{ fontFamily: theme?.typography?.fontFamily, fontSize: 16 }}>
|
||||
<Checkbox checked={currentRefinement.includes(item.label)} />
|
||||
{item.label} ({item.count})
|
||||
</MenuItem>
|
||||
@@ -686,15 +764,27 @@ const LabelDropdown = ({ items, currentRefinement, refine }) => {
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
multiple
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }}
|
||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: theme?.typography?.fontFamily, flex: 1 }}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) return 'All Labels';
|
||||
return (
|
||||
<div style={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '90%'
|
||||
}}>
|
||||
{selected.join(', ')}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem disabled value="">
|
||||
All Labels
|
||||
</MenuItem>
|
||||
{items.map(item => (
|
||||
<MenuItem key={item.label} value={item.label} style={{
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: 16
|
||||
}}>
|
||||
<Checkbox checked={currentRefinement.includes(item.label)} />
|
||||
@@ -835,7 +925,7 @@ const LoadingGrid = () => {
|
||||
|
||||
// Main Apps Component
|
||||
const Apps2 = (props) => {
|
||||
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn, checkLogin, isCloud } = props;
|
||||
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn, checkLogin } = props;
|
||||
let navigate = useNavigate();
|
||||
const { leftSideBarOpenByClick } = useContext(Context);
|
||||
const location = useLocation();
|
||||
@@ -869,9 +959,16 @@ const Apps2 = (props) => {
|
||||
const [field1, setField1] = useState("");
|
||||
const [field2, setField2] = useState("");
|
||||
const [validation, setValidation] = useState(null);
|
||||
const [createAppModalOpen, setCreateAppModalOpen] = useState(false);
|
||||
|
||||
const baseRepository = "https://github.com/frikky/shuffle-apps";
|
||||
|
||||
const isCloud =
|
||||
window.location.host === "localhost:3002" ||
|
||||
window.location.host === "shuffler.io"
|
||||
? true
|
||||
: false;
|
||||
|
||||
// Set the current tab based on the query parameter
|
||||
useEffect(() => {
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
@@ -931,14 +1028,13 @@ const Apps2 = (props) => {
|
||||
const fetchApps = async () => {
|
||||
const baseUrl = globalUrl;
|
||||
let url;
|
||||
|
||||
setIsLoading(true);
|
||||
const userId = userdata?.id;
|
||||
if (currTab === 1 && userId) {
|
||||
url = `${baseUrl}/api/v1/users/${userId}/apps`;
|
||||
} else if (currTab === 0) {
|
||||
url = `${baseUrl}/api/v1/apps`;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
@@ -1262,7 +1358,7 @@ const Apps2 = (props) => {
|
||||
borderRadius: 2,
|
||||
border: "1px solid #494949",
|
||||
minWidth: '440px',
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
backgroundColor: "#212121",
|
||||
zIndex: 1000,
|
||||
'& .MuiDialogContent-root': {
|
||||
@@ -1272,10 +1368,10 @@ const Apps2 = (props) => {
|
||||
backgroundColor: "#212121",
|
||||
},
|
||||
'& .MuiTypography-root': {
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
},
|
||||
'& .MuiButton-root': {
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
},
|
||||
}
|
||||
}}
|
||||
@@ -1393,7 +1489,8 @@ const Apps2 = (props) => {
|
||||
/>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ p: 3,
|
||||
<DialogActions sx={{
|
||||
p: 3,
|
||||
backgroundColor: "#212121"
|
||||
}}>
|
||||
<Button
|
||||
@@ -1406,7 +1503,7 @@ const Apps2 = (props) => {
|
||||
py: 1,
|
||||
px: 3,
|
||||
color: "#fff",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
onClick={() => setLoadAppsModalOpen(false)}
|
||||
>
|
||||
@@ -1423,7 +1520,7 @@ const Apps2 = (props) => {
|
||||
py: 1,
|
||||
px: 3,
|
||||
color: "#fff",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
disabled={openApi.length === 0 || !openApi.includes("http")}
|
||||
onClick={() => handleGithubValidation(true)}
|
||||
@@ -1441,7 +1538,7 @@ const Apps2 = (props) => {
|
||||
py: 1,
|
||||
px: 3,
|
||||
color: "black",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
disabled={openApi.length === 0 || !openApi.includes("http")}
|
||||
onClick={() => handleGithubValidation(false)}
|
||||
@@ -1510,6 +1607,7 @@ const Apps2 = (props) => {
|
||||
|
||||
const handleCreateApp = (e) => {
|
||||
e.preventDefault();
|
||||
setCreateAppModalOpen(true);
|
||||
// setOpenModal(true);
|
||||
};
|
||||
|
||||
@@ -1553,37 +1651,28 @@ const Apps2 = (props) => {
|
||||
navigate(`${location.pathname}?${queryParams.toString()}`);
|
||||
};
|
||||
|
||||
// Update useEffect to handle initial load and URL search params
|
||||
useEffect(() => {
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
const searchParam = queryParams.get('q');
|
||||
if (searchParam) {
|
||||
setSearchQuery(searchParam);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Update useEffect for filtering to handle both tabs
|
||||
// Update useEffect for filtering without URL manipulation
|
||||
useEffect(() => {
|
||||
if (currTab === 2) return; // Skip for "Discover Apps" tab as it uses Algolia
|
||||
|
||||
const apps = currTab === 1 ? userApps : orgApps;
|
||||
const filteredApps = filterApps(apps, searchQuery, selectedCategory, selectedLabel);
|
||||
setAppsToShow(filteredApps);
|
||||
}, [searchQuery, selectedCategory, selectedLabel, currTab, userApps, orgApps]);
|
||||
|
||||
// Update URL with search query
|
||||
// Add URL update only when search is performed
|
||||
const handleSearchChange = (event) => {
|
||||
const newSearchQuery = event.target.value;
|
||||
setSearchQuery(newSearchQuery);
|
||||
|
||||
// Update URL only when user performs search
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
if (searchQuery) {
|
||||
queryParams.set('q', searchQuery);
|
||||
if (newSearchQuery) {
|
||||
queryParams.set('q', newSearchQuery);
|
||||
} else {
|
||||
queryParams.delete('q');
|
||||
}
|
||||
window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`);
|
||||
}, [searchQuery, selectedCategory, selectedLabel, currTab, userApps, orgApps]);
|
||||
|
||||
// Update search input handler to maintain state across tabs
|
||||
const handleSearchChange = (event) => {
|
||||
const newSearchQuery = event.target.value;
|
||||
setSearchQuery(newSearchQuery);
|
||||
};
|
||||
|
||||
const boxStyle = {
|
||||
@@ -1594,7 +1683,7 @@ const Apps2 = (props) => {
|
||||
width: "100%",
|
||||
margin: "auto",
|
||||
maxWidth: "70%",
|
||||
fontFamily: "Inter",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
// padding: '20px 380px',
|
||||
};
|
||||
|
||||
@@ -1619,7 +1708,7 @@ const Apps2 = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ paddingTop: 70, minHeight: 1000, paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease", backgroundColor: "#1A1A1A" }}>
|
||||
<div style={{ paddingTop: 70, paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease", backgroundColor: "#1A1A1A", fontFamily: theme?.typography?.fontFamily, zoom: 0.8, }}>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
||||
<AppModal
|
||||
open={openModal}
|
||||
@@ -1628,10 +1717,17 @@ const Apps2 = (props) => {
|
||||
userdata={userdata}
|
||||
globalUrl={globalUrl}
|
||||
/>
|
||||
<AppCreationModal
|
||||
open={createAppModalOpen}
|
||||
onClose={() => setCreateAppModalOpen(false)}
|
||||
theme={theme}
|
||||
globalUrl={globalUrl}
|
||||
isCloud={isCloud}
|
||||
/>
|
||||
{appsModalLoad}
|
||||
<div style={boxStyle}>
|
||||
<div style={{ display: "flex", flexDirection: "row", width: "100%", justifyContent: "space-between" }}>
|
||||
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: "Inter" }}>
|
||||
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: theme?.typography?.fontFamily }}>
|
||||
Apps
|
||||
</Typography>
|
||||
{isCloud ? null : (
|
||||
@@ -1648,7 +1744,7 @@ const Apps2 = (props) => {
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
fontSize: 14,
|
||||
border: "1px solid rgba(73, 73, 73, 1)",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -1688,7 +1784,7 @@ const Apps2 = (props) => {
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
fontSize: 14,
|
||||
border: "1px solid rgba(73, 73, 73, 1)",
|
||||
fontFamily: "Inter"
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -1720,22 +1816,25 @@ const Apps2 = (props) => {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ borderBottom: '1px solid gray', marginBottom: 30, marginRight: 10 }}>
|
||||
<div style={{ borderBottom: '1px solid gray', marginBottom: 30 }}>
|
||||
<Tabs
|
||||
value={currTab}
|
||||
onChange={(event, newTab) => handleTabChange(event, newTab)}
|
||||
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10 } }}
|
||||
style={{ fontFamily: "Inter" }}
|
||||
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10, backgroundColor: "#FF8544" } }}
|
||||
style={{ fontFamily: theme?.typography?.fontFamily }}
|
||||
>
|
||||
<Tab label="Organization Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: "Inter" }} />
|
||||
<Tab label="My Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: "Inter" }} />
|
||||
<Tab label="Discover Apps" style={{ textTransform: 'none', fontFamily: "Inter" }} />
|
||||
<Tab label="Organization Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: theme?.typography?.fontFamily }} />
|
||||
<Tab label="My Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: theme?.typography?.fontFamily }} />
|
||||
<Tab label="Discover Apps" style={{ textTransform: 'none', fontFamily: theme?.typography?.fontFamily }} />
|
||||
</Tabs>
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45 }}>
|
||||
<div style={{ flex: 1, width: '100%', borderRadius: '7px' }}>
|
||||
{
|
||||
(currTab === 0 || currTab === 1) &&
|
||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45, paddingRight: 25 }}>
|
||||
<div style={{
|
||||
width: "25%",
|
||||
minWidth: "25%",
|
||||
maxWidth: "25%"
|
||||
}}>
|
||||
{(currTab === 0 || currTab === 1) ? (
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
@@ -1756,13 +1855,14 @@ const Apps2 = (props) => {
|
||||
},
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{searchQuery.length === 0 ? (
|
||||
<Search />
|
||||
) : (
|
||||
{searchQuery.length === 0 ? <Search /> : (
|
||||
<ClearIcon
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
setSearchQuery("");
|
||||
setSearchQuery("")
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
queryParams.delete('q');
|
||||
window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -1770,13 +1870,16 @@ const Apps2 = (props) => {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
{
|
||||
currTab === 2 &&
|
||||
) : (
|
||||
<CustomSearchBox searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div style={{ flex: 1, width: '100%', borderRadius: '7px', position: 'relative' }}>
|
||||
<div style={{
|
||||
width: "25%",
|
||||
minWidth: "25%",
|
||||
maxWidth: "25%",
|
||||
position: 'relative'
|
||||
}}>
|
||||
{currTab === 2 ? (
|
||||
<CustomCategoryDropdown attribute="categories" />
|
||||
) : (
|
||||
@@ -1788,14 +1891,30 @@ const Apps2 = (props) => {
|
||||
onChange={handleCategoryChange}
|
||||
displayEmpty
|
||||
multiple
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: "Inter" }}
|
||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
height: 45,
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) return 'All Categories';
|
||||
return (
|
||||
<div style={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '90%'
|
||||
}}>
|
||||
{selected.join(', ')}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem disabled value="" style={{ fontFamily: "Inter" }}>
|
||||
<MenuItem disabled value="" style={{ fontFamily: theme?.typography?.fontFamily }}>
|
||||
All Categories
|
||||
</MenuItem>
|
||||
{categories?.map((category) => (
|
||||
<MenuItem key={category.category} value={category.category} style={{ fontFamily: "Inter", fontSize: 16 }}>
|
||||
<MenuItem key={category.category} value={category.category} style={{ fontFamily: theme?.typography?.fontFamily, fontSize: 16 }}>
|
||||
<Checkbox checked={selectedCategory.includes(category.category)} />
|
||||
{category.category}
|
||||
</MenuItem>
|
||||
@@ -1819,7 +1938,12 @@ const Apps2 = (props) => {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ flex: 1, width: '100%', borderRadius: '7px', position: 'relative' }}>
|
||||
<div style={{
|
||||
width: "25%",
|
||||
minWidth: "25%",
|
||||
maxWidth: "25%",
|
||||
position: 'relative'
|
||||
}}>
|
||||
{currTab === 2 ? (
|
||||
<CustomLabelDropdown attribute="action_labels" />
|
||||
) : (
|
||||
@@ -1831,14 +1955,30 @@ const Apps2 = (props) => {
|
||||
onChange={handleLabelChange}
|
||||
displayEmpty
|
||||
multiple
|
||||
style={{ borderRadius: 8, height: 45, fontFamily: "Inter" }}
|
||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
height: 45,
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
renderValue={(selected) => {
|
||||
if (selected.length === 0) return 'All Labels';
|
||||
return (
|
||||
<div style={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '90%'
|
||||
}}>
|
||||
{selected.join(', ')}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MenuItem disabled value="" style={{ fontFamily: "Inter" }}>
|
||||
<MenuItem disabled value="" style={{ fontFamily: theme?.typography?.fontFamily }}>
|
||||
All Labels
|
||||
</MenuItem>
|
||||
{labels?.map((tag) => (
|
||||
<MenuItem key={tag.tag} value={tag.tag} style={{ fontFamily: "Inter", fontSize: 16 }}>
|
||||
<MenuItem key={tag.tag} value={tag.tag} style={{ fontFamily: theme?.typography?.fontFamily, fontSize: 16 }}>
|
||||
<Checkbox checked={selectedLabel.includes(tag.tag)} />
|
||||
{tag.tag}
|
||||
</MenuItem>
|
||||
@@ -1862,14 +2002,28 @@ const Apps2 = (props) => {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{
|
||||
width: "25%",
|
||||
minWidth: "25%",
|
||||
maxWidth: "25%"
|
||||
}}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleCreateApp}
|
||||
style={{ height: "100%", width: '100%', borderRadius: '7px', textTransform: 'none', backgroundColor: "#FF8544", color: "#1A1A1A", fontFamily: "Inter" }}
|
||||
style={{
|
||||
height: "100%",
|
||||
width: '100%',
|
||||
borderRadius: '7px',
|
||||
textTransform: 'none',
|
||||
backgroundColor: "#FF8544",
|
||||
color: "#1A1A1A",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: 16,
|
||||
fontWeight: 500
|
||||
}}
|
||||
startIcon={<Add style={{ color: "#1A1A1A" }} />}
|
||||
>
|
||||
<Add style={{ marginRight: 10, color: "#1A1A1A", fontSize: 20 }} />
|
||||
Create an App
|
||||
</Button>
|
||||
</div>
|
||||
@@ -1892,7 +2046,8 @@ const Apps2 = (props) => {
|
||||
gap: "20px",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
padding: "0 10px"
|
||||
padding: "0 10px",
|
||||
paddingBottom: 40
|
||||
}}>
|
||||
{appsToShow.map((data, index) => (
|
||||
<AppCard
|
||||
@@ -1931,7 +2086,7 @@ const Apps2 = (props) => {
|
||||
}
|
||||
{
|
||||
currTab === 1 && (
|
||||
<div style={{ minHeight: 570, overflowY: "auto", overflowX: "hidden" }}>
|
||||
<div style={{ minHeight: 570 }}>
|
||||
{isLoading ? (
|
||||
<LoadingGrid />
|
||||
) : (
|
||||
@@ -1945,7 +2100,8 @@ const Apps2 = (props) => {
|
||||
gap: "20px",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
padding: "0 10px"
|
||||
padding: "0 10px",
|
||||
paddingBottom: 40
|
||||
}}>
|
||||
{appsToShow.map((data, index) => (
|
||||
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} userdata={userdata}
|
||||
@@ -1955,7 +2111,16 @@ const Apps2 = (props) => {
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ width: "100%", marginTop: 60, textAlign: "center", display: "flex", justifyContent: "center", alignItems: "center" }}>
|
||||
<Typography variant="body1">No Apps Found</Typography>
|
||||
<AppSelection
|
||||
userdata={userdata}
|
||||
globalUrl={globalUrl}
|
||||
appFramework={appFramework}
|
||||
setAppFramework={setAppFramework}
|
||||
defaultSearch={defaultSearch}
|
||||
setDefaultSearch={setDefaultSearch}
|
||||
checkLogin={checkLogin}
|
||||
isAppPage={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
@@ -1976,6 +2141,7 @@ const Apps2 = (props) => {
|
||||
searchQuery={searchQuery}
|
||||
mouseHoverIndex={mouseHoverIndex}
|
||||
setMouseHoverIndex={setMouseHoverIndex}
|
||||
currTab={currTab}
|
||||
leftSideBarOpenByClick={leftSideBarOpenByClick}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -274,7 +274,8 @@ const CodeWorkflow = (defaultprops) => {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100vh', // Set to full viewport height
|
||||
backgroundColor: '#252526'
|
||||
backgroundColor: '#252526',
|
||||
marginLeft: '100px',
|
||||
}}>
|
||||
{/* IDE-like toolbar */}
|
||||
<Toolbar
|
||||
|
||||
@@ -337,11 +337,23 @@ const Dashboard = (props) => {
|
||||
const [, setUpdate] = useState(0);
|
||||
|
||||
let navigate = useNavigate();
|
||||
const isCloud =
|
||||
window.location.host === "localhost:3002" ||
|
||||
window.location.host === "shuffler.io";
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
|
||||
const path = window.location.pathname
|
||||
if (path !== undefined && path !== null) {
|
||||
if (path.includes("/automate")) {
|
||||
navigate("/usecases")
|
||||
}
|
||||
|
||||
if (path.includes("/security")) {
|
||||
navigate("/forms")
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// Look for the path. If it is automation, go to usecases
|
||||
// Handles redirect
|
||||
|
||||
const widgetnames = ["app_executions_cloud"]
|
||||
for (let widgetkey in widgetnames) {
|
||||
const widgetName = widgetnames[widgetkey]
|
||||
@@ -859,7 +871,7 @@ const Dashboard = (props) => {
|
||||
);
|
||||
|
||||
const dataWrapper = (
|
||||
<div style={{ maxWidth: 1366, margin: "auto" }}>{data}</div>
|
||||
<div style={{ maxWidth: 1366, margin: "auto", paddingTop: 10, }}>{data}</div>
|
||||
);
|
||||
|
||||
return dataWrapper;
|
||||
|
||||
@@ -251,7 +251,7 @@ export const CodeHandler = (props) => {
|
||||
}
|
||||
|
||||
const Docs = (defaultprops) => {
|
||||
const { globalUrl, selectedDoc, serverside, serverMobile, userdata } = defaultprops;
|
||||
const { globalUrl, selectedDoc, serverside, serverMobile, isLoggedIn, isLoaded } = defaultprops;
|
||||
let navigate = useNavigate();
|
||||
// Quickfix for react router 5 -> 6
|
||||
const params = useParams();
|
||||
@@ -1266,7 +1266,7 @@ const Docs = (defaultprops) => {
|
||||
|
||||
// Padding and zIndex etc set because of footer in cloud.
|
||||
const loadedCheck = (
|
||||
<DocsWrapper userdata={userdata}>
|
||||
<DocsWrapper isLoggedIn={isLoggedIn} isLoaded={isLoaded}>
|
||||
<DocsContent postDataBrowser={postDataBrowser} postDataMobile={postDataMobile}/>
|
||||
</DocsWrapper>
|
||||
);
|
||||
@@ -1285,18 +1285,18 @@ const DocsContent = memo(({postDataBrowser, postDataMobile}) => {
|
||||
</div>
|
||||
)})
|
||||
|
||||
const DocsWrapper = memo(({userdata, children })=>{
|
||||
const DocsWrapper = memo(({isLoggedIn, isLoaded, children })=>{
|
||||
|
||||
const { leftSideBarOpenByClick, windowWidth } = useContext(Context);
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
minHeight: 1000, zIndex: 1,
|
||||
maxWidth: Math.min(leftSideBarOpenByClick ? windowWidth - 300 : windowWidth - 200, 1920),
|
||||
minWidth: isMobile ? null : leftSideBarOpenByClick ? 800 : 900, margin: "auto",
|
||||
position: leftSideBarOpenByClick ? "relative" : "static",
|
||||
left: leftSideBarOpenByClick ? 120 : !leftSideBarOpenByClick ? 80 : 0,
|
||||
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick ? 160 : !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
||||
maxWidth: Math.min(!(isLoggedIn && isLoaded) ? 1920 : leftSideBarOpenByClick ? windowWidth - 300 : windowWidth - 200, 1920),
|
||||
minWidth: isMobile ? null : (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 800 : 900 : null, margin: "auto",
|
||||
position: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? "relative" : "static",
|
||||
left: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? 120 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0,
|
||||
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"
|
||||
}}>
|
||||
{children}
|
||||
|
||||
@@ -108,7 +108,6 @@ const RunWorkflow = (defaultprops) => {
|
||||
const boxStyle = {
|
||||
color: "white",
|
||||
padding: "25px 50px 50px 50px",
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
borderRadius: 25,
|
||||
minHeight: 500,
|
||||
}
|
||||
@@ -1116,7 +1115,7 @@ const RunWorkflow = (defaultprops) => {
|
||||
|
||||
const ExplorerUi = () => {
|
||||
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 ?
|
||||
<div>
|
||||
@@ -1126,9 +1125,14 @@ const RunWorkflow = (defaultprops) => {
|
||||
<FormList />
|
||||
</div>
|
||||
:
|
||||
<Typography variant="h6" style={{marginTop: 100, marginBottom: 20, }}>
|
||||
No Form Found
|
||||
<div>
|
||||
<Typography variant="h4" style={{marginTop: 125, marginBottom: 25, }}>
|
||||
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>
|
||||
)
|
||||
@@ -1474,7 +1478,7 @@ const RunWorkflow = (defaultprops) => {
|
||||
|
||||
{workflowQuestion !== "" ? null :
|
||||
<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>
|
||||
}
|
||||
</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 loadedCheck = isLoaded ?
|
||||
<div style={{marginTop: 30, }}>
|
||||
<div style={{paddingTop: 60, }}>
|
||||
{editWorkflowModalOpen === true ?
|
||||
<EditWorkflow
|
||||
saveWorkflow={saveWorkflow}
|
||||
@@ -1570,6 +1574,7 @@ const RunWorkflow = (defaultprops) => {
|
||||
<div style={{position: "fixed", top: 10, right: 20, }}>
|
||||
|
||||
<Button
|
||||
disabled={workflow.id === undefined || workflow.id === null}
|
||||
variant={"outlined"}
|
||||
color={"secondary"}
|
||||
style={{marginRight: 10, }}
|
||||
@@ -1582,6 +1587,7 @@ const RunWorkflow = (defaultprops) => {
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
disabled={workflow.id === undefined || workflow.id === null}
|
||||
variant={workflow.sharing === "form" ? "outlined" : "contained"}
|
||||
color={"secondary"}
|
||||
style={{marginRight: 10, }}
|
||||
@@ -1603,6 +1609,7 @@ const RunWorkflow = (defaultprops) => {
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
disabled={workflow.id === undefined || workflow.id === null}
|
||||
variant={"contained"}
|
||||
color={"primary"}
|
||||
style={{}}
|
||||
|
||||
@@ -91,7 +91,7 @@ const Search = (props) => {
|
||||
userdata={userdata}
|
||||
/>, [curTab]);
|
||||
|
||||
const MemoizedDiscordChat = useMemo(() => <DiscordChat isMobile={isMobile} />)
|
||||
const MemoizedDiscordChat = useMemo(() => <DiscordChat isMobile={isMobile} />, [curTab])
|
||||
|
||||
const useStyles = makeStyles({
|
||||
hideIndicator: {
|
||||
|
||||
@@ -1220,7 +1220,7 @@ const Usecases2 = (props) => {
|
||||
) : null
|
||||
|
||||
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
|
||||
userdata={userdata}
|
||||
@@ -1241,7 +1241,7 @@ const Usecases2 = (props) => {
|
||||
|
||||
const dataWrapper =
|
||||
<Fade in={true} timeout={1250}>
|
||||
<div style={{ maxWidth: 1366, margin: "auto", }}>
|
||||
<div style={{ maxWidth: 1366, margin: "auto", zoom: 0.8, }}>
|
||||
{data}
|
||||
</div>
|
||||
</Fade>
|
||||
|
||||
+319
-321
@@ -58,6 +58,7 @@ import {
|
||||
AvatarGroup,
|
||||
Zoom,
|
||||
Collapse,
|
||||
Skeleton,
|
||||
} from "@mui/material";
|
||||
|
||||
// Material UI Icons
|
||||
@@ -430,14 +431,17 @@ export const GetIconInfo = (action) => {
|
||||
};
|
||||
|
||||
const chipStyle = {
|
||||
backgroundColor: "#3d3f43",
|
||||
backgroundColor: "#2F2F2F",
|
||||
marginRight: 5,
|
||||
paddingLeft: 5,
|
||||
paddingRight: 5,
|
||||
height: 28,
|
||||
height: 35,
|
||||
cursor: "pointer",
|
||||
borderColor: "#3d3f43",
|
||||
color: "white",
|
||||
borderColor: "#2F2F2F",
|
||||
color: "#C8C8C8",
|
||||
fontSize: "14px",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
borderRadius: "17.5px"
|
||||
};
|
||||
|
||||
export const collapseField = (field) => {
|
||||
@@ -618,9 +622,11 @@ const useDropzoneStyles = () => {
|
||||
const { leftSideBarOpenByClick } = useContext(Context);
|
||||
|
||||
return {
|
||||
maxWidth: window.innerWidth > 1366 ? 1366 : isMobile ? "100%" : 1200,
|
||||
margin: "auto",
|
||||
padding: 20,
|
||||
paddingTop: 70,
|
||||
// minHeight: 1000,
|
||||
backgroundColor: "#1A1A1A",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
// maxWidth: window.innerWidth > 1366 ? 1366 : isMobile ? "100%" : 1200,
|
||||
paddingLeft: leftSideBarOpenByClick ? 200 : 0,
|
||||
transition: "padding-left 0.3s ease",
|
||||
};
|
||||
@@ -640,6 +646,7 @@ const DropzoneWrapper = memo(({ onDrop, WorkflowView }) => {
|
||||
|
||||
const Workflows2 = (props) => {
|
||||
const { globalUrl, isLoggedIn, isLoaded, userdata, checkLogin } = props;
|
||||
const { leftSideBarOpenByClick } = useContext(Context);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [currTab, setCurrTab] = useState(0);
|
||||
@@ -708,7 +715,6 @@ const Workflows2 = (props) => {
|
||||
|
||||
const [apps, setApps] = React.useState([]);
|
||||
|
||||
|
||||
document.title = "Shuffle - Workflows";
|
||||
const handleTabChange = (event, newValue) => {
|
||||
// Set loading when switching to public workflows tab
|
||||
@@ -1516,24 +1522,25 @@ const Workflows2 = (props) => {
|
||||
};
|
||||
|
||||
const paperAppStyle = {
|
||||
minHeight: 130,
|
||||
maxHeight: 130,
|
||||
minHeight: 146,
|
||||
maxHeight: 146,
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
color: "white",
|
||||
padding: "12px 12px 0px 15px",
|
||||
display: "flex",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
boxSizing: "border-box",
|
||||
position: "relative",
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
borderRadius: "8px",
|
||||
// backgroundColor: "#212121",
|
||||
};
|
||||
|
||||
const gridContainer = {
|
||||
height: "auto",
|
||||
color: "white",
|
||||
margin: "10px",
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
backgroundColor: "#212121",
|
||||
position: "relative",
|
||||
};
|
||||
|
||||
@@ -1542,6 +1549,7 @@ const Workflows2 = (props) => {
|
||||
width: 160,
|
||||
height: 44,
|
||||
justifyContent: "space-between",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
};
|
||||
|
||||
const exportAllWorkflows = (allWorkflows) => {
|
||||
@@ -2107,6 +2115,80 @@ const Workflows2 = (props) => {
|
||||
return appsFound
|
||||
}
|
||||
|
||||
const WorkflowSkeleton = () => {
|
||||
return (
|
||||
<Paper elevation={0} style={{
|
||||
backgroundColor: "#212121",
|
||||
width: "100%",
|
||||
height: 120,
|
||||
borderRadius: 8,
|
||||
}}>
|
||||
<div style={{
|
||||
display: "flex",
|
||||
padding: 10,
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
}}>
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={100}
|
||||
height={90}
|
||||
style={{
|
||||
borderRadius: 6,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
||||
}}
|
||||
/>
|
||||
<div style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
marginLeft: 10,
|
||||
flex: 1,
|
||||
gap: 6
|
||||
}}>
|
||||
<Skeleton
|
||||
variant="text"
|
||||
width="40%"
|
||||
height={24}
|
||||
style={{ backgroundColor: "rgba(255, 255, 255, 0.1)" }}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="text"
|
||||
width="60%"
|
||||
height={20}
|
||||
style={{ backgroundColor: "rgba(255, 255, 255, 0.1)" }}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="text"
|
||||
width="30%"
|
||||
height={20}
|
||||
style={{ backgroundColor: "rgba(255, 255, 255, 0.1)" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
// Replace the loading sections in the main component with this
|
||||
const LoadingWorkflowGrid = () => {
|
||||
return (
|
||||
<div style={{
|
||||
marginTop: 16,
|
||||
width: "100%",
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(365px, 1fr))",
|
||||
gap: "20px",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
padding: "0 10px"
|
||||
}}>
|
||||
{[...Array(7)].map((_, index) => (
|
||||
<WorkflowSkeleton key={index} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const WorkflowPaper = (props) => {
|
||||
const { data, type = "org" } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
@@ -2283,8 +2365,9 @@ const Workflows2 = (props) => {
|
||||
marginRight: 10,
|
||||
};
|
||||
|
||||
|
||||
image =
|
||||
foundOrg.image === "" ? (
|
||||
foundOrg.image === "" || foundOrg.image === null || foundOrg.image === undefined ? (
|
||||
<img
|
||||
alt={foundOrg.name}
|
||||
src={theme.palette.defaultImage}
|
||||
@@ -2336,8 +2419,30 @@ const Workflows2 = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (type === "public" && currTab === 2) {
|
||||
|
||||
const imageStyle = {
|
||||
width: 24,
|
||||
height: 24,
|
||||
marginRight: 10,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
}
|
||||
|
||||
image = data.creator_info !== undefined && data.creator_info !== null && data.creator_info.image !== undefined && data.creator_info.image !== null && data.creator_info.image.length > 0 ? <Avatar alt={data.creator} src={data.creator_info.image} style={imageStyle} /> : <Avatar alt={"shuffle_image"} src={theme.palette.defaultImage} style={imageStyle} />
|
||||
const creatorname = data.creator_info !== undefined && data.creator_info !== null && data.creator_info.username !== undefined && data.creator_info.username !== null && data.creator_info.username.length > 0 ? data.creator_info.username : "Shuffle"
|
||||
if ((data.objectID === undefined || data.objectID === null) && data.id !== undefined && data.id !== null) {
|
||||
data.objectID = data.id
|
||||
}
|
||||
|
||||
//console.log("IMG: ", data)
|
||||
var parsedUrl = `/workflows/${data.objectID}`
|
||||
if (data.__queryID !== undefined && data.__queryID !== null) {
|
||||
parsedUrl += `?queryID=${data.__queryID}`
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", minWidth: 320, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? "1px solid #40E0D0" : "inherit", borderRadius: theme.palette?.borderRadius, }}>
|
||||
<div style={{ width: "100%", minWidth: 320, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? "1px solid #40E0D0" : "inherit", borderRadius: theme.palette?.borderRadius, backgroundColor: "#212121", fontFamily: theme?.typography?.fontFamily }}>
|
||||
<Paper square style={paperAppStyle}>
|
||||
{selectedCategory !== "" ?
|
||||
<Tooltip title={`Usecase Category: ${selectedCategory}`} placement="bottom">
|
||||
@@ -2351,6 +2456,7 @@ const Workflows2 = (props) => {
|
||||
width: 3,
|
||||
backgroundColor: boxColor,
|
||||
borderRadius: "0 100px 0 0",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}
|
||||
onClick={() => {
|
||||
addFilter(selectedCategory)
|
||||
@@ -2360,7 +2466,7 @@ const Workflows2 = (props) => {
|
||||
: null}
|
||||
<Grid
|
||||
item
|
||||
style={{ display: "flex", flexDirection: "column", width: "100%" }}
|
||||
style={{ display: "flex", flexDirection: "column", width: "100%", fontFamily: theme?.typography?.fontFamily }}
|
||||
>
|
||||
<Grid item style={{ display: "flex", maxHeight: 34 }}>
|
||||
<Tooltip title={`Org "${orgName}". Click to edit image.`} placement="bottom">
|
||||
@@ -2389,7 +2495,7 @@ const Workflows2 = (props) => {
|
||||
maxWidth: 310,
|
||||
padding: "12px 0",
|
||||
}}>
|
||||
{data.image !== undefined && data.image !== null && data.image.length > 0 ? (
|
||||
{(data?.image !== undefined || data?.image_url !== undefined) ? (
|
||||
<div style={{
|
||||
marginBottom: 15,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
@@ -2397,8 +2503,8 @@ const Workflows2 = (props) => {
|
||||
border: `1px solid ${theme.palette.inputColor}`,
|
||||
}}>
|
||||
<img
|
||||
src={data.image}
|
||||
alt={data.name}
|
||||
src={data?.image || data?.image_url}
|
||||
alt={data?.name}
|
||||
style={{
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
width: "100%",
|
||||
@@ -2411,6 +2517,8 @@ const Workflows2 = (props) => {
|
||||
|
||||
<Typography style={{
|
||||
color: "rgba(255,255,255,0.9)",
|
||||
fontSize: "16px",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}>
|
||||
Edit: {data.name}
|
||||
</Typography>
|
||||
@@ -2443,10 +2551,14 @@ const Workflows2 = (props) => {
|
||||
paddingBottom: 0,
|
||||
maxHeight: 30,
|
||||
flex: 10,
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to={"/workflows/" + data.id}
|
||||
to={
|
||||
type === "public" ? parsedUrl : data.workflow_as_code ? `/workflows/${data.id}/code` : `/workflows/${data.id}`
|
||||
}
|
||||
style={{ textDecoration: "none", color: "inherit" }}
|
||||
>
|
||||
{parsedName}
|
||||
@@ -2620,8 +2732,9 @@ const Workflows2 = (props) => {
|
||||
style={{
|
||||
justifyContent: "left",
|
||||
overflow: "hidden",
|
||||
marginTop: 5,
|
||||
maxHeight: 28,
|
||||
marginTop: 8,
|
||||
maxHeight: 35,
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}
|
||||
>
|
||||
{data.tags !== undefined && data.tags !== null
|
||||
@@ -3079,11 +3192,7 @@ const Workflows2 = (props) => {
|
||||
</Typography>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Subflows used"
|
||||
placement="bottom"
|
||||
>
|
||||
<Tooltip color="primary" title="Subflows used" placement="bottom">
|
||||
<span
|
||||
style={{
|
||||
marginLeft: 15,
|
||||
@@ -3235,7 +3344,7 @@ const Workflows2 = (props) => {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div style={gridContainer}>
|
||||
<div style={{ ...gridContainer, backgroundColor: "#212121" }}>
|
||||
<Tooltip title={`New Workflow`} placement="bottom">
|
||||
<IconButton
|
||||
style={{ position: "absolute", top: 10, right: 50, zIndex: 1000 }}
|
||||
@@ -3797,9 +3906,9 @@ const Workflows2 = (props) => {
|
||||
// }
|
||||
|
||||
useEffect(() => {
|
||||
if (userdata !== undefined && userdata !== null) {
|
||||
var filteredWorkflows = []
|
||||
if (userdata !== undefined && userdata !== null && currTab !== 2) {
|
||||
setIsLoadingWorkflow(true);
|
||||
var filteredWorkflows = []
|
||||
if (currTab === 0) {
|
||||
filteredWorkflows = workflows.filter(workflow => workflow?.org_id === userdata?.active_org?.id)
|
||||
}
|
||||
@@ -3807,7 +3916,10 @@ const Workflows2 = (props) => {
|
||||
filteredWorkflows = workflows.filter(workflow => workflow?.org_id === userdata?.active_org?.id && workflow?.owner === userdata?.id)
|
||||
}
|
||||
setFilteredWorkflows(filteredWorkflows)
|
||||
setTimeout(() => {
|
||||
setIsLoadingWorkflow(false);
|
||||
}, 500);
|
||||
|
||||
}
|
||||
}, [currTab, workflows, userdata])
|
||||
|
||||
@@ -3819,25 +3931,29 @@ const Workflows2 = (props) => {
|
||||
var counted = 0
|
||||
console.log("Public workflows", hits)
|
||||
|
||||
if (isLoadingPublicWorkflow) {
|
||||
return (
|
||||
<div style={{ textAlign: "center", marginTop: 50 }}>
|
||||
<CircularProgress style={{ color: "#f85a3e" }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
isLoadingPublicWorkflow ?
|
||||
(
|
||||
<LoadingWorkflowGrid />
|
||||
) : (
|
||||
|
||||
<div style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(3, 1fr)", // Creates 3 equal columns
|
||||
gap: "20px", // Adds consistent spacing between items
|
||||
marginTop: 16,
|
||||
width: "100%",
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(365px, 1fr))",
|
||||
gap: "20px",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
padding: "0 10px",
|
||||
paddingBottom: 40
|
||||
}}>
|
||||
{hits.map((data, index) => {
|
||||
return <WorkflowPaper key={index} data={data} type="public" />
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
@@ -3849,6 +3965,21 @@ const Workflows2 = (props) => {
|
||||
setSelectedCategory(e.target.value)
|
||||
}
|
||||
|
||||
|
||||
const iconButtonStyle = {
|
||||
color: 'white',
|
||||
backgroundColor: '#212121',
|
||||
borderRadius: '4px',
|
||||
padding: "12px 16px",
|
||||
cursor: 'pointer',
|
||||
minWidth: '40px',
|
||||
height: 'auto',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
}
|
||||
|
||||
const WorkflowView = memo(() => {
|
||||
if (workflows.length === 0) {
|
||||
}
|
||||
@@ -3858,47 +3989,98 @@ const Workflows2 = (props) => {
|
||||
|
||||
const foundPriority = userdata === undefined || userdata === null || userdata.priorities === undefined || userdata.priorities === null ? null : userdata.priorities.find(prio => prio.type === "usecase" && prio.active === true)
|
||||
return (
|
||||
<div style={viewStyle}>
|
||||
<div style={workflowViewStyle}>
|
||||
<div style={{ display: "flex", marginTop: 25, }}>
|
||||
{/* <div style={{ flex: 1 }}>
|
||||
<Typography variant="h1" style={{fontSize: 30}}>
|
||||
<>
|
||||
<div style={{
|
||||
color: "white",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
maxWidth: "70%",
|
||||
margin: "auto",
|
||||
}}>
|
||||
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: theme?.typography?.fontFamily }}>
|
||||
Workflows
|
||||
</Typography>
|
||||
</div> */}
|
||||
{/*
|
||||
<div style={{ flex: 1 }}>
|
||||
<Typography style={{ marginTop: 7, marginBottom: "auto" }}>
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href="https://shuffler.io/docs/workflows"
|
||||
style={{ textDecoration: "none", color: "#f85a3e" }}
|
||||
|
||||
<div style={{ borderBottom: '1px solid gray', marginBottom: 30 }}>
|
||||
<Tabs
|
||||
value={currTab}
|
||||
onChange={handleTabChange}
|
||||
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10, backgroundColor: "#FF8544" } }}
|
||||
style={{ fontFamily: theme?.typography?.fontFamily }}
|
||||
>
|
||||
Learn more about Workflows
|
||||
</a>
|
||||
</Typography>
|
||||
<Tab label="Organization Workflows" style={{ textTransform: 'none', marginRight: 20, fontFamily: theme?.typography?.fontFamily }} />
|
||||
<Tab label="My Workflows" style={{ textTransform: 'none', marginRight: 20, fontFamily: theme?.typography?.fontFamily }} />
|
||||
<Tab label="Discover Workflows" style={{ textTransform: 'none', fontFamily: theme?.typography?.fontFamily }} />
|
||||
</Tabs>
|
||||
</div>
|
||||
*/}
|
||||
{/* {isMobile ? null :
|
||||
<div style={{ display: "flex", margin: "0px 0px 20px 0px" }}>
|
||||
<div style={{ flex: 1, float: "right" }}>
|
||||
|
||||
|
||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, paddingRight: 25, minHeight: 47 }}>
|
||||
|
||||
|
||||
<MuiChipsInput
|
||||
style={{}}
|
||||
style={{
|
||||
width: "25%",
|
||||
maxWidth: "25%",
|
||||
minWidth: "25%",
|
||||
height: 43,
|
||||
maxHeight: "fit-content",
|
||||
backgroundColor: "#212121",
|
||||
zIndex: 1000,
|
||||
}}
|
||||
disabled={currTab === 2}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
maxWidth: 275,
|
||||
minWidth: 275,
|
||||
height: "fit-content",
|
||||
maxHeight: "fit-content",
|
||||
backgroundColor: "#212121",
|
||||
},
|
||||
placeholder: "Filter Workflows",
|
||||
// endAdornment: (
|
||||
// <InputAdornment position="end">
|
||||
// <SearchIcon style={{ color: 'white', paddingRight: 5 }} />
|
||||
// </InputAdornment>
|
||||
// ),
|
||||
onKeyDown: (e) => {
|
||||
// Prevent default behavior for Enter and Backspace
|
||||
if (e.key === 'Enter' || e.key === 'Backspace') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.target.focus();
|
||||
}
|
||||
},
|
||||
}}
|
||||
rows={1}
|
||||
placeholder="Filter Workflows"
|
||||
color="primary"
|
||||
fullWidth
|
||||
clearInputOnBlur={false}
|
||||
sx={{
|
||||
// Container styling
|
||||
'& .MuiOutlinedInput-root': {
|
||||
height: "fit-content",
|
||||
borderRadius: '4px',
|
||||
backgroundColor: '#212121',
|
||||
'& fieldset': {
|
||||
borderColor: 'rgba(255, 255, 255, 0.23)',
|
||||
},
|
||||
'&:hover fieldset': {
|
||||
borderColor: 'rgba(255, 255, 255, 0.4)',
|
||||
},
|
||||
},
|
||||
|
||||
// Adjust chip container to center vertically
|
||||
'& .MuiInputBase-root': {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '4px',
|
||||
padding: '4px 8px',
|
||||
alignItems: 'center',
|
||||
height: "fit-content", // Match height
|
||||
},
|
||||
|
||||
// Rest of the styling remains the same...
|
||||
}}
|
||||
value={filters}
|
||||
onChange={(chips) => {
|
||||
console.log("CHANGE: ", chips);
|
||||
setFilters(chips);
|
||||
findWorkflow(chips);
|
||||
}}
|
||||
@@ -3911,180 +4093,6 @@ const Workflows2 = (props) => {
|
||||
// removeFilter(index);
|
||||
//}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
} */}
|
||||
{/* <div style={{ flex: 1, textAlign: "right", }}>
|
||||
{workflowButtons}
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
{/* <div style={{width: "100%", minHeight: isMobile ? 0 : hasWorkflows ? 0 : 51, maxHeight: isMobile ? 0 : 51, marginTop: 10, }}>
|
||||
{!isMobile && !hasWorkflows && usecases !== null && usecases !== undefined && usecases.length > 0 ?
|
||||
<div style={{ display: "flex", }}>
|
||||
{usecases.map((usecase, index) => {
|
||||
if (usecase.name === "5. Verify") {
|
||||
return null
|
||||
}
|
||||
|
||||
const percentDone = usecase.matches.length > 0 ? parseInt(usecase.matches.length/usecase.list.length*100) : 0
|
||||
if (percentDone === 0) {
|
||||
usecase = findMatches(usecase, workflows)
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
key={usecase.name}
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundImage: `linear-gradient(to right, ${usecase.color}, ${usecase.color} ${percentDone}%, transparent ${percentDone}%, transparent 100%)`,
|
||||
backgroundColor: filters.includes(usecase.name.toLowerCase()) ? null : theme.palette.surfaceColor,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
marginRight: index === usecases.length-1 ? 0 : 10,
|
||||
cursor: "pointer",
|
||||
border: `2px solid ${usecase.color}`,
|
||||
overflow: "hidden",
|
||||
padding: 10,
|
||||
}}
|
||||
onClick={() => {
|
||||
console.log("Filters: ", filters, usecase.name.toLowerCase())
|
||||
if (!filters.includes(usecase.name.toLowerCase())) {
|
||||
addFilter(usecase.name)
|
||||
} else {
|
||||
removeFilter(filters.indexOf(usecase.name.toLowerCase()))
|
||||
}
|
||||
|
||||
}}
|
||||
>
|
||||
<span style={{ textDecoration: "none", display: "flex", }}>
|
||||
<Typography variant="body1" color="textPrimary" style={{flex: 4, }}>
|
||||
{usecase.name}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary" style={{flex: 1, marginTop: 0,}}>
|
||||
{usecase.matches.length}/{usecase.list.length}
|
||||
</Typography>
|
||||
</span>
|
||||
</Paper>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
: null}
|
||||
</div> */}
|
||||
|
||||
|
||||
|
||||
{userdata.priorities !== undefined && userdata.priorities !== null && userdata.priorities.length > 0 && userdata.priorities[0].name.includes("CPU") && userdata.priorities[0].active === true ?
|
||||
<div style={{
|
||||
border: "1px solid rgba(255,255,255,0.1)", borderRadius: theme.palette?.borderRadius, marginTop: 10,
|
||||
marginBottom: 10, padding: 15, textAlign: "center", height: 70, textAlign: "left", backgroundColor:
|
||||
theme.palette.surfaceColor, display: "flex", maxHeight: "105px", minHeight: "110px"
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: 2, overflow: "hidden", }}>
|
||||
<Typography variant="body1" >
|
||||
{userdata.priorities[0].name}
|
||||
</Typography>
|
||||
<div style={{ flex: "2 1 0%", overflow: "hidden" }}>
|
||||
<span style={{ display: "flex", marginTop: "10px" }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: "3px" }}>
|
||||
{userdata.priorities[0].description}
|
||||
</Typography>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ flex: 1, display: "flex", marginLeft: 30, }}>
|
||||
<Button style={{ height: 50, borderRadius: 25, marginTop: 8, width: 175, backgroundColor: "rgba(255,255,255,0.8)" }} variant="contained" color="secondary" onClick={() => { navigate(userdata.priorities[0].url) }}>
|
||||
explore
|
||||
</Button>
|
||||
{/*
|
||||
<Button style={{borderRadius: 25, width: 200, height: 50, marginTop: 8, }} variant="text" color="secondary">
|
||||
Ignore
|
||||
</Button>
|
||||
*/}
|
||||
</div>
|
||||
</div>
|
||||
: null}
|
||||
|
||||
{/* {foundPriority != null && workflows.length < 6 ?
|
||||
<Priority
|
||||
globalUrl={globalUrl}
|
||||
userdata={userdata}
|
||||
priority={foundPriority}
|
||||
checkLogin={checkLogin}
|
||||
appFramework={appFramework}
|
||||
/>
|
||||
: null} */}
|
||||
|
||||
<div style={{
|
||||
color: "white",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
marginTop: 50,
|
||||
margin: "auto",
|
||||
// maxWidth: "80%",
|
||||
|
||||
}}>
|
||||
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15 }}>
|
||||
Workflows
|
||||
</Typography>
|
||||
|
||||
<div style={{ borderBottom: '1px solid gray', marginBottom: 30 }}>
|
||||
<Tabs
|
||||
value={currTab}
|
||||
onChange={handleTabChange}
|
||||
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10 } }}
|
||||
>
|
||||
<Tab label="Organization Workflows" style={{ textTransform: 'none', marginRight: 20 }} />
|
||||
<Tab label="My Workflows" style={{ textTransform: 'none', marginRight: 20 }} />
|
||||
<Tab label="Discover Workflows" style={{ textTransform: 'none' }} />
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20, gap: 10 }}>
|
||||
|
||||
|
||||
<MuiChipsInput
|
||||
placeholder="Filter Workflows"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
value={filters}
|
||||
onChange={(chips) => {
|
||||
console.log("CHANGE: ", chips);
|
||||
setFilters(chips);
|
||||
findWorkflow(chips);
|
||||
}}
|
||||
style={{ flex: 0.9 }}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
borderRadius: 8,
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: 'rgba(255, 255, 255, 0.2)',
|
||||
},
|
||||
'&:hover fieldset': {
|
||||
borderColor: 'rgba(255, 255, 255, 0.3)',
|
||||
},
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#f85a3e',
|
||||
},
|
||||
},
|
||||
'& .MuiChip-root': {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
color: 'white',
|
||||
'& .MuiChip-deleteIcon': {
|
||||
color: 'rgba(255, 255, 255, 0.7)',
|
||||
'&:hover': {
|
||||
color: 'white',
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<Select
|
||||
fullWidth
|
||||
@@ -4092,8 +4100,23 @@ const Workflows2 = (props) => {
|
||||
value={selectedCategory}
|
||||
onChange={handleCategoryChange}
|
||||
displayEmpty
|
||||
disabled={currTab === 2}
|
||||
multiple
|
||||
style={{ flex: 0.9, maxWidth: 350, borderRadius: 8 }}
|
||||
style={{
|
||||
width: "25%",
|
||||
minWidth: "25%",
|
||||
maxWidth: "25%",
|
||||
height: 47,
|
||||
borderRadius: 4,
|
||||
backgroundColor: "#212121",
|
||||
}}
|
||||
sx={{
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: 'rgba(255, 255, 255, 0.23)',
|
||||
},
|
||||
},
|
||||
}}
|
||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
||||
>
|
||||
<MenuItem disabled value="" style={{}}>All Categories</MenuItem>
|
||||
@@ -4174,62 +4197,50 @@ const Workflows2 = (props) => {
|
||||
})}
|
||||
</Select>
|
||||
|
||||
<div style={{ display: "flex", gap: 8, height: "100%" }}>
|
||||
|
||||
<div style={{ width: "50%", minWidth: "50%", maxWidth: "50%", height: 47, display: "flex", gap: 5 }}>
|
||||
<div style={{
|
||||
display: "flex", height: "100%",
|
||||
justifyContent: "space-around",
|
||||
flex: 0.7,
|
||||
paddingLeft: 1,
|
||||
paddingRight: 1,
|
||||
gap: 4
|
||||
}}>
|
||||
<Tooltip title="Explore Workflow Runs" placement="top">
|
||||
<IconButton
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#212121',
|
||||
borderRadius: '8px',
|
||||
padding: '6px',
|
||||
width: '55px',
|
||||
height: '55px',
|
||||
}}
|
||||
style={iconButtonStyle}
|
||||
onClick={() => navigate("/workflows/debug")}
|
||||
disabled={currTab === 2}
|
||||
>
|
||||
<QueryStatsIcon />
|
||||
<QueryStatsIcon style={{ color: "#F1F1F1" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={view === "grid" ? "Grid view" : "List view"} placement="top">
|
||||
|
||||
<Tooltip title={view === "grid" ? "List view" : "Grid view"} placement="top">
|
||||
<IconButton
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#212121',
|
||||
borderRadius: '8px',
|
||||
padding: '6px',
|
||||
width: '55px',
|
||||
height: '55px',
|
||||
}}
|
||||
style={iconButtonStyle}
|
||||
onClick={() => {
|
||||
if (view === "grid") {
|
||||
localStorage.setItem("workflowView", "list");
|
||||
setView("list");
|
||||
} else {
|
||||
localStorage.setItem("workflowView", "grid");
|
||||
setView("grid");
|
||||
}
|
||||
const newView = view === "grid" ? "list" : "grid";
|
||||
localStorage.setItem("workflowView", newView);
|
||||
setView(newView);
|
||||
}}
|
||||
disabled={currTab === 2}
|
||||
>
|
||||
{
|
||||
view === "list" ? <ListIcon /> : <GridOnIcon />
|
||||
}
|
||||
{view === "grid" ? <ListIcon /> : <GridOnIcon />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Import workflows" placement="top">
|
||||
<IconButton
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#212121',
|
||||
borderRadius: '8px',
|
||||
padding: '6px',
|
||||
width: '55px',
|
||||
height: '55px',
|
||||
}}
|
||||
style={iconButtonStyle}
|
||||
onClick={() => upload.click()}
|
||||
disabled={currTab === 2}
|
||||
>
|
||||
{submitLoading ? <CircularProgress color="secondary" /> : <PublishIcon />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<input
|
||||
hidden
|
||||
type="file"
|
||||
@@ -4237,62 +4248,60 @@ const Workflows2 = (props) => {
|
||||
ref={(ref) => (upload = ref)}
|
||||
onChange={importFiles}
|
||||
/>
|
||||
<Tooltip title={`Download ALL workflows (${workflows.length})`}
|
||||
placement="top">
|
||||
|
||||
<Tooltip title={`Download ALL workflows (${workflows.length})`} placement="top">
|
||||
<IconButton
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#212121',
|
||||
borderRadius: '8px',
|
||||
padding: '6px',
|
||||
width: '55px',
|
||||
height: '55px',
|
||||
}}
|
||||
disabled={isCloud}
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
exportAllWorkflows(workflows);
|
||||
}}
|
||||
style={{ ...iconButtonStyle, cursor: "pointer" }}
|
||||
disabled={isCloud || currTab === 2}
|
||||
onClick={() => exportAllWorkflows(workflows)}
|
||||
>
|
||||
<GetAppIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleCreateWorkflow}
|
||||
style={{
|
||||
height: "56px",
|
||||
borderRadius: 8,
|
||||
borderRadius: 4,
|
||||
flex: 0.8,
|
||||
textTransform: 'none',
|
||||
|
||||
backgroundColor: "#FF8544",
|
||||
color: "#1A1A1A",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
fontSize: 16,
|
||||
fontWeight: 500
|
||||
}}
|
||||
startIcon={<Add style={{ color: "#1A1A1A" }} />}
|
||||
>
|
||||
<Add style={{ marginRight: 10 }} />
|
||||
Create Workflow
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div style={{
|
||||
width: "100%",
|
||||
position: "relative",
|
||||
zIndex: 1
|
||||
}}>
|
||||
{
|
||||
isLoadingWorkflow ? (
|
||||
<div style={{ textAlign: "center", marginTop: 50 }}>
|
||||
<CircularProgress style={{ color: "#f85a3e" }} />
|
||||
</div>
|
||||
<LoadingWorkflowGrid/>
|
||||
) : (
|
||||
view === "grid" && currTab !== 2 ? (
|
||||
<>
|
||||
<div style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(3, 1fr)", // Creates 3 equal columns
|
||||
gap: "20px", // Adds consistent spacing between items
|
||||
marginTop: 16,
|
||||
width: "100%",
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(365px, 1fr))",
|
||||
gap: "20px",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
padding: "0 10px",
|
||||
paddingBottom: 40
|
||||
}}>
|
||||
|
||||
|
||||
@@ -4330,7 +4339,7 @@ const Workflows2 = (props) => {
|
||||
(
|
||||
<InstantSearch searchClient={searchClient} indexName="workflows">
|
||||
<Configure clickAnalytics />
|
||||
<CustomHits hitsPerPage={5} />
|
||||
<CustomHits hitsPerPage={5} type="public" />
|
||||
</InstantSearch>
|
||||
)
|
||||
}
|
||||
@@ -4338,19 +4347,8 @@ const Workflows2 = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
|
||||
{/* {foundPriority != null && filteredWorkflows.length > 6 ?
|
||||
<Priority
|
||||
style={{marginTop: 15, }}
|
||||
globalUrl={globalUrl}
|
||||
priority={foundPriority}
|
||||
checkLogin={checkLogin}
|
||||
appFramework={appFramework}
|
||||
/>
|
||||
: null} */}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4758,7 +4756,7 @@ const Workflows2 = (props) => {
|
||||
);
|
||||
|
||||
// Maybe use gridview or something, idk
|
||||
return <div>{loadedCheck}</div>;
|
||||
return <div style={{zoom: 0.8, }}>{loadedCheck}</div>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -2932,9 +2932,7 @@ func checkTenzirNode() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Failed to verify Tenzir node on %s: %s", url, err)
|
||||
|
||||
return fmt.Errorf("Tenzir node is not available")
|
||||
return fmt.Errorf("Tenzir node is not available due to: %s", err)
|
||||
}
|
||||
|
||||
func createPipeline(command, identifier string) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user