SearchKit - Improve UX for refresh after editing
authorColeman Watts <coleman@civicrm.org>
Wed, 24 Nov 2021 01:57:24 +0000 (20:57 -0500)
committerColeman Watts <coleman@civicrm.org>
Wed, 24 Nov 2021 01:57:24 +0000 (20:57 -0500)
After bulk-editing or in-place-editing, ensures the pager count is correctly updated.
Does the update and refresh for in-place-edit in a single ajax request, without the loading placeholders.

ext/search_kit/ang/crmSearchDisplay/colType/field.html
ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
ext/search_kit/ang/crmSearchTasks/traits/searchDisplayTasksTrait.service.js

index 0979969bb1f05bb2530a2ddf5c76db7ff63bd656..cee95047ffe407723f49f6b5f9a21c7c81374196 100644 (file)
@@ -1,4 +1,4 @@
-<crm-search-display-editable row="row" col="colData" on-success="$ctrl.runSearch(row)" cancel="$ctrl.editing = null;" ng-if="colData.edit && $ctrl.editing && $ctrl.editing[0] === rowIndex && $ctrl.editing[1] === colIndex"></crm-search-display-editable>
+<crm-search-display-editable row="row" col="colData" do-save="$ctrl.runSearch([apiCall], {}, row)" cancel="$ctrl.editing = null;" ng-if="colData.edit && $ctrl.editing && $ctrl.editing[0] === rowIndex && $ctrl.editing[1] === colIndex"></crm-search-display-editable>
 <span ng-if="::!colData.links" ng-class="{'crm-editable-enabled': colData.edit && !$ctrl.editing}" ng-click="colData.edit && !$ctrl.editing && ($ctrl.editing = [rowIndex, colIndex])">
   {{:: $ctrl.formatFieldValue(colData) }}
 </span>
index 2df08087f87561793818d9e30fd52b1c68ebdd01..052b9dcfbc5f7bc3f618b0229ec925465758c120 100644 (file)
@@ -9,10 +9,10 @@
       row: '<',
       col: '<',
       cancel: '&',
-      onSuccess: '&'
+      doSave: '&'
     },
     templateUrl: '~/crmSearchDisplay/crmSearchDisplayEditable.html',
-    controller: function($scope, $element, crmApi4, crmStatus) {
+    controller: function($scope, $element, crmApi4) {
       var ctrl = this,
         initialValue,
         col;
@@ -58,9 +58,7 @@
         var record = _.cloneDeep(col.edit.record);
         record[col.edit.value_key] = ctrl.value;
         $('input', $element).attr('disabled', true);
-        crmStatus({}, crmApi4(col.edit.entity, 'update', {
-          values: record
-        })).then(ctrl.onSuccess);
+        ctrl.doSave({apiCall: [col.edit.entity, 'update', {values: record}]});
       };
 
       function loadOptions() {
index e1e49cbf8d9ca845d7aeb031665693c94d9b17b1..41c07dda5539d17d6106133810e506ba21b167e9 100644 (file)
@@ -2,7 +2,7 @@
   "use strict";
 
   // Trait provides base methods and properties common to all search display types
-  angular.module('crmSearchDisplay').factory('searchDisplayBaseTrait', function(crmApi4) {
+  angular.module('crmSearchDisplay').factory('searchDisplayBaseTrait', function(crmApi4, crmStatus) {
 
     // Return a base trait shared by all search display controllers
     // Gets mixed in using angular.extend()
       },
 
       // Call SearchDisplay.run and update ctrl.results and ctrl.rowCount
-      runSearch: function(editedRow) {
+      runSearch: function(apiCalls, statusParams, editedRow) {
         var ctrl = this,
           requestId = ++this._runCount,
           apiParams = this.getApiParams();
-        this.loading = true;
+        if (!statusParams) {
+          this.loading = true;
+        }
         _.each(ctrl.onPreRun, function(callback) {
           callback.call(ctrl, apiParams);
         });
-        return crmApi4('SearchDisplay', 'run', apiParams).then(function(results) {
+        apiCalls = apiCalls || [];
+        apiCalls.push(['SearchDisplay', 'run', apiParams]);
+        var apiRequest = crmApi4(apiCalls);
+        apiRequest.then(function(apiResults) {
           if (requestId < ctrl._runCount) {
             return; // Another request started after this one
           }
-          ctrl.results = results;
+          ctrl.results = _.last(apiResults);
           ctrl.editing = ctrl.loading = false;
-          if (!ctrl.rowCount) {
-            if (!ctrl.limit || results.length < ctrl.limit) {
-              ctrl.rowCount = results.length;
+          // Update rowCount if running for the first time or during an update op
+          if (!ctrl.rowCount || editedRow) {
+            if (!ctrl.limit || ctrl.results.length < ctrl.limit) {
+              ctrl.rowCount = ctrl.results.length;
             } else if (ctrl.settings.pager) {
               var params = ctrl.getApiParams('row_count');
               crmApi4('SearchDisplay', 'run', params).then(function(result) {
             }
           }
           _.each(ctrl.onPostRun, function(callback) {
-            callback.call(ctrl, results, 'success', editedRow);
+            callback.call(ctrl, ctrl.results, 'success', editedRow);
           });
         }, function(error) {
           if (requestId < ctrl._runCount) {
             callback.call(ctrl, error, 'error', editedRow);
           });
         });
+        if (statusParams) {
+          crmStatus(statusParams, apiRequest);
+        }
+        return apiRequest;
       },
       formatFieldValue: function(colData) {
         return angular.isArray(colData.val) ? colData.val.join(', ') : colData.val;
index f7cb558d76649b176a57509ddbe0571cd7b995bd..4dc4e14a12041f406fddffe77cd045cd3bce455d 100644 (file)
@@ -55,6 +55,7 @@
       refreshAfterTask: function() {
         this.selectedRows.length = 0;
         this.allRowsSelected = false;
+        this.rowCount = undefined;
         this.runSearch();
       },
 
@@ -70,7 +71,7 @@
         if (editedRow && status === 'success') {
           // 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, {id: editedRow.key})) {
+          if (index > -1 && !_.findWhere(results, {key: editedRow.key})) {
             this.selectedRows.splice(index, 1);
           }
         }