Uh oh!
There was an error while loading. Please reload this page.
fix(list): sort picker falls back to all sortable fields, and gains a reset to the view's default sort (#4243) - #4299
Merged
Conversation
… reset to the view's default sort (#4243) `filterableFields` was applied to the one field set both toolbar builders read, so a whitelist authored for filtering silently doubled as the sort whitelist. A view declaring a two-level default sort on non-filterable fields got a picker offering neither and rows rendering blank: the declared sort worked on load and could then be neither reproduced nor modified. The whitelist now narrows the filter builder alone. The sort picker starts from every field the view can name and applies its own sortability rules: the existing relational exclusion, plus `formula`, which the server refuses to order by outright (objectstack's `UNMATERIALIZED_SORT_TYPES`) and which matters here precisely because the base set widened. The exclusion is `formula` alone, not the spec's `COMPUTED_VALUE_TYPES` — `summary` and `autonumber` each get a real maintained column and sort correctly. Second half: a column-header click replaced the whole sort array, so a view's multi-level default was unreachable for the session. The sort panel gains a reset control that restores the declared array whole, read through the same resolver the initial render uses. Disabled while the active sort already matches; absent when the view declares no sort. The header click's own semantics are unchanged. Per the maintainer ruling recorded on #4243 (2026-08-11): the narrow fix, no new `sortableFields` spec key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 11, 2026 12:14
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#4243
Implements the maintainer ruling recorded on #4243 on 2026-08-11 — the narrow fix, both halves, no new spec vocabulary:
That ruling was itself recorded as the PM seat executing the maintainer's direct instruction in chat, quoted verbatim in the same comment: 「接受你的全部建议,请更新 issue 的状态和标签」.
Part 1 — the sort picker stops borrowing the filter whitelist
filterableFieldswas applied inside the one memo that built the field set both toolbar builders read, so a whitelist authored for filtering silently became the sort whitelist. The card's reported shape reproduces exactly: a view declaring a two-level default sort onplan_start_datethenname, with neither field whitelisted, got a sort panel that offered neither and rendered both rows blank — Radix resolves a select's display label from its item list, so a value absent from the list renders as nothing.The whitelist now narrows the filter builder alone. The sort picker starts from every field the view can name and applies its own sortability rules.
Fix site. Both halves are in
packages/plugin-list/src/ListView.tsx. Triage citedpackages/plugin-view/src/SortUI.tsx:166as the second face; re-verified at current main, that attribution does not hold —SortUIis a separately registeredsort-uicomponent whosefieldscome from its own authoredSortUISchema, and it is never fed by ListView's field set. ListView's sort panel rendersSortBuilderdirectly. The card's own claim ("one array feeds both builders") is exactly right; only the file pointer was off, soSortUI.tsxneeds no change and is untouched.The measurement rider: which types the widened set must still exclude
The dispatch asked whether
formula(and other computed types) must be excluded from the widened fallback, given #3950. Measured against objectstack, read-only:packages/metadata-protocol/src/protocol.ts:1593—UNMATERIALIZED_SORT_TYPESis a set holdingformula. A sort naming a formula field is refused there with400 INVALID_SORT; before objectstack#6994 it degraded silently (200, every row present,ascanddescbyte-identical, measured on a realSqlDriver).The more important half of the measurement is where the exclusion stops. It is
formulaalone, deliberately not the spec'sCOMPUTED_VALUE_TYPES(formula/summary/autonumber). objectstack's own conformance test pins that trap by name — "a summary field still sorts, in both directions — the family isformula, not 'computed'" — and warns that widening the gate toCOMPUTED_VALUE_TYPES"would break two types that work": that set is the WRITE contract, andsummary/autonumbereach get a real maintained column. The renderer's constant mirrors the server's, with that reasoning recorded at the definition.Both rules keep the existing escape hatch: a field the current sort already uses stays listed. For a formula field that is the only way to remove an offending row, since the sort it names is one the server refuses outright.
ObjectGrid'ssortableflag). Different site, different fix, still open.Part 2 — reset to the view's declared sort
The sort panel gains a Reset to view default control.
parseSortConfig(schema.sort), the same resolver the initialuseStateand the view-switch effect already use — not a re-derivation. The comparison is by(field, order)in order, never byid, whichparseSortConfigmints fresh fromcrypto.randomUUID()on every call.handleHeaderSort, not a special case of it: samecurrentSortstate, same page-1 reset, sameonSortChangenotification, so a host persists a reset exactly as it persists a header click.An interaction worth naming
The hint explaining the relational omission used to be gated by the same whitelist. A view whitelisting only
statusshowed a near-empty sort picker and no word about why, because the relational field never entered the loop that records something as withheld. It now reaches the relational rule, is withheld by it, and says so. This surfaced as a reverse-verification surprise: a case labelled a control went red, and it is a pin, not a control — relabelled as such, with the reason recorded in the test.Tests
New:
packages/plugin-list/src/__tests__/ListView.sortFieldFallback.test.tsx(9 cases).Reverse verification — the fix reverted with
git checkout origin/main -- ListView.tsx, direction predicted before running, 6 red / 3 green, as predicted:['Status']only, rows blank)formulafieldformulafield the current sort usesfilterableFieldsThe "hidden when the view declares no sort" case asserts both branches — same header click, one fixture declaring a sort and one not. A bare null-check there would have been green on the unfixed code for the empty reason that no such control exists at all; the contrast is what makes it an assertion.
Green-both-sides controls for the pre-existing rules are the untouched
ListView.relationalSort.test.tsxandListView.headerSort.test.tsx— both verified green against the reverted file and against this branch.Local runs (repo-root vitest, per objectui#3378):
Gates:
check:i18n-keys,check:i18n-drift,check:control-bytes, changeset presence / no-major / fixed — all OK. The drift gate reports the new key added across all ten packs.i18n
One new key,
list.resetSortToDefault, added to all ten locale packs with native translations. NodefaultValueat the call site, matching the sibling sort strings.Out-of-scope finding
Filed #4294 (unassigned, unlabeled for triage):
list.sortRelationalHinttells the user "To sort by that name, add a formula field holding it" — the one type the server refuses to sort by. objectstack's hint for the same situation says the opposite in as many words ("Not a formula field: it is virtual"). Pre-existing and untouched here; re-wording it changes anenvalue and so drags all nine other packs into the same PR.Changeset
.changeset/list-sort-field-fallback-and-reset-4243.md— patch on@object-ui/plugin-listand@object-ui/i18n.Generated by Claude Code