From 44b2ccd2573a191fd894ce3c7bdb167ab50ecd0a Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 26 Aug 2026 07:10:42 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20address=20Copilot=20review=20round=2019?= =?UTF-8?q?=20=E2=80=94=20empty-string=20const=20in=20the=20web=20required?= =?UTF-8?q?=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hasMissingRequiredFields treated every empty string as missing, so a required field the schema pins to `""` — rendered read-only, and seeded with the only value it accepts — left Execute and Open App permanently disabled. It now matches the TUI check: an empty string counts as supplied when the property's own `const` pins it there, and an ordinary blank required string still does not. Signed-off-by: cliffhall --- clients/web/src/utils/jsonUtils.test.ts | 22 ++++++++++++++++++++++ clients/web/src/utils/jsonUtils.ts | 8 +++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/clients/web/src/utils/jsonUtils.test.ts b/clients/web/src/utils/jsonUtils.test.ts index 82614c34..0178ff12 100644 --- a/clients/web/src/utils/jsonUtils.test.ts +++ b/clients/web/src/utils/jsonUtils.test.ts @@ -488,6 +488,28 @@ describe("root composition (#2123)", () => { ).toBe(values); }); + it("accepts an empty string a const pins the field to", () => { + // Rendered read-only, so treating the seeded value as missing would + // disable submit on a value the user cannot change. + const pinnedEmpty: InspectorFormSchema = { + type: "object", + properties: { kind: { type: "string", const: "" } }, + required: ["kind"], + }; + expect(hasMissingRequiredFields(pinnedEmpty, { kind: "" })).toBe(false); + // An ordinary required string is still missing when left blank. + expect( + hasMissingRequiredFields( + { + type: "object", + properties: { kind: { type: "string" } }, + required: ["kind"], + }, + { kind: "" }, + ), + ).toBe(true); + }); + it("blocks submission while no branch is satisfied", () => { expect(hasMissingRequiredFields(UNION, {})).toBe(true); expect(hasMissingRequiredFields(UNION, { kind: "email" })).toBe(true); diff --git a/clients/web/src/utils/jsonUtils.ts b/clients/web/src/utils/jsonUtils.ts index a93f330c..85d0d00c 100644 --- a/clients/web/src/utils/jsonUtils.ts +++ b/clients/web/src/utils/jsonUtils.ts @@ -292,7 +292,13 @@ function hasMissingIn( const fieldSchema = properties[field]; return fieldSchema === undefined ? true : !admitsNull(fieldSchema); } - return value === undefined || value === ""; + if (value === "") { + // A schema may pin a field to the empty string, and the form renders such + // a field read-only — so reporting the seeded value as missing would + // disable submit on a value the user cannot change (#2123). + return properties[field]?.const !== ""; + } + return value === undefined; }); }