From 571c67a4cce5d1bf7b704279d5773e1dd2e0813c Mon Sep 17 00:00:00 2001 From: Valentin Serra Date: Fri, 29 Dec 2023 08:32:51 +0100 Subject: [PATCH] fix: properly handle all formats of options sources Closes #960 --- package-lock.json | 110 ++++++--- packages/form-js-viewer/package.json | 1 + .../components/form-fields/Checklist.js | 22 +- .../render/components/form-fields/Radio.js | 6 +- .../render/components/form-fields/Taglist.js | 25 ++- .../form-fields/parts/SearchableSelect.js | 32 +-- .../form-fields/parts/SimpleSelect.js | 6 +- .../src/render/components/util/optionsUtil.js | 62 ++++-- .../render/components/util/sanitizerUtil.js | 14 +- .../hooks/useCleanupMultiSelectValues.js | 6 +- .../hooks/useCleanupSingleSelectValue.js | 4 +- .../render/hooks/useGetLabelCorrelation.js | 17 ++ .../components/form-fields/Checklist.spec.js | 208 +++++++++++++++++- .../components/form-fields/Radio.spec.js | 33 +++ .../form-fields/util/optionsUtil.spec.js | 56 ++++- 15 files changed, 499 insertions(+), 103 deletions(-) create mode 100644 packages/form-js-viewer/src/render/hooks/useGetLabelCorrelation.js diff --git a/package-lock.json b/package-lock.json index 4afbab392..4db75eb08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9411,25 +9411,32 @@ } }, "node_modules/deep-equal": { - "version": "2.1.0", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", - "which-typed-array": "^1.1.8" + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10420,18 +10427,20 @@ } }, "node_modules/es-get-iterator": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", "is-map": "^2.0.2", "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10439,8 +10448,9 @@ }, "node_modules/es-get-iterator/node_modules/isarray": { "version": "2.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/es-module-lexer": { "version": "1.3.0", @@ -12864,8 +12874,9 @@ }, "node_modules/is-arguments": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -16180,8 +16191,7 @@ "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" }, "node_modules/lodash.ismatch": { "version": "4.4.0", @@ -20121,6 +20131,18 @@ "node": ">= 0.8" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/streamroller": { "version": "3.1.1", "dev": true, @@ -22131,6 +22153,7 @@ "feelin": "^3.0.0", "flatpickr": "^4.6.13", "ids": "^1.0.0", + "lodash.isequal": "^4.5.0", "min-dash": "^4.0.0", "preact": "^10.5.14", "preact-markup": "^2.1.1", @@ -23703,6 +23726,7 @@ "feelin": "^3.0.0", "flatpickr": "^4.6.13", "ids": "^1.0.0", + "lodash.isequal": "^4.5.0", "min-dash": "^4.0.0", "preact": "^10.5.14", "preact-markup": "^2.1.1", @@ -28867,24 +28891,29 @@ } }, "deep-equal": { - "version": "2.1.0", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", - "which-typed-array": "^1.1.8" + "which-typed-array": "^1.1.13" }, "dependencies": { "isarray": { @@ -29533,21 +29562,26 @@ } }, "es-get-iterator": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "dev": true, "requires": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", "is-map": "^2.0.2", "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" }, "dependencies": { "isarray": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true } } @@ -31206,6 +31240,8 @@ }, "is-arguments": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -33553,8 +33589,7 @@ "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" }, "lodash.ismatch": { "version": "4.4.0", @@ -36220,6 +36255,15 @@ "version": "2.0.1", "dev": true }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "requires": { + "internal-slot": "^1.0.4" + } + }, "streamroller": { "version": "3.1.1", "dev": true, diff --git a/packages/form-js-viewer/package.json b/packages/form-js-viewer/package.json index cce291672..9c68f06ad 100644 --- a/packages/form-js-viewer/package.json +++ b/packages/form-js-viewer/package.json @@ -52,6 +52,7 @@ "feelin": "^3.0.0", "flatpickr": "^4.6.13", "ids": "^1.0.0", + "lodash.isequal": "^4.5.0", "min-dash": "^4.0.0", "preact": "^10.5.14", "preact-markup": "^2.1.1", diff --git a/packages/form-js-viewer/src/render/components/form-fields/Checklist.js b/packages/form-js-viewer/src/render/components/form-fields/Checklist.js index 7263ed7cf..d6eea2435 100644 --- a/packages/form-js-viewer/src/render/components/form-fields/Checklist.js +++ b/packages/form-js-viewer/src/render/components/form-fields/Checklist.js @@ -2,12 +2,13 @@ import { useRef } from 'preact/hooks'; import useOptionsAsync, { LOAD_STATES } from '../../hooks/useOptionsAsync'; import useCleanupMultiSelectValues from '../../hooks/useCleanupMultiSelectValues'; import classNames from 'classnames'; +import isEqual from 'lodash/isEqual'; import Description from '../Description'; import Errors from '../Errors'; import Label from '../Label'; -import { sanitizeMultiSelectValue } from '../util/sanitizerUtil'; +import { sanitizeMultiSelectValue, hasEqualValue } from '../util/sanitizerUtil'; import { createEmptyOptions } from '../util/optionsUtil'; @@ -41,19 +42,15 @@ export default function Checklist(props) { const { required } = validate; - const toggleCheckbox = (v) => { + const toggleCheckbox = (toggledValue) => { - let newValue = [ ...values ]; - - if (!newValue.includes(v)) { - newValue.push(v); - } else { - newValue = newValue.filter(x => x != v); - } + const newValues = hasEqualValue(toggledValue, values) + ? values.filter(value => !isEqual(value, toggledValue)) + : [ ...values, toggledValue ]; props.onChange({ field, - value: newValue, + value: newValues, }); }; @@ -96,17 +93,18 @@ export default function Checklist(props) { loadState == LOAD_STATES.LOADED && options.map((o, index) => { const itemDomId = `${domId}-${index}`; + const isChecked = hasEqualValue(o.value, values); return (