Skip to content

feat(app-shell): Delete Behavior row in the Studio field panel on lookup, user and master_detail fields - #29853

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-13g0wj
Nov 3, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-13g0wj

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #29807

Clause-②: no
Metadata-protocol: none

Claim: 6596731216 (amended 6596763338)

维护者速读

  • 改了什么:Studio 对象设计器的字段面板(ObjectFieldInspector)在 lookup、user 与 master_detail 字段上新增「删除行为」下拉框(deleteBehavior)。lookup 与 user 可选 置空 / 级联 / 限制;master_detail 只有 级联 / 限制(规范拒绝在主从字段上写 set_null)。首项「— 无 —」把该键从字段定义里删掉。字段改成没有该行的类型时删除该键,改成 master_detail 时删除已写的 set_null。
  • 为什么改:删除行为决定被引用记录删除时本记录怎么办,在 user 字段上「不声明」本身就是一种生效的结果。此前 Studio 里看不到也设不了,只能改原始元数据。
  • 风险与回滚:只动字段面板的类型专属区与类型切换;text、tree 等类型不出现该行(有测试钉住)。回滚即 revert 本 PR。
  • 先看:ObjectFieldInspector.tsx 的 offeredDeleteBehaviors(哪种类型给哪些值)、changeType 里的 dropsDeleteBehavior、DeleteBehaviorField 的 onCommit(选值写入 / 选「无」走 unsetDefKey)。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.test.tsx,预期 54 个用例全部通过(其中 9 个是本 PR 新增的删除行为用例)。
  • 需要你做的:无,席位落地。

What changes

The Studio object designer's field panel can now set and clear FieldSchema.deleteBehavior. Until now only the generic field / object metadata forms (PR #29712) offered it, and the object editor draws the designer and its inspectors, not those forms.

Field in the panel Before Now
lookup picker config, name toggle, related list; no Delete Behavior a Delete Behavior select: — None —, Set Null, Cascade, Restrict
user the name toggle only the same select with the same four items
master_detail picker config, related list the select with — None —, Cascade, Restrict (the spec refuses an authored set_null there)
text, tree and every other type unchanged unchanged, no row
  • Values follow the generic form's rows (field.form.ts): all three on lookup and user, cascade / restrict on master_detail. One helper, offeredDeleteBehaviors(type), decides both the row and its values.
  • Unset removes the key. The select leads with the designer's existing "— None —" item, using the inspector's own absent-key convention: InspectorSelectField's '' option mapped to unsetDefKey, the shape the valueDomain row already uses. The field then carries no deleteBehavior at all, never '' or null. On a lookup that means the spec default; on a user field it keeps the field out of the delete walk.
  • Retype. changeType now removes deleteBehavior when the next type draws no row, tree included, and removes an authored set_null on a retype to master_detail. cascade and restrict survive a retype to master_detail.
  • Wording. The label, help text and option labels are five new Studio namespace keys (designer.field.deleteBehavior, .help, .set_null, .cascade, .restrict) in en and zh, the two locales that namespace carries. The label and help text match the form row; the Cascade and Restrict labels are field.form.ts's master_detail option labels.

Tests

ui/packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.test.tsx, a new top-level describe in the shared harness (9 cases, over the real inspector with a host that feeds each patch back as Studio's draft does):

  • The row is drawn on lookup and user with None plus three values, and on master_detail with None plus two.
  • CONTROL: no row on a text or a tree field.
  • Picking Cascade on a user field writes deleteBehavior: 'cascade'.
  • Picking None on a lookup holding restrict leaves the key absent (hasOwnProperty false), with reference kept.
  • A retype from lookup to Text drops the key.
  • A retype from lookup to Master-Detail drops set_null, and keeps cascade.

Ablations through scripts/ablation-replace.mjs, each restored to the HEAD blob with git diff HEAD empty, each red:

Mutation Result
A1 the row's render guard prefixed with false && 5 failed (the three draw cases, set, unset)
A2 the retype's delete nextDef.deleteBehavior removed 2 failed (both retype cases)

Acceptance notes

  • Surface: exactly the amended claim's five files. ObjectFieldInspector.tsx (a type helper, changeType, the row and its component), its shared test harness, ui/packages/i18n/src/namespaces/studio/{en,zh}.ts (five keys each), and .changeset/29807-field-panel-delete-behavior.md (patches for @object-ui/app-shell and @object-ui/i18n). The Studio namespace table is a plain string-to-string record outside the locale packs, so the new keys widen no published type and the claim's Clause-②: no holds.
  • PR fix(app-shell): optional choice rows in Studio metadata forms can be cleared again #29805 (Studio metadata forms: an optional enum select has no empty item, so a chosen deleteBehavior on a user field cannot be cleared #29733) does not touch this file; its "— None —" item is private to SchemaForm. This row reuses the field panel's own absent-key path instead, so the two PRs share no code (claim amendment 6596763338). fix(app-shell): optional choice rows in Studio metadata forms can be cleared again #29805 has since merged and is in this branch through the main merge.
  • A stored value the type does not offer (an authored set_null on a master_detail) is drawn flagged by InspectorSelectField, as every select in the panel does, so the author sees what the save refuses.
  • The help text sits under the select as plain text. InspectorSelectField takes no description, so it is not wired as the control's accessible description, unlike the name toggle's checkbox.
  • The dead-keys report lists designer.field.deleteBehavior. among the dynamic prefixes it keeps alive (3 keys, one call site), the same as designer.field.summary.fn..

Verification

Real backend (objectstack dev --seed-admin --fresh in examples/app-crm) and the source Console on Vite, as the admin, on head e646fdc1 (this PR's code is unchanged by the later main merge). Screenshots and scripts are in the project folder issue-29807/ (shots/, setup.mjs, measure.cjs, read.mjs), not on GitHub.

Before, set, publish, unset: the definition carries the key, then drops it
  • A scratch package com.example.dbx over REST: dbx_account, and dbx_ticket with title (text), parent_ticket (lookup), assignee (user) and account (master_detail), none declaring the key.
  • Before (ObjectFieldInspector.tsx from origin/main swapped in under the same Vite server, then restored to the HEAD blob): no Delete Behavior row on any of the four fields (before-*.png).
  • After, at /apps/setup/metadata/object/dbx_ticket: the row is on parent_ticket and assignee with — None —, Set Null (clear the reference), Cascade (delete children), Restrict (block the delete), and on account with — None —, Cascade, Restrict; title has none (set-*.png). Picking Cascade, Restrict and Restrict autosaved the draft (PUT /api/v1/meta/object/dbx_ticket?mode=draft 200, three times), Publish answered POST …/dbx_ticket/publish 200, and GET /api/v1/meta/object/dbx_ticket then served parent_ticket.deleteBehavior cascade, assignee restrict, account restrict, and no key on title. After a reload the selects read those values (set-reloaded-*.png).
  • Picking — None — on parent_ticket and assignee: the last draft PUT body carried neither key on those two fields (account kept restrict), Publish answered 200, and the served definition had no deleteBehavior on parent_ticket or assignee (unset-*.png).
Local gates and suites
  • dispatch-gates --commands derives no tier mandate (default tier). Changed lines 229 (+228 / -1), 5 files.
  • On the merged head eab8960c (main merged, which brought in PR fix(app-shell): optional choice rows in Studio metadata forms can be cleared again #29805), after pnpm install --frozen-lockfile and a full pnpm build (117/117): turbo run type-check for @object-ui/app-shell and @object-ui/i18n 66/66; 128 test files (all 31 ObjectFieldInspector* files, the zh base-term census, block-config-i18n, the whole @object-ui/i18n package) at 2 workers under the verify lock, 128/128 files, 1800 passed, 13 skipped.
  • On eab8960c: the derived set, 35 commands, every one exit 0, including check-sdui-manifest (manifest intact, 106 components) and pnpm --dir ui exec vitest run scripts/ under the lock (170 files passed, 2 skipped); --ran reconciles 35 derived, 35 run, 0 NOT-MEASURED. The same set was also all exit 0 on e646fdc1 before the merge.
  • ui check:i18n-keys, check:i18n-drift, check:i18n-dead-keys, check:designer-field-key-parity, check:phantom-deps, check:spec-symbols exit 0 on eab8960c; eslint on the four touched source files exit 0 (warnings only, all on lines this PR does not touch).

Generated by Claude Code

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Nov 3, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

席位核对 · ACCEPT · 2026-11-03T07:50Z

Head-sha: eab8960c336d44d437ad812010c133abd88e8322

  • Shape: draft → main, and Fixes #29807 is the only closing keyword in the body. 5 files, +228 / −1. check-governed-merges --pr 29853 reports NOT governed, at 229 lines, so this is an ordinary queue landing. Clause-②: no and Metadata-protocol: none are line-initial in the body and the changeset, as in claim 6596731216 (amended 6596763338). No contract review is owed: the new labels are Studio namespace keys (Record<string, string>, outside the locale packs), and nothing is exported. The changeset is a patch for @object-ui/app-shell and @object-ui/i18n.
  • File surface: exactly the five files in amendment 6596763338. The dev's premise correction (PR fix(app-shell): optional choice rows in Studio metadata forms can be cleared again #29805 never touched ObjectFieldInspector.tsx) is recorded there.
  • Read in the diff:
    • offeredDeleteBehaviors(type): lookup and user offer all three values, master_detail offers cascade and restrict, and every other type offers none. This matches field.form.ts and the spec's refusal of an authored set_null on a master_detail.
    • The row draws only where values are offered. The "— None —" item (engine.form.none) commits through unsetDefKey('deleteBehavior'), so the key is absent, never '' or null.
    • The retype guard drops the key when the next type offers none, and drops an authored set_null on a retype to master_detail. It joins the existing referenceNameVisible and kinds cleanup in one write.
    • The row sits inside DisplayPatchLock and honours locked.
  • Tests (dev, report 6597970140): 9 new cases in the shared harness, and the file passes 54/54. Ablation A1 (render guard) reds 5, and A2 (retype delete) reds 2; both were restored to the HEAD blob. Build passes 117/117 and type-check 66/66. A 128-file sweep is green. Of 35 derived gates, all 35 exit 0, with 0 NOT-MEASURED.
  • Live: main shows no row. After the change, the row appears on lookup, user and master_detail with the expected options, and not on text. A set value survives publish and is served by GET. "None" removes the key from the draft PUT and from the served definition. Shots are in /mnt/project-files/issue-29807/shots/.
  • Gates (check-runs on this head): 44 success, 11 skipped (opt-in and schedule gates), 0 failed, 0 pending. Lint & Repo Gates and TypeScript Type Check both succeeded. mergeable_state is clean.
  • Accepted deviations: the help line is a plain paragraph, because InspectorSelectField takes no description prop and sits outside the surface. Phone width was not measured, since the designer row takes no click at 390 px (Studio: the object designer's field panel cannot turn on a lookup's referenceNameVisible #29629's probe). Main moved 5 commits without touching these files.
  • Out of scope: none reported. Nothing to file.
  • Landing: pr_ready, then automerge_enable. Merging closes Studio: the object designer's field panel offers no Delete Behavior row on a lookup or user field, so deleteBehavior cannot be set or cleared from Studio #29807.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 3, 2026 07:52
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 3, 2026 07:52
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 118bee4 Nov 3, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-13g0wj branch November 3, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

1 participant