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}
+
+
+
+ )
+ })}
{
*/}
@@ -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 (
-