[Issue]: Paginate PO history #104

Closed
opened 2026-06-23 21:46:58 +00:00 by shad0w · 3 comments
Owner

Raised by

Kaushal Pal Singh (kps@pelagiamarine.com, MANAGER) — via portal Report Issue button

Description

Paginate /history with items per page dropdown

Priority

P2 — Medium

Context

  • Page: /history
  • Reported at: 2026-06-23T21:46:58.350Z
### Raised by Kaushal Pal Singh (kps@pelagiamarine.com, MANAGER) — via portal Report Issue button ### Description Paginate /history with items per page dropdown ### Priority P2 — Medium ### Context - Page: `/history` - Reported at: 2026-06-23T21:46:58.350Z
shad0w added the
portal
label 2026-06-23 21:46:58 +00:00
shad0w added the
feature
claude-queue
triaged
labels 2026-06-23 21:51:07 +00:00
Author
Owner

Claude triage

Triage — Issue #104: Paginate PO history

Type: Feature (enhancement to existing /history behaviour)
Priority: P2 — Medium
Page: /history

Interpretation

The PO History page (/history) currently fetches the most recent 200 POs in
a single query (take: 200, orderBy createdAt desc) and renders them in one flat
table, with a notice ("Showing first 200 results — refine filters to narrow results")
when the cap is hit. There is no way to page past the first 200, and no control over
how many rows show at once.

The request is to add pagination to this table plus an items-per-page dropdown
(e.g. 25 / 50 / 100), preserving the existing filters across page changes.

Action items

  1. Server component — App/app/(portal)/history/page.tsx

    • Read page and perPage from searchParams (add to the Props type). Default
      page=1; default perPage to a sensible value (e.g. 25) and clamp to the allowed
      set (25/50/100) to avoid arbitrary/abusive page sizes.
    • Replace the fixed take: 200 with skip: (page-1)*perPage + take: perPage.
    • Add a db.purchaseOrder.count({ where }) (run in the existing Promise.all) to
      get total rows → compute total pages. count is already an established pattern
      (e.g. dashboard/page.tsx).
    • Replace the "first 200 results" notice (lines 152–154) with pagination controls
      (Prev/Next + page indicator, "Showing X–Y of N"). Keep the Export PDF/CSV
      links exporting the full filtered set (they build their own params and hit
      /api/reports/export — must remain unpaginated).
    • Guard against out-of-range page (e.g. page beyond last → clamp or show empty).
  2. Client filter component — App/app/(portal)/history/history-filters.tsx

    • Add an items-per-page <select> (25/50/100). On change, push to /history with
      the updated perPage and reset page to 1.
    • Ensure apply() / clear() preserve or reset page/perPage consistently
      (changing a filter should reset to page 1).
    • Decision: items-per-page control can live in this filter bar (alongside Apply/Clear)
      or in the pagination footer — either is fine; the filter bar keeps it with the other
      controls and is the lower-risk reuse of the existing useRouter/useSearchParams
      wiring.
  3. (Optional) extract a small pagination helper/component under components/ui/ if
    it reads cleanly — but the codebase has no existing pagination component, so an
    inline footer in page.tsx is acceptable and lower-risk for a single page.

Files / areas involved

  • App/app/(portal)/history/page.tsx (query: skip/take + count; pagination footer)
  • App/app/(portal)/history/history-filters.tsx (per-page dropdown; page reset on filter change)
  • No DB, no schema, no permissions, no API route changes (export route untouched).

Open questions (non-blocking — sensible defaults available)

  • Allowed page sizes & default? Assume 25 / 50 / 100, default 25 (current cap is 200).
  • Should perPage offer an "All" option? Recommend no, to preserve the original
    intent of capping large result sets; if desired it can map back to the old 200 cap.
  • Page-state in URL vs local state? Recommend URL params (?page=&perPage=) to match
    the existing filter pattern (shareable/back-button friendly) — history-filters.tsx
    already round-trips all filters through the query string.

Verifiability

  • pnpm type-check and pnpm lint cover the type/query changes.
  • Behaviour is deterministic and reviewable from the diff; no visual-only feature, no
    external system. The staging DB (pelagia_test) holds prod-like volume so paging is
    exercisable, though no automated history test exists today (could add a light unit test
    for a clamp/perPage helper if extracted).

Routing rationale: Localized two-file enhancement (server component query + client filter control) with a clear acceptance, no DB/auth/payments/external dependency, verifiable by type-check + lint and diff review → claude-queue.

Routing: claude-queue | Type: feature

## Claude triage # Triage — Issue #104: Paginate PO history **Type:** Feature (enhancement to existing `/history` behaviour) **Priority:** P2 — Medium **Page:** `/history` ## Interpretation The PO History page (`/history`) currently fetches the most recent **200** POs in a single query (`take: 200`, `orderBy createdAt desc`) and renders them in one flat table, with a notice ("Showing first 200 results — refine filters to narrow results") when the cap is hit. There is no way to page past the first 200, and no control over how many rows show at once. The request is to add **pagination** to this table plus an **items-per-page dropdown** (e.g. 25 / 50 / 100), preserving the existing filters across page changes. ## Action items 1. **Server component — `App/app/(portal)/history/page.tsx`** - Read `page` and `perPage` from `searchParams` (add to the `Props` type). Default `page=1`; default `perPage` to a sensible value (e.g. 25) and clamp to the allowed set (25/50/100) to avoid arbitrary/abusive page sizes. - Replace the fixed `take: 200` with `skip: (page-1)*perPage` + `take: perPage`. - Add a `db.purchaseOrder.count({ where })` (run in the existing `Promise.all`) to get total rows → compute total pages. `count` is already an established pattern (e.g. `dashboard/page.tsx`). - Replace the "first 200 results" notice (lines 152–154) with pagination controls (Prev/Next + page indicator, "Showing X–Y of N"). Keep the **Export PDF/CSV** links exporting the full filtered set (they build their own params and hit `/api/reports/export` — must remain unpaginated). - Guard against out-of-range `page` (e.g. page beyond last → clamp or show empty). 2. **Client filter component — `App/app/(portal)/history/history-filters.tsx`** - Add an items-per-page `<select>` (25/50/100). On change, push to `/history` with the updated `perPage` and **reset `page` to 1**. - Ensure `apply()` / `clear()` preserve or reset `page`/`perPage` consistently (changing a filter should reset to page 1). - Decision: items-per-page control can live in this filter bar (alongside Apply/Clear) or in the pagination footer — either is fine; the filter bar keeps it with the other controls and is the lower-risk reuse of the existing `useRouter`/`useSearchParams` wiring. 3. **(Optional) extract a small pagination helper/component** under `components/ui/` if it reads cleanly — but the codebase has **no existing pagination component**, so an inline footer in `page.tsx` is acceptable and lower-risk for a single page. ## Files / areas involved - `App/app/(portal)/history/page.tsx` (query: skip/take + count; pagination footer) - `App/app/(portal)/history/history-filters.tsx` (per-page dropdown; page reset on filter change) - No DB, no schema, no permissions, no API route changes (export route untouched). ## Open questions (non-blocking — sensible defaults available) - **Allowed page sizes & default?** Assume 25 / 50 / 100, default 25 (current cap is 200). - **Should `perPage` offer an "All" option?** Recommend no, to preserve the original intent of capping large result sets; if desired it can map back to the old 200 cap. - **Page-state in URL vs local state?** Recommend URL params (`?page=&perPage=`) to match the existing filter pattern (shareable/back-button friendly) — `history-filters.tsx` already round-trips all filters through the query string. ## Verifiability - `pnpm type-check` and `pnpm lint` cover the type/query changes. - Behaviour is deterministic and reviewable from the diff; no visual-only feature, no external system. The staging DB (`pelagia_test`) holds prod-like volume so paging is exercisable, though no automated history test exists today (could add a light unit test for a clamp/`perPage` helper if extracted). Routing rationale: Localized two-file enhancement (server component query + client filter control) with a clear acceptance, no DB/auth/payments/external dependency, verifiable by type-check + lint and diff review → claude-queue. **Routing:** `claude-queue` | **Type:** `feature`
shad0w added
claude-working
and removed
claude-queue
labels 2026-06-23 21:51:07 +00:00
Author
Owner

[Claude] Started working on this issue on branch claude/issue-104.

<!-- ppms-bot --> [Claude] Started working on this issue on branch `claude/issue-104`.
shad0w added
claude-pr
and removed
claude-working
labels 2026-06-23 21:56:59 +00:00
Author
Owner

[Claude] Opened PR #105 with a proposed fix. Review and merge it, then create a release tag to deploy.

<!-- ppms-bot --> [Claude] Opened PR [#105](https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/105) with a proposed fix. Review and merge it, then create a release tag to deploy.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: shad0w/pelagia-portal#104
No description provided.