Repository navigation
Console: opening a list filter panel persists a view overlay that overrides the source-defined view filter (empties the list) #4155
Description
Activity
Additional field report from downstream acceptance testing (private app repo steedos-labs/os-project-titanwind-ehr, S06 batch, 2026-08-10, console @objectstack/*@17.0.0-rc.5):
- Filter conditions set via the list filter panel on a source-defined shared view ("全部派工单" / all dispatch orders) survive logout + re-login for the same account — the persisted overlay keeps applying, conditions stack across sessions, and the list eventually shows "no matching records" until the user clicks "Clear all" in the filter panel.
- During the acceptance run this produced repeated false "empty list" states; the run had to adopt a "always Clear-all before each filter change" discipline to get stable results.
Evidence screenshot lives in the downstream private repo (evidence branch
20260810-s06-work-order/PROBE-001-筛选面板.png) — happy to re-capture on a public reproduction if useful. Behavior matches the persisted view-overlay described in this issue; adding the cross-session persistence angle as extra repro signal.Triage:
pm:queue— concrete high-severity defect with a repro and two independent observations (a QA run and a dev run, different objects/accounts, plus the downstream S06 acceptance field report on this thread: overlays stack across sessions and survive logout/re-login).- Substance: interacting with the list filter panel persists a view-customization overlay in
sys_metadatathat replaces the source-defined viewfilter(a strayfield equals ""condition), cross-user and unrecoverable from the panel's own Clear-all. Silent overwrite of a source declaration by a non-admin用户 path + misleading "no data yet" empty state — this is a dispatchable defect, not an observation. - Dup check: no open objectui/objectstack card covers filter-panel overlay persistence (Studio 在代码定义的包里把「只读」一刀切到所有类型:运行时实测接受其中 15 类的 overlay 写入,同屏还并存「可写」徽标与全部禁用的控件 #4036 is Studio read-only badge vs overlay writes — different surface; local filter over cached open lists). Server-side overlay semantics (which rows may be persisted, whether an end-user interaction should ever write a view overlay) may grow an objectstack-side card once the landing is diagnosed; nothing to split pre-diagnosis.
- Premise: report is from live rc.5 runs today; nothing on
origin/main@521a37bclaims a fix in this area (no overlay/filter-panel entries in recent history touching the persist path).
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Substance: interacting with the list filter panel persists a view-customization overlay in
CLAIM (objectui whole-repo seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3) — dispatching a dev agent now.- Branch
claude/issue-4155-filter-panel-overlay, worktreeobjectui-issue-4155(M container, diagnosis-first) - Delegated product ruling for the client half (veto window open), answering the card's own question: an end-user's filter-panel interaction must NOT persist a view-customization overlay — transient filter state is session/URL state; overlay writes belong to an explicit save-view action only. Additionally: an empty-value condition must never be persisted or applied as
field equals "", and Clear-all must actually clear any overlay the panel wrote (recovery for already-poisoned installs). - Lane split: if diagnosis lands the cross-user scoping half server-side (a per-user customization stored org-wide in
sys_metadata), the dev stops at evidence and the seat files the objectstack-side card — this lane never lands platform code. - Surface constraints:
TabBar.tsxis train-held (unmerged PR fix(i18n): render I18nLabel objects at the 13 remaining sites #4208);packages/data-objectstack/src/index.tsis held by updateView reads the base view without preview=draft, so renaming a freshly-created draft view is silently lost (404 → create-equivalent partial write → 422) #4139's agent right now — both read-only for this task.
Generated by Claude Code
- Branch
ACCEPT (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4214, delivered across two host restarts (gen-1/2 diagnosis + source inherited and verified, gen-3 added the missing changesets, corrected a measurably-wrong prediction header, and ran the full evidence ladder).The diagnosis is complete and mechanistic:
onFilterChange → persistViewFilter → persistViewPatch → updateViewConfigwrote an overlay on every panel emission; "Add filter" emits an incompleteequals ''row immediately, the key-wise merge made that one row REPLACE the declared filter, and the live grid's own AST conversion skips empty values — so the only condition the screen ignored was the only condition that reached storage, which is why nothing looked wrong until the next load. Clear-all'sfilter: []was still an override with an opinion. All four rulings landed: R1 the panel persist bindings are deleted (explicit save-view remains the only overlay write, pinned as a control, with the objectstack#5159 fold surviving on that path under a retargeted ratchet); R2 two-layer (fold drops valueless rows matching the live query's own predicate;sanitizeViewOverridestrips them in both at-rest shapes on read, dropping thefilterKEY so the source declaration wins — poisoned installs self-heal with no metadata surgery); R3 from both ends; R4 via the existinglist.noMatcheskeys (all ten locales verified, zero new keys). The deliberate expressiveness loss — an overlay can no longer say "NO filter" over a declaring source — is recorded in code, changeset and PR, and I endorse it: that shape was the eraser.The corrected prediction header deserves note: the inherited claim that the control block stays green under reversion was measured false (module dies at import when the export vanishes — a missing export cannot discriminate), rewritten to record the real 24/13 split and name the genuinely discriminating cases. That is the reverse-verification discipline applied to inherited work.
CI converged 18 success / 2 skipped / 0 failures on
b4800fd4b. Cross-user verdict accepted as platform-side and NOT closed here: the seat takes the handoff — an objectstack-side card will be filed forupdateViewConfigwriting "per-view personal config" as one org-wide metadata item (evidence at data-objectstack index.ts:2818), folding in the related observation that sort/columnState overlays pin the filter as-of-write. Flipping ready + auto-merge.
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 - added a commit that references this issue
on Oct 4, 2026
Summary
In Console, opening a list view's filter panel and interacting with it (add / clear a condition) persists the transient filter state as a view customization overlay in
sys_metadata(type=view). The overlay overrides the source-defined viewfilter— e.g. a source view whose default filter isstatus not_in [archived, deleted]gets its filter replaced by a strayfield equals ""(empty-value) condition. On the next visit the list is served with that empty-value filter →total: 0→ the list looks permanently empty.Two things make this hard to diagnose:
field equals ""filter.Recovery requires deleting the overlay row from
sys_metadataand restarting the service.Impact
Environment
@objectstack/*@17.0.0-rc.5filter(status not_in [...]).Steps to reproduce
filter(e.g.status not_in ['archived','deleted']).Expected: the source-defined
filteris intact; the list shows the same rows as before.Actual: the list is served with a persisted
field equals ""overlay filter →total: 0→ empty list with "no data yet" copy; the filter panel shows no conditions; the source filter is gone until thesys_metadataview overlay row is deleted and the service restarted.Notes / questions
field equals ""? And surface a "clear customization / reset to default" affordance for non-admins?Reproduced while building an ObjectStack 17 app. Detailed screen captures are available on request (currently in a private project repo).