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 e49bbbcef8..6134ab4a30 100644 --- a/app/src/pages/auth/ForgotPasswordForm.tsx +++ b/app/src/pages/auth/ForgotPasswordForm.tsx @@ -8,13 +8,15 @@ type ForgotPasswordFormParams = { email: string; }; -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 { @@ -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({ defaultValues: { email: "" }, }); return ( <> - {message ? ( - - {message} - - ) : null} {error ? ( {error} @@ -69,12 +62,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 3c5a83181b..f2bad35083 100644 --- a/app/src/pages/auth/ForgotPasswordPage.tsx +++ b/app/src/pages/auth/ForgotPasswordPage.tsx @@ -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(false); + const content = resetSent ? ( + + Check your email +

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

+
+ ) : ( + <> + + 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 a7bc185966..98fe6c7588 100644 --- a/app/src/pages/auth/LoginForm.tsx +++ b/app/src/pages/auth/LoginForm.tsx @@ -70,29 +70,43 @@ export function LoginForm() { /> )} /> - ( - { - if (e.key === "Enter") { - handleSubmit(onSubmit)(); - } - }} - /> - )} - />
+ ( + { + if (e.key === "Enter") { + handleSubmit(onSubmit)(); + } + }} + /> + )} + /> + Forgot your password? +
+
Login - Forgot password?
diff --git a/cspell.json b/cspell.json index 52ceed915b..264b970ded 100644 --- a/cspell.json +++ b/cspell.json @@ -23,6 +23,7 @@ "HDBSCAN", "httpx", "Instrumentor", + "instrumentors", "langchain", "litellm", "llamaindex", diff --git a/src/phoenix/config.py b/src/phoenix/config.py index 2f3dcf8377..74d72ec465 100644 --- a/src/phoenix/config.py +++ b/src/phoenix/config.py @@ -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 "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..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="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.

+