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; }); }