Skip to content

feat: add trailing whitespace warning on login username field (#2040)#2177

Open
GeoffreyCoulaud wants to merge 1 commit intoseerr-team:developfrom
GeoffreyCoulaud:warn-whitespace-after-username
Open

feat: add trailing whitespace warning on login username field (#2040)#2177
GeoffreyCoulaud wants to merge 1 commit intoseerr-team:developfrom
GeoffreyCoulaud:warn-whitespace-after-username

Conversation

@GeoffreyCoulaud
Copy link
Contributor

@GeoffreyCoulaud GeoffreyCoulaud commented Nov 26, 2025

Description

Adds a UsernameInput component and uses it in both local and jellyfin login.
If trailing whitespace is detected, a warning is displayed under the input.

No AI tools were used to create this PR.
Edit: I got help from Claude code to apply requested changes.

Screenshot (if UI-related)

Seerr Login Jellyfin Login
Capture d’écran du 2026-03-07 19-55-19 Capture d’écran du 2026-03-07 19-54-59

To-Dos

  • Disclosed any use of AI (see our policy)
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Issues Fixed or Closed

Summary by CodeRabbit

  • New Features
    • Added visual warnings that display when username or email fields contain trailing whitespace during login.
    • Warning indicators now appear to help prevent authentication issues caused by accidental whitespace in credentials.
    • Enhanced visual distinction with new warning styling and localized warning messages in multiple languages.

@GeoffreyCoulaud GeoffreyCoulaud requested a review from a team as a code owner November 26, 2025 22:22
@GeoffreyCoulaud GeoffreyCoulaud force-pushed the warn-whitespace-after-username branch from b0f9812 to 2923af0 Compare December 2, 2025 19:12
@github-actions github-actions bot added the merge conflict Cannot merge due to merge conflicts label Jan 29, 2026
@github-actions
Copy link

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@GeoffreyCoulaud GeoffreyCoulaud force-pushed the warn-whitespace-after-username branch from 2923af0 to 05a9d95 Compare February 28, 2026 17:37
@github-actions github-actions bot removed the merge conflict Cannot merge due to merge conflicts label Feb 28, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 91a4b475-e410-45bd-adec-14d2fcf0a5ac

📥 Commits

Reviewing files that changed from the base of the PR and between c4c424d and 30e0b69.

📒 Files selected for processing (4)
  • src/components/Login/JellyfinLogin.tsx
  • src/components/Login/LocalLogin.tsx
  • src/i18n/locale/en.json
  • src/styles/globals.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Login/LocalLogin.tsx

📝 Walkthrough

Walkthrough

The changes add visual warnings in login forms to alert users when their username or email field contains trailing whitespace. This includes importing icon components, adding internationalized warning messages, updating UI to display warnings conditionally, and introducing a corresponding CSS styling class.

Changes

Cohort / File(s) Summary
Login Components
src/components/Login/JellyfinLogin.tsx, src/components/Login/LocalLogin.tsx
Added ExclamationTriangleIcon imports and trailing whitespace warnings that display when username/email fields are touched and contain trailing spaces. Updated Formik render props to destructure values for validation checking.
Internationalization
src/i18n/locale/en.json
Added two new English translation keys for trailing whitespace warning messages: one for username and one for email.
Styling
src/styles/globals.css
Introduced new .warning CSS utility class with yellow text styling to support the visual warning indicators.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

Hop hop, those trailing spaces fade,
A yellow warning light is made,
No more login frustration—clear and clean,
Your whitespace is now plainly seen! 🐰✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a trailing whitespace warning on the login username field, which is the core feature across both login components.
Linked Issues check ✅ Passed The PR implements trailing whitespace detection and warning display for both username and email fields in login forms, directly addressing issue #2040's core concern about invisible trailing spaces causing login failures.
Out of Scope Changes check ✅ Passed All changes are within scope: username/email warning UI components, supporting translations, and CSS styling. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/components/Login/JellyfinLogin.tsx (1)

76-79: Consider trimming the username before submission for consistency.

Similar to the LocalLogin component, the username value is passed to the API without trimming. For consistency and to fully address issue #2040:

💡 Suggested enhancement
           await axios.post('/api/v1/auth/jellyfin', {
-            username: values.username,
+            username: values.username.trim(),
             password: values.password,
-            email: values.username,
+            email: values.username.trim(),
           });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Login/JellyfinLogin.tsx` around lines 76 - 79, The
JellyfinLogin component sends values.username directly to the API; trim the
username before submission so the payload uses a trimmed value for username and
email. Update the axios.post call in JellyfinLogin (the object containing
username, password, email) to use values.username.trim() (and assign the trimmed
value to both username and email) so the API receives a consistent,
whitespace-free username.
src/components/Login/LocalLogin.tsx (1)

59-61: Consider trimming the email/username before submission.

The original issue #2040 requests that usernames be trimmed before login to prevent failures caused by trailing spaces (especially from mobile keyboard autocomplete). The current implementation only warns users but still sends the untrimmed value to the API.

Consider also trimming the value before submission to fully address the UX issue:

💡 Suggested enhancement
         try {
           await axios.post('/api/v1/auth/local', {
-            email: values.email,
+            email: values.email.trim(),
             password: values.password,
           });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Login/LocalLogin.tsx` around lines 59 - 61, The submitted
email/username is not being trimmed before the POST, so trailing spaces can
cause login failures; update the payload sent in the function that calls
axios.post('/api/v1/auth/local') (in LocalLogin.tsx) to send trimmed values
(e.g., use values.email.trim() and/or values.username?.trim()) instead of the
raw values, and if the form state is reused elsewhere also update the form field
or local variable prior to submission so the trimmed value is consistently used.
src/components/Login/UsernameInput.tsx (1)

17-18: Consider adding the form-input-field wrapper for styling consistency.

The parent components (LocalLogin and JellyfinLogin) wrap the password field in <div className="form-input-field">, which applies flexbox layout, a max-width constraint, rounded corners, and shadow styling. The username input field in UsernameInput lacks this wrapper, creating a visual inconsistency between the two fields.

💡 Suggested enhancement
   return (
     <div>
-      <input type="text" {...field} {...props} />
+      <div className="form-input-field">
+        <input type="text" {...field} {...props} />
+      </div>
       {touched[field.name] && hasTrailingWhitespace(field.value) ? (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Login/UsernameInput.tsx` around lines 17 - 18, The
UsernameInput component is missing the consistent wrapper used elsewhere; wrap
the existing <input> (which spreads {...field} and {...props}) inside a div with
className="form-input-field" to match LocalLogin and JellyfinLogin styling,
preserving the current props/field spreads and structure in the UsernameInput
component so flex layout, max-width, rounded corners, and shadow are applied
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Login/UsernameInput.tsx`:
- Around line 14-27: The current check uses the `in` operator on `touched` which
only tests key existence; update the UsernameInput component to check that the
field is actually touched by using a truthy lookup (e.g.,
`!!touched[field.name]` or `Boolean(touched[field.name])`) instead of
`field.name in touched`, so the trailing-whitespace warning
(hasTrailingWhitespace(field.value)) only renders when the field is truly
touched; modify the conditional that currently reads `field.name in touched &&
hasTrailingWhitespace(field.value)` to use the truthy lookup of
`touched[field.name]`.

---

Nitpick comments:
In `@src/components/Login/JellyfinLogin.tsx`:
- Around line 76-79: The JellyfinLogin component sends values.username directly
to the API; trim the username before submission so the payload uses a trimmed
value for username and email. Update the axios.post call in JellyfinLogin (the
object containing username, password, email) to use values.username.trim() (and
assign the trimmed value to both username and email) so the API receives a
consistent, whitespace-free username.

In `@src/components/Login/LocalLogin.tsx`:
- Around line 59-61: The submitted email/username is not being trimmed before
the POST, so trailing spaces can cause login failures; update the payload sent
in the function that calls axios.post('/api/v1/auth/local') (in LocalLogin.tsx)
to send trimmed values (e.g., use values.email.trim() and/or
values.username?.trim()) instead of the raw values, and if the form state is
reused elsewhere also update the form field or local variable prior to
submission so the trimmed value is consistently used.

In `@src/components/Login/UsernameInput.tsx`:
- Around line 17-18: The UsernameInput component is missing the consistent
wrapper used elsewhere; wrap the existing <input> (which spreads {...field} and
{...props}) inside a div with className="form-input-field" to match LocalLogin
and JellyfinLogin styling, preserving the current props/field spreads and
structure in the UsernameInput component so flex layout, max-width, rounded
corners, and shadow are applied consistently.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f74306e and 05a9d95.

📒 Files selected for processing (5)
  • src/components/Login/JellyfinLogin.tsx
  • src/components/Login/LocalLogin.tsx
  • src/components/Login/UsernameInput.tsx
  • src/i18n/locale/en.json
  • src/styles/globals.css

@GeoffreyCoulaud GeoffreyCoulaud force-pushed the warn-whitespace-after-username branch from 05a9d95 to c4c424d Compare February 28, 2026 17:50
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Login/UsernameInput.tsx`:
- Around line 14-18: The component UsernameInput is currently capturing Formik's
meta via the rest spread and accidentally spreading it onto the <input>, causing
invalid DOM prop warnings; fix by explicitly destructuring meta from the props
(e.g., ({ field, form: { touched }, meta, ...props }: FieldProps)) and then
spread only field and props into the <input> (do not spread meta), so meta is
removed from the DOM attributes while preserving other HTML props.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05a9d95 and c4c424d.

📒 Files selected for processing (5)
  • src/components/Login/JellyfinLogin.tsx
  • src/components/Login/LocalLogin.tsx
  • src/components/Login/UsernameInput.tsx
  • src/i18n/locale/en.json
  • src/styles/globals.css
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/i18n/locale/en.json
  • src/components/Login/LocalLogin.tsx

Comment on lines +14 to +18
const UsernameInput = ({ field, form: { touched }, ...props }: FieldProps) => {
const intl = useIntl();
return (
<div>
<input type="text" {...field} {...props} />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid spreading Formik's meta prop onto the DOM element.

The rest destructuring ...props captures Formik's meta object (along with valid HTML attributes). Spreading meta onto the <input> will cause React warnings about invalid DOM props.

🐛 Proposed fix to exclude meta from spread
-const UsernameInput = ({ field, form: { touched }, ...props }: FieldProps) => {
+const UsernameInput = ({
+  field,
+  form: { touched },
+  meta: _meta,
+  ...props
+}: FieldProps) => {
   const intl = useIntl();
   return (
     <div>
       <input type="text" {...field} {...props} />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const UsernameInput = ({ field, form: { touched }, ...props }: FieldProps) => {
const intl = useIntl();
return (
<div>
<input type="text" {...field} {...props} />
const UsernameInput = ({
field,
form: { touched },
meta: _meta,
...props
}: FieldProps) => {
const intl = useIntl();
return (
<div>
<input type="text" {...field} {...props} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Login/UsernameInput.tsx` around lines 14 - 18, The component
UsernameInput is currently capturing Formik's meta via the rest spread and
accidentally spreading it onto the <input>, causing invalid DOM prop warnings;
fix by explicitly destructuring meta from the props (e.g., ({ field, form: {
touched }, meta, ...props }: FieldProps)) and then spread only field and props
into the <input> (do not spread meta), so meta is removed from the DOM
attributes while preserving other HTML props.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a reusable login username/email input component that displays a warning when trailing whitespace is present, and applies it to both local and Jellyfin login flows.

Changes:

  • Introduce UsernameInput component that detects trailing whitespace and renders an inline warning under the field
  • Reuse UsernameInput in LocalLogin and JellyfinLogin
  • Add global .warning styling and an i18n string for the warning text

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/styles/globals.css Adds a .warning utility class for warning text styling
src/i18n/locale/en.json Adds the localized warning message key
src/components/Login/UsernameInput.tsx New component wrapping a Formik field and showing a trailing-whitespace warning
src/components/Login/LocalLogin.tsx Switches username/email Field to use UsernameInput
src/components/Login/JellyfinLogin.tsx Switches username Field to use UsernameInput

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +17 to +23
<div>
<input type="text" {...field} {...props} />
{touched[field.name] && hasTrailingWhitespace(field.value) ? (
<div className="warning label-tip flex items-center">
<ExclamationTriangleIcon className="mr-1 h-4 w-4" />
{intl.formatMessage(messages.tipUsernameHasTrailingWhitespace)}
</div>
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UsernameInput no longer applies the form-input-field wrapper styling that the login form previously relied on (max width + shadow). This likely causes a visual/layout regression vs the password field and prior behavior. Consider wrapping the <input> in a form-input-field container (or re-introducing that wrapper where the component is used) to preserve consistent styling.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +11
tipUsernameHasTrailingWhitespace: 'The username/email ends with a space',
});

const hasTrailingWhitespace = (value: string): boolean => {
return /\s$/.test(value);
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warning text says the value ends with a "space", but the detection uses /\s$/ which matches any trailing whitespace (tabs, newlines, non‑breaking spaces, etc.). Either tighten the check to a literal space or change the message to say "whitespace" so the UI message matches the actual condition.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +94
<Field
id="email"
name="email"
placeholder={`${intl.formatMessage(
messages.email
)} / ${intl.formatMessage(messages.username)}`}
type="text"
inputMode="email"
data-testid="email"
data-form-type="username,email"
className="!bg-gray-700/80 placeholder:text-gray-400"
component={UsernameInput}
/>
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field used to be wrapped in a form-input-field div (adds max width + shadow). With component={UsernameInput} the wrapper was removed, so the username/email input may render inconsistently compared to other login inputs (e.g., password). Consider restoring the wrapper here, or ensuring UsernameInput provides equivalent wrapper styling.

Suggested change
<Field
id="email"
name="email"
placeholder={`${intl.formatMessage(
messages.email
)} / ${intl.formatMessage(messages.username)}`}
type="text"
inputMode="email"
data-testid="email"
data-form-type="username,email"
className="!bg-gray-700/80 placeholder:text-gray-400"
component={UsernameInput}
/>
<div className="form-input-field">
<Field
id="email"
name="email"
placeholder={`${intl.formatMessage(
messages.email
)} / ${intl.formatMessage(messages.username)}`}
type="text"
inputMode="email"
data-testid="email"
data-form-type="username,email"
className="!bg-gray-700/80 placeholder:text-gray-400"
component={UsernameInput}
/>
</div>

Copilot uses AI. Check for mistakes.
Comment on lines +124 to +132
<Field
id="username"
name="username"
type="text"
placeholder={intl.formatMessage(messages.username)}
className="!bg-gray-700/80 placeholder:text-gray-400"
data-form-type="username"
component={UsernameInput}
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please keep the <div className="form-input-field">

@GeoffreyCoulaud
Copy link
Contributor Author

GeoffreyCoulaud commented Feb 28, 2026

I can do what the AIs suggested if you think it's meaningful, don't hesitate to tell me :)

@seerr-team seerr-team deleted a comment from Copilot AI Mar 1, 2026
Copy link
Member

@gauthier-th gauthier-th left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the new behavior with UsernameInput.tsx a bit confusing. It adds complexity and abstraction only for a small warning.
Couldn't you instead:

  • Keep the current username input field as it is
  • Optional: create a small component for this warning, but I don't think it's necessary since it's used in only 2 places
  • Add the warning depending on the username value, like {username.match(...) && <WarningTooltip>}

Comment on lines +124 to +132
<Field
id="username"
name="username"
type="text"
placeholder={intl.formatMessage(messages.username)}
className="!bg-gray-700/80 placeholder:text-gray-400"
data-form-type="username"
component={UsernameInput}
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please keep the <div className="form-input-field">

@GeoffreyCoulaud GeoffreyCoulaud force-pushed the warn-whitespace-after-username branch from c4c424d to ee94461 Compare March 7, 2026 18:56
@GeoffreyCoulaud GeoffreyCoulaud force-pushed the warn-whitespace-after-username branch from ee94461 to 30e0b69 Compare March 7, 2026 18:57
@GeoffreyCoulaud
Copy link
Contributor Author

I edited the code as requested.
I got a bit of help from claude code to apply requested changes and updated PR description accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Username trailing whitespace preserved when logging in

3 participants