From 36c8f584c0fd9840cf16dfdcd9afc94b2f39c318 Mon Sep 17 00:00:00 2001 From: Mikyo King Date: Wed, 18 Sep 2024 16:01:59 -0600 Subject: [PATCH 1/4] WIP --- app/src/pages/auth/ForgotPasswordForm.tsx | 6 ++- app/src/pages/auth/ForgotPasswordPage.tsx | 15 ++++++- app/src/pages/auth/LoginForm.tsx | 55 ++++++++++++++--------- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/app/src/pages/auth/ForgotPasswordForm.tsx b/app/src/pages/auth/ForgotPasswordForm.tsx index e49bbbcef8..3be2b2cf5c 100644 --- a/app/src/pages/auth/ForgotPasswordForm.tsx +++ b/app/src/pages/auth/ForgotPasswordForm.tsx @@ -8,6 +8,8 @@ type ForgotPasswordFormParams = { email: string; }; +const DEFAULT_ERROR_MESSAGE = + "Failed to send password reset email. Please contact your administrator."; export function ForgotPasswordForm() { const [message, setMessage] = useState(null); const [error, setError] = useState(null); @@ -26,11 +28,11 @@ export function ForgotPasswordForm() { body: JSON.stringify(params), }); if (!response.ok) { - setError("Failed attempt"); + setError(DEFAULT_ERROR_MESSAGE); return; } } catch (error) { - setError("Failed attempt"); + setError(DEFAULT_ERROR_MESSAGE); return; } finally { setIsLoading(() => false); diff --git a/app/src/pages/auth/ForgotPasswordPage.tsx b/app/src/pages/auth/ForgotPasswordPage.tsx index 3c5a83181b..fbe8f2bcb9 100644 --- a/app/src/pages/auth/ForgotPasswordPage.tsx +++ b/app/src/pages/auth/ForgotPasswordPage.tsx @@ -1,12 +1,15 @@ -import React from "react"; +import React, { useState } from "react"; import { Flex, View } 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(false); return ( @@ -14,7 +17,15 @@ export function ForgotPasswordPage() { - + + + Back to Login + ); } diff --git a/app/src/pages/auth/LoginForm.tsx b/app/src/pages/auth/LoginForm.tsx index a7bc185966..252f7d9d0a 100644 --- a/app/src/pages/auth/LoginForm.tsx +++ b/app/src/pages/auth/LoginForm.tsx @@ -70,26 +70,40 @@ export function LoginForm() { /> )} /> - ( - { - if (e.key === "Enter") { - handleSubmit(onSubmit)(); - } - }} - /> - )} - /> +
+ ( + { + if (e.key === "Enter") { + handleSubmit(onSubmit)(); + } + }} + /> + )} + /> + Forgot your password? +
Login - Forgot password?
From 1efd0eb66136d8abeccff3c4cb23fa111be45888 Mon Sep 17 00:00:00 2001 From: Mikyo King Date: Wed, 18 Sep 2024 18:32:10 -0600 Subject: [PATCH 2/4] feat(auth): cleanup reset password UI --- app/.env.example | 4 ++ app/src/pages/auth/ForgotPasswordForm.tsx | 30 ++++----- app/src/pages/auth/ForgotPasswordPage.tsx | 61 +++++++++++++++---- app/src/pages/auth/LoginForm.tsx | 2 +- cspell.json | 1 + src/phoenix/config.py | 2 +- src/phoenix/server/email/sender.py | 2 +- .../email/templates/password_reset.html | 31 ++++++---- 8 files changed, 88 insertions(+), 45 deletions(-) diff --git a/app/.env.example b/app/.env.example index c6aecf37a3..fc0eac6b30 100644 --- a/app/.env.example +++ b/app/.env.example @@ -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 diff --git a/app/src/pages/auth/ForgotPasswordForm.tsx b/app/src/pages/auth/ForgotPasswordForm.tsx index 3be2b2cf5c..ce9fbb297d 100644 --- a/app/src/pages/auth/ForgotPasswordForm.tsx +++ b/app/src/pages/auth/ForgotPasswordForm.tsx @@ -10,13 +10,15 @@ type ForgotPasswordFormParams = { const DEFAULT_ERROR_MESSAGE = "Failed to send password reset email. Please contact your administrator."; -export function ForgotPasswordForm() { - const [message, setMessage] = useState(null); +export function ForgotPasswordForm({ + onResetSent, +}: { + onResetSent: () => void; +}) { const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); const onSubmit = useCallback( async (params: ForgotPasswordFormParams) => { - setMessage(null); setError(null); setIsLoading(true); try { @@ -28,31 +30,22 @@ export function ForgotPasswordForm() { body: JSON.stringify(params), }); if (!response.ok) { - setError(DEFAULT_ERROR_MESSAGE); + const message = await response.text(); + setError(message); return; } - } catch (error) { - setError(DEFAULT_ERROR_MESSAGE); - 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({ defaultValues: { email: "" }, }); return ( <> - {message ? ( - - {message} - - ) : null} {error ? ( {error} @@ -71,12 +64,13 @@ export function ForgotPasswordForm() { onChange={onChange} value={value} placeholder="your email address" + description="Enter the email address associated with your account." /> )} />
- Submit + Send
diff --git a/app/src/pages/auth/ForgotPasswordPage.tsx b/app/src/pages/auth/ForgotPasswordPage.tsx index fbe8f2bcb9..f71bf5faac 100644 --- a/app/src/pages/auth/ForgotPasswordPage.tsx +++ b/app/src/pages/auth/ForgotPasswordPage.tsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; +import { css } from "@emotion/react"; -import { Flex, View } from "@arizeai/components"; +import { Flex, Heading, Text, View } from "@arizeai/components"; import { Link } from "@phoenix/components"; @@ -10,22 +11,58 @@ import { PhoenixLogo } from "./PhoenixLogo"; export function ForgotPasswordPage() { const [resetSent, setResetSent] = useState(false); - return ( - - - - - - + const content = resetSent ? ( + + Check your email +

+ {`Thanks! If an account with that email address exists, we sent you a link to reset your password.`} +

+
+ ) : ( + <> - - Back to Login + Forgot Password +

+ {`Enter the email address associated with your account and we'll send you + a link to reset your password.`} +

+ setResetSent(true)} /> + + ); + return ( + +
+ {content} + + Back to Login + +
); } diff --git a/app/src/pages/auth/LoginForm.tsx b/app/src/pages/auth/LoginForm.tsx index 252f7d9d0a..98fe6c7588 100644 --- a/app/src/pages/auth/LoginForm.tsx +++ b/app/src/pages/auth/LoginForm.tsx @@ -106,7 +106,7 @@ export function LoginForm() {
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 "noreply@arize.com" def get_env_smtp_hostname() -> str: diff --git a/src/phoenix/server/email/sender.py b/src/phoenix/server/email/sender.py index f44219af70..d2afcbb5f3 100644 --- a/src/phoenix/server/email/sender.py +++ b/src/phoenix/server/email/sender.py @@ -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", diff --git a/src/phoenix/server/email/templates/password_reset.html b/src/phoenix/server/email/templates/password_reset.html index aab4b3dddc..511e447c08 100644 --- a/src/phoenix/server/email/templates/password_reset.html +++ b/src/phoenix/server/email/templates/password_reset.html @@ -1,15 +1,22 @@ - - - Password Reset - - -

Hello.

-

You have requested a password reset. Please click on the link below to reset your password:

-

- Reset Password -

-

If you did not make this request, please contact your administrator.

- + + + Password Reset + + +

Hello.

+

+ You have requested a password reset. Please click on the link below to + reset your password: +

+

+ Reset Password +

+

If you did not make this request, please contact your administrator.

+ From 5a44158be4d83c3f3a6e959037801108ce17b2bb Mon Sep 17 00:00:00 2001 From: Mikyo King Date: Wed, 18 Sep 2024 18:35:22 -0600 Subject: [PATCH 3/4] cleanup --- app/src/pages/auth/ForgotPasswordForm.tsx | 2 -- src/phoenix/server/email/sender.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/pages/auth/ForgotPasswordForm.tsx b/app/src/pages/auth/ForgotPasswordForm.tsx index ce9fbb297d..6134ab4a30 100644 --- a/app/src/pages/auth/ForgotPasswordForm.tsx +++ b/app/src/pages/auth/ForgotPasswordForm.tsx @@ -8,8 +8,6 @@ type ForgotPasswordFormParams = { email: string; }; -const DEFAULT_ERROR_MESSAGE = - "Failed to send password reset email. Please contact your administrator."; export function ForgotPasswordForm({ onResetSent, }: { diff --git a/src/phoenix/server/email/sender.py b/src/phoenix/server/email/sender.py index d2afcbb5f3..2beae17d3d 100644 --- a/src/phoenix/server/email/sender.py +++ b/src/phoenix/server/email/sender.py @@ -18,7 +18,7 @@ async def send_password_reset_email( values: PasswordResetTemplateBody, ) -> None: message = MessageSchema( - subject="Phoenix Password Reset Request", + subject="[Phoenix] Password Reset Request", recipients=[email], template_body=asdict(values), subtype="html", From 9e026bbba7038a7b88d80d6f105a66ae65a73cce Mon Sep 17 00:00:00 2001 From: Mikyo King Date: Wed, 18 Sep 2024 18:38:50 -0600 Subject: [PATCH 4/4] cleanup --- app/src/pages/auth/ForgotPasswordPage.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/pages/auth/ForgotPasswordPage.tsx b/app/src/pages/auth/ForgotPasswordPage.tsx index f71bf5faac..f2bad35083 100644 --- a/app/src/pages/auth/ForgotPasswordPage.tsx +++ b/app/src/pages/auth/ForgotPasswordPage.tsx @@ -1,13 +1,12 @@ import React, { useState } from "react"; import { css } from "@emotion/react"; -import { Flex, Heading, Text, 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(false);