Skip to content

Rank saved research areas with a drag-and-drop editor (research-area phase D) - #194

Merged
shu1513 merged 4 commits into
mainfrom
feat/research-area-rank-editor
Jul 5, 2026
Merged

shu1513 merged 4 commits into
mainfrom
feat/research-area-rank-editor

Conversation

@shu1513

@shu1513 shu1513 commented Jul 5, 2026 •

Copy link
Copy Markdown
Owner

What

Research-area phase D: the settings "Issues you care about" section becomes a ranked editor. Until now the UI saved areas without ranks, so the my_areas weighting (rank 1 → weight 7 … rank 7 → weight 1) treated everything as weight-1. Now the list order is the rank.

  • Selected areas: numbered sortable list — drag handle (dnd-kit, 4px pointer activation so the row's buttons stay clickable, keyboard sorting included), ↑/↓ arrows as the no-drag fallback, × to remove, #n rank badge per row.
  • Every add / remove / reorder PUTs the full list with rank = index + 1 — the API validated ranks since migration 125; the UI just never sent them.
  • Unselected catalog renders below as add buttons with a n/7 counter, disabled at the cap (previously an 8th toggle just 400'd).
  • Write safety matches the other full-replace preference sections: optimistic pending overlay + cross-mount useIsMutating guard on ["put-research-area-preferences"].

New dependencies: @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities (keyboard-accessible sortable, the one dependency the plan budgeted for phase D).

Testing

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • You can now reorder “Issues you care about” with drag and drop in Settings.
    • The list now supports a clearer ranked order, with changes saved in the order you choose.
  • Bug Fixes

    • Settings edits are now more resilient during quick consecutive updates.
    • Add/remove actions are disabled while saving to help prevent conflicting changes.
    • A limit is now enforced when the list reaches its maximum size.

Research-area phase D: the settings "Issues you care about" section
becomes a ranked editor instead of flat toggles, so the seven saved
areas finally carry the rank the scoring formula weights.

- Selected areas render as a numbered sortable list (dnd-kit: pointer
  drag with a 4px activation distance so row buttons stay clickable,
  keyboard sorting for accessibility) with up/down arrow buttons as the
  no-drag fallback and a remove control per row.
- List position is the rank: every add, remove, or reorder PUTs the
  full list with rank = index + 1 (the API already validated ranks;
  the UI just never sent them).
- The unselected catalog renders below as add buttons, disabled at the
  7-area cap with a visible counter, replacing the previous uncapped
  toggles that let an 8th selection 400.
- Same write-safety pattern as the other full-replace preference
  sections: optimistic pending overlay for quick consecutive edits and
  a cross-mount useIsMutating guard keyed on
  ["put-research-area-preferences"].

New dependencies: @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@shu1513, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6f008d9a-786c-4bc3-a8a4-add73a474a78

📥 Commits

Reviewing files that changed from the base of the PR and between e462751 and 726b724.

📒 Files selected for processing (1)
  • frontend/src/pages/SettingsPage.tsx
📝 Walkthrough

Walkthrough

Adds @dnd-kit dependencies to the frontend package manifest and reworks the "Issues you care about" editor in SettingsPage.tsx to support drag-and-drop reordering, sending ranked ordering to the backend PUT endpoint with an optimistic pending overlay and in-flight save guard.

Changes

Research Areas Drag-and-Drop Reordering

Layer / File(s) Summary
DnD-kit dependencies and imports
frontend/package.json, frontend/src/pages/SettingsPage.tsx
Adds @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities dependencies and imports DnD context, sensors, sortable helpers, CSS transform utilities, and a MAX_RESEARCH_AREA_RANK constant.
Optimistic pending state and ranked PUT mutation
frontend/src/pages/SettingsPage.tsx
Introduces a pending state for optimistic ordering, changes the PUT body to send ranked {research_area_id, rank} pairs, adds an in-flight saving guard across remounts, and configures pointer/touch/keyboard drag sensors.
Sortable editor UI and draggable rows
frontend/src/pages/SettingsPage.tsx
Replaces the toggle-based list with a DndContext/SortableContext editor deriving orderedIds and atCapacity, implements onDragEnd reordering via arrayMove, and adds a SortableAreaRow component with drag handles and a remove button.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SortableAreaRow
  participant ResearchAreasSection
  participant API

  User->>SortableAreaRow: drag row to new position
  SortableAreaRow->>ResearchAreasSection: onDragEnd(DragEndEvent)
  ResearchAreasSection->>ResearchAreasSection: arrayMove(orderedIds)
  ResearchAreasSection->>ResearchAreasSection: set pending overlay
  ResearchAreasSection->>API: PUT ranked {research_area_id, rank}
  API-->>ResearchAreasSection: updated preferences
  ResearchAreasSection->>ResearchAreasSection: clear pending, saving=false
  ResearchAreasSection->>User: render updated ordered list
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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: ranking research areas with a drag-and-drop editor.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/research-area-rank-editor

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.

@greptile-apps

greptile-apps Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR turns the research-area settings list into a ranked editor. The main changes are:

  • Adds dnd-kit sortable rows for drag, touch, and keyboard reordering.
  • Sends ranked research-area preferences with rank = index + 1.
  • Adds optimistic pending state and an in-flight save guard for full-list writes.
  • Disables add controls at the configured research-area limit.
  • Adds the new dnd-kit dependencies.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
frontend/src/pages/SettingsPage.tsx Adds the ranked research-area editor, ranked save payloads, optimistic state, ballot invalidation, and an in-flight save guard.
frontend/package.json Adds the dnd-kit dependencies used by the sortable editor.
frontend/package-lock.json Locks the new dnd-kit dependency graph.

Reviews (4): Last reviewed commit: "Check the mutation cache in save(); inva..." | Re-trigger Greptile

Comment thread frontend/src/pages/SettingsPage.tsx
Feedback on the rank editor: drag is the one reordering gesture, and
the per-row up/down arrows read as a competing second mechanism. Rows
now drag from anywhere (not just the handle glyph, which stays as a
visual hint), the arrows are gone, and rows keep only the rank badge,
the name, and remove.

Touch gets its own sensor: press-and-hold (200ms, 5px tolerance)
starts a drag so finger-dragging works on mobile without hijacking
page scrolling. Mouse drags still need 4px of movement, so the remove
button stays an ordinary click. Keyboard sorting remains for
accessibility.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread frontend/src/pages/SettingsPage.tsx
Repository owner deleted a comment from coderabbitai Bot Jul 5, 2026
@shu1513

shu1513 commented Jul 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@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: 1

🧹 Nitpick comments (1)
frontend/src/pages/SettingsPage.tsx (1)

477-501: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Move the drag listeners to the grip. Spreading attributes/listeners onto the <li> makes the whole row the drag activator, so the remove button sits inside the drag target. Attach them to the ⠿ handle instead and keep the row itself as a plain container.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/SettingsPage.tsx` around lines 477 - 501, The
drag-and-drop row in the reorder item is using the entire <li> as the activator
because attributes/listeners are spread on the container, which makes the remove
button part of the drag target. Update the reorder item component in
SettingsPage so the drag props from useSortable are attached to the ⠿ grip
element instead of the <li>, while keeping the <li> as a plain layout container;
preserve the existing aria-labels, transform/transition styling, and onClick
remove behavior on the button.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/pages/SettingsPage.tsx`:
- Around line 356-360: The sensor setup in SettingsPage.tsx is pairing
PointerSensor with TouchSensor, but PointerSensor already covers touch and
blocks the intended press-and-hold behavior. Update the sensors used in the
useSensors call to avoid this overlap by switching the mouse path to
MouseSensor, or by using a single PointerSensor with pointer-type-specific
constraints, while keeping KeyboardSensor and sortableKeyboardCoordinates
intact.

---

Nitpick comments:
In `@frontend/src/pages/SettingsPage.tsx`:
- Around line 477-501: The drag-and-drop row in the reorder item is using the
entire <li> as the activator because attributes/listeners are spread on the
container, which makes the remove button part of the drag target. Update the
reorder item component in SettingsPage so the drag props from useSortable are
attached to the ⠿ grip element instead of the <li>, while keeping the <li> as a
plain layout container; preserve the existing aria-labels, transform/transition
styling, and onClick remove behavior on the button.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 49f3a8e4-f615-4e15-b96b-f3925bff5a11

📥 Commits

Reviewing files that changed from the base of the PR and between e4a86c4 and e462751.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • frontend/package.json
  • frontend/src/pages/SettingsPage.tsx

Comment thread frontend/src/pages/SettingsPage.tsx
…PUTs

Review follow-ups on the rank editor:

- PointerSensor also claims touch input, so pairing it with TouchSensor
  meant the 4px pointer path won on touch devices and the press-and-hold
  delay never engaged — a finger drag started on 4px of movement and
  fought page scrolling. MouseSensor + TouchSensor split the inputs the
  way the dnd-kit docs prescribe, and rows switch touch-none →
  touch-manipulation since the TouchSensor prevents scrolling itself
  once its delay activates, leaving plain touches free to scroll.
- save() now no-ops while a PUT is in flight: controls disable during a
  save, but a drag already in progress when the save started can still
  drop, and committing that drop would race the full-list replace.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread frontend/src/pages/SettingsPage.tsx Outdated
Two more review follow-ups on the rank editor:

- The save guard read the rendered `saving` value, which only updates
  after React re-renders: a handler created before that re-render could
  pass the guard in the same tick as another edit's mutate() and send a
  second full-list PUT from an older snapshot. save() now asks the
  mutation cache imperatively (queryClient.isMutating), which reflects
  an in-flight mutation synchronously, closing the pre-render window.
- Saving areas now invalidates ["me", "ballot"] and
  ["me", "ballot-preferences"]: the saved ballot is server-sorted by
  these preferences under my_areas, and the ballot-preferences default
  flips from vote_power to my_areas when the first area is saved —
  without invalidation the saved ballot page kept its stale order and
  subtitle until staleTime expired or a reload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@shu1513
shu1513 merged commit 0ea247c into main Jul 5, 2026
3 checks passed
@shu1513
shu1513 deleted the feat/research-area-rank-editor branch July 5, 2026 03:19
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