Make Site / Building / Rack columns sortable in the miner list (server-side sort support)
- Dominant language
- Go
- Stars
- 55
- Forks
- 16
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 87
Description
## Context
The miner selection modal (Search / Manage miners) now shows Model, IP, **Site, Building, Rack**, and Groups columns (#673). Model, IP, and Name are sortable; **Site, Building, and Rack are not**, because the server has no sort support for placement columns.
## Why it's blocked today
The miner list is server-paginated (50/page), so sorting must be server-side — a client-only sort would only reorder the current page. But the server's sort whitelist doesn't include placement:
- `server/internal/domain/stores/sqlstores/device_query_fragments.go` — `sortExpressions` supports only Name, IP, MAC, Model, Hashrate, Temperature, Power, Efficiency, Firmware, WorkerName.
- `SORT_FIELD_LOCATION` exists in `common.v1.SortField` but is explicitly *reserved/unimplemented* (`renaming_test.go`).
- The fleet miner-list page (`MinerList/sortConfig.ts`) doesn't offer these either — so this would be net-new capability, not just wiring.
## Scope
Add server-side sort for **Site, Building, Rack** (Group sort is lower value and multi-valued — call it out but likely skip):
- **Proto:** add `SORT_FIELD_SITE`, `SORT_FIELD_BUILDING`, `SORT_FIELD_RACK` to `common.v1.SortField` (or repurpose `SORT_FIELD_LOCATION` as a composite site→building→rack ordering). Regen Go/TS/SDK.
- **Server:** add `sortExpressions` entries with the JOINs to the placement/collection + site/building tables, plus matching keyset-pagination expressions (`device_sort.go`) so cursor paging stays correct. Handle NULLs (unplaced miners) with `NULLS LAST`.
- **Client:** extend `SORT_FIELD_BY_COLUMN` in `MinerSelectionList.tsx` (and optionally `MinerList/sortConfig.ts` for the fleet page) so the site/building/rack column headers become sortable.
- **Tests:** server sort + keyset-pagination tests; client sort wiring.
## Notes
- Decide composite vs. discrete: a single `LOCATION` sort (site → building → rack → slot) may match operator intent better than three independent sorts. Worth a quick UX call before implementing.
- Group is multi-valued per miner (a miner can be in several groups), so "sort by group" is ambiguous — recommend leaving Group unsortable.
## Related
- Follows #673 (miner selection modal: columns + nested filters + assignable-only toggle). Client already lists Site/Building/Rack columns; this makes them sortable.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Contributor guide
Research direction
Start with common.v1.SortField and its renaming_test.go coverage, then read server/internal/domain/stores/sqlstores/device_query_fragments.go, device_sort.go, and the client sort mapping in MinerSelectionList.tsx. Compare existing server sort and keyset-pagination tests before resolving the composite-versus-discrete location choice. Done means regenerated clients, correct NULLS LAST cursor sorting, sortable client columns, and passing server and client tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, sql, typescript
- Domain
- backend-api-design, databases, frontend, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100