Repository navigation
fix(fields): a boolean field draws a checkbox and a toggle field a switch, on the canvas and in the form - #27665
Conversation
…vas and in the form One type-to-widget resolution, resolveBooleanControl, read by BooleanField (record form, inline edit) and the Studio canvas preview. Claude-Session: https://claude.ai/code/session_01Utp6CY2n1JmZZKrHgtp9jC Co-authored-by: Claude <noreply@anthropic.com>
…nd canvas; changeset Claude-Session: https://claude.ai/code/session_01Utp6CY2n1JmZZKrHgtp9jC Co-authored-by: Claude <noreply@anthropic.com>
…, inline edit and dialogs Claude-Session: https://claude.ai/code/session_01Utp6CY2n1JmZZKrHgtp9jC Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CY2n1JmZZKrHgtp9jC Co-authored-by: Claude <noreply@anthropic.com>
…ject-ui/fields exports Claude-Session: https://claude.ai/code/session_01Utp6CYXVQFhXabW3ZQcxWt Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Contract reviewServed-tier: Face: only the ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC 席位核对ACCEPT · head
Generated by Claude Code |
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Requested by Bill · project thread
Fixes #27519
Clause-②: yes (widening) —
@object-ui/fieldsgains two public exports,resolveBooleanControlandtype BooleanControlMetadata-protocol: none
维护者速读
boolean)创建的字段,现在在 Studio 表单画布、运行时新建/编辑表单和表格行内编辑里都画成复选框;只有「Toggle — shown as a switch」(toggle)才画开关。字段显式写了widget(checkbox/boolean或switch/toggle)时仍以widget为准。field:boolean控件,它只认widget: 'checkbox',否则一律画开关;画布又各自手写一份,toggle还掉成了文本框。分诊裁定:画布与运行时表单共用一张「类型→控件」映射,不做分面覆盖。boolean的字段(含 Setup 的元数据表单)都会从开关变成复选框,这正是分诊要求的行为;想保留开关的字段应声明为toggle或写widget: 'switch'。只改前端渲染,元数据与存储值不变。回滚即 revert 本 PR。ui/packages/fields/src/widgets/booleanControl.ts(唯一的映射);BooleanField.tsx里改为读它的那一行;ObjectFormDesigner.tsx的FieldControlPreview布尔分支。pnpm --dir ui exec vitest run packages/fields/src/__tests__/booleanControl-27519.test.tsx packages/app-shell/src/views/studio-design/ObjectFormDesigner.booleanControl-27519.test.tsx,预期全部通过。What changes
One type-to-widget resolution for the two boolean types,
resolveBooleanControl(newui/packages/fields/src/widgets/booleanControl.ts, exported from@object-ui/fields), answering'checkbox' | 'switch':widgetnaming a boolean face wins:checkbox/booleandraw a checkbox,switch/togglea switch;type, through the same four names:booleandraws a checkbox,togglea switch;field:booleanid of a hand-authored form entry, no type) draws a checkbox, thebooleantype's own face.A
widgetnaming anything else is not a boolean face and leaves the type to answer, which is the spec'sFieldSchema.widgetdegrade.Readers:
BooleanField(the record form'sfield:booleanwidget, and the grid's inline editor throughFieldEditWidget'sboolean/togglerows) draws the control the resolution names. It used to draw a switch unlesswidget === 'checkbox', so the authoredbooleanwas lost.FieldControlPreview(inObjectFormDesigner.tsx; only that function and one import line) previewsbooleanas a checkbox andtoggleas a switch from the same resolution. It used to draw the switch pill forbooleanand the empty text box fortoggle.Widget spellings:
checkboxandswitchare whatparamToFieldandScreenViewstamp and whatform.tsx's built-in arms are named; in the form those two still take the built-incheckbox/switcharms before the registry (resolveRenderableWidget, unchanged), and they draw the same control the resolution names.toggleandbooleanare accepted as widget names so a widget naming a type means that type's face.Not changed:
field-type-alias.tskeeps both types on the onefield:booleanwidget (comment updated to say the widget splits them);form.tsxneeded no change, sinceBOOLEAN_WIDGET_TYPESonly seedsfalsefor two-state rows and its built-in arms are the explicit widgets above;BooleanCellRenderer(see Acceptance notes).Changeset:
@object-ui/fieldsand@object-ui/app-shellpatch.Clause-②: yes (widening): the published@object-ui/fieldssurface gainsresolveBooleanControlandtype BooleanControl; nothing is removed or narrowed.Metadata-protocol: none: what an author can write and whatboolean/togglemean are unchanged (the spec already declares them distinct UIs); the renderer now honours the declared type.Tests
ui/packages/fields/src/__tests__/booleanControl-27519.test.tsx: the resolution's table (type defaults, the four widget overrides, a non-boolean widget leaving the type to answer, missing input),BooleanFielddrawingcheckbox/switchper type and per widget override,FieldEditWidgetdrawing the same per type.ui/packages/app-shell/src/views/studio-design/ObjectFormDesigner.booleanControl-27519.test.tsx: abooleanand atogglefield on the canvas preview a checkbox and a switch, equal toresolveBooleanControl's answer.boolean-label-association-e2e.test.tsx(the form-hosted suite now uses theObjectFormentry shape,field:booleanplus the object field, as atoggle; the two-field case hosts abooleancheckbox beside atoggleswitch; the standalone and host-id cases taketogglefor the switch variant andbooleanfor the checkbox variant),standard-widgets.test.tsx(BooleanField cases cover both types),formPageRequiredMarker-10178.test.tsxandFormPage.sharedWidgets-10179.test.tsx(abooleanrow is a checkbox),InlineFieldInput.delegation.test.tsx(booleanroutes to a checkbox; thetoggleswitch case unchanged),RequiredFieldsDialog.ariaInvalidText-7126.test.tsx(one checkbox and one switch carryaria-invalid).field-type-coverage.test.tsneeded no change and is green.Ablation (
scripts/ablation-replace.mjs, the resolution's return replaced by the oldwidget === 'checkbox' ? 'checkbox' : 'switch', anchor 1 to 0, restored to the HEAD blob withgit diff HEADempty): the two new files and the label-association file go red, 13 of 28 cases; the canvas case is among them, which shows the canvas reads the shared resolution.Acceptance notes
BooleanCellRenderer's disabled checkbox (DetailSection, "An editable boolean keeps the checkbox"), whose primitive is a square (rounded-sm) atdisabled:opacity-50; a value that is not a boolean draws the em-dashEmptyValue. The only round boolean face in the tree is the completion indicator, gated on the namescompleted/is_completed/done/is_done, whichUrgentis not. Recorded as a finding for the seat, unfiled.BooleanCellRendererdraws a disabled checkbox for bothbooleanandtoggle; atogglecell therefore reads as a checkbox in the grid. The ruling names the canvas and the runtime form, so the read-only cell face is left as it is; whether atogglecell should draw a disabled switch is the seat's call.FieldControlPreviewis handed the field'stypeonly (its caller inSortableFieldpassestype={type}), so the canvas previews by type; an authoredwidgetoverride would need that one caller line, outside the function agreed with seat 3.paramToFieldandScreenViewstill stampwidget: 'checkbox'on boolean params; with the type default now a checkbox the stamp is redundant but harmless, and both files are outside this card.Verification
Targeted tests and typecheck
Test Files 10 passed (10),Tests 227 passed (227).pnpm --dir ui exec vitest run --maxWorkers=2 packages/fields/ packages/plugin-detail/ packages/plugin-kanban/ packages/plugin-form/ packages/components/src/renderers/form/:Test Files 989 passed | 2 skipped (991),Tests 10835 passed | 43 skipped (10878)(before theorigin/mainmerge).origin/main(head302bcb25, closure rebuilt):packages/components/src/renderers/form/,packages/plugin-form/,packages/app-shell/src/views/studio-design/and the ten boolean files:Test Files 555 passed (555),Tests 4955 passed | 18 skipped (4973).type-checkfor@object-ui/fields,@object-ui/app-shell,@object-ui/plugin-detail,@object-ui/plugin-kanban: exit 0.eslint --no-inline-configon the 13 changed ui files: 0 errors (warnings only, pre-existingany).pnpm check:new-line-citations: 0 new citations.Derived gates
node scripts/pm/dispatch-gates.mjs --commandson head302bcb25: 34 families, each run with its exit code recorded, allexit 0(includingnode scripts/check-sdui-manifest.mjs,pnpm check:type-check-debtunder the verify lock, andpnpm --dir ui exec vitest run scripts/: 169 files passed).--ranreconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN.Current head
f2a547f9adds one commit on top of302bcb25that changes only the changeset'sClause-②line; on it the changeset families were re-run, allexit 0:check-adr-0087-registration --base origin/main,check-changeset-no-major --base origin/main,check-empty-changeset --base origin/main,check:changeset-gate-self-tests,check:pm-changeset-deadline-census,check:closed-ceremony-text,check:nul-bytes. The tests above were not re-run for it (no code or test line moved).Generated by Claude Code