From f036575175efc0a6af2b277ed1a6d7fb0138fffe Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Mon, 7 Mar 2022 02:31:20 -0500 Subject: [PATCH 1/3] SearchKit - Allow searching by range --- .../crmSearchDisplayTableBody.html | 2 +- .../traits/searchDisplayTasksTrait.service.js | 47 ++++++++++++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html index e1310ae63b39..8dcb6a279862 100644 --- a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html +++ b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html @@ -3,7 +3,7 @@ - + diff --git a/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js b/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js index 17c02d5d0828..c93167a8977a 100644 --- a/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js +++ b/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js @@ -36,14 +36,49 @@ }, // Toggle row selection - selectRow: function(row) { - var index = this.selectedRows.indexOf(row.key); + selectRow: function(row, event) { + var ctrl = this, + index = ctrl.selectedRows.indexOf(row.key); + + // See if any boxes are checked above/below this one + function checkRange(allRows, checkboxPosition, dir) { + for (var row = checkboxPosition; row >= 0 && row <= allRows.length; row += dir) { + if (ctrl.selectedRows.indexOf(allRows[row]) > -1) { + return row; + } + } + } + + // Check a bunch of boxes + function selectRange(allRows, start, end) { + for (var row = start; row <= end; ++row) { + ctrl.selectedRows.push(allRows[row]); + } + } + if (index < 0) { - this.selectedRows.push(row.key); - this.allRowsSelected = (this.rowCount === this.selectedRows.length); + // Shift-click - select range between clicked checkbox and the nearest selected row + if (event.shiftKey && ctrl.selectedRows.length) { + var allRows = _.pluck(ctrl.results, 'key'), + checkboxPosition = allRows.indexOf(row.key); + + var nearestBefore = checkRange(allRows, checkboxPosition, -1), + nearestAfter = checkRange(allRows, checkboxPosition, 1); + + // Select range between clicked box and the previous/next checked box + // In the ambiguous situation where there are checked boxes both above AND below the clicked box, + // choose the direction of the box which was most recently clicked. + if (nearestAfter !== undefined && (nearestBefore === undefined || nearestAfter === allRows.indexOf(_.last(ctrl.selectedRows)))) { + selectRange(allRows, checkboxPosition + 1, nearestAfter - 1); + } else if (nearestBefore !== undefined && (nearestAfter === undefined || nearestBefore === allRows.indexOf(_.last(ctrl.selectedRows)))) { + selectRange(allRows, nearestBefore + 1, checkboxPosition -1); + } + } + ctrl.selectedRows.push(row.key); + ctrl.allRowsSelected = (ctrl.rowCount === ctrl.selectedRows.length); } else { - this.allRowsSelected = false; - this.selectedRows.splice(index, 1); + ctrl.allRowsSelected = false; + ctrl.selectedRows.splice(index, 1); } }, From 72dd6782018b1a91005177b81d17500872a6c227 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Mon, 7 Mar 2022 14:30:51 -0500 Subject: [PATCH 2/3] SearchKit - Add menu for selecting all/page/none --- .../crmSearchAdminResultsTable.html | 3 +- .../crmSearchDisplayTable.html | 4 +- .../crmSearchDisplayTableBody.html | 2 +- .../crmSearchDisplayTaskHeader.html | 26 ++++++++ .../traits/searchDisplayTasksTrait.service.js | 64 ++++++++++++------- ext/search_kit/css/crmSearchAdmin.css | 4 -- ext/search_kit/css/crmSearchTasks.css | 7 +- 7 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTaskHeader.html diff --git a/ext/search_kit/ang/crmSearchAdmin/resultsTable/crmSearchAdminResultsTable.html b/ext/search_kit/ang/crmSearchAdmin/resultsTable/crmSearchAdminResultsTable.html index aff0c96b795a..31e8b6f0e863 100644 --- a/ext/search_kit/ang/crmSearchAdmin/resultsTable/crmSearchAdminResultsTable.html +++ b/ext/search_kit/ang/crmSearchAdmin/resultsTable/crmSearchAdminResultsTable.html @@ -7,8 +7,7 @@ -
- + diff --git a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html index 2731e1f05681..0293a9294f47 100644 --- a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html +++ b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html @@ -6,9 +6,7 @@ - diff --git a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTaskHeader.html b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTaskHeader.html new file mode 100644 index 000000000000..7cd2216186b6 --- /dev/null +++ b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTaskHeader.html @@ -0,0 +1,26 @@ + + diff --git a/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js b/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js index c93167a8977a..b15c67d8e732 100644 --- a/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js +++ b/ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js @@ -8,35 +8,48 @@ // Trait properties get mixed into display controller using angular.extend() return { - selectedRows: [], - allRowsSelected: false, + // Use ajax to select all rows on every page + selectAllPages: function() { + var ctrl = this; + ctrl.loadingAllRows = ctrl.allRowsSelected = true; + var params = ctrl.getApiParams('id'); + crmApi4('SearchDisplay', 'run', params).then(function(ids) { + ctrl.loadingAllRows = false; + ctrl.selectedRows = _.uniq(_.toArray(ids)); + }); + }, + + // Select all rows on the current page + selectPage: function() { + this.allRowsSelected = true; + this.selectedRows = _.uniq(_.pluck(this.results, 'key')); + }, + + // Clear selection + selectNone: function() { + this.allRowsSelected = false; + this.selectedRows = []; + }, // Toggle the "select all" checkbox - selectAllRows: function() { - var ctrl = this; + toggleAllRows: function() { // Deselect all - if (ctrl.allRowsSelected) { - ctrl.allRowsSelected = false; - ctrl.selectedRows.length = 0; - return; + if (this.selectedRows && this.selectedRows.length) { + this.selectNone(); } // Select all - ctrl.allRowsSelected = true; - if (ctrl.page === 1 && ctrl.results.length < ctrl.limit) { - ctrl.selectedRows = _.pluck(ctrl.results, 'key'); - return; + else if (this.page === 1 && this.rowCount === this.results.length) { + this.selectPage(); } // If more than one page of results, use ajax to fetch all ids - ctrl.loadingAllRows = true; - var params = ctrl.getApiParams('id'); - crmApi4('SearchDisplay', 'run', params).then(function(ids) { - ctrl.loadingAllRows = false; - ctrl.selectedRows = _.toArray(ids); - }); + else { + this.selectAllPages(); + } }, // Toggle row selection - selectRow: function(row, event) { + toggleRow: function(row, event) { + this.selectedRows = this.selectedRows || []; var ctrl = this, index = ctrl.selectedRows.indexOf(row.key); @@ -74,7 +87,7 @@ selectRange(allRows, nearestBefore + 1, checkboxPosition -1); } } - ctrl.selectedRows.push(row.key); + ctrl.selectedRows = _.uniq(ctrl.selectedRows.concat([row.key])); ctrl.allRowsSelected = (ctrl.rowCount === ctrl.selectedRows.length); } else { ctrl.allRowsSelected = false; @@ -87,8 +100,13 @@ return this.allRowsSelected || _.includes(this.selectedRows, row.key); }, + isPageSelected: function() { + return (this.allRowsSelected && this.rowCount === this.results.length) || + (!this.allRowsSelected && this.selectedRows && this.selectedRows.length === this.results.length); + }, + refreshAfterTask: function() { - this.selectedRows.length = 0; + this.selectedRows = []; this.allRowsSelected = false; this.rowCount = undefined; this.runSearch(); @@ -97,13 +115,13 @@ // Add onChangeFilters callback (gets merged with others via angular.extend) onChangeFilters: [function() { // Reset selection when filters are changed - this.selectedRows.length = 0; + this.selectedRows = []; this.allRowsSelected = false; }], // Add onPostRun callback (gets merged with others via angular.extend) onPostRun: [function(results, status, editedRow) { - if (editedRow && status === 'success') { + if (editedRow && status === 'success' && this.selectedRows) { // If edited row disappears (because edits cause it to not meet search criteria), deselect it var index = this.selectedRows.indexOf(editedRow.key); if (index > -1 && !_.findWhere(results, {key: editedRow.key})) { diff --git a/ext/search_kit/css/crmSearchAdmin.css b/ext/search_kit/css/crmSearchAdmin.css index f69558afdc17..b5963b44d330 100644 --- a/ext/search_kit/css/crmSearchAdmin.css +++ b/ext/search_kit/css/crmSearchAdmin.css @@ -166,10 +166,6 @@ height: 36px; } -#bootstrap-theme.crm-search th.crm-search-result-select { - padding-right: 10px; -} - #bootstrap-theme .crm-search-delete-display { position: absolute; right: 0; diff --git a/ext/search_kit/css/crmSearchTasks.css b/ext/search_kit/css/crmSearchTasks.css index 89fada1d5909..8a96d12a5f2f 100644 --- a/ext/search_kit/css/crmSearchTasks.css +++ b/ext/search_kit/css/crmSearchTasks.css @@ -5,7 +5,12 @@ } #bootstrap-theme .crm-search-display-table > table.table > thead > tr > th.crm-search-result-select { - vertical-align: middle; + padding-left: 0; + padding-right: 0; + text-transform: none; + color: initial; + /* Don't allow button to be split on 2 lines */ + min-width: 86px; } .crm-search-display.crm-search-display-table td > crm-search-display-editable, From 7ef2c5cb1c8bf6f59575ab5d0118bc0beec3ae67 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 8 Mar 2022 14:38:07 -0500 Subject: [PATCH 3/3] Remove unnecessary shared variable --- .../traits/searchDisplaySortableTrait.service.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplaySortableTrait.service.js b/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplaySortableTrait.service.js index b671627c4af8..c8f4faaa681d 100644 --- a/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplaySortableTrait.service.js +++ b/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplaySortableTrait.service.js @@ -8,8 +8,6 @@ // Trait properties get mixed into display controller using angular.extend() return { - sort: [], - isSortable: function(col) { return !this.settings.draggable && col.type === 'field' && col.sortable !== false; },
- - + diff --git a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html index 8dcb6a279862..36aba9cd4e31 100644 --- a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html +++ b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTableBody.html @@ -3,7 +3,7 @@ - +