Skip to content

Console renders nav:menu / global:search / global:notifications / app:launcher as "Component Placeholder" — four spec-declared PageComponentType members with no renderer #12183

Description

@huangyiirene

Four page-component types that @objectstack/spec declares as first-class, no-props members of PageComponentType have no renderer in the console: each one draws the literal scaffold text Component Placeholder with its own type name above it, on the page where an author placed it.

Measured in a real browser against a running app — not read off source. Downstream tracking card: objectstack-ai/hotcrm#734 (half 1).

Environment

  • @objectstack/*17.1.0 (every package in the app pinned to it; nothing bumped for the measurement)
  • App: HotCRM at objectstack-ai/hotcrm@f685136, served by objectstack dev -p 4001, seed data loaded on first boot
  • Browser: Chromium 1194 via Playwright, admin-authenticated as the seeded dev admin (admin@objectos.ai), viewport 1600×1200
  • Node 22.22.2, pnpm 10.33.0

Reproduction

Sign in to the console as an admin and open, in the published app:

/_console/apps/app.objectstack.hotcrm/page/sales_home_page
/_console/apps/app.objectstack.hotcrm/page/app_launcher_page
/_console/apps/app.objectstack.hotcrm/page/utility_bar_page

What renders

All five component instances across the three pages draw the placeholder. Each is a dashed-outline box containing a document-with-question-mark glyph, the component type in monospace, and the caption Component Placeholder:

PageComponentRenders
sales_home_pagenav:menu (inside the Quick Create card)nav:menu / Component Placeholder
app_launcher_pageglobal:searchglobal:search / Component Placeholder
app_launcher_pageapp:launcherapp:launcher / Component Placeholder
utility_bar_pageglobal:notificationsglobal:notifications / Component Placeholder
utility_bar_pageglobal:searchglobal:search / Component Placeholder

Occurrences of the literal string Component Placeholder in document.body.innerText: 1 on sales_home_page, 2 on app_launcher_page, 2 on utility_bar_page.

Verbatim innerText from the app_launcher_page main region:

Central hub for accessing all applications
global:search
Component Placeholder
App Launcher
Select an app to get started
app:launcher
Component Placeholder

and from utility_bar_page:

Utility Bar
Quick access utility bar with floating tools
global:notifications
Component Placeholder
Quick Notes
global:search
Component Placeholder

This is not a page-framework failure — the same pages render everything else correctly. On sales_home_page the four object-metric KPI cards pull real figures (Revenue (Won) 1,290,000.00 / Deals Won 8 / Pipeline Value 3,775,000.00 / Open Leads 21), the embedded list views return 21 / 10 / 6 real rows, and page:header draws. Only these four component types fall through to the placeholder.

Why this is a platform gap and not app metadata using a wrong spelling

All four are named members of the PageComponentType enum shipped in @objectstack/spec@17.1.0, and each has a deliberate no-props row in ComponentPropsMap:

dist/ui/index.d.ts:

readonly'app:launcher': z.ZodObject<{},z.core.$strict>;readonly'nav:menu': z.ZodObject<{},z.core.$strict>;readonly'global:search': z.ZodObject<{},z.core.$strict>;readonly'global:notifications': z.ZodObject<{},z.core.$strict>;

dist/ui/index.js:

"app:launcher": emptyProps("app:launcher"),"nav:menu": emptyProps("nav:menu"),"global:search": emptyProps("global:search"),"global:notifications": emptyProps("global:notifications"),

where emptyProps builds a strict, intentionally empty props object whose own history string is explicit that the emptiness is the point:

varemptyProps=(type)=>strictObject({surface: `this \`${type}\` component`,history: `\`${type}\` declares no props at all. ${PROPS_HISTORY}`,guidanceSets: COMPONENT_LEVEL_GUIDANCE},{});

So the app is using the spec's sanctioned spelling, with the exact props shape the spec prescribes (properties: {}), and objectstack validate passes clean on all three pages. The metadata is right; the renderer is missing.

Impact

An end user who reaches any of these pages sees developer scaffolding. app_launcher_page and utility_bar_page are, between them, entirely placeholder plus one empty card — there is no non-scaffold content on either page. Any app that composes a launcher, a global search box, a notifications panel or a nav menu from the spec's own vocabulary gets the same result.

Ask

Either implement renderers for the four types, or — if they are not intended to be author-placeable on a page — make that explicit in the spec and in validate so the failure lands at author time rather than in front of a user. Shipping them as first-class enum members with prescribed props and no renderer is the state that produces this report.

Notes for whoever picks this up

  • Screenshots of all five placeholder instances were captured during the measurement and are archived on the downstream card, [17.0-rc2验收] sales_home_page / app_launcher_page / utility_bar_page 多个组件渲染为「Component Placeholder」,首页欢迎语用户名插值为空 hotcrm#734.
  • ⚠️ The downstream app metadata is deliberately being left untouched: these three pages are currently the only reproduction of this gap, so "fixing" them app-side would delete the evidence rather than the defect.
  • Adjacent but separate, and not part of this report: page:card components declaring a title and no body render as titled empty boxes (Quick Notes on utility_bar_page, Recent Items / Today's Schedule on sales_home_page). That is a container with nothing to draw, not a missing renderer.
  • Small spec-accuracy note while looking: PageComponentSchema.type is a z.ZodUnion<[z.ZodEnum<{…}>, z.ZodString]>, so despite being an enumerated vocabulary it accepts arbitrary strings at parse time. That is why an unimplemented type reaches the renderer as a plain string and lands on the placeholder branch rather than being rejected. It does not weaken anything above — the four names are declared members with declared props — but it is likely relevant to any fix that wants author-time rejection.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions