Repository navigation
Commit e9e31e9
refactor(studio)!: one word per item state on the All metadata tiles, headers and marks (#29784)
domain:ui#5 · zhuangjianguo · session_01QsR2jQjvWkZ7is6GXbC6DB
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9Ubb1HqvWsgjFfhijKzb1h4T7b)_
Fixes #29705
Clause-②: no (narrowing)
Metadata-protocol: none
Skills-docs: none — the four retired keys are rows of the Studio
designer's own string table; no `skills/**`, `ui/skills/**` or docs page
names them (grep at `601832b1` finds them only in package CHANGELOGs)
## 维护者速读
-
**改了什么**:Studio「全部元数据」的类型卡片、列表和条目标题上的状态徽标、以及侧栏标记,现在统一用各板块已有的那组词:只读、可写、可定制、可新增、已定制、新增。只读软件包(代码包或已安装的包)里可以定制的类型显示「可定制」,不再显示「可写」;其它类型显示「只读」。页面顶部的说明改为告诉你在这里能做什么,不再数「协议暴露了多少类型」,筛选按钮改为「隐藏只读」。「权限」板块的共享设置去掉了中英重复(如
`Private 私有` 改为 `私有`),矩阵的 `OWD` 列名改为「记录共享模型」。
- **为什么改**:以前同一个状态在卡片、徽标和板块里各说各的,只读包里明明不能直接改的类型却写着「可写」,用户会以为可以原地编辑。
- **风险与回滚**:只改文案和徽标对应关系,没有新状态、没有新的元数据键或选项,保存、定制、发布的行为都不变。Studio 字符串表退役了
4 个键(下表),工作区内已无读取者。回滚即 revert 本 PR。
- **先看**:`ui/packages/app-shell/src/views/metadata-admin/PageShell.tsx`
的 `typeStateWord` 与
`TYPE_STATE_WORD_KEY`(卡片、列表标题和条目标题共用这一处);`DirectoryPage.stateVocabulary-29705.test.tsx`。
- **两分钟验证**:中文界面打开 Studio → ObjectStack Showcase →
全部元数据:仪表板、报表、视图、邮件模板显示「可定制」,其余显示「只读」,没有「可写」或「仅可新建」;打开「视图」列表,标题徽标同样是「可定制」。
- **需要你做的**:无,席位落地。
## What changes
- **One word per state, one key per word.** The All metadata tiles, the
list and item headers (`WritabilityBadge`), the rail marks and the
landing draw the words the pillars already use. The mapping is one
function, `typeStateWord` in `PageShell.tsx`, and one key table,
`TYPE_STATE_WORD_KEY`. The tile and the header both call them, so they
cannot disagree.
- **A tile answers "what can I do here" for the open package.**
- On a read-only package, a type that takes a customization (an
`allowEnvironmentOverlay` type, outside the `OS_METADATA_WRITABLE`
hatch, and overridable in the spec's classification) reads **Can be
customized**. Every other type there reads **Read-only**.
- On a writable package, `~all` and Setup, an overlay type reads
**Writable** and a create-only type reads **Can be added**. A type with
neither flag reads **Read-only**.
- **The lead sentence says what a person can do.**
`engine.directory.description` no longer counts protocol types or says
"runtime override". The "Writable only" filter becomes "Hide read-only"
and counts the types whose word is not Read-only.
- **The flow status keeps en "Off".** zh already reads 已停用, the same
word as the landing's count. Moving en to "Switched off" is left to
#29729, because the en-drift gate needs a waiver for an en-only change,
and its waiver ledger accepts only `objectui#` issue numbers.
- **Access: zh values only.** The sharing settings drop their English
doublets (`Private 私有` → `私有`, `Public read 公共只读` → `公共只读`, `Public
read/write 公共读写` → `公共读写`, `Controlled by parent 受父级控制` → `受父级控制`). The
matrix's bare `OWD` column reads 记录共享模型, and the explain row reads
记录共享基线(OWD). English is unchanged.
### The vocabulary
| State | Key | en | zh |
|:---|:---|:---|:---|
| read-only | `engine.studio.pkg.readonly` | Read-only | 只读 |
| writable | `engine.studio.pkg.writable` | Writable | 可写 |
| can be customized | `engine.studio.customize.available` (new) | Can be
customized | 可定制 |
| can be added | `engine.studio.customize.addable` (new) | Can be added
| 可新增 |
| customized | `engine.customizationMark.customized` | Customized | 已定制
|
| added | `engine.customizationMark.added` | Added | 新增 |
| switched off | `engine.studio.auto.off` | Off (Switched off in #29729)
| 已停用 |
Retired keys (zero `t()` readers after this change, per the
`i18n-key-retirement` recipe):
| Removed key | Replacement |
|:---|:---|
| `engine.badge.readOnly` | `engine.studio.pkg.readonly` |
| `engine.badge.writable` | `engine.studio.pkg.writable` on a writable
package, `engine.studio.customize.available` on a read-only one |
| `engine.badge.createOnly` | `engine.studio.customize.addable` |
| `engine.directory.writableOnly` | `engine.directory.hideReadOnly`
(new) |
## Tests
- `DirectoryPage.stateVocabulary-29705.test.tsx` (new, 29 tests) runs
the real `MetadataDirectoryPage` and `ResourceListPage` under
`MetadataAreaHostContext`, in zh with the studio catalogue loaded.
- A read-only package: the overlay tiles read 可定制, the create-only and
closed tiles read 只读, and no tile reads 可写 or 仅可新建. CONTROL: the same
registry on a writable package reads 可写 / 可新增 / 只读, and a hatched
(`overrideSource: 'env'`) type reads 可写.
- The filter reads 隐藏只读 (3) on the read-only package and (5) on the
writable one. The lead sentence has no digits and no 协议 or 运行时覆盖.
- The list header draws the tile's word: the view list reads 可定制 and the
page list 只读 on a read-only package.
- The census: each state's single key with its en and zh, the keys that
must say the same word, the retired keys and spellings absent from both
packs, and `typeStateWord` over every context (permission reads
Read-only everywhere, because it is not overridable).
- Access in zh: the sharing values carry no Latin script, `colOwd` reads
记录共享模型, and en is unchanged.
### Moved pins
These tests pinned the old words or found the header badge by its text.
Each now pins the new word, or finds the badge by `data-state-word` or
the package chip by its title. The seat approved the last three files,
which were outside the first surface.
- `DirectoryPage.environmentOverlay-12141.test.tsx`: 'Writable' /
'Read-only' / 'Hide read-only (6|0)'.
- `PageShell.narrowHeader-12306.test.tsx`: 'Can be added'.
- `packagedItemWriteGate-12169.test.tsx`: 'Writable'.
- `PermissionMatrixEditor.readonlyHeaderBadge.test.tsx`: the badge is
found by `[data-state-word="readOnly"]`.
- `PermissionMatrixEditor.artifactTier.test.tsx`: 'Can be added' /
'Writable'. The package chip is found by its 'Read-only package' title.
- `inspectors/inspectorStrings.studioNamespace-25922.test.ts`: the
`'engine.badge.': 3` floor is removed (the family retired).
- `PermissionMatrixEditor.readonly.test.tsx` and
`PermissionMatrixEditor.cloneToCustomize.test.tsx` (seat-approved): the
header badge and the identity strip's chip now both draw Read-only from
one key, so the package chip is found by its 'Read-only package' title.
- `metadataAreaHost.gates-28561.test.tsx` (seat-approved): under a
read-only host, the translation header reads
`engine.studio.customize.available` with its title.
## Acceptance notes
- **Deviation, accepted by the seat:** on a read-only package, a
create-only type reads **Read-only**, not "Can be added". The All
metadata area offers no create on a read-only host (`ResourceListPage`'s
`canCreate` requires `!host.readOnly`), and the list header there must
agree with the tile.
- **Access, how it was read:** OWD, the C/R/U/D/E/Tr/VA/MA letters and
Private / Public read are sharing settings of an object, not states of
an item, so they are not words in this vocabulary. Only their zh values
changed, to drop the English doublets.
- **The permission matrix header** was checked live in zh. 只读 shows once
in the breadcrumb chips and once at the right of the set's row, never
twice side by side. No change was needed (screenshot below).
- **Out of scope, card #29729:**
- The FlowLedgerSwitch's 本部署中已关闭 against 已停用.
- The Customize verb 自定义 against the state 定制.
- `perm.badge.custom` 自定义.
- The CRUD legend letters C/R/U/D/E/Tr/VA/MA.
- en "Switched off" for `engine.studio.auto.off` / `offTitle` (en still
reads "Off" / "Disabled — will not run").
- The matrix's `OWD ` row-chip prefix, a literal in
`PermissionMatrixEditor.tsx`.
- `StudioItemHeader.tsx` is untouched.
## Verification
Head `624a4f8f` adds a comment-only fix to the `tFormat` docstring
example in `metadata-admin/i18n.ts` (it named `count` and `writable` on
`engine.directory.description`; it now names
`engine.directory.itemCountTooltip`) and merges `origin/main` `601832b1`
(no overlap with this diff). `5472e3cb` keeps en "Off" (commit
`6a4ea44a`, after CI's Type Check UI went red on `check-i18n-en-drift`
at `d917cfef`) and merges `origin/main` `946a173f`. On `5472e3cb`:
`check-i18n-en-drift`, `check:i18n-drift`, `check:i18n-keys`,
`check:designer-field-key-parity`, `check-sdui-manifest`,
`check-changeset-no-major` and `check-empty-changeset` exit 0; the
census file, `FlowStatusDot.test.tsx`, main's new
`draftObjectFlowGroup-29706` file and the `packages/i18n` suite: 98
files, 1482 passed, 13 skipped.
The gates, the dogfood battery and the i18n suite were measured on
`8d590d21`, which merges `origin/main` `3eeb81d1`. Head `d917cfef`
merged `origin/main` `e82bf642`. No commit in that merge touches the
studio packs, `DirectoryPage.tsx` or `PageShell.tsx`. Main's `cba12d22`
and `7ba8b11f` touch `PermissionMatrixEditor.tsx` and its tests, but not
its badge or chip. On `d917cfef` the derived gate list is unchanged
(35). These were rerun on that head:
- The changed test files plus main's two new matrix test files: 13
files, 331 tests passed.
- `check-sdui-manifest`, `check-changeset-no-major` and
`check-empty-changeset`: exit 0.
<details><summary>Premise, the new tests and the ablations</summary>
- Premise on `7b55ea95` (main), a temporary test (not committed) over
the real directory under a read-only host with five types: it drew 可写 on
the dashboard, report and view tiles and 仅可新建 on page. The lead sentence
counted 5 types, "4 of which support runtime overrides".
- Ablations with `scripts/ablation-replace.mjs`. Each was restored, the
blob equals HEAD, and `git diff HEAD` is empty.
- `if (packageReadOnly)` → `if (packageReadOnly && (false as boolean))`
in `typeStateWord`: 3 tests failed (the read-only tiles, the list header
and the mapping census).
- The tile's `readOnly={packageReadOnly}` → `readOnly={false &&
packageReadOnly}`: 1 test failed (the read-only tiles).
</details>
<details><summary>Real browser: zh-CN screenshots of All metadata, a
pillar and Access</summary>
`examples/app-showcase` with the Console's Vite dev server on app-shell
source, Playwright (Chromium), zh-CN, package `com.example.showcase`
(read-only). The before leg served the four source files from
`origin/main`, restored by trap, and the blobs were proven equal to
HEAD.
- Before: dashboard, report, view and email_template read 可写. Object,
flow, page, action, permission, position and seven more types read 仅可新建.
Lead: 平台协议共暴露 21 个元数据类型(其中 17 个支持运行时覆盖)。点击任意卡片即可浏览、覆盖或创建实例。 Access:
`Public read/write 公共读写`.
- After: dashboard, report, view and email_template read 可定制, and every
other type reads 只读. Lead: 打开一个类型即可查看其中的项。每个类型都标明你在这里能做什么:只读、可定制、可新增或可写。
The view list header reads 可定制. Access shows the 记录共享模型 column and 公共读写
/ 私有 / 受父级控制.
- Files: `before-` and `after-` `all-metadata`, `all-metadata-full`,
`view-list`, `pillar-automations`, `access` (.png and .json), plus
`after-permission-matrix-header.png`.
</details>
<details><summary>Sweep, type-check and gates</summary>
- Neighbour sweeps under the verify lock, every ui test file that names
a changed key, spelling or component: 149 files, then 150 more. The
first runs failed 7 tests in 4 files: three matrix files found Read-only
twice once the header badge and the package chip shared a key, and the
area header read the new word. Those files were repinned (listed above),
and every file is green. On `8d590d21`, the changed test files, main's
two new Access-pair test files and the `packages/i18n` suite: 108 files,
1771 passed, 13 skipped.
- `turbo run type-check --filter=@object-ui/app-shell
--filter=@object-ui/i18n`: 66/66 tasks.
- `dispatch-gates --commands`: 35 derived families, all exit 0,
including `check-sdui-manifest` and `pnpm --dir ui exec vitest run
scripts/` (170 files passed, 2 skipped). `pnpm check:new-line-citations`
(ui): 0 new citations. `dispatch-gates --ran`: 35 derived, 35 run, 0
NOT-MEASURED. `check-closing-keyword-parity`, `check-changeset-no-major`
and `check-adr-0087-registration` were also run against this body.
- `clause2-line.mjs` is a library with no CLI. Its `readClause2Line`
reads the changeset as `no` / `narrowing`, and
`readMetadataProtocolLine` reads it as `none`. These match this body.
- Dogfood battery (owed for the narrowing arm), `pnpm --filter
@objectstack/dogfood test` under the lock after a full build on
`8d590d21`: 402 files passed, 3 skipped; 3317 tests passed, 28 skipped.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jUqduUwnb8TeMn2R3D)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 72877bc commit e9e31e9
16 files changed
Lines changed: 545 additions & 142 deletions
File tree
- .changeset
- ui/packages
- app-shell/src/views/metadata-admin
- inspectors
- i18n/src/namespaces/studio
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
| 17 | + | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
124 | 125 | | |
125 | 126 | | |
126 | 127 | | |
127 | | - | |
| 128 | + | |
128 | 129 | | |
129 | 130 | | |
130 | 131 | | |
131 | | - | |
| 132 | + | |
132 | 133 | | |
133 | 134 | | |
134 | 135 | | |
135 | 136 | | |
136 | 137 | | |
137 | | - | |
138 | | - | |
| 138 | + | |
| 139 | + | |
139 | 140 | | |
140 | | - | |
141 | | - | |
| 141 | + | |
| 142 | + | |
142 | 143 | | |
143 | 144 | | |
144 | 145 | | |
145 | 146 | | |
146 | 147 | | |
147 | 148 | | |
148 | 149 | | |
149 | | - | |
150 | | - | |
151 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
152 | 153 | | |
153 | 154 | | |
154 | 155 | | |
| |||
165 | 166 | | |
166 | 167 | | |
167 | 168 | | |
168 | | - | |
| 169 | + | |
169 | 170 | | |
170 | 171 | | |
171 | 172 | | |
172 | 173 | | |
173 | | - | |
| 174 | + | |
174 | 175 | | |
175 | 176 | | |
176 | 177 | | |
177 | 178 | | |
178 | 179 | | |
179 | 180 | | |
180 | 181 | | |
181 | | - | |
182 | | - | |
| 182 | + | |
| 183 | + | |
183 | 184 | | |
184 | 185 | | |
185 | 186 | | |
186 | 187 | | |
187 | 188 | | |
188 | | - | |
189 | | - | |
| 189 | + | |
| 190 | + | |
190 | 191 | | |
191 | 192 | | |
0 commit comments