Skip to content

fix(ui): fall back the book sorting service to primary file#944

Merged
imnotjames merged 2 commits into
grimmory-tools:developfrom
imnotjames:fix/-/sorting-service-files
Apr 27, 2026
Merged

fix(ui): fall back the book sorting service to primary file#944
imnotjames merged 2 commits into
grimmory-tools:developfrom
imnotjames:fix/-/sorting-service-files

Conversation

@imnotjames

@imnotjames imnotjames commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Description

the frontend sorting service does not take into account the cases where file info may be on the primaryFile rather than on the book itself. in some cases, this also led to the values being undefined which was invalid

Linked Issue: Fixes #

Changes

  • falls back to primaryFile for sorting when the file info isn't on the Book model itself

Summary by CodeRabbit

  • Bug Fixes

    • Improved book sorting when file metadata (name, size, path) is missing — sorting now consistently falls back to alternative file data and handles absent values correctly.
  • Tests

    • Added unit test coverage verifying sorting behavior for fallback file name scenarios to prevent regressions.

@coderabbitai

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 83eb76cb-efc9-4020-bce2-226ee407e895

📥 Commits

Reviewing files that changed from the base of the PR and between 0ff90ee and fb5c747.

📒 Files selected for processing (1)
  • frontend/src/app/features/book/service/sort.service.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/app/features/book/service/sort.service.spec.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test Suite / Backend Tests
  • GitHub Check: Test Suite / Frontend Tests
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (java-kotlin)

📝 Walkthrough

Walkthrough

The SortService now treats missing top-level file fields (fileName, filePath, fileSizeKb) as nullish and falls back to book.primaryFile equivalents. A unit test was added to verify sorting by fileName when the top-level value is absent.

Changes

Cohort / File(s) Summary
Sort service implementation
frontend/src/app/features/book/service/sort.service.ts
Updated fieldExtractors so fileSizeKb, fileName, and filePath return top-level values if present, otherwise fall back to book.primaryFile properties; returns null when no source exists.
Sort service tests
frontend/src/app/features/book/service/sort.service.spec.ts
Added unit test validating applySort sorts by fileName using primaryFile.fileName when the book's top-level fileName is undefined.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • zachyale
  • balazs-szucs

Poem

🐰 I hopped through code in search of names,
When top-level fields played little games.
I peeked in primaryFile with cheer,
Found the names we hold so dear—
Sorted snug, the list appears! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format with 'fix' type prefix and describes the main change of implementing fallback to primaryFile in book sorting.
Description check ✅ Passed The description includes required sections (Description and Changes) with clear explanation of the issue, impact, and solution. The Linked Issue section is present though empty.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@imnotjames imnotjames marked this pull request as ready for review April 27, 2026 14:52
@coderabbitai coderabbitai Bot requested review from balazs-szucs and zachyale April 27, 2026 14:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/app/features/book/service/sort.service.spec.ts`:
- Around line 46-54: The test is not exercising the primaryFile fallback because
makeBook still sets a top-level fileName; update the spec so at least one book
has its top-level fileName cleared (e.g., pass fileName: undefined/null in the
makeBook override) and set primaryFile.fileName values that produce a different
sort order than the default `Book ${id}`; specifically modify the two test books
used with service.applySort (and SortOption/SortDirection) so one relies on
primaryFile.fileName only and the other has a top-level fileName to also cover
precedence (top-level wins).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 28faf8a8-72a5-4028-940a-cef0c6b8a6d8

📥 Commits

Reviewing files that changed from the base of the PR and between 75568d3 and 0ff90ee.

📒 Files selected for processing (2)
  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Packaging Smoke Test
🧰 Additional context used
📓 Path-based instructions (4)
frontend/src/**/*.{ts,tsx,html,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Use 2-space indentation in TypeScript, HTML, and SCSS in frontend code

Files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer inject() over constructor injection in frontend code

Files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
frontend/src/**/*.{ts,tsx,html}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx,html}: Follow frontend/eslint.config.js: component selectors use app-, directive selectors use app, and any is disallowed in frontend code
Put user-facing strings in Transloco files under frontend/src/i18n/

Files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
frontend/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest for tests in frontend code

Files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: pedronave
Repo: grimmory-tools/grimmory PR: 173
File: booklore-api/src/main/java/org/booklore/service/hardcover/HardcoverSyncService.java:188-199
Timestamp: 2026-03-24T18:46:47.249Z
Learning: In grimmory-tools/grimmory (HardcoverSyncService.java), when a `hardcoverBookId` is stored in book metadata but is malformed (non-numeric), the preferred behavior is to return null and skip the sync rather than falling back to ISBN-based lookup. The reasoning is that an explicitly set bookId represents deliberate user intent, and silently resolving via ISBN could sync progress to a different book than intended.
Learnt from: alexhb1
Repo: grimmory-tools/grimmory PR: 831
File: frontend/src/app/features/book/service/shelf.service.ts:15-16
Timestamp: 2026-04-24T11:20:15.820Z
Learning: Repo grimmory-tools/grimmory — In frontend/src/app/features/book/service/shelf.service.ts, detecting the Kobo system shelf via exact match on name 'Kobo' and icon 'pi pi-tablet' is an intentional exception approved by maintainers; do not flag this as fragile or request a backend systemKey for this case.
Learnt from: pedronave
Repo: grimmory-tools/grimmory PR: 247
File: booklore-api/src/main/java/org/booklore/service/hardcover/HardcoverSyncService.java:156-159
Timestamp: 2026-04-01T17:50:06.817Z
Learning: In grimmory-tools/grimmory (HardcoverSyncService.java), the Hardcover API already returns `user_book_reads` in a consistent, ordered fashion (ascending by recency), so `getLast()` reliably retrieves the most recent read entry. Adding an explicit `order_by` to the `user_book_reads` query is unnecessary.
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 372
File: frontend/src/app/features/book/service/app-books-api.service.ts:150-178
Timestamp: 2026-04-04T14:03:28.295Z
Learning: In `frontend/src/app/features/book/service/app-books-api.service.ts`, the `summaryToBook` function intentionally uses `as unknown as Book` to cast a partial object to the `Book` type. The returned object omits some required `Book` fields (e.g. `metadata.bookId`, `pdfProgress.page`) and includes an extra `bookFiles: []` property not in the `Book` interface. This is by design — consumers of `AppBooksApiService.books()` (e.g. `BookCardComponent`) only access the subset of properties that are populated from `AppBookSummary`, so no runtime issues occur. Do not flag this as a type safety error.
📚 Learning: 2026-04-22T01:56:39.495Z
Learnt from: CR
Repo: grimmory-tools/grimmory PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-22T01:56:39.495Z
Learning: Applies to frontend/src/**/*.{test,spec}.{ts,tsx} : Use Vitest for tests in frontend code

Applied to files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
📚 Learning: 2026-04-04T14:03:28.295Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 372
File: frontend/src/app/features/book/service/app-books-api.service.ts:150-178
Timestamp: 2026-04-04T14:03:28.295Z
Learning: In `frontend/src/app/features/book/service/app-books-api.service.ts`, the `summaryToBook` function intentionally uses `as unknown as Book` to cast a partial object to the `Book` type. The returned object omits some required `Book` fields (e.g. `metadata.bookId`, `pdfProgress.page`) and includes an extra `bookFiles: []` property not in the `Book` interface. This is by design — consumers of `AppBooksApiService.books()` (e.g. `BookCardComponent`) only access the subset of properties that are populated from `AppBookSummary`, so no runtime issues occur. Do not flag this as a type safety error.

Applied to files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
📚 Learning: 2026-04-05T21:16:01.715Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 385
File: frontend/src/app/app.component.ts:55-56
Timestamp: 2026-04-05T21:16:01.715Z
Learning: When reviewing code in the Grimmory frontend (Angular), prefer modern Angular patterns. Specifically: (1) Prefer `DestroyRef` with `takeUntilDestroyed(destroyRef)` for teardown in Angular v16+ instead of manually tracking `Subscription` arrays and calling `unsubscribe()` in `ngOnDestroy()`. (2) Prefer `inject()` for dependency injection over constructor injection where appropriate. (3) Prefer Angular signals (e.g., `signal`, `computed`) over `BehaviorSubject`/`Observable` for state where signals/computed values fit the use case. Flag older patterns when they can be replaced with these modern equivalents without changing behavior.

Applied to files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
📚 Learning: 2026-04-07T09:28:09.587Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 393
File: frontend/src/app/features/readers/pdf-reader/pdf-reader.component.ts:255-263
Timestamp: 2026-04-07T09:28:09.587Z
Learning: In this Angular frontend (under frontend/src/app/), flag manual resource management/cleanup patterns when there is an Angular v16+ automatic alternative. Examples to prefer: (1) Instead of manually pairing document/window event listeners with stored cleanup functions (e.g., add/removeEventListener with mouseMoveCleanup/documentClickCleanup/keydownCleanup/touchCleanup fields), register teardown via DestroyRef.onDestroy(cleanupFn) (or equivalent Angular v16+ teardown mechanism). (2) Instead of storing Subscriptions in fields and explicitly unsubscribing in ngOnDestroy (e.g., annotationSaveSubscription/annotationCacheSubscription), use takeUntilDestroyed(destroyRef) (piped into the observable) or other Angular v16+ primitives. (3) If teardown is lifecycle-coupled and can be automated via DestroyRef/takeUntilDestroyed/signals (or other Angular v16+ mechanisms), prefer the automated approach over manual ngOnDestroy cleanup. Raise a review finding for the manual pattern and recommend the aut...

Applied to files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
📚 Learning: 2026-04-11T03:55:57.229Z
Learnt from: zachyale
Repo: grimmory-tools/grimmory PR: 439
File: frontend/src/app/features/series-browser/components/series-browser/series-browser.component.ts:178-196
Timestamp: 2026-04-11T03:55:57.229Z
Learning: In this Angular frontend (frontend/src/app/), prefer the team’s reactive i18n “signal/computed” pattern: (1) For individual reactive translated strings, use `translateSignal()` from `jsverse/transloco`. (2) For option/label arrays that must update on language switch, create a single `activeLang` signal with `toSignal(t.langChanges$, { initialValue: t.getActiveLang() })`, then derive the arrays as `computed()` signals that read `activeLang()`. This should avoid manual `langChanges$` subscriptions and any `ngOnDestroy` subscription cleanup; prefer this over subscribing in `ngOnInit` when implementing reactive localization.

Applied to files:

  • frontend/src/app/features/book/service/sort.service.spec.ts
  • frontend/src/app/features/book/service/sort.service.ts
🔇 Additional comments (1)
frontend/src/app/features/book/service/sort.service.ts (1)

92-94: LGTM — nullish-coalescing fallback to primaryFile is the right shape.

Switching to ?? (rather than ||) for these three extractors is correct: it preserves valid falsy values like fileSizeKb === 0 and fileName === '' instead of incorrectly treating them as missing and falling back. The fallback chain matches the optionality of Book extends FileInfo and Book.primaryFile?: BookFile in book.model.ts.

Comment thread frontend/src/app/features/book/service/sort.service.spec.ts
@imnotjames imnotjames enabled auto-merge (squash) April 27, 2026 15:08
@imnotjames imnotjames merged commit 7da3377 into grimmory-tools:develop Apr 27, 2026
15 checks passed
paulbovbel pushed a commit to paulbovbel/grimmory that referenced this pull request Apr 27, 2026
dsmouse pushed a commit to dsmouse/grimmory that referenced this pull request May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants