SearchKit - Add column for scheduled communications to savedSearch listing
authorcolemanw <coleman@civicrm.org>
Sat, 19 Aug 2023 22:50:54 +0000 (18:50 -0400)
committercolemanw <coleman@civicrm.org>
Tue, 5 Sep 2023 11:39:19 +0000 (07:39 -0400)
ext/search_kit/ang/crmSearchAdmin/searchListing/communications.html [new file with mode: 0644]
ext/search_kit/ang/crmSearchAdmin/searchListing/crmSearchAdminSearchListing.component.js

diff --git a/ext/search_kit/ang/crmSearchAdmin/searchListing/communications.html b/ext/search_kit/ang/crmSearchAdmin/searchListing/communications.html
new file mode 100644 (file)
index 0000000..5041de1
--- /dev/null
@@ -0,0 +1,20 @@
+<div class="btn-group">
+  <button type="button" ng-click="row.openScheduleMenu = true" class="btn btn-xs dropdown-toggle btn-primary-outline" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+    {{:: row.data.schedule_id.length === 1 ? ts('1 Communication') : ts('%1 Communications', {1: row.data.schedule_id ? row.data.schedule_id.length : 0}) }} <span class="caret"></span>
+  </button>
+  <ul class="dropdown-menu" ng-if=":: row.openScheduleMenu">
+    <li ng-repeat="schedule_id in row.data.schedule_id" title="{{:: ts('Edit Scheduled Communication') }}">
+      <a ng-href="{{ crmUrl('civicrm/admin/scheduleReminders/edit?reset=1&action=update&mapping_id=saved_search&id=' + schedule_id + '&entity_value=' + row.data.id) }}" target="crm-popup">
+        <i class="crm-i fa-pencil"></i>
+        {{ row.data.schedule_title[$index] }}
+      </a>
+    </li>
+    <li class="divider" role="separator"></li>
+    <li title="{{:: ts('Add Scheduled Communication') }}">
+      <a ng-href="{{ crmUrl('civicrm/admin/scheduleReminders/edit?reset=1&action=add&mapping_id=saved_search&entity_value=' + row.data.id) }}" target="crm-popup">
+        <i class="crm-i fa-plus"></i>
+        {{:: ts('New Communication') }}
+      </a>
+    </li>
+  </ul>
+</div>
index 977e965f6940afb34596d3e49416b79d43436c0b..9278b133a27fdb122bd1c31f6c7e48defb7314aa 100644 (file)
         ctrl = angular.extend(this, _.cloneDeep(searchDisplayBaseTrait), _.cloneDeep(searchDisplaySortableTrait)),
         afformLoad;
 
+      $scope.crmUrl = CRM.url;
       this.searchDisplayPath = CRM.url('civicrm/search');
       this.afformPath = CRM.url('civicrm/admin/afform');
       this.afformEnabled = 'org.civicrm.afform' in CRM.crmSearchAdmin.modules;
       this.afformAdminEnabled = (CRM.checkPerm('administer CiviCRM') || CRM.checkPerm('administer afform')) &&
         'org.civicrm.afform_admin' in CRM.crmSearchAdmin.modules;
+      const scheduledCommunicationsEnabled = 'scheduled_communications' in CRM.crmSearchAdmin.modules;
 
       this.apiEntity = 'SavedSearch';
       this.search = {
             'DATE(created_date) AS date_created',
             'DATE(modified_date) AS date_modified',
             'DATE(expires_date) AS expires',
-            'GROUP_CONCAT(display.name ORDER BY display.id) AS display_name',
-            'GROUP_CONCAT(display.label ORDER BY display.id) AS display_label',
-            'GROUP_CONCAT(display.type:icon ORDER BY display.id) AS display_icon',
-            'GROUP_CONCAT(display.acl_bypass ORDER BY display.id) AS display_acl_bypass',
+            // Get all search displays
+            'GROUP_CONCAT(UNIQUE display.name ORDER BY display.label) AS display_name',
+            'GROUP_CONCAT(UNIQUE display.label ORDER BY display.label) AS display_label',
+            'GROUP_CONCAT(UNIQUE display.type:icon ORDER BY display.label) AS display_icon',
+            'GROUP_CONCAT(UNIQUE display.acl_bypass ORDER BY display.label) AS display_acl_bypass',
             'tags', // Not a selectable field but this hacks around the requirement that filters be in the select clause
-            'GROUP_CONCAT(DISTINCT entity_tag.tag_id) AS tag_id',
-            'GROUP_CONCAT(DISTINCT group.title) AS groups'
+            'GROUP_CONCAT(UNIQUE entity_tag.tag_id) AS tag_id',
+            // Really there can only be 1 smart group per saved-search; aggregation is just for the sake of the query
+            'GROUP_CONCAT(UNIQUE group.id) AS group_id',
+            'GROUP_CONCAT(UNIQUE group.title) AS groups'
           ],
           join: [
             ['SearchDisplay AS display', 'LEFT', ['id', '=', 'display.saved_search_id']],
         }
       };
 
+      // Add scheduled communication to query if extension is enabled
+      if (scheduledCommunicationsEnabled) {
+        this.search.api_params.select.push('GROUP_CONCAT(UNIQUE schedule.id ORDER BY schedule.title) AS schedule_id');
+        this.search.api_params.select.push('GROUP_CONCAT(UNIQUE schedule.title ORDER BY schedule.title) AS schedule_title');
+        this.search.api_params.join.push(['ActionSchedule AS schedule', 'LEFT', ['schedule.mapping_id', '=', '"saved_search"'], ['id', '=', 'schedule.entity_value']]);
+      }
+
       this.$onInit = function() {
         buildDisplaySettings();
         this.initializeDisplay($scope, $element);
             path: '~/crmSearchAdmin/searchListing/afforms.html'
           });
         }
+        // Add scheduled communication column if extension is enabled
+        if (scheduledCommunicationsEnabled) {
+          ctrl.display.settings.columns.push({
+            type: 'include',
+            label: ts('Communications'),
+            path: '~/crmSearchAdmin/searchListing/communications.html'
+          });
+        }
         ctrl.display.settings.columns.push(
-          searchMeta.fieldToColumn('GROUP_CONCAT(DISTINCT group.title) AS groups', {
+          searchMeta.fieldToColumn('GROUP_CONCAT(UNIQUE group.title) AS groups', {
             label: ts('Smart Group')
           })
         );