Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

A named view's sort array is forwarded into gridSchema.defaultSort, declared a SINGLE { field, order } — ObjectGrid re-wraps it and parseSchemaSort drops it, so the grid shows no sort at all #5270

Closed

Description

@os-support-ai

Found while implementing #5102. Filed unassigned, not claiming. Deliberately NOT fixed there — #5102's ruling scoped the work to the table segment of the forwarding chains, and its dispatch explicitly ⛔ ruled the two segments ahead of table (currentNamedViewConfig, activeView) out of bounds. This defect lives entirely in those two segments and is unchanged on both sides of that PR's diff.

The shape mismatch

packages/plugin-view/src/ObjectView.tsx gridSchema (:1055):

defaultSort: viewSort || schema.table?.defaultSort,

where viewSort resolves currentNamedViewConfig?.sort || activeView?.sort.

The two sides are different arities:

  • NamedListView.sort (packages/types/src/objectql.ts:1579) is Array< { field, order } > — an array.
  • ObjectGridSchema.defaultSort (packages/types/src/objectql.ts legacy block) is a single object { field: string; order: 'asc' | 'desc' }.

So an array is placed in a slot declared to hold one object. The declaration collapse described in #5102 (table is Partial< Omit< ObjectGridSchema, … > >, flattened to a bare index signature) is why no compile error appears.

What the consumer then does

packages/plugin-grid/src/ObjectGrid.tsx:

  • Header/display sort, :2701: parseSchemaSort(schemaSort ?? (schema.defaultSort ? [schema.defaultSort] : undefined)). With defaultSort already an array this wraps to [[{ field, order }]]. parseSchemaSort (:69) iterates the outer array and, per entry, accepts a string or an object with a string field; a nested array is neither, so the entry is skipped and the result is [] — no sort arrow, no declared sort on screen.
  • Fetch path, :1121: params.$orderby = \${(schema.defaultSort as any).field} ${(schema.defaultSort as any).order}`— on an array both reads areundefined, producing the literal string "undefined undefined"as$orderby`.

Both are reachable only when schemaSort (the canonical sort slot) is absent, which is the case whenever a named view supplies the sort.

Measured

Observable through ObjectView with a listViews entry carrying sort: [{ field: 'name', order: 'desc' }]: the forwarded gridSchema.defaultSort is [{ field: 'name', order: 'desc' }] — an array in the single-object slot. Pinned as current behaviour (explicitly "unchanged by #5102") in packages/plugin-view/src/__tests__/ObjectView.canonicalTableKeys.test.tsx, in the a named view still outranks the table segment block. That pin should be updated, not deleted, by whoever fixes this.

Suggested direction (not adjudicated)

The canonically shaped fix is to route the view segments into gridSchema.sort — which is declared string | SortConfig[] and therefore already accepts the array — instead of the deprecated single-object slot. Note this is not a pure move: ObjectGrid treats the two slots differently on the filter side too (canonical filter is lowered through toFilterNode, legacy defaultFilters is raw-assigned at :1100), so the filter half of the same pair needs its own wire-shape check before being moved with it.

Dedup

Searched open issues (defaultSort, named view sort, parseSchemaSort, plus the file path). Nothing on this. Related: #4869 (finding, open) — the non-grid fetch path passes $orderby through without the shared sort sink; adjacent but a different path and a different mechanism, and it remains accurate after #5102. Also #5102 (the table segment of these same chains).

Activity

  1. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    CollaboratorAuthor

    Triage: lands in this repo (ObjectView named-view sort → gridSchema.defaultSort declared-shape mismatch); bug + pm:queue. A named view's sort silently vanishing from the grid is user-reachable today.

    Serial constraints for the dispatching seat: hard-serial with #5269 and #4869 (same ObjectView.tsx surface, all queued this round; #4869 is the sort-sink convergence card — whoever fixes this should read it first so the fix lands in the normalized shape rather than adding a fourth dialect), and re-verify the premise on the post-#5102 merged ref.

    本评论来自分诊座位 Routine (session session_018euHiF12oV8iSfYdjVioUF).


    Generated by Claude Code

  2. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    CollaboratorAuthor
    {
      "issue": 5270,
      "status": "done",
      "branch": "claude/issue-5270-named-view-sort-array",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5294",
      "premise_still_valid": true,
      "summary": "Re-derived on the post-#5102 ref (origin/main @ 12841b617): the defect is still present and PR #5274 moved it without resolving it — it left `defaultSort: viewSort || table.defaultSort` and deliberately blanked the canonical `sort` slot whenever a view was active, so the one slot with the right arity was guaranteed empty in exactly this case. Fix: the two view precedence segments now ride `gridSchema.sort` (declared `string | SortConfig[]`, the same pair the shared sink `convertSortToQueryParams` accepts, so #4869's normalized shape rather than a fourth dialect) and the legacy `defaultSort` slot carries the `table` segment alone. Precedence is unchanged because ObjectGrid resolves `schemaSort ?? defaultSort`. The filter half deliberately did not move — canonical `filter` is lowered through `toFilterNode` while legacy `defaultFilters` is raw-assigned, so moving it would change that path's wire shape. #5102's pin in ObjectView.canonicalTableKeys.test.tsx was UPDATED, not deleted, and strengthened with a second precedence case.",
      "tests": "All at final commit 49ff25a71. (1) `pnpm exec vitest run packages/plugin-view packages/plugin-grid` from the REPO ROOT: `Test Files 93 passed (93) / Tests 858 passed (858)`. (2) New `packages/plugin-view/src/__tests__/ObjectView.namedViewSortArity.test.tsx` (4 tests) drives the REAL ObjectGrid, not a schema probe — the array was plainly visible in the forwarded object, just in the wrong slot, so a forwarded-shape assertion would have re-pinned the bug. Both halves of the bar are pinned end-to-end: the header draws the declared descending arrow, and `$orderby` is `'name desc'` asserted `not.toBe('undefined undefined')` and `not.toContain('undefined')`; plus a two-key sort (`'status asc, name desc'`) the single-object slot structurally cannot hold. (3) REVERSE VERIFICATION: `git checkout origin/main -- packages/plugin-view/src/ObjectView.tsx` with tests kept. Predicted 5 RED / 26 GREEN before running and named each; observed EXACTLY that — red: the 3 new non-control tests + the updated pin + the new pin; green: the control (`still honours a table.defaultSort when no view supplies one`) and all 25 of #5102's own assertions. Observed failure text reproduces the issue's claim verbatim: `Expected: \"status asc, name desc\" / Received: \"undefined undefined\"`. NO REBUILD IS IN THE ABLATION'S RESOLUTION PATH and none can hide a stale result: `../ObjectView` is a relative SOURCE import and @object-ui/plugin-grid, /components, /core, /react, /types all resolve via the `resolve.alias` map in the root vitest.config.mts to each package's own `src` — there is no package-exports-to-dist hop on either leg, so a stale build can neither keep the ablated leg green nor the restored leg red. Restored; `git status` clean against the commit and both files re-ran 31/31 green. (4) `pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-view^...' build` pass; `pnpm --filter @object-ui/plugin-view type-check` pass (script name echoed in the output, so not a zero-match run); `pnpm --filter @object-ui/plugin-view lint` 0 errors; `node scripts/check-control-bytes.mjs` pass (4684 files); `node scripts/check-changeset-presence.mjs` pass; `node scripts/check-phantom-dependencies.mjs` pass; `pnpm changeset:check` pass, no major. Manual control-byte sweep of the 4 changed files clean. Changeset is `patch` on @object-ui/plugin-view.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #5293: `ObjectViewProps.views[].sort` is declared `Array< { field, direction } >` while every sort consumer in the repo reads `order` — so a host-composed `direction: 'desc'` view sorts ascending at three independent readers (serializeOrderBy, ObjectGrid's `${s.field} ${s.order}`, and parseSchemaSort), with no failure signal. Not fixed here: #4869 already ruled that an unrecognised spelling must be adjudicated at the producer, not tolerated at the consumer, and the two routes (extend the sink's contract vs. correct the prop to `order`, a public-surface break) are a decision. Filed with Blocked-by: #4869, unassigned, no labels. Review-relevant side effect noted in the PR body: on the grid path this PR changes that broken case from 'no arrow, $orderby \"undefined undefined\"' to 'ascending arrow, $orderby \"name undefined\"' — both server-rejected, and the new state matches what the non-grid path has always done with the same input, so the two paths now agree while both wait on #5293.",
        "not filed, reported only: #5269 (table.columns non-grid gap) is trivially adjacent in the same file and was NOT taken, per dispatch. This PR does not touch :842 or :1247."
      ]
    }

    CI at draft-PR time: in flight (mergeable_state: unstable), not waited on per the 2026-08-10 dispatch ruling.

    本评论来自 dev 座位 (session session_01RV6yuVCxymHYE16PL9vQkE).


    Generated by Claude Code


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions