Skip to content

Commit baf0eb1

Browse files
os-zhuangclaude
andauthored
docs(ui): apps 页停止教 17.0.0 已退役的 version / mobileNavigation,两个 os:check 块改用 defineApp() (#5313) (#5466)
`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。 Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1ce2030 commit baf0eb1

2 files changed

Lines changed: 68 additions & 20 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
---
3+
4+
docs(ui): `ui/apps` 停止教 17.0.0 已退役的 `App.version``App.mobileNavigation`,两个 `os:check` 示例改用 `defineApp()` 以便退役键在 tsc 就红 (#5313)
5+
6+
`content/docs/ui/apps.mdx` 有四处仍把 17.0.0(2026-06 liveness audit / ADR-0049
7+
enforce-or-remove)已退役的键当作可作者化面在教:「Basic Structure」示例里的
8+
`version: '1.0.0'`、App Properties 表里的 `version` 行、整节 `## Mobile Navigation`
9+
(含 `mobileNavigation: { mode, bottomNavItems }` 示例与 `mode` 取值说明),以及
10+
「Complete Example」里的 `version: '2.0.0'`
11+
12+
墓碑是 `retiredKey()`(`z.never().optional()`),所以照抄这两个示例不是「多写一个没用
13+
的键」,而是**整条 save 硬失败**。实测把「Basic Structure」块原样喂给
14+
`getMetadataTypeSchema('app')`:
15+
16+
version :: `App.version` was removed in @objectstack/spec 17.0.0 (2026-06 liveness
17+
audit — no consumer in framework or objectui). An app is versioned by its owning
18+
package: use `manifest.version`. Delete the key.
19+
20+
处置按墓碑自己的处方:`version` 删键(应用的版本是其所属包的 `manifest.version`);
21+
`mobileNavigation` 没有替代能力——它是完全未实现的键,连 `packages/mobile` 都没读过,
22+
`mode` 选择器不改变任何东西——故整节删除,并在 App Properties 表后新增 Callout 点名这
23+
两个键、给出各自处方,顺带指回已在正文交代过的 `homePageId`(#4667 / #4709)。
24+
25+
同时给该页两个 `{/* os:check */}` 块加上 `defineApp()` 标注。此前两块都是无类型标注的
26+
对象字面量(`const crmApp = { … }`),没有任何东西把它们和 `AppSchema` 关联起来,
27+
`retiredKey()` 赖以在编译期开火的 `never` 入参类型永远不参与推断——`check:skill-examples`
28+
只做 tsc,于是对退役键这一类恒绿。加标注后同一个门在旧示例上会红:
29+
30+
✗ Prose TypeScript examples do not compile against @objectstack/spec:
31+
content/docs/ui/apps.mdx:19:3 error TS2322: Type 'string' is not assignable to type 'undefined'.
32+
content/docs/ui/apps.mdx:239:3 error TS2322: Type 'string' is not assignable to type 'undefined'.
33+
34+
改后 `✅ 204 prose examples type-check against @objectstack/spec`,两个块喂 schema 也都
35+
`parses: true`。这条标注是本次修复的护栏:此后该页示例里任何退役键都在门里当场红,而不是
36+
等作者照抄后在 save 时才发现。
37+
38+
门本体(`packages/spec/scripts/check-skill-examples.ts`)不动——issue 里的 B 方案(对能
39+
推断出 schema 的块追加一次 `safeParse`)覆盖更广,但需要先解决「哪个块对应哪个 schema」
40+
的归属推断,是独立的一次设计。不碰 `packages/spec/**``content/docs/references/**`
41+
`content/docs/releases/`。Docs-only。

content/docs/ui/apps.mdx

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ An **App** is a logical container that bundles objects, views, pages, and dashbo
1111

1212
{/* os:check */}
1313
```typescript
14-
const crmApp = {
14+
import { defineApp } from '@objectstack/spec';
15+
16+
const crmApp = defineApp({
1517
name: 'crm',
1618
label: 'CRM',
17-
version: '1.0.0',
1819
description: 'Customer Relationship Management',
1920
icon: 'briefcase',
2021
active: true,
@@ -33,7 +34,7 @@ const crmApp = {
3334
],
3435

3536
requiredPermissions: ['crm_access'],
36-
};
37+
});
3738
```
3839

3940
## App Properties
@@ -42,7 +43,6 @@ const crmApp = {
4243
| :--- | :--- | :--- | :--- |
4344
| `name` | `string` || Machine name (`snake_case`) |
4445
| `label` | `string` || Display name |
45-
| `version` | `string` | optional | App version |
4646
| `description` | `string` | optional | App description |
4747
| `icon` | `string` | optional | App icon (Lucide) |
4848
| `active` | `boolean` | optional | Is app active (default: `true`) |
@@ -51,6 +51,25 @@ const crmApp = {
5151
| `branding` | `AppBranding` | optional | Visual customization |
5252
| `requiredPermissions` | `string[]` | optional | Required permissions to access |
5353

54+
<Callout type="warn">
55+
**Older app samples no longer parse** — check yours before copying it forward.
56+
`@objectstack/spec` 17.0.0 (2026-06 liveness audit, ADR-0049 enforce-or-remove)
57+
removed `version` and `mobileNavigation`, and both are now refused at parse
58+
time rather than ignored, so one leftover key fails the whole save.
59+
60+
- `version` — an app is versioned by its owning package. Use
61+
`manifest.version` and delete the key; nothing in framework or objectui ever
62+
read the per-app number, which could silently disagree with the package's.
63+
- `mobileNavigation` — fully unimplemented: no renderer, `packages/mobile`
64+
included, ever read it, so the `mode` picker changed nothing. Delete the
65+
key; the block returns if and when a real mobile navigation ships.
66+
67+
`homePageId` (removed in the same major, #4667/#4709) is covered under
68+
[Common Navigation Properties](#common-navigation-properties). Every rejection
69+
carries its own replacement instruction, so paste the old app and read what
70+
the error tells you.
71+
</Callout>
72+
5473
## Navigation Items
5574

5675
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: {
212231
| `logo` | `string` | Logo image URL |
213232
| `favicon` | `string` | Favicon URL |
214233

215-
## Mobile Navigation
216-
217-
Configure mobile-specific navigation behavior:
218-
219-
```typescript
220-
mobileNavigation: {
221-
mode: 'bottom_nav',
222-
bottomNavItems: ['nav_home', 'nav_accounts', 'nav_contacts', 'nav_settings'],
223-
}
224-
```
225-
226-
`mode` accepts `'drawer'` (default), `'bottom_nav'`, or `'hamburger'`. `bottomNavItems` lists the navigation item `id`s to surface in the bottom bar (max 5).
227-
228234
## Complete Example
229235

230236
{/* os:check */}
231237
```typescript
232-
const projectApp = {
238+
import { defineApp } from '@objectstack/spec';
239+
240+
const projectApp = defineApp({
233241
name: 'project_management',
234242
label: 'Project Management',
235-
version: '2.0.0',
236243
description: 'Track projects, tasks, and team workload',
237244
icon: 'folder-kanban',
238245
active: true,
@@ -287,7 +294,7 @@ const projectApp = {
287294
// and the ROOT landing follows `isDefault`. The key was removed in 17.0.0
288295
// (#4667, #4709) — it did have a consumer, but it pointed at a navigation item
289296
// by id and fell back silently when that id dangled.
290-
};
297+
});
291298
```
292299

293300
## Related

0 commit comments

Comments
 (0)