From 732018f412007d96c6e54928a5c72b518921564b Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 13:10:11 +0000 Subject: [PATCH] =?UTF-8?q?docs(ui):=20apps=20=E9=A1=B5=E5=81=9C=E6=AD=A2?= =?UTF-8?q?=E6=95=99=2017.0.0=20=E5=B7=B2=E9=80=80=E5=BD=B9=E7=9A=84=20`ve?= =?UTF-8?q?rsion`=20/=20`mobileNavigation`,=E4=B8=A4=E4=B8=AA=20os:check?= =?UTF-8?q?=20=E5=9D=97=E6=94=B9=E7=94=A8=20`defineApp()`=20(#5313)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `content/docs/ui/apps.mdx` 有四处仍把 17.0.0(2026-06 liveness audit / ADR-0049)已退役的键当作可作者化面在教:「Basic Structure」示例的 `version: '1.0.0'`、App Properties 表的 `version` 行、整节 `## Mobile Navigation`(含 `mobileNavigation: { mode, bottomNavItems }` 示例与 `mode` 取值说明),以及「Complete Example」的 `version: '2.0.0'`。 墓碑是 `retiredKey()`(`z.never().optional()`),照抄不是「多写个没用的 键」,是整条 save 硬失败。把「Basic Structure」块原样喂 `getMetadataTypeSchema('app')` 实测 `parses: false`,报 「`App.version` was removed in @objectstack/spec 17.0.0 … Delete the key.」 处置按墓碑自己的处方:`version` 删键(应用版本 = 所属包的 `manifest.version`);`mobileNavigation` 无替代能力(完全未实现,连 packages/mobile 都没读过),整节删除。App Properties 表后新增 Callout 点名这两个键并给出处方,指回正文已交代的 `homePageId`(#4667/#4709)。 同时给两个 `{/* os:check */}` 块加 `defineApp()` 标注。此前两块都是无 类型标注的对象字面量,没有任何东西把它们和 `AppSchema` 关联起来, `retiredKey()` 赖以在编译期开火的 `never` 入参永远不参与推断—— `check:skill-examples` 只做 tsc,于是对退役键这一类恒绿。加标注后同一个 门在旧示例上会红(apps.mdx:19:3 / :239:3,TS2322 Type 'string' is not assignable to type 'undefined'),改后绿(204 prose examples type-check)。 门本体不动:issue 的 B 方案(块级 safeParse)需先解决块→schema 归属推断, 是独立的一次设计。不碰 packages/spec/**、content/docs/references/** 与 content/docs/releases/。Docs-only。 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE --- ...s-mdx-retired-version-mobile-navigation.md | 41 ++++++++++++++++ content/docs/ui/apps.mdx | 47 +++++++++++-------- 2 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 .changeset/apps-mdx-retired-version-mobile-navigation.md diff --git a/.changeset/apps-mdx-retired-version-mobile-navigation.md b/.changeset/apps-mdx-retired-version-mobile-navigation.md new file mode 100644 index 0000000000..e2caf9eb4b --- /dev/null +++ b/.changeset/apps-mdx-retired-version-mobile-navigation.md @@ -0,0 +1,41 @@ +--- +--- + +docs(ui): `ui/apps` 停止教 17.0.0 已退役的 `App.version` 与 `App.mobileNavigation`,两个 `os:check` 示例改用 `defineApp()` 以便退役键在 tsc 就红 (#5313) + +`content/docs/ui/apps.mdx` 有四处仍把 17.0.0(2026-06 liveness audit / ADR-0049 +enforce-or-remove)已退役的键当作可作者化面在教:「Basic Structure」示例里的 +`version: '1.0.0'`、App Properties 表里的 `version` 行、整节 `## Mobile Navigation` +(含 `mobileNavigation: { mode, bottomNavItems }` 示例与 `mode` 取值说明),以及 +「Complete Example」里的 `version: '2.0.0'`。 + +墓碑是 `retiredKey()`(`z.never().optional()`),所以照抄这两个示例不是「多写一个没用 +的键」,而是**整条 save 硬失败**。实测把「Basic Structure」块原样喂给 +`getMetadataTypeSchema('app')`: + + version :: `App.version` was removed in @objectstack/spec 17.0.0 (2026-06 liveness + audit — no consumer in framework or objectui). An app is versioned by its owning + package: use `manifest.version`. Delete the key. + +处置按墓碑自己的处方:`version` 删键(应用的版本是其所属包的 `manifest.version`); +`mobileNavigation` 没有替代能力——它是完全未实现的键,连 `packages/mobile` 都没读过, +`mode` 选择器不改变任何东西——故整节删除,并在 App Properties 表后新增 Callout 点名这 +两个键、给出各自处方,顺带指回已在正文交代过的 `homePageId`(#4667 / #4709)。 + +同时给该页两个 `{/* os:check */}` 块加上 `defineApp()` 标注。此前两块都是无类型标注的 +对象字面量(`const crmApp = { … }`),没有任何东西把它们和 `AppSchema` 关联起来, +`retiredKey()` 赖以在编译期开火的 `never` 入参类型永远不参与推断——`check:skill-examples` +只做 tsc,于是对退役键这一类恒绿。加标注后同一个门在旧示例上会红: + + ✗ Prose TypeScript examples do not compile against @objectstack/spec: + content/docs/ui/apps.mdx:19:3 error TS2322: Type 'string' is not assignable to type 'undefined'. + content/docs/ui/apps.mdx:239:3 error TS2322: Type 'string' is not assignable to type 'undefined'. + +改后 `✅ 204 prose examples type-check against @objectstack/spec`,两个块喂 schema 也都 +`parses: true`。这条标注是本次修复的护栏:此后该页示例里任何退役键都在门里当场红,而不是 +等作者照抄后在 save 时才发现。 + +门本体(`packages/spec/scripts/check-skill-examples.ts`)不动——issue 里的 B 方案(对能 +推断出 schema 的块追加一次 `safeParse`)覆盖更广,但需要先解决「哪个块对应哪个 schema」 +的归属推断,是独立的一次设计。不碰 `packages/spec/**`、`content/docs/references/**` +与 `content/docs/releases/`。Docs-only。 diff --git a/content/docs/ui/apps.mdx b/content/docs/ui/apps.mdx index 4667e9049f..56c7ac0bad 100644 --- a/content/docs/ui/apps.mdx +++ b/content/docs/ui/apps.mdx @@ -11,10 +11,11 @@ An **App** is a logical container that bundles objects, views, pages, and dashbo {/* os:check */} ```typescript -const crmApp = { +import { defineApp } from '@objectstack/spec'; + +const crmApp = defineApp({ name: 'crm', label: 'CRM', - version: '1.0.0', description: 'Customer Relationship Management', icon: 'briefcase', active: true, @@ -33,7 +34,7 @@ const crmApp = { ], requiredPermissions: ['crm_access'], -}; +}); ``` ## App Properties @@ -42,7 +43,6 @@ const crmApp = { | :--- | :--- | :--- | :--- | | `name` | `string` | ✅ | Machine name (`snake_case`) | | `label` | `string` | ✅ | Display name | -| `version` | `string` | optional | App version | | `description` | `string` | optional | App description | | `icon` | `string` | optional | App icon (Lucide) | | `active` | `boolean` | optional | Is app active (default: `true`) | @@ -51,6 +51,25 @@ const crmApp = { | `branding` | `AppBranding` | optional | Visual customization | | `requiredPermissions` | `string[]` | optional | Required permissions to access | + + **Older app samples no longer parse** — check yours before copying it forward. + `@objectstack/spec` 17.0.0 (2026-06 liveness audit, ADR-0049 enforce-or-remove) + removed `version` and `mobileNavigation`, and both are now refused at parse + time rather than ignored, so one leftover key fails the whole save. + + - `version` — an app is versioned by its owning package. Use + `manifest.version` and delete the key; nothing in framework or objectui ever + read the per-app number, which could silently disagree with the package's. + - `mobileNavigation` — fully unimplemented: no renderer, `packages/mobile` + included, ever read it, so the `mode` picker changed nothing. Delete the + key; the block returns if and when a real mobile navigation ships. + + `homePageId` (removed in the same major, #4667/#4709) is covered under + [Common Navigation Properties](#common-navigation-properties). Every rejection + carries its own replacement instruction, so paste the old app and read what + the error tells you. + + ## Navigation Items The navigation tree supports nine item types, combined to create rich menu structures: `object`, `dashboard`, `page`, `url`, `report`, `action`, `component`, `group` and `separator`. Each is documented below. @@ -212,27 +231,15 @@ branding: { | `logo` | `string` | Logo image URL | | `favicon` | `string` | Favicon URL | -## Mobile Navigation - -Configure mobile-specific navigation behavior: - -```typescript -mobileNavigation: { - mode: 'bottom_nav', - bottomNavItems: ['nav_home', 'nav_accounts', 'nav_contacts', 'nav_settings'], -} -``` - -`mode` accepts `'drawer'` (default), `'bottom_nav'`, or `'hamburger'`. `bottomNavItems` lists the navigation item `id`s to surface in the bottom bar (max 5). - ## Complete Example {/* os:check */} ```typescript -const projectApp = { +import { defineApp } from '@objectstack/spec'; + +const projectApp = defineApp({ name: 'project_management', label: 'Project Management', - version: '2.0.0', description: 'Track projects, tasks, and team workload', icon: 'folder-kanban', active: true, @@ -287,7 +294,7 @@ const projectApp = { // and the ROOT landing follows `isDefault`. The key was removed in 17.0.0 // (#4667, #4709) — it did have a consumer, but it pointed at a navigation item // by id and fell back silently when that id dangled. -}; +}); ``` ## Related