Skip to content

Conversation

@david-roper
Copy link
Contributor

@david-roper david-roper commented Mar 25, 2025

closes issue #48

Allows users to go to the first page or the last page of the client table data.

Summary by CodeRabbit

  • New Features

    • Introduced "First Page" and "Last Page" navigation buttons on the client table, enabling quick jumps to the beginning or end of the dataset.
    • Added localized labels for these buttons in English and French for an improved user experience.
  • Tests

    • Introduced a new test suite for the ClientTable component to ensure correct rendering and functionality.
  • Enhancements

    • Added a data attribute for easier targeting of the ClientTable component in testing scenarios.

@david-roper david-roper requested a review from joshunrau as a code owner March 25, 2025 20:36
@coderabbitai
Copy link

coderabbitai bot commented Mar 25, 2025

Walkthrough

This update introduces two navigation buttons to the ClientTablePagination component, allowing users to quickly jump to the first and last pages. The buttons are conditionally disabled based on the current page status. Additionally, new localization entries for these buttons have been added to the translation file to support English and French labels. A new test file for the ClientTable component has also been created to ensure its proper rendering. Furthermore, a data-testid attribute has been added to the ClientTable for improved test targeting.

Changes

File Change Summary
src/components/.../ClientTablePagination.tsx Added "First Page" and "Last Page" buttons with conditional disabling based on the current page position.
src/i18n/.../libui.json Introduced new translation entries for "firstPage" and "lastPage" with English ("<< First", "Last >>") and French ("<< Première", "Dernière >>") texts.
src/components/.../ClientTable.spec.tsx Added a new test file for the ClientTable component to verify correct rendering and functionality.
src/components/.../ClientTable.tsx Added data-testid="ClientTable" attribute to the wrapping <div> for easier targeting in tests.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant PT as ClientTablePagination

    U->>PT: Click "First Page" button
    alt Not on first page
        PT->>PT: Set currentPage to 1
        PT-->>U: Refresh table view
    else Already at first page
        PT-->>U: No action (button disabled)
    end

    U->>PT: Click "Last Page" button
    alt Not on last page
        PT->>PT: Set currentPage to pageCount
        PT-->>U: Refresh table view
    else Already at last page
        PT-->>U: No action (button disabled)
    end
Loading

Poem

I'm a rabbit with a digital hop,
Skipping pages until I reach the top.
First and last, now in my sight,
Translation magic makes it right.
With joyful hops in code so neat,
I celebrate these changes with a beat!
🐰🎉

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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

@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 (4)
src/components/ClientTable/ClientTable.spec.tsx (4)

8-25: Consider simplifying the test data structure

The ExampleItem type declaration includes 15 numeric fields which seems excessive for this test. Best practice is to keep test data minimal while still being representative of real use cases.

-type ExampleItem = {
-  c1: number;
-  c2: number;
-  c3: number;
-  c4: number;
-  c5: number;
-  c6: number;
-  c7: number;
-  c8: number;
-  c9: number;
-  c10: number;
-  c11: number;
-  c12: number;
-  c13: number;
-  c14: number;
-  c15: number;
-  id: string;
-};
+type ExampleItem = {
+  id: string;
+  value1: number;
+  value2: number;
+  value3: number;
+};

49-53: Improve test callback implementation

The current implementation of onSelection just returns the column label but doesn't test any actual behavior. Consider using a mock function to verify it's being called correctly.

-            onSelection: (column) => {
-              return column.label;
-            }
+            onSelection: vi.fn()

78-80: Improve test callback implementation

Similar to the onSelection callback, the onEntryClick just returns the entry. Consider using a mock function to verify it's being called properly.

-        onEntryClick={(entry) => {
-          return entry;
-        }}
+        onEntryClick={vi.fn()}

69-75: Consider test data consistency

The test data uses fields f1, f2, and f3 which don't match the ExampleItem type defined earlier. This inconsistency can lead to confusion.

Make the test data consistent with your type definitions or adjust your types to match the actual test data:

        data={[
          {
-            f1: 1,
-            f2: range(1000).join(', '),
-            f3: 3
+            id: '1',
+            value1: 1,
+            value2: 2, 
+            value3: 3
          }
        ]}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b24cec and f8cfa43.

📒 Files selected for processing (2)
  • src/components/ClientTable/ClientTable.spec.tsx (1 hunks)
  • src/components/ClientTable/ClientTable.tsx (1 hunks)
🔇 Additional comments (1)
src/components/ClientTable/ClientTable.tsx (1)

88-88: LGTM: Test ID added for component testing

Adding the data-testid attribute is a good practice for testing React components, as it provides a reliable way to target the component in tests.

Copy link

@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

🧹 Nitpick comments (4)
src/components/ClientTable/ClientTable.spec.tsx (4)

38-38: Simplify test data to improve test readability and performance.

Using range(1000).join(', ') creates an unnecessarily large string which doesn't add testing value and could slow down test execution.

-            f2: range(1000).join(', '),
+            f2: 'Sample text content',

44-46: Use mock functions for callbacks to improve test effectiveness.

The current callback simply returns the parameter, which doesn't provide meaningful test coverage.

-        onEntryClick={(entry) => {
-          return entry;
-        }}
+        onEntryClick={vi.fn()}

This would allow you to verify the callback is called with the expected arguments in future tests.


16-18: Use mock functions for dropdown callbacks.

Similar to the onEntryClick handler, this callback doesn't provide meaningful test coverage.

-            onSelection: (column) => {
-              return column.label;
-            }
+            onSelection: vi.fn()

1-7: Consider adding a descriptive test file comment.

Adding a brief comment at the top of the file explaining the purpose of these tests would improve documentation.

+/**
+ * Tests for the ClientTable component
+ * Verifies basic rendering and pagination functionality
+ */
 import { range } from '@douglasneuroinformatics/libjs';
 import { render, screen } from '@testing-library/react';
 import { describe, expect, it } from 'vitest';
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f8cfa43 and 8619d1c.

📒 Files selected for processing (1)
  • src/components/ClientTable/ClientTable.spec.tsx (1 hunks)
🔇 Additional comments (1)
src/components/ClientTable/ClientTable.spec.tsx (1)

9-50: Add tests for pagination and new first/last page functionality.

This test only verifies that the component renders, but doesn't test the pagination functionality or the new first/last page buttons that this PR is intended to add.

Consider adding tests that specifically:

  1. Verify first/last page buttons are present
  2. Check that buttons are correctly disabled/enabled based on current page
  3. Confirm clicking these buttons triggers the expected page change
// Example test structure to add:
it('should handle pagination navigation correctly', async () => {
  const onPageChange = vi.fn();
  render(
    <ClientTable
      // ...existing props
      data={Array(30).fill(0).map((_, i) => ({ f1: i, f2: `Row ${i}`, f3: i * 10 }))}
      pageSize={10}
      pagination={true}
      onPageChange={onPageChange}
    />
  );
  
  // Get pagination buttons
  const firstPageButton = screen.getByRole('button', { name: /first page/i });
  const lastPageButton = screen.getByRole('button', { name: /last page/i });
  
  // Test disabled state on first page
  expect(firstPageButton).toBeDisabled();
  
  // Navigate to second page
  await userEvent.click(screen.getByRole('button', { name: /next/i }));
  expect(onPageChange).toHaveBeenCalledWith(expect.objectContaining({ pageIndex: 1 }));
  
  // Test first page button is now enabled
  expect(firstPageButton).not.toBeDisabled();
  
  // More navigation tests...
});

Copy link

@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 (1)
src/components/ClientTable/ClientTable.spec.tsx (1)

12-20: 🛠️ Refactor suggestion

Enhance tests for pagination functionality

While the basic rendering tests are a good start, they don't verify the actual functionality of the pagination buttons (especially the new first/last page buttons that are the focus of this PR). The tests only check if elements are present in the document, not if they work correctly.

Consider adding these tests:

  1. Verify buttons are disabled in appropriate states (e.g., first/previous buttons disabled on first page)
  2. Verify page navigation works by clicking buttons and checking if callbacks are called with correct page numbers
  3. Test page data updates correctly after navigation

Example test enhancement:

import { render, screen, fireEvent } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

// Add more comprehensive tests
it('should disable first/previous buttons on first page', () => {
  render(<ClientTable columns={[]} data={[]} minRows={10} />);
  expect(screen.getByTestId(FIRST_BUTTON_ID)).toBeDisabled();
  expect(screen.getByTestId(PREVIOUS_BUTTON_ID)).toBeDisabled();
});

it('should call onPageChange when pagination buttons are clicked', () => {
  const onPageChange = vi.fn();
  // Render with enough data to have multiple pages
  render(<ClientTable 
    columns={[{field: 'id', label: 'ID'}]} 
    data={Array(50).fill(0).map((_, i) => ({id: i}))} 
    pageSize={10}
    onPageChange={onPageChange}
  />);
  
  // Click next page button
  fireEvent.click(screen.getByTestId(NEXT_BUTTON_ID));
  expect(onPageChange).toHaveBeenCalledWith(expect.objectContaining({ pageIndex: 1 }));
  
  // Click last page button
  fireEvent.click(screen.getByTestId(LAST_BUTTON_ID));
  expect(onPageChange).toHaveBeenCalledWith(expect.objectContaining({ pageIndex: 4 }));
});
🧹 Nitpick comments (2)
src/components/ClientTable/ClientTable.spec.tsx (2)

7-10: Improve test ID naming for consistency

The test ID constants are using different naming patterns - some with hyphens and some with underscores. Consistent naming improves code maintainability.

Consider standardizing on one pattern:

-const TEST_ID = 'ClientTable';
-const FIRST_BUTTON_ID = 'first-page-button';
-const PREVIOUS_BUTTON_ID = 'previous-page-button';
-const NEXT_BUTTON_ID = 'next-page-button';
-const LAST_BUTTON_ID = 'last-page-button';
+const TEST_ID = 'client-table';
+const FIRST_BUTTON_ID = 'first-page-button';
+const PREVIOUS_BUTTON_ID = 'previous-page-button';
+const NEXT_BUTTON_ID = 'next-page-button';
+const LAST_BUTTON_ID = 'last-page-button';

Or:

-const TEST_ID = 'ClientTable';
-const FIRST_BUTTON_ID = 'first-page-button';
-const PREVIOUS_BUTTON_ID = 'previous-page-button';
-const NEXT_BUTTON_ID = 'next-page-button';
-const LAST_BUTTON_ID = 'last-page-button';
+const TEST_ID = 'client_table';
+const FIRST_BUTTON_ID = 'first_page_button';
+const PREVIOUS_BUTTON_ID = 'previous_page_button';
+const NEXT_BUTTON_ID = 'next_page_button';
+const LAST_BUTTON_ID = 'last_page_button';

21-24: Enhance class name test with additional assertions

The test for custom class names could be more robust by verifying that both the custom class and default classes are present.

Consider expanding the test:

it('should apply custom class name while preserving default classes', () => {
  render(<ClientTable className="foo" columns={[]} data={[]} minRows={10} />);
  const table = screen.getByTestId(TEST_ID);
  
  // Verify custom class is applied
  expect(table).toHaveClass('foo');
  
  // Verify default classes are still present (update with actual default classes)
  expect(table).toHaveClass('default-class-1');
  expect(table).toHaveClass('default-class-2');
});
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2055ff3 and 31e6630.

📒 Files selected for processing (1)
  • src/components/ClientTable/ClientTable.spec.tsx (1 hunks)
🔇 Additional comments (1)
src/components/ClientTable/ClientTable.spec.tsx (1)

1-5: LGTM! Imports are well-organized

The imports are properly organized with testing library imports first, followed by a blank line, then the component import.

@joshunrau joshunrau merged commit b578e12 into DouglasNeuroInformatics:main Mar 26, 2025
2 checks passed
@github-actions
Copy link

🎉 This PR is included in version 3.9.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants