Skip to content

refactor: replace PermissionsTableFilter with FilterByText - #41186

Open
VanshajPoonia wants to merge 5 commits into
RocketChat:developfrom
VanshajPoonia:refactor/permissions-table-filter-by-text
Open

refactor: replace PermissionsTableFilter with FilterByText#41186
VanshajPoonia wants to merge 5 commits into
RocketChat:developfrom
VanshajPoonia:refactor/permissions-table-filter-by-text

Conversation

@VanshajPoonia

@VanshajPoonia VanshajPoonia commented Jul 5, 2026

Copy link
Copy Markdown

Proposed changes (including videos or screenshots)

Resolves the TODO left in #41143. FilterByText renders the same search input, so the custom PermissionsTableFilter component is no longer needed.

  • PermissionsTable now renders the shared FilterByText component directly and keeps the filter state plus the 500ms debounce, same wiring as the other admin tables
  • Deleted PermissionsTableFilter.tsx
  • Updated render snapshots. The only DOM change is the standard FilterByText form wrapper and an aria-label on the search input

No user-facing behavior change, so no changeset added.

Issue(s)

Closes #41165

Steps to test or reproduce

  1. Go to Admin > Workspace > Permissions
  2. Type in the search input, the table should filter after a short debounce, same as before
  3. The filter should look the same as on other admin pages (for example Custom Sounds)

Further comments

PermissionsTable props are unchanged, so PermissionsPage is untouched. Lint, typecheck and the PermissionsTable.spec.tsx suite (render, a11y and interaction tests) pass locally.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved the admin permissions table text search with a debounced input (500ms) for smoother filtering.
    • Pagination now automatically returns to the first page whenever the debounced search text changes (including while on later pages).
    • Updated the filter UI to an inline “filter by text” control.
  • Tests
    • Added async test coverage to confirm search input updates the filter and resets pagination to page 1.

Resolves the TODO left in RocketChat#41143. FilterByText renders the same search
input, so the custom filter component is no longer needed. The filter
state and its 500ms debounce now live in PermissionsTable.

Closes RocketChat#41165
@VanshajPoonia
VanshajPoonia requested a review from a team as a code owner July 5, 2026 11:22
@dionisio-bot

dionisio-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

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

changeset-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4c1aa6c

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

This PR includes changesets to release 3 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings 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

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: eec82a78-a8d8-4949-867d-85232870b553

📥 Commits

Reviewing files that changed from the base of the PR and between 63c40c1 and 382c21c.

📒 Files selected for processing (1)
  • .changeset/permissions-table-filter-by-text.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/permissions-table-filter-by-text.md
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: cubic · AI code reviewer

Walkthrough

PermissionsTable now keeps local debounced text filter state, renders FilterByText, and resets pagination to the first page when the filter changes. The old standalone filter component was removed, and the test suite now verifies the reset behavior.

Changes

Permissions filter consolidation

Layer / File(s) Summary
Debounced filter state and UI switch
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
PermissionsTable now owns the text input state, debounces it before calling setFilter, resets pagination with setCurrent(0), and renders FilterByText.
Pagination reset test and changeset
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx, .changeset/permissions-table-filter-by-text.md
The updated test types into the search box and verifies the pagination reset, and the changeset records the patch note for the permissions table behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: type: chore

Suggested reviewers: tassoevan, ggazzo

🚥 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 title clearly matches the main change: replacing the custom PermissionsTableFilter with FilterByText.
Linked Issues check ✅ Passed The PR satisfies #41165 by switching the permissions table to FilterByText and removing the custom filter component.
Out of Scope Changes check ✅ Passed The test and changeset updates are directly tied to the filter refactor and pagination fix, with no unrelated scope detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@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

🤖 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
`@apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx`:
- Around line 26-31: The filter update in PermissionsTable currently only calls
setFilter(debouncedText), which leaves usePermissionsAndRoles on whatever
paginationData.current was previously selected. Update the existing useEffect
tied to debouncedText so that changing the debounced filter also resets the
current page to 0 before/along with applying the new filter, ensuring stale
offsets from later pages are cleared.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c3d98211-1619-4976-964e-e687a67023d7

📥 Commits

Reviewing files that changed from the base of the PR and between 3296b4d and 6198186.

⛔ Files ignored due to path filters (1)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/__snapshots__/PermissionsTable.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTableFilter.tsx
💤 Files with no reviewable changes (1)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTableFilter.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: cubic · AI code reviewer
🧰 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/admin/permissions/PermissionsTable/PermissionsTable.tsx
🧠 Learnings (2)
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.

Applied to files:

  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
🔇 Additional comments (1)
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx (1)

4-13: LGTM!

Also applies to: 73-73

Comment thread apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx Outdated

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 3 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx Outdated
Narrowing the filter while on a later page kept the stale offset, so the
client-side slice in usePermissionsAndRoles could return an empty page and
render the no-results state even though matches exist. Reset current to the
first page whenever the debounced filter changes.

@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.

🧹 Nitpick comments (1)
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx (1)

100-122: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assertion doesn't actually verify the reset-on-filter-change behavior.

Per PermissionsTable.tsx, setCurrent(0) fires unconditionally on every effect run, including the initial mount (debouncedText starts as ''). Since setCurrent is only ever called with 0, expect(setCurrent).toHaveBeenLastCalledWith(0) would pass even if the reset-on-change logic were broken, as it's already satisfied by the mount-time call alone. Consider asserting call count (e.g. toHaveBeenCalledTimes(2)) or verifying setCurrent was invoked again after setFilter('admin'), to actually exercise the commit's intended behavior.

♻️ Suggested strengthening
 	await userEvent.type(screen.getByRole('textbox', { name: 'Search' }), 'admin');

 	await waitFor(() => expect(setFilter).toHaveBeenCalledWith('admin'));
-	expect(setCurrent).toHaveBeenLastCalledWith(0);
+	expect(setCurrent).toHaveBeenCalledTimes(2);
+	expect(setCurrent).toHaveBeenLastCalledWith(0);
🤖 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
`@apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx`
around lines 100 - 122, The PermissionsTable pagination test is too weak because
setCurrent(0) is already called on the initial mount, so the final assertion can
pass even if the reset-on-filter-change behavior is broken. Update the
PermissionsTable.spec.tsx test around the PermissionsTable render and
userEvent.type flow to verify a second setCurrent call happens after the filter
changes, either by asserting the call count increases or by checking the
post-search invocation order alongside setFilter('admin').
🤖 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.

Nitpick comments:
In
`@apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx`:
- Around line 100-122: The PermissionsTable pagination test is too weak because
setCurrent(0) is already called on the initial mount, so the final assertion can
pass even if the reset-on-filter-change behavior is broken. Update the
PermissionsTable.spec.tsx test around the PermissionsTable render and
userEvent.type flow to verify a second setCurrent call happens after the filter
changes, either by asserting the call count increases or by checking the
post-search invocation order alongside setFilter('admin').

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: db8892d4-d89e-4e83-aec4-04451f25ce9d

📥 Commits

Reviewing files that changed from the base of the PR and between 6198186 and 8ad2564.

📒 Files selected for processing (2)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: cubic · AI code reviewer
🧰 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/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx
🧠 Learnings (3)
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.

Applied to files:

  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx
🔇 Additional comments (1)
apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.spec.tsx (1)

4-4: LGTM!

VanshajPoonia and others added 3 commits July 6, 2026 19:33
Clear the setFilter/setCurrent mocks after mount so the assertion no longer
passes on the mount-time setCurrent(0) call alone, and instead verifies the
reset is triggered by the filter change itself.
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.

Replaced this by FilterByText, it has the same render

1 participant