Repository navigation
Commit 16d151b
feat(studio): external-object fields show their datasource and write state; no DDL controls on an external object (#27316)
<!-- claude-projects-attribution: {"github_login":"marchtian"} -->
_Requested by **田騏** · [project
thread](https://claude.ai/code/project/chan_01VmuUhXU9SSUzqJYyXSmYSi?thread=cmsg_01VmuUhXU9SSUzqJYyXSmYSiVy7F2atKWpo5rp3YPrqddh)_
Fixes #27279
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么:** Studio 对象设计器(字段画布与字段检查器)里,带 `external` 绑定的外部对象:每个字段标「来自 数据源名
· 只读或可写」,画布顶部一条说明;不再出现「添加字段」、批量删除,字段检查器里 API 名与类型置灰、无复制与删除。
- **为什么改:** 外部对象的表属于远端数据库,平台从不对它做
DDL;以前设计器照常提供加列、改类型、删字段,而平台不会对远端表执行这些改动(ADR-0015 欠的 Studio 半边,裁决 D6 的 P1
部分)。
- **风险与回滚:** 只影响带 `external` 的对象的设计器界面,平台自有对象不变;不改元数据协议、不改服务端。回滚即还原本 PR。
- **先看:** `previews/external-object.tsx`(判定与写入状态,含数据源读取)→
`previews/ObjectFormCanvas.tsx`(隐藏加字段与批量删除)→
`inspectors/ObjectFieldInspector.tsx`(`ddlLocked` 一行决定四个控件)。
- **两分钟验证:** `pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/previews/external-object.test.tsx`,预期
11 passed;其中一条断言中文标记为「来自 plan_gantt · 只读」且无「添加字段」按钮。
- **需要你做的:** 无,席位落地。
## What changes
An object that carries an ADR-0015 `external` binding is never a DDL
target (the runtime's own test is the same presence check,
`isFederatedObject` in `@objectstack/objectql`). The object designer
under `ui/packages/app-shell/src/views/metadata-admin` now reads
`object.external` / `object.datasource` and:
- **Marks every field.** Each field row on the canvas and the field
inspector carry a badge "From DATASOURCE · STATE" (zh: 「来自 DATASOURCE ·
只读」), and a note above the canvas names the datasource and says why
fields cannot be reshaped there.
- **Write state, never guessed.** ADR-0015 writes need both
`datasource.external.allowWrites` and `object.external.writable` (the
engine's write gate, `assertWriteAllowed`). Without `writable: true` on
the object the state is settled from the object alone: Read-only, and no
request is made. With it, the datasource is read through the metadata
door (`GET /meta/datasource/NAME`, the same item `DatasourcePreview`
reads `external.allowWrites` from): both set ⇒ Writable, otherwise
Read-only, and a datasource that cannot be read ⇒ "Writes unconfirmed"
with a tooltip naming the missing half. The read is keyed on the
datasource name, not on the client's identity (`ui/AGENTS.md` #10).
- **Hides the DDL affordances**, each read from the code:
| Control | Where | Why it is DDL |
|:---|:---|:---|
| Add field (bottom bar, empty state, section header "+") |
`ObjectFormCanvas` `addField` | appends a field = a new remote column |
| Bulk Delete | `ObjectFormCanvas` `bulkDelete` | removes fields = drops
remote columns |
| API name input | `ObjectFieldInspector` `setKey` | renames the field
key = renames the column |
| Type picker | `ObjectFieldInspector` `changeType` | retypes the column
|
| Duplicate | `ObjectFieldInspector` `duplicateField` | adds a field |
| Remove | `ObjectFieldInspector` `removeField` | drops the column |
The label-to-API-name derivation (`deriveNameFor`) is also off on an
external object, since it renames the key. Kept: label, inline label
rename, sections, ordering, bulk move-to-section, and the other
display/validation settings, which change only platform metadata.
- **Strings:** six `designer.external.*` rows in the `studio` namespace
of `@object-ui/i18n` (`en` + `zh`), the folder's existing i18n
mechanism.
## Tests
`previews/external-object.test.tsx` (new, 11 cases): the binding reader;
on the canvas, per-field and header badges "From plan_gantt · Read-only"
with no datasource read, the zh mark 「来自 plan_gantt · 只读」 with no
「添加字段」, no Add field on an empty external object nor on a section
header, bulk move kept and bulk delete dropped, the three `writable:
true` outcomes (allowWrites ⇒ Writable, no allowWrites ⇒ Read-only, read
failure ⇒ unconfirmed); in the field inspector, API name and Type
disabled, Duplicate and Remove absent, Label still editable. Each group
has a platform-owned-object control case that keeps every control.
## Acceptance notes
- **Studio Data pillar is not covered by this PR.**
`views/studio-design/StudioDesignSurface.tsx` (outside this card's file
surface, `views/metadata-admin/**`) has its own add-field doors: the
records grid's "+" column (`onAddColumn` → `AddFieldPopover`) and the
Form layout designer's `onAddField`. Its right rail reuses
`ObjectFieldInspector`, so there the badge shows and rename / retype /
duplicate / remove are already gone, but the grid and form-designer "Add
field" still show for an external object. Named in the dev report for a
follow-up.
- The Ask AI button on the canvas's bottom bar stays; it opens the
assistant and adds nothing by itself.
- The datasource read happens only for `writable: true` objects; the
canvas and the field inspector each read it once per datasource name.
## Verification
All readings at head `fdeadb17` on a shared container.
<details><summary>Affected tests and type-check</summary>
- `pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/previews/external-object.test.tsx
packages/app-shell/src/views/metadata-admin/previews/ObjectFormCanvas.test.tsx
packages/app-shell/src/views/metadata-admin/inspectors/
packages/i18n/src/__tests__/studio-namespace.test.ts` → lock VERDICT
command-exit 0, Test Files 204 passed (204), Tests 2833 passed, 1
skipped.
- `pnpm --filter @object-ui/i18n --filter @object-ui/app-shell run
type-check` → VERDICT command-exit 0 (both `tsc --noEmit` and `tsc -p
tsconfig.test.json`).
- `pnpm --dir ui exec vitest run scripts/` → VERDICT command-exit 0,
Test Files 174 passed, 2 skipped; Tests 4990 passed, 2 skipped. (An
earlier run of the same command exited 1 on a 15 s timeout of the
whole-tree sweep in `check-vi-mock-inherit.test.ts` under shared load;
that file alone passed 83/83, and the full re-run above is green.)
- ui-local: `check:new-line-citations` (0 new citations),
`check:i18n-dead-keys`, `check:i18n-keys`, `check:i18n-drift` (6 keys
added, 0 en values changed), `check:control-bytes` → all exit 0.
</details>
<details><summary>Derived gate families (dispatch-gates
--commands)</summary>
`node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran FILE` → 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN; every command
exit 0 (the list with exit codes is in the dev report). Also run outside
the derivation: `pnpm check:changeset-fixed` exit 0. CI-owned type-check
lanes and whole-tree families are left to CI.
</details>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_017ihL2c5z3q4h8inrn5kwqV
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6abcb72 commit 16d151b
9 files changed
Lines changed: 608 additions & 28 deletions
File tree
- .changeset
- ui/packages
- app-shell/src/views
- metadata-admin
- inspectors
- previews
- 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 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
105 | 110 | | |
106 | 111 | | |
107 | 112 | | |
| |||
664 | 669 | | |
665 | 670 | | |
666 | 671 | | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
667 | 679 | | |
668 | 680 | | |
669 | 681 | | |
| |||
875 | 887 | | |
876 | 888 | | |
877 | 889 | | |
878 | | - | |
| 890 | + | |
879 | 891 | | |
880 | 892 | | |
881 | 893 | | |
| |||
1012 | 1024 | | |
1013 | 1025 | | |
1014 | 1026 | | |
1015 | | - | |
| 1027 | + | |
1016 | 1028 | | |
1017 | 1029 | | |
1018 | 1030 | | |
| |||
1033 | 1045 | | |
1034 | 1046 | | |
1035 | 1047 | | |
1036 | | - | |
| 1048 | + | |
1037 | 1049 | | |
1038 | 1050 | | |
1039 | 1051 | | |
| |||
1058 | 1070 | | |
1059 | 1071 | | |
1060 | 1072 | | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
| 1077 | + | |
1061 | 1078 | | |
1062 | 1079 | | |
1063 | 1080 | | |
1064 | 1081 | | |
1065 | | - | |
| 1082 | + | |
1066 | 1083 | | |
1067 | 1084 | | |
1068 | 1085 | | |
| |||
1105 | 1122 | | |
1106 | 1123 | | |
1107 | 1124 | | |
1108 | | - | |
| 1125 | + | |
1109 | 1126 | | |
1110 | 1127 | | |
1111 | 1128 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
75 | 81 | | |
76 | 82 | | |
77 | 83 | | |
| |||
104 | 110 | | |
105 | 111 | | |
106 | 112 | | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
107 | 119 | | |
108 | 120 | | |
109 | 121 | | |
| |||
448 | 460 | | |
449 | 461 | | |
450 | 462 | | |
451 | | - | |
| 463 | + | |
452 | 464 | | |
453 | 465 | | |
454 | 466 | | |
455 | 467 | | |
456 | 468 | | |
| 469 | + | |
457 | 470 | | |
458 | 471 | | |
459 | 472 | | |
| |||
470 | 483 | | |
471 | 484 | | |
472 | 485 | | |
473 | | - | |
| 486 | + | |
474 | 487 | | |
475 | 488 | | |
476 | 489 | | |
| |||
493 | 506 | | |
494 | 507 | | |
495 | 508 | | |
496 | | - | |
| 509 | + | |
497 | 510 | | |
498 | 511 | | |
499 | 512 | | |
| |||
504 | 517 | | |
505 | 518 | | |
506 | 519 | | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
507 | 525 | | |
508 | 526 | | |
509 | 527 | | |
| |||
538 | 556 | | |
539 | 557 | | |
540 | 558 | | |
541 | | - | |
| 559 | + | |
542 | 560 | | |
543 | 561 | | |
544 | 562 | | |
| |||
681 | 699 | | |
682 | 700 | | |
683 | 701 | | |
684 | | - | |
| 702 | + | |
| 703 | + | |
685 | 704 | | |
686 | 705 | | |
687 | 706 | | |
| |||
725 | 744 | | |
726 | 745 | | |
727 | 746 | | |
728 | | - | |
729 | | - | |
730 | | - | |
731 | | - | |
732 | | - | |
733 | | - | |
734 | | - | |
735 | | - | |
736 | | - | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
737 | 758 | | |
738 | 759 | | |
739 | 760 | | |
| |||
1001 | 1022 | | |
1002 | 1023 | | |
1003 | 1024 | | |
| 1025 | + | |
1004 | 1026 | | |
1005 | 1027 | | |
1006 | 1028 | | |
| |||
1014 | 1036 | | |
1015 | 1037 | | |
1016 | 1038 | | |
| 1039 | + | |
| 1040 | + | |
1017 | 1041 | | |
1018 | 1042 | | |
1019 | 1043 | | |
| |||
1200 | 1224 | | |
1201 | 1225 | | |
1202 | 1226 | | |
| 1227 | + | |
1203 | 1228 | | |
1204 | 1229 | | |
1205 | 1230 | | |
| |||
0 commit comments