Skip to content

Commit

Permalink
feat(auth): cleaned up reset password UI (#4671)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeldking authored Sep 19, 2024
1 parent 3bef099 commit ee3ef81
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 63 deletions.
4 changes: 4 additions & 0 deletions app/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export PHOENIX_SECRET=sa18f44bd9b6b4b0606e58a2d03d09039aee8283e0074c6517fda58577a07dd#A
export PHOENIX_ENABLE_AUTH=True
export PHOENIX_SMTP_HOSTNAME=smtp.sendgrid.net
export PHOENIX_SMTP_PORT=587
export PHOENIX_SMTP_USERNAME=apikey
export PHOENIX_SMTP_PASSWORD=XXXXXXXXXXXXXXXX
30 changes: 12 additions & 18 deletions app/src/pages/auth/ForgotPasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ type ForgotPasswordFormParams = {
email: string;
};

export function ForgotPasswordForm() {
const [message, setMessage] = useState<string | null>(null);
export function ForgotPasswordForm({
onResetSent,
}: {
onResetSent: () => void;
}) {
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const onSubmit = useCallback(
async (params: ForgotPasswordFormParams) => {
setMessage(null);
setError(null);
setIsLoading(true);
try {
Expand All @@ -26,31 +28,22 @@ export function ForgotPasswordForm() {
body: JSON.stringify(params),
});
if (!response.ok) {
setError("Failed attempt");
const message = await response.text();
setError(message);
return;
}
} catch (error) {
setError("Failed attempt");
return;
onResetSent();
} finally {
setIsLoading(() => false);
}
setMessage(
"A link to reset your password has been sent. Check your email for details."
);
},
[setMessage, setError]
[onResetSent, setError]
);
const { control, handleSubmit } = useForm<ForgotPasswordFormParams>({
defaultValues: { email: "" },
});
return (
<>
{message ? (
<View paddingBottom="size-100">
<Alert variant="success">{message}</Alert>
</View>
) : null}
{error ? (
<View paddingBottom="size-100">
<Alert variant="danger">{error}</Alert>
Expand All @@ -69,12 +62,13 @@ export function ForgotPasswordForm() {
onChange={onChange}
value={value}
placeholder="your email address"
description="Enter the email address associated with your account."
/>
)}
/>
<div
css={css`
margin-top: var(--ac-global-dimension-size-400);
margin-top: var(--ac-global-dimension-size-200);
margin-bottom: var(--ac-global-dimension-size-50);
button {
width: 100%;
Expand All @@ -86,7 +80,7 @@ export function ForgotPasswordForm() {
loading={isLoading}
onClick={handleSubmit(onSubmit)}
>
Submit
Send
</Button>
</div>
</Form>
Expand Down
65 changes: 56 additions & 9 deletions app/src/pages/auth/ForgotPasswordPage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
import React from "react";
import React, { useState } from "react";
import { css } from "@emotion/react";

import { Flex, View } from "@arizeai/components";
import { Flex, Heading } from "@arizeai/components";

import { Link } from "@phoenix/components";

import { AuthLayout } from "./AuthLayout";
import { ForgotPasswordForm } from "./ForgotPasswordForm";
import { PhoenixLogo } from "./PhoenixLogo";

export function ForgotPasswordPage() {
const [resetSent, setResetSent] = useState<boolean>(false);
const content = resetSent ? (
<Flex
direction="column"
alignItems="center"
justifyContent="center"
gap="size-100"
>
<Heading level={1}>Check your email</Heading>
<p>
{`Thanks! If an account with that email address exists, we sent you a link to reset your password.`}
</p>
</Flex>
) : (
<>
<Flex
direction="column"
alignItems="center"
justifyContent="center"
gap="size-100"
>
<Heading level={1}>Forgot Password</Heading>
<p>
{`Enter the email address associated with your account and we'll send you
a link to reset your password.`}
</p>
</Flex>
<ForgotPasswordForm onResetSent={() => setResetSent(true)} />
</>
);
return (
<AuthLayout>
<Flex direction="column" gap="size-200" alignItems="center">
<View paddingBottom="size-200">
<PhoenixLogo />
</View>
</Flex>
<ForgotPasswordForm />
<div
css={css`
& a {
text-align: center;
width: 100%;
display: block;
text-align: center;
padding-top: var(--ac-global-dimension-size-200);
}
`}
>
{content}
<Flex
direction="column"
alignItems="center"
justifyContent="center"
gap="size-200"
>
<Link to="/login">Back to Login</Link>
</Flex>
</div>
</AuthLayout>
);
}
57 changes: 35 additions & 22 deletions app/src/pages/auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,29 +70,43 @@ export function LoginForm() {
/>
)}
/>
<Controller
name="password"
control={control}
render={({ field: { onChange, value } }) => (
<TextField
label="Password"
name="password"
type="password"
isRequired
onChange={onChange}
value={value}
placeholder="your password"
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSubmit(onSubmit)();
}
}}
/>
)}
/>
<div
css={css`
margin-top: var(--ac-global-dimension-size-400);
position: relative;
a {
position: absolute;
float: right;
right: 0;
top: var(--ac-global-dimension-size-50);
font-size: 12px;
}
`}
>
<Controller
name="password"
control={control}
render={({ field: { onChange, value } }) => (
<TextField
label="Password"
name="password"
type="password"
isRequired
onChange={onChange}
value={value}
placeholder="your password"
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSubmit(onSubmit)();
}
}}
/>
)}
/>
<Link to="/forgot-password">Forgot your password?</Link>
</div>
<div
css={css`
margin-top: var(--ac-global-dimension-size-200);
margin-bottom: var(--ac-global-dimension-size-50);
button {
width: 100%;
Expand All @@ -106,7 +120,6 @@ export function LoginForm() {
>
Login
</Button>
<Link to={"/forgot-password"}>Forgot password?</Link>
</div>
</Form>
</>
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"HDBSCAN",
"httpx",
"Instrumentor",
"instrumentors",
"langchain",
"litellm",
"llamaindex",
Expand Down
2 changes: 1 addition & 1 deletion src/phoenix/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def get_env_smtp_password() -> str:


def get_env_smtp_mail_from() -> str:
return os.getenv(ENV_PHOENIX_SMTP_MAIL_FROM) or ""
return os.getenv(ENV_PHOENIX_SMTP_MAIL_FROM) or "[email protected]"


def get_env_smtp_hostname() -> str:
Expand Down
2 changes: 1 addition & 1 deletion src/phoenix/server/email/sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def send_password_reset_email(
values: PasswordResetTemplateBody,
) -> None:
message = MessageSchema(
subject="Password Reset Request",
subject="[Phoenix] Password Reset Request",
recipients=[email],
template_body=asdict(values),
subtype="html",
Expand Down
31 changes: 19 additions & 12 deletions src/phoenix/server/email/templates/password_reset.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Password Reset</title>
</head>
<body>
<p>Hello.</p>
<p>You have requested a password reset. Please click on the link below to reset your password:</p>
<p>
<a id="reset-url" href="{{ base_url }}/reset-password-with-token?token={{ token }}">Reset Password</a>
</p>
<p>If you did not make this request, please contact your administrator.</p>
</body>
<head>
<meta charset="UTF-8" />
<title>Password Reset</title>
</head>
<body>
<p>Hello.</p>
<p>
You have requested a password reset. Please click on the link below to
reset your password:
</p>
<p>
<a
id="reset-url"
href="{{ base_url }}reset-password-with-token?token={{ token }}"
>Reset Password</a
>
</p>
<p>If you did not make this request, please contact your administrator.</p>
</body>
</html>

0 comments on commit ee3ef81

Please sign in to comment.