diff --git a/frontend/src/components/Billing.jsx b/frontend/src/components/Billing.jsx index 3be59424..44e36334 100644 --- a/frontend/src/components/Billing.jsx +++ b/frontend/src/components/Billing.jsx @@ -1210,8 +1210,8 @@ const Billing = memo((props) => { } const url = userdata.licensed === true - ? "https://book.stripe.com/6oEeY23fw2T84M06oq" - : "https://book.stripe.com/00g6rw3fw9hwguI289" + ? "https://buy.stripe.com/aEU3fk17o0L092g5kt" + : "https://buy.stripe.com/aEU3fk17o0L092g5kt" window.open(url, "_blank") }} > diff --git a/frontend/src/components/ssoTab.jsx b/frontend/src/components/ssoTab.jsx index 8f39a296..5034f521 100644 --- a/frontend/src/components/ssoTab.jsx +++ b/frontend/src/components/ssoTab.jsx @@ -7,11 +7,7 @@ import { Tooltip, TextField, Grid, - Skeleton, - Dialog, - DialogTitle, - DialogContent, - Box, + Checkbox } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { Link } from "react-router-dom"; @@ -30,6 +26,8 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle const classes = useStyles(); const [show2faSetup, setShow2faSetup] = React.useState(false); const [autoPrivision, setAutoProvision] = React.useState(selectedOrganization?.sso_config?.auto_provision) + const [showOpenIdCred, setShowOpenIdCred] = React.useState(false); + const [showSamlCred, setShowSamlCred] = React.useState(false); const [ssoEntrypoint, setSsoEntrypoint] = React.useState( selectedOrganization.sso_config === undefined ? "" @@ -393,7 +391,27 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle IdP URL for Shuffle OpenID: {`${globalUrl}/api/v1/login_openid`} - + +
+ + Show OpenID Credentials + + setShowOpenIdCred(e.target.checked)} + name="showOpenIdCred" + color="primary" + style={{ color: "rgba(255, 255, 255, 1)", }} + /> +
@@ -407,30 +425,29 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor, }} fullWidth={true} - type="name" multiline={true} rows={2} id="outlined-with-placeholder" margin="normal" variant="outlined" placeholder="The OpenID client ID from the identity provider" - value={openidClientId} - onChange={(e) => { - setOpenidClientId(e.target.value); - }} + value={showOpenIdCred ? openidClientId : openidClientId?.length > 0 ? "•".repeat(50) : ""} + onChange={(e) => setOpenidClientId(e.target.value)} + onFocus={(e) => setShowOpenIdCred(true)} + onBlur={(e) => setShowOpenIdCred(false)} InputProps={{ classes: { - notchedOutline: isEditOrgTab ? null : classes.notchedOutline, + notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { - color: "white", - fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", - fontWeight: 400, - fontSize: 16, - borderRadius: 4, + color: "white", + fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", + fontWeight: 400, + fontSize: 16, + borderRadius: 4, }, }} - /> + /> @@ -445,17 +462,19 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor, }} fullWidth={true} - type="name" + type={showOpenIdCred ? "text" : "password"} multiline={true} rows={2} id="outlined-with-placeholder" margin="normal" variant="outlined" placeholder="The OpenID client secret - DONT use this if dealing with implicit auth / PKCE" - value={openidClientSecret} + value={showOpenIdCred ? openidClientSecret : openidClientSecret?.length > 0 ? "•".repeat(50) : ""} onChange={(e) => { setOpenidClientSecret(e.target.value); - }} + }} + onFocus={(e) => setShowOpenIdCred(true)} + onBlur={(e) => setShowOpenIdCred(false)} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, @@ -485,17 +504,19 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor, }} fullWidth={true} - type="name" + type={showOpenIdCred ? "text" : "password"} id="outlined-with-placeholder" margin="normal" variant="outlined" multiline={true} rows={2} placeholder="The OpenID authorization URL (usually ends with /authorize)" - value={openidAuthorization} + value={showOpenIdCred ? openidAuthorization : openidAuthorization?.length > 0 ? "•".repeat(50) : ""} onChange={(e) => { setOpenidAuthorization(e.target.value) - }} + }} + onFocus={(e) => setShowOpenIdCred(true)} + onBlur={(e) => setShowOpenIdCred(false)} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, @@ -523,17 +544,19 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor, }} fullWidth={true} - type="name" + type={showOpenIdCred ? "text" : "password"} id="outlined-with-placeholder" margin="normal" variant="outlined" multiline={true} rows={2} placeholder="The OpenID token URL (usually ends with /token)" - value={openidToken} + value={showOpenIdCred ? openidToken : openidToken?.length > 0 ? "•".repeat(50) : ""} onChange={(e) => { setOpenidToken(e.target.value) - }} + }} + onFocus={(e) => setShowOpenIdCred(true)} + onBlur={(e) => setShowOpenIdCred(false)} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, @@ -557,7 +580,27 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle SAML SSO (v1.1) IdP URL for Shuffle SAML/SSO: {`${globalUrl}/api/v1/login_sso`} - + +
+ + Show SAML Credentials + + setShowSamlCred(e.target.checked)} + name="showSamlCred" + color="primary" + style={{ color: "rgba(255, 255, 255, 1)", }} + /> +
@@ -571,17 +614,19 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor, }} fullWidth={true} - type="name" + type={showSamlCred ? "text" : "password"} multiline={true} rows={2} id="outlined-with-placeholder" margin="normal" variant="outlined" placeholder="The entrypoint URL from your provider" - value={ssoEntrypoint} + value={showSamlCred ? ssoEntrypoint : ssoEntrypoint?.length > 0 ? "•".repeat(50) : ""} onChange={(e) => { setSsoEntrypoint(e.target.value); - }} + }} + onFocus={(e) => setShowSamlCred(true)} + onBlur={(e) => setShowSamlCred(false)} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, @@ -609,14 +654,16 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle backgroundColor: isEditOrgTab ? "rgba(33, 33, 33, 1)" : theme.palette.inputColor, }} fullWidth={true} - type="name" + type={showSamlCred ? "text" : "password"} id="outlined-with-placeholder" margin="normal" variant="outlined" multiline={true} rows={2} placeholder="The X509 certificate to use" - value={ssoCertificate} + value={showSamlCred ? ssoCertificate : ssoCertificate?.length > 0 ? "•".repeat(50) : ""} + onFocus={(e) => setShowSamlCred(true)} + onBlur={(e) => setShowSamlCred(false)} onChange={(e) => { setSsoCertificate(e.target.value); }} @@ -646,4 +693,4 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle ) } -export default SSOTab \ No newline at end of file +export default SSOTab diff --git a/frontend/src/views/LoginPage.jsx b/frontend/src/views/LoginPage.jsx index ede54153..9bcc6966 100755 --- a/frontend/src/views/LoginPage.jsx +++ b/frontend/src/views/LoginPage.jsx @@ -5,8 +5,8 @@ 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 VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; import { ConnectingAirportsOutlined, ConstructionOutlined, @@ -81,21 +81,6 @@ const useStyles = makeStyles({ notchedOutline: { borderColor: "#f85a3e !important" }, - marketplaceButton: { - width: "100%", - justifyContent: "flex-start", - padding: "12px", - marginBottom: "12px", - backgroundColor: "#1A1A1A", - border: "1px solid #494949", - borderRadius: "8px", - color: "white", - opacity: 0.7, - '&:hover': { - opacity: 1, - cursor: "not-allowed", - }, - }, marketplaceIcon: { width: 28, height: 28, @@ -174,6 +159,14 @@ const FreePlanCard = ({ classes }) => { const MarketplaceCard = ({ classes }) => { const marketplaceOptions = [ + { + name: "Open Source Install", + logo: "https://static.cdnlogo.com/logos/g/69/github-icon.svg", + tooltipText: "Click to install!", + valid: true, + + link: "https://github.com/shuffle/shuffle/blob/main/.github/install-guide.md" + }, { name: "Amazon Web Services", logo: "https://cdn.cdnlogo.com/logos/a/19/aws.svg", @@ -213,31 +206,50 @@ const MarketplaceCard = ({ classes }) => { Self Host - {marketplaceOptions.map((option, index) => ( - - - - ))} + style={{ + width: "100%", + justifyContent: "flex-start", + padding: "12px", + marginBottom: "12px", + backgroundColor: "#1A1A1A", + border: "1px solid #494949", + borderRadius: "8px", + color: "white", + opacity: 0.7, + cursor: option.valid === true ? "pointer" : "not-allowed", + }} + disabled={option.valid === false} + > + {option.name} + + {option.name} + + + + ) + })}
{ */} @@ -282,7 +294,7 @@ const LoginPage = props => { const [register, setRegister] = useState(inregister); const [checkboxClicked, setCheckboxClicked] = useState(false); const [loginWithSSO, setLoginWithSSO] = useState(false) - + const [showPassword, setShowPassword] = useState(false) const [ssoUrl, setSSOUrl] = useState(""); const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "migration.shuffler.io"; @@ -315,7 +327,15 @@ const LoginPage = props => { } else { document.title = "Register to Shuffle SaaS" } - } + } + + useEffect(() => { + + if (loginWithSSO && window?.location?.pathname === "/register") { + setLoginWithSSO(false) + } + + },[window?.location?.pathname]) // Just a way to force location loading properly // Register & login should be split :3 @@ -354,7 +374,8 @@ const LoginPage = props => { color: "white", padding: "40px", flex: 1, - maxWidth: isMobile ? "100%" : "550px", + maxWidth: isMobile ? "100%" : 410, + minWidth: 410, background: "#212121", borderRadius: "12px", display: "flex", @@ -649,26 +670,16 @@ const LoginPage = props => { setLoginWithSSO(true) } - //const onClickRegister = () => { - // if (props.location.pathname === "/login") { - // window.location.pathname = "/register" - // } else { - // window.location.pathname = "/login" - // } - - // setLoginCheck(!register) - //} - - //var loginChange = register ? (

Want to register? Click here.

) : (

Go back to login? Click here.

); var formtitle = register ?
Welcome Back!
:
Create your account
var formButton = !isCloud ? "" : register ?
Don’t have an account yet?
Register here
: <> +
Already have an account?
Login here
//
Click here to Login
// {formtitle} - const buttonBackground = "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)" + const buttonBackground = "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)" const buttonStyle = { borderRadius: 25, height: 50, fontSize: 18, backgroundImage: handleValidateForm(username, password) || loginLoading || (checkboxClicked && register) ? buttonBackground : "grey", color: "white" } //
- {ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ? ( + {( + ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length) > 0 + //|| (isCloud && !loginWithSSO && window?.location?.pathname !== "/register") + ? (
Or
@@ -916,11 +944,17 @@ const LoginPage = props => { color="secondary" variant="outlined" type="button" - style={{ flex: "1", marginTop: 5 }} - onClick={() => { + style={{ flex: "1", marginTop: 5, textTransform: 'none', fontSize: 16 }} + onClick={(e) => { //console.log("CLICK SSO"); - window.location.href = ssoUrl + e.preventDefault(); //navigate(ssoUrl) + if (isCloud) { + setLoginWithSSO(true) + setPassword("") + }else { + window.location.href = ssoUrl + } }} > Use SSO @@ -928,6 +962,19 @@ const LoginPage = props => {
) : null} + {isCloud && loginWithSSO && ( + + )} @@ -951,7 +998,7 @@ const LoginPage = props => { return ( -
+
{loadedCheck}
)