Skip to content

feat: Privacy setting to disable finding users by partial matches of their name - #3316

Open
samuelwei wants to merge 16 commits into
developfrom
2264-disable-find-users-by-name
Open

feat: Privacy setting to disable finding users by partial matches of their name#3316
samuelwei wants to merge 16 commits into
developfrom
2264-disable-find-users-by-name

Conversation

@samuelwei

@samuelwei samuelwei commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Fixes #2264

Type

  • Bugfix
  • Feature
  • Documentation
  • Refactoring (e.g. Style updates, Test implementation, etc.)
  • Other (please describe):

Checklist

  • Code updated to current develop branch head
  • Passes CI checks
  • Is a part of an issue
  • Tests added for the bugfix or newly implemented feature, describe below why if not
  • Changelog is updated
  • Documentation of code and features exists

Changes

  • Add privacy setting to disable finding users by partial matches of their name

Summary by CodeRabbit

  • New Features
    • Added an administrator setting to enable or disable searching users by partial name or email (default: enabled).
    • When disabled, user lookups use exact email matching only.
  • UI/UX Improvements
    • Updated member-add and ownership-transfer user pickers to use a shared search component with debounced input and cancellation of outdated searches.
    • Improved email-only messaging, placeholders, and no-results states when the setting is disabled.
  • Backend/API
    • Search behavior and returned settings now reflect the new toggle.
  • Tests & Documentation
    • Updated feature and E2E tests; extended changelog and admin translations.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@samuelwei, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8c50783e-b8f2-49d0-8c2a-61b8b5d0a6bb

📥 Commits

Reviewing files that changed from the base of the PR and between 9f9154a and a713748.

📒 Files selected for processing (4)
  • lang/en/rooms.php
  • resources/js/components/RoomTabMembersAddSingleModal.vue
  • resources/js/components/RoomTransferOwnershipButton.vue
  • resources/js/components/UserSearch.vue

Walkthrough

Adds an administrator-controlled user.search_by_name setting. The backend switches between name-or-email and email-only searches, while member and ownership-transfer dialogs use a shared debounced search component with cancellation support.

Changes

User search privacy setting

Layer / File(s) Summary
Settings persistence and administration
database/settings/*, app/Settings/*, app/Http/Controllers/api/v1/SettingsController.php, app/Http/Requests/*, app/Http/Resources/*, resources/js/views/AdminSettings.vue, lang/en/admin.php, tests/Backend/Feature/api/v1/SettingsTest.php, tests/Frontend/e2e/AdminSettings*.cy.js
Adds, validates, persists, exposes, and administrates the user_search_by_name setting with backend and UI coverage.
Conditional API search
app/Http/Controllers/api/v1/UserController.php, tests/Backend/Feature/api/v1/UserTest.php
Uses name-or-email matching when enabled and escaped email-only matching when disabled.
Member lookup UI and request handling
resources/js/components/UserSearch.vue, resources/js/components/RoomTabMembersAddSingleModal.vue, resources/js/components/RoomTransferOwnershipButton.vue, lang/en/rooms.php, tests/Frontend/e2e/RoomsView*.cy.js, tests/Frontend/fixtures/config.json
Centralizes user lookup, updates conditional prompts, debounces searches, cancels prior requests, and tests email-only behavior in member dialogs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested labels: tests, frontend, UI

Suggested reviewers: copilot, sabr1n4w

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds a global name-search toggle, but it does not implement the requested per-user profile visibility control for user lists. Add a per-user visibility setting and ensure member selection, room add, and ownership transfer searches honor it.
Docstring Coverage ⚠️ Warning Docstring coverage is 52.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main privacy-search feature changed in this PR.
Description check ✅ Passed The description matches the template with issue reference, type, checklist, and changes summary.
Out of Scope Changes check ✅ Passed The changes stay focused on the privacy-search feature across settings, UI, tests, and docs.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2264-disable-find-users-by-name

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.

@samuelwei

Copy link
Copy Markdown
Collaborator Author
image image

@samuelwei

Copy link
Copy Markdown
Collaborator Author

@Pierre-Lannoy Is that resolving your issue ?

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.38710% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.10%. Comparing base (8f5fb85) to head (a713748).
⚠️ Report is 4 commits behind head on develop.

Files with missing lines Patch % Lines
resources/js/components/UserSearch.vue 97.95% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #3316      +/-   ##
=============================================
- Coverage      97.10%   97.10%   -0.01%     
- Complexity      1949     1950       +1     
=============================================
  Files            483      484       +1     
  Lines          16656    16666      +10     
  Branches        2408     2409       +1     
=============================================
+ Hits           16174    16183       +9     
- Misses           482      483       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cypress

cypress Bot commented Jul 16, 2026

Copy link
Copy Markdown

PILOS    Run #3213

Run Properties:  status check failed Failed #3213  •  git commit a713748947: feat: Privacy setting to disable finding users by partial matches of their name
Project PILOS
Branch Review 2264-disable-find-users-by-name
Run status status check failed Failed #3213
Run duration 07m 57s
Commit git commit a713748947: feat: Privacy setting to disable finding users by partial matches of their name
Committer Samuel Weirich
View all properties for this run ↗︎

Test results
Tests that failed  Failures 1
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 636
View all changes introduced in this branch ↗︎

Tests for review

Failed  e2e/RoomsJoinWithLobby.cy.js • 1 failed test • System tests

View Output

Test Artifacts
Room Join with lobby settings > Lobby enabled Test Replay Screenshots

@Pierre-Lannoy

Copy link
Copy Markdown

Hello @samuelwei !
Anything that prevents direct visibility or accounts enumeration meets the criteria. So yes, your suggestion is great and will solve this issue that my users have reported.
Thank you again for taking care of all this…

@samuelwei
samuelwei marked this pull request as ready for review July 17, 2026 09:54

@Sabr1n4W Sabr1n4W left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not completely sure about debouncing the user search requests.
The debounce itself makes sense to reduce the number of user search requests but especially the error messages shown while typing (Too many users found, No user found) can be a bit confusing.

e.g. the following scenario:

  1. Open add single user dialog
  2. Enter a name that produces no results.
    • Error message "Oops! No user was found for this query" shown while typing
  3. Clear name and wait for request with empty query
  4. Enter the same name again
    • Error message "To many users found..." shown while typing

Not sure if the error messages could/should maybe be improved to be less confusing or maybe be hidden while typing.

->assertSuccessful()
->assertJsonCount(0, 'data');

// Check with exact lastname match (search for names should not be possible)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Check with exact lastname match (search for names should not be possible)
// Check with exact firstname match (search for names should not be possible)

"rooms.members.modals.add.no_options_email_only",
);

// Check placeholder and type in input

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Check placeholder and type in input
// Check placeholder

"rooms.members.modals.add.no_options_email_only",
);

// Check placeholder and type in input

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Check placeholder and type in input
// Check placeholder

Comment on lines +44 to +50
* @return AnonymousResourceCollection
*/
public function search(UserSearchRequest $request)
public function search(UserSearchRequest $request, UserSettings $userSettings)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not completely sure about this

Currently we mostly use app(UserSettings::class) etc. to access the settings. The way used here is also working and from what I understand might be the cleaner way to do this so I would tend to keep it.

If this is kept, the docblock should perhaps be updated accordingly.
Also the new search behavior should be included/described in the docblock.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

  • change to app(...) syntax for now
  • refactor everything to dependency injection in a new PR


const onSearchChange = useDebounceFn((query) => {
asyncFind(query);
}, 500);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Unsure what a good debounce time would be. Research is unclear, somewhere between 200 - 500 ms.
Added ms query logging to our instance on 23.07.2026 10:40 (Europe/Berlin), will analyse logs after a week to find min./avg./med. input time for our users

@samuelwei

Copy link
Copy Markdown
Collaborator Author

Current results:

51b79445051ab3d231eceb1a950c1485c68e3fc4f1821a9776df71cbc5a5a0a8 session=1
  requests : 13
  duration : 1900 ms
  intervals: 12
  min      : 52 ms
  max      : 217 ms
  avg      : 158.33 ms
  median   : 160.00 ms

51b79445051ab3d231eceb1a950c1485c68e3fc4f1821a9776df71cbc5a5a0a8 session=2
  requests : 14
  duration : 2921 ms
  intervals: 13
  min      : 32 ms
  max      : 938 ms
  avg      : 224.69 ms
  median   : 160.00 ms

34719e85a179f2ace3b9690e88a9b0847aa107a94d6191f2505b3b0ab99a2389 session=1
  requests : 8
  duration : 2024 ms
  intervals: 7
  min      : 87 ms
  max      : 786 ms
  avg      : 289.14 ms
  median   : 210.00 ms

d949537394c7daf6afc66df7db44073ca5f420a5d53e4428bd430a54f53eac46 session=1
  requests : 14
  duration : 5355 ms
  intervals: 13
  min      : 136 ms
  max      : 1835 ms
  avg      : 411.92 ms
  median   : 245.00 ms

Copilot AI review requested due to automatic review settings July 28, 2026 13:06

Copilot AI left a comment

Copy link
Copy Markdown

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 new instance-wide privacy setting that controls whether users can be found via partial name/email matching, wiring it through backend settings/config APIs and updating affected frontend member/ownership transfer search UX accordingly.

Changes:

  • Introduces user.search_by_name setting (default true) and exposes it via /api/v1/settings and /api/v1/config.
  • Updates user search behavior: when disabled, backend search only matches exact email instead of partial name/email matching.
  • Updates admin UI + member/ownership-transfer UI strings and Cypress coverage (including debounced searching).

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Frontend/fixtures/settings.json Adds user_search_by_name to settings fixture.
tests/Frontend/fixtures/config.json Adds user.search_by_name to config fixture.
tests/Frontend/e2e/RoomsViewSettings.cy.js Updates ownership transfer placeholder expectations; adds “search by name disabled” scenario.
tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js Updates member-add search assertions; adds “search by name disabled” scenario.
tests/Frontend/e2e/AdminSettingsView.cy.js Verifies new admin setting is displayed in view-only mode.
tests/Frontend/e2e/AdminSettingsEdit.cy.js Verifies new admin setting can be edited and is sent in form payload.
tests/Backend/Feature/api/v1/UserTest.php Adds backend coverage for search behavior when the setting is disabled.
tests/Backend/Feature/api/v1/SettingsTest.php Extends settings API tests to include the new setting (but contains a naming bug).
resources/js/views/AdminSettings.vue Adds toggle UI for the new setting in Admin Settings.
resources/js/components/RoomTransferOwnershipButton.vue Uses config setting to adjust placeholder/prompt text; debounces search requests.
resources/js/components/RoomTabMembersAddSingleModal.vue Uses config setting to adjust placeholder/prompt text; debounces search requests.
lang/en/rooms.php Adds new i18n strings for email-only prompt/placeholder.
lang/en/admin.php Adds i18n title/description for the admin setting.
database/settings/2026_07_15_130614_add_user_name_search_disabled.php Adds the new user.search_by_name setting (default true).
CHANGELOG.md Documents the feature and adds link references (one link target is incorrect).
app/Settings/UserSettings.php Adds public bool $search_by_name.
app/Http/Resources/SettingsResource.php Exposes user_search_by_name via SettingsResource.
app/Http/Resources/ConfigResource.php Exposes user.search_by_name via ConfigResource.
app/Http/Requests/UpdateSettingsRequest.php Validates user_search_by_name as a required boolean.
app/Http/Controllers/api/v1/UserController.php Switches user search query logic based on search_by_name.
app/Http/Controllers/api/v1/SettingsController.php Persists user_search_by_name into UserSettings::search_by_name.

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

Comment thread tests/Backend/Feature/api/v1/SettingsTest.php Outdated
Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Http/Controllers/api/v1/UserController.php`:
- Around line 52-62: Update the search method PHPDoc to describe both supported
behaviors: name-or-email searching when UserSettings::search_by_name is enabled
and email-only searching otherwise. Keep the documentation aligned with the
existing User::withNameOrEmail and User::whereLike branches.
- Around line 52-62: Update the search_by_name-disabled branch in UserController
to perform an exact, case-insensitive email lookup instead of passing raw input
to User::whereLike, ensuring % and _ remain literal characters. Preserve the
existing name-or-email search behavior and add regression coverage for email
queries containing both wildcard characters.

In `@resources/js/components/RoomTabMembersAddSingleModal.vue`:
- Around line 192-200: Prevent stale search results and loading updates by
adding a monotonically increasing search generation to the debounced/API flow in
resources/js/components/RoomTabMembersAddSingleModal.vue lines 192-200 and
resources/js/components/RoomTransferOwnershipButton.vue lines 282-290. Pass the
generation through each search, apply results and loading-state changes only
when it is still current, and invalidate or cancel the generation when the modal
closes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d0139e97-78ec-40fb-8b04-a24cbb3927ca

📥 Commits

Reviewing files that changed from the base of the PR and between 8f5fb85 and 2715511.

📒 Files selected for processing (21)
  • CHANGELOG.md
  • app/Http/Controllers/api/v1/SettingsController.php
  • app/Http/Controllers/api/v1/UserController.php
  • app/Http/Requests/UpdateSettingsRequest.php
  • app/Http/Resources/ConfigResource.php
  • app/Http/Resources/SettingsResource.php
  • app/Settings/UserSettings.php
  • database/settings/2026_07_15_130614_add_user_name_search_disabled.php
  • lang/en/admin.php
  • lang/en/rooms.php
  • resources/js/components/RoomTabMembersAddSingleModal.vue
  • resources/js/components/RoomTransferOwnershipButton.vue
  • resources/js/views/AdminSettings.vue
  • tests/Backend/Feature/api/v1/SettingsTest.php
  • tests/Backend/Feature/api/v1/UserTest.php
  • tests/Frontend/e2e/AdminSettingsEdit.cy.js
  • tests/Frontend/e2e/AdminSettingsView.cy.js
  • tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js
  • tests/Frontend/e2e/RoomsViewSettings.cy.js
  • tests/Frontend/fixtures/config.json
  • tests/Frontend/fixtures/settings.json

Comment thread app/Http/Controllers/api/v1/UserController.php
Comment thread resources/js/components/RoomTabMembersAddSingleModal.vue Outdated
Copilot AI review requested due to automatic review settings July 28, 2026 15:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

app/Http/Controllers/api/v1/UserController.php:64

  • Typo in comment: “wild-card” is usually written as “wildcard”.
            // Escape wild-card characters and escape backslashes to prevent escaping our added escape backslash

app/Http/Controllers/api/v1/UserController.php:48

  • Docblock grammar: “search of partial matches” should be “search for partial matches” to accurately read as a sentence.

This issue also appears on line 64 of the same file.

     * Search for users in the whole database
     * Depending on the search_by_name setting it will either search of partial matches of firstname, lastname and email
     * or only for an exact email match

Copilot AI review requested due to automatic review settings July 28, 2026 16:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

tests/Backend/Feature/api/v1/UserTest.php:279

  • This comment says "exact lastname match" but the query used is Gregory (firstname). This makes the test harder to understand/maintain.
        // Check with exact lastname match (search for names should not be possible)

app/Http/Controllers/api/v1/UserController.php:48

  • Docblock grammar: "search of partial matches" should be "search for partial matches" to accurately describe the behavior.
     * Search for users in the whole database
     * Depending on the search_by_name setting it will either search for partial matches of firstname, lastname and email
     * or only for an exact email match

tests/Backend/Feature/api/v1/UserTest.php:274

  • This comment says "exact firstname match" but the query used is Dumas (lastname). This makes the test harder to understand/maintain.

This issue also appears on line 279 of the same file.

        // Check with exact firstname match (search for names should not be possible)

resources/js/components/RoomTransferOwnershipButton.vue:287

  • onSearchChange() clears users and sets loading, but it doesn't reset tooManyResults. If the previous query produced a 204 "too many results", the UI can briefly show the wrong message for subsequent queries until the next response arrives.
function onSearchChange(query) {
  isLoadingSearch.value = true;
  users.value = [];
  debouncedFind(query);
}

resources/js/components/RoomTabMembersAddSingleModal.vue:197

  • onSearchChange() clears users and sets loading, but it doesn't reset tooManyResults. If the previous query produced a 204 "too many results", the UI can briefly show the wrong message for subsequent queries until the next response arrives.
function onSearchChange(query) {
  isLoadingSearch.value = true;
  users.value = [];
  debouncedFind(query);
}

database/settings/2026_07_15_130614_add_user_name_search_disabled.php:18

  • The settings migration filename suggests the feature is about "user name search disabled", but the setting being added is user.search_by_name with a default of true (enabled). Renaming the migration file to match the actual setting intent will make the settings history easier to follow.
<?php

declare(strict_types=1);

use Spatie\LaravelSettings\Migrations\SettingsMigration;

return new class extends SettingsMigration
{
    public function up(): void
    {
        $this->migrator->add('user.search_by_name', true);
    }

    public function down(): void
    {
        $this->migrator->delete('user.search_by_name');
    }
};

Copilot AI review requested due to automatic review settings July 28, 2026 16:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

tests/Backend/Feature/api/v1/UserTest.php:279

  • The comment says this is a lastname match, but the query being used is the user's firstname (Gregory). This makes the test harder to understand/maintain.
        // Check with exact lastname match (search for names should not be possible)

resources/js/components/RoomTransferOwnershipButton.vue:287

  • tooManyResults and the in-flight request aren't reset/cancelled when a new search starts. With the 300ms debounce, an older request can still resolve and repopulate the dropdown with stale results (and the UI can keep showing the “too many results” message) until the next request runs.
function onSearchChange(query) {
  isLoadingSearch.value = true;
  users.value = [];
  debouncedFind(query);
}

resources/js/components/RoomTabMembersAddSingleModal.vue:197

  • tooManyResults and the previous in-flight request aren't reset/cancelled when a new search starts. Because the request is only aborted inside asyncFind (after the debounce delay), the prior request can still resolve and briefly show stale results for the previous query.
function onSearchChange(query) {
  isLoadingSearch.value = true;
  users.value = [];
  debouncedFind(query);
}

tests/Backend/Feature/api/v1/UserTest.php:262

  • Test name contains a duplicated word (test_search_search_…). Renaming it improves readability while keeping PHPUnit discovery (method still starts with test_).
    public function test_search_search_by_name_disabled()

tests/Backend/Feature/api/v1/UserTest.php:274

  • The comment says this is a firstname match, but the query being used is the user's lastname (Dumas). This makes the test harder to understand/maintain.

This issue also appears on line 279 of the same file.

        // Check with exact firstname match (search for names should not be possible)

database/settings/2026_07_15_130614_add_user_name_search_disabled.php:11

  • The migration filename suggests this adds a disabled setting (add_user_name_search_disabled), but the migration actually adds user.search_by_name with a default of true. Renaming the migration file to match the setting/purpose would avoid confusion when scanning migration history.
        $this->migrator->add('user.search_by_name', true);

Copilot AI review requested due to automatic review settings July 28, 2026 17:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

resources/js/components/RoomTransferOwnershipButton.vue:287

  • onSearchChange clears users but doesn’t reset tooManyResults, so a previous “too many results” state can be shown while the debounced request is pending. Also, because the request is only aborted inside asyncFind, stale results from the previous in-flight request can still resolve during the 300ms debounce window and overwrite the list.
function onSearchChange(query) {
  isLoadingSearch.value = true;
  users.value = [];
  debouncedFind(query);
}

resources/js/components/RoomTabMembersAddSingleModal.vue:197

  • onSearchChange clears users but doesn’t reset tooManyResults, so the “too many results” message can persist from a previous search while the new debounced request is pending. Also, aborting only inside asyncFind means an older in-flight request can still resolve during the debounce delay and overwrite the results.
function onSearchChange(query) {
  isLoadingSearch.value = true;
  users.value = [];
  debouncedFind(query);
}

lang/en/rooms.php:228

  • New i18n keys (no_options_email_only, placeholder_email_only) were added only to the English locale. Since other lang/*/rooms.php files exist and don’t contain these keys, users on those locales will likely see the raw translation key in the UI when name search is disabled.
                'no_options' => 'Enter the name or email address of a user.',
                'no_options_email_only' => 'Enter the email address of a user.',
                'no_result' => 'Oops! No user was found for this query.',
                'placeholder' => 'Name or email',
                'placeholder_email_only' => 'Email',

lang/en/admin.php:432

  • The new admin.settings.user_search_by_name.* translation keys were added only in lang/en/admin.php. Other locales (lang/*/admin.php) exist and don’t include these keys, so non-English admins may see untranslated keys in the settings UI.
        'user_search_by_name' => [
            'description' => 'Allows users to find others by partial matches of their name or email address. When disabled, users can only be found by entering their exact email address.',
            'title' => 'Allow searching users by name',
        ],

Copilot AI review requested due to automatic review settings July 29, 2026 10:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (7)

resources/js/components/RoomTransferOwnershipButton.vue:168

  • users is now unused after switching to UserSearch (it manages its own options list). Keeping this ref increases confusion and can drift out of sync with the UI.

This issue also appears on line 220 of the same file.

const isLoadingAction = ref(false);
const modalVisible = ref(false);
const users = ref([]);
const newOwner = ref(null);
const newRoleInRoom = ref(3);

resources/js/components/RoomTransferOwnershipButton.vue:225

  • This reset is for the now-removed users ref and can be deleted once users is removed.
function showModal() {
  newOwner.value = null;
  users.value = [];
  newRoleInRoom.value = 3;
  formErrors.clear();
  modalVisible.value = true;

resources/js/components/UserSearch.vue:95

  • Abort any in-flight request when UserSearch unmounts to avoid updating state after unmount and to prevent unnecessary network work.
let abortController = new AbortController();

function onSearchChange(query) {

resources/js/components/RoomTransferOwnershipButton.vue:38

  • Room transfer ownership: the user picker no longer receives the invalid state, so validation errors for user won't visually mark the input as invalid even though a FormError is shown. Pass the invalid prop through to UserSearch like the other member dialogs do.
        <UserSearch
          v-model="newOwner"
          aria-labelledby="user-label"
          data-test="new-owner-dropdown"
          :disabled="isLoadingAction"
        />

resources/js/components/RoomTransferOwnershipButton.vue:38

  • Room transfer ownership: removing the local asyncFind() logic means the current owner is no longer marked as disabled in the dropdown, so users can select an invalid target and only learn on submit (TransferOwnershipRequest rejects selecting the current owner). Consider adding support in UserSearch for disabling/filtering specific user IDs (e.g. the current owner) and use it here.
        <UserSearch
          v-model="newOwner"
          aria-labelledby="user-label"
          data-test="new-owner-dropdown"
          :disabled="isLoadingAction"
        />

resources/js/components/RoomTabMembersAddSingleModal.vue:133

  • After switching to UserSearch, the local users ref is unused and the corresponding reset in showModal() is dead code. Removing both avoids confusion and keeps the state minimal.
const user = ref(null);
const role = ref(null);
const users = ref([]);
const isLoadingAction = ref(false);

resources/js/components/UserSearch.vue:63

  • UserSearch performs async requests; add an unmount hook so in-flight requests can be canceled when the component is destroyed.

This issue also appears on line 93 of the same file.

import Multiselect from "vue-multiselect";
import { ref } from "vue";
import { useApi } from "../composables/useApi.js";

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (1)
resources/js/components/UserSearch.vue (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

vue-multiselect used instead of a PrimeVue component.

This new shared component is built on vue-multiselect rather than a PrimeVue component (e.g. AutoComplete/Select). This mirrors the prior inline implementation, but the coding guideline for resources/js/{views,components}/**/*.vue calls for PrimeVue-based UI for design consistency.

As per coding guidelines, resources/js/{views,components}/**/*.vue: "Use PrimeVue components for building the UI within a Vue.js SPA instead of custom UI components". Since this is a lift of an existing established pattern rather than a new decision, please confirm whether a PrimeVue-based replacement (e.g., AutoComplete) was considered or is planned for a follow-up.

Also applies to: 61-61

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/js/components/UserSearch.vue` at line 2, Replace the
vue-multiselect instance in UserSearch with a PrimeVue component, preferably
AutoComplete or Select, while preserving the existing user-search behavior and
shared component API. Remove the vue-multiselect-specific usage and adapt its
bindings, options, and selection handling to the chosen PrimeVue component.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@resources/js/components/UserSearch.vue`:
- Line 67: Update the defineModel declaration in UserSearch.vue to explicitly
type model as the selected user object or null, using the existing user type
symbol if available. Preserve the current model behavior and default value.

---

Nitpick comments:
In `@resources/js/components/UserSearch.vue`:
- Line 2: Replace the vue-multiselect instance in UserSearch with a PrimeVue
component, preferably AutoComplete or Select, while preserving the existing
user-search behavior and shared component API. Remove the
vue-multiselect-specific usage and adapt its bindings, options, and selection
handling to the chosen PrimeVue component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8960f7fb-1628-4e94-a67f-89c83d4b1b66

📥 Commits

Reviewing files that changed from the base of the PR and between 39a3488 and 9f9154a.

📒 Files selected for processing (4)
  • lang/en/rooms.php
  • resources/js/components/RoomTabMembersAddSingleModal.vue
  • resources/js/components/RoomTransferOwnershipButton.vue
  • resources/js/components/UserSearch.vue
🚧 Files skipped from review as they are similar to previous changes (2)
  • lang/en/rooms.php
  • resources/js/components/RoomTransferOwnershipButton.vue

Comment thread resources/js/components/UserSearch.vue Outdated
Copilot AI review requested due to automatic review settings July 29, 2026 11:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

tests/Backend/Feature/api/v1/UserTest.php:306

  • The query string here includes a raw backslash and '%'. Both characters should be URL-encoded when building the test request; otherwise parsing can differ from real client behavior and may vary by server/proxy. Using http_build_query also makes it explicit you’re testing literal handling of these characters after URL decoding.
        $this->actingAs($users[0])->getJson(route('api.v1.users.search').'?query=gregory\%')
            ->assertSuccessful()
            ->assertJsonCount(0, 'data');

tests/Backend/Feature/api/v1/UserTest.php:314

  • Same URL-encoding issue as above: this request includes a raw backslash and '%'. Encoding via http_build_query ensures the test is asserting behavior after proper URL decoding (what a browser/client would send).
        $this->actingAs($users[0])->getJson(route('api.v1.users.search').'?query=gregory\%')
            ->assertSuccessful()
            ->assertJsonCount(0, 'data');

tests/Backend/Feature/api/v1/UserTest.php:322

  • This query string includes a raw backslash and '%' (both should be URL-encoded). Using http_build_query here keeps the test aligned with real client behavior while still verifying that the backend treats escaped wildcard characters literally.
        $this->actingAs($users[0])->getJson(route('api.v1.users.search').'?query=gregory\_%.dumas@example.com')
            ->assertSuccessful()
            ->assertJsonCount(1, 'data');

lang/en/rooms.php:229

  • The translation for the loading state uses spaced ellipsis ("Searching ..."), which is inconsistent with typical punctuation and other UI strings. Consider changing to "Searching..." for a cleaner message.
                'searching' => 'Searching ...',

tests/Backend/Feature/api/v1/UserTest.php:298

  • These requests put a raw '%' in the query string. In URLs, '%' should be percent-encoded (otherwise it can be interpreted as the start of an escape sequence), so the test is relying on permissive parsing. Build the query string with http_build_query/urlencode so the request matches real client behavior while still asserting that '%' is treated literally by the backend.

This issue also appears in the following locations of the same file:

  • line 304
  • line 312
  • line 320
        $this->actingAs($users[0])->getJson(route('api.v1.users.search').'?query=gregory%')
            ->assertSuccessful()
            ->assertJsonCount(0, 'data');

Copilot AI review requested due to automatic review settings July 29, 2026 11:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

resources/js/components/RoomTransferOwnershipButton.vue:39

  • Selecting the current room owner as the “new owner” is no longer prevented in the dropdown (previously the owner option was marked as disabled). The backend correctly rejects this in TransferOwnershipRequest, but this is a UX regression that will now surface as a validation error that could be avoided client-side.
      <div class="field relative mt-2 flex flex-col gap-2 overflow-visible">
        <label id="user-label">{{ $t("app.user") }}</label>
        <UserSearch
          v-model="newOwner"
          :disabled="isLoadingAction"
          :invalid="formErrors.fieldInvalid('user')"
          aria-labelledby="user-label"
          data-test="new-owner-dropdown"
        />

Copilot AI review requested due to automatic review settings July 29, 2026 11:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.

@samuelwei
samuelwei requested a review from Sabr1n4W July 30, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow users to hide themselves in user lists

4 participants