diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 37174871..477c6f4a 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -2,7 +2,7 @@ module shuffle go 1.22.2 -//replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared +replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared require ( cloud.google.com/go/datastore v1.15.0 diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 9fc34790..a24b4daf 100755 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -34,7 +34,7 @@ import RunWorkflow from "./views/RunWorkflow.jsx"; import Admin2 from "./views/Admin2.jsx"; import LoginPage from "./views/LoginPage.jsx"; -//import LoginPage from "./views/LoginPage.jsx"; +import LoginPageOld from "./views/LoginPageOld.jsx"; import SettingsPage from "./views/SettingsPage.jsx"; import KeepAlive from "./views/KeepAlive.jsx"; @@ -257,6 +257,44 @@ const App = (message, props) => { } /> + + } + /> + + + } + /> + { } /> ) : null} + { /> } /> + { 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); - } - }; + //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); + window.addEventListener("keydown", handleKeyDown); - return () => { - window.removeEventListener("keydown", handleKeyDown); - }; -}, [setSearchBarModalOpen]); + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [setSearchBarModalOpen]); const CustomPopper = (props) => { return ( @@ -155,6 +155,7 @@ useEffect(() => { > {props.children} + { marginLeft: 5, }} > + + {expandLeftNav && + + } { }; export default LeftSideBar; - - const ModalView = memo(({searchBarModalOpen, setSearchBarModalOpen, globalUrl, serverside, userdata}) => { return ( ( diff --git a/frontend/src/components/TenantsTab.jsx b/frontend/src/components/TenantsTab.jsx index afeb9563..907c982e 100644 --- a/frontend/src/components/TenantsTab.jsx +++ b/frontend/src/components/TenantsTab.jsx @@ -785,7 +785,7 @@ const TenantsTab = memo((props) => {

Tenants

- Control sub organizations (tenants)! {" "} + Create, manage and change to sub-organizations (tenants)! {" "} {isCloud ? "You can only make a sub organization if you are a customer of shuffle or running a POC of the platform. Please contact support@shuffler.io to try it out." : ''} diff --git a/frontend/src/views/AdminSetup.jsx b/frontend/src/views/AdminSetup.jsx index f8f3d747..0365cf2f 100755 --- a/frontend/src/views/AdminSetup.jsx +++ b/frontend/src/views/AdminSetup.jsx @@ -1,6 +1,8 @@ /* eslint-disable react/no-multi-comp */ import React, { useState } from "react"; import { makeStyles } from "@mui/styles"; +import theme from '../theme.jsx'; +import { useNavigate } from "react-router-dom"; import { CircularProgress, @@ -20,11 +22,8 @@ const surfaceColor = "#27292D"; const inputColor = "#383B40"; const boxStyle = { - paddingLeft: "30px", - paddingRight: "30px", - paddingBottom: "30px", - paddingTop: "30px", - backgroundColor: surfaceColor, + padding: 40, + backgroundColor: theme.palette.backgroundColor, }; const useStyles = makeStyles({ @@ -41,8 +40,10 @@ const AdminAccount = (props) => { const [firstRequest, setFirstRequest] = useState(true); const [loginLoading, setLoginLoading] = useState(false); + // Used to swap from login to register. True = login, false = register const register = true; + let navigate = useNavigate(); const classes = useStyles(); // Error messages etc @@ -70,13 +71,16 @@ const AdminAccount = (props) => { setLoginInfo(responseJson["reason"]); } else { if (responseJson.reason === "redirect") { - window.location.pathname = "/login"; + setTimeout(() => { + window.location.pathname = "/login"; + }, 2500) } } }) ) .catch((error) => { - setLoginInfo("Error in userdata: ", error); + setLoginInfo("Error in userdata (1): ", error); + navigate("/loginsetup") }); }; @@ -108,13 +112,17 @@ const AdminAccount = (props) => { setLoginInfo(responseJson["reason"]); } else { setLoginInfo("Successful register :)"); - window.location.pathname = "/login"; + + setTimeout(() => { + window.location.pathname = "/login"; + }, 2500) } }) ) .catch((error) => { - setLoginLoading(false); - setLoginInfo("Error in userdata: ", error); + setLoginInfo("Error in userdata (2): ", error); + setLoginLoading(false) + navigate("/loginsetup") }); }; diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 51812543..5f9eadd2 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -2540,18 +2540,21 @@ const AngularWorkflow = (defaultprops) => { } */ + // FIXME: What is this? if (cy !== undefined && cy !== null) { // scale: 0.3, // bg: "#27292d", - const cyImageData = cy.png({ - output: "base64uri", - maxWidth: 480, - maxHeight: 270, - }) + if (cy.png !== undefined && cy.png !== null) { + const cyImageData = cy.png({ + output: "base64uri", + maxWidth: 480, + maxHeight: 270, + }) - if (cyImageData !== undefined && cyImageData !== null && cyImageData.length > 0) { - useworkflow.image = cyImageData - } + if (cyImageData !== undefined && cyImageData !== null && cyImageData.length > 0) { + useworkflow.image = cyImageData + } + } } if (useworkflow.id === undefined || useworkflow.id === null || useworkflow.id.length === 0) { @@ -9785,9 +9788,14 @@ const AngularWorkflow = (defaultprops) => { toast("Successfully stopped schedule"); } - workflow.triggers[triggerindex].status = "stopped"; - trigger.status = "stopped"; - setSelectedTrigger(trigger); + if (triggerindex !== undefined && triggerindex !== null && triggerindex >= 0) { + workflow.triggers[triggerindex].status = "stopped"; + } + + //trigger.status = "stopped"; + //console.log("TRIGGER: ", trigger) + //setSelectedTrigger(trigger); + setWorkflow(workflow); saveWorkflow(workflow) @@ -14637,20 +14645,19 @@ const AngularWorkflow = (defaultprops) => { cy.add(cybranch); } - console.log("Value to be set: ", e.target.value); try { - workflow.triggers[ - selectedTriggerIndex - ].parameters[3].value = e.target.value.id; - } catch { - workflow.triggers[selectedTriggerIndex].parameters[3] = - { - name: "startnode", - value: e.target.value.id, - }; + workflow.triggers[selectedTriggerIndex].parameters[3].value = e.target.value.id + } catch(e) { + console.log("Error: ", e) + workflow.triggers[selectedTriggerIndex].parameters[3] = + { + name: "startnode", + value: e.target.value.id, + }; } - setWorkflow(workflow); + setWorkflow(workflow) + setUpdate(Math.random()) } } @@ -15035,7 +15042,7 @@ const AngularWorkflow = (defaultprops) => { {data.image !== undefined && data.image !== null && data.image.length > 0 ? - {data.name} + {data.name} : null} Choose Subflow '{data.name}' diff --git a/frontend/src/views/LoginPage.jsx b/frontend/src/views/LoginPage.jsx index ece6897c..030781ab 100755 --- a/frontend/src/views/LoginPage.jsx +++ b/frontend/src/views/LoginPage.jsx @@ -1,9 +1,10 @@ /* eslint-disable react/no-multi-comp */ -import React, { useState } from 'react'; +import React, { useState, useEffect, } from 'react'; import { makeStyles } from '@mui/styles'; import { useNavigate, Link, useParams } from "react-router-dom"; import { isMobile } from "react-device-detect"; import { toast } from 'react-toastify'; +import { useInterval } from "react-powerhooks"; import { @@ -259,7 +260,7 @@ const MarketplaceCard = ({ classes }) => { target="_blank" style={{ color: "rgba(255, 132, 68, 1)", textDecoration: "underline" }} > - Read more about self hosting + Learn more about self hosting
@@ -269,7 +270,7 @@ const MarketplaceCard = ({ classes }) => { const LoginPage = props => { - const { globalUrl, isLoaded, isLoggedIn, setIsLoggedIn, setCookie, inregister, serverside } = props; + const { globalUrl, isLoaded, isLoggedIn, setIsLoggedIn, setCookie, inregister, serverside, checkLogin, } = props; let navigate = useNavigate(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); @@ -284,6 +285,21 @@ const LoginPage = props => { const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "migration.shuffler.io"; const parsedsearch = serverside === true ? "" : window.location.search + + useEffect(() => { + if (!isCloud) { + checkAdmin() + } + }, []) + + const { start, stop } = useInterval({ + duration: 3000, + startImmediate: false, + callback: () => { + checkAdmin() + }, + }) + if (serverside !== true) { const tmpMessage = new URLSearchParams(window.location.search).get("message") if (tmpMessage !== undefined && tmpMessage !== null && message !== tmpMessage) { @@ -409,6 +425,38 @@ const LoginPage = props => { window.location.pathname = "/workflows" } + const checkAdmin = () => { + const url = globalUrl + "/api/v1/checkusers"; + fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === false) { + setLoginInfo(responseJson["reason"]); + } else { + + // Stay = 0 users + // Redirect = >1 user + if (responseJson.reason === "stay") { + setTimeout(() => { + navigate("/adminsetup") + }, 2500) + } + } + }) + ) + .catch((error) => { + setTimeout(() => { + navigate("/adminsetup") + }, 2500) + }) + }; + + const onSubmit = (e) => { //toast("Testing from login page") @@ -629,12 +677,13 @@ const LoginPage = props => { width: "max-content", }} > -
+ Shuffle Logo { variant="body2" > {register - ? "Find new ways to automate by discovering usecases made by Shufflers" + ? "Find new ways to automate by discovering usecases Shufflers" : "Please fill in the information to continue to discover the power of Shuffle" } -
+
{isCloud ? "Email" : "Username"}
{
{!loginWithSSO && ( -
+
Password
{ flexDirection: "column", marginTop: "0px" }}> - {register && !loginWithSSO && ( + {isCloud && register && !loginWithSSO && ( { - if (!isCloud) { - toast.warn("Talk to your administrator") - } - }} style={{ ...hrefStyle, alignSelf: isMobile ? "center" : "flex-end" diff --git a/frontend/src/views/LoginPageOld.jsx b/frontend/src/views/LoginPageOld.jsx index aaf376cd..6b34b957 100755 --- a/frontend/src/views/LoginPageOld.jsx +++ b/frontend/src/views/LoginPageOld.jsx @@ -58,9 +58,9 @@ const LoginDialog = (props) => { // Used to swap from login to register. True = login, false = register - useEffect(() => { - checkAdmin() - }, [loginViewLoading]) + useEffect(() => { + checkAdmin() + }, [loginViewLoading]) // Error messages etc const [loginInfo, setLoginInfo] = useState(""); @@ -91,6 +91,8 @@ const LoginDialog = (props) => { if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) { setSSOUrl(responseJson.sso_url); } + + navigate("/login") if (loginViewLoading) { setLoginViewLoading(false); @@ -125,7 +127,7 @@ const LoginDialog = (props) => { callback: () => { checkAdmin(); }, - }); + }) if (firstRequest) { setFirstRequest(false); @@ -294,7 +296,7 @@ const LoginDialog = (props) => { style={{ marginBottom: 20, color: "white" }} > Waiting for the Shuffle database to become available. This may - take up to a minute. + take up to two minutes. {loginInfo === undefined ||