Repository navigation
Interfaces pillar: the rail is the app's navigation tree (groups, metadata icons, kind tags), "+" offers the ten nav kinds, and the canvas follows the kind: page regions designer, object runtime list preview, dashboard canvas #12455
Description
Source
Epic #12446, decisions 1, 3 and 5. Measured on objectui main a2225f91 at /studio/app.objectstack.hotcrm/interfaces against the running HotCRM app's sidebar and src/sales/apps/crm.app.ts: the shipped sidebar renders Home, Sales Home, then the groups Sales, My Work, Activity, Marketing, Service, Insights, each entry with its metadata icon (home, layout-grid, user-plus, building, target, receipt, file-signature, package, chart-line, circle-check, calendar-days, inbox, activity, megaphone, layout-dashboard, trending-up, columns-3). The spec declares ten nav kinds: object, page, dashboard, report, url, action, component, doc, group, separator. Studio's rail today shows a second band ("Home · Dashboard"), two-line rows with ids and no icons, "Canvas / Properties" as tabs with a w-9 icon strip, and a Design / Run pair below.
The maintainer's ruling (quoted on the epic): look at the real frontend; there are many menu kinds, the dashboard is only one.
Target
- Rail (shared rail card): the navigation tree as the shipped sidebar orders it. Top-level entries and group headers (uppercase 11 px label with a chevron, collapsible, honoring the metadata
expandeddefault); child rows indented 12 px; every row shows its metadata icon, its label, and a 10 px uppercase kind tag at the right — Dashboard, Page, Object, View (an object entry bound toviewName), Component, Report, Link, Action, Doc; separators render as 1 px rules; an empty group shows "No items in this package". The id and the bound target stay in the row's title. The "+" in the rail header opens a kind picker: a 268 px popover listing the ten kinds, each with its glyph, name and one-line description (Object — a list view or one record; Page — a custom page built from blocks; Dashboard — widgets over filters; Report — a saved report; Link — an external URL, same or new tab; Action — runs a global action from the menu; Component — a registered component, like the approvals inbox; Doc — a doc page, a book, or both; Group — a titled section of the menu; Separator — a divider, no label, opens nothing). Choosing one adds the unbound entry and opens its inspector (today's create flow for pages / dashboards / reports continues from there). - Item header row: a primary-soft tile with the kind's icon, the entry label at 18 px / 600, a kind chip, the target api name as a mono chip; at the right Design / Run as a 26 px segmented control (pencil and play glyphs; hidden for kinds that have no design mode, as today's
StudioCanvasgate decides), a divider, the properties toggle (aria-pressed), a more button. The "Home · Dashboard" band retires. - Tab row: Canvas, and Source where the kind has a source editor (page, dashboard, report); object entries show Preview only with a trailing 12 px note "Runtime list preview · fields and structure are edited in the Data pillar" and an "Open in Data" outline chip in the header.
- Canvas by kind: page — a sidebar-tinted designer whose regions (
header · full,left_sidebar · small,main · large,right_sidebar · medium, named from the page's own layout) are dashed 8 px frames with a 10 px uppercase region label, blocks as white cards with a title,#idin mono and a kind tag (page:card,page:tabs,list-view,object-metric,element:text), an empty region reading "Empty region. Drop a block here.", a "Design mode · drop blocks into a region, click a block to edit it" toolbar with "Add block"; object — the runtime list in a white 8 px card (search, density, Export, New; the grid; a footer count); dashboard — today's widget canvas with the widget cards at 16 px padding and the selected widget ringed. - Inspector per the shared aside card: for a nav entry, eyebrow "Nav item · Page", the label, the nav id; Label, Icon (a 32 px preview tile plus the icon name in mono), Type, the kind's target field (Page / Object / Dashboard / Report / URL + Open in / Action / Component / Doc page + Book), the object-only Landing (List view / Record), View, Record ID, Open mode and URL filters rows the inspector already has, "Visible when" showing the
visiblepredicate read-only, and "Remove nav item" at the bottom. For a selected block or widget, that item's properties.
Everything the nav inspector enforces today stays: unbound entries are left out of the saved navigation (navPlaceholderSave-11776), entry identity by id (navEntryIdentity-11774), label maps (navItemInspectorLabelMaps-11148), standard entries (standardNavEntries-11201), the badge and separator rows (railSeparatorBadge-11791), the nav kinds list (navItemTypes-11790), deep links (navDeepLink-11153), autosave flush on navigation (navAutosaveFlush-11189).
File surface
packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (InterfacesPillar, NavTree, StudioNavItemInspector, NavTargetSelect, NavUrlFields), interfaceCreate.tsx (entry from the kind picker), studio-canvas-preview.tsx (page / object canvas frames), packages/app-shell/src/views/metadata-admin/i18n.ts (kind names and descriptions; engine.inspector.appNav.* keys stay).
Acceptance
- With HotCRM open the rail renders the same order, groups and icons as the running app's sidebar for that package (screenshot pair), with kind tags; the empty Service group shows the empty row.
- The "+" picker lists all ten kinds; choosing Separator adds a rule, choosing Group adds a header, choosing Link adds an unbound entry whose inspector shows URL and Open in.
- Selecting Home (dashboard), Sales Home (page) and Leads (object) shows the three canvases described above with the item header's kind chip and api chip.
- The band and the
w-9strip are gone; the properties toggle in the header opens and closes the aside. - All
StudioDesignSurface.nav*,interfaces*,InterfacesPillar.*,interfaceCreate.*andstudio-canvas-previewtests stay green or are updated in the same PR, each ablated once. - Before/after screenshots at 1280 px, light and dark.
Constraints
- Tailwind utilities and theme tokens only; no inline style.
- Existing
data-testids and i18n keys stay. - Gates:
pnpm --filter @object-ui/app-shell test,lint,build,pnpm check:i18n. - Lands after the shared rail and inspector cards (the Blocked-by lines below).
Reference artboard
docs/design/studio-redesign/interfaces-page.html, interfaces-object.html and interfaces-dashboard.html (one per entry kind the card names) on objectui main (landed in #12458); the three .png files beside them are their 1280 px renders. The folder's README carries the shared numbers and what a pull request against this card must show: two screenshots per artboard it touches (light and dark, 1280 px, cropped to the artboard's region), a deviation list with a reason per line, and the card's named tests green or updated. Where this card and the artboard disagree, this card's numbers win and the disagreement is reported here.
Blocked-by: #12459
Body refreshed 2026-10-15T09:53Z by the epic PM session: a Reference artboard section added now that #12458 is on main. Earlier refresh 2026-10-15T08:18Z: the Blocked-by line now names the layout skeleton card #12459, which supersedes #12447, #12448 and #12449.
Parent: #12446
Activity
objectstack-fleet commentedon Oct 15, 2026
Unlock read 2026-10-15T09:52Z: #12459 landed in #12460 (main
cf430cd10e), so the Blocked-by line that names it is satisfied. The reference artboards are on main underdocs/design/studio-redesign/(#12458) and the body now carries a Reference artboard section naming this card's.Claimable by the
domain:uilane inside the epic's reservation, as #12450, #12452 and #12454 were claimed by seatdomain:ui#4at 09:35Z; acceptance against the artboard stays with the epic PM.Epic PM session
session_cdb7a717-def7-4e71-9988-f089fbaa18ff.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 1 (epic #12446 subtree)
Session:
session_01SJn1GEkrbbBQkhGC26wEDwAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12455-interfaces-nav-treeWorktree:
objectui-issue-12455(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#4File surface:
packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(region:InterfacesPillar,NavTree,StudioNavItemInspector,NavTargetSelect,NavUrlFields,StudioNameLabel),interfaceCreate.tsx(entry from the kind picker),studio-canvas-preview.tsx(page and object canvas frames; exported signatures unchanged), presentation-only edits topackages/app-shell/src/views/metadata-admin/previews/PagePreview.tsxandDashboardPreview.tsxif the page and dashboard canvases render there,StudioRail.tsx(additive only, if a needed slot is missing),packages/app-shell/src/views/metadata-admin/i18n.ts(kind names and descriptions;engine.inspector.appNav.*keys stay), new tests beside them, the screenshots underdocs/design/studio-redesign/after/named12455-*.png, one.changeset/12455-*.md(stop on breach; explain in the report)Container & model:
L,mode:cloud,model: opus(cloud on the maintainer's stance 「后续重型任务可以开云卡」, this session's chat, 2026-10-15)Clause-②: no
Responsibility:
n/a — not a defect cardThread-read: 6189330242
Serial constraints cleared: objectui#12442's PR objectui#12467 touched
PagePreview.tsxand merged at3e2394d, so this card starts after it. In flight on the same file at claim time: objectui#12450 (DataPillar) and objectui#12454 (AutomationsPillarand the flow previews), both this seat, regions disjoint fromInterfacesPillar. PR objectui#12470 (objectui#12452, the shell header nav) is accepted and waits to land; a different region. objectui#12453 (read-only posture) follows this card in theInterfacesPillarregion.objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 12455,
"status": "done",
"branch": "claude/issue-12455-interfaces-nav-tree",
"pr": null,
"session": "session_019rengbtahCnAYGa4ESiqLR",
"premise_still_valid": true,
"summary": "Interfaces 支柱已按卡片和三张画板落地。导航栏改为应用导航树:每项一行 32 px,带图标和大写类型标签;分组按运行时侧栏的规则展开或收起,遵守 expanded;空分组显示提示;子项缩进 12 px。"+" 列出 spec 声明的十种导航类型并附说明:页面、仪表盘、报表沿用现有创建流程,其余七种追加未绑定条目并打开导航项检查器。条目头部有类型图标和类型标签、26 px 的 Design/Run 分段控件、分隔线、带 aria-pressed 的属性开关;对象条目另有 Open in Data 和 Preview 标签页。导航项检查器新增 "Nav item · 类型" 抬头、Icon 选择器、只读的 Visible when 和 Remove nav item。fleet relay 对 dispatches 返回 403(本会话类型不允许 repository_dispatch),所以按席位说明走降级通道:分支已推送到 8ba34ac,PR 正文放在 pr_body_draft,由席位代开 PR 并代贴本报告。机制假设实测:1 成立(骨架已有 StudioItemHeader、canvas-mode-toggle、属性开关);2 部分成立(NavTree 原本只有对象条目有元数据图标,其余为本卡新增);3 成立;4 成立,但本卡没有改 PagePreview 和 DashboardPreview,区域设计器本就有虚线框和区域标签;5 成立,导出签名零变化;6 成立,StudioRail.tsx 未改。",
"tests": "head 8ba34ac(已合并 origin/main):studio-design 目录 182 个测试文件分三次跑,62/58/60 个文件、360/348/627 个测试全部通过。目录外的读者测试(apps/console/src/components、Studio 懒注册、AI build landing、studio-locale.i18n、select-placeholder-literal-11252、product-neutral-renderer.ratchet、i18n 设计器表脚本测试)50 个文件、758 个测试全部通过。新 pin StudioDesignSurface.interfacesNavTree-12455.test.tsx 共 12 个测试。消融一次(同一轮变异三处:View 标签、expanded、属性开关的 aria-pressed):恰好对应的 3 个测试转红,其余 9 个保持绿;随后用 git checkout HEAD 恢复,blob hash 与 HEAD 一致,git diff HEAD 为空。被更新的既有测试(11823 两个、11158、11196、11791、11862 两个、sharedSelect-11865,以及改按 test id 定位对象选择器的 6 个 nav 测试)在 fdde490 到 47490ff 之间都是先红后绿,红的原因就是本卡的行为变化。",
"gates": "本地子集,退出码都在管道之前捕获:pnpm --filter @object-ui/app-shell type-check exit 0;pnpm --filter @object-ui/app-shell build exit 0(dist completeness 1104 个文件);对改动文件跑 eslint exit 0,0 个 error,warning 数与 origin/main 同一批文件相同(14=14);pnpm check:i18n-keys 0;check:i18n-drift 0;check:i18n-designer-parity 0;check:new-line-citations 0;node scripts/check-changeset-presence.mjs 0;node scripts/check-changeset-no-major.mjs 0;控制字节自扫无命中。objectui 没有 dispatch-gates 派生,门禁清单按其 package.json 手工推导。scripts/check-nul-bytes.mjs 在 objectui 不存在(MODULE_NOT_FOUND),记 NOT MEASURED,不算失败读数。verify skill 未跑,因为 PagePreview.tsx 和 DashboardPreview.tsx 没有改动。PR check-runs 记 NOT MEASURED:PR 尚未开出,席位代开后由 CI 跑全量。",
"mcp_calls": "3 次,全部为读工具,零写工具:mcp__github__issue_read(get #12455)、mcp__github__issue_read(get_comments #12455)、mcp__github__issue_read(get #12446)。",
"api_writes": "0 次落地。1 次尝试被拒:node objectstack/scripts/pm/fleet-write/dispatch.mjs pr_create → POST /repos/objectstack-ai/objectstack/dispatches 返回 HTTP 403(repository_dispatch is not permitted for this session type;write-pace 判定为代理拒绝该路径,没有扣预算)。未重试,也没有改走 MCP 或 curl。os-dev-report 卡片评论走同一通道,所以未发,交席位代贴。git push 4 次(不属于 REST 写)。",
"deviations": [
"artboard shows an api chip; not rendered because surfaceIdentity pins objectui#7254(该 pin 未改动且全绿)",
"sharedSelect-11865 预期的 combobox 名称列表加了 'Icon'(检查器新增 Icon 选择器),这改变了一个 pin。另有 6 个 nav 测试改为按既有 test id nav-link-object 定位对象选择器,每个 expect 的含义不变",
"objectui#11862:导航行的机器名从第二行移到行的 tooltip,因为卡片要求 id 和目标留在 title 上、行高 32 px。navRailLabels-11862 和 navDraftLabels-11862 改为断言 title 和可访问描述",
"页面行也带了类型标签,页面行的可访问名称因此多了 'Page';11158、11196、11791 三个测试改用新名称查询",
""+" 菜单项按类型命名,不再是 'New dashboard';11823 的两个测试通过保留的 if-create-* test id 打开创建对话框",
"浏览模式下,检查器仍显示条目自身的属性(页面基础信息、仪表盘部件、对象列表视图检查器);导航项检查器只在导航编辑和 "+" 选择器中打开。原因:替换会丢掉已上线的编辑面,而且导航自动保存以导航编辑为前提(11189/11167/11153 的 pin)",
"仪表盘和报表没有 Source 标签页,也没有 more 按钮:Studio 里没有对应的源码编辑器,画板也没有给 more 定义动作",
"导航栏没有搜索框和计数:不在卡片目标范围内",
"页面、对象、仪表盘三种画布沿用现状,PagePreview.tsx 和 DashboardPreview.tsx 未改",
"截图里是只读包(objectstack dev 下 HotCRM 的应用包是只读的),"+" 选择器被隐藏;它的打开状态由新 pin 测试覆盖",
"objectstack 的 os-dev.md 与派发令在其余各处一致,没有冲突。唯一的差异是:派发令要求 pr_create 和卡片评论两笔写入,实测返回 403,因此按席位后续消息走降级通道(pr: null 加 pr_body_draft)"
],
"files_changed": [
".changeset/12455-interfaces-nav-tree.md",
"docs/design/studio-redesign/after/12455-interfaces-dashboard-dark.png",
"docs/design/studio-redesign/after/12455-interfaces-dashboard-light.png",
"docs/design/studio-redesign/after/12455-interfaces-object-dark.png",
"docs/design/studio-redesign/after/12455-interfaces-object-light.png",
"docs/design/studio-redesign/after/12455-interfaces-page-dark.png",
"docs/design/studio-redesign/after/12455-interfaces-page-light.png",
"packages/app-shell/src/views/metadata-admin/i18n.ts",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.interfacesCreate-11823.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.interfacesCreatePage-11823.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.interfacesNavTree-12455.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.interfacesRailLabelMap-11158.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navDraftLabels-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemInspector.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemInspectorLabel-11196.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemInspectorLabelMaps-11148.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemTypes-11790.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navPlaceholderSave-11776.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navRailLabels-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.railLabelInherits-11196.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.railSeparatorBadge-11791.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.sharedSelect-11865.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.standardNavEntries-11201.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx"
],
"line_budget": "n/a — no skills/** surface",
"open_questions": [
{
"question": "浏览模式下选中导航行时,检查器应显示条目自身的属性,还是导航项检查器?",
"options": [
"A 保持显示条目自身的属性(本 PR 的做法),导航项检查器在导航编辑和 "+" 中打开",
"B 按画板改为显示导航项检查器;这需要把导航自动保存从 editNav 门上解耦,并重写 11189/11167/11153 相关的 pin"
],
"recommendation": "A。实际业务需求轴:页面基础信息、仪表盘部件、对象列表视图都是在用的编辑面。项目长远合理性轴:B 需要另开一张卡来重构编辑与浏览模式。防 AI 犯错轴:A 不放宽自动保存的门。创业阶段轴:不扩散本卡范围"
},
{
"question": ""+" 中的 Page、Dashboard、Report 走现有创建对话框(新建并链接),而不是先加一个未绑定条目",
"options": [
"A 走创建对话框(本 PR 的做法,依据卡片原话 'today's create flow … continues from there')",
"B 先加未绑定条目,再在检查器里选已有目标"
],
"recommendation": "A:沿用已有 pin 的 11823 创建流程;要绑定已有目标,仍可在检查器里改类型后选择"
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · 观察:在 Studio 折叠宽布局下(foldInspector 且 xl 以上),origin/main 收起属性面板后,头部没有展开按钮(原条件为 !foldInspector && inspectorCollapsed)。本 PR 的属性开关改按 canCollapseInspector 显示,顺带消除了这个问题。只写进 PR Acceptance notes,不立卡"
],
"cleanup": "我启动的 HotCRM 后端(端口 4317)和 console(端口 5317)已按自己记下的 PID 和自选端口停止。worktree ../objectui-issue-12455 保留:PR 不是本会话开的,分支已全部推送,工作树干净。共享检出 /home/user/objectui 为了建 worktree 已 detach HEAD。",
"pr_body_draft": "(elided by the seat: opened verbatim as the body of PR #12544, read back identical)"
}
Relayed verbatim by seat
domain:ui#4(sessionsession_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final message, the degraded write channel: the session's relay dispatch was refused 403. The seat opened the draft PR #12544 frompr_body_draft, with assigneeos-sales, and wrote its title (the report carries none)."pr": nullabove is the session's own value at report time.Generated by Claude Code
feat(app-shell): Interfaces pillar — the rail is the app's navigation…