From 53ae7a156f46c8b26cbe7df33722ef7512f379a5 Mon Sep 17 00:00:00 2001 From: Sandrina Pereira Date: Sat, 27 Jul 2024 14:41:56 +0100 Subject: [PATCH 1/6] fix: execute new attributes only if it's "schema" key --- src/helpers.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/helpers.js b/src/helpers.js index 8eca889..2b7747e 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -244,8 +244,12 @@ function updateField(field, requiredFields, node, formValues, logic, config) { const updateAttributes = (fieldAttrs) => { Object.entries(fieldAttrs).forEach(([key, value]) => { - // some attributes' value (eg "schema") are a function, so we need to call it here - field[key] = typeof value === 'function' ? value() : value; + field[key] = value; + + if (key === 'schema' && typeof value === 'function') { + // key "schema" refers to YupSchema that needs to be processed for validations. + field[key] = value(); + } if (key === 'value') { // The value of the field should not be driven by the json-schema, From 84ac48f4f8d6589fc771979284f5cc1968792ada Mon Sep 17 00:00:00 2001 From: Sandrina Pereira Date: Sat, 27 Jul 2024 14:42:53 +0100 Subject: [PATCH 2/6] write code comments about the lack of testing for the key "value" --- src/helpers.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helpers.js b/src/helpers.js index 2b7747e..38a8889 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -252,6 +252,10 @@ function updateField(field, requiredFields, node, formValues, logic, config) { } if (key === 'value') { + /* NOTE/TODO: This section does not have any unit test. Be careful when changing this. + You'll need to check the internal MRs !9266 and !6572 (or other through git blame) + to better understand the reason. Then try to remove this workaround and/or write comprehensive unit tests. */ + // The value of the field should not be driven by the json-schema, // unless it's a read-only field // If the readOnly property has changed, use that updated value, From a8e43ac772c182d920f971bfa4097579b72dbbb8 Mon Sep 17 00:00:00 2001 From: Sandrina Pereira Date: Sat, 27 Jul 2024 14:56:40 +0100 Subject: [PATCH 3/6] write test about conditional fields with custom attributes as functions --- src/tests/createHeadlessForm.test.js | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/tests/createHeadlessForm.test.js b/src/tests/createHeadlessForm.test.js index 061043d..f038e0a 100644 --- a/src/tests/createHeadlessForm.test.js +++ b/src/tests/createHeadlessForm.test.js @@ -2177,6 +2177,68 @@ describe('createHeadlessForm', () => { }); }); + it('pass custom attributes as function', () => { + // Any custom attributes must be inside "x-jsf-presentation" + const { fields, handleValidation } = createHeadlessForm({ + properties: { + field_a: { + title: 'A field', + 'x-jsf-presentation': { + inputType: 'text', + }, + }, + field_b: { + title: 'Field B', + 'x-jsf-presentation': { + inputType: 'text', + MyComponent: (props) => { + // Return a custom component, react, svelte, etc. + // This is just a fake dummy example + const { label, description } = props; + return `A React component with ${label} and ${description}`; + }, + }, + }, + }, + allOf: [ + { + if: { + properties: { + field_a: { const: 'yes' }, + }, + required: ['field_a'], + }, + then: { + required: ['field_b'], + }, + }, + ], + }); + + const fieldB = getField(fields, 'field_b'); + expect(fieldB).toMatchObject({ + label: 'Field B', + required: false, + MyComponent: expect.any(Function), + }); + + const fakeProps = { label: 'Field B', description: 'fake description' }; + expect(fieldB.MyComponent(fakeProps)).toBe( + 'A React component with Field B and fake description' + ); + + // Ensure "MyComponent" attribute still exsits after a validation cycle. + // This covers the updateField(). Check PR for more context. + handleValidation({ field_a: 'yes' }); + + const fieldBVisible = getField(fields, 'field_b'); + + expect(fieldBVisible).toMatchObject({ + required: true, + MyComponent: expect.any(Function), + }); + }); + it('passes scopedJsonSchema to each field', () => { const { fields } = createHeadlessForm(schemaWithoutInputTypes, { strictInputType: false, From 6412160803d4aae933b484ad88d2f30af19387ac Mon Sep 17 00:00:00 2001 From: Sandrina Pereira Date: Mon, 29 Jul 2024 10:31:05 +0100 Subject: [PATCH 4/6] self-review --- src/tests/createHeadlessForm.test.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/tests/createHeadlessForm.test.js b/src/tests/createHeadlessForm.test.js index f038e0a..872309d 100644 --- a/src/tests/createHeadlessForm.test.js +++ b/src/tests/createHeadlessForm.test.js @@ -2178,25 +2178,25 @@ describe('createHeadlessForm', () => { }); it('pass custom attributes as function', () => { + function FakeComponent(props) { + const { label, description } = props; + return `A React component with ${label} and ${description}`; + } // Any custom attributes must be inside "x-jsf-presentation" const { fields, handleValidation } = createHeadlessForm({ properties: { field_a: { - title: 'A field', + title: 'Field A', 'x-jsf-presentation': { inputType: 'text', + MyComponent: FakeComponent, }, }, field_b: { title: 'Field B', 'x-jsf-presentation': { inputType: 'text', - MyComponent: (props) => { - // Return a custom component, react, svelte, etc. - // This is just a fake dummy example - const { label, description } = props; - return `A React component with ${label} and ${description}`; - }, + MyComponent: FakeComponent, }, }, }, @@ -2215,6 +2215,12 @@ describe('createHeadlessForm', () => { ], }); + const fieldA = getField(fields, 'field_a'); + expect(fieldA).toMatchObject({ + label: 'Field A', + MyComponent: expect.any(Function), + }); + const fieldB = getField(fields, 'field_b'); expect(fieldB).toMatchObject({ label: 'Field B', @@ -2231,9 +2237,10 @@ describe('createHeadlessForm', () => { // This covers the updateField(). Check PR for more context. handleValidation({ field_a: 'yes' }); - const fieldBVisible = getField(fields, 'field_b'); - - expect(fieldBVisible).toMatchObject({ + expect(getField(fields, 'field_a')).toMatchObject({ + MyComponent: expect.any(Function), + }); + expect(getField(fields, 'field_b')).toMatchObject({ required: true, MyComponent: expect.any(Function), }); From bf20af485a2500174a08b0bf2d97931597290b02 Mon Sep 17 00:00:00 2001 From: Sandrina Pereira Date: Mon, 29 Jul 2024 11:42:23 +0100 Subject: [PATCH 5/6] Release 0.11.2-dev.20240729104214 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9aaeb8..0fac316 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.11.1-beta.0", + "version": "0.11.2-dev.20240729104214", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@remoteoss/json-schema-form", - "version": "0.11.1-beta.0", + "version": "0.11.2-dev.20240729104214", "license": "MIT", "dependencies": { "json-logic-js": "^2.0.2", diff --git a/package.json b/package.json index 9a8b860..ccdf247 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.11.1-beta.0", + "version": "0.11.2-dev.20240729104214", "description": "Headless UI form powered by JSON Schemas", "author": "Remote.com (https://remote.com/)", "license": "MIT", From 24b30067b45c90acb59c0f10d866e90f3190693d Mon Sep 17 00:00:00 2001 From: Sandrina Pereira Date: Tue, 30 Jul 2024 12:27:51 +0100 Subject: [PATCH 6/6] Revert back to 0.11.1-beta.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0fac316..a9aaeb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.11.2-dev.20240729104214", + "version": "0.11.1-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@remoteoss/json-schema-form", - "version": "0.11.2-dev.20240729104214", + "version": "0.11.1-beta.0", "license": "MIT", "dependencies": { "json-logic-js": "^2.0.2", diff --git a/package.json b/package.json index ccdf247..9a8b860 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@remoteoss/json-schema-form", - "version": "0.11.2-dev.20240729104214", + "version": "0.11.1-beta.0", "description": "Headless UI form powered by JSON Schemas", "author": "Remote.com (https://remote.com/)", "license": "MIT",