Repository navigation
Commit 7eb613c
feat(app-shell): author a nav entry's landing, badge, order and visible condition in the Studio inspector (#26977)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ895JboDnMZJBN12E3pQATJL)_
Fixes #26740
## 维护者速读
- 改了什么:Studio「界面」支柱的导航项检查器,现在能编辑导航项本就声明的键:对象项的落点(默认、命名视图 `viewName`、记录
`recordId` 加 `recordMode`、筛选 `filters`),以及
`badge`/`badgeVariant`、`order`、`visible`。没有新增任何键。
- 为什么改:这些键 spec 早已声明、运行时也会兑现,但 Studio 里只能看不能改(`visible`
只读,其余根本没有入口),作者只能去 Setup 或手改 JSON。
- 风险与回滚:只动 `StudioNavItemInspector` 一个组件,外加把 `FiltersEditor` 原样搬到新文件
`NavFiltersEditor.tsx`;i18n 只增 11 行 studio 键。回滚就是 revert 本 PR。
- 先看:`StudioDesignSurface.tsx` 里 `chooseLanding` 与 `onVisibleLint`
两个处理函数;前者保证 spec 互斥的落点键不会同时写入,后者保证有 CEL 错误的条件不会被写进草稿。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemInspectorKeys-26740.test.tsx`,19
条应全绿。
- 需要你做的:评审即可;无需决定。三条顺路观察写在 Acceptance notes,均未立卡。
## What changes
The Studio Interfaces pillar's nav-item inspector
(`StudioNavItemInspector`) now authors every key `NavigationItemSchema`
declares on the entry's member that the ruling names, and nothing the
member does not declare:
- **Landing of an `object` entry**, as one choice: the object's default,
a named view (`viewName`, picked from the package's views of that object
through `usePackageNavTargets`), a record (`recordId` plus
`recordMode`), or a filtered slice (`filters`, through the same rows
editor Setup's `AppNavInspector` mounts). Choosing a landing removes the
other landings' keys, because `objectNavTargetExclusivity` refuses
`filters` beside `viewName`/`recordId`; choosing a record also removes
`runAction`, which the spec refuses beside `recordId`. The landing is
read off the keys the entry holds (`deriveObjectTargetMode`, the
runtime's precedence).
- **`badge` and `badgeVariant`**: a text field and a picker over the
four variants the spec declares. The variant table is keyed by the
spec-derived type, so a variant the spec adds or drops stops the file
compiling.
- **`order`**: a number field, written as a number; an emptied field
removes the key.
- **`visible`**: now edited in `CelPredicateField`, the control the Data
pillar and the page-block inspector already use for predicates, with the
roots the console binds for a nav entry (`current_user`, plus `data`
only on an entry that declares `dataSource`). Text reaches the entry
only while its lint finds no error, so the nav autosave can never send
an unparseable condition; until then the entry keeps its previous
condition and the field says "Not saved yet". An envelope keeps its
envelope (only its `source` is edited). An envelope with no CEL `source`
is still shown read-only, as before.
- Every emptied field removes its key; nothing writes `''`.
Supporting changes:
- `FiltersEditor` is moved out of `AppNavInspector.tsx` into
`metadata-admin/inspectors/NavFiltersEditor.tsx` as a pure move (the
only change is `export`), so both inspectors mount the same editor.
- 11 new `engine.inspector.appNav.*` rows in the `studio` namespace
(`en`, `zh`). No row in `metadata-admin/i18n.ts` is added or changed.
- Changeset: `@object-ui/i18n` patch.
Clause-②: no
Metadata-protocol: none
## Why
The spec has declared these keys all along and the running menu honours
them, but the Studio inspector offered no way to set them: `visible` was
shown read-only and the rest had no field. Studio builders had to leave
for Setup or hand-edit JSON.
## Tests
New file `StudioDesignSurface.navItemInspectorKeys-26740.test.tsx`, 19
tests:
- Each declared key is authored, written in the spec's spelling, and the
resulting entry parses: named view (and the running menu's link goes to
that view), record, filters, badge and variant, order (a number),
visible.
- A key the member does not declare is not offered: a `page` entry has
no landing; a `separator` offers `order` only; an `object` entry with no
object has no landing; each landing shows only its own fields.
- A landing change removes the keys the spec refuses beside it (record
to filters, filters to record including `runAction`, back to default).
- `visible` round-trips: shown and left as authored; an envelope keeps
its envelope; a condition with a lint error is not written and the hint
shows, then the fix is written; emptying removes the key; a non-CEL
envelope is read-only.
- `order` moves an entry in the running menu (`NavigationRenderer`).
Four existing tests change. Three now name the Label textbox they query,
because the inspector gained a second textbox (Badge):
`navItemInspectorLabel-11196`, `navItemInspectorLabelMaps-11148`,
`navItemTypes-11790`. `interfacesNavTree-12455` now asserts the
`visible` value in the editable field, and its control case uses a
separator.
Ablations, one per control, each through `scripts/ablation-replace.mjs`
(anchor hit once, blob changed, then restored with blob equal to HEAD).
Every one turned the suite red:
| Control | Mutation | Red |
|---|---|---|
| landing | picker does nothing | 7 |
| landing clears other keys | key removal loop dropped | 3 |
| view | picker does nothing | 1 |
| record id | field does nothing | 2 |
| record mode | picker does nothing | 1 |
| filters | editor commit does nothing | 1 |
| badge | field does nothing | 1 |
| badge variant | picker does nothing | 1 |
| order | field does nothing | 2 |
| order as a number | writes the string | 2 |
| visible | lint-clean text not written | 4 |
| visible lint gate | erroring text written too | 1 |
| badge offered only where declared | shown on every member | 1 |
## Acceptance notes
Observations from reading the code; none reproduced through a public
door, none filed:
- The Studio rail and canvas list entries in array order and do not sort
by `order`, while the running menu does (`byNavOrder`). Once entries
carry `order`, a drag reorder in the rail can be overridden at runtime.
- Setup's `AppNavInspector` derives its target mode from the keys
present, so choosing "record" or "view" there is not held until a value
is entered.
- Setup's `clearedTargetPatch` does not remove `runAction` when the
target becomes a record.
Design note: the dispatch asks that `visible` use Studio's predicate
control and validation. The Studio's other blocking predicates block the
host autosave through `onBlockingIssuesChange`; wiring that here would
edit the host outside this card's file surface. Instead the inspector
writes the condition only when its lint is clean, which gives the same
guarantee (no erroring predicate is ever saved) and says so on the
field.
Not added, because the ruling does not list them: `requiredPermissions`,
`requiresObject`, `requiresService`, `dataSource`.
## Verification
On head `13df6681` (main merged in; the merge touched none of this PR's
files):
- New tests: `StudioDesignSurface.navItemInspectorKeys-26740.test.tsx`
19/19 pass.
- Neighbouring Studio nav and `AppNavInspector` tests: 15 files, 124
tests pass. Before the merge: every `metadata-admin/inspectors/` test
plus the deep-link and nav-surface tests, 198 files, 2650 pass, 1
skipped.
- `@object-ui/app-shell` and `@object-ui/i18n` type-check exit 0;
`@object-ui/i18n` tests 89 files, 1373 pass, 13 skipped.
- ESLint on every touched file: 0 errors.
- `dispatch-gates --commands` derived 34 gate families; all 34 ran and
exit 0, and `dispatch-gates --ran` reconciles 34 derived, 34 run, 0 not
measured. That includes `node scripts/check-sdui-manifest.mjs` and `pnpm
check:nul-bytes`.
- One gate, `pnpm --dir ui exec vitest run scripts/`, first went red (2
tests in `check-readme-exports.test.ts`) because the local
`plugin-detail` dist predated the merge that added `RecordPageColumns`.
After rebuilding `@object-ui/plugin-detail` it ran 178 files, 5065 pass,
exit 0. This PR does not touch that package.
- 13 ablations, one per control, all red, each restored with blob equal
to HEAD (table under Tests).
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(`packages/spec` not touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; ESLint on every touched file reports 0
errors.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: not applicable.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English (the maintainer summary
above is the requested Chinese digest).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxbXKcuJdVEkbLwwWgKt)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9fab076 commit 7eb613c
13 files changed
Lines changed: 804 additions & 126 deletions
File tree
- .changeset
- ui/packages
- app-shell/src/views
- metadata-admin/inspectors
- studio-design
- i18n/src/namespaces/studio
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
45 | 44 | | |
46 | 45 | | |
47 | 46 | | |
48 | 47 | | |
49 | | - | |
50 | 48 | | |
51 | 49 | | |
52 | 50 | | |
| |||
66 | 64 | | |
67 | 65 | | |
68 | 66 | | |
| 67 | + | |
69 | 68 | | |
70 | 69 | | |
71 | 70 | | |
| |||
221 | 220 | | |
222 | 221 | | |
223 | 222 | | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
272 | | - | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | | - | |
279 | | - | |
280 | | - | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
285 | | - | |
286 | | - | |
287 | | - | |
288 | | - | |
289 | | - | |
290 | | - | |
291 | | - | |
292 | | - | |
293 | | - | |
294 | | - | |
295 | | - | |
296 | | - | |
297 | | - | |
298 | | - | |
299 | | - | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
312 | | - | |
313 | 223 | | |
314 | 224 | | |
315 | 225 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
287 | 287 | | |
288 | 288 | | |
289 | 289 | | |
290 | | - | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
291 | 293 | | |
292 | 294 | | |
293 | 295 | | |
| |||
298 | 300 | | |
299 | 301 | | |
300 | 302 | | |
301 | | - | |
302 | | - | |
303 | | - | |
| 303 | + | |
| 304 | + | |
304 | 305 | | |
305 | 306 | | |
306 | | - | |
307 | | - | |
| 307 | + | |
308 | 308 | | |
309 | 309 | | |
310 | 310 | | |
311 | | - | |
| 311 | + | |
312 | 312 | | |
313 | 313 | | |
314 | 314 | | |
| |||
0 commit comments