Repository navigation
Commit b889c40
feat(plugin-list): an empty list offers "Clear filters" when the reader's own filter emptied it (#29047)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbX5G6pE9Kiy5NcqB1zgkmJy)_
Fixes #28908
Clause-②: yes (widening)
Metadata-protocol: none
## 维护者速读
-
**改了什么**:列表被读者自己加的筛选(筛选面板的条件、「在队列中」开关)筛空时,空状态现在把「清除筛选」作为主按钮,「添加记录」降为次按钮;点一下清掉读者的整套查询(面板条件、队列开关、搜索词),工具栏筛选角标归零,记录回来。只有搜索时保持原样(「清除搜索」+
主按钮「添加记录」)。视图自己声明的筛选永远不清,只被它筛空时不出现清除按钮。新增一条界面文案
`list.clearFilters`(十个语言包)。
-
**为什么改**:今天文案说「试试调整或清除它们」,唯一按钮却是「添加记录」,读者得回去找工具栏的小角标;在筛选状态下点「添加记录」还会新建记录。
- **风险与回滚**:低。只改空状态的按钮与一个清除回调;清空的面板条件走与面板编辑相同的
`onFilterChange`,宿主存下的是空条件组。用户筛选标签(chips)不在本次范围内,各自就地清除。回滚即回退本 PR。
-
**先看**:`ui/packages/plugin-list/src/ListView.tsx`(`handleClearReaderQuery`
与传给 `ListEmptyState` 的 `onClearFilters`
判定);`ui/packages/plugin-list/src/ListEmptyState.tsx`(主次按钮与「只出现一个清除按钮」);新测试
`ListView.emptyStateClearFilters-28908.test.tsx`。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/plugin-list/src/__tests__/ListView.emptyStateClearFilters-28908.test.tsx`,预期
7 个用例全部通过;第一个用例断言主按钮是「Clear filters」、点击后空状态消失、角标不再显示 active。
- **需要你做的**:无,席位落地。
## What changes
**The empty state's clear action covers the reader's filters.**
`ListView` hands `ListEmptyState` a new `onClearFilters` callback
whenever a filter the reader applied is part of the empty query: the
filter panel's finished conditions (the same predicate `hasUserQuery`
already reads) or the "In a queue" toggle. The callback,
`handleClearReaderQuery`, removes the reader's whole query:
- the panel group is emptied (`conditions: []`, id and logic kept)
through the same emit as a panel edit, so the toolbar badge clears and a
host that stores the group through `onFilterChange` stores the empty
group;
- the "In a queue" toggle is released;
- the search box is cleared through `handleSearchChange('')` when it
holds anything, so `onSearchChange('')` reaches the host as it does for
"Clear search".
The view's declared `filter` is never touched: it is not the reader's
query, and `buildEffectiveFilter` still ANDs it into the next fetch.
**One clear action, leading.** `ListEmptyState` gains the
`onClearFilters` prop. Supplied, it draws "Clear filters"
(`data-testid="empty-state-clear-filters"`, the default button variant)
and the add-record action steps down to the outline variant; it replaces
"Clear search" rather than sitting beside it, since it clears the search
too. Not supplied, the actions are exactly as before: a search alone
draws the outline "Clear search" beside the primary "Add record".
`ListEmptyState` is module-internal (not exported from the package
barrel), so the prop widens no public surface.
**Copy.** One new string, `list.clearFilters`, in all ten built-in
locale packs and in plugin-list's `LIST_DEFAULT_TRANSLATIONS` (en "Clear
filters", zh 清除筛选). Each translation matches the wording the same locale
already uses for the Gantt quick-filter's clear action.
## Tests
`ui/packages/plugin-list/src/__tests__/ListView.emptyStateClearFilters-28908.test.tsx`
(new), 7 cases, mounted on a data source that answers zero rows for the
reader's miss and one lead otherwise:
- a panel filter that empties the list: "Clear filters" is primary, "Add
record" secondary, no "Clear search"; the click empties the group
through `onFilterChange`, the next fetch carries no miss, the empty
state is gone and the filter trigger's label no longer reads active;
- a search alone: "Clear search" (outline) beside the primary "Add
record", and the click reaches `onSearchChange('')`;
- a filter and a search together: one clear action, which clears both;
- the "In a queue" toggle: "Clear filters" releases it and the rows come
back;
- a view emptied by its declared filter alone: the view-filter copy and
no clear action;
- a reader filter over a declared filter: the click removes the reader's
part only, and the next fetch still carries the declared filter;
- a list emptied by a user-filter chip alone: the "your filters or
search" copy and no clear action.
## Acceptance notes
- **User-filter chips are out of scope** (claim amendment 6569743409).
`UserFilters` holds its own selection and each chip clears in place;
resetting chips from the empty state would need a key remount, which
ui/AGENTS.md #8 forbids. So a list emptied by a chip alone keeps the
"your current filters or search" copy and offers only "Add record". When
the panel or the queue toggle is also set, "Clear filters" clears those
and the search, and the chip stays.
- The declaration reads `Clause-②: yes (widening)` for the one new key
on `@object-ui/i18n`'s locale catalogue, as the claim amendment rules;
`Metadata-protocol: none` (no metadata key or option).
## Verification
Readings on `f44092be` (the change) unless named; `ceaa4f90` merges
`origin/main` (`2ac698ba` touched the locale packs with other keys,
clean merge), and the scoped re-check after it is named below.
<details><summary>Tests</summary>
- New file alone: 1 file, 7/7 passed.
- `pnpm --dir ui exec vitest run packages/plugin-list/ packages/i18n/`
(under the verify lock, `--maxWorkers=2`): 274 files passed; 3172 tests
passed, 13 skipped.
- `pnpm --dir ui exec vitest run scripts/`: 169 files passed, 2 skipped;
4900 tests passed.
- Ablation (one-time, not kept): `scripts/ablation-replace.mjs` replaced
`? handleClearReaderQuery` in the `onClearFilters` handoff with an
undefined callback. The new file went 4 failed / 3 passed (the four
"Clear filters" cases red; search-only, declared-only and chip-only
green, as they pin unchanged behaviour). The restore leg read blob ==
HEAD and an empty `git diff HEAD`.
- After the merge (`ceaa4f90`): `packages/i18n/` plus the 15 plugin-list
test files that name the empty state (`git grep -l` of `empty-state`,
`ListEmptyState`, `clearSearch`) and the new file: 109 files passed;
1694 tests passed, 13 skipped. The merge rebuilt the plugin-list closure
first (49/49 tasks).
</details>
<details><summary>Type-check, lint</summary>
- `turbo run type-check --filter=@object-ui/plugin-list
--filter=@object-ui/i18n`: 51/51 tasks on `f44092be`; 51/51 tasks again
on `ceaa4f90`.
- eslint on every changed source, test and locale file: 0 errors
(warnings only: two `as any` data-source casts in the new test, the
pattern the neighbouring empty-state tests use, and pre-existing ones).
- `node scripts/check-sdui-manifest.mjs`: exit 0 (no component config
changed).
- `pnpm check:new-line-citations` under `ui/`: 0 new citations.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --ran`: 34 derived families
accounted for, 34 run, 0 NOT MEASURED, every one exit 0. The PR-body
gates (`check-changeset-no-major`, `check-closing-keyword-parity`,
`check-partof-closing-keyword`, `check-adr-0087-registration`,
`check-empty-changeset`) ran on this body: exit 0 on each.
</details>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01QsR2jS5v57GVJJL1k8m1nN
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jS5v57GVJJL1k8m1nN)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent a4015ab commit b889c40
14 files changed
Lines changed: 308 additions & 5 deletions
File tree
- .changeset
- ui/packages
- i18n/src/locales
- plugin-list/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
854 | 854 | | |
855 | 855 | | |
856 | 856 | | |
| 857 | + | |
857 | 858 | | |
858 | 859 | | |
859 | 860 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
764 | 764 | | |
765 | 765 | | |
766 | 766 | | |
| 767 | + | |
767 | 768 | | |
768 | 769 | | |
769 | 770 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1069 | 1069 | | |
1070 | 1070 | | |
1071 | 1071 | | |
| 1072 | + | |
1072 | 1073 | | |
1073 | 1074 | | |
1074 | 1075 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
790 | 790 | | |
791 | 791 | | |
792 | 792 | | |
| 793 | + | |
793 | 794 | | |
794 | 795 | | |
795 | 796 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
785 | 785 | | |
786 | 786 | | |
787 | 787 | | |
| 788 | + | |
788 | 789 | | |
789 | 790 | | |
790 | 791 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
764 | 764 | | |
765 | 765 | | |
766 | 766 | | |
| 767 | + | |
767 | 768 | | |
768 | 769 | | |
769 | 770 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
764 | 764 | | |
765 | 765 | | |
766 | 766 | | |
| 767 | + | |
767 | 768 | | |
768 | 769 | | |
769 | 770 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
785 | 785 | | |
786 | 786 | | |
787 | 787 | | |
| 788 | + | |
788 | 789 | | |
789 | 790 | | |
790 | 791 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
809 | 809 | | |
810 | 810 | | |
811 | 811 | | |
| 812 | + | |
812 | 813 | | |
813 | 814 | | |
814 | 815 | | |
| |||
0 commit comments