Skip to content

Conversation

@Anshumancanrock
Copy link
Contributor

@Anshumancanrock Anshumancanrock commented Jan 18, 2026

Proposed changes (including videos or screenshots)

This PR fixes an issue where the "Save Changes" button appears in the profile settings when users add only whitespace (spaces/tabs) to text fields, even though no meaningful changes have been made.

Changes:

  • Added isTrulyDirty logic in AccountProfilePage.tsx that compares trimmed values of form fields instead of raw values
  • Added trimming of string fields in handleSave in AccountProfileForm.tsx to ensure clean data is saved and the form state is reset with trimmed values
  • Prevents unnecessary API calls and improves UX by only showing the Save button when actual content changes occur

Issue(s)

Closes #38243

Steps to test or reproduce

  1. Navigate to Account Settings → Profile
  2. Click on any text field (Name, Username, Nickname, Bio, Status Message, Email)
  3. Add spaces at the beginning or end of the existing value
  4. Verify the "Save Changes" button does NOT appear
  5. Make an actual change (e.g., change "John" to "Jane")
  6. Verify the "Save Changes" button does appear
  7. Click Save and verify the values are saved correctly without leading/trailing spaces

Before Fix:

Recording.2026-01-18.220530.mp4

After Fix:

Recording.2026-01-18.222106.1.mp4

Summary by CodeRabbit

  • New Features

    • Avatar refresh now occurs after a successful profile save.
  • Bug Fixes

    • All profile text fields (name, username, email, status, nickname, bio) are trimmed before saving; email updates only when the trimmed value changes.
    • Form reset now uses trimmed values to avoid restoring unintended whitespace.
    • Bio length validation relaxed to avoid blocking edits.
  • UI/UX Changes

    • Dirty-state detection ignores whitespace-only differences so Save/Cancel enable only for true changes.
    • Nickname addon removed and bio input simplified for cleaner editing.

✏️ Tip: You can customize this high-level summary in your review settings.

@Anshumancanrock Anshumancanrock requested a review from a team as a code owner January 18, 2026 16:58
@changeset-bot
Copy link

changeset-bot bot commented Jan 18, 2026

🦋 Changeset detected

Latest commit: f7bda30

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 40 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/ui-voip Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/abac Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Jan 18, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 18, 2026

Walkthrough

Trim whitespace from profile text fields on save and reset; compute a trimmed-value-aware dirty flag (isTrulyDirty) comparing trimmed string fields and non-string fields to gate Cancel/Save and submission; simplify nickname input rendering and adjust bio validation/aria-invalid handling.

Changes

Cohort / File(s) Summary
Profile form
apps/meteor/client/views/account/profile/AccountProfileForm.tsx
Trim name, username, email, statusText, nickname, and bio before building payload; only send email when trimmed value changes; reset form with trimmed defaults (preserving customFields); simplify nickname input (remove Controller/addon); remove bio maxLength rule and correct aria-invalid reference.
Profile page / form state
apps/meteor/client/views/account/profile/AccountProfilePage.tsx
Add control/useWatch, memoize defaultValues, compute isTrulyDirty by comparing trimmed string fields (name, username, statusText, nickname, bio, email) and non-string fields (avatar, statusType, customFields); use isTrulyDirty to enable/disable Cancel/Save and to gate reset and submit.
Changeset
.changeset/prevent-whitespace-saving.md
Add changeset documenting patch release to prevent saving whitespace-only profile changes.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant Form as ProfileForm (client)
  participant Page as AccountProfilePage
  participant API as Server API
  participant Avatar as AvatarUpdater

  User->>Form: edit fields (name, email, username, nickname, bio, status)
  Form->>Page: update form state via useWatch/control
  Page->>Page: compute isTrulyDirty (trim strings + compare avatar/statusType/customFields)
  alt isTrulyDirty true
    User->>Page: click Save
    Page->>Form: validate & collect trimmed values
    Form->>API: send updateOwnBasicInfo(payload with trimmed fields)
    API-->>Form: success
    Form->>Avatar: trigger avatar update (if changed)
    Form-->>User: show success / reset form with trimmed defaults
  else isTrulyDirty false
    Page-->>User: Save disabled (no submit)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • dougfabris
  • ricardogarim
  • cardoso

Poem

🐇 I nibble trailing spaces away,
I trim the fluff so truth can stay,
Nick and bio clean and bright,
Save wakes only when there's light,
Hop—your profile's tidy, right ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: preventing the Save button from appearing when only whitespace is added to profile fields.
Linked Issues check ✅ Passed The changes fully address issue #38243 by implementing trimmed dirty detection and trimming saved values to prevent false positives from whitespace-only edits.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue: trimming logic in AccountProfileForm.tsx, isTrulyDirty logic in AccountProfilePage.tsx, and a changeset entry documenting the fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@codecov
Copy link

codecov bot commented Jan 18, 2026

Codecov Report

❌ Patch coverage is 46.15385% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.73%. Comparing base (37e7b75) to head (f7bda30).
⚠️ Report is 28 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #38244      +/-   ##
===========================================
+ Coverage    70.66%   70.73%   +0.06%     
===========================================
  Files         3135     3158      +23     
  Lines       108592   109375     +783     
  Branches     19555    19897     +342     
===========================================
+ Hits         76740    77362     +622     
- Misses       29845    29981     +136     
- Partials      2007     2032      +25     
Flag Coverage Δ
e2e 60.29% <46.15%> (-0.03%) ⬇️
e2e-api 48.04% <ø> (+0.03%) ⬆️
unit 71.85% <ø> (+0.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/meteor/client/views/account/profile/AccountProfileForm.tsx (1)

112-140: Remove inline implementation comment.

Line 113 adds a comment that restates the code and isn’t needed. Please remove it.

🧹 Suggested cleanup
-		// Trim string values before saving
As per coding guidelines, avoid code comments in the implementation.
🤖 Fix all issues with AI agents
In `@apps/meteor/client/views/account/profile/AccountProfilePage.tsx`:
- Around line 47-75: Remove the two inline explanatory comments inside the
AccountProfilePage component: drop the comment above the useWatch call ("//
Watch all form values to compare trimmed versions") and the comment before
stringFields ("// Check if form is truly dirty by comparing trimmed string
values"), leaving the logic for watchedValues, defaultValues, and the
isTrulyDirty useMemo (including stringFields, avatar/statusType/customFields
checks) intact; ensure only the code around useWatch, getProfileInitialValues,
and the isTrulyDirty computation is preserved without those comments.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Copy link
Contributor

@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

🤖 Fix all issues with AI agents
In `@apps/meteor/client/views/account/profile/AccountProfileForm.tsx`:
- Line 113: Remove the inline explanatory comment "// Trim string values before
saving" inside the AccountProfileForm component (look for the AccountProfileForm
function/JSX where trimming is performed) so the implementation contains no
in-code comments; leave the trimming code intact but delete that comment to
comply with the coding guideline against inline comments.
🧹 Nitpick comments (1)
apps/meteor/client/views/account/profile/AccountProfileForm.tsx (1)

139-141: Consider including avatar in the reset and improve line formatting.

The reset omits avatar, which could leave stale state if the avatar was changed. Also, this line exceeds typical length limits, making it hard to read.

♻️ Suggested refactor
 		} finally {
-			reset({ email: trimmedEmail, name: trimmedName, username: trimmedUsername, statusType, statusText: trimmedStatusText, nickname: trimmedNickname, bio: trimmedBio, customFields });
+			reset({
+				email: trimmedEmail,
+				name: trimmedName,
+				username: trimmedUsername,
+				statusType,
+				statusText: trimmedStatusText,
+				nickname: trimmedNickname,
+				bio: trimmedBio,
+				customFields,
+				avatar: undefined,
+			});
 		}

Verify that resetting avatar to undefined (or its appropriate default) aligns with the expected behavior after a successful save.

@Anshumancanrock Anshumancanrock force-pushed the space branch 2 times, most recently from 78fa457 to d15fc31 Compare January 18, 2026 18:36
Copy link
Contributor

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/meteor/client/views/account/profile/AccountProfileForm.tsx (1)

299-313: Broken JSX structure around Nickname/Bio fields.

From Line 302 onward, the bio props are dangling (no <TextAreaInput ...> opener) and the bio errors are rendered under the Nickname label. This will fail to compile or render correctly. Please restore a dedicated Bio controller/TextAreaInput and close the Nickname field row before it.

🛠️ Suggested fix
-				<FieldRow>
-				<Controller control={control} name='nickname' render={({ field }) => <TextInput {...field} id={nicknameId} flexGrow={1} />} />
-									id={bioId}
-									error={errors.bio?.message}
-									rows={3}
-									flexGrow={1}
-									addon={<Icon name='edit' size='x20' alignSelf='center' />}
-									aria-invalid={errors.statusText ? 'true' : 'false'}
-									aria-describedby={`${bioId}-error`}
-								/>
-							)}
-						/>
-					</FieldRow>
-					{errors?.bio && (
-						<FieldError aria-live='assertive' id={`${bioId}-error`}>
-							{errors.bio.message}
-						</FieldError>
-					)}
-				</Field>
+				<FieldRow>
+					<Controller control={control} name='nickname' render={({ field }) => <TextInput {...field} id={nicknameId} flexGrow={1} />} />
+				</FieldRow>
+			</Field>
+			<Field>
+				<FieldLabel htmlFor={bioId}>{t('Bio')}</FieldLabel>
+				<FieldRow>
+					<Controller
+						control={control}
+						name='bio'
+						render={({ field }) => (
+							<TextAreaInput
+								{...field}
+								id={bioId}
+								error={errors.bio?.message}
+								rows={3}
+								flexGrow={1}
+								aria-invalid={errors.bio ? 'true' : 'false'}
+								aria-describedby={`${bioId}-error`}
+							/>
+						)}
+					/>
+				</FieldRow>
+				{errors?.bio && (
+					<FieldError aria-live='assertive' id={`${bioId}-error`}>
+						{errors.bio.message}
+					</FieldError>
+				)}
+			</Field>

…file

Trims field values on blur to prevent whitespace-only changes from triggering the dirty state.
This is more performant than watching all form values since it only runs when user leaves a field.
Copy link
Contributor

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/meteor/client/views/account/profile/AccountProfileForm.tsx (1)

299-313: Fix the broken JSX in the nickname/bio section.

Line 302 closes the nickname Controller, but the subsequent bio props (id={bioId}, rows, etc.) are now outside any JSX element, which will break rendering/compilation. The bio field needs its own Controller/TextAreaInput block after the nickname field is closed.

🐛 Proposed fix
 				<FieldLabel htmlFor={nicknameId}>{t('Nickname')}</FieldLabel>
 				<FieldRow>
-				<Controller control={control} name='nickname' render={({ field }) => <TextInput {...field} id={nicknameId} flexGrow={1} />} />
-									id={bioId}
-									error={errors.bio?.message}
-									rows={3}
-									flexGrow={1}
-									addon={<Icon name='edit' size='x20' alignSelf='center' />}
-									aria-invalid={errors.statusText ? 'true' : 'false'}
-									aria-describedby={`${bioId}-error`}
-								/>
-							)}
-						/>
-					</FieldRow>
-					{errors?.bio && (
-						<FieldError aria-live='assertive' id={`${bioId}-error`}>
-							{errors.bio.message}
-						</FieldError>
-					)}
-				</Field>
+					<Controller
+						control={control}
+						name='nickname'
+						render={({ field }) => <TextInput {...field} id={nicknameId} flexGrow={1} />}
+					/>
+				</FieldRow>
+			</Field>
+			<Field>
+				<FieldLabel htmlFor={bioId}>{t('Bio')}</FieldLabel>
+				<FieldRow>
+					<Controller
+						control={control}
+						name='bio'
+						rules={{
+							maxLength: {
+								value: BIO_TEXT_MAX_LENGTH,
+								message: t('Max_length_is', BIO_TEXT_MAX_LENGTH),
+							},
+						}}
+						render={({ field }) => (
+							<TextAreaInput
+								{...field}
+								id={bioId}
+								error={errors.bio?.message}
+								rows={3}
+								flexGrow={1}
+								aria-invalid={errors.bio ? 'true' : 'false'}
+								aria-describedby={`${bioId}-error`}
+							/>
+						)}
+					/>
+				</FieldRow>
+				{errors?.bio && (
+					<FieldError aria-live='assertive' id={`${bioId}-error`}>
+						{errors.bio.message}
+					</FieldError>
+				)}
+			</Field>

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.

Save button appears when adding only whitespace to profile fields

1 participant