diff --git a/lib/DataHarmonizer.js b/lib/DataHarmonizer.js index 1f38186b..406dc61e 100644 --- a/lib/DataHarmonizer.js +++ b/lib/DataHarmonizer.js @@ -364,15 +364,15 @@ class DataHarmonizer { this.setExportField(new_field, true); /* https://linkml.io/linkml-model/docs/structured_pattern/ - https://github.com/linkml/linkml/issues/674 - Look up its parts in "settings", and assemble a regular - expression for them to compile into "pattern" field. - This augments basic datatype validation - structured_pattern: - syntax: "{float} {unit.length}" - interpolated: true ## all {...}s are replaced using settings - partial_match: false - */ + https://github.com/linkml/linkml/issues/674 + Look up its parts in "settings", and assemble a regular + expression for them to compile into "pattern" field. + This augments basic datatype validation + structured_pattern: + syntax: "{float} {unit.length}" + interpolated: true ## all {...}s are replaced using settings + partial_match: false + */ if ('structured_pattern' in new_field) { switch (new_field.structured_pattern.syntax) { case '{UPPER_CASE}': @@ -559,14 +559,16 @@ class DataHarmonizer { addRowsToBottom(numRows) { this.runBehindLoadingScreen(() => { - this.hot.alter('insert_row', this.hot.countRows() - 1 + numRows, numRows); + this.hot.alter('insert_row_below', this.hot.countRows() - 1 + numRows, numRows); }); } showAllColumns() { this.hot.scrollViewportTo(0, 1); const hiddenColsPlugin = this.hot.getPlugin('hiddenColumns'); - hiddenColsPlugin.showColumns(hiddenColsPlugin.hiddenColumns); + const hidden = hiddenColsPlugin.getHiddenColumns(); + if (hidden) + hiddenColsPlugin.showColumns(hidden); this.hot.render(); } @@ -626,7 +628,8 @@ class DataHarmonizer { // Un-hide all currently hidden cols const hiddenRowsPlugin = this.hot.getPlugin('hiddenRows'); - hiddenRowsPlugin.showRows(hiddenRowsPlugin.hiddenRows); + const hidden = hiddenRowsPlugin.getHiddenRows(); + hiddenRowsPlugin.showRows(hidden); // Hide user-specified rows const rows = [...Array(this.hot.countRows()).keys()]; @@ -818,8 +821,9 @@ class DataHarmonizer { * @param {Object} hot Handsontable instance of grid. */ scrollTo(row, column) { - const hiddenCols = this.hot.getPlugin('hiddenColumns').hiddenColumns; - if (hiddenCols.includes(column)) { + const hiddenColsPlugin = this.hot.getPlugin('hiddenColumns'); + const hidden = hiddenColsPlugin.getHiddenColumns(); + if (hidden.includes(column)) { // If user wants to scroll to a hidden column, make all columns unhidden this.showAllColumns(); } @@ -1671,9 +1675,9 @@ class DataHarmonizer { } // This will output a list of fields added to exportHeaders by way of template specification which haven't been included in export.js //if (field_message) - // console.log('Export fields added by template:', field_message) + // console.log('Export fields added by template:', field_message) //if (field_export_message) - // console.log('Export fields stated in export.js):', field_export_message) + // console.log('Export fields stated in export.js):', field_export_message) } /** @@ -2049,15 +2053,15 @@ class DataHarmonizer { } /** - * Adjust given dateString date to match year or month granularity given by - * dateGranularity parameter. If month unit required but not supplied, then - * a yyyy-__-01 will be supplied to indicate that month needs attention. - * - * @param {String} dateGranularity, either 'year' or 'month' - * @param {String} ISO 8601 date string or leading part, possibly just YYYY or - YYYY-MM - * @return {String} ISO 8601 date string. - */ + * Adjust given dateString date to match year or month granularity given by + * dateGranularity parameter. If month unit required but not supplied, then + * a yyyy-__-01 will be supplied to indicate that month needs attention. + * + * @param {String} dateGranularity, either 'year' or 'month' + * @param {String} ISO 8601 date string or leading part, possibly just YYYY or + YYYY-MM + * @return {String} ISO 8601 date string. + */ setDateChange(dateGranularity, dateString, dateBlank = '__') { var dateParts = dateString.split('-'); // Incomming date may have nothing in it. @@ -2205,6 +2209,10 @@ class DataHarmonizer { ? this.template.annotations.version : this.schema.version); + // See https://handsontable.com/docs/javascript-data-grid/batch-operations/ + // Rendering is executed after all of the operations such as are completed + this.hot.batch(() => { + for (let row = 0; row < this.hot.countRows(); row++) { if (this.hot.isEmptyRow(row)) continue; @@ -2373,6 +2381,7 @@ class DataHarmonizer { } // row loop end // Check row uniqueness for identifier fields and unique_key sets + // This is not affected by a column's datatype. const doUniqueValidation = (columnNumbers) => { const values = columnNumbers.map((columnNumber) => { if (columnNumber < 0) { @@ -2397,6 +2406,7 @@ class DataHarmonizer { }); }; + // Returns FIRST index for a field marked as an .identifier const identifierFieldCol = fields.findIndex( (field) => field.identifier && field.identifier === true ); @@ -2404,6 +2414,9 @@ class DataHarmonizer { doUniqueValidation([identifierFieldCol]); } + // .template_unique_keys contains an object of 0 or more unique keys, + // each key being a combination of one or more .unique_key_slots names. + // Does unique validation on each unique key combo. for (const unique_key of this.template_unique_keys) { const uniqueKeyCols = unique_key.unique_key_slots.map((fieldName) => { return fields.findIndex((field) => field.name === fieldName); @@ -2412,7 +2425,11 @@ class DataHarmonizer { } // Here an array of (row, column, value)... is being passed - if (provenanceChanges.length) this.hot.setDataAtCell(provenanceChanges); + if (provenanceChanges.length) + this.hot.setDataAtCell(provenanceChanges); + + }); + return invalidCells; } diff --git a/package.json b/package.json index 0bbb0454..52ad1266 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "date-fns": "^2.28.0", "file-saver": "^2.0.5", "flatpickr": "^4.6.13", - "handsontable": "^7.4.2", + "handsontable": "13.1.0", "sifter": "^0.5.4", "xlsx": "^0.18.5" }, diff --git a/yarn.lock b/yarn.lock index aba7d5e9..24cddfa4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1032,14 +1032,6 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@handsontable/formulajs@^2.0.2": - version "2.0.2" - resolved "https://registry.npmjs.org/@handsontable/formulajs/-/formulajs-2.0.2.tgz" - integrity sha512-maIyMJtYjA5e/R9nyA22Qd7Yw73MBSxClJvle0a8XWAS/5l6shc/OFpQqrmwMy4IXUCmywJ9ER0gOGz/YA720w== - dependencies: - bessel "^1.0.2" - jstat "^1.9.2" - "@humanwhocodes/config-array@^0.9.2": version "0.9.5" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz" @@ -1635,7 +1627,7 @@ "@types/pikaday@1.7.4": version "1.7.4" - resolved "https://registry.npmjs.org/@types/pikaday/-/pikaday-1.7.4.tgz" + resolved "https://registry.yarnpkg.com/@types/pikaday/-/pikaday-1.7.4.tgz#aa41f928f0f5af31a4a656f471a78177a9260abf" integrity sha512-0KsHVyw5pTG829nqG4IRu7m+BFQlFEBdbE/1i3S5182HeKUKv1uEW0gyEmkJVp5i4IV+9pyh23O83+KpRkSQbw== dependencies: moment ">=2.14.0" @@ -2168,14 +2160,9 @@ batch@0.6.1: resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== -bessel@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/bessel/-/bessel-1.0.2.tgz" - integrity sha512-Al3nHGQGqDYqqinXhQzmwmcRToe/3WyBv4N8aZc5Pef8xw2neZlR9VPi84Sa23JtgWcucu18HxVZrnI0fn2etw== - bignumber.js@^8.0.1: version "8.1.1" - resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.1.1.tgz#4b072ae5aea9c20f6730e4e5d529df1271c4d885" integrity sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ== binary-extensions@^2.0.0: @@ -2380,6 +2367,13 @@ char-regex@^1.0.2: resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chevrotain@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-6.5.0.tgz#dcbef415516b0af80fd423cc0d96b28d3f11374e" + integrity sha512-BwqQ/AgmKJ8jcMEjaSnfMybnKMgGTrtDKowfTP3pX4jwVy0kNjRsT/AP6h+wC3+3NC+X8X15VWBnTCQlX+wQFg== + dependencies: + regexp-to-ast "0.4.0" + chokidar@^3.4.0, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" @@ -2593,10 +2587,10 @@ core-js-compat@^3.21.0, core-js-compat@^3.22.1: browserslist "^4.21.3" semver "7.0.0" -core-js@^3.0.0: - version "3.23.2" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.23.2.tgz" - integrity sha512-ELJOWxNrJfOH/WK4VJ3Qd+fOqZuOuDNDJz0xG6Bt4mGg2eO/UT9CljCrbqDGovjLKUrGajEEBcoTOc0w+yBYeQ== +core-js@^3.31.1: + version "3.32.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.2.tgz#172fb5949ef468f93b4be7841af6ab1f21992db7" + integrity sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ== core-util-is@~1.0.0: version "1.0.3" @@ -2885,6 +2879,11 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: dependencies: domelementtype "^2.2.0" +dompurify@^2.1.1: + version "2.4.7" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.7.tgz#277adeb40a2c84be2d42a8bcd45f582bfa4d0cfc" + integrity sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ== + domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" @@ -3498,17 +3497,19 @@ handle-thing@^2.0.0: resolved "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz" integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== -handsontable@^7.4.2: - version "7.4.2" - resolved "https://registry.npmjs.org/handsontable/-/handsontable-7.4.2.tgz" - integrity sha512-xJ81nZfXWHmS+K8/Eshj776MQSe8003iue1hHumgb0bnJmG/WLOxRpN+Vurdl/WPwI3+fQOqb9nTzmM5n/LI2g== +handsontable@13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/handsontable/-/handsontable-13.1.0.tgz#a820d331088a9e4a7db9f4974661208f51789771" + integrity sha512-KqJtS3rJeOWsFWCffnDlM8fcLMTqmW+Vbc7OCVM4X7dYDpfefgFerjNLIxLfT9xohcQoUOS1jcvXwV8dwSppVQ== dependencies: "@types/pikaday" "1.7.4" - core-js "^3.0.0" - hot-formula-parser "^3.0.1" - moment "2.24.0" + core-js "^3.31.1" + dompurify "^2.1.1" + moment "2.29.4" numbro "2.1.2" - pikaday "1.8.0" + pikaday "1.8.2" + optionalDependencies: + hyperformula "^2.4.0" has-flag@^3.0.0: version "3.0.0" @@ -3544,14 +3545,6 @@ he@^1.2.0: resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hot-formula-parser@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/hot-formula-parser/-/hot-formula-parser-3.0.2.tgz" - integrity sha512-W/Dj/UbIyuViMIQOQD6tUEVySl7jd6ei+gfWslTiRqa4yRhkyHnIz8N4oLnqgDRhhVAQIcFF5NfNz49k4X8IxQ== - dependencies: - "@handsontable/formulajs" "^2.0.2" - tiny-emitter "^2.1.0" - hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz" @@ -3667,6 +3660,15 @@ humanize@^0.0.9: resolved "https://registry.npmjs.org/humanize/-/humanize-0.0.9.tgz" integrity sha512-bvZZ7vXpr1RKoImjuQ45hJb5OvE2oJafHysiD/AL3nkqTZH2hFCjQ3YZfCd63FefDitbJze/ispUPP0gfDsT2Q== +hyperformula@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hyperformula/-/hyperformula-2.5.0.tgz#b4c88de766ed5f6fb9f811ff4ef02290fbfe3a76" + integrity sha512-HkP7JZAmG7EQFF5XAhB3aGtTHvafblSRITTMYUsVoT9czIvYY7CvMQFfK1JNHJUVS844t8bnJpKEOqwcgBcHZg== + dependencies: + chevrotain "^6.5.0" + tiny-emitter "^2.1.0" + unorm "^1.6.0" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -4346,11 +4348,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jstat@^1.9.2: - version "1.9.5" - resolved "https://registry.npmjs.org/jstat/-/jstat-1.9.5.tgz" - integrity sha512-cWnp4vObF5GmB2XsIEzxI/1ZTcYlcfNqxQ/9Fp5KFUa0Jf/4tO0ZkGVnqoEHDisJvYgvn5n3eWZbd2xTVJJPUQ== - kind-of@^6.0.2: version "6.0.3" resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" @@ -4558,15 +4555,10 @@ minimist@~0.0.1: resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" integrity sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw== -moment@2.24.0: - version "2.24.0" - resolved "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz" - integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== - -moment@>=2.14.0: - version "2.29.3" - resolved "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz" - integrity sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw== +moment@2.29.4, moment@>=2.14.0: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== ms@2.0.0: version "2.0.0" @@ -4665,7 +4657,7 @@ nth-check@^2.0.1: numbro@2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/numbro/-/numbro-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/numbro/-/numbro-2.1.2.tgz#2d51104f09b5d69aef7e15bb565d7795e47ecfd6" integrity sha512-7w833BxZmKGLE9HI0aREtNVRVH6WTYUUlWf4qgA5gKNhPQ4F/MRZ14sc0v8eoLORprk9ZTVwYaLwj8N3Zgxwiw== dependencies: bignumber.js "^8.0.1" @@ -4894,10 +4886,10 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pikaday@1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/pikaday/-/pikaday-1.8.0.tgz" - integrity sha512-SgGxMYX0NHj9oQnMaSyAipr2gOrbB4Lfs/TJTb6H6hRHs39/5c5VZi73Q8hr53+vWjdn6HzkWcj8Vtl3c9ziaA== +pikaday@1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/pikaday/-/pikaday-1.8.2.tgz#72cc73fab7ccc068cbdf7dcaa1ce400fcfd894e3" + integrity sha512-TNtsE+34BIax3WtkB/qqu5uepV1McKYEgvL3kWzU7aqPCpMEN6rBF3AOwu4WCwAealWlBGobXny/9kJb49C1ew== pirates@^4.0.4: version "4.0.5" @@ -5340,6 +5332,11 @@ regenerator-transform@^0.15.0: dependencies: "@babel/runtime" "^7.8.4" +regexp-to-ast@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz#f3dbcb42726cd71902ba50193f63eab5325cd7cb" + integrity sha512-4qf/7IsIKfSNHQXSwial1IFmfM1Cc/whNBQqRwe0V2stPe7KmN1U0tWQiIx6JiirgSrisjE0eECdNf7Tav1Ntw== + regexpp@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" @@ -5990,7 +5987,7 @@ thunky@^1.0.2: tiny-emitter@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== tmpl@1.0.5: @@ -6090,6 +6087,11 @@ universalify@^2.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unorm@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" + integrity sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"