Skip to content

Improve table pagination #1567

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

jfacoustic
Copy link

@jfacoustic jfacoustic commented Apr 22, 2025

Summarize the changes made and the motivation behind them.

  • Updated the pagination table layout to take itemsPerPage and totalItems instead of totalPages.
  • This allows standard table-like pagination. Most tables allow specifying how many items are shown per page.

Reference related issues using # followed by the issue number.
#1181

If there are breaking API changes - like adding or removing props, or changing the structure of the theme - describe them, and provide steps to update existing code.

PaginationProps differentiates TablePaginationProps from the props for navigation/pagination layouts. Since the number of pages is based on itemsPerPage and totalItems, it is unnecessary to have the user specify totalPages when using a table layout.

This is achieved by creating the BasePaginationProps interface, which contains the props shared by all layouts, and extending it with DefaultPaginationProps (for navigation and pagination layouts) and TablePaginationProps. PaginationProps is now set to a union type.

No changes are necessary to update existing code that uses navigation or pagination layouts. The only changes necessary for table layouts are to update their usage from

 <Pagination layout="table" currentPage={currentPage} totalPages={100} onPageChange={onPageChange} />

to

<Pagination layout="table" currentPage={currentPage} itemsPerPage={10} totalItems={100} onPageChange={onPageChange} />

Summary by CodeRabbit

  • New Features
    • Introduced a dedicated "table" layout for the Pagination component, supporting item range summaries and navigation with itemsPerPage and totalItems props.
  • Refactor
    • Pagination component logic modularized into separate components for standard and table layouts, with improved prop handling, runtime validation, and type safety.
    • Storybook stories updated to handle layout-specific pagination props and rendering.
    • Pagination examples updated to use itemsPerPage and totalItems for the table layout.
  • Tests
    • Added comprehensive tests for the new table layout, covering navigation, item range display, button states, and edge cases such as zero or few total items.

Joshua Mathews added 2 commits April 22, 2025 12:19
- Table Pagination Layout takes totalItems and itemsPerPage instead of
  totalPages.
- Navigation and Pagination Layouts remain the same, although they now
  extend BasePaginationProps.
- Update Tests
Copy link

vercel bot commented Apr 22, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
flowbite-react ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 22, 2025 9:17pm
flowbite-react-storybook ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 22, 2025 9:17pm

Copy link

changeset-bot bot commented Apr 22, 2025

⚠️ No Changeset found

Latest commit: 6c62e90

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Copy link
Contributor

coderabbitai bot commented Apr 22, 2025

Walkthrough

The changes introduce a clear separation between default and table-based pagination layouts across the codebase. The Pagination component is refactored to use two distinct prop types: one for standard pagination and another for table layouts, each with its own required properties. The storybook and example usage are updated to reflect these new props, ensuring that table layouts now require itemsPerPage and totalItems instead of totalPages. Tests are expanded to cover the new table layout, including helper utilities for verifying pagination state. The codebase now modularizes pagination logic for better type safety and clarity.

Changes

File(s) Change Summary
packages/ui/src/components/Pagination/Pagination.tsx Refactored PaginationProps into a union of DefaultPaginationProps and TablePaginationProps. Introduced DefaultPagination and TablePagination components, each handling their respective layouts. Updated main Pagination component to render the correct subcomponent based on the layout prop. Modularized and separated logic for table and default pagination. Added runtime prop validation for both layouts.
apps/storybook/src/Pagination.stories.tsx Refactored the story template to accept a single props object, with conditional logic to handle table and default layouts separately. Updated prop extraction and typing to use the new DefaultPaginationProps and TablePaginationProps. Improved type safety and layout-specific prop handling in the storybook.
apps/web/examples/pagination/pagination.table.tsx,
apps/web/examples/pagination/pagination.tableWithIcons.tsx
Updated usage of the Pagination component to replace totalPages with itemsPerPage and totalItems for table layouts. Adjusted props in both single-line and multi-line JSX usage to align with new table pagination requirements.
packages/ui/src/components/Pagination/Pagination.test.tsx Added a "Table Layout" test suite with helper components and functions to test the new table pagination logic. Introduced PaginationTestTable, PaginationTestOnePageTable, PaginationTestEmptyTable, and tablePaginationState helpers. Expanded tests to verify correct display of item ranges, navigation button behavior, and edge cases for table pagination. Added prop validation tests for both layouts. Updated existing tests to use the new helpers where appropriate.
packages/ui/src/components/Pagination/index.ts Added exported type declarations: DefaultPaginationProps and TablePaginationProps to the module exports for use outside the package.

Sequence Diagram(s)

sequenceDiagram
    participant ParentComponent
    participant Pagination
    participant DefaultPagination
    participant TablePagination

    ParentComponent->>Pagination: Render with props
    alt layout == "table"
        Pagination->>TablePagination: Render with itemsPerPage, totalItems, currentPage, etc.
        TablePagination-->>ParentComponent: onPageChange event
    else layout == "pagination" or "navigation"
        Pagination->>DefaultPagination: Render with totalPages, currentPage, etc.
        DefaultPagination-->>ParentComponent: onPageChange event
    end
Loading

Poem

In the garden of code, the pages turn anew,
Table layouts now shine, with a clearer view.
Items per page, and totals in sight—
Rabbits hop forward, their logic just right.
With tests and stories, the journey’s complete,
Modular and tidy, this change is a treat!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/storybook/src/Pagination.stories.tsx

Oops! Something went wrong! :(

ESLint: 8.57.0

ESLint couldn't find the plugin "eslint-plugin-react".

(The package "eslint-plugin-react" was not found when loaded as a Node module from the directory "/apps/storybook".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react@latest --save-dev

The plugin "eslint-plugin-react" was referenced from the config file in "apps/storybook/.eslintrc.cjs".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85f9d09 and 6c62e90.

📒 Files selected for processing (1)
  • apps/storybook/src/Pagination.stories.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/storybook/src/Pagination.stories.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: 🧰 Build

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
packages/ui/src/components/Pagination/Pagination.test.tsx (1)

254-265: Consider handling undefined case in tablePaginationState

The tablePaginationState function handles null items when pagination values aren't found, but it doesn't handle the case where paginationValues is undefined when the regex match fails.

  const paginationValues = firstItemElement?.textContent?.match(/\d+/g);
- if (paginationValues?.length !== 3) return { firstItem: null, lastItem: null, totalItems: null };
+ if (!paginationValues || paginationValues.length !== 3) return { firstItem: null, lastItem: null, totalItems: null };
apps/storybook/src/Pagination.stories.tsx (1)

5-8: Import types from the distribution build

You're importing types from the compiled distribution rather than source files. This is unusual but might be intentional in your project setup. Consider importing from source files if possible for better development integration.

 import {
   DefaultPaginationProps,
   TablePaginationProps,
-} from "../../../packages/ui/dist/components/Pagination/Pagination";
+} from "../../../packages/ui/src/components/Pagination/Pagination";
packages/ui/src/components/Pagination/Pagination.tsx (3)

47-67: Consider making layout the discriminant key in the base interface

Right now layout is optional in DefaultPaginationProps and mandatory in TablePaginationProps, but it is missing from BasePaginationProps.
If you declare it once in the base interface (as layout?: "navigation" | "pagination" | "table"), TypeScript will recognise it as a discriminant key and JSX excess‑property checks become clearer (e.g. trying to pass totalPages with layout="table" will surface a nicer error).

-export interface BasePaginationProps extends ComponentProps<"nav">, ThemingProps<PaginationTheme> {
+export interface BasePaginationProps
+  extends ComponentProps<"nav">,
+    ThemingProps<PaginationTheme> {
+  /**
+   * Select the visual layout. `"table"` enables the auto‑calculated page
+   * summary, everything else falls back to the classic paginator.
+   */
+  layout?: "navigation" | "pagination" | "table";
   currentPage: number;
   nextLabel?: string;
   onPageChange: (page: number) => void;
   previousLabel?: string;
   showIcons?: boolean;
 }

90-93: Variable aliasing leads to naming inconsistency

showIcons (plural) is defined in the props, but the destructuring renames it to showIcon (singular).
Because the plural form is also used in other components, keeping the name consistent improves readability and avoids accidental duplication in future refactors.

-    showIcons: showIcon = false,
+    showIcons = false,

(Subsequent usages of showIcon on lines 110, 131, 188 & 198 must be changed to showIcons as well.)


178-208: Missing aria-label on the <nav> landmark

Both DefaultPagination and TablePagination render a <nav> but rely solely on visual context.
Add a short label (e.g. “Pagination”) so screen‑reader users can quickly identify the landmark.

-    <nav ref={ref} className={twMerge(theme.base, className)} {...restProps}>
+    <nav
+      ref={ref}
+      aria-label="Pagination"
+      className={twMerge(theme.base, className)}
+      {...restProps}
+    >

Apply the same change to DefaultPagination.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dcc282 and 82120ce.

📒 Files selected for processing (5)
  • apps/storybook/src/Pagination.stories.tsx (3 hunks)
  • apps/web/examples/pagination/pagination.table.tsx (2 hunks)
  • apps/web/examples/pagination/pagination.tableWithIcons.tsx (2 hunks)
  • packages/ui/src/components/Pagination/Pagination.test.tsx (4 hunks)
  • packages/ui/src/components/Pagination/Pagination.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
apps/web/examples/pagination/pagination.tableWithIcons.tsx (1)
packages/ui/src/components/Pagination/Pagination.tsx (1)
  • Pagination (68-71)
packages/ui/src/components/Pagination/Pagination.test.tsx (1)
packages/ui/src/components/Pagination/Pagination.tsx (1)
  • Pagination (68-71)
apps/web/examples/pagination/pagination.table.tsx (1)
packages/ui/src/components/Pagination/Pagination.tsx (1)
  • Pagination (68-71)
apps/storybook/src/Pagination.stories.tsx (1)
packages/ui/src/components/Pagination/Pagination.tsx (4)
  • PaginationProps (66-66)
  • TablePaginationProps (60-64)
  • Pagination (68-71)
  • DefaultPaginationProps (55-59)
packages/ui/src/components/Pagination/Pagination.tsx (1)
packages/ui/src/types/index.ts (1)
  • ThemingProps (20-46)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: 🧰 Build
🔇 Additional comments (10)
apps/web/examples/pagination/pagination.tableWithIcons.tsx (2)

20-20: Props updated to align with the new table pagination API

The migration from totalPages to itemsPerPage and totalItems follows the PR's objective to simplify the pagination API. This change makes the pagination component more intuitive by allowing it to calculate the total pages internally.


33-40: LGTM! The multi-line version correctly implements the new pagination props

The expanded version of the component correctly implements the same prop structure as the inline example, using itemsPerPage and totalItems instead of totalPages.

apps/web/examples/pagination/pagination.table.tsx (2)

20-20: Props updated to align with the new table pagination API

The migration from totalPages to itemsPerPage and totalItems follows the PR's objective to simplify the pagination API. This change makes the pagination component more intuitive by allowing it to calculate the total pages internally.


33-39: LGTM! The multi-line version correctly implements the new pagination props

The expanded version of the component correctly implements the same prop structure as the inline example, using itemsPerPage and totalItems instead of totalPages.

packages/ui/src/components/Pagination/Pagination.test.tsx (3)

100-151: Comprehensive test coverage for the table layout pagination

The new test suite thoroughly covers the table layout pagination functionality, including item range display, navigation button behavior, and page boundary conditions.


161-161: Updated test to use the new PaginationTestTable component

The test for displaying numbered buttons with the table layout has been correctly updated to use the new PaginationTestTable component which implements the new props structure.


212-233: Well-structured test helper component for table pagination

The PaginationTestTable component correctly implements the new table pagination props structure with itemsPerPage and totalItems instead of totalPages.

apps/storybook/src/Pagination.stories.tsx (3)

22-24: Good refactoring of the Template function signature

The Template function now accepts a single props object instead of destructuring specific props upfront, which is a cleaner approach for handling conditional props based on layout.


35-47: Well-implemented conditional rendering for table layout

The conditional rendering for the table layout correctly extracts and passes the appropriate props (itemsPerPage and totalItems) when the layout is "table". The type casting to TablePaginationProps ensures type safety.


49-49: Correct type casting for default pagination props

Type casting to DefaultPaginationProps ensures that the correct props are extracted for non-table layouts. This completes the union type handling approach.

Comment on lines 144 to 169
const TablePagination = forwardRef<HTMLElement, TablePaginationProps>((props, ref) => {
const provider = useThemeProvider();
const theme = useResolveTheme(
[paginationTheme, provider.theme?.pagination, props.theme],
[get(provider.clearTheme, "pagination"), props.clearTheme],
[get(provider.applyTheme, "pagination"), props.applyTheme],
);

const {
className,
currentPage,
nextLabel = "Next",
onPageChange,
previousLabel = "Previous",
showIcons: showIcon = false,
itemsPerPage,
totalItems,
...restProps
} = resolveProps<TablePaginationProps>(props, provider.props?.pagination);

const totalPages = Math.ceil(totalItems / itemsPerPage);

const offset = (currentPage - 1) * itemsPerPage;
const firstItem = offset + 1;
const lastItem = currentPage === totalPages ? totalItems : offset + itemsPerPage;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle 0 or negative itemsPerPage / totalItems to avoid NaN & confusing UI

If itemsPerPage is 0 (or a negative number) the division yields Infinity/NaN.
When totalItems is 0, the text currently renders “Showing 1 to 0 of 0 Entries”.

-  const totalPages = Math.ceil(totalItems / itemsPerPage);
-
-  const offset = (currentPage - 1) * itemsPerPage;
-  const firstItem = offset + 1;
-  const lastItem = currentPage === totalPages ? totalItems : offset + itemsPerPage;
+  // Guard‑clause against invalid inputs
+  const safeItemsPerPage = Math.max(1, itemsPerPage);
+  const safeTotalItems = Math.max(0, totalItems);
+
+  const totalPages = Math.max(1, Math.ceil(safeTotalItems / safeItemsPerPage));
+
+  const offset = (currentPage - 1) * safeItemsPerPage;
+  const firstItem = safeTotalItems === 0 ? 0 : offset + 1;
+  const lastItem =
+    safeTotalItems === 0
+      ? 0
+      : Math.min(offset + safeItemsPerPage, safeTotalItems);

This removes potential runtime warnings and yields “Showing 0 to 0 of 0 Entries” when there are no rows.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/ui/src/components/Pagination/Pagination.tsx (2)

181-181: Improve accessibility for table pagination status.

Good change from role="meter" to role="status", which is semantically correct. However, the component should notify assistive technologies when the content changes.

Add aria-live="polite" to ensure screen readers announce updates when the pagination changes:

- <div role="status" aria-label="Table Pagination" className={theme.layout.table.base}>
+ <div role="status" aria-live="polite" aria-label="Table Pagination" className={theme.layout.table.base}>

165-169: 🛠️ Refactor suggestion

Handle edge cases in pagination calculations.

The current implementation has potential issues with edge cases:

  1. If itemsPerPage is 0 or negative, the division will yield Infinity or NaN
  2. When totalItems is 0, the display shows "Showing 0 to 0 of 0 Entries"

Add safeguards to handle these cases:

- const totalPages = totalItems > 0 ? Math.ceil(totalItems / itemsPerPage) : 1;
-
- const offset = (currentPage - 1) * itemsPerPage;
- const firstItem = totalItems > 0 ? offset + 1 : 0;
- const lastItem = currentPage === totalPages ? totalItems : offset + itemsPerPage;
+ // Guard against invalid inputs
+ const safeItemsPerPage = Math.max(1, itemsPerPage);
+ const safeTotalItems = Math.max(0, totalItems);
+
+ const totalPages = Math.ceil(safeTotalItems / safeItemsPerPage) || 1;
+
+ const offset = (currentPage - 1) * safeItemsPerPage;
+ const firstItem = safeTotalItems === 0 ? 0 : offset + 1;
+ const lastItem = safeTotalItems === 0 
+   ? 0 
+   : Math.min(offset + safeItemsPerPage, safeTotalItems);
🧹 Nitpick comments (1)
packages/ui/src/components/Pagination/Pagination.tsx (1)

53-53: Inconsistent naming between prop and internal usage.

The prop is named showIcons (plural) in the interface but aliased to showIcon (singular) when destructuring. This creates an inconsistency between the public API and internal usage.

Consider renaming the prop in the interface definition to match the theme property:

- showIcons?: boolean;
+ showIcon?: boolean;

Then update the destructuring to match:

- showIcons: showIcon = false,
+ showIcon = false,

Also applies to: 91-91

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82120ce and ad22db7.

📒 Files selected for processing (4)
  • apps/storybook/src/Pagination.stories.tsx (3 hunks)
  • packages/ui/src/components/Pagination/Pagination.test.tsx (4 hunks)
  • packages/ui/src/components/Pagination/Pagination.tsx (3 hunks)
  • packages/ui/src/components/Pagination/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/ui/src/components/Pagination/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/storybook/src/Pagination.stories.tsx
  • packages/ui/src/components/Pagination/Pagination.test.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/ui/src/components/Pagination/Pagination.tsx (2)
packages/ui/src/types/index.ts (1)
  • ThemingProps (20-46)
packages/ui/src/components/Pagination/index.ts (3)
  • PaginationButtonProps (14-14)
  • paginationTheme (19-19)
  • PaginationNavigation (16-16)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: 🧰 Build
🔇 Additional comments (3)
packages/ui/src/components/Pagination/Pagination.tsx (3)

47-67: Well-structured props hierarchy with union type.

Great job restructuring the pagination props into a clean hierarchy with a base interface and specialized interfaces for default and table pagination. This approach improves type safety and clarifies the API contract for consumers.


69-72: Good component composition pattern.

Excellent use of component composition to cleanly delegate to specialized components based on layout type. This keeps the main component simple while separating implementation details.


145-210:

✅ Verification successful

Consider additional test cases for the new TablePagination component.

The new TablePagination component introduces complex logic for calculating item ranges and pagination limits. While the implementation is sound, these calculations have potential edge cases.

Consider adding tests for the following scenarios:

  • Zero total items
  • Total items less than items per page
  • Edge cases with large numbers of items
  • Boundary conditions (first page, last page)

🏁 Script executed:

#!/bin/bash
# Check for existing tests that cover the TablePagination edge cases

echo "Searching for existing pagination tests..."
rg -A 3 "test\([\'\"]table|describe\([\'\"]table" --type tsx

Length of output: 272


🏁 Script executed:

#!/bin/bash
echo "Searching for TablePagination references in test files..."
rg "TablePagination" --glob "*.test.tsx" --glob "*.spec.tsx" -n || echo "No direct references to TablePagination found."

echo "Searching for pagination-related tests in test files..."
rg -i "pagination" --glob "*.test.tsx" --glob "*.spec.tsx" -n || echo "No pagination-related tests found."

Length of output: 5660


Tests already cover TablePagination edge cases

I’ve confirmed in packages/ui/src/components/Pagination/Pagination.test.tsx that:

  • PaginationTestEmptyTable covers zero total items
  • PaginationTestOnePageTable covers total items less than items per page
  • PaginationTestTable exercises first, middle, and last‐page boundaries

Given this existing coverage, no additional TablePagination tests are necessary.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/ui/src/components/Pagination/Pagination.tsx (2)

182-186: Add safety guards for edge cases in pagination calculations

The current implementation might have issues with edge cases. Consider adding additional guards to ensure calculations produce expected results in all scenarios.

-  const totalPages = totalItems > 0 ? Math.ceil(totalItems / itemsPerPage) : 1;
-
-  const offset = (currentPage - 1) * itemsPerPage;
-  const firstItem = totalItems > 0 ? offset + 1 : 0;
-  const lastItem = currentPage === totalPages ? totalItems : offset + itemsPerPage;
+  // Guard against edge cases with safe calculations
+  const safeItemsPerPage = Math.max(1, itemsPerPage);
+  const safeTotalItems = Math.max(0, totalItems);
+
+  const totalPages = Math.max(1, Math.ceil(safeTotalItems / safeItemsPerPage));
+
+  const offset = (currentPage - 1) * safeItemsPerPage;
+  const firstItem = safeTotalItems === 0 ? 0 : offset + 1;
+  const lastItem = safeTotalItems === 0 ? 0 : Math.min(offset + safeItemsPerPage, safeTotalItems);

This ensures that:

  1. Division by zero is prevented even if validation is bypassed
  2. When totalItems is 0, both firstItem and lastItem are 0
  3. lastItem never exceeds totalItems

198-202: Add aria-live attribute for better accessibility

For dynamic content that updates as the user navigates, adding an aria-live attribute helps screen readers announce changes.

-      <div role="status" aria-label="Table Pagination" className={theme.layout.table.base}>
+      <div role="status" aria-live="polite" aria-label="Table Pagination" className={theme.layout.table.base}>
🧹 Nitpick comments (2)
packages/ui/src/components/Pagination/Pagination.test.tsx (1)

450-461: Consider more robust error handling in the tablePaginationState helper

The current implementation returns null values if the pagination element isn't found or doesn't contain exactly 3 numbers, which could lead to cryptic test failures.

  const tablePaginationState = () => {
    const firstItemElement = screen
      .getAllByRole("status")
      .find((elem) => elem.getAttribute("aria-label") === "Table Pagination");
    const paginationValues = firstItemElement?.textContent?.match(/\d+/g);
-   if (!paginationValues || paginationValues?.length !== 3) return { firstItem: null, lastItem: null, totalItems: null };
+   if (!paginationValues || paginationValues?.length !== 3) {
+     throw new Error(`Table pagination element not found or has unexpected format. Found text: "${firstItemElement?.textContent}"`);
+   }
    return {
      firstItem: parseInt(paginationValues[0]),
      lastItem: parseInt(paginationValues[1]),
      totalItems: parseInt(paginationValues[2]),
    };
  };
packages/ui/src/components/Pagination/Pagination.tsx (1)

188-194: Consider extracting shared navigation functions

The goToNextPage and goToPreviousPage functions are duplicated between DefaultPagination and TablePagination. Consider extracting them to a shared utility.

+// Add at the top of the file
+function createPaginationHandlers(currentPage: number, totalPages: number, onPageChange: (page: number) => void) {
+  return {
+    goToNextPage: () => onPageChange(Math.min(currentPage + 1, totalPages)),
+    goToPreviousPage: () => onPageChange(Math.max(currentPage - 1, 1)),
+  };
+}

// Then in TablePagination
-  function goToNextPage() {
-    onPageChange(Math.min(currentPage + 1, totalPages));
-  }
-
-  function goToPreviousPage() {
-    onPageChange(Math.max(currentPage - 1, 1));
-  }
+  const { goToNextPage, goToPreviousPage } = createPaginationHandlers(currentPage, totalPages, onPageChange);

// And use the same approach in DefaultPagination
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad22db7 and a5451cb.

📒 Files selected for processing (2)
  • packages/ui/src/components/Pagination/Pagination.test.tsx (4 hunks)
  • packages/ui/src/components/Pagination/Pagination.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/ui/src/components/Pagination/Pagination.test.tsx (1)
packages/ui/src/components/Pagination/Pagination.tsx (1)
  • Pagination (69-72)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: 🧰 Build
🔇 Additional comments (12)
packages/ui/src/components/Pagination/Pagination.test.tsx (8)

100-171: The new Table Layout test suite provides excellent coverage. LGTM!

The test suite comprehensively covers important scenarios for the table pagination, including:

  • Display of pagination state (first/last item, total items)
  • Next/previous button functionality
  • Button disabling logic at boundaries
  • Edge cases like empty tables and tables with fewer items than page size

This is a well-structured set of tests with good coverage of the functionality.


219-224: Good test for table layout not displaying numbered buttons

This test ensures that the table layout doesn't display numbered buttons, which is important for maintaining the expected UI behavior.


226-263: Comprehensive validation tests for currentPage in table layout

The tests ensure that the component properly validates currentPage must be a positive integer in the table layout, preventing potential rendering issues or calculation errors.


265-302: Good validation tests for itemsPerPage in table layout

These tests ensure that itemsPerPage is properly validated as a positive integer, which is essential for correct pagination calculations.


304-329: Proper validation testing for totalItems in table layout

The tests verify that totalItems must be a non-negative integer, which is an appropriate constraint for the pagination component.


362-383: Well-structured test helper component for table pagination

This helper component provides a clean setup for testing table pagination with multiple pages (95 items with 10 per page = 10 pages).


385-406: Great test helper for single-page table scenario

This helper tests an important edge case where there are fewer items than the page size, ensuring that the pagination behaves correctly in this scenario.


408-429: Excellent test coverage for empty table scenario

Testing the edge case of zero items is important to ensure the pagination component degrades gracefully when no data is available.

packages/ui/src/components/Pagination/Pagination.tsx (4)

47-67: Well-structured interface separation improves type safety and API clarity

The division into base props and layout-specific prop interfaces creates a cleaner API and better type safety. This enables strong typing for layout-specific properties and clear documentation of required props for each layout.


69-72: Clean component structure with conditional rendering based on layout

The refactoring to use separate components for different layouts improves code organization and maintainability.


95-101: Good validation of props to prevent invalid states

Adding explicit validation for currentPage and totalPages prevents common usage errors and provides clear error messages.


173-181: Good prop validation for TablePagination component

The validation ensures that all required props have valid values, preventing runtime errors and unexpected behavior.

@jfacoustic
Copy link
Author

@SutuSebastian Could you review this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant