From 67f29f490bbc9a392acffcd48e7db9eec1152847 Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Fri, 8 Dec 2023 14:35:08 +0300 Subject: [PATCH 1/3] Handle `const` like `enum` with only one option By definition `const: xxx` is equivalent to `enum: [xxx]` : https://json-schema.org/draft/2020-12/json-schema-validation#name-const , so e.g. for "abc": { "type": "string", "const": "ABC" }, "def": { "type": "string", "enum": ["DEF"] } `abc` and `def` fields should be handled in the same way via select with only one item. Fixes https://github.com/json-editor/json-editor/issues/1428 --- src/editors/enum.js | 6 ++- src/editors/multiselect.js | 7 +++- src/editors/select.js | 10 ++++- src/resolvers.js | 4 +- tests/codeceptjs/core_test.js | 49 +++++++---------------- tests/codeceptjs/editors/array_test.js | 9 +++++ tests/codeceptjs/editors/select_test.js | 6 +++ tests/pages/anyof-2.html | 2 +- tests/pages/array-multiselects-const.html | 43 ++++++++++++++++++++ tests/pages/oneof-2.html | 2 +- tests/pages/select-const.html | 40 ++++++++++++++++++ 11 files changed, 135 insertions(+), 43 deletions(-) create mode 100644 tests/pages/array-multiselects-const.html create mode 100644 tests/pages/select-const.html diff --git a/src/editors/enum.js b/src/editors/enum.js index 409caa6f0..a2fd86b3f 100644 --- a/src/editors/enum.js +++ b/src/editors/enum.js @@ -12,7 +12,11 @@ export class EnumEditor extends AbstractEditor { this.options.enum_titles = this.options.enum_titles || [] - this.enum = this.schema.enum + if (this.schema.const) { + this.enum = [this.schema.const] + } else { + this.enum = this.schema.enum + } this.selected = 0 this.select_options = [] this.html_values = [] diff --git a/src/editors/multiselect.js b/src/editors/multiselect.js index 53d57e2a0..4d573021b 100644 --- a/src/editors/multiselect.js +++ b/src/editors/multiselect.js @@ -38,7 +38,12 @@ export class MultiSelectEditor extends AbstractEditor { let i const itemsSchema = this.jsoneditor.expandRefs(this.schema.items || {}) - const e = itemsSchema.enum || [] + let e + if (itemsSchema.const) { + e = [itemsSchema.const] + } else { + e = itemsSchema.enum || [] + } const oe = itemsSchema.options ? itemsSchema.options.enum || [] : [] /* fallback to enum_titles, when options.enum is not present */ const t = itemsSchema.options ? itemsSchema.options.enum_titles || [] : [] diff --git a/src/editors/select.js b/src/editors/select.js index 535711ecb..9169980c2 100644 --- a/src/editors/select.js +++ b/src/editors/select.js @@ -73,8 +73,14 @@ export class SelectEditor extends AbstractEditor { let i let callback - /* Enum options enumerated */ - if (this.schema.enum) { + /* Const value */ + if (this.schema.const) { + const value = this.schema.const + this.enum_options = [`${value}`] + this.enum_display = [`${this.translateProperty(value) || value}`] + this.enum_values = [this.typecast(value)] + /* Enum options enumerated */ + } else if (this.schema.enum) { const display = (this.schema.options && this.schema.options.enum_titles) || [] this.schema.enum.forEach((option, i) => { diff --git a/src/resolvers.js b/src/resolvers.js index 4001931c6..91070e839 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -51,7 +51,7 @@ const enumSource = schema => { /* Use the `enum` or `select` editors for schemas with enumerated properties */ const enumeratedProperties = schema => { - if (schema.enum) { + if (schema.enum || schema.const) { if (schema.type === 'array' || schema.type === 'object') return 'enum' if (schema.type === 'number' || schema.type === 'integer' || schema.type === 'string') { if (schema.format === 'radio') return 'radio' @@ -75,7 +75,7 @@ const arraysOfStrings = (schema, je) => { /* if 'selectize' enabled it is expected to be selectized control */ if (schema.format === 'selectize') return 'arraySelectize' if (schema.format === 'select2') return 'arraySelect2' - if (schema.items.enum) return 'multiselect' /* otherwise it is select */ + if (schema.items.enum || schema.items.const) return 'multiselect' /* otherwise it is select */ } } } diff --git a/tests/codeceptjs/core_test.js b/tests/codeceptjs/core_test.js index d3900c376..b2ab9a491 100644 --- a/tests/codeceptjs/core_test.js +++ b/tests/codeceptjs/core_test.js @@ -195,71 +195,52 @@ Scenario('should display anyOf and oneOf error messages in the correct places @8 I.dontSeeElement('[data-schemapath="root.list_group"] .invalid-feedback', DEFAULT_WAIT_TIME) }) -Scenario('Should switch between all json 7 data types in @oneof and display error messages for each one @core', async ({ I }) => { +Scenario('Should switch between all json 7 data types in @oneof and set value according to specified constant for each one @core', async ({ I }) => { I.amOnPage('oneof-2.html') I.waitForElement('.je-ready') I.selectOption('.je-switcher', 'Value, string') - I.waitForValue('#value', '{"test":""}') - I.waitForText('Value must validate against exactly one of the provided schemas.') - I.waitForText('Value must be the constant value') + I.waitForValue('#value', '{"test":"test"}') I.selectOption('.je-switcher', 'Value, boolean') - I.waitForValue('#value', '{"test":false}') - I.waitForText('Value must validate against exactly one of the provided schemas.') - I.waitForText('Value must be the constant value') + I.waitForValue('#value', '{"test":true}') I.selectOption('.je-switcher', 'Value, array') - I.waitForValue('#value', '{"test":[]}') - I.waitForText('Value must validate against exactly one of the provided schemas.') - I.waitForText('Value must be the constant value') + I.waitForValue('#value', '{"test":[0]}') I.selectOption('.je-switcher', 'Value, object') - I.waitForValue('#value', '{"test":{}}') - I.waitForText('Value must validate against exactly one of the provided schemas.') - I.waitForText('Value must be the constant value') - I.waitForText('Object is missing the required property \'test\'') + I.waitForValue('#value', '{"test":{"test":"test"}}') I.selectOption('.je-switcher', 'Value, number') - I.waitForValue('#value', '{"test":0}') - I.waitForText('Value must validate against exactly one of the provided schemas.') - I.waitForText('Value must be the constant value') + I.waitForValue('#value', '{"test":1.1}') I.selectOption('.je-switcher', 'Value, integer') - I.waitForValue('#value', '{"test":0}') - I.waitForText('Value must validate against exactly one of the provided schemas.') - I.waitForText('Value must be the constant value') + I.waitForValue('#value', '{"test":1}') I.selectOption('.je-switcher', 'Value, null') I.waitForValue('#value', '{"test":null}') }) -Scenario('Should switch between all json 7 data types in @anyof and display error messages for each one @core', ({ I }) => { +Scenario('Should switch between all json 7 data types in @anyof and set value according to specified constant for each one @core', ({ I }) => { I.amOnPage('anyof-2.html') I.waitForElement('.je-ready') - I.waitForValue('#value', '{"test":""}') - I.waitForText('Value must validate against at least one of the provided schemas') + I.waitForValue('#value', '{"test":"test"}') I.selectOption('.je-switcher', 'Value, boolean') - I.waitForValue('#value', '{"test":false}') - I.waitForText('Value must validate against at least one of the provided schemas') + I.waitForValue('#value', '{"test":true}') I.selectOption('.je-switcher', 'Value, array') - I.waitForValue('#value', '{"test":[]}') - I.waitForText('Value must validate against at least one of the provided schemas') + I.waitForValue('#value', '{"test":[0]}') I.selectOption('.je-switcher', 'Value, object') - I.waitForValue('#value', '{"test":{}}') - I.waitForText('Value must validate against at least one of the provided schemas') + I.waitForValue('#value', '{"test":{"test":"test"}}') I.selectOption('.je-switcher', 'Value, number') - I.waitForValue('#value', '{"test":0}') - I.waitForText('Value must validate against at least one of the provided schemas') + I.waitForValue('#value', '{"test":1.1}') I.selectOption('.je-switcher', 'Value, integer') - I.waitForValue('#value', '{"test":0}') - I.waitForText('Value must validate against at least one of the provided schemas') + I.waitForValue('#value', '{"test":1}') I.selectOption('.je-switcher', 'Value, null') I.waitForValue('#value', '{"test":null}') @@ -383,7 +364,6 @@ Scenario('should override error messages if specified in schema options @core @e I.waitForText('Error Messages') I.waitForText('CUSTOM EN: Value required') - I.waitForText('CUSTOM EN: Value must be the constant value') I.waitForText('CUSTOM EN: Value must be at least 6 characters long') I.waitForText('CUSTOM EN: Value must be at most 6 characters long') I.waitForText('CUSTOM EN: Value must validate against at least one of the provided schemas') @@ -417,7 +397,6 @@ Scenario('should override error messages if specified in schema options @core @e I.click('Switch to ES') I.waitForText('CUSTOM ES: Value required') - I.waitForText('CUSTOM ES: Value must be the constant value') I.waitForText('CUSTOM ES: Value must be at least 6 characters long') I.waitForText('CUSTOM ES: Value must be at most 6 characters long') I.waitForText('CUSTOM ES: Value must validate against at least one of the provided schemas') diff --git a/tests/codeceptjs/editors/array_test.js b/tests/codeceptjs/editors/array_test.js index 32c190474..f84fcd31d 100644 --- a/tests/codeceptjs/editors/array_test.js +++ b/tests/codeceptjs/editors/array_test.js @@ -710,6 +710,15 @@ Scenario('should work well with multiselect editors', async ({ I }) => { I.dontSee('Multiselect 3') }) +Scenario('should handle const well in multiselect editor', async ({ I }) => { + I.amOnPage('array-multiselects-const.html') + I.click('Add Multiselect') + I.seeElement('[data-schemapath="root.0"]') + I.selectOption('[name="root[0]"]', 'abc') + I.click('.get-value') + I.waitForValue('.debug', '[["abc"]]') +}) + Scenario('should work well with object editors', async ({ I }) => { I.amOnPage('array-objects.html') I.click('Add Object') diff --git a/tests/codeceptjs/editors/select_test.js b/tests/codeceptjs/editors/select_test.js index 323e87ca9..5e6d3963d 100644 --- a/tests/codeceptjs/editors/select_test.js +++ b/tests/codeceptjs/editors/select_test.js @@ -18,3 +18,9 @@ Scenario('should be disabled if "readonly" is specified', async ({ I }) => { I.amOnPage('read-only.html') I.seeDisabledAttribute('[name="root[select]"]') }) + +Scenario('should handle const like enum with 1 item', async ({ I }) => { + I.amOnPage('select-const.html') + I.click('.get-value') + I.waitForValue('.value', '{"constval":"constant"}') +}) diff --git a/tests/pages/anyof-2.html b/tests/pages/anyof-2.html index 9ec71ed47..08b2d8e8c 100644 --- a/tests/pages/anyof-2.html +++ b/tests/pages/anyof-2.html @@ -55,7 +55,7 @@ { 'type': 'integer', 'title': 'Value, integer', - 'const': 1.1 + 'const': 1 }, { 'type': 'null', diff --git a/tests/pages/array-multiselects-const.html b/tests/pages/array-multiselects-const.html new file mode 100644 index 000000000..0ef12f0da --- /dev/null +++ b/tests/pages/array-multiselects-const.html @@ -0,0 +1,43 @@ + + + + + + + + + + +
+ + + + + + diff --git a/tests/pages/oneof-2.html b/tests/pages/oneof-2.html index 4aa342ac6..c4971e5aa 100644 --- a/tests/pages/oneof-2.html +++ b/tests/pages/oneof-2.html @@ -55,7 +55,7 @@ { 'type': 'integer', 'title': 'Value, integer', - 'const': 1.1 + 'const': 1 }, { 'type': 'null', diff --git a/tests/pages/select-const.html b/tests/pages/select-const.html new file mode 100644 index 000000000..8358fe716 --- /dev/null +++ b/tests/pages/select-const.html @@ -0,0 +1,40 @@ + + + + + wysiwyg-sceditor + + + + + + +
+ + + + + From afc29e0b60275455152a7cf37c540611001a12ce Mon Sep 17 00:00:00 2001 From: German Bisurgi <13135260+germanbisurgi@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:58:26 +0200 Subject: [PATCH 2/3] Update select.js fix lint errors --- src/editors/select.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editors/select.js b/src/editors/select.js index 68b2ef20f..202812c14 100644 --- a/src/editors/select.js +++ b/src/editors/select.js @@ -79,7 +79,7 @@ export class SelectEditor extends AbstractEditor { this.hasPlaceholderOption = this.schema?.options?.has_placeholder_option || false this.placeholderOptionText = this.schema?.options?.placeholder_option_text || ' ' - + /* Const value */ if (this.schema.const) { const value = this.schema.const From 3bb47b4d10909445dbbca0500310f0e50f1cc514 Mon Sep 17 00:00:00 2001 From: German Bisurgi <13135260+germanbisurgi@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:01:36 +0200 Subject: [PATCH 3/3] Update select.js fix linting errors --- src/editors/select.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editors/select.js b/src/editors/select.js index 202812c14..9ed262f09 100644 --- a/src/editors/select.js +++ b/src/editors/select.js @@ -76,7 +76,7 @@ export class SelectEditor extends AbstractEditor { this.enum_display = [] let i let callback - + this.hasPlaceholderOption = this.schema?.options?.has_placeholder_option || false this.placeholderOptionText = this.schema?.options?.placeholder_option_text || ' '