From 9385d19bd1047fbd39cc8f8ea8336926258a1710 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Mon, 9 Dec 2024 14:48:29 +0100 Subject: [PATCH 01/15] Implemented deferred bounce method --- webpack/app/widgets/queryselect/widget.js | 43 ++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/webpack/app/widgets/queryselect/widget.js b/webpack/app/widgets/queryselect/widget.js index ea1a473b0b..b010406967 100644 --- a/webpack/app/widgets/queryselect/widget.js +++ b/webpack/app/widgets/queryselect/widget.js @@ -119,19 +119,54 @@ class QuerySelectWidgetController extends React.Component { /* * Throttle wrapper + * + * @returns {Promise} */ debounce(func) { - let timer; + let timer = null; + const context = this; + let deferred = null; + return function (...args) { - const context = this; - if (timer) clearTimeout(timer); + // clear the timer + if (timer) { + clearTimeout(timer); + } + + // deferred promise that is returned to the caller + deferred = this.create_deferred() + timer = setTimeout(() => { + // resolve the promise + Promise.resolve(func.apply(context, args)) + .then(deferred.resolve) + .catch(deferred.reject) + // reset timer and promise timer = null; - func.apply(context, args); + deferred = null; }, 500); + + return deferred.promise; }; }; + + /* + * Helper method to create a deferred object + * + * @returns {Object} of promise, resolve, reject + */ + create_deferred() { + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve, reject }; + } + + /* * Fix overflow at the bottom or at the right of the container */ From 0a373a18bd70a1d3989912ec1ca364dded0827c5 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Mon, 9 Dec 2024 14:50:06 +0100 Subject: [PATCH 02/15] Refactoring --- webpack/app/widgets/queryselect/widget.js | 56 +++++++++++++++++++---- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/webpack/app/widgets/queryselect/widget.js b/webpack/app/widgets/queryselect/widget.js index b010406967..c315265532 100644 --- a/webpack/app/widgets/queryselect/widget.js +++ b/webpack/app/widgets/queryselect/widget.js @@ -276,6 +276,26 @@ class QuerySelectWidgetController extends React.Component { } + /* + * Check if the passed object is an array + * + * @returns {Boolean} true/false if object is an Array + */ + is_array(obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + } + + + /* + * Check if the passed object is an object + * + * @returns {Boolean} true/false if object is an Object + */ + is_object(obj) { + return Object.prototype.toString.call(obj) === '[object Object]' + } + + /* * Returns if the field accepts single values only * @@ -296,6 +316,16 @@ class QuerySelectWidgetController extends React.Component { } + /* + * Check if the field has a value set + * + * @returns {Boolean} true/false if a value is set or not + */ + has_value() { + return this.state.values.length > 0; + } + + /* * Checks if the field should be rendered as disabled * @@ -308,7 +338,7 @@ class QuerySelectWidgetController extends React.Component { if (this.state.readonly) { return true; } - if (this.is_single_valued() && this.state.values.length > 0) { + if (this.is_single_valued() && this.has_value()) { return true; } return false; @@ -327,7 +357,7 @@ class QuerySelectWidgetController extends React.Component { if (this.state.readonly) { return false; } - if (this.is_single_valued() && this.state.values.length > 0) { + if (this.is_single_valued() && this.has_value()) { return false; } return true; @@ -354,6 +384,16 @@ class QuerySelectWidgetController extends React.Component { } + /* + * Returns the item value key + * + * @returns {String} name + */ + get_item_value_key() { + return this.state.value_key; + } + + /* * Create a query object for the API * @@ -591,12 +631,12 @@ class QuerySelectWidgetController extends React.Component { * Add/remove the focused result * */ - select_focused(searchvalue) { + select_focused() { console.debug("QuerySelectWidgetController::select_focused"); let focused = this.state.focused; let result = this.state.results.at(focused); if (result) { - let value = result[this.state.value_key]; + let value = result[this.get_item_value_key()]; if (this.state.values.indexOf(value) == -1) { this.select(value); } else { @@ -778,7 +818,7 @@ class QuerySelectWidgetController extends React.Component { // for stored UIDs when the edit form is initially rendered let records = Object.assign(this.state.records, {}) for (let item of items) { - let value = item[this.state.value_key]; + let value = item[this.get_item_value_key()]; records[value] = item; } @@ -832,7 +872,7 @@ class QuerySelectWidgetController extends React.Component { promise.then((data) => { let items = data.items || []; for (let item of items) { - let value = item[this.state.value_key]; + let value = item[this.get_item_value_key()]; records[value] = item; } this.toggle_loading(false); @@ -892,7 +932,7 @@ class QuerySelectWidgetController extends React.Component { */ on_sync(event) { let values = event.detail.values || []; - let is_array = {}.toString.call( values ) === '[object Array]'; + let is_array = this.is_array(values) if (!is_array) { values = values.split("/n"); } @@ -929,7 +969,7 @@ class QuerySelectWidgetController extends React.Component { className="queryselectwidget-results-container position-fixed shadow-lg border border-light rounded-lg bg-white mt-2 p-1" columns={this.get_columns()} values={this.state.values} - value_key={this.state.value_key} + value_key={this.get_item_value_key()} searchterm={this.state.searchterm} width={this.state.results_table_width} results={this.state.results} From c58c1e76e4a52cd741951fc5e0690e47b16a46fc Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Mon, 9 Dec 2024 14:50:43 +0100 Subject: [PATCH 03/15] Allow to set object/array values --- webpack/app/widgets/queryselect/widget.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/webpack/app/widgets/queryselect/widget.js b/webpack/app/widgets/queryselect/widget.js index c315265532..143664eccd 100644 --- a/webpack/app/widgets/queryselect/widget.js +++ b/webpack/app/widgets/queryselect/widget.js @@ -590,6 +590,18 @@ class QuerySelectWidgetController extends React.Component { return; } console.debug("QuerySelectWidgetController::select:value:", value); + // clear any previous result for single value fields + if (this.is_single_valued() && this.has_value()) { + this.state.values = []; + } + // handle object values + if (this.is_object(value)) { + return this.select(value[this.get_item_value_key()]); + } + // handle array values + if (this.is_array(value)) { + return value.forEach((item) => { this.select(item) }) + } // create a copy of the selected values let values = [].concat(this.state.values); // Add the new value if it is not selected yet From df1e2b5118d0a1be7fde980b6a4aa8a269146838 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Mon, 9 Dec 2024 16:31:45 +0100 Subject: [PATCH 04/15] Paste action --- .../analysisrequest/templates/ar_add2.pt | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/bika/lims/browser/analysisrequest/templates/ar_add2.pt b/src/bika/lims/browser/analysisrequest/templates/ar_add2.pt index f0ac4ff9de..923dfca603 100644 --- a/src/bika/lims/browser/analysisrequest/templates/ar_add2.pt +++ b/src/bika/lims/browser/analysisrequest/templates/ar_add2.pt @@ -24,6 +24,18 @@ + + +