Repository navigation
Commit 0ab4a09
fix(studio): open system-scope packages read-only, with Customize (#29591)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbSQv4ZnRLpEwaigh35YLReU)_
Fixes #29567
Clause-②: no
Metadata-protocol: none
The two lines are copied from the claim (comment 6586202344).
## 维护者速读
- 改了什么:Studio 打开系统级(scope 为
system/cloud)的包时,按服务端的判定读成只读:顶栏包名旁出现「只读」锁标,条目头部出现「自定义」,修改存进该包配对的 .custom
定制包,和代码启动的包一样。包切换器的下拉列表照旧不列系统包。
- 为什么改:包列表的解析为切换器把系统包过滤掉了,Studio
的写入判定只查切换器的条目,查不到就当成「没有判定」而放开编辑;作者改完保存才被 403 NOT_OVERRIDABLE
拒绝,而服务端其实接受把它定制进配对包(ensure-customization 回 201)。
- 风险与回滚:只改 app-shell 两个文件的判定读取(切换器查不到时改读列表行上服务端的
writable),不加文案、不动服务端、不动下拉列表。回滚即撤销本 PR。
- 先看:`StudioDesignSurface.tsx` 里写入判定的 effect(切换器无条目时读
`listedPackageEntry`);`PackageSwitcher` 的 `current` 回退到新 prop
`openEntry`;新测试 `StudioDesignSurface.kernelReadOnly-29567.test.tsx`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/studio-design/StudioDesignSurface.kernelReadOnly-29567.test.tsx`,预期
4 个用例全过(换回 main 的 StudioDesignSurface.tsx 时其中 3 个转红)。
- 需要你做的:无,席位落地。
## What changes
- **`packages-io.ts`: new `listedPackageEntry(manifests, id)`.** A
`PkgEntry` for any package the list names, read from the listed row
(`parseListedPackageManifests`), the server's `writable` verdict
included. Unlike `parsePackages` it answers for a kernel package
(manifest scope `system` / `cloud`), which the switcher's list still
leaves out. `parsePackages` is unchanged.
- **`StudioDesignSurface.tsx`, the surface's write gate.** When the
switcher's entries do not carry the open package, the gate now reads
`listedPackageEntry` instead of settling on "no verdict". A system
package therefore reads `writable: false`: the surface is read-only, the
base facts (listed version, listed pair) are read, and the customization
prop is built, so Customize runs the existing ensure path. `pkgWritable`
stays "still asking" until that answer lands, so the surface never opens
editable first. An id the list does not name still ends in "package not
found", as before.
- **`PackageSwitcher` (same file).** New prop `openEntry`, the surface's
entry for the open package. The trigger's `current` falls back to it
once the list has answered, so the chip shows the package's name and the
read-only lock. The menu is unchanged: kernel packages stay out of it,
and "Manage package" still reads only the list's own entry.
- No new strings, no server change.
## Tests
- **New `StudioDesignSurface.kernelReadOnly-29567.test.tsx`.** The real
`StudioDesignSurface` and metadata client over a fetch stub that lists
`com.objectstack.plugin-auth` (scope `system`, namespace `sys`,
`writable: false`) beside a writable package. Pins: the chip names the
package and shows `studio-pkg-readonly`, and the menu still does not
offer it; Customize is offered on its dashboard and the first edit POSTs
`ensure-customization` (201) and writes the pair's draft declaring the
override at the listed version; a system package the door refuses (its
manifest states no version, so the pair's `^major` range cannot be
declared) shows Customize disabled with the `noVersion` reason and never
asks the door; CONTROL, a writable package opens with no chip and no
Customize.
- **`packages-io.writableVerdict.test.ts`: one case.**
`listedPackageEntry` answers a system row with the server's `writable:
false` and its namespace while `parsePackages` still leaves it out, and
answers `null` for an id the list does not name.
- **Red on main:** `StudioDesignSurface.tsx` restored to `208d3e2e`
(`git restore --source`): 3 of the 4 new cases red (chip, Customize,
door-refused), CONTROL green. Restored with `git checkout HEAD --`, `git
diff HEAD` empty.
- **Ablation of the chip fallback** (`scripts/ablation-replace.mjs`,
`const current = listedCurrent ?? (…openEntry…)` replaced by
`listedCurrent`, anchor 1 to 0): the two cases asserting the chip go
red, the Customize case stays green (it reads the gate, not the chip).
Restored: blob equals HEAD, `git diff HEAD` empty.
## Acceptance notes
- **Kernel packages stay out of the switcher's menu** on purpose: the
claim fixed the verdict, not which packages are offered. An open one is
reached by URL (the card's measurement path) or from a link.
- **A system package's pair is listed without its base.** Once a pair
exists (`com.objectstack.plugin-auth.custom`), `foldCustomizationPairs`
cannot fold it under a base the list leaves out, so the pair shows as
its own row; opening it lands on the base through the existing pair URL
redirect (`customizationPairBaseOf`; read in code, not measured). Noted,
not changed.
- **Shared `sys` namespace.** Measured on a fresh `pnpm dev:crm` at this
head: 18 of the 25 listed packages are scope `system` with namespace
`sys` (plugin-auth, plugin-security, audit, rest.api,
service-automation, service.settings and others). `POST
/api/v1/packages/com.objectstack.plugin-auth/ensure-customization`
answered 201 (`sys_custom`, `^3`); after it, the same door for
`com.objectstack.plugin-security` and `com.objectstack.audit` answered
`422 NAMESPACE_CONFLICT` ("its namespace 'sys_custom' is already owned
by package 'com.objectstack.plugin-auth.custom'"). So only the first
`sys` package can get a pair. The console cannot read that answer before
asking (it is the registry's namespace owners), so such a package shows
Customize and the refusal arrives at the first save, in the door's own
sentence. Whether more than one system package should be customizable is
outside this card and goes to the seat as a finding; the code is left as
it is.
- The listed-manifest fallback for a server that predates `writable`
(`scope !== 'project'`) is unchanged, and it reads a scope-`system` row
as writable; every current server serves the verdict on every row.
## Verification
All on head f933fef (base 208d3e2), in worktree
`objectstack-issue-29567`.
<details><summary>Tests</summary>
- `pnpm --dir ui exec vitest run --maxWorkers=2` over the 2 touched test
files: 2 files, 11 tests passed.
- The same over every app-shell test naming `StudioDesignSurface` or
`packages-io` (`git grep -l`), in five batches: 210 files passed, 1409
tests passed. Narrowed: CI's Test UI runs the rest of app-shell.
- `pnpm --dir ui exec vitest run scripts/`: 170 files passed, 2 skipped;
4972 tests passed.
- `pnpm --filter @object-ui/app-shell run type-check` (`tsc --noEmit`
and `tsc -p tsconfig.test.json`): exit 0.
- `pnpm exec eslint` over the four touched ui files: exit 0, 0 errors
(46 warnings, all on lines this PR does not touch).
</details>
<details><summary>Gates</summary>
- `node scripts/pm/dispatch-gates.mjs --commands`: 34 derived families.
All 34 ran and exited 0, including `check-sdui-manifest.mjs` and its
`--self-test`, `check-changeset-no-major`,
`check-adr-0087-registration`, `check-closing-keyword-parity`,
`check-empty-changeset` and `check:published-files`.
- `dispatch-gates --ran`: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN.
- `pnpm --dir ui check:new-line-citations`: 0 new citations.
- Dogfood battery: n/a, because there is no `!` in the title and no
(narrowing) arm.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jV3kBe3QqeCq1aYvu8)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent e9d9549 commit 0ab4a09
5 files changed
Lines changed: 364 additions & 20 deletions
File tree
- .changeset
- ui/packages/app-shell/src/views/studio-design
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 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 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
391 | 391 | | |
392 | 392 | | |
393 | 393 | | |
| 394 | + | |
394 | 395 | | |
395 | 396 | | |
396 | 397 | | |
| |||
907 | 908 | | |
908 | 909 | | |
909 | 910 | | |
| 911 | + | |
910 | 912 | | |
911 | 913 | | |
912 | 914 | | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
913 | 922 | | |
914 | 923 | | |
915 | 924 | | |
| |||
985 | 994 | | |
986 | 995 | | |
987 | 996 | | |
988 | | - | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
989 | 1000 | | |
990 | 1001 | | |
991 | 1002 | | |
| |||
1493 | 1504 | | |
1494 | 1505 | | |
1495 | 1506 | | |
1496 | | - | |
| 1507 | + | |
1497 | 1508 | | |
1498 | 1509 | | |
1499 | | - | |
| 1510 | + | |
1500 | 1511 | | |
1501 | 1512 | | |
1502 | 1513 | | |
| |||
1632 | 1643 | | |
1633 | 1644 | | |
1634 | 1645 | | |
| 1646 | + | |
| 1647 | + | |
| 1648 | + | |
| 1649 | + | |
| 1650 | + | |
| 1651 | + | |
| 1652 | + | |
| 1653 | + | |
| 1654 | + | |
| 1655 | + | |
| 1656 | + | |
| 1657 | + | |
| 1658 | + | |
| 1659 | + | |
| 1660 | + | |
| 1661 | + | |
1635 | 1662 | | |
1636 | 1663 | | |
1637 | 1664 | | |
1638 | 1665 | | |
1639 | | - | |
1640 | | - | |
1641 | | - | |
1642 | | - | |
1643 | | - | |
1644 | | - | |
1645 | | - | |
1646 | | - | |
1647 | | - | |
1648 | | - | |
1649 | | - | |
1650 | | - | |
1651 | | - | |
1652 | | - | |
| 1666 | + | |
| 1667 | + | |
| 1668 | + | |
1653 | 1669 | | |
1654 | | - | |
| 1670 | + | |
| 1671 | + | |
| 1672 | + | |
| 1673 | + | |
| 1674 | + | |
| 1675 | + | |
| 1676 | + | |
| 1677 | + | |
| 1678 | + | |
| 1679 | + | |
| 1680 | + | |
| 1681 | + | |
| 1682 | + | |
1655 | 1683 | | |
1656 | 1684 | | |
1657 | 1685 | | |
| |||
2484 | 2512 | | |
2485 | 2513 | | |
2486 | 2514 | | |
2487 | | - | |
| 2515 | + | |
| 2516 | + | |
| 2517 | + | |
| 2518 | + | |
| 2519 | + | |
| 2520 | + | |
| 2521 | + | |
2488 | 2522 | | |
2489 | 2523 | | |
2490 | 2524 | | |
| |||
0 commit comments