Search ext: Choose smart group contact column
authorColeman Watts <coleman@civicrm.org>
Tue, 29 Sep 2020 15:30:19 +0000 (11:30 -0400)
committerColeman Watts <coleman@civicrm.org>
Fri, 2 Oct 2020 17:22:05 +0000 (13:22 -0400)
ext/search/CRM/Search/Page/Ang.php
ext/search/ang/search/SaveSmartGroup.ctrl.js
ext/search/ang/search/crmSearch.component.js
ext/search/ang/search/saveSmartGroup.html

index c2619910c79b9f1e87ede63655faa0d85a6ff161..0c9c228f21635b92fde815c23eeab4624191f656 100644 (file)
@@ -90,7 +90,7 @@ class CRM_Search_Page_Ang extends CRM_Core_Page {
       ->setChain([
         'get' => ['$name', 'getActions', ['where' => [['name', '=', 'get']]], ['params']],
       ])->execute();
-    $getFields = ['name', 'label', 'description', 'options', 'input_type', 'input_attrs', 'data_type', 'serialize'];
+    $getFields = ['name', 'label', 'description', 'options', 'input_type', 'input_attrs', 'data_type', 'serialize', 'fk_entity'];
     foreach ($schema as $entity) {
       // Skip if entity doesn't have a 'get' action or the user doesn't have permission to use get
       if ($entity['get']) {
index 18b0298e96f79c3dd1a7b1721f29775485bfff34..ece503cf2879d9c57eb7216db3d7e14e7dd78495 100644 (file)
@@ -1,13 +1,15 @@
 (function(angular, $, _) {
   "use strict";
 
-  angular.module('search').controller('SaveSmartGroup', function ($scope, $element, crmApi4, dialogService) {
+  angular.module('search').controller('SaveSmartGroup', function ($scope, $element, $timeout, crmApi4, dialogService, searchMeta) {
     var ts = $scope.ts = CRM.ts(),
-      model = $scope.model;
+      model = $scope.model,
+      joins = _.pluck((model.api_params.join || []), 0),
+      entityCount = {};
     $scope.groupEntityRefParams = {
       entity: 'Group',
       api: {
-        params: {is_hidden: 0, is_active: 1, 'saved_search_id.api_entity': model.entity},
+        params: {is_hidden: 0, is_active: 1, 'saved_search_id.api_entity': model.api_entity},
         extra: ['saved_search_id', 'description', 'visibility', 'group_type']
       },
       select: {
         placeholder: ts('Select existing group')
       }
     };
+    // Find all possible search columns that could serve as contact_id for the smart group
+    $scope.columns = _.transform([model.api_entity].concat(joins), function(columns, joinExpr) {
+      var joinName = joinExpr.split(' AS '),
+        entityName = joinName[0],
+        entity = searchMeta.getEntity(entityName),
+        prefix = joinName[1] ? joinName[1] + '.' : '';
+      _.each(entity.fields, function(field) {
+        if ((entityName === 'Contact' && field.name === 'id') || field.fk_entity === 'Contact') {
+          columns.push({
+            id: prefix + field.name,
+            text: entity.titlePlural + (entityCount[entityName] ? ' ' + entityCount[entityName] : '') + ': ' + field.label,
+            icon: entity.icon
+          });
+        }
+      });
+      entityCount[entityName] = 1 + (entityCount[entityName] || 1);
+    });
+
+    if (!$scope.columns.length) {
+      CRM.alert(ts('Cannot create smart group; search does not include any contacts.'), ts('Error'));
+      $timeout(function() {
+        dialogService.cancel('saveSearchDialog');
+      });
+      return;
+    }
+
+    // Pick the first applicable column for contact id
+    model.api_params.select[0] = _.intersection(model.api_params.select, _.pluck($scope.columns, 'id'))[0] || $scope.columns[0].name;
+    model.api_params.select.length = 1;
+
     if (!CRM.checkPerm('administer reserved groups')) {
       $scope.groupEntityRefParams.api.params.is_reserved = 0;
     }
@@ -45,8 +77,8 @@
       group.group_type = model.group_type;
       group.saved_search_id = '$id';
       var savedSearch = {
-        api_entity: model.entity,
-        api_params: model.params
+        api_entity: model.api_entity,
+        api_params: model.api_params
       };
       if (group.id) {
         savedSearch.id = model.saved_search_id;
index 88ba4c7b11d4090d9d8b6d4a79f4edd255a7e357..33ed7f3ca97b04a700f9beb481841577786b4066 100644 (file)
       };
 
       $scope.saveGroup = function() {
-        var selectField = ctrl.entity === 'Contact' ? 'id' : 'contact_id';
-        if (ctrl.entity !== 'Contact' && !searchMeta.getField('contact_id')) {
-          CRM.alert(ts('Cannot create smart group from %1.', {1: searchMeta.getEntity(true).titlePlural}), ts('Missing contact_id'), 'error', {expires: 5000});
-          return;
-        }
         var model = {
           title: '',
           description: '',
           visibility: 'User and User Admin Only',
           group_type: [],
           id: ctrl.load ? ctrl.load.id : null,
-          entity: ctrl.entity,
-          params: angular.extend({}, ctrl.params, {version: 4})
+          api_entity: ctrl.entity,
+          api_params: _.cloneDeep(angular.extend({}, ctrl.params, {version: 4}))
         };
-        delete model.params.orderBy;
+        delete model.api_params.orderBy;
+        if (ctrl.load && ctrl.load.api_params) {
+          model.api_params.select = ctrl.load.api_params.select;
+        }
         var options = CRM.utils.adjustDialogDefaults({
           autoOpen: false,
           title: ts('Save smart group')
index a0caf4af2c1938f9450379b9892db59c61c8a328..a2ef0560473451d3b00c8ab3cc9729df92860dd2 100644 (file)
@@ -1,22 +1,30 @@
 <form id="bootstrap-theme">
   <div ng-controller="SaveSmartGroup">
+    <div crm-ui-debug="model"></div>
     <input class="form-control" id="api-save-search-select-group" ng-model="model.id" crm-entityref="groupEntityRefParams" >
     <label ng-show="!model.id">{{:: ts('Or') }}</label>
-    <input class="form-control" placeholder="Create new group" ng-model="model.title" ng-show="!model.id">
+    <input class="form-control" placeholder="{{:: ts('Create new group') }}" ng-model="model.title" ng-show="!model.id">
+    <hr />
+    <div class="form-inline">
+     <label for="api-save-search-select-column">{{:: ts('Contact Column:') }}</label>
+      <input id="api-save-search-select-column" ng-model="model.api_params.select[0]" class="form-control" crm-ui-select="{data: columns}"/>
+    </div>
     <hr />
     <label>{{:: ts('Description:') }}</label>
     <textarea class="form-control" ng-model="model.description"></textarea>
-    <label>{{:: ts('Group Type:') }}</label>
     <div class="form-inline">
-      <div class="checkbox" ng-repeat="option in groupFields.group_type.options track by option.id">
+      <label>{{:: ts('Group Type:') }} </label>
+      <div class="checkbox" ng-repeat="option in groupFields.group_type.options track by option.id">&nbsp;
         <label>
           <input type="checkbox" checklist-model="model.group_type" checklist-value="option.id">
           {{ option.label }}
-        </label>
+        </label>&nbsp;
       </div>
     </div>
-    <label>{{:: ts('Visibility:') }}</label>
-    <select class="form-control" ng-model="model.visibility" ng-options="item.id as item.label for item in groupFields.visibility.options track by item.id"></select>
+    <div class="form-inline">
+      <label>{{:: ts('Visibility:') }}</label>
+      <select class="form-control" ng-model="model.visibility" ng-options="item.id as item.label for item in groupFields.visibility.options track by item.id" crm-ui-select></select>
+    </div>
     <hr />
     <div class="buttons pull-right">
       <button type="button" ng-click="cancel()" class="btn btn-danger">{{:: ts('Cancel') }}</button>