Skip to content

fix: Prevent adding duplicate omnichannel agents with client-side validation#38687

Open
Dnyanesh-29 wants to merge 1 commit intoRocketChat:developfrom
Dnyanesh-29:fix/omnichannel-duplicate-agents-v2
Open

fix: Prevent adding duplicate omnichannel agents with client-side validation#38687
Dnyanesh-29 wants to merge 1 commit intoRocketChat:developfrom
Dnyanesh-29:fix/omnichannel-duplicate-agents-v2

Conversation

@Dnyanesh-29
Copy link
Copy Markdown

@Dnyanesh-29 Dnyanesh-29 commented Feb 14, 2026

Summary
Currently, attempting to add a user as an Omnichannel agent when they are already an agent results in a misleading "Agent added" success toast, even though no change occurred on the server. This PR introduces client-side validation to check the existing agents list before the API call is made.

Changes
AgentsTable.tsx: Now passes the agents data list to the AddAgent component.

AddAgent.tsx:

Added a check using .some() to verify if the selected username already exists in the current agents list.

Prevents the API request if a duplicate is found.

Displays an error toast: "User is already an agent."

Changeset: Added a patch changeset for @rocket.chat/meteor.

Fixes
Closes #38684 ---

How to test
Navigate to Omnichannel > Agents.

Add a user as an agent.

Immediately try to add that same user again.

Expected Result: An error toast should appear, and no network request should be sent to the server.

Summary by CodeRabbit

  • Bug Fixes

    • Prevents adding duplicate omnichannel agents by validating the entered username before saving; shows an error notification and blocks the operation if a duplicate is detected.
    • Improves save flow to reliably reset the input on success and display appropriate success or error notifications on failure.
  • Localization

    • Added a localized message for the duplicate-agent error ("User is already an agent").

@Dnyanesh-29 Dnyanesh-29 requested a review from a team as a code owner February 14, 2026 14:55
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot Bot commented Feb 14, 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

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 14, 2026

🦋 Changeset detected

Latest commit: b4e118e

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 14, 2026

No actionable comments were generated in the recent review. 🎉

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 450db2f and b4e118e.

📒 Files selected for processing (4)
  • .changeset/chilly-wasps-love.md
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
  • packages/i18n/src/locales/en.i18n.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
  • packages/i18n/src/locales/en.i18n.json
  • .changeset/chilly-wasps-love.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
🔇 Additional comments (1)
apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx (1)

75-75: Paginated data is insufficient for reliable duplicate detection — still unresolved.

This was flagged in a prior review and remains the core issue: data?.users only contains agents on the current page. If the organization has more agents than itemsPerPage, duplicates on other pages won't be caught, silently falling back to the old behavior (success toast, no actual change).

Consider one of:

  1. A dedicated lightweight endpoint or query that fetches all agent usernames (not paginated) for the check.
  2. A server-side–aware approach: since the server returns 200 OK for duplicates, compare the response to detect no-ops and adjust the toast accordingly.
  3. At minimum, a pre-flight GET filtered by the selected username to confirm existence before calling the mutation.

[duplicate_comment, raise_major_issue]


Walkthrough

Client-side duplicate-check added: AddAgent now receives the current agents list, validates the username before calling the save mutation, shows an error toast and aborts if duplicate; otherwise proceeds with the existing save and success handling.

Changes

Cohort / File(s) Summary
Changeset
/.changeset/chilly-wasps-love.md
New changeset recording a patch bump for @rocket.chat/meteor and noting client-side duplicate-agent validation.
AddAgent component
apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
Signature updated to accept agents?: { username?: string }[]. handleSave checks for duplicate username, shows User_is_already_an_agent error toast and aborts if found; otherwise calls saveAction inside try/catch and preserves success flow (invalidate query, reset input, show success toast).
AgentsTable usage
apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
Now passes agents={data?.users} into AddAgent so the component can perform client-side duplicate validation.
i18n
packages/i18n/src/locales/en.i18n.json
Added localization key User_is_already_an_agent: "User is already an agent" used by the new client-side validation error toast.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant AgentsTable as AgentsTable
  participant AddAgent as AddAgent
  participant Validation as Validation
  participant API as API
  participant QueryCache as QueryCache
  participant Toast as Toast

  User->>AgentsTable: open Add Agent UI
  AgentsTable->>AddAgent: render (agents list -> prop)
  User->>AddAgent: enter username & click Add
  AddAgent->>Validation: check username in agents list
  alt username exists
    Validation-->>AddAgent: duplicate found
    AddAgent->>Toast: show "User_is_already_an_agent" (error)
  else username new
    Validation-->>AddAgent: not found
    AddAgent->>API: saveAction (POST /v1/livechat/users/agent)
    API-->>AddAgent: success
    AddAgent->>QueryCache: invalidate agents query
    AddAgent->>Toast: show success toast
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 I hop through code with nimble feet,
I peek the list and skip repeat,
No extra call when twins appear,
I warn with toast — concise and clear,
Hooray, each agent stays unique! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements most objectives from #38684: client-side duplicate check, error toast display, and preventing API calls for duplicates. However, the implementation lacks case-insensitive username comparison, which allows duplicates to be added when usernames differ in case. Add toLowerCase() normalization to both the username input and the duplicate check comparison to handle case-insensitive matching.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (10 files):

⚔️ apps/meteor/app/livechat/server/lib/contacts/resolveContactConflicts.spec.ts (content)
⚔️ apps/meteor/app/livechat/server/lib/contacts/resolveContactConflicts.ts (content)
⚔️ apps/meteor/app/livechat/server/lib/contacts/updateContact.spec.ts (content)
⚔️ apps/meteor/app/livechat/server/lib/contacts/updateContact.ts (content)
⚔️ apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx (content)
⚔️ apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx (content)
⚔️ apps/meteor/tests/end-to-end/api/livechat/contacts.ts (content)
⚔️ packages/i18n/src/locales/en.i18n.json (content)
⚔️ packages/model-typings/src/models/ILivechatContactsModel.ts (content)
⚔️ packages/models/src/models/LivechatContacts.ts (content)

These conflicts must be resolved before merging into develop.
Resolve conflicts locally and push changes to this branch.
✅ 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 and concisely describes the main change: implementing client-side validation to prevent duplicate omnichannel agents.
Out of Scope Changes check ✅ Passed All changes are directly related to the PR objectives: the changeset documents the fix, AddAgent implements the validation logic, AgentsTable passes agent data, and i18n adds the required error message.
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.


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
Copy Markdown
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 3 files

Copy link
Copy Markdown
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: 2

🤖 Fix all issues with AI agents
In `@apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx`:
- Around line 28-37: The duplicate-agent check in handleSave (which reads agents
from the paginated agents variable) only compares against the current page;
change the flow to call a server-side existence check (e.g., a new
/v1/livechat/users/agent/:username endpoint) or fetch an unpaginated list of
agent usernames before validating to ensure full-scope detection, and update
handleSave to use that result instead of agents?.some(...); also add an error
handler to the saveAction mutation invocation to surface API failures via
dispatchToastMessage (type: 'error') and add the missing translation key
'User_is_already_an_agent' to i18n so the error message resolves correctly.

In `@apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx`:
- Line 75: The AddAgent child receives only the paginated subset data?.users
which misses agents on other pages and is undefined while loading, so modify
AgentsTable to provide AddAgent with a complete, reliable source for duplicate
checks: either fetch all agents (e.g., call a new fetchAllUsers or use the
existing non-paginated users query) and pass that array (e.g., allUsers) to the
AddAgent component, or at minimum pass a stable empty array plus the isLoading
flag (agents={allUsers ?? []} isLoading={isLoading}) so AddAgent can defer
checking until data is ready; update the call site (<AddAgent ...>) and wiring
so AddAgent uses the fullUsers/allUsers prop (or the isLoading prop) for
duplicate detection.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11e1c51 and f5b8cc0.

📒 Files selected for processing (3)
  • .changeset/chilly-wasps-love.md
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (2)
.changeset/chilly-wasps-love.md (1)

1-5: LGTM!

Changeset is properly formatted with the correct package name and patch level.

apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx (1)

34-34: ⚠️ Potential issue | 🟠 Major

Add User_is_already_an_agent translation key to i18n files.

The key is used in the code but is missing from all translation files in packages/i18n/src/locales/. Add the translation to at least en.i18n.json and other locale files, otherwise users will see the raw key string.

⛔ Skipped due to learnings
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@KevLehman KevLehman added the valid A valid contribution where maintainers will review based on priority label Feb 14, 2026
@Dnyanesh-29 Dnyanesh-29 force-pushed the fix/omnichannel-duplicate-agents-v2 branch from f5b8cc0 to e64a7c4 Compare February 14, 2026 19:25
Copy link
Copy Markdown
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/omnichannel/agents/AgentsTable/AddAgent.tsx`:
- Around line 28-39: The handleSave async event in AddAgent.tsx redundantly
calls setUsername('') after await saveAction({ username }) while the
saveAction's onSuccess callback already clears the username; remove the
duplicate by deleting the setUsername('') inside handleSave (the function
created with useEffectEvent) so only the onSuccess handler performs success-side
effects, or alternatively move all success effects into handleSave and remove
the onSuccess callback—ensure you update references to handleSave, saveAction,
and the onSuccess callback accordingly.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5b8cc0 and e64a7c4.

📒 Files selected for processing (4)
  • .changeset/chilly-wasps-love.md
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
  • packages/i18n/src/locales/en.i18n.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.

Applied to files:

  • packages/i18n/src/locales/en.i18n.json
🔇 Additional comments (3)
.changeset/chilly-wasps-love.md (1)

1-5: LGTM! Changeset is properly formatted.

The changeset follows the correct format, specifies an appropriate patch version bump for a bug fix, and provides a clear description of the change.

packages/i18n/src/locales/en.i18n.json (1)

40-40: LGTM — clear, user-facing string for duplicate-agent error.

apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx (1)

37-39: The code already has protection against raw error objects rendering as [object Object] through ToastMessagesProvider. When dispatchToastMessage({ type: 'error', message: error }) is called, the provider's subscribeToToastMessages callback automatically extracts the error message using getErrorMessage() for error objects and handles Error instances explicitly before falling back to String(error).

However, removing the any type annotation and extracting error.message defensively is still reasonable practice for clarity:

Suggested fix
- } catch (error: any) {
-   dispatchToastMessage({ type: 'error', message: error });
+ } catch (error) {
+   dispatchToastMessage({ type: 'error', message: error instanceof Error ? error.message : String(error) });
  }

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@Naetiksoni08
Copy link
Copy Markdown
Contributor

Hi, I'm the original reporter of issue #38684.
I noticed this fix doesn't handle the case-sensitivity edge case — UserAutoComplete returns mixed case display names (e.g. "Rocket.Cat") while the database stores lowercase usernames (e.g. "rocket.cat"). Without toLowerCase(), the duplicate check silently fails and the bug persists.

I've addressed this along with the correct i18n key placement in my PR #38702.

@Dnyanesh-29 Dnyanesh-29 force-pushed the fix/omnichannel-duplicate-agents-v2 branch from e64a7c4 to 450db2f Compare February 16, 2026 14:18
Copy link
Copy Markdown
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/omnichannel/agents/AgentsTable/AddAgent.tsx`:
- Around line 28-33: The duplicate-agent check in the handleSave (created via
useEffectEvent) uses strict equality and is case-sensitive, so normalize both
sides for a case-insensitive comparison: when checking agents?.some((agent) =>
agent.username && agent.username === username) convert agent.username and
username to the same case (e.g., .toLowerCase()) and guard null/undefined
usernames to avoid errors; update the isAlreadyAgent computation accordingly so
mixed-case display names from UserAutoComplete match stored lowercase usernames.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e64a7c4 and 450db2f.

📒 Files selected for processing (4)
  • .changeset/chilly-wasps-love.md
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
  • packages/i18n/src/locales/en.i18n.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/i18n/src/locales/en.i18n.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx
  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
🧠 Learnings (1)
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx
🧬 Code graph analysis (1)
apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx (1)
packages/models/src/models/Users.ts (1)
  • setUsername (2835-2839)
🔇 Additional comments (2)
.changeset/chilly-wasps-love.md (1)

1-5: LGTM!

Changeset is correctly configured as a patch bump for @rocket.chat/meteor.

apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx (1)

37-38: The code is correct as-is. The ToastMessagesProvider implementation explicitly handles error objects passed to dispatchToastMessage by calling getErrorMessage() (line 51-52 in ToastMessagesProvider.tsx), which gracefully extracts the message string from error properties like reason, error, or message. The error object will not render as [object Object] because the framework's error handling is designed to accept error objects for the error type (as shown in ToastMessagePayload's type definition where error messages accept unknown). No changes needed.

Likely an incorrect or invalid review comment.

@Dnyanesh-29 Dnyanesh-29 force-pushed the fix/omnichannel-duplicate-agents-v2 branch from 450db2f to b4e118e Compare February 16, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

valid A valid contribution where maintainers will review based on priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(omnichannel): prevent duplicate agent addition with client-side validation

3 participants