Skip to content

feat(paper): switch saved view to dense list#379

Merged
Linjie-top merged 4 commits into
jerry609:devfrom
Linjie-top:fix/paper-table2list
Mar 13, 2026
Merged

feat(paper): switch saved view to dense list#379
Linjie-top merged 4 commits into
jerry609:devfrom
Linjie-top:fix/paper-table2list

Conversation

@Linjie-top

@Linjie-top Linjie-top commented Mar 13, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Refactor

    • Redesigned saved papers from table rows to card-like items with per-item actions (Details, Unsave) and status controls for clearer layout and interaction.
    • Improved reading status labels for clearer user-facing text.
    • Updated paging summary to show correct range (Showing x–y of z) with Prev/Next controls.
  • Tests

    • Added unit tests validating reading status labels and per-item behavior.

@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@Linjie-top has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 4 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 54e26ac1-96c2-4790-82cf-89429a235ffb

📥 Commits

Reviewing files that changed from the base of the PR and between 234f6d5 and bcb73ce.

📒 Files selected for processing (1)
  • web/src/components/research/SavedPapersList.tsx
📝 Walkthrough

Walkthrough

Refactors SavedPapersList to extract a new SavedPaperListItem component and formatReadingStatusLabel helper, switches from table to card-based per-item rendering, changes toggleReadStatus signature to (paperId, nextStatus), updates per-item loading state handling, and adds unit tests for status labels and item shape.

Changes

Cohort / File(s) Summary
SavedPapersList core + item component
web/src/components/research/SavedPapersList.tsx
Extracts SavedPaperListItem component and formatReadingStatusLabel helper; replaces table rows with per-item card rendering; adds per-item actions (Detail, Unsave), status dropdown; updates toggleReadStatus signature to (paperId, nextStatus) and request payload; preserves pagination and selection UI; tracks per-item togglingRead/unsaving state.
Tests
web/src/components/research/SavedPapersList.test.tsx
Adds unit tests for formatReadingStatusLabel mapping and a SavedPaperItem shape/type compatibility check using vitest.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant List as "SavedPapersList"
  participant Item as "SavedPaperListItem"
  participant API as "Server API"
  participant DB as "Database"

  Note over List,Item: UI rendering and per-item actions
  User->>List: view saved papers
  List->>Item: render per-item card (props: item, status, handlers)
  User->>Item: clicks status dropdown / Unsave
  Item->>List: calls onToggleReadStatus(paperId, nextStatus) / onUnsave(paperId)
  List->>API: POST/PUT status change or unsave (status: nextStatus)
  API->>DB: update paper reading_status / saved flag
  DB-->>API: ack
  API-->>List: response success
  List->>Item: update item state (reading_status, toggling flags)
  Item-->>User: updated UI (badge, loading cleared)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

Poem

🐰 In cards they hop, each paper in line,

Status tucked neatly, a little sign,
Click and it scurries from read to to-read,
Unsaved with a thump, then back to its bed,
A rabbit's small cheer for components refined.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: refactoring the saved papers view from a table-based layout to a card-based dense list with modular item components.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience for viewing saved papers by transitioning from a tabular display to a dense, card-like list. This change aims to make the list more visually appealing and easier to scan, while also improving the overall layout and interaction for individual paper items.

Highlights

  • UI Redesign: The display of saved papers has been switched from a traditional table layout to a more compact and dense list format, improving readability and space utilization.
  • Component Refactoring: A new SavedPaperListItem component was introduced to encapsulate the rendering logic for individual saved papers, promoting better modularity and reusability.
  • Table Component Removal: Imports and usage of Table, TableBody, TableCell, TableHead, and TableRow components were removed, replaced by div-based styling for the new list view.
  • Enhanced List Header: The list now includes a 'Select all' checkbox and a display for the total number of papers, providing more interactive and informative controls.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • web/src/components/research/SavedPapersList.tsx
    • Removed imports for Table and related components.
    • Introduced a new SavedPaperListItem functional component to render individual paper details and actions.
    • Refactored the main SavedPapersList component to utilize the new SavedPaperListItem and a div-based layout instead of a Table.
    • Added a 'Select all' checkbox and a paper count display to the list header.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

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 Review

This pull request successfully refactors the saved papers view from a table to a more compact, dense list. The introduction of the SavedPaperListItem component is a great improvement, encapsulating the item rendering logic and making the main component cleaner and more maintainable. The changes are well-executed and align with the goal of improving the UI. I have one suggestion to enhance the clarity of the button labels for updating a paper's reading status.

Comment thread web/src/components/research/SavedPapersList.tsx Outdated
@Linjie-top
Linjie-top marked this pull request as ready for review March 13, 2026 07:07
@Linjie-top
Linjie-top requested a review from jerry609 as a code owner March 13, 2026 07:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
web/src/components/research/SavedPapersList.tsx (1)

156-165: Rename callback arg to match new contract.

onToggleReadStatus now receives the target status, but the prop name still says currentStatus. Please rename it to avoid misuse in future edits.

✏️ Suggested rename
 type SavedPaperListItemProps = {
   item: SavedPaperItem
   status: ReadingStatus
   selected: boolean
   togglingRead: boolean
   unsaving: boolean
   onToggleSelect: (paperId: number) => void
-  onToggleReadStatus: (paperId: number, currentStatus: ReadingStatus) => void
+  onToggleReadStatus: (paperId: number, nextStatus: ReadingStatus) => void
   onUnsave: (paperId: number, externalId: string | null) => void
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/research/SavedPapersList.tsx` around lines 156 - 165, The
prop type SavedPaperListItemProps declares onToggleReadStatus with parameter
named currentStatus but the implementation contract now passes the target
status; update the parameter name to targetStatus in the SavedPaperListItemProps
type (and any related local typings) and then update all call sites and
implementations that reference that parameter name (e.g., components using
onToggleReadStatus, any handlers that accept currentStatus) to use targetStatus
to prevent confusion and match the new contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/components/research/SavedPapersList.tsx`:
- Around line 997-1034: The refactor changed the rendered list structure and how
callbacks are wired (SavedPapersList.tsx: pagedItems mapping to
SavedPaperListItem and handlers toggleSelectAll, toggleSelect, toggleReadStatus,
unsavePaper), but there are no updated tests; add/modify unit/RTL tests to cover
the new dense-list behavior and ensure callbacks are invoked: test rendering of
pagedItems count and "Select all" checkbox (toggleSelectAll), individual
selection (toggleSelect), read-status toggle wiring (toggleReadStatus) including
the updatingAction states (togglingRead/unsaving), and unsave flow
(unsavePaper), plus selectedIds state changes and UI feedback for
toggling/unsaving.
- Around line 240-287: The dropdown is missing the "archived" action so users
cannot set archived status; add another DropdownMenuItem inside
DropdownMenuContent mirroring the others that calls onToggleReadStatus(paper.id,
"archived"), shows the Check icon when status === "archived", and displays the
"Archived" label so formatReadingStatusLabel and the status model remain
consistent; update the list of items adjacent to the existing "To
read"/"Reading"/"Read" DropdownMenuItem entries to include this new "Archived"
entry.

---

Nitpick comments:
In `@web/src/components/research/SavedPapersList.tsx`:
- Around line 156-165: The prop type SavedPaperListItemProps declares
onToggleReadStatus with parameter named currentStatus but the implementation
contract now passes the target status; update the parameter name to targetStatus
in the SavedPaperListItemProps type (and any related local typings) and then
update all call sites and implementations that reference that parameter name
(e.g., components using onToggleReadStatus, any handlers that accept
currentStatus) to use targetStatus to prevent confusion and match the new
contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8a3f69b2-2c97-41ee-8926-cd699ca22449

📥 Commits

Reviewing files that changed from the base of the PR and between 85bc398 and 2ed83a3.

📒 Files selected for processing (1)
  • web/src/components/research/SavedPapersList.tsx

Comment thread web/src/components/research/SavedPapersList.tsx
Comment thread web/src/components/research/SavedPapersList.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/components/research/SavedPapersList.tsx (1)

37-64: ⚠️ Potential issue | 🔴 Critical

Export types and helper for test access.

The test file imports ReadingStatus, SavedPaperItem, and formatReadingStatusLabel, but these are not exported from this module. This will cause compilation errors.

🔧 Proposed fix
-type SavedPaperSort = "saved_at" | "judge_score" | "published_at"
+export type SavedPaperSort = "saved_at" | "judge_score" | "published_at"

-type ReadingStatus = "unread" | "reading" | "read" | "archived"
+export type ReadingStatus = "unread" | "reading" | "read" | "archived"

-type SavedPaperItem = {
+export type SavedPaperItem = {

And for the helper function:

-function formatReadingStatusLabel(status: ReadingStatus): string {
+export function formatReadingStatusLabel(status: ReadingStatus): string {

Also applies to: 149-154

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/research/SavedPapersList.tsx` around lines 37 - 64, The
tests import ReadingStatus, SavedPaperItem, and formatReadingStatusLabel from
this module but they are not exported; update the module to export the
ReadingStatus type, the SavedPaperItem type, and the helper function
formatReadingStatusLabel (and any other helper referenced around the later block
at lines ~149-154) by adding explicit exports for those symbols so tests can
import them (e.g., export type ReadingStatus = ...; export type SavedPaperItem =
...; export function formatReadingStatusLabel(...) { ... }).
🧹 Nitpick comments (2)
web/src/components/research/SavedPapersList.test.tsx (2)

1-1: Remove unused vi import.

The vi mock utility is imported but never used in this file.

🧹 Proposed fix
-import { describe, expect, it, vi } from "vitest"
+import { describe, expect, it } from "vitest"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/research/SavedPapersList.test.tsx` at line 1, The import
statement in SavedPapersList.test.tsx includes an unused symbol `vi`; remove
`vi` from the import so it only imports the used test helpers (`describe`,
`expect`, `it`) to eliminate the unused-import warning and keep imports minimal.

9-44: Tests provide baseline coverage for the helper logic.

The formatReadingStatusLabel tests verify all four status mappings, and the type-shape test confirms structural compatibility. Consider adding RTL-based tests for component rendering and callback wiring (selection, status changes, unsave) to fully cover the behavioral changes from this refactor.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/research/SavedPapersList.test.tsx` around lines 9 - 44,
Current tests cover formatReadingStatusLabel and SavedPaperItem shape but lack
integration/behavioral tests for the SavedPapersList component; add React
Testing Library tests that render the SavedPapersList (using a mock
SavedPaperItem), verify the UI displays the paper title and reading status label
(formatReadingStatusLabel), and simulate user interactions to assert callbacks
are invoked: select item (selection handler), change reading status (status
update handler), and unsave/remove (unsave handler). Use the SavedPapersList
component and SavedPaperItem test data, mock the callback props (onSelect,
onUpdateReadingStatus, onUnsave), fire events to trigger selection/status
change/unsave, and assert the mocks were called with the expected arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/components/research/SavedPapersList.test.tsx`:
- Around line 3-7: The tests import SavedPaperItem, ReadingStatus, and
formatReadingStatusLabel from SavedPapersList but those are not exported yet;
open SavedPapersList.tsx and add exports for the types SavedPaperItem and
ReadingStatus (export type ...) and export the helper function
formatReadingStatusLabel (export function formatReadingStatusLabel) while
keeping the default export SavedPapersList intact so the test imports succeed.

In `@web/src/components/research/SavedPapersList.tsx`:
- Around line 156-165: The prop type SavedPaperListItemProps currently names the
second parameter of onToggleReadStatus as currentStatus but callers pass the
target status to transition to; update the parameter name in the
SavedPaperListItemProps declaration (onToggleReadStatus) from currentStatus to
targetStatus (or similar) so the type reflects actual semantics and avoid
confusion when reading functions that call onToggleReadStatus in this component.

---

Outside diff comments:
In `@web/src/components/research/SavedPapersList.tsx`:
- Around line 37-64: The tests import ReadingStatus, SavedPaperItem, and
formatReadingStatusLabel from this module but they are not exported; update the
module to export the ReadingStatus type, the SavedPaperItem type, and the helper
function formatReadingStatusLabel (and any other helper referenced around the
later block at lines ~149-154) by adding explicit exports for those symbols so
tests can import them (e.g., export type ReadingStatus = ...; export type
SavedPaperItem = ...; export function formatReadingStatusLabel(...) { ... }).

---

Nitpick comments:
In `@web/src/components/research/SavedPapersList.test.tsx`:
- Line 1: The import statement in SavedPapersList.test.tsx includes an unused
symbol `vi`; remove `vi` from the import so it only imports the used test
helpers (`describe`, `expect`, `it`) to eliminate the unused-import warning and
keep imports minimal.
- Around line 9-44: Current tests cover formatReadingStatusLabel and
SavedPaperItem shape but lack integration/behavioral tests for the
SavedPapersList component; add React Testing Library tests that render the
SavedPapersList (using a mock SavedPaperItem), verify the UI displays the paper
title and reading status label (formatReadingStatusLabel), and simulate user
interactions to assert callbacks are invoked: select item (selection handler),
change reading status (status update handler), and unsave/remove (unsave
handler). Use the SavedPapersList component and SavedPaperItem test data, mock
the callback props (onSelect, onUpdateReadingStatus, onUnsave), fire events to
trigger selection/status change/unsave, and assert the mocks were called with
the expected arguments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 15ed4b90-0c8c-4814-aad6-abf8fe8de556

📥 Commits

Reviewing files that changed from the base of the PR and between 2ed83a3 and 234f6d5.

📒 Files selected for processing (2)
  • web/src/components/research/SavedPapersList.test.tsx
  • web/src/components/research/SavedPapersList.tsx

Comment on lines +3 to +7
import type { SavedPaperItem, ReadingStatus } from "./SavedPapersList"

// We import the default component only to ensure the module compiles,
// but these tests focus on the pure helper logic.
import SavedPapersList, { formatReadingStatusLabel } from "./SavedPapersList"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Imports depend on exports being added to the main file.

These imports will fail until SavedPaperItem, ReadingStatus, and formatReadingStatusLabel are exported from SavedPapersList.tsx (see comment on that file).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/research/SavedPapersList.test.tsx` around lines 3 - 7, The
tests import SavedPaperItem, ReadingStatus, and formatReadingStatusLabel from
SavedPapersList but those are not exported yet; open SavedPapersList.tsx and add
exports for the types SavedPaperItem and ReadingStatus (export type ...) and
export the helper function formatReadingStatusLabel (export function
formatReadingStatusLabel) while keeping the default export SavedPapersList
intact so the test imports succeed.

Comment thread web/src/components/research/SavedPapersList.tsx
@Linjie-top
Linjie-top merged commit c5a7646 into jerry609:dev Mar 13, 2026
11 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 11, 2026
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.

1 participant