Adds « ‹ [1][2][3][4] › » navigation to the library. Page window slides to keep the current page in view. Prev/next/first/last controls are always rendered but disabled at their respective bounds. Also wires up karmaConfig in angular.json so FirefoxHeadless is used for tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.9 KiB
Tasks: Pagination Controls Redesign
Input: Design documents from specs/018-pagination-controls/
Branch: 018-pagination-controls
Scope: Two files change — library.component.ts (template, styles, class) and library.component.spec.ts (tests). No API, no data model, no new files.
Phase 1: Setup
Purpose: Baseline verification before touching the component.
- T001 Confirm existing library component tests pass by running
ng test --include=**/library.component.spec.ts --watch=falsein ui/
Phase 2: Foundational
Purpose: No blocking infrastructure work required — all three user stories build directly on the existing LibraryComponent. Skipped.
Phase 3: User Story 1 — Page Number Navigation (Priority: P1) 🎯 MVP
Goal: Replace the "Page X of Y" text with up to four clickable numbered page buttons. User can jump directly to any visible page.
Independent Test: With more than four pages of images, four numbered buttons appear; clicking a button loads that page and the button shows as active.
Tests for User Story 1 (REQUIRED per §5.1)
- T002 [US1] Write failing tests for
pageWindowgetter covering: first page (→ [1,2,3,4]), last page (→ last 4), middle page (current in window), total pages < 4 (all shown) in ui/src/app/library/library.component.spec.ts
Implementation for User Story 1
- T003 [US1] Add
get pageWindow(): number[]getter toLibraryComponentusing the sliding-window algorithm from plan.md in ui/src/app/library/library.component.ts - T004 [US1] Add
goToPage(page: number)method toLibraryComponent(navigate via router queryParam, callload()) in ui/src/app/library/library.component.ts - T005 [US1] Replace the
<span class="page-indicator">Page {{ currentPage }} of {{ totalPages }}</span>with*ngFornumbered page buttons; add.page-btnand.page-btn.activestyles; verify T002 tests pass in ui/src/app/library/library.component.ts
Checkpoint: Four numbered page buttons visible; clicking one loads the correct page; active button is highlighted.
Phase 4: User Story 2 — Previous/Next Chevrons (Priority: P2)
Goal: Replace text "← Previous" / "Next →" buttons with ‹ › chevrons that are always rendered but visually disabled and non-interactive when at the first or last page.
Independent Test: On page 1 ‹ is disabled; on last page › is disabled; clicking either on a valid page advances or retreats by one.
Tests for User Story 2 (REQUIRED per §5.1)
- T006 [US2] Write failing tests for ‹ › disabled attribute and non-interactivity: disabled on page 1, disabled on last page, enabled otherwise in ui/src/app/library/library.component.spec.ts
Implementation for User Story 2
- T007 [US2] Replace the
*ngIf-gated ← Previous / Next → buttons with always-rendered<button [disabled]="currentPage === 1">‹</button>and<button [disabled]="currentPage === totalPages">›</button>; add.pag-btn:disabledstyle; verify T006 tests pass in ui/src/app/library/library.component.ts
Checkpoint: ‹ and › always visible; disabled at bounds; single-page step works.
Phase 5: User Story 3 — First/Last Jump Buttons (Priority: P3)
Goal: Add « and » buttons that jump directly to page 1 and the last page, disabled when already there.
Independent Test: From any middle page, « jumps to page 1 and » jumps to the last page; both are disabled when already at the respective bound.
Tests for User Story 3 (REQUIRED per §5.1)
- T008 [US3] Write failing tests for
firstPage()andlastPage()methods and disabled states of « » at page boundaries in ui/src/app/library/library.component.spec.ts
Implementation for User Story 3
- T009 [US3] Add
firstPage()andlastPage()methods toLibraryComponent; add<button [disabled]="currentPage === 1">«</button>and<button [disabled]="currentPage === totalPages">»</button>to each end of the pagination bar; verify T008 tests pass in ui/src/app/library/library.component.ts
Checkpoint: Full bar renders as « ‹ [1][2][3][4] › »; all disabled states correct.
Phase 6: Polish & Cross-Cutting Concerns
- T010 Apply final styles: consistent button sizing, gap spacing, and mobile-friendly layout (flex-wrap or min-width as needed) for the full pagination bar in ui/src/app/library/library.component.ts
- T011 Run ESLint and Prettier on ui/src/app/library/ and resolve any issues
Dependencies & Execution Order
- T001: Run first — baseline gate
- T002 → T003 → T004 → T005: Sequential (tests before implementation; each method before its template usage)
- T006 → T007: Sequential (tests before implementation)
- T008 → T009: Sequential (tests before implementation)
- T010, T011: After all story phases complete; can run in either order
User Story Dependencies
- US1 (P1): Independent — starts after T001
- US2 (P2): Starts after US1 is complete (shares same template section)
- US3 (P3): Starts after US2 is complete (adds to the same template section)
All three stories touch the same two files, so parallel execution is not applicable here.
Implementation Strategy
MVP (User Story 1 only)
- T001: Baseline check
- T002–T005: Numbered buttons + goToPage
- Validate: Four page buttons work, active state correct
- Defer US2 and US3 if shipping early
Full Delivery
- T001 baseline → US1 (T002–T005) → US2 (T006–T007) → US3 (T008–T009) → Polish (T010–T011)
- Each story checkpoint validates independence before moving on
Notes
pageWindowalgorithm:start = max(1, currentPage-1); end = min(totalPages, start+3); start = max(1, end-3); pages = [start..end]- No
[P]markers — all tasks share the same two files and must run sequentially - Entire pagination bar hidden when
totalPages <= 1(existing behaviour; do not regress)