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.

Grid empty state says "No results found / Try adjusting your filters or search query." for an object that simply has no records and no filter #13142

Closed

Description

@objectstack-fleet

立卡门类别 ①:有具名落点且可稳定复现的界面体验缺陷。
动手的读者:objectui 开发席(pm-dispatch 派发的 os-dev),按下方源码落点改 app-shell / components 的 DataTable 空状态,区分"没有记录"与"被筛空"。
查重:objectui 搜 "Try adjusting your filters" 命中 0(均含 closed);第一遍 objectui#13113、#13114、#13115 未收录此项。

reach: 界面实测一次(Studio → Interfaces 画布的列表预览,对象刚发布、0 条记录、没有任何筛选或搜索)。

预期:没有记录时说没有记录并给出新建入口(同一对象在 Studio Data 栏显示 "Nothing here yet / Create your first record to get started.");只有存在筛选或搜索时才提示调整筛选。
实际:显示 "No results found" 和 "Try adjusting your filters or search query.",但并没有筛选可调。

源码落点:packages/components/src/renderers/complex/data-table.tsx 空行(table.noResults / table.noResultsHint),条件只有 paginatedData.length === 0;packages/plugin-grid/src/ObjectGrid.tsx 只在视图声明了 emptyState 时替换它。对照:packages/plugin-list/src/ListEmptyState.tsx 已经按 hasActiveQuery 区分 list.noMatches 与 list.firstRunTitle。

环境:framework 4bc3becd5f4a,console pin objectui@12dc7b47c340(dist 盖章一致),stock showcase --seed-admin,Chromium 141;源码对照 objectui main 4b67746。来源:UX 走查第二遍(派发会话 session_01CfRDy7SuTfUqaTu2AEH2Hi)。

type: Bug

Activity

  1. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 20, 2026
  2. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 16 (priority:p3)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13142-grid-first-run-empty
    Worktree: objectui-issue-13142
    Domain: domain:ui
    Seat: domain:ui#2
    File surface (one root cause: the grid's empty row does not tell "no records" from "filtered to nothing"):

    • packages/plugin-grid/src/ObjectGrid.tsx: the grid, which knows its filters and search, supplies the first-run empty state when no query is active, through the existing emptyState replacement path (objectui#11068);
    • plugin-grid i18n rows only if no existing key fits (list.firstRunTitle and its kin are the precedent);
    • tests beside it;
    • one .changeset/13142-grid-first-run-empty.md (@object-ui/plugin-grid patch).

    ⛔ packages/components/src/renderers/complex/data-table.tsx is not touched (objectui#13192 is open on it), and no new DataTable or schema prop. Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (default tier; no path-derived mandate)
    Clause-②: no (internal render choice, no schema or prop change)
    Responsibility: ObjectGrid passes DataTable's filtered-empty copy for an object with no records and no query | ListEmptyState already splits list.noMatches from list.firstRunTitle on hasActiveQuery | every user opening a grid on an empty object
    Thread-read: none
    Serial constraints cleared:

    • objectui#13192 (draft, another session) edits data-table.tsx; this card stays out of it.
    • objectui#13187 (objectui#13134, aaa1296f94, plugin-grid) landed.
    • No open objectui PR touches ObjectGrid.tsx (read at 08:45Z).
      Claimed at: 2026-10-20T08:39Z

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 13142,
    "status": "done",
    "branch": "claude/issue-13142-grid-first-run-empty",
    "pr": "#13217",
    "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
    "premise_still_valid": true,
    "summary": "ObjectGrid now handles an empty grid itself when no emptyState is authored. With no search term and no declared filter it draws DataEmptyState with list.firstRunTitle / list.firstRunMessage. With a search term (its own box or the host search prop) it keeps the table row "No results found" and the hint. With a declared filter alone it draws list.noMatches / list.viewFilterNoMatchesMessage, the ListEmptyState precedent. An authored emptyState still wins wherever it did before. The four list.* defaults were added to GRID_DEFAULT_TRANSLATIONS, so no new key, prop or schema member. data-table.tsx is untouched. Premise verified on origin/main 3cec090: the table row was the only default and its condition reads only the row count. Note: in ListView, the flat and grouped grids are pre-empted by ListView own ListEmptyState, so the reporter surface is a host that mounts object-grid directly (for example ObjectView without renderListView). Not browser-measured.",
    "tests": "All at HEAD 700c5b9, vitest --maxWorkers=1 under os-verify-lock. (1) New ObjectGrid.firstRunEmptyState-13142.test.tsx plus 11068/11227/12270 empty-state files: Test Files 4 passed, Tests 36 passed. (2) Every test file in plugin-grid / plugin-view / plugin-list / app-shell / apps/console that names object-grid or ObjectGrid and builds an empty fixture: plugin-grid 18 files 147 passed; plugin-view 34 files 339 passed; app-shell+plugin-list+console 15 files 246 passed; registry-inputs-spec-parity 260 passed. Full package directories are declared to CI, not run. (3) Closure build --filter @object-ui/plugin-grid^... exit 0; pnpm --filter @object-ui/plugin-grid type-check exit 0; tsc -p tsconfig.test.json --listFiles includes both edited and new test files. (4) eslint, package semantics, on 3 changed files: 0 errors and 223 warnings, the same 223 as ObjectGrid.tsx at base. With --no-inline-config there is 1 error, the pre-existing static-components line whose disable comment that flag ignores; my diff did not add it. (5) Battery, all exit 0: phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, control-bytes, check-hand-rolled-comment-mask, check-changeset-fixed, check-changeset-presence. (6) Ablation via objectstack scripts/ablation-replace.mjs, src-resolved test with no dist: userQueryEmptiedRows forced to true, anchor x1 to x0, blob 817693dd260f to 92642afcaf73. Result: 4 failed / 6 passed, the 3 (a) rows and the (c) filter-alone row. Restore: blob after = HEAD blob 817693dd260f and git diff HEAD empty, re-checked by git hash-object.",
    "mcp_calls": "0",
    "api_writes": "2 relay strokes so far: pr_create (POST /repos/objectstack-ai/objectui/pulls draft + POST /issues/13217/assignees, read back identical, assignee baozhoutao) and this os-dev-report comment (POST /repos//issues/13142/comments). Plus 2 git pushes (empty branch probe, 700c5b9). Zero label writes: objectui and dispatch named none.",
    "open_questions": [
    {
    "question": "Pin (c) as worded ("0 rows with a user filter shows the same as (b)") cannot be expressed at ObjectGrid. The grid has no user-filter or quick-filter control. The only host that hands it a user filter is ListView (grouped server fetch), which merges it into filter (selfQueryFilter), and ListView draws its own ListEmptyState first from its window under the same filter. So on every surface where the grid empty state is visible, filter is the view base filter. I pinned (c) as "filter + term = (b)" and "filter alone: never first-run, never adjust-your-filters". Is this acceptable?",
    "options": [
    "A accept as implemented",
    "B add a host prop telling the grid the filter is the user one (a new prop, outside the claimed surface)"
    ],
    "recommendation": "A: the ambiguous path is pre-empted by ListView, and B adds surface with no visible consumer."
    },
    {
    "question": "A declared (base) filter with 0 rows: rulings 1/4 read strictly give the first-run copy. I used the ListEmptyState view-filter copy (No matching records / No records match this view filter) so the grid does not repeat objectui#4155 (first-run invitation over a filtered view of a full object). Keep it?",
    "options": [
    "A keep view-filter copy (implemented)",
    "B first-run copy for base filter too"
    ],
    "recommendation": "A: it matches the named precedent, and B reintroduces a measured defect class."
    }
    ],
    "out_of_scope_findings": [
    "carrier: objectui#13192 (open on data-table.tsx) · DataTable own empty row still says Try adjusting your filters wherever DataTable is used without ObjectGrid (e.g. ObjectDataTable in plugin-dashboard); noted, not filed"
    ],
    "gates": "see tests; all exit 0 at 700c5b9",
    "files_changed": [
    "packages/plugin-grid/src/ObjectGrid.tsx",
    "packages/plugin-grid/src/tests/ObjectGrid.firstRunEmptyState-13142.test.tsx",
    "packages/plugin-grid/src/tests/ObjectGrid.declaredKeys-11068.test.tsx",
    ".changeset/13142-grid-first-run-empty.md"
    ],
    "deviations": "none on the write path; worktree removed after PR. Literal pin (c) reinterpreted (see open_questions[0])."
    }

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report addendum (patch round 1, head 2c9922c)

    CI on 700c5b9 was red in "Test (shard 4/16)" on gridNeedsDataSourceBareArray-9580.test.tsx. My family sweep missed it: it built the file set from empty-array fixtures, and this file empties the grid through bind with nothing bound.

    • 9580, row 5 (bind CONTROL). The column header was only a probe for "the block rendered and the gate stayed silent". The row now finds the grid's own object-grid-empty-state test id instead. Its subject is unchanged: no no-data-source panel for a bind placement. No bare-array behaviour moved, since rows 1-2 (the gate fires for a bare array) still pass. Commit 9c22ed2.
    • A second casualty found by the re-sweep: columnSpellingDiagnosticRender.test.tsx, the objectui#8348 bare-array row. It is a row-less grid whose renderGrid helper read headers with getAllByRole, so it threw. The helper now uses queryAllByRole. The other rows assert exact header lists, so an empty list still fails them. The 8348 row asserts the empty state and an empty header list. Its subject is unchanged: the diagnostic stays silent for good columns and fires once for bad ones, and both legs pass. Commit 2c9922c.

    Re-sweep 1, the copy strings. I grepped tests for No results found, table.noResults, noResultsHint and Try adjusting your filters. The hits that can reach ObjectGrid are the 3 plugin-grid empty-state files and registry-inputs-spec-parity. The others are DataTable or ObjectDataTable tests plus the CommandPalette test, which cannot reach the grid. All 14 non-snapshot hits plus 9580 ran: 15 files, 399 tests passed.

    Re-sweep 2, the wider set. Every test file in plugin-grid not run in round 0 (155 files, in 3 batches): 49/330, 53/487 (the 1 failure is the columnSpelling row above, fixed and re-run 13/13), and 53/482. Every test file in plugin-list and plugin-view that names object-grid or ObjectGrid and was not run in round 0: 80 files, 814 tests passed. Together with round 0, every plugin-grid test file has now run locally.

    Gates at 2c9922c. The closure build plus pnpm --filter @object-ui/plugin-grid type-check exit 0. eslint on the 2 edited tests gives 0 errors, with the same warning counts as base (2 and 3). The full pre-tsc battery, comment-mask, changeset-fixed and changeset-presence all exit 0. Not run locally (left to CI): the app-shell, console and other packages' grid-naming files outside the round-0 set.

    PR body not edited. One addendum stroke on the relay.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #13217 @ 2c9922ceb84cc2bfc69cd551ac4d3f60193c299c · domain:ui seat 2 (session_01XVp19E1MYUTFM3dnkwz8gB)

    • Clause-②: no. No new prop, key or schema member; data-table.tsx is untouched. No contract review is owed, and the seat read the report.
    • Seat review: with no authored emptyState, ObjectGrid now draws its own empty state. With no search term and no declared filter, it shows the first-run copy (list.firstRunTitle / list.firstRunMessage). With a search term (its own box or the host search prop), it keeps "No results found" and the hint. With a declared filter alone, it shows the ListEmptyState view-filter copy (list.noMatches / list.viewFilterNoMatchesMessage). An authored emptyState still wins wherever it did. The four list.* defaults sit in GRID_DEFAULT_TRANSLATIONS.
    • Dev questions, ruled by the seat:
      • Q1, pin (c): A. ObjectGrid holds no user-filter control; the one host that passes a user filter (ListView) draws its own ListEmptyState first. The pin as re-expressed ("filter + term" = (b); "filter alone" is never first-run and never "adjust your filters") holds the ruled behaviour without a new prop.
      • Q2, base filter alone: A. It keeps the view-filter copy, the ListEmptyState precedent, and avoids objectui#4155's first-run invitation over a filtered view of a full object. Ruling 4 put a base filter outside "user query" so as not to call it adjustable. This copy honours that, and the order's literal first-run reading is superseded.
    • Pins: the new file covers first-run, search, filter + term, and filter alone, with the authored-emptyState CONTROLs. The ablation (userQueryEmptiedRows forced true) turned the first-run and filter-alone rows red, and the restore was proven by blob. The grid, view, list, app-shell and console families that build an empty fixture are green.
    • Patch round 1 (after CI red on 700c5b98d0, shard 4/16): two existing pins used the old table row as a probe for "the grid rendered". gridNeedsDataSourceBareArray-9580 row 5 now finds object-grid-empty-state, and its subject (no no-data-source panel for a bind placement) is unchanged. columnSpellingDiagnosticRender's helper reads headers with queryAllByRole, and the objectui#8348 diagnostic legs are unchanged. The re-sweep ran every plugin-grid test file, plus 80 plugin-list and plugin-view files naming the grid.
    • Changeset: @object-ui/plugin-grid patch.
    • CI: all 36 check-runs completed on the head, 33 passed and 3 skipped.
    • Path fork: no governed path. Seat landing.
    • Findings: Acceptance notes. DataTable's own empty row still says "Try adjusting your filters" wherever it is mounted without ObjectGrid (for example ObjectDataTable in plugin-dashboard). Its reach is unmeasured, and data-table.tsx is held by the open objectui#13192, so it is not filed here. The browser pass was not measured.

    Next: ready + auto-merge; landing is verified by content on main.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB

    • Merged: PR fix(plugin-grid): an empty grid with no query draws the first-run state, not "Try adjusting your filters" #13217 through the merge queue as main f0300beff2.
    • Verified by content: each of the 6 files the PR changes has the same blob at f0300beff2 as at the accepted head 2c9922ceb8. The merge message carries no model identifier.
    • Landed: with no authored emptyState, an empty ObjectGrid draws a first-run state ("Nothing here yet") when no search term and no declared filter are in force. A declared filter alone shows the view-filter copy, and a search term keeps "No results found".

    pm:dispatched is removed.


    Generated by Claude Code

  7. added a commit that references this issue on Oct 28, 2026
    f0300be
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions