Repository navigation
fix(app-shell): optional choice rows in Studio metadata forms can be cleared again - #29805
Merged
Merged
Conversation
… that unsets the key Both builtin select paths of the metadata-admin SchemaForm (form options and the schema's own enum) listed only the enum values, so a picked value on an optional key could never be returned to absent. An optional row now leads with the existing engine.form.none item; choosing it calls onChange(undefined), the form's clear convention (setField deletes the key). Required rows and scalar list elements are unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUDMc41NruhHkjaN5X
…draft as absent The "More fields" SchemaForm in the action, dashboard, hook, page and report default inspectors handed its emitted object straight to onPatch, which the hosts merge over the draft. SchemaForm reports a cleared key by deleting it, so the merge kept the old value and every clear (a None pick, an emptied text box) was undone. fallbackFormPatch returns the dropped keys as explicit undefined, which the merge applies and the saved JSON omits. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUDMc41NruhHkjaN5X
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUDMc41NruhHkjaN5X
Contributor
Author
|
domain:ui#2 · zhuangjianguo · session_01QsR2jRFuJz9QBZqPVHYVhJ 维护者速读
席位意见: 实测发现卡片举的 席位核对 — ACCEPT ·
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Steedos · project thread
Fixes #29733
Clause-②: no
Metadata-protocol: none
Claim: 6595203212 (amendment 6595600429)
维护者速读
deleteBehavioron auserfield cannot be cleared #29733 指出可选枚举选过一次就回不去「未声明」;对user字段的deleteBehavior来说「未声明」本身就是一种生效的语义(不进删除级联)。实测发现 Studio 的字段面板目前根本不显示deleteBehavior这一行(席位另立卡),但缺陷本身在「更多字段」区可复现(动作的openIn只能在 self / new-tab 之间选)。undefined进入草稿,保存时 JSON 自然省略。回滚即 revert 本 PR。ui/packages/app-shell/src/views/metadata-admin/SchemaForm.tsx的offerUnset与两处 Select;inspectors/fallbackFormPatch.ts;五个 DefaultInspector 各一行onChange。pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/SchemaForm.optionalEnumUnset-29733.test.tsx packages/app-shell/src/views/metadata-admin/inspectors/fallbackFormPatch-29733.test.tsx,预期 12 个用例全部通过。What changes
1. An optional enum select offers "— None —". Both builtin select paths of the metadata-admin
SchemaForm(a form row'soptions, and a schema property's ownenum) listed only the enum values, so an optional key, once picked, could never return to absent.FieldControlnow leads an optional row's list with a "— None —" item: the existingengine.form.nonekey (en "— None —", zh "— 无 —"), the word the metadata-admin pickers already use, so no new i18n key. Radix refuses an item whose value is the empty string, so the item carries a sentinel thatonValueChangemaps back toundefined, the form's existing clear convention (setFielddeletes the key; a repeater row keeps anundefinedthat serialisation drops). With nothing set, the trigger still shows the "Select…" placeholder and nothing is written on render.required, a form row'srequired, a grid column'srequired)2. Clears in the "More fields" fallback form reach the draft. The action, dashboard, hook, page and report default inspectors render a fallback
SchemaFormand wired itonChange={(next) => onPatch(next)}. The host'sonPatchmerges the patch over the draft, andSchemaFormreports a clear by deleting the key fromnext, so the merge kept the old value: a None pick, an emptied text box or an emptied number box there was undone at once. The new pure helperfallbackFormPatch(draft, next)returnsnextplus every key the draft had andnextdropped, set toundefined; the five call sites route through it.onPatch's merge itself is unchanged, and a key the form did not touch is never turned intoundefined.Tests
SchemaForm.optionalEnumUnset-29733.test.tsx(new, 8), over the realSchemaForm: the schema-enum path and the form-options path each emit an object without the key after "— None —" (nothing else moves); a repeater card row (the object form'sfieldsrows, wheredeleteBehaviorsits) serialises without the key; the placeholder still shows and nothing is emitted on render. CONTROLS: a required enum on each path offers no None item; in a grid repeater a required column offers none while an optional one does; a scalar list element offers none.inspectors/fallbackFormPatch-29733.test.tsx(new, 4): the helper through a merge leaves a cleared key absent and an edited key at its new value; CONTROL: untouched keys pass through and nothing becomesundefined; the realActionDefaultInspectorunder a merging host: "— None —" onopenInand an emptieddescriptioneach leave the draft without the key, with the curated keys untouched.scripts/ablation-replace.mjs, each restored to the HEAD blob withgit diff HEADempty): A1offerUnsetforced false, 4 of 8 red (the three positive pins and the grid optional column), the 4 controls green. A2 the helper's undefined-for-dropped-key line removed, 3 of 4 red, the control green.--maxWorkers=2: the 144 ui test files that nameSchemaForm, one of the five inspectors orengine.form.none(git grep -l), 1464 tests, all green.Acceptance notes
ObjectFieldInspector) offers no Delete Behavior row on auserfield nor on alookupfield; thedeleteBehaviorrows live inobject.form.ts/field.form.ts, whichSchemaFormrenders, and forobjectthe editor shows the designer and its inspectors instead. So the named consequence (a cascade or restrict left in force on auserfield) is prevented here for the moment a form that renders those rows is reached. The missing row in the designer's field panel is filed by the seat as its own finding.onChangecall sites and one helper, after the live run showed a None item alone would be a dead control there. Clearing a text box or a number box in those fallback forms is fixed by the same change.defaultis listed in the served schema'srequiredand so offers no None item (hookonError,runAs). That is the existing required signal, not changed here.variantselect (anInspectorSelectField, notSchemaForm) still has no unset item; it is outside this card.packages/app-shellsuite is CI's (Test UI); locally the 144-file grep set above ran.Verification
Real backend (
examples/app-crm,objectstack dev --fresh) and the source Console (Vite onui/apps/console), admin session, a scratch package with an objectudb_ticket(auserfieldassignee, alookupfieldparent_ticket) and an actionudb_escalate(type: url,openIn: self). Screenshots are in the project folder (issue-29733/), not on GitHub.Before (main 6f09464), the "More fields" Open In select on the action
["self","new-tab"]: no way back to absent.self: the merging host kept the key.assignee(user) andparent_ticket(lookup) shows no Delete Behavior row.After, on this branch
["— None —","self","new-tab"].GET /api/v1/meta/action/udb_escalateafter publish: the item carries noopenIn(before it read"openIn":"self").Local gates
On head
74e47d1e(main merged at25450217; 11 later main commits touch none of this PR's files):node scripts/pm/dispatch-gates.mjs --commandsderives 35 commands; each ran with exit 0 (check:type-check-debtandpnpm --dir ui exec vitest run scripts/under the verify lock), and--ranreconciles 35 derived, 35 run, 0 NOT-MEASURED. Also exit 0:pnpm --filter @object-ui/app-shell run type-check;eslinton the 9 touched files (0 errors; the warnings are on untouched lines);check-partof-closing-keyword;check-closing-keyword-parity --body(binds only this card). The two new test files rerun on this head: 12/12.dispatch-gates --tier: no path-derived mandate (default tier); 520 changed lines before the main merge, under 3000. The repo-wide sweep (pnpm lintand the rest of the farm) is CI's.🤖 Generated with Claude Code
Generated by Claude Code