Skip to content

Conversation

@CodeBBakGoSu
Copy link

@CodeBBakGoSu CodeBBakGoSu commented Feb 2, 2026

What changed

  • Keep server ordering for the paginated skills list (no client-side re-sort when browsing without a search query)
  • Align listPublicPageV2 default dir with UI semantics (name defaults to asc)

Why

Sorting by stars/installs/downloads should apply to the full dataset, not only within the currently loaded page(s).

Test plan

  • bun run test
  • bun run lint

UI verification (screenshot)

image
  • Visit /skills?sort=stars&dir=desc and confirm the top rows show the highest star counts.

Related: #92

Greptile Overview

Greptile Summary

This PR updates the public skills listing to preserve global sorting across pagination by relying on server-side ordering (instead of re-sorting paginated results on the client). It also extends the Convex listPublicPageV2 query to accept sort/dir parameters and adds new skills indexes to support those sort modes efficiently, plus updates the UI and unit tests to pass the new defaults.

Key touchpoints:

  • convex/schema.ts: adds several by_active_* indexes to filter out soft-deleted skills while sorting.
  • convex/skills.ts: introduces SORT_INDEXES and uses it in listPublicPageV2 with configurable sort/dir.
  • src/routes/skills/index.tsx: passes sort/dir to the paginated query and avoids client-side sorting when not searching.
  • Tests/import ordering: updates expectations and applies formatting tweaks.

Confidence Score: 4/5

  • This PR is generally safe to merge; the main risk is subtle ordering inconsistencies between server pagination and client search sorting for equal-valued stats.
  • Changes are scoped and mostly adjust sort/pagination behavior using new indexes. The only notable concern is mismatched tie-breakers between server-side index ordering and client-side comparators, which can cause confusing reordering when many skills share the same stat values or when switching between search and non-search paths.
  • convex/skills.ts and src/routes/skills/index.tsx (sorting semantics/tie-breakers)

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

Context used:

  • Context from dashboard - AGENTS.md (source)

@vercel
Copy link
Contributor

vercel bot commented Feb 2, 2026

@knox-glorang is attempting to deploy a commit to the Amantus Machina Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 730 to 755
export const listPublicPageV2 = query({
args: {
paginationOpts: paginationOptsValidator,
sort: v.optional(
v.union(
v.literal('newest'),
v.literal('updated'),
v.literal('downloads'),
v.literal('installs'),
v.literal('stars'),
v.literal('name'),
),
),
dir: v.optional(v.union(v.literal('asc'), v.literal('desc'))),
},
handler: async (ctx, args) => {
// Use the new index to filter out soft-deleted skills at query time.
const sort = args.sort ?? 'newest'
const dir = args.dir ?? (sort === 'name' ? 'asc' : 'desc')

// Use the index to filter out soft-deleted skills at query time.
// softDeletedAt === undefined means active (non-deleted) skills only.
const result = await paginator(ctx.db, schema)
.query('skills')
.withIndex('by_active_updated', (q) => q.eq('softDeletedAt', undefined))
.order('desc')
.withIndex(SORT_INDEXES[sort], (q) => q.eq('softDeletedAt', undefined))
.order(dir)
.paginate(args.paginationOpts)
Copy link

Choose a reason for hiding this comment

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

[P1] listPublicPageV2 can return a different order than the client expects when sorting by stats, because the index tie-breaker fields don’t match the client-side comparator.

For downloads/stars/installs, the index is statsX, updatedAt but the UI’s results.sort only compares the primary stat (and doesn’t fall back to updatedAt / slug). This means within equal-stat groups you’ll get a stable-but-different ordering depending on whether results came from server pagination vs the client search path.

This matters when switching between search and non-search views or when many items share the same stat value (often 0). Consider aligning the server index/order with the UI’s full comparator (e.g., add deterministic secondary keys) or updating the client comparator to match the server ordering.

Also appears in: src/routes/skills/index.tsx:169-189

Prompt To Fix With AI
This is a comment left during a code review.
Path: convex/skills.ts
Line: 730:755

Comment:
[P1] `listPublicPageV2` can return a different order than the client expects when sorting by stats, because the index tie-breaker fields don’t match the client-side comparator.

For `downloads`/`stars`/`installs`, the index is `statsX, updatedAt` but the UI’s `results.sort` only compares the primary stat (and doesn’t fall back to `updatedAt` / slug). This means within equal-stat groups you’ll get a stable-but-different ordering depending on whether results came from server pagination vs the client search path.

This matters when switching between search and non-search views or when many items share the same stat value (often 0). Consider aligning the server index/order with the UI’s full comparator (e.g., add deterministic secondary keys) or updating the client comparator to match the server ordering.

Also appears in: `src/routes/skills/index.tsx:169-189`

How can I resolve this? If you propose a fix, please make it concise.

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.

3 participants