Skip to content

feat: implement AG Grid with atomic architecture and filter controls - #4

Open
codewalnut-labs wants to merge 3 commits into
mainfrom
dev
Open

codewalnut-labs wants to merge 3 commits into
mainfrom
dev

Conversation

@codewalnut-labs

Copy link
Copy Markdown

What does this PR do?

  • Implements complete AG Grid demo component - Creates a fully functional data grid with Random User API integration, displaying 50 users with comprehensive column definitions and type-safe interfaces
  • Adds user data model and TypeScript interfaces - Implements UserProps interface in dedicated models folder with strict typing for gender, name, email, phone, date of birth, location, and picture fields
  • Creates custom React hook for data management - Implements useAgGridData hook for API data fetching with loading states and proper error handling patterns
  • Implements all AG Grid filter types - Adds text filters (name, email, phone), number filter (age), date filter (DOB), and set filters (city, gender) with floating filter support for enhanced UX
  • Adds dynamic filter toggle functionality - Creates Show/Remove Filters buttons with active (blue) and inactive (gray) states for controlling floating filter visibility in real-time
  • Implements conditional cell styling - Adds age-based color coding (green for <30, orange for >60, blue for middle-age) and gender-based styling (pink for female, blue for male) with proper type safety
  • Creates row-level styling - Implements gender-based row borders (pink for female, blue for male) using AG Grid's getRowStyle callback
  • Creates comprehensive test utilities - Implements renderComponent, checkGridLoaded, checkColumnCount, and checkFiltersEnabled helpers for robust grid testing

What steps does your reviewer have to take to test this PR manually?

  1. Install dependencies - Run npm install to install AG Grid Enterprise, testing libraries, and development tools
  2. Verify TypeScript compilation - Run npm run typecheck to ensure no type errors exist
  3. Run all tests - Execute npm test to confirm all 5 grid tests pass (renders grid, loads data, shows loading state, correct column count, filters enabled)
  4. Check linting - Run npm run lint to validate code quality (should show 0 warnings)
  5. Check formatting - Run npm run format:check to verify code formatting consistency
  6. Run spell check - Execute npm run spell to verify no spelling errors in source files
  7. Start development server - Run npm run dev and navigate to http://localhost:5173 to see the grid
  8. Test filter toggle buttons - Click "Show Filters" and "Remove Filters" buttons in top-right to verify floating filters appear/disappear dynamically
  9. Verify all filter types - Test text filters (First Name, Last Name, Email, Phone), number filter (Age with conditions), date filter (DOB with date picker), and set filters (City, Gender with checkboxes)
  10. Check conditional styling - Verify age-based cell colors (green for young, orange for senior, blue for middle-age) and gender-based row borders (pink/blue)
  11. Test pagination - Navigate through pages using pagination controls and change page size (10, 20, 50) to verify data updates correctly
  12. Test sorting - Click column headers to sort data ascending/descending
  13. Test cell editing - Edit cells and check browser console for change logs (all columns except Picture are editable)

Screenshots

Screenshot 2026-01-30 at 6 18 24 PM Screenshot 2026-01-30 at 6 18 49 PM

Pull Request standards checklist - Please check off

  • This Branch will be carrying one single responsibility - feature/bugfix/style/refactor...
  • I have followed conventional commit messages and descriptive Branch naming.
  • My PR has descriptive folder/file names that I have worked on.

Testing checklist - Please check off

  • I have performed manual testing on my local to validate all changes.

Definition of Done - Please check off

  • My code is well tested and I have confidence my code works as I expect in a variety of situations.
  • I have lint and format code is enabled when the file is saved and I have fixed all errors highlighted by lint.
  • I have deleted all non-descriptive comments and dead code from the files I've touched.
  • I have rebased my branch with the base branch I want to merge into and all the commits in this PR are my own.

- Implement AG Grid component with Random User API integration
- Create custom React hook (useAgGridData) for data fetching and state management
- Implement all AG Grid filter types (text, number, date, set) with floating filters
- Add dynamic filter toggle buttons with active/inactive states
- Implement conditional cell styling based on age ranges and gender
- Add row styling with gender-based border colors
- Create comprehensive test utilities with grid validation helpers
- Establish atomic folder structure (app, features, models, services, hooks, utils)
- Implement pagination with configurable page sizes
…handling, and testing

- Rename AgGridDemo to UserTable for better semantic naming
- Extract UserThumbnail and Button components for reusability
- Move column definitions and default config to utils with style constants
- Add error handling in useAgGridData hook with proper cleanup
- Refactor tests to use fixtures, getByRole, and remove complex utils
- Use semantic HTML tags and optimize grid height with calc()
- Simplify user model types and add API base URL constant
- Remove Vite favicon link from index.html
- Add valueGetter to convert dob.date to Date object for proper agDateColumnFilter functionality
- Map Random User API response to UserProps shape, ensuring city and thumbnailPicture fields are correctly populated for grid display and filtering
@mergemitra-cw

mergemitra-cw Bot commented Apr 27, 2026

Copy link
Copy Markdown

File Change Summary

Moves the top-level bootstrap and shell into src/app, updating the HTML entrypoint and removing the original root files.
Adds the AG Grid user-table slice with fetching, typed models, custom renderers, and shared column utilities.
Updates testing and project config for Biome, CSpell, Vitest setup, and new npm scripts.
Note: the diff only adds local helpers and assertions in src/features/user-table/components/UserTable.test.tsx; the named utilities and editable-cell logging are absent.

File Changes
File Summary
biome.json Adds Biome linting and formatting rules with TypeScript source inclusion and scanner ignores.
cspell.json Adds CSpell vocabulary, TypeScript overrides, and ignore paths for AG Grid, testing, and SVG assets.
eslint.config.js Removes the ESLint flat config after migrating linting to Biome and spelling to CSpell.
index.html Updates the Vite entry script to load src/app/main.tsx instead of src/main.tsx.
package.json Updates scripts for Biome, typechecking, formatting, and spelling while adding AG Grid Enterprise and clsx.
src/App.tsx Removes the previous root component that only rendered the taskflow heading.
src/main.tsx Removes the old root bootstrap that mounted App directly from src/main.tsx.
src/app/App.tsx Adds the main page shell with a user data heading and the UserTable feature.
src/app/main.tsx Adds the new root bootstrap, validates #root, and renders App inside StrictMode.
src/constants/api.ts Adds the Random User API endpoint constant consumed by the data service.
src/features/user-table/components/Button.tsx Adds a reusable variant button with primary and secondary styles plus disabled guarding.
src/features/user-table/components/UserTable.tsx Adds the AG Grid table, filter toggle buttons, pagination, plus loading and error states.
src/features/user-table/components/UserThumbnail.tsx Adds a thumbnail cell renderer that returns a circular 40px image when available.
src/features/user-table/components/fixtures/users.fixture.ts Adds two user fixtures covering male and female rows for component tests.
src/features/user-table/components/UserTable.test.tsx Adds component tests with local helpers for loading, error, row count, column count, and floating filters.
src/features/user-table/hooks/useAgGridData.ts Adds a fetch hook with loading and error state guards around mounted updates.
src/features/user-table/models/user.model.ts Adds typed user fields for gender, names, email, phone, location, DOB, and picture.
src/features/user-table/services/apiService.ts Adds an axios fetch helper that returns Random User results as typed rows.
src/features/user-table/utils/UserTable.utils.ts Extracts nine-column definitions with text, number, date, and set filters plus conditional styling.
src/test/setup.ts Updates the Vitest setup import to the /vitest Jest-DOM entry point.
tsconfig.app.json Updates app TypeScript options by dropping erasable syntax and inline linting comments.

Based on f370dad...84f206a

@mergemitra-cw

mergemitra-cw Bot commented Apr 27, 2026

Copy link
Copy Markdown

PR Review

TL;DR

This PR replaces the starter app with an AG Grid-based user table backed by the Random User API, adds filter-toggle controls, and introduces new styling, hook, service, model, and test layers. The biggest risk is that the grid and fixtures assume a flattened user shape that the live API does not return, so City and Picture data will be blank in production even though the current tests pass. Additional gaps remain around the promised cell-editing flow, AG Grid enterprise bootstrapping, and coverage for the new interaction and helper paths.

Merge Recommendation: Approve with suggestions — the feature is mostly in place, but the live data contract, production hardening, and test coverage still need follow-up before this is ready to rely on.

Focus Areas for Architect Review
  • ag-grid-enterprise is now a runtime dependency and SetFilterModule is registered, but there is no AG Grid license bootstrap anywhere in the repo. If the project is not licensed elsewhere, expect enterprise watermarking and console warnings at runtime.
  • The feature would benefit from a clearer separation between API schema, grid view-model, AG Grid bootstrap, and visual styling. Right now those concerns are split across apiService, useAgGridData, UserTable, and a generic utils file in a way that will get noisy as soon as a second grid or richer user model appears.
  • The PR introduces several behavior-defining literals (results=50, age thresholds, page sizes, filter labels, color values) directly in component/config code. Centralizing those constants early would make the feature easier to tune without editing multiple unrelated files.
  • Random User supports both version pinning and field selection (inc= / exc=); using those in src/constants/api.ts would make this demo more stable and reduce payload size on every mount. (randomuser.me)
  • If ag-grid-enterprise is intentional, the repo needs an explicit operational story for license-key injection and a decision on whether production should keep the full bundle modules or switch to selected modules.
  • The repository has a Vitest/RTL setup, but the new feature is still covered by one component smoke spec; there is no direct unit coverage for the hook/service/helper layer.
  • The fixture data only covers two mid-range users, so multi-page behavior plus the documented sorting/pagination/editing flows are not represented in automated tests.
  • Verification gap: this container has node but no npm/pnpm/yarn/corepack, so I could not run typecheck, test, or build.

🟠 15 major (See below inline comments)

💬 Minor / Nitpicks (5)
  • [Code Quality] 💬 [nitpick] — UserThumbnail uses a type assertion on params.value and stores it in a variable named value. That weakens the type boundary and uses one of the checklist’s banned vague names in a renderer that would be clearer as something explicit like thumbnailUrl. (src/features/user-table/components/UserThumbnail.tsx:15)
  • [Code Quality] 💬 [nitpick] — FILTER_BUTTONS stores a boolean in a property named value, which is both vague and awkward for a boolean flag. The render logic would be easier to follow with a name that states the condition directly, such as showFilters or areFiltersVisible. (src/features/user-table/components/UserTable.tsx:18)
  • [Code Quality] 💬 [nitpick] — UserTable duplicates the same centered status shell for loading and error states, changing only the text and color. That duplication is small now, but these branches tend to drift once empty states, retry actions, or telemetry get added. (src/features/user-table/components/UserTable.tsx:39)
  • [Enterprise Quality] 💬 [nitpick] — The filter toggle communicates state only through button color. The active control never exposes aria-pressed or equivalent selected semantics, so screen-reader users have no programmatic way to tell whether floating filters are currently enabled. (src/features/user-table/components/UserTable.tsx:56)
  • [Test Quality] 💬 [nitpick] — src/features/user-table/components/UserTable.test.tsx:15 and src/features/user-table/components/UserTable.test.tsx:52 rely on findAllByRole('grid')[0] plus .ag-row / .ag-floating-filter class selectors. Those are AG Grid implementation details, so the tests can fail for unrelated DOM churn or keep passing while the public behavior changes. Prefer a single getByRole('grid') and assertions against visible text, labels, or user-facing controls. (src/features/user-table/components/UserTable.test.tsx:15)

Based on f370dad...84f206a


export const fetchUsers = async (): Promise<UserProps[]> => {
const userResponse = await axios.get(RANDOM_USER_API_URL);
return userResponse.data.results;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Correctness] 🟠 The grid is wired to a flattened user shape, but fetchUsers() returns randomuser.me results verbatim. The live payload has location.city and picture.thumbnail, while the model/columns expect top-level city and thumbnailPicture, so the City column/filter never receives real city values and the Picture renderer gets undefined for every row. The current tests miss this because the fixture is already flattened to the incorrect shape.

Related: src/features/user-table/models/user.model.ts:4-11, src/features/user-table/utils/UserTable.utils.ts:95-109, src/features/user-table/components/fixtures/users.fixture.ts:1-20

resizable: true,
filter: true,
floatingFilter: showFilters,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Correctness] 🟠 The advertised cell-editing flow is not implemented. defaultColDef only enables sorting/resizing/filtering, and the grid instance has no onCellValueChanged-style handler, so all columns remain read-only and there is nothing to log when a user edits a cell. Any QA pass that follows the PR’s “edit cells and check console” step will fail immediately.

Related: src/features/user-table/components/UserTable.tsx:63-71


[Code Quality] 🟠 UserTable.utils.ts is already a catch-all module for row styling, cell styling, age/gender styling rules, date formatting, column definitions, and default column config. That violates the one-job-per-module guideline and will make routine grid changes sprawl through a generic utils file instead of a focused column/config module.

headerName: 'DOB',
filter: 'agDateColumnFilter',
valueGetter: (p) => new Date(p.data?.dob.date ?? 0),
valueFormatter: (p) => new Date(p.value).toLocaleDateString(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Correctness] 🟠 DOBs are being converted from full UTC timestamps with new Date(...).toLocaleDateString(), which shifts the calendar day for non-UTC users. For example, 1980-07-30T03:56:55.496Z renders as July 29 in UTC-4/UTC-7. I sampled the current API and 16 of 50 returned DOB timestamps were before 08:00Z, so US users will see and filter against the wrong DOB for a sizable slice of rows.

getRowStyle,
} from '../utils/UserTable.utils';

ModuleRegistry.registerModules([AllCommunityModule, SetFilterModule]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Code Quality] 🟠 ModuleRegistry.registerModules(...) runs as a top-level side effect inside the UserTable component module. That mixes app bootstrap with component rendering, so importing this component now has global behavior attached to it, which makes the component harder to reuse and harder to test in isolation.


[Enterprise Quality] 🟠 ModuleRegistry.registerModules([AllCommunityModule, SetFilterModule]) opts into AG Grid’s full community bundle even though this screen only needs a narrow subset of grid features. AG Grid’s module docs position cherry-picking modules as the bundle-size optimization path and note that AllCommunityModule contains every community module, so every initial load now ships substantially more JavaScript than this table needs.

email: string;
phone: string;
dob: dobType;
city: string;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Code Quality] 🟠 The new model names are misleading for a domain object: UserProps reads like React props, while nameType and dobType are implementation-shaped and not descriptive types. This makes every call site harder to read because the central user model does not sound like a user model.

Comment thread package.json
"@tailwindcss/vite": "^4.1.18",
"ag-grid-community": "^35.0.1",
"ag-grid-enterprise": "^35.0.1",
"ag-grid-react": "^35.0.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Enterprise Quality] 🟠 The PR enables enterprise filtering via SetFilterModule and adds ag-grid-enterprise, but there is no licenseKey/LicenseManager.setLicenseKey integration anywhere in the repo. AG Grid’s React licensing docs require that setup for enterprise usage and call out production watermarks plus console warnings otherwise, so this is not production-ready as merged.

Related: src/features/user-table/components/UserTable.tsx:4-14


return () => {
isMounted = false;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Enterprise Quality] 🟠 useAgGridData only flips an isMounted flag on cleanup; it never cancels the in-flight request, and fetchUsers exposes no abort signal or timeout policy. If the user leaves the page or the Random User endpoint stalls, the browser keeps the connection open and this view can sit in the loading state indefinitely because the request is still outstanding.

Related: src/features/user-table/services/apiService.ts:5-7

Comment thread src/app/App.tsx
return (
<div className="min-h-screen bg-white p-6">
<h1 className="text-3xl font-bold mb-6 text-gray-800">User Data</h1>
<UserTable />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Enterprise Quality] 🟠 The grid is rendered directly under the app root with custom valueGetter, valueFormatter, and cell-renderer logic, but there is no error boundary anywhere in the tree. A render-time exception from AG Grid or malformed remote data will therefore take down the entire page instead of degrading to a controlled fallback.

Related: src/features/user-table/components/UserTable.tsx:63-72, src/features/user-table/utils/UserTable.utils.ts:87-109


return (
<article className="space-y-4">
<nav className="flex justify-end gap-2">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Test Quality] 🟠 The new filter toggle UI in src/features/user-table/components/UserTable.tsx:47 only has a static smoke check in src/features/user-table/components/UserTable.test.tsx:66; nothing clicks Show Filters / Remove Filters with userEvent or verifies that the floating filters actually disappear and reappear. A broken setShowFilters handler, mismatched button labels, or stale active/inactive button state would still leave the suite green. Add one interaction test that drives both buttons and asserts the visible filter controls change.

import { UserThumbnail } from '../components/UserThumbnail';
import type { UserProps } from '../models/user.model';

export const getRowStyle = (params: RowClassParams<UserProps>) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Test Quality] 🟠 The new helper layer has no direct tests: Button, UserThumbnail, useAgGridData, fetchUsers, and the helpers in src/features/user-table/utils/UserTable.utils.ts:10 are only exercised indirectly through src/features/user-table/components/UserTable.test.tsx:28. That leaves the hook's error/unmount path, the thumbnail null fallback, the disabled-button guard, and the age/default styling branches unverified. The fixture in src/features/user-table/components/fixtures/users.fixture.ts:1 only uses ages 34 and 39, so the <30 and >60 cases are never hit.

@codewalnut-labs

Copy link
Copy Markdown
Author

@mergemitra help

@mergemitra

mergemitra Bot commented May 19, 2026

Copy link
Copy Markdown

Available Commands

Command Description
@mergemitra review Full review of the PR diff, considering all previous comments in the conversation
@mergemitra rereview Review only changes since last reviewed commit (falls back to full review if no previous reviews)
@mergemitra list List all available commands

Aliases

  • analyse, analyzereview
  • ls, helplist

More commands coming soon!

1 similar comment
@mergemitra-cw

mergemitra-cw Bot commented May 19, 2026

Copy link
Copy Markdown

Available Commands

Command Description
@mergemitra review Full review of the PR diff, considering all previous comments in the conversation
@mergemitra rereview Review only changes since last reviewed commit (falls back to full review if no previous reviews)
@mergemitra list List all available commands

Aliases

  • analyse, analyzereview
  • ls, helplist

More commands coming soon!

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.

2 participants