Skip to content

add per-column sort controls#32

Open
AntonNiklasson wants to merge 3 commits into
mainfrom
an/sort-controls
Open

add per-column sort controls#32
AntonNiklasson wants to merge 3 commits into
mainfrom
an/sort-controls

Conversation

@AntonNiklasson
Copy link
Copy Markdown
Owner

Summary

  • Each dashboard column gets a header row of clickable sort dimensions (My PRs: created/updated/title/size, Reviews: created/updated/title/author, Notifications: updated/title/repo). Active field shows an arrow; click again to flip asc/desc.
  • Keyboard: s cycles dimension on the active column, Shift+S toggles direction. Documented in the ? help.
  • Per-column sort state persists in localStorage via atomWithStorage (prSort / reviewSort / notificationSort).
  • Defaults: My PRs by created desc (newest first, doesn't jump on activity), Reviews / Notifications by updated desc.
  • Side tweak: PR card label renamed "opened" → "created" to match the sort option.

Test plan

  • pnpm typecheck, pnpm lint, pnpm fmt:check, pnpm test clean
  • Open dashboard, click a dimension — list re-sorts; click again — direction flips
  • Focus a column with 1/2/3, press s repeatedly — wraps through dimensions
  • Press Shift+S — direction flips on active dimension
  • Refresh page — per-column sort settings persist

Each dashboard column gets a row of clickable dimensions in its
header. Active dimension shows an arrow; clicking it toggles
asc/desc, clicking another switches to it (defaulting to desc).
State per column persists in localStorage via atomWithStorage.

Defaults: My PRs by created desc (stable, doesn't jump on activity),
Review Requests / Notifications by updated desc.
@AntonNiklasson AntonNiklasson marked this pull request as ready for review May 13, 2026 11:40
Copilot AI review requested due to automatic review settings May 13, 2026 11:40
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds per-column sorting to the web dashboard, with clickable header sort controls and keyboard shortcuts, persisting preferences via Jotai localStorage-backed atoms.

Changes:

  • Introduces shared sort state/types, per-section sort field lists, and comparators for PRs, reviews, and notifications.
  • Adds a reusable SortControl header component and wires it into each dashboard column, including s / Shift+S shortcuts.
  • Updates UI copy (“opened” → “created”) and documents new shortcuts in the help overlay.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/web/src/sort.ts Defines sort state, persisted atoms, and comparator functions for each column.
packages/web/src/components/SortControl.tsx New UI control to select/toggle sort field + direction in column headers.
packages/web/src/components/ShortcutHelp.tsx Documents the new sort keyboard shortcuts.
packages/web/src/components/SectionHeader.tsx Adds support for rendering right-side header content (sort controls + fetching indicator).
packages/web/src/components/PrCard.tsx Renames label text to “created” to align with sort terminology.
packages/web/src/App.tsx Applies sorting in each column, persists state, adds header controls, and implements s/Shift+S handling.
Comments suppressed due to low confidence (1)

packages/web/src/App.tsx:984

  • e.key === "S" is case-sensitive and depends on Caps Lock / keyboard layout. If you intend this to mean “Shift+S”, use e.shiftKey (and typically e.code === "KeyS") instead of matching the capital letter. This will make the shortcut work consistently and avoid conflicting with the lower-case s handler.
      } else if (e.key === "S") {
        const flip = (d: "asc" | "desc") => (d === "asc" ? "desc" : "asc");
        if (activeSection === "prs") {
          setPrSort((cur) => ({ ...cur, dir: flip(cur.dir) }));
        } else if (activeSection === "reviews") {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/web/src/sort.ts
Comment on lines +55 to +56
const aT = a ? new Date(a).getTime() : 0;
const bT = b ? new Date(b).getTime() : 0;
Comment thread packages/web/src/sort.ts
Comment on lines +64 to +76
export function comparePrs(a: PR, b: PR, sort: SortState<PrSortField>) {
const sign = sort.dir === "asc" ? 1 : -1;
switch (sort.field) {
case "created":
return sign * cmpDate(a.createdAt, b.createdAt);
case "updated":
return sign * cmpDate(a.updatedAt, b.updatedAt);
case "title":
return sign * cmpString(a.title, b.title);
case "size":
return sign * (a.additions + a.deletions - (b.additions + b.deletions));
}
}
Comment thread packages/web/src/App.tsx
Comment on lines +951 to +955
} else if (e.key === "s") {
if (activeSection === "prs") {
setPrSort((cur) => {
const i = PR_SORT_FIELDS.findIndex((f) => f.field === cur.field);
const next = PR_SORT_FIELDS[(i + 1) % PR_SORT_FIELDS.length];
Comment on lines +20 to +25
<button
key={opt.field}
type="button"
className={cn(
"text-[10px] uppercase tracking-tight tabular-nums",
active
Comment thread packages/web/src/sort.ts
Comment on lines +64 to +69
export function comparePrs(a: PR, b: PR, sort: SortState<PrSortField>) {
const sign = sort.dir === "asc" ? 1 : -1;
switch (sort.field) {
case "created":
return sign * cmpDate(a.createdAt, b.createdAt);
case "updated":
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.

2 participants