SearchKit - Convert 'Field Transformations' accordion into 'Select Fields' tab
authorcolemanw <coleman@civicrm.org>
Mon, 18 Dec 2023 02:34:14 +0000 (21:34 -0500)
committercolemanw <coleman@civicrm.org>
Mon, 18 Dec 2023 02:34:14 +0000 (21:34 -0500)
ext/search_kit/ang/crmSearchAdmin/crmSearch-fields.html
ext/search_kit/ang/crmSearchAdmin/crmSearchAdmin.component.js
ext/search_kit/ang/crmSearchAdmin/crmSearchAdminFields.component.js [new file with mode: 0644]
ext/search_kit/ang/crmSearchAdmin/crmSearchAdminFields.html [new file with mode: 0644]
ext/search_kit/ang/crmSearchAdmin/resultsTable/crmSearchAdminResultsTable.component.js
ext/search_kit/ang/crmSearchAdmin/resultsTable/crmSearchAdminResultsTable.html

index c02e30b1407f05ba8b7fa6b931dfcc5b76df67b2..e699ea56e22e8a74e96ec2ce12ba763597d52e5b 100644 (file)
@@ -1,8 +1,3 @@
-<fieldset id="crm-search-build-functions" class="crm-search-select-fields">
-  <div>
-    <!-- Must use track by $index with an array of primitives, and manually refresh this loop when indexes change -->
-    <fieldset ng-repeat="col in $ctrl.savedSearch.api_params.select track by $index" ng-if="!$ctrl.isPseudoField(col)">
-      <crm-search-function class="form-inline" mode="select" expr="$ctrl.savedSearch.api_params.select[$index]"></crm-search-function>
-    </fieldset>
-  </div>
+<fieldset class="crm-search-select-fields">
+  <crm-search-admin-fields></crm-search-admin-fields>
 </fieldset>
index 1414ba4bd204c9e235fd2d26e9e1aeb7720f842f..48e8f31f7bd9edd1dba2c816f50c757b7da651e4 100644 (file)
 
     // Deletes an item from an array param
     this.clearParam = function(name, idx) {
-      if (name === 'select') {
-        // Function selectors use `ng-repeat` with `track by $index` so must be refreshed when splicing the array
-        ctrl.hideFuncitons();
-      }
       ctrl.savedSearch.api_params[name].splice(idx, 1);
     };
 
-    this.hideFuncitons = function() {
-      $scope.controls.showFunctions = false;
-    };
-
     function onChangeSelect(newSelect, oldSelect) {
       // When removing a column from SELECT, also remove from ORDER BY & HAVING
       _.each(_.difference(oldSelect, newSelect), function(col) {
       return {results: ctrl.getSelectFields()};
     };
 
+    this.fieldsForSelect = function() {
+      return {
+        results: ctrl.getAllFields(':label', ['Field', 'Custom', 'Extra', 'Pseudo'], (key) => {
+          ctrl.savedSearch.api_params.select.includes(key);
+        })
+      };
+    };
+
     this.getAllFields = function(suffix, allowedTypes, disabledIf, topJoin) {
       disabledIf = disabledIf || _.noop;
       allowedTypes = allowedTypes || ['Field', 'Custom', 'Extra', 'Filter'];
diff --git a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminFields.component.js b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminFields.component.js
new file mode 100644 (file)
index 0000000..9b84223
--- /dev/null
@@ -0,0 +1,56 @@
+(function(angular, $, _) {
+  "use strict";
+
+  angular.module('crmSearchAdmin').component('crmSearchAdminFields', {
+    bindings: {
+    },
+    require: {
+      crmSearchAdmin: '^crmSearchAdmin'
+    },
+    templateUrl: '~/crmSearchAdmin/crmSearchAdminFields.html',
+    controller: function ($scope, $element) {
+      var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
+        ctrl = this;
+
+      // savedSearch.api_params.select is an array of strings.
+      // ui-sortable (and angularJs loops in general) don't work well with primitives
+      // So this controller converts the strings into objects and maintains 2-way sync between
+      // the two arrays.
+      this.select = [];
+
+      $scope.$watchCollection('$ctrl.crmSearchAdmin.savedSearch.api_params.select', function(flatSelect) {
+        ctrl.select.length = flatSelect.length;
+        flatSelect.forEach((key, index) => {
+          ctrl.select[index] = ctrl.select[index] || {};
+          ctrl.select[index].key = key;
+          ctrl.select[index].label = ctrl.crmSearchAdmin.getFieldLabel(key);
+          ctrl.select[index].isPseudoField = ctrl.crmSearchAdmin.isPseudoField(key);
+        });
+      });
+
+      $scope.$watch('$ctrl.select', function(selectObject, oldSelect) {
+        if (oldSelect && oldSelect.length && selectObject) {
+          ctrl.crmSearchAdmin.savedSearch.api_params.select.length = selectObject.length;
+          selectObject.forEach((item, index) => {
+            ctrl.crmSearchAdmin.savedSearch.api_params.select[index] = item.key;
+          });
+        }
+      }, true);
+
+      // Drag-n-drop settings for reordering search fields
+      this.sortableOptions = {
+        containment: '.crm-search-select-fields',
+        axis: 'y',
+        forcePlaceholderSize: true,
+        update: function(e, ui) {
+          // Don't allow items to be moved to position 0 if locked
+          if (!ui.item.sortable.dropindex && ctrl.crmSearchAdmin.groupExists) {
+            ui.item.sortable.cancel();
+          }
+        }
+      };
+
+    }
+  });
+
+})(angular, CRM.$, CRM._);
diff --git a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminFields.html b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminFields.html
new file mode 100644 (file)
index 0000000..9bb43b8
--- /dev/null
@@ -0,0 +1,13 @@
+<div ng-model="$ctrl.select" ui-sortable="$ctrl.sortableOptions">
+  <fieldset ng-repeat="col in $ctrl.select" class="crm-draggable">
+    <i class="crm-i fa-arrows crm-search-move-icon"></i>
+    <crm-search-function ng-if="!col.isPseudoField" class="form-inline" mode="select" expr="col.key"></crm-search-function>
+    <label ng-if="col.isPseudoField">{{:: col.label }}</label>
+    <button type="button" class="btn-xs pull-right" ng-if="$ctrl.select.length > 1" ng-click="$ctrl.crmSearchAdmin.clearParam('select', $index)" title="{{:: ts('Remove') }}">
+      <i class="crm-i fa-ban"></i>
+    </button>
+  </fieldset>
+</div>
+<input class="form-control crm-action-menu fa-plus collapsible-optgroups"
+       crm-ui-select="::{data: $ctrl.crmSearchAdmin.fieldsForSelect, placeholder: ts('Add')}"
+       on-crm-ui-select="$ctrl.crmSearchAdmin.addParam('select', selection)" >
index b55816ee87ce43f37c5c82c9225384ff4ba4fdc7..b44da215eeca27400f677086f09194a9366a902f 100644 (file)
           if (!ui.item.sortable.dropindex && ctrl.crmSearchAdmin.groupExists) {
             ui.item.sortable.cancel();
           }
-          // Function selectors use `ng-repeat` with `track by $index` so must be refreshed when rearranging the array
-          ctrl.crmSearchAdmin.hideFuncitons();
         }
       };
 
       $scope.fieldsForSelect = function() {
-        return {results: ctrl.crmSearchAdmin.getAllFields(':label', ['Field', 'Custom', 'Extra', 'Pseudo'], function(key) {
-            return _.contains(ctrl.search.api_params.select, key);
-          })
-        };
+        return ctrl.crmSearchAdmin.fieldsForSelect();
       };
 
       $scope.addColumn = function(col) {
index f4a1c86fdfbee3c17b6aae99227c0890dca6ef2f..b6b0e653cbfb4d88ee319dadc13f778739f033d8 100644 (file)
@@ -19,7 +19,7 @@
         </th>
         <th class="form-inline text-right">
           <input class="form-control crm-action-menu fa-plus collapsible-optgroups"
-                 crm-ui-select="::{data: fieldsForSelect, placeholder: ts('Add'), width: '80px', containerCss: {minWidth: '80px'}, dropdownCss: {width: '300px'}}"
+                 crm-ui-select="::{data: fieldsForSelect, placeholder: ' ', width: '48px', containerCss: {minWidth: '48px'}, dropdownCss: {width: '300px'}}"
                  on-crm-ui-select="addColumn(selection)" >
         </th>
       </tr>