Skip to content

feat: add pagination for item selector#1422

Open
IceeAn wants to merge 1 commit into
sysadminsmedia:mainfrom
IceeAn:fix/parent-item-selector-pagination
Open

feat: add pagination for item selector#1422
IceeAn wants to merge 1 commit into
sysadminsmedia:mainfrom
IceeAn:fix/parent-item-selector-pagination

Conversation

@IceeAn
Copy link
Copy Markdown
Contributor

@IceeAn IceeAn commented Apr 10, 2026

What type of PR is this?

  • bug
  • feature

What this PR does / why we need it:

This PR fixes a performance issue caused by rendering too many items in the item selector popover by adding a paginated UI.

  • frontend/components/Item/Selector.vue: Add pagination for the item selector, using a single request and handling pagination on the frontend to stay closer to the original behavior. Some item list paginations already work this way.
  • frontend/locales/en.json: adds English localization strings for items.first_page and items.last_page.

Which issue(s) this PR fixes:

Fixes #1333

Special notes for your reviewer:

I'm a bit confused by the existed i18n keys and translations for the pagination controls' aria labels (items.prev_page, items.next_page, items.first, and items.last), so I checked the commit history.

These keys were introduced in 0a4c5fb, then become unused in cbaf483 due to a component change. After that, items.first and items.last were translated to different meanings across languages. For example, items.last has been translated as "last", "last item", "last page", or even "last name".

In this change, I reused items.prev_page and items.next_page. However, for translation accuracy and clearer semantics, I added items.first_page and items.last_page instead of reusing the existing items.first and items.last.

If needed, I believe items.first and items.last could be safely removed.

Summary by CodeRabbit

Release Notes

  • New Features
    • Item Selector command list now supports pagination with navigation controls to jump to first, previous, next, or last page
    • Users can input a specific page number to navigate directly
    • Customizable page size (default 10 items per page)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

Walkthrough

The Item Selector component now supports pagination of command list results through a new pageSize prop, pagination state management, computed navigation properties, and page navigation handlers. Pagination resets when the popover opens and when search terms change. Additionally, English locale strings for "First Page" and "Last Page" labels were added.

Changes

Cohort / File(s) Summary
Pagination Feature
frontend/components/Item/Selector.vue
Added pagination support with pageSize prop, currentPage state, computed properties for pageCount, showPagination, navigation enablement, and handlers for first/prev/next/last page navigation. Pagination state resets on popover open and search changes. Component renders paginatedItems instead of full filtered list.
Locale Strings
frontend/locales/en.json
Added two new English i18n keys: items.first_page ("First Page") and items.last_page ("Last Page") for pagination UI labels.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Suggested labels

⬆️ enhancement

Suggested reviewers

  • tankerkiller125
  • tonyaellie

Security Recommendations

When reviewing pagination logic, please verify:

  1. Input Validation: Ensure pageInput and currentPage values are properly validated and cannot exceed pageCount or accept negative numbers that could bypass intended bounds checking.
  2. XSS Prevention: Confirm that page numbers and pagination UI elements don't introduce template injection vulnerabilities, particularly in how the selected item key is mapped to pages.
  3. Frontend-only Pagination: Verify this is intentionally frontend-only pagination (for UX responsiveness) and that any backend search/filtering still occurs server-side to prevent information disclosure of private items.
  4. State Reset Security: Ensure pagination state reset logic cannot be exploited to bypass search filters or expose unintended items through race conditions between state resets and async search operations.

Poem

📄✨ Six thousand items now dance with grace,
Pagination brings order to the space,
No more freezes, no more endless scroll,
The selector's burden finally under control! 🎭

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add pagination for item selector' clearly summarizes the main change in the PR, which introduces pagination functionality to the item selector component.
Description check ✅ Passed The PR description covers all required sections: type (bug, feature), what it does (adds pagination to fix performance issue), which issue it fixes (#1333), and special notes explaining i18n decisions. The description is complete and well-documented.
Linked Issues check ✅ Passed The PR directly addresses issue #1333 by implementing pagination on the frontend to handle the performance issue with ~6,500 items, making the dropdown responsive and usable without rendering all items at once.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the pagination feature: the Selector component implements pagination logic and the locale file adds necessary i18n strings. No unrelated modifications are present.
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 unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot added the ⬆️ enhancement New feature or request label Apr 10, 2026
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.

🧹 Nitpick comments (3)
frontend/components/Item/Selector.vue (3)

202-203: Minor type simplification opportunity.

pageInput is typed as ref<string | number> but is consistently set to a string via String() throughout the code. Since HTML number inputs return strings via v-model, the type could be simplified to ref<string>("1") for clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/Item/Selector.vue` around lines 202 - 203, Change
pageInput from ref<string | number>("1") to ref<string>("1") to reflect that
HTML number inputs and existing String() calls always produce strings; update
any places that consume pageInput as a number (e.g., pagination handlers or uses
alongside currentPage) to explicitly parseInt(pageInput.value, 10) or use
Number(...) before numeric operations, and keep currentPage as ref(1) unchanged.
Use the symbols pageInput and currentPage to locate and adjust the related code
in Selector.vue.

177-194: Consider validating pageSize to be positive.

If a caller passes pageSize: 0 or a negative value, pageCount becomes Infinity or NaN, and findPageForSelectedKey would produce incorrect results due to division by zero. While unlikely in practice, a defensive check could prevent subtle bugs.

♻️ Optional: Add runtime validation
+  const effectivePageSize = computed(() => Math.max(1, props.pageSize));
+
-  const pageCount = computed(() => Math.ceil(filtered.value.length / props.pageSize));
+  const pageCount = computed(() => Math.ceil(filtered.value.length / effectivePageSize.value));
   // ... and use effectivePageSize.value elsewhere instead of props.pageSize
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/Item/Selector.vue` around lines 177 - 194, Validate and
guard the pageSize prop to ensure it's a positive integer before it's used
(currently set via withDefaults on the props), because zero or negative values
make pageCount Infinity/NaN and break findPageForSelectedKey; update the prop
normalization where pageSize is defined (the withDefaults/defineProps block) to
coerce or clamp incoming pageSize to a minimum of 1 (or throw a clear error) and
ensure any local calculations that read pageSize (e.g., pageCount computation
and findPageForSelectedKey) use the normalized value.

344-357: The blur loop may be more aggressive than necessary.

event.preventDefault() already prevents focus transfer from pagination buttons. The subsequent loop that blurs all inputs in the parent element (including the search input) seems redundant and could cause unexpected UX where the search input loses focus when navigating pages.

If the intent is specifically to blur the page number input after interaction, consider targeting it more precisely.

♻️ Simplify to rely on preventDefault alone
  function handlePaginationToolbarPointerDown(event: PointerEvent) {
-   const toolbar = event.currentTarget as HTMLElement | null;
    const target = event.target as HTMLElement | null;
    if (target?.closest("input")) {
      return;
    }

    event.preventDefault();
-   const inputElements = toolbar?.parentElement?.querySelectorAll<HTMLInputElement>("input");
-   inputElements?.forEach(inputElement => {
-     inputElement.blur();
-   });
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/Item/Selector.vue` around lines 344 - 357, The blur loop
in handlePaginationToolbarPointerDown is too aggressive and unnecessary; remove
the blanket inputElements.forEach(...) blur logic and either rely solely on
event.preventDefault() to stop focus changes or target and blur only the
specific page-number input (e.g., locate it via a dedicated selector or class
such as a page-input or name="page" using toolbar.parentElement?.querySelector)
so the search input doesn't lose focus unintentionally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/components/Item/Selector.vue`:
- Around line 202-203: Change pageInput from ref<string | number>("1") to
ref<string>("1") to reflect that HTML number inputs and existing String() calls
always produce strings; update any places that consume pageInput as a number
(e.g., pagination handlers or uses alongside currentPage) to explicitly
parseInt(pageInput.value, 10) or use Number(...) before numeric operations, and
keep currentPage as ref(1) unchanged. Use the symbols pageInput and currentPage
to locate and adjust the related code in Selector.vue.
- Around line 177-194: Validate and guard the pageSize prop to ensure it's a
positive integer before it's used (currently set via withDefaults on the props),
because zero or negative values make pageCount Infinity/NaN and break
findPageForSelectedKey; update the prop normalization where pageSize is defined
(the withDefaults/defineProps block) to coerce or clamp incoming pageSize to a
minimum of 1 (or throw a clear error) and ensure any local calculations that
read pageSize (e.g., pageCount computation and findPageForSelectedKey) use the
normalized value.
- Around line 344-357: The blur loop in handlePaginationToolbarPointerDown is
too aggressive and unnecessary; remove the blanket inputElements.forEach(...)
blur logic and either rely solely on event.preventDefault() to stop focus
changes or target and blur only the specific page-number input (e.g., locate it
via a dedicated selector or class such as a page-input or name="page" using
toolbar.parentElement?.querySelector) so the search input doesn't lose focus
unintentionally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b0967c5c-5624-4a90-b3f0-c2d1a400cb51

📥 Commits

Reviewing files that changed from the base of the PR and between dc0c45c and 8e1aa97.

📒 Files selected for processing (2)
  • frontend/components/Item/Selector.vue
  • frontend/locales/en.json

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

Labels

⬆️ enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance issue when selecting parent item

1 participant