From ffa08d76f54cece5b75841f3689fd3ec3859bee2 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 26 Aug 2026 13:09:54 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20address=20Copilot=20review=20round=2033?= =?UTF-8?q?=20=E2=80=94=20keep=20a=20cleared=20field=20cleared=20across=20?= =?UTF-8?q?a=20branch=20switch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The carry filter dropped a name whose value was `undefined`, but clearing a number or JSON field leaves exactly that: the name present with no value, which is the user's answer rather than an absence. The incoming branch's defaults then put the field's default back and undid the clear. Own-property presence alone is now the test. Signed-off-by: cliffhall --- .../groups/SchemaForm/SchemaForm.test.tsx | 25 +++++++++++++++++++ .../groups/SchemaForm/SchemaForm.tsx | 5 +++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx index 575c52d0..0d492714 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx @@ -2291,6 +2291,31 @@ describe("SchemaForm multiline strings (#2042)", () => { expect(onChange).not.toHaveBeenCalled(); }); + it("keeps a cleared root field cleared across a branch switch", async () => { + const user = userEvent.setup(); + const onChange = vi.fn(); + const schema: InspectorFormSchema = { + type: "object", + properties: { count: { type: "number", default: 7, title: "Count" } }, + anyOf: [ + { type: "object", title: "A", properties: { x: {} } }, + { type: "object", title: "B", properties: { y: {} } }, + ], + }; + renderWithMantine( + , + ); + await user.click(screen.getByRole("textbox", { name: /Variant/ })); + await user.click(screen.getByRole("option", { name: "B" })); + expect(onChange).toHaveBeenCalledWith({ count: undefined }); + }); + it("renders no picker for a single-branch union but still shows its fields", () => { const schema: InspectorFormSchema = { type: "object", diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx index 8dfde16f..7cd2b174 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx @@ -799,8 +799,11 @@ export function SchemaForm({ Object.entries(nextProperties) .filter( ([name, fieldSchema]) => + // Own-property presence alone, `undefined` included: clearing a + // number or JSON field leaves the name present with no value, and + // that is the user's answer. Dropping it would let the defaults + // below put the field's default back and undo the clear. Object.hasOwn(values, name) && - values[name] !== undefined && fieldSchema.const === undefined && // Carried only where the incoming branch leaves the root's // declaration as it found it. Anything the incoming branch declares