chore: Updating the login and signup page for cloud hosting as per new design (#32641)

## Description

Updating the login and signup page for cloud hosting as per new design

Fixes [#32267](https://github.com/appsmithorg/appsmith/issues/32267) 

## Automation

/ok-to-test tags="@tag.All"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/8723701550>
> Commit: 65a0179c5d22e1f950888c24a119af608aed2a28
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8723701550&attempt=4"
target="_blank">Click here!</a>

<!-- end of auto-generated comment: Cypress test results  -->




































<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced titles and messages across login, signup, and forgot password
pages for clarity and engagement.
- Added new analytics event for tracking visits to self-hosting
documentation.
- Introduced new content and layout adjustments in user authentication
pages to improve user experience.
- Implemented conditional rendering to optimize content display for
mobile devices and cloud hosting scenarios.

- **Bug Fixes**
	- Updated footer links to use consistent capitalization.

- **Refactor**
- Major structural and styling overhaul of forms and user authentication
components to utilize modern CSS practices and improve maintainability.

- **Documentation**
- Added direct links to self-hosting documentation to facilitate user
access.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Ankita Kinger 2024-04-17 21:46:44 +05:30 committed by GitHub
parent 313338899e
commit e07e3ecd04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 415 additions and 126 deletions

View File

@ -64,7 +64,7 @@ describe(
homePage.Signout();
// validating sso with github is enabled
assertHelper.AssertContains(
"Continue with Github",
"Github",
"be.visible",
adminSettingsLocators.loginWithGithub,
);
@ -110,7 +110,7 @@ describe(
homePage.Signout();
// validating sso with github is disabled
assertHelper.AssertContains(
"Continue with Github",
"Github",
"not.exist",
adminSettingsLocators.loginWithGithub,
);

View File

@ -61,10 +61,7 @@ describe(
cy.get(homePage.signOutIcon).click();
cy.wait(500);
// validating sso with google is enabled
cy.get(adminSettings.loginWithGoogle).should(
"have.text",
"Continue with Google",
);
cy.get(adminSettings.loginWithGoogle).should("have.text", "Google");
});
it("3. Go to admin settings and disable Google", function () {

View File

@ -111,7 +111,7 @@
"d3-geo": "^3.1.0",
"dayjs": "^1.10.6",
"deep-diff": "^1.0.2",
"design-system": "npm:@appsmithorg/design-system@2.1.36",
"design-system": "npm:@appsmithorg/design-system@2.1.37",
"design-system-old": "npm:@appsmithorg/design-system-old@1.1.16",
"downloadjs": "^1.4.7",
"echarts": "^5.4.2",

View File

@ -57,8 +57,7 @@ export const FORM_VALIDATION_INVALID_PASSWORD = FORM_VALIDATION_PASSWORD_RULE;
export const LOGIN_PAGE_EMAIL_INPUT_LABEL = () => `Email`;
export const LOGIN_PAGE_PASSWORD_INPUT_LABEL = () => `Password`;
export const LOGIN_PAGE_EMAIL_INPUT_PLACEHOLDER = () =>
`Enter your email address`;
export const LOGIN_PAGE_EMAIL_INPUT_PLACEHOLDER = () => `Enter your email`;
export const LOGIN_PAGE_PASSWORD_INPUT_PLACEHOLDER = () =>
`Enter your password`;
export const LOGIN_PAGE_INVALID_CREDS_ERROR = () =>
@ -66,25 +65,28 @@ export const LOGIN_PAGE_INVALID_CREDS_ERROR = () =>
export const LOGIN_PAGE_INVALID_CREDS_FORGOT_PASSWORD_LINK = () =>
`Reset password`;
export const NEW_TO_APPSMITH = () => `Don't have an account?`;
export const LOGIN_PAGE_TITLE = () => `Sign in`;
export const LOGIN_PAGE_TITLE = () => `Sign in to your account`;
export const LOGIN_PAGE_SUBTITLE = () => `Sign in to your account`;
export const LOGIN_PAGE_LOGIN_BUTTON_TEXT = () => `Sign in`;
export const LOGIN_PAGE_FORGOT_PASSWORD_TEXT = () => `Forgot password`;
export const LOGIN_PAGE_REMEMBER_ME_LABEL = () => `Remember`;
export const LOGIN_PAGE_SIGN_UP_LINK_TEXT = () => `Sign up`;
export const SIGNUP_PAGE_TITLE = () => `Create your free account`;
export const SIGNUP_PAGE_TITLE = () => `Create your account`;
export const SIGNUP_PAGE_SUBTITLE = () => `Use your workspace email`;
export const SIGNUP_PAGE_EMAIL_INPUT_LABEL = () => `Email`;
export const SIGNUP_PAGE_EMAIL_INPUT_PLACEHOLDER = () => `Email`;
export const SIGNUP_PAGE_EMAIL_INPUT_PLACEHOLDER = () => `Enter your email`;
export const SIGNUP_PAGE_NAME_INPUT_PLACEHOLDER = () => `Name`;
export const SIGNUP_PAGE_NAME_INPUT_LABEL = () => `Name`;
export const SIGNUP_PAGE_PASSWORD_INPUT_LABEL = () => `Password`;
export const SIGNUP_PAGE_PASSWORD_INPUT_PLACEHOLDER = () => `Password`;
export const SIGNUP_PAGE_PASSWORD_INPUT_PLACEHOLDER = () =>
`Enter your password`;
export const SIGNUP_PAGE_LOGIN_LINK_TEXT = () => `Sign in`;
export const SIGNUP_PAGE_NAME_INPUT_SUBTEXT = () => `How should we call you?`;
export const SIGNUP_PAGE_SUBMIT_BUTTON_TEXT = () => `Sign up`;
export const ALREADY_HAVE_AN_ACCOUNT = () => `Already have an account?`;
export const LOOKING_TO_SELF_HOST = () => "Looking to self-host Appsmith?";
export const VISIT_OUR_DOCS = () => "Visit our docs";
export const SIGNUP_PAGE_SUCCESS = () =>
`Awesome! You have successfully registered.`;
@ -110,11 +112,14 @@ export const RESET_PASSWORD_INVALID_TOKEN = () =>
export const RESET_PASSWORD_FORGOT_PASSWORD_LINK = () => `Forgot password`;
export const FORGOT_PASSWORD_PAGE_EMAIL_INPUT_LABEL = () => `Email`;
export const FORGOT_PASSWORD_PAGE_EMAIL_INPUT_PLACEHOLDER = () => `Email`;
export const FORGOT_PASSWORD_PAGE_EMAIL_INPUT_PLACEHOLDER = () =>
`Enter your email`;
export const FORGOT_PASSWORD_PAGE_TITLE = () => `Reset password`;
export const FORGOT_PASSWORD_PAGE_SUB_TITLE = () =>
`Enter the email address associated with your account`;
export const FORGOT_PASSWORD_PAGE_SUBTITLE = () =>
`We will send a reset link to the email below`;
export const FORGOT_PASSWORD_PAGE_SUBMIT_BUTTON_TEXT = () => `Reset`;
export const FORGOT_PASSWORD_PAGE_SUBMIT_BUTTON_TEXT = () => `Send reset link`;
export const FORGOT_PASSWORD_SUCCESS_TEXT = (email: string) =>
`A password reset link has been sent to your email address ${email} registered with Appsmith.`;
@ -122,12 +127,12 @@ export const VERIFICATION_PENDING_TITLE = () => `Check your inbox`;
export const VERIFICATION_PENDING_BODY = () =>
`To finish your account setup click on the verification link we have sent in an email to `;
export const VERIFICATION_PENDING_NOT_YOU = () => `(not you?)`;
export const VERIFICATION_PENDING_NOT_YOU = () => `Not you?`;
export const VERIFICATION_PENDING_NO_EMAIL = () =>
`No email in your inbox or spam folder?`;
export const VERIFICATION_PENDING_RESEND_LINK = () => `Resend the link`;
export const VERIFICATION_PENDING_RESEND_LINK = () => `Resend link`;
export const VERIFY_ERROR_ALREADY_VERIFIED_TITLE = () =>
`Email already verified`;

View File

@ -126,6 +126,8 @@ import AnalyticsUtil from "utils/AnalyticsUtil";
import { useIsMobileDevice } from "utils/hooks/useDeviceDetect";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import CreateNewAppFromTemplatesWrapper from "./CreateNewAppFromTemplateModal/CreateNewAppFromTemplatesWrapper";
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
export const { cloudHosting } = getAppsmithConfigs();
@ -644,7 +646,7 @@ export function ApplicationsSection(props: any) {
<div className="flex flex-col items-center justify-center mt-[180px]">
<img
className="mb-6"
src="https://assets.appsmith.com/no-workspace-found.svg"
src={`${getAssetUrl(`${ASSETS_CDN_URL}/no-workspace-found.svg`)}`}
/>
<NewText className="!mb-3 !font-semibold" kind="heading-s">
{createMessage(NO_WORKSPACE_HEADING)}

View File

@ -352,7 +352,8 @@ export type EventName =
| "MULTI_FILE_PICKER_EXCEEDS_LIMIT"
| "TEMPLATE_ADD_PAGE_FROM_TEMPLATE_FLOW"
| HOMEPAGE_CREATE_APP_FROM_TEMPLATE_EVENTS
| "EDITOR_MODE_CHANGE";
| "EDITOR_MODE_CHANGE"
| "VISIT_SELF_HOST_DOCS";
type HOMEPAGE_CREATE_APP_FROM_TEMPLATE_EVENTS =
| "TEMPLATE_DROPDOWN_CLICK"

View File

@ -2,7 +2,12 @@ import { Form } from "redux-form";
import styled from "styled-components";
const StyledForm = styled(Form)`
width: 100%;
display: flex;
flex-direction: column;
gap: 12px;
.bp3-form-group {
margin: 0;
}
`;
export default StyledForm;

View File

@ -7,6 +7,8 @@ export const GITHUB_RELEASE_URL =
"https://github.com/appsmithorg/appsmith/releases/tag";
export const GET_RELEASE_NOTES_URL = (tagName: string) =>
`${GITHUB_RELEASE_URL}/${tagName}`;
export const SELF_HOSTING_DOC =
"https://docs.appsmith.com/getting-started/setup";
export const GOOGLE_MAPS_SETUP_DOC =
"https://docs.appsmith.com/getting-started/setup/instance-configuration/google-maps";
export const GOOGLE_SIGNUP_SETUP_DOC =

View File

@ -1,9 +1,12 @@
import React from "react";
import { useSelector } from "react-redux";
import FooterLinks from "./FooterLinks";
import { getTenantConfig } from "@appsmith/selectors/tenantSelectors";
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
import LeftSideContent from "./LeftSideContent";
import { getAppsmithConfigs } from "@appsmith/configs";
import { useIsMobileDevice } from "utils/hooks/useDeviceDetect";
import styled from "styled-components";
interface ContainerProps {
title: string;
@ -14,38 +17,67 @@ interface ContainerProps {
testId?: string;
}
const ContainerWrapper = styled.div`
a {
span {
font-weight: 500;
}
}
`;
const BoxWrapper = styled.div<{ isMobileView: boolean }>`
box-shadow: 0px 1px 20px 0px rgba(76, 86, 100, 0.11);
border-radius: var(--ads-v2-border-radius);
background: var(--ads-v2-color-bg);
display: flex;
flex-direction: column;
gap: var(--ads-v2-spaces-5);
padding: 32px 24px;
${({ isMobileView }) =>
isMobileView ? "border: 1px solid var(--ads-v2-color-border);" : ""}
`;
function Container(props: ContainerProps) {
const { children, footer, subtitle, testId, title } = props;
const tenantConfig = useSelector(getTenantConfig);
const { cloudHosting } = getAppsmithConfigs();
const isMobileDevice = useIsMobileDevice();
return (
<div
className="flex flex-col items-center gap-4 my-auto min-w-min"
<ContainerWrapper
className={`gap-14 my-auto flex items-center justify-center min-w-min`}
data-testid={testId}
>
<div className="bg-white border border-t-4 border-[color:var(--ads-v2\-color-border)] border-t-[color:var(--ads-v2\-color-border-brand)] py-8 px-6 w-[min(400px,80%)] flex flex-col gap-6 t--login-container rounded-[var(--ads-v2\-border-radius)]">
<img
className="h-8 mx-auto"
src={getAssetUrl(tenantConfig.brandLogoUrl)}
/>
<div className="flex flex-col gap-2 text-center">
<h1 className="text-xl font-semibold text-center text-[color:var(--ads-v2\-color-fg-emphasis)]">
{title}
</h1>
{subtitle && (
<p className="text-base text-center text-[color:var(--ads-v2\-color-fg)]">
{subtitle}
</p>
)}
{cloudHosting && !isMobileDevice && <LeftSideContent />}
<BoxWrapper
className={`t--login-container ${
isMobileDevice ? "w-full" : "w-[min(400px,80%)]"
}`}
isMobileView={isMobileDevice}
>
{!isMobileDevice && (
<img
className="h-8 mx-auto"
src={getAssetUrl(tenantConfig.brandLogoUrl)}
/>
)}
<div className={`flex flex-col gap-4`}>
<div className="flex flex-col gap-2 text-center">
<h1 className="text-lg font-semibold text-center text-[color:var(--ads-v2\-color-fg-emphasis)]">
{title}
</h1>
{subtitle && (
<p className="text-[14px] text-center text-[color:var(--ads-v2\-color-fg)]">
{subtitle}
</p>
)}
</div>
{children}
{footer}
</div>
{children}
</div>
<div className="bg-white border w-[min(400px,80%)] rounded-[var(--ads-v2\-border-radius)] border-[color:var(--ads-v2\-color-border)]">
{footer}
<FooterLinks />
</div>
</div>
</BoxWrapper>
</ContainerWrapper>
);
}

View File

@ -1,16 +1,35 @@
import React from "react";
import { Link } from "design-system";
import styled from "styled-components";
const FooterWrapper = styled.div`
width: 85%;
margin: 0 auto;
text-align: center;
a {
display: inline;
span {
display: inline;
svg {
display: inline;
}
}
}
`;
function FooterLinks() {
return (
<div className="flex items-center justify-center gap-4 px-2 py-2">
<FooterWrapper>
By using Appsmith, you are agreeing to our &nbsp;
<Link target="_blank" to="/privacy-policy.html">
Privacy policy
privacy policy
</Link>
&nbsp; and &nbsp;
<Link target="_blank" to="/terms-and-conditions.html">
Terms and conditions
terms of service
</Link>
</div>
.
</FooterWrapper>
);
}

View File

@ -14,14 +14,14 @@ import {
FORM_VALIDATION_EMPTY_EMAIL,
FORM_VALIDATION_INVALID_EMAIL,
FORGOT_PASSWORD_SUCCESS_TEXT,
FORGOT_PASSWORD_PAGE_LOGIN_LINK,
createMessage,
FORGOT_PASSWORD_PAGE_SUB_TITLE,
} from "@appsmith/constants/messages";
import { AUTH_LOGIN_URL } from "constants/routes";
import { FORGOT_PASSWORD_FORM_NAME } from "@appsmith/constants/forms";
import FormTextField from "components/utils/ReduxFormTextField";
import { FormGroup } from "design-system-old";
import { Button, Link, Callout } from "design-system";
import { Button, Link, Callout, Icon } from "design-system";
import { isEmail, isEmptyString } from "utils/formhelpers";
import type { ForgotPasswordFormValues } from "./helpers";
import { forgotPasswordSubmitHandler } from "./helpers";
@ -58,18 +58,25 @@ export const ForgotPassword = (props: ForgotPasswordProps) => {
}
}, [props.emailValue]);
const footerSection = (
<div className="px-2 flex items-center justify-center text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
<Icon name="arrow-left-line" size="md" />
&nbsp;Back to&nbsp;
<Link
className="text-sm justify-center"
kind="primary"
target="_self"
to={AUTH_LOGIN_URL}
>
Sign in
</Link>
</div>
);
return (
<Container
subtitle={
<Link
className="text-sm justify-center"
startIcon="arrow-left-line"
target="_self"
to={AUTH_LOGIN_URL}
>
{createMessage(FORGOT_PASSWORD_PAGE_LOGIN_LINK)}
</Link>
}
footer={footerSection}
subtitle={createMessage(FORGOT_PASSWORD_PAGE_SUB_TITLE)}
title={createMessage(FORGOT_PASSWORD_PAGE_TITLE)}
>
<FormMessagesContainer>

View File

@ -0,0 +1,119 @@
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
import React from "react";
import styled from "styled-components";
import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
import { Avatar } from "design-system";
const Wrapper = styled.div`
width: 432px;
.left-description {
padding-bottom: 24px;
border-bottom: 1px solid var(--ads-v2-color-border);
display: flex;
flex-direction: column;
gap: var(--ads-spaces-4);
}
.left-description-container {
width: 100%;
margin: 0 auto;
font-size: 16px;
font-style: italic;
color: var(--ads-v2-color-gray-800);
}
.left-description-author {
display: flex;
align-items: center;
gap: var(--ads-spaces-3);
}
.left-description-author > div {
font-weight: 500;
font-size: 12px;
}
.dot {
font-weight: 800;
}
.client-logo-container {
padding-top: 24px;
}
.client-heading {
font-size: 12px;
font-weight: normal;
line-height: 1.33;
text-align: center;
margin-bottom: 24px;
}
.client-logo-container img {
height: 30px;
}
.client-logo-container .client-logo-section {
display: flex;
justify-content: space-around;
margin-bottom: 24px;
gap: var(--ads-spaces-3);
flex-wrap: wrap;
}
`;
function LeftSideContent() {
return (
<Wrapper>
<div className="left-description">
<div className="left-description-container">
&quot;Wed been looking for a tool like Appsmith for years. With
Appsmith we were able to build a UI on top of 12 different Snowflake
control tables. Appsmith was easy for our developers to learn, and
its easy to implement.&quot;
</div>
<div className="left-description-author">
<Avatar
image={`${getAssetUrl(`${ASSETS_CDN_URL}/thomas-zwick.png`)}`}
label="Thomas Zwick"
size="sm"
/>
<div>Thomas Zwick</div>
<div className="dot">&#183;</div>
<div>Director, Omron</div>
</div>
</div>
<div className="client-logo-container">
<div className="client-heading">
Used by more than 10,000 organisations across the globe
</div>
<div className="client-logo-section">
<img
alt="GSK logo"
src={`${getAssetUrl(`${ASSETS_CDN_URL}/gsk-logo-grey.svg`)}`}
/>
<img
alt="Omron logo"
src={`${getAssetUrl(`${ASSETS_CDN_URL}/omron-logo.svg`)}`}
/>
<img
alt="Dropbox logo"
src={`${getAssetUrl(`${ASSETS_CDN_URL}/dropbox-text-logo.svg`)}`}
/>
<img
alt="AWS logo"
src={`${getAssetUrl(`${ASSETS_CDN_URL}/aws-logo-grey.svg`)}`}
/>
<img
alt="Twilio logo"
src={`${getAssetUrl(`${ASSETS_CDN_URL}/twilio-logo.svg`)}`}
/>
</div>
</div>
</Wrapper>
);
}
export default LeftSideContent;

View File

@ -24,7 +24,6 @@ import {
LOGIN_PAGE_INVALID_CREDS_FORGOT_PASSWORD_LINK,
NEW_TO_APPSMITH,
createMessage,
LOGIN_PAGE_SUBTITLE,
} from "@appsmith/constants/messages";
import { FormGroup } from "design-system-old";
import { Button, Link, Callout } from "design-system";
@ -33,7 +32,11 @@ import ThirdPartyAuth from "pages/UserAuth/ThirdPartyAuth";
import { isEmail, isEmptyString } from "utils/formhelpers";
import type { LoginFormValues } from "pages/UserAuth/helpers";
import { SpacedSubmitForm, FormActions } from "pages/UserAuth/StyledComponents";
import {
SpacedSubmitForm,
FormActions,
EmailFormWrapper,
} from "pages/UserAuth/StyledComponents";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { LOGIN_SUBMIT_PATH } from "@appsmith/constants/ApiConstants";
import PerformanceTracker, {
@ -125,10 +128,10 @@ export function Login(props: LoginFormProps) {
}
const footerSection = isFormLoginEnabled && (
<div className="px-2 py-4 flex align-center justify-center text-base text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
{createMessage(NEW_TO_APPSMITH)}
<div className="px-2 flex align-center justify-center text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
{createMessage(NEW_TO_APPSMITH)}&nbsp;
<Link
className="t--sign-up t--signup-link pl-[var(--ads-v2\-spaces-3)]"
className="t--sign-up t--signup-link"
kind="primary"
target="_self"
to={signupURL}
@ -139,11 +142,7 @@ export function Login(props: LoginFormProps) {
);
return (
<Container
footer={footerSection}
subtitle={createMessage(LOGIN_PAGE_SUBTITLE)}
title={createMessage(LOGIN_PAGE_TITLE)}
>
<Container footer={footerSection} title={createMessage(LOGIN_PAGE_TITLE)}>
<Helmet>
<title>{htmlPageTitle}</title>
</Helmet>
@ -171,7 +170,7 @@ export function Login(props: LoginFormProps) {
<ThirdPartyAuth logins={socialLoginList} type={"SIGNIN"} />
)}
{isFormLoginEnabled && (
<>
<EmailFormWrapper>
<SpacedSubmitForm action={loginURL} method="POST">
<FormGroup
intent={error ? "danger" : "none"}
@ -218,12 +217,13 @@ export function Login(props: LoginFormProps) {
</SpacedSubmitForm>
<Link
className="justify-center"
kind="secondary"
target="_self"
to={forgotPasswordURL}
>
{createMessage(LOGIN_PAGE_FORGOT_PASSWORD_TEXT)}
</Link>
</>
</EmailFormWrapper>
)}
</Container>
);

View File

@ -9,7 +9,7 @@ import { RESET_PASSWORD_FORM_NAME } from "@appsmith/constants/forms";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { getIsTokenValid, getIsValidatingToken } from "selectors/authSelectors";
import FormTextField from "components/utils/ReduxFormTextField";
import { Button, Callout, Link } from "design-system";
import { Button, Callout, Icon, Link } from "design-system";
import Spinner from "components/editorComponents/Spinner";
import StyledForm from "components/editorComponents/Form";
import { isEmptyString, isStrongPassword } from "utils/formhelpers";
@ -20,7 +20,6 @@ import { AUTH_LOGIN_URL, FORGOT_PASSWORD_URL } from "constants/routes";
import {
RESET_PASSWORD_PAGE_PASSWORD_INPUT_LABEL,
RESET_PASSWORD_PAGE_PASSWORD_INPUT_PLACEHOLDER,
RESET_PASSWORD_LOGIN_LINK_TEXT,
RESET_PASSWORD_SUBMIT_BUTTON_TEXT,
RESET_PASSWORD_PAGE_TITLE,
FORM_VALIDATION_INVALID_PASSWORD,
@ -153,18 +152,25 @@ export function ResetPassword(props: ResetPasswordProps) {
if (!isTokenValid && validatingToken) {
return <Spinner />;
}
const footerSection = (
<div className="px-2 flex items-center justify-center text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
<Icon name="arrow-left-line" size="md" />
&nbsp; Back to &nbsp;
<Link
className="text-sm justify-center"
kind="primary"
target="_self"
to={AUTH_LOGIN_URL}
>
Sign in
</Link>
</div>
);
return (
<Container
subtitle={
<Link
className="text-sm justify-center"
startIcon="arrow-left-line"
target="_self"
to={AUTH_LOGIN_URL}
>
{createMessage(RESET_PASSWORD_LOGIN_LINK_TEXT)}
</Link>
}
footer={footerSection}
title={createMessage(RESET_PASSWORD_PAGE_TITLE)}
>
{(showSuccessMessage || showFailureMessage) && (

View File

@ -5,7 +5,11 @@ import { AUTH_LOGIN_URL } from "constants/routes";
import { SIGNUP_FORM_NAME } from "@appsmith/constants/forms";
import type { RouteComponentProps } from "react-router-dom";
import { useHistory, useLocation, withRouter } from "react-router-dom";
import { SpacedSubmitForm, FormActions } from "pages/UserAuth/StyledComponents";
import {
SpacedSubmitForm,
FormActions,
OrWithLines,
} from "pages/UserAuth/StyledComponents";
import {
SIGNUP_PAGE_TITLE,
SIGNUP_PAGE_EMAIL_INPUT_LABEL,
@ -19,8 +23,9 @@ import {
SIGNUP_PAGE_SUBMIT_BUTTON_TEXT,
ALREADY_HAVE_AN_ACCOUNT,
createMessage,
SIGNUP_PAGE_SUBTITLE,
GOOGLE_RECAPTCHA_KEY_ERROR,
LOOKING_TO_SELF_HOST,
VISIT_OUR_DOCS,
} from "@appsmith/constants/messages";
import FormTextField from "components/utils/ReduxFormTextField";
import ThirdPartyAuth from "pages/UserAuth/ThirdPartyAuth";
@ -54,13 +59,14 @@ import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { getHTMLPageTitle } from "@appsmith/utils/BusinessFeatures/brandingPageHelpers";
import log from "loglevel";
import { SELF_HOSTING_DOC } from "constants/ThirdPartyConstants";
declare global {
interface Window {
grecaptcha: any;
}
}
const { googleRecaptchaSiteKey } = getAppsmithConfigs();
const { cloudHosting, googleRecaptchaSiteKey } = getAppsmithConfigs();
const validate = (values: SignupFormValues) => {
const errors: SignupFormValues = {};
@ -171,25 +177,40 @@ export function SignUp(props: SignUpFormProps) {
};
const footerSection = (
<div className="px-2 py-4 flex align-center justify-center text-base text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
{createMessage(ALREADY_HAVE_AN_ACCOUNT)}
<Link
className="t--sign-up t--signup-link pl-[var(--ads-v2\-spaces-3)]"
kind="primary"
target="_self"
to={AUTH_LOGIN_URL}
>
{createMessage(SIGNUP_PAGE_LOGIN_LINK_TEXT)}
</Link>
</div>
<>
<div className="px-2 flex align-center justify-center text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
{createMessage(ALREADY_HAVE_AN_ACCOUNT)}&nbsp;
<Link
className="t--sign-up t--signup-link"
kind="primary"
target="_self"
to={AUTH_LOGIN_URL}
>
{createMessage(SIGNUP_PAGE_LOGIN_LINK_TEXT)}
</Link>
</div>
{cloudHosting && (
<>
<OrWithLines>or</OrWithLines>
<div className="px-2 text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
{createMessage(LOOKING_TO_SELF_HOST)}
<Link
className="t--visit-docs t--visit-docs-link pl-[var(--ads-v2\-spaces-3)] justify-center"
kind="primary"
onClick={() => AnalyticsUtil.logEvent("VISIT_SELF_HOST_DOCS")}
target="_self"
to={`${SELF_HOSTING_DOC}?utm_source=cloudSignup`}
>
{createMessage(VISIT_OUR_DOCS)}
</Link>
</div>
</>
)}
</>
);
return (
<Container
footer={footerSection}
subtitle={createMessage(SIGNUP_PAGE_SUBTITLE)}
title={createMessage(SIGNUP_PAGE_TITLE)}
>
<Container footer={footerSection} title={createMessage(SIGNUP_PAGE_TITLE)}>
<Helmet>
<title>{htmlPageTitle}</title>
</Helmet>

View File

@ -98,6 +98,9 @@ export const AuthCardBody = styled.div`
export const SpacedForm = styled(Form)``;
export const SpacedSubmitForm = styled.form`
display: flex;
flex-direction: column;
gap: 12px;
&& .bp3-label {
color: var(--ads-v2-color-fg);
margin-bottom: var(--ads-v2-spaces-2);
@ -108,6 +111,15 @@ export const SpacedSubmitForm = styled.form`
&:only-child {
margin-right: 0;
}
.bp3-form-group {
margin: 0;
}
`;
export const EmailFormWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
`;
export const FormActions = styled.div`
@ -117,7 +129,6 @@ export const FormActions = styled.div`
}
justify-content: space-between;
align-items: baseline;
margin-top: ${(props) => props.theme.spaces[5]}px;
& > label {
margin-right: ${(props) => props.theme.spaces[11]}px;
}
@ -158,3 +169,29 @@ export const StyledFormGroup = styled(FormGroup)`
margin-bottom: var(--ads-v2-spaces-2);
}
`;
export const OrWithLines = styled.div`
overflow: hidden;
text-align: center;
&::before,
&::after {
background-color: var(--ads-v2-color-border);
content: "";
display: inline-block;
height: 1px;
position: relative;
vertical-align: middle;
width: 50%;
}
&::before {
right: 0.5em;
margin-left: -50%;
}
&::after {
left: 0.5em;
margin-right: -50%;
}
`;

View File

@ -12,12 +12,24 @@ import { Button } from "design-system";
const ThirdPartyAuthWrapper = styled.div`
display: flex;
flex-direction: column;
gap: var(--ads-v2-spaces-3);
width: 100%;
flex-wrap: wrap;
`;
const StyledButton = styled(Button)`
flex: 1 0 171px;
`;
type SignInType = "SIGNIN" | "SIGNUP";
const startIcon: {
[key: string]: string;
} = {
Google: "google-colored",
Github: "github-fill",
};
function SocialLoginButton(props: {
logo: string;
name: string;
@ -33,7 +45,7 @@ function SocialLoginButton(props: {
url += `?redirectUrl=${encodeURIComponent(redirectUrl)}`;
}
return (
<Button
<StyledButton
href={url}
kind="secondary"
onClick={() => {
@ -55,14 +67,14 @@ function SocialLoginButton(props: {
size="md"
startIcon={
["Google", "Github"].includes(props.name)
? props.name.toLowerCase() + `-fill`
? startIcon[props.name]
: "key-2-line"
}
>
<div className="login-method" data-testid={`login-with-${props.name}`}>
{props.label ?? `Continue with ${props.name}`}
{props.label ?? `${props.name}`}
</div>
</Button>
</StyledButton>
);
}

View File

@ -1,11 +1,10 @@
import React, { useEffect } from "react";
import Container from "./Container";
import { Button, Callout, Link, Text } from "design-system";
import { Button, Callout, Icon, Link, Text } from "design-system";
import { AUTH_LOGIN_URL } from "constants/routes";
import {
createMessage,
DEFAULT_ERROR_MESSAGE,
FORGOT_PASSWORD_PAGE_LOGIN_LINK,
PAGE_CLIENT_ERROR_DESCRIPTION,
VERIFY_ERROR_ALREADY_VERIFIED_TITLE,
VERIFY_ERROR_EXPIRED_TITLE,
@ -97,14 +96,16 @@ const VerificationError = (
return (
<Container
footer={
<div className="px-2 py-4 flex align-center justify-center text-base text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
<div className="px-2 py-4 flex items-center justify-center text-base text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
<Icon name="arrow-left-line" size="md" />
&nbsp; Back to &nbsp;
<Link
className="pl-[var(--ads-v2\-spaces-3)]"
className="text-sm justify-center pl-[var(--ads-v2\-spaces-3)]"
kind="primary"
target="_self"
to={AUTH_LOGIN_URL}
>
{createMessage(FORGOT_PASSWORD_PAGE_LOGIN_LINK)}
Sign in
</Link>
</div>
}

View File

@ -2,7 +2,6 @@ import React from "react";
import Container from "./Container";
import {
createMessage,
VERIFICATION_PENDING_BODY,
VERIFICATION_PENDING_NO_EMAIL,
VERIFICATION_PENDING_NOT_YOU,
VERIFICATION_PENDING_RESEND_LINK,
@ -33,16 +32,21 @@ const VerificationPending = (props: RouteComponentProps<{ email: string }>) => {
return (
<Container
footer={
<div className="px-2 flex align-center justify-center text-center text-[color:var(--ads-v2\-color-fg)] text-[14px]">
<Link kind="primary" target="_self" to={AUTH_LOGIN_URL}>
{createMessage(VERIFICATION_PENDING_NOT_YOU)}
</Link>
</div>
}
testId="verification-pending"
title={createMessage(VERIFICATION_PENDING_TITLE)}
>
<Body>
<Text kind={"body-m"}>
{createMessage(VERIFICATION_PENDING_BODY)} <Email>{email}</Email>
Click the verification link sent to <Email>{email}</Email> to finish
setting up your account.
</Text>
<Link kind="primary" target="_self" to={AUTH_LOGIN_URL}>
{createMessage(VERIFICATION_PENDING_NOT_YOU)}
</Link>
</Body>
<Body>
<Text kind="body-m">

View File

@ -14,6 +14,11 @@ import { ThemeProvider } from "styled-components";
import VerificationPending from "./VerificationPending";
import VerifyUser from "./VerifyUser";
import VerificationError from "./VerificationError";
import FooterLinks from "./FooterLinks";
import { useIsMobileDevice } from "utils/hooks/useDeviceDetect";
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
import { getTenantConfig } from "@appsmith/selectors/tenantSelectors";
import { getAppsmithConfigs } from "@appsmith/configs";
const SentryRoute = Sentry.withSentryRouting(Route);
@ -23,11 +28,24 @@ export function UserAuth() {
const lightTheme = useSelector((state: AppState) =>
getThemeDetails(state, ThemeMode.LIGHT),
);
const isMobileDevice = useIsMobileDevice();
const tenantConfig = useSelector(getTenantConfig);
const { cloudHosting } = getAppsmithConfigs();
return (
<ThemeProvider theme={lightTheme}>
{/* TODO: (Albin) - chnages this to ads-v2 variable once branding is sorted out. */}
<div className="absolute inset-0 flex flex-col overflow-y-auto auth-container bg-[color:var(--ads-color-background-secondary)] p-4 t--auth-container">
<div
className={`absolute inset-0 flex flex-col overflow-y-auto auth-container bg-[color:var(--ads-color-background-secondary)] ${
!isMobileDevice ? "p-4" : "px-6 py-12"
} t--auth-container justify-between`}
>
{isMobileDevice && (
<img
className="h-8 mx-auto"
src={getAssetUrl(tenantConfig.brandLogoUrl)}
/>
)}
<Switch location={location}>
<SentryRoute component={Login} exact path={`${path}/login`} />
<SentryRoute component={SignUp} exact path={`${path}/signup`} />
@ -54,6 +72,7 @@ export function UserAuth() {
/>
<SentryRoute component={PageNotFound} />
</Switch>
{cloudHosting && <FooterLinks />}
</div>
</ThemeProvider>
);

View File

@ -13257,7 +13257,7 @@ __metadata:
d3-geo: ^3.1.0
dayjs: ^1.10.6
deep-diff: ^1.0.2
design-system: "npm:@appsmithorg/design-system@2.1.36"
design-system: "npm:@appsmithorg/design-system@2.1.37"
design-system-old: "npm:@appsmithorg/design-system-old@1.1.16"
diff: ^5.0.0
dotenv: ^8.1.0
@ -17288,9 +17288,9 @@ __metadata:
languageName: node
linkType: hard
"design-system@npm:@appsmithorg/design-system@2.1.36":
version: 2.1.36
resolution: "@appsmithorg/design-system@npm:2.1.36"
"design-system@npm:@appsmithorg/design-system@2.1.37":
version: 2.1.37
resolution: "@appsmithorg/design-system@npm:2.1.37"
dependencies:
"@radix-ui/react-dialog": ^1.0.2
"@radix-ui/react-dropdown-menu": ^2.0.4
@ -17320,7 +17320,7 @@ __metadata:
react-dom: ^17.0.2
react-router-dom: ^5.0.0
styled-components: ^5.3.6
checksum: 410db12c576560c6195d5b9ed776f1172c00985966b39d75fbfff119694f2227c94521e5e6d1c3068dd2d49fbac37975c2bc05b1284a09ef434ac7bd551bf84c
checksum: 012936cc603bf5c21bcd6486c35935bc22171f2243dd988cb93f92ed559fcd3245561ceda2f791845dce559de942c2acce8cde1fc8c3d30d45c24d4768aedf72
languageName: node
linkType: hard