diff --git a/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js b/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js index 7ba8fc7ea..73f3c48d2 100644 --- a/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js +++ b/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js @@ -23,6 +23,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { '' + '' + '' + + '' + ''; self.$el.find('table').addClass('oe_table_search'); self.$el.prepend($(search)); @@ -39,8 +40,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { this._searchTimeout = null; this._currentSearchValue = ''; this._isSearching = false; - - // Store the original records this._originalRecords = null; this._searchMode = false; }, @@ -86,6 +85,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { return; } + // Show loading indicator + this.$el.find('.oe_search_loading').show(); + this.$el.find('.oe_search_count').hide(); this._isSearching = true; // Store original records if not already stored @@ -99,6 +101,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { if (fields.length === 0) { this._isSearching = false; + this.$el.find('.oe_search_loading').hide(); + console.warn('No searchable fields found for model:', model); return; } @@ -106,34 +110,82 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var domain = this._buildSearchDomain(value, fields); // Add existing domain if any - if (this.state.domain && this.state.domain.length > 0) { - domain = this.state.domain.concat([['id', 'in', this.state.res_ids || []]]).concat(domain); + var baseDomain = this.state.domain || []; + if (baseDomain.length > 0) { + // Combine base domain with search domain + domain = baseDomain.concat(domain); } - // Perform RPC search + // Get only visible and stored fields to avoid computed fields issues + var fieldsToRead = this._getFieldsToRead(); + + // Perform RPC search with specific fields only - NO LIMIT this._rpc({ model: model, method: 'search_read', args: [domain], kwargs: { - fields: this.state.fields_get ? Object.keys(this.state.fields_get) : [], - limit: this.state.limit || 80, + fields: fieldsToRead, // Only read necessary fields + limit: false, // No limit - get all records offset: 0, - context: this.state.context, + context: this.state.context || session.user_context, + order: this.state.orderedBy ? this.state.orderedBy[0].name : false } }).then(function(result) { self._updateListWithSearchResults(result, value); - self._isSearching = false; - - // Restore search value (in case it was cleared during reload) - self.$el.find('.oe_search_input').val(self._currentSearchValue); }).catch(function(error) { console.error('Search error:', error); + self._showError(_t('Search failed. Please try again.')); + }).finally(function() { self._isSearching = false; + self.$el.find('.oe_search_loading').hide(); + // Restore search value self.$el.find('.oe_search_input').val(self._currentSearchValue); }); }, + _getFieldsToRead: function() { + var self = this; + var fields = ['id']; // Always include ID + + // Get only visible, stored fields from columns + _.each(this.columns, function(column) { + if (!column.invisible && column.attrs.name) { + var fieldName = column.attrs.name; + var field = self.state.fields[fieldName]; + + // Only include stored fields or safe field types + if (field) { + // Skip computed fields unless they're stored + if (field.compute && !field.store) { + return; // Skip this field + } + + // For many2one, we only need the ID and display_name + if (field.type === 'many2one') { + fields.push(fieldName); + } + // For other fields, include if they're stored + else if (field.store !== false) { + fields.push(fieldName); + } + } + } + }); + + // Always try to include display_name if available + if (self.state.fields.display_name && !fields.includes('display_name')) { + fields.push('display_name'); + } + + // Always try to include name if available + if (self.state.fields.name && !fields.includes('name')) { + fields.push('name'); + } + + return _.uniq(fields); + }, + _buildSearchDomain: function(value, fields) { var domain = []; var orConditions = []; @@ -150,21 +202,21 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { orConditions.push([field.name, 'ilike', normalizedValue]); } } - // For many2one fields + // For many2one fields - search in the name else if (field.type === 'many2one') { - // Search in the display_name of the related field + // Use the field name directly with ilike orConditions.push([field.name, 'ilike', value]); } - // For number fields (if value is numeric) - else if (['integer', 'float', 'monetary'].includes(field.type)) { - if (!isNaN(value)) { - orConditions.push([field.name, '=', parseFloat(value)]); - } - } // For selection fields else if (field.type === 'selection') { orConditions.push([field.name, 'ilike', value]); } + // For number fields (if value is numeric) + else if (['integer', 'float', 'monetary'].includes(field.type)) { + if (!isNaN(value) && value !== '') { + orConditions.push([field.name, '=', parseFloat(value)]); + } + } }); // Create OR domain @@ -182,34 +234,49 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { _getSearchableFields: function() { var self = this; var fields = []; + var addedFields = {}; // Track added fields to avoid duplicates - // Get visible fields from the list view columns + // Priority 1: Get visible stored fields from columns _.each(this.columns, function(column) { if (!column.invisible && column.attrs.name) { var fieldName = column.attrs.name; var field = self.state.fields[fieldName]; - if (field && field.searchable !== false && field.store !== false) { - fields.push({ - name: fieldName, - type: field.type, - string: field.string - }); - } - } - }); - - // If no visible fields, get common searchable fields - if (fields.length === 0) { - var commonFields = ['name', 'display_name', 'reference', 'code', 'description']; - _.each(commonFields, function(fieldName) { - if (self.state.fields[fieldName]) { - var field = self.state.fields[fieldName]; - if (field.searchable !== false && field.store !== false) { + + if (field && !addedFields[fieldName]) { + // Only searchable in stored fields or specific field types + var isSearchable = ( + field.searchable !== false && + (field.store !== false || field.type === 'many2one') && + (!field.compute || field.store) // Skip non-stored computed fields + ); + + if (isSearchable) { fields.push({ name: fieldName, type: field.type, string: field.string }); + addedFields[fieldName] = true; + } + } + } + }); + + // Priority 2: Add common searchable fields if not enough fields + if (fields.length < 3) { + var commonFields = ['name', 'display_name', 'reference', 'code', 'ref', 'description']; + _.each(commonFields, function(fieldName) { + if (self.state.fields[fieldName] && !addedFields[fieldName]) { + var field = self.state.fields[fieldName]; + if (field.searchable !== false && + field.store !== false && + (!field.compute || field.store)) { + fields.push({ + name: fieldName, + type: field.type, + string: field.string + }); + addedFields[fieldName] = true; } } }); @@ -224,50 +291,61 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { // Update the count display var count = records.length; var $countEl = this.$el.find('.oe_search_count'); - if (searchValue && count >= 0) { - $countEl.text(_t('Found: ') + count + _t(' records')).show(); - } else { - $countEl.hide(); - } - // Update the table rows - filter displayed records - if (records.length > 0) { - var recordIds = records.map(function(r) { return r.id; }); + if (count > 0) { + var message = _t('Found: ') + count + _t(' records'); + // Show warning if too many records + if (count > 1000) { + message += ' ' + _t('(Large result set, may affect performance)'); + } + $countEl.text(message).show(); - // Hide rows that don't match - this.$el.find('.o_data_row').each(function() { - var $row = $(this); - var recordId = $row.data('id'); - if (recordId) { - var isVisible = recordIds.includes(recordId); - $row.toggle(isVisible); - } + // Update the view with new records + this.state.data.records = records; + this._searchMode = true; + + // Re-render the body with new records + this._renderBody().then(function() { + // Restore search input value + self.$el.find('.oe_search_input').val(self._currentSearchValue); + self.$el.find('.oe_clear_search').show(); + $countEl.show(); }); - // If we need to load more records, update the state - if (count > this.state.data.records.length) { - // Need to reload with new records - this.state.data.records = records; - this._renderBody().then(function() { - // Restore search input value - self.$el.find('.oe_search_input').val(self._currentSearchValue); - self.$el.find('.oe_clear_search').show(); - self.$el.find('.oe_search_count').text(_t('Found: ') + count + _t(' records')).show(); - }); - } } else { - // No results - hide all rows - this.$el.find('.o_data_row').hide(); - - // Show no results message - if (!this.$el.find('.oe_no_results').length) { - var noResultsHtml = '' + - _t('No records found for: ') + _.escape(searchValue) + ''; - this.$el.find('tbody').append(noResultsHtml); - } + $countEl.text(_t('No records found')).show(); + this._showNoResults(searchValue); } }, + _showNoResults: function(searchValue) { + // Hide all data rows + this.$el.find('.o_data_row').hide(); + + // Remove existing no results message + this.$el.find('.oe_no_results').remove(); + + // Add no results message + var colspan = this.$el.find('thead tr:first th').length || 1; + var noResultsHtml = '' + + '' + + '' + + '

' + _t('No records found') + '

' + + '

' + _t('No results for: ') + '' + _.escape(searchValue) + '

' + + '

' + _t('Try different keywords or check your filters') + '

' + + ''; + this.$el.find('tbody').append(noResultsHtml); + }, + + _showError: function(message) { + var $countEl = this.$el.find('.oe_search_count'); + $countEl.text(message).css('color', '#dc3545').show(); + + setTimeout(function() { + $countEl.css('color', '#6c757d'); + }, 3000); + }, + _clearSearch: function() { var self = this; @@ -275,13 +353,11 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { this.$el.find('.oe_search_input').val(''); this.$el.find('.oe_clear_search').hide(); this.$el.find('.oe_search_count').hide(); + this.$el.find('.oe_search_loading').hide(); // Remove no results message this.$el.find('.oe_no_results').remove(); - // Show all rows again - this.$el.find('.o_data_row').show(); - // Reset search state this._currentSearchValue = ''; this._searchMode = false; @@ -292,6 +368,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { this._renderBody().then(function() { self._originalRecords = null; }); + } else { + // Just show all rows + this.$el.find('.o_data_row').show(); } },