Skip to content

feat(app-shell): Studio opens an off-nav list view on its object's page, lists only views no dropdown reaches, and reads form views as forms - #30401

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-5r0o5c
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-5r0o5c

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2

维护者速读

  • 改了什么:Studio 界面里,从「不在导航中 → 视图」打开列表视图,现在落到对象页(标题 对象 / 视图 ▾),条件格式化和视图表单分节一并搬到右侧面板;有导航入口的对象,其列表视图不再重复列在该分组;表单视图显示为「线索表单」这类可读名字,分组标题按内容写「表单视图 / 视图 / 表单视图与列表视图」,表单视图的「视图类型」读出 简单 / 标签页 / 向导,不再是「simple(未找到)」。
  • 为什么改:Studio Interfaces: choose an object's view from a dropdown at the top of the preview, in the object's title, the way the running list does #30046 Scope 6–8(裁定 A,6651738887)。同一个列表视图以前有两个页面、两套面板,导航里已能到达的视图又在「不在导航中」重复出现,表单视图名字是 crm_lead.form 这类内部名。
  • 风险与回滚:只动 Studio 前端(app-shell 与 studio 语言包三个新键),不动元数据、spec 或服务端。共用的视图检查器只在表单视图上换类型清单,列表视图那一侧不变并有测试钉住。回滚即 revert 本 PR。
  • 先看:StudioDesignSurface.tsx 的 pickOffNav / listViewDoorOf 与离线分组过滤,ListViewMoreSection.tsx(新),ViewVariantInspector.tsx 的 useTypeOptions。
  • 两分钟验证:打开示例 CRM 的 Studio → 界面:「不在导航中」只剩「表单视图」4 项;点「线索表单」,视图类型显示「简单」;访问 ?surface=view:crm_lead.pipeline 落到「线索 / 线索看板」。
  • 需要你做的:本 PR 新增三个 i18n 键(Clause-② widening),席位需安排 TIER_DEFAULT 评审;其余无。

Fixes #30046

Clause-②: yes (widening) — three new published @object-ui/i18n Studio keys: engine.studio.if.offNav.viewForms, engine.studio.if.offNav.viewMixed, engine.studio.if.offNav.formName (en + zh). No accept set narrowed.
Metadata-protocol: none — Studio UI only: no metadata key, spec schema, server route or stored shape is added or read differently; the view items are read through the existing /meta/view list (drafts overlaid) and written through the existing list-view draft path.

What changes

Scope 6–8 of #30046, ruled as option A (6651738887). Scope 1–5 landed in #30175 and are untouched.

  • Scope 6 — a list view opens on its object's page from every door. Picking a list view under 不在导航中 → 视图, or following a link to the view itself (?surface=view:OBJECT.KEY), now lands on the object page with its header dropdown (object / view ▾) on that view: the object's nav entry when it has one, else the object itself with no entry (?surface=object:OBJECT&view=…, which a reload or a shared link opens again). The panel there gains ListViewMoreSection (new): the view's 条件格式化 (ConditionalFormattingEditor, whose CEL verdicts now hold the list-view autosave the way they held the view page's Save) and the spec authoring form's sections for a view, pruned of every key the panel already edits, so no setting has two controls. A form view, and a view a read-only base's pair adds (addedIn), still open as themselves. Studio on zh-CN still mixes languages and terms: view properties panel, flow nodes, publish sheet labels, and 仪表板 beside 仪表盘 #30039 owns translating those sections.
  • Scope 7 — the 视图 group lists what the dropdowns do not reach. A list view whose object has a nav entry is no longer listed, a view only drafted in the package included (withDraftViewBindings reads the drafted rows' object/viewKind from the draft-overlaid list, fail-soft). The list views of an object with no entry stay listed. The only-customized filter is unchanged.
  • Scope 8 — form views read as forms. A form view is listed by its label, else as the object's name plus 表单 ("Lead form", 「线索表单」, with · key for a non-default form); the group's heading says what it holds (表单视图, 视图, or 表单视图与列表视图). In ViewVariantInspector, a form view's 视图类型 reads the form-variant schema's type enum (simple / tabbed / wizard, labelled with the existing engine.inspector.pageBlock.option.formType.* keys) and defaults to simple; a list view's picker is byte-for-byte the same roster as before.
  • ObjectListViewInspector.tsx: the hook gains openView(surface, viewId); the panel appends ListViewMoreSection as an independent block after the sort block, with no existing section reordered (seat 4's [Decision] Selection-bar actions cannot be configured in Studio: should the view panel offer them? #30089 adds a section in the same render region). fix(app-shell): a draft-only object's nav entry opens its drafted default list view in Studio Interfaces #30315's listViewTargetOf hunks are not touched. StudioDesignSurface.tsx's restoreOriginal / publishNonce region (Studio: after 恢复原版 the rail keeps the customized mark and 仅看定制 (1) until a reload #30238) is not touched.

Tests

  • New InterfacesPillar.offNavListViews-30046.test.tsx (13 cases): Scope 7 filtering with controls (an object with no entry stays listed, a drafted view included), Scope 8 names and the three headings, Scope 6 object page landing, the panel's 条件格式化 and spec sections, a second pick on the same page, ?surface=object:…&view= and ?surface=view:… links with and without an entry, CONTROL that a form view still opens as itself, and the CEL hold (autosave blocked on a bad rule, saved once fixed).
  • New ViewVariantInspector.formViewType-30046.test.tsx (8 cases, en + zh): a form view reads its layout and offers only the form roster; a form view with no type reads Simple; CONTROL a list view still offers the list types; CONTROL an off-enum list type is still flagged.
  • packageSurfaces.test.ts: 3 cases for viewBindingOf / withDraftViewBindings.
  • InterfacesPillar.offNavItems-26889.test.tsx and InterfacesPillar.offNavDeepLink-28561.test.tsx: their off-nav view fixture is now a form view (web_form), since a list view of an object with an entry is no longer listed there; what they assert is unchanged.
  • Red first: with origin/main's five source files checked out, 17 of the new/changed cases fail (5 files); all pass on this branch.
  • Ablations (scripts/ablation-replace.mjs, each restored with blob == HEAD and an empty git diff HEAD): Scope 7 filter → 3 red; the list-view door → 5 red; the form-type roster pick → 2 red (both locales); the CEL hold term → 1 red.

Acceptance notes

  • Card Acceptance 5, browser checks on both package kinds (branch head before the main merge, which brought no ui change), screenshots in the project files under ui-seat2/card-30046/screenshots/:
    • Read-only example CRM (examples/app-crm): 不在导航中 lists only 表单视图 (4): 活动表单, 线索表单 · web_to_lead, 线索表单, 商机表单; the default landing panel carries 条件格式化 and 基础信息 below the sort block; ?surface=view:crm_lead.pipeline lands on 线索 / 线索看板 at surface=object:crm_lead&nav=nav_leads&view=crm_lead.pipeline; 线索表单 opens as a form view whose 视图类型 reads 简单.
    • Writable throwaway package (one object with a nav entry, one without, all views drafted): the heading reads 表单视图与列表视图 with Case表单 and Open cases only; the entry object's drafted All tasks / My tasks are absent from the group and present in its header dropdown; Open cases lands on Case / Open cases at surface=object:ws_case&view=ws_case.open, survives a reload, and its panel shows the view's CEL rule (CEL 有效).
  • Observed, not in this card's scope: the form view inspector's header still reads the item name (crm_lead.form), and its spec sections (Layout, Columns, Title) are English in zh, which is Studio on zh-CN still mixes languages and terms: view properties panel, flow nodes, publish sheet labels, and 仪表板 beside 仪表盘 #30039's.
  • Line budget: 1153 insertions, 41 deletions (1194 changed lines, about half of them tests), under the ~1200 stop.

Verification

On the final tree (head 9eff7192, origin/main 870ebce3 merged in), every exit code recorded to a file before any pipe:

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack <14 changed paths>: 35 commands, all exit 0 (pnpm --dir ui exec vitest run scripts/: Test Files 170 passed | 2 skipped, Tests 4985 passed | 2 skipped). --ran reconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN.
  • node scripts/check-sdui-manifest.mjs: exit 0 (and --self-test exit 0).
  • pnpm --filter @object-ui/app-shell --filter @object-ui/i18n lint: exit 0, 0 errors (warnings only, existing patterns).
  • pnpm --dir ui run check:new-line-citations: exit 0. pnpm check:nul-bytes: exit 0.
  • pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n --concurrency=2 (under os-verify-lock): 69/69 tasks, exit 0.
  • Targeted re-run after the merge: the five changed/new test files, Test Files 5 passed, Tests 50 passed.
  • Before the merge, every test file importing a changed module plus every InterfacesPillar.* and StudioDesignSurface.* test (167 files): 1220/1221, the one red being the zh lazy-catalogue race in the new inspector test, since fixed (top-level await loadStudioCatalogue('zh')) and green three runs in a row.

Generated by Claude Code

…s object's page; the group lists what the dropdown does not reach; a form view reads a real type

WIP: the three remaining scopes of the Interfaces view dropdown card, with
their tests; not yet run.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXDf4Yt5PtKZFbtLVD
…e opened from 不在导航中; controls stay controls

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXDf4Yt5PtKZFbtLVD
… first; changeset

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXDf4Yt5PtKZFbtLVD
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 9eff719240e8b21f3877c663e4f1b211ad4628f8
Local-runs: none

Reviewed 2026-11-05T09:45Z. Face: Clause-②: yes (widening) declaration only (changeset line). The diff touches no packages/spec/src/** and no governed rule text. It does not narrow anything.

① Derived judgments

  • @object-ui/i18n gains three keys. They are engine.studio.if.offNav.viewForms, engine.studio.if.offNav.viewMixed and engine.studio.if.offNav.formName ({object} placeholder). Each is added to both en.ts and zh.ts, and no existing key is renamed or removed. The keys are additive and widen the bundle's published key set. ✔
  • PackageSurface gains optional object? / viewKind? members, and viewBindingOf / withDraftViewBindings are new exports. They live in app-shell's internal studio-design/packageSurfaces.ts. The fields are optional and appear only on view rows, so every existing reader keeps its shape. ✔
  • ViewVariantInspector reads its 视图类型 options from getFormVariantSchema() for a form-family view. The source enum is the spec's FormViewSchema.type, read as served and not restated here. The list family keeps getListVariantSchema() unchanged. A form view with no type now reads the spec default simple, where it used to read grid. Nothing new is written: the value is only displayed until the author commits a pick. ✔
  • ListViewMoreSection drives the generic SchemaForm from the spec's list-variant JSONSchema plus getViewForm. It prunes the keys the panel already edits and keeps no per-key field list. repinned() restores the pruned keys from the body on every emit, so a form edit cannot move them. ✔
  • The list-view autosave is held while a conditional-formatting CEL verdict is non-zero. It reuses the existing engine.studio.held.inspectorInvalid clause, which adds to what the panel holds (it holds more edits, not fewer). It matches the Save hold on the view's own page (objectui#4527). ✔
  • New door: ?surface=object:OBJECT for an object that has no nav entry. This deep-link shape is new for the Studio and the mirror already wrote object: leaves. It only resolves when the package lists a list view of that object; otherwise the off-nav fallback applies as before. ✔

② Semver level

The changeset sets @object-ui/app-shell: patch and @object-ui/i18n: patch. Both are additive with no removal, which matches repo precedent for Clause-②: yes (widening) (for example .changeset/27193-recompute-home-amounts.md, 27195-…). The level is consistent with the declaration. ✔ Metadata-protocol: none is correct, since no server or protocol path is touched.

③ Boundary flags

Implemented-by: claude/project-thread-5r0o5c
Reviewed-by: session_01Utp6Cb5R6JDdfyvtj3dPR2

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2

维护者速读

  • 改了什么: Studio 界面里有三处改动。
    1. 从「不在导航中 → 视图」打开列表视图,或者直接访问 ?surface=view:对象.视图 链接,现在都会落到对象页(对象 / 视图 ▾),条件格式化和视图表单分节也一起搬进了右侧面板。
    2. 有导航入口的对象,它的列表视图不再在该分组里重复出现。
    3. 表单视图显示为「线索表单」这样的可读名字;分组标题按实际内容写成「表单视图」「视图」或「表单视图与列表视图」;表单视图的「视图类型」读出「简单 / 标签页 / 向导」,不再显示「simple(未找到)」。
  • 为什么改: Studio Interfaces: choose an object's view from a dropdown at the top of the preview, in the object's title, the way the running list does #30046 Scope 6–8(裁定 A,6651738887)。同一个列表视图原先有两个页面、两套面板;导航里已经能到达的视图又在「不在导航中」重复出现;表单视图显示的是 crm_lead.form 这样的内部名。
  • 风险与回滚: 改动只在 Studio 前端:app-shell 加三个新的 studio 语言包键。不动元数据、spec 和服务端。共用的视图检查器只在表单视图上换类型清单,列表视图那一侧不变,并有测试钉住。回滚办法是撤销本 PR。
  • 先看: StudioDesignSurface.tsx 里的 pickOffNav / listViewDoorOf;新文件 ListViewMoreSection.tsx;ViewVariantInspector.tsx 里的 useTypeOptions。
  • 两分钟验证: 打开示例 CRM 的 Studio → 界面。「不在导航中」应只剩「表单视图」4 项;点「线索表单」,视图类型应显示「简单」;访问 ?surface=view:crm_lead.pipeline,应落到「线索 / 线索看板」。
  • 需要您做的: 无。本 PR 不在受管面,共 1194 行,三个新 i18n 键的 TIER_DEFAULT 契约复核已经 PASS(6654816602)。席位会经合并队列落地。
  • 席位意见: ACCEPT。

席位核对 — ACCEPT · domain:ui#2 · head 9eff719240e8b21f3877c663e4f1b211ad4628f8

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 11:31
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 5, 2026 11:31
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 5, 2026
…-5r0o5c

ViewVariantInspector.tsx: main moved the list-view type labels to
viewTypeLabels.ts (imported as typeLabel); this branch's form-layout
labels (FORM_TYPE_LABELS, formTypeLabel) are kept beside that import.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXDf4Yt5PtKZFbtLVD
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2

席位核对 — ACCEPT(新 head 复核)· domain:ui#2 · head f40b6c1d97c880b8aa210e875c24360fbfb93c81

合并队列在 11:46Z 以 MERGE_CONFLICT 把 9eff7192 退回了。原因是刚合入 main 的 #30381 改了同一个 StudioDesignSurface.tsx。

卡线程随后把 origin/main 合了进来(合并提交 f40b6c1d,包含 #30381、#30426、#30378、#30433、#30428),并解决了冲突。

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 5, 2026
…-5r0o5c

ObjectListViewInspector.tsx: main's selection-bar actions section
(ListViewBulkActionsSection) and this branch's ListViewMoreSection are
kept as two sibling blocks after the sort block, bulk actions first;
both imports kept.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXDf4Yt5PtKZFbtLVD
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2

席位核对 — ACCEPT(第二次新 head 复核)· domain:ui#2 · head 81fb90a21f4ca562d17bd4d8cc69e0f7dd5427e4

12:30Z 合并队列再次以 MERGE_CONFLICT 退回 f40b6c1d。原因是 #30339(#30089)刚合入 main,它也改了 ObjectListViewInspector.tsx 的面板区,以及 studio 的 en/zh 语言包。

卡线程随后用 merge 把 origin/main 合了进来(合并提交 81fb90a2,含 #30339 和 #30387)。冲突的处理方式是:main 的 ListViewBulkActionsSection 及其 objectName && listViewHasSelectionBar(body) 条件原样保留,本 PR 的 ListViewMoreSection 作为并列块排在它后面,两者都在 DraftSourceLine 之前。两处 import 都保留了。

  • 本 PR 自身的改动没有变: 我比对了 git diff f40b6c1d^2 f40b6c1d 和 git diff 81fb90a2^2 81fb90a2 的全部 +/- 行,两边逐行一致,仍是 14 个文件,+1153/−41。冲突区里变的只有上下文,也就是相邻的 feat(app-shell): configure a list view's selection-bar actions in Studio (#30089) #30339 块。所以 6654816602 的 TIER_DEFAULT PASS 记录和 6655125407 的 ACCEPT 照旧有效。studio en/zh 里本 PR 只新增三个键,没有重复键。
  • 门禁 check-runs: 81fb90a2 上共 55 个 run,全部 success 或 skipped,0 个失败。Live E2E UI 的 attempt 1 有一个用例失败(studio-customize-journey,后端直连 GET 时 ECONNRESET,断言本身没有失败,其余 16 个用例通过)。同一个 spec 在 9eff7192 和 f40b6c1d 上都是绿的,经中继重跑后 attempt 2 为 success(job 127262339351)。本 head 与当前 main 用 git merge-tree 试合,结果干净。
  • 落地条款: Fixes Studio Interfaces: choose an object's view from a dropdown at the top of the preview, in the object's title, the way the running list does #30046。维护者 11:29Z 已在席位线程授权落地,本席位在这个 head 上重新执行 automerge_enable。

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit bc8945f Nov 5, 2026
87 of 88 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-5r0o5c branch November 5, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio Interfaces: choose an object's view from a dropdown at the top of the preview, in the object's title, the way the running list does

1 participant