Skip to content

Commit b889c40

Browse files
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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@object-ui/plugin-list': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
feat(plugin-list): a list emptied by a filter the reader applied offers "Clear filters" as its primary action
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
A list whose own filter panel or "In a queue" toggle left it with no rows said to adjust or clear the filters, and its only button was "Add record", which creates a record while the list is filtered. Now:
12+
13+
- **Filtered by the reader:** the empty state draws "Clear filters" as the primary button and "Add record" as the secondary one. A click removes the reader's whole query (the filter panel's conditions, the "In a queue" toggle and the search), so the toolbar's filter badge clears and the rows come back. The cleared panel group is emitted through `onFilterChange` like any panel edit, so a host that stores it stores the empty group.
14+
- **Searched only:** unchanged. "Clear search" sits beside the primary "Add record".
15+
- **Filtered by the view only:** no clear action. The view's declared filter is not the reader's, and "Clear filters" never removes it.
16+
- **User-filter chips** are not cleared by this action: each chip clears in place.
17+
18+
`@object-ui/i18n` gains one string, `list.clearFilters` ("Clear filters"), in every locale pack.

‎ui/packages/i18n/src/locales/ar.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,7 @@ const ar = {
854854
noMatches: "لا توجد سجلات مطابقة",
855855
noMatchesMessage: "لا توجد سجلات تطابق عوامل التصفية أو البحث الحالية. حاول تعديلها أو مسحها.",
856856
clearSearch: "مسح البحث",
857+
clearFilters: "مسح عوامل التصفية",
857858
viewFilterNoMatchesMessage: "لا توجد سجلات تطابق عامل التصفية لطريقة العرض هذه.",
858859
ownedNoneTitle: "لا يوجد شيء يخصك بعد",
859860
ownedNoneMessage: "تعرض طريقة العرض هذه سجلاتك فقط، وليس لديك أي سجل بعد.",

‎ui/packages/i18n/src/locales/de.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ const de = {
764764
noMatches: "Keine passenden Datensätze",
765765
noMatchesMessage: "Keine Datensätze entsprechen Ihren aktuellen Filtern oder Ihrer Suche. Passen Sie sie an oder setzen Sie sie zurück.",
766766
clearSearch: "Suche löschen",
767+
clearFilters: "Filter zurücksetzen",
767768
viewFilterNoMatchesMessage: "Keine Datensätze entsprechen dem Filter dieser Ansicht.",
768769
ownedNoneTitle: "Noch nichts von Ihnen",
769770
ownedNoneMessage: "Diese Ansicht listet nur Ihre eigenen Datensätze auf, und Sie haben noch keine.",

‎ui/packages/i18n/src/locales/en.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,7 @@ const en = {
10691069
noMatches: 'No matching records',
10701070
noMatchesMessage: 'No records match your current filters or search. Try adjusting or clearing them.',
10711071
clearSearch: 'Clear search',
1072+
clearFilters: 'Clear filters',
10721073
viewFilterNoMatchesMessage: 'No records match this view’s filter.',
10731074
ownedNoneTitle: 'Nothing of yours yet',
10741075
ownedNoneMessage: 'This view lists only records that are yours, and you don’t have any yet.',

‎ui/packages/i18n/src/locales/es.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ const es = {
790790
noMatches: "No hay registros coincidentes",
791791
noMatchesMessage: "Ningún registro coincide con sus filtros o su búsqueda actuales. Pruebe a ajustarlos o borrarlos.",
792792
clearSearch: "Borrar búsqueda",
793+
clearFilters: "Borrar filtros",
793794
viewFilterNoMatchesMessage: "Ningún registro coincide con el filtro de esta vista.",
794795
ownedNoneTitle: "Aún no tiene nada propio",
795796
ownedNoneMessage: "Esta vista solo muestra sus propios registros, y todavía no tiene ninguno.",

‎ui/packages/i18n/src/locales/fr.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ const fr = {
785785
noMatches: "Aucun enregistrement correspondant",
786786
noMatchesMessage: "Aucun enregistrement ne correspond à vos filtres ou à votre recherche. Essayez de les ajuster ou de les effacer.",
787787
clearSearch: "Effacer la recherche",
788+
clearFilters: "Effacer les filtres",
788789
viewFilterNoMatchesMessage: "Aucun enregistrement ne correspond au filtre de cette vue.",
789790
ownedNoneTitle: "Rien à vous pour l'instant",
790791
ownedNoneMessage: "Cette vue ne liste que vos propres enregistrements, et vous n'en avez encore aucun.",

‎ui/packages/i18n/src/locales/ja.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ const ja = {
764764
noMatches: "該当するレコードがありません",
765765
noMatchesMessage: "現在のフィルターや検索条件に一致するレコードはありません。条件を調整するか解除してください。",
766766
clearSearch: "検索をクリア",
767+
clearFilters: "フィルターをクリア",
767768
viewFilterNoMatchesMessage: "このビューのフィルターに一致するレコードはありません。",
768769
ownedNoneTitle: "あなたのレコードはまだありません",
769770
ownedNoneMessage: "このビューにはあなたのレコードだけが表示されますが、まだ1件もありません。",

‎ui/packages/i18n/src/locales/ko.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ const ko = {
764764
noMatches: "일치하는 레코드가 없습니다",
765765
noMatchesMessage: "현재 필터나 검색어와 일치하는 레코드가 없습니다. 조건을 조정하거나 지워 보세요.",
766766
clearSearch: "검색 지우기",
767+
clearFilters: "필터 지우기",
767768
viewFilterNoMatchesMessage: "이 뷰의 필터와 일치하는 레코드가 없습니다.",
768769
ownedNoneTitle: "아직 내 레코드가 없습니다",
769770
ownedNoneMessage: "이 뷰에는 내 레코드만 표시되며, 아직 하나도 없습니다.",

‎ui/packages/i18n/src/locales/pt.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ const pt = {
785785
noMatches: "Nenhum registro correspondente",
786786
noMatchesMessage: "Nenhum registro corresponde aos seus filtros ou à sua busca atuais. Tente ajustá-los ou limpá-los.",
787787
clearSearch: "Limpar pesquisa",
788+
clearFilters: "Limpar filtros",
788789
viewFilterNoMatchesMessage: "Nenhum registro corresponde ao filtro desta visualização.",
789790
ownedNoneTitle: "Ainda não há nada seu",
790791
ownedNoneMessage: "Esta visualização lista apenas os seus registros, e você ainda não tem nenhum.",

‎ui/packages/i18n/src/locales/ru.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@ const ru = {
809809
noMatches: "Подходящих записей нет",
810810
noMatchesMessage: "Ни одна запись не соответствует текущим фильтрам или поиску. Измените или сбросьте их.",
811811
clearSearch: "Очистить поиск",
812+
clearFilters: "Очистить фильтры",
812813
viewFilterNoMatchesMessage: "Ни одна запись не соответствует фильтру этого представления.",
813814
ownedNoneTitle: "У вас пока ничего нет",
814815
ownedNoneMessage: "В этом представлении показаны только ваши записи, а у вас их пока нет.",

0 commit comments

Comments
 (0)