Skip to content

data-objectstack 的 listViewOverrides 读的是 meta/{对象名}(把对象名当 metadata type),写却落在 type='view' —— 两边键空间不相交,已保存的视图个性化永远读不回来 #3774

Closed

Description

@yinlianghui

在做 #3770(默认列表视图身份)的存量数据测量时端到端读了 override 的读/写两条路径,发现的相邻缺陷,不在该单范围内(不同包、不同事实),按 PD #10 单独立此单,未在 PR 里修。

结论

ObjectView 的「每视图配置 override」(密度、列宽、排序、隐藏列、inlineEdit…)写在一个 metadata 命名空间,读在另一个。批量读方法永远返回空 map,而它返回的空 map 又恰好挡住了本来正确的逐视图回落路径。结果:用户在列表上调的密度/列宽/排序,硬刷新后拿不回来。

证据(读/写两条路径逐跳)

写(正确) —— packages/app-shell/src/views/ObjectView.tsx persistViewPatch:

dataSource.updateViewConfig(objectName, viewId, cfg)
  → packages/data-objectstack/src/index.ts  updateViewConfig
  → client.meta.saveItem('view', viewId, { ...cfg, object: objectName, name: viewId })
  → PUT /api/v1/meta/view/{viewId}      →  sys_metadata 行:type='view', name={viewId}

updateViewConfig 的注释本身写明了这一点:type='view'(NOT type={objectName} —— 那是 pre-overlay 的误用,服务端从没接过)。

读(命名空间错了) —— 同文件 listViewOverrides:

client.meta.getItems(objectName)
  → GET /api/v1/meta/{objectName}       ← 把对象名当成 metadata TYPE
  → protocol.getMetaItems({ type: '{objectName}' })
  → registry.listItems('{objectName}')  +  sys_metadata WHERE type='{objectName}'

override 全部写在 type='view' 下,这个列举因此不可能包含它们。异常时 listViewOverrides 自己 catch 掉并返回 {}。

空 map 还挡住了正确的回落。 ObjectView 的 loadBatch:

if (typeof (dataSource as any).listViewOverrides === 'function') {
  try {
    const all = await (dataSource as any).listViewOverrides(objectName);
    if (all && typeof all === 'object') { /* 建 map */ return map; }   // {} 也是 object
  } catch { /* fall through */ }
}
if (typeof dataSource.getView !== 'function') return {};
// 逐视图 getView → client.meta.getItem('view', viewId) —— 命名空间是对的

{} 是 object,于是 return map 提前返回;而 listViewOverrides 内部已经把异常吃掉,所以对这个适配器来说 catch 分支也永不触发 —— 逐视图 getView 回落在 data-objectstack 上是不可达代码,尽管它读的正是写入的那个命名空间。

影响

用户在列表视图上做的持久化偏好(密度切换、列宽拖拽、排序、隐藏列、inlineEdit 开关)写进去了、也确实存在 sys_metadata 里,但下次进页面读不回来,表现为「设置没保存」。与视图 id 拼写无关:任何 id 都读不回来,#3770 改不改都一样(那单只改 id 的推导方式)。

备注 / 方向建议(未擅自动手)

批量方法的动机是好的(避免每个视图打一次 GET、对没定制过的视图刷一串 404),问题只在类型槽填错。可能的方向:让 listViewOverrides 走 type='view' 的列举(如按 object 过滤的 /meta/view?object=,listViews() 已经在用类似的过滤法),或在批量结果为空时不要吞掉逐视图回落。具体取哪条要看服务端列举端点的语义,故留给分诊。

相关

Activity

  1. self-assigned this
    on Aug 8, 2026
  2. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    分诊 + 认领:PM 循环批 182(objectui 整仓席位,登记表 objectstack#4604)

    分诊:具体缺陷、逐跳证据、用户可感("设置没保存")→ auto-queue(bug + pm:queue)。方向按测量定:①批量读的 type 槽修正(先测服务端 type='view' 过滤列举的真实语义——listViews() 已在用类似过滤,照它的拼法);②吞错不再冒充权威(listViewOverrides 内部 catch 掉异常返回 {} 使逐视图 getView 回落成为不可达代码——错误应穿透到回落,与 filter 契约同族:拿不准就别装知道)。两半件同 PR,各自带钉。

    会话:session_01GTRjn8xBqp75dk7kFupVRt
    分支:claude/issue-3774-view-overrides-readback
    Worktree:objectui-3774
    文件面:packages/data-objectstack/src/index.ts(listViewOverrides)+ 必要时 packages/app-shell/src/views/ObjectView.tsx 的 loadBatch 遮蔽半件 + 两包测试(越界即停)


    Generated by Claude Code

  3. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    验收:PR #3777 ACCEPT(会话 session_01GTRjn8xBqp75dk7kFupVRt,PM 循环批 183)。

    交付内容:①类型槽修正——测量推翻了 issue 建议的 ?object= 路由(框架 rest-server.ts 实读:GET /meta/:type 只认 package/preview 两参数),按裁定 4 豁免走 listViews 同款批准路线(type='view' 一次列举、客户端收窄),两个读者共用新的 viewItemObjectName() 访问器使其无法再分叉;②吞错不再冒充权威——空成功仍权威早返回(批量优化保住),失败改为 reject 使逐视图 getView 回落可达,且 rejection 不进缓存(单独钉);消费半径扫出第二个同形消费者 InterfaceListPage(批量调用在外层 try 里,rejection 会连自己的回落一起跳过)给了作用域 catch;DataSource 接口 JSDoc 从"把错误命名空间当范本"改为写明双契约条款——防其他适配器复植。

    证据:往返式测试设计有据(手写 fixture 会带着 bug 全绿——命名空间错误恰好活在 fixture 里;写路径灌、读路径排才是真钉);revert 类型槽 → 6 红含字面 pre-fix URL,且如实指出空成功测试在该 revert 下保持绿正是"往返而非空成功才是抓手"的证明;我派发词里的预测 (c) 被 dev 论证为不可达成(app-shell 测试直接 stub 数据源,适配器 revert 移不动它)——dev 没有为凑预测造红,而是让适配器钉承担该方向并给出"每半件各自带钉"的不对称性论证,采纳,方法库记一笔:跨层修复的逆向验证要按层预测,PM 不应跨层拍红点位置。字节纪律事故又立一功:Write 工具把模板字面量的空格具象化成 5 个裸 NUL,check-control-bytes 因文件未跟踪而失明(#4890 盲区原样),靠派发词强制的手工 grep -naP 抓住——该手工步骤继续保留为必做项。CI 报告时 14/19 零失败,余下由 merge queue 兜底。

    新立 #3778(4 处失效调用无人填充的死缓存键,观察级,两方向留分诊)入分诊池。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions