Search ext: Dynamic templates and a preview button for displays
authorColeman Watts <coleman@civicrm.org>
Wed, 28 Oct 2020 18:02:36 +0000 (14:02 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 29 Oct 2020 23:48:28 +0000 (19:48 -0400)
13 files changed:
ext/search/Civi/Search/Admin.php
ext/search/Civi/Search/Display.php [new file with mode: 0644]
ext/search/ang/crmSearchPage.ang.php
ext/search/ang/crmSearchPage.module.js
ext/search/ang/crmSearchPage/display.html [deleted file]
ext/search/ang/searchAdmin/crmSearchAdmin.html
ext/search/ang/searchAdmin/crmSearchAdminDisplay.component.js [new file with mode: 0644]
ext/search/ang/searchAdmin/crmSearchAdminDisplay.html [new file with mode: 0644]
ext/search/ang/searchAdmin/display.html [deleted file]
ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.component.js
ext/search/ang/searchAdmin/displays/table.html [deleted file]
ext/search/ang/searchAdmin/tabs.html
ext/search/search.php

index 6d2a2a7d2f25fa3975f61e0746afc66b8fd43bea..58f8d5e1927265ff4b555d77d7142e02bcb52672 100644 (file)
@@ -24,7 +24,7 @@ class Admin {
     return [
       'operators' => \CRM_Utils_Array::makeNonAssociative(self::getOperators()),
       'functions' => \CRM_Api4_Page_Api4Explorer::getSqlFunctions(),
-      'displayTypes' => self::getDisplayTypes(['name', 'label', 'description', 'icon']),
+      'displayTypes' => Display::getDisplayTypes(['name', 'label', 'description', 'icon']),
     ];
   }
 
@@ -105,21 +105,4 @@ class Admin {
     return array_filter($results);
   }
 
-  /**
-   * @param array $props
-   * @return array
-   */
-  public static function getDisplayTypes(array $props):array {
-    try {
-      return \Civi\Api4\SearchDisplay::getFields(FALSE)
-        ->setLoadOptions($props)
-        ->addWhere('name', '=', 'type')
-        ->execute()
-        ->first()['options'];
-    }
-    catch (\Exception $e) {
-      return [];
-    }
-  }
-
 }
diff --git a/ext/search/Civi/Search/Display.php b/ext/search/Civi/Search/Display.php
new file mode 100644 (file)
index 0000000..aa23ac4
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Search;
+
+/**
+ * Class Display
+ * @package Civi\Search
+ */
+class Display {
+
+  /**
+   * @return array
+   */
+  public static function getPageSettings():array {
+    return [
+      'displayTypes' => self::getDisplayTypes(['name']),
+    ];
+  }
+
+  /**
+   * @param array $props
+   * @return array
+   */
+  public static function getDisplayTypes(array $props):array {
+    try {
+      return \Civi\Api4\SearchDisplay::getFields(FALSE)
+        ->setLoadOptions($props)
+        ->addWhere('name', '=', 'type')
+        ->execute()
+        ->first()['options'];
+    }
+    catch (\Exception $e) {
+      return [];
+    }
+  }
+
+}
index 54442bdcd0166b213bafd2d04e64ab002957b3a0..b806777464eb52a3385cd381cda82cb105442743 100644 (file)
@@ -11,4 +11,5 @@ return [
   ],
   'basePages' => ['civicrm/search'],
   'requires' => ['ngRoute', 'api4', 'crmUi', 'crmSearchDisplay'],
+  'settingsFactory' => ['\Civi\Search\Display', 'getPageSettings'],
 ];
index 0c8862c8691124f3cd7ba52a38ce9144adf6523c..8eafa0e1699dffd27a2e11ba2d0678c4fed27254 100644 (file)
@@ -4,11 +4,24 @@
   // Declare module
   angular.module('crmSearchPage', CRM.angRequires('crmSearchPage'))
 
-
     .config(function($routeProvider) {
+      // Load & render a SearchDisplay
       $routeProvider.when('/display/:savedSearchName/:displayName', {
         controller: 'crmSearchPageDisplay',
-        templateUrl: '~/crmSearchPage/display.html',
+        // Dynamic template generates the directive for each display type
+        template: function() {
+          var html =
+            '<h1 crm-page-title>{{:: $ctrl.display.label }}</h1>\n' +
+            '<div ng-switch="$ctrl.display.type" id="bootstrap-theme">\n';
+          _.each(CRM.crmSearchPage.displayTypes, function(type) {
+            html +=
+            '  <div ng-switch-when="' + type.name + '">\n' +
+            '    <crm-search-display-' + type.name + ' api-entity="$ctrl.apiEntity" api-params="$ctrl.apiParams" settings="$ctrl.display.settings"></crm-search-display-' + type.name + '>\n' +
+            '  </div>\n';
+          });
+          html += '</div>';
+          return html;
+        },
         resolve: {
           // Load saved search display
           display: function($route, crmApi4) {
@@ -25,6 +38,8 @@
     // Controller for displaying a search
     .controller('crmSearchPageDisplay', function($scope, $routeParams, $location, display) {
       this.display = display;
+      this.apiEntity = display['saved_search.api_entity'];
+      this.apiParams = display['saved_search.api_params'];
       $scope.$ctrl = this;
     });
 
diff --git a/ext/search/ang/crmSearchPage/display.html b/ext/search/ang/crmSearchPage/display.html
deleted file mode 100644 (file)
index 789963a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<h1 crm-page-title>{{:: $ctrl.display.label }}</h1>
-
-<div ng-switch="$ctrl.display.type" id="bootstrap-theme">
-  <div ng-switch-when="table">
-    <crm-search-display-table api-entity="$ctrl.display['saved_search.api_entity']" api-params="$ctrl.display['saved_search.api_params']" settings="$ctrl.display.settings"></crm-search-display-table>
-  </div>
-</div>
index a4b184b6ec136914cd1115651efba0285d2dcc1f..fb5ada405b23f48af79e93d58806b708e2b43df1 100644 (file)
@@ -41,7 +41,7 @@
         </div>
         <div ng-switch-default>
           <div ng-repeat="display in $ctrl.savedSearch.displays" ng-if="controls.tab === ('display_' + $index)">
-            <div ng-include="'~/searchAdmin/display.html'"></div>
+            <crm-search-admin-display display="display" saved-search="$ctrl.savedSearch"></crm-search-admin-display>
           </div>
         </div>
       </div>
diff --git a/ext/search/ang/searchAdmin/crmSearchAdminDisplay.component.js b/ext/search/ang/searchAdmin/crmSearchAdminDisplay.component.js
new file mode 100644 (file)
index 0000000..cc771b4
--- /dev/null
@@ -0,0 +1,54 @@
+(function(angular, $, _) {
+  "use strict";
+
+  angular.module('searchAdmin').component('crmSearchAdminDisplay', {
+    bindings: {
+      savedSearch: '<',
+      display: '<'
+    },
+    template: function() {
+      // Dynamic template generates switch condition for each display type
+      var html =
+        '<div ng-include="\'~/searchAdmin/crmSearchAdminDisplay.html\'"></div>\n' +
+        '<div ng-switch="$ctrl.display.type">\n';
+      _.each(CRM.searchAdmin.displayTypes, function(type) {
+        html +=
+          '<div ng-switch-when="' + type.name + '">\n' +
+          '  <search-admin-display-' + type.name + ' api-entity="$ctrl.savedSearch.api_entity" api-params="$ctrl.savedSearch.api_params" display="$ctrl.display"></search-admin-display-' + type.name + '>\n' +
+          '  <hr>\n' +
+          '  <button type="button" class="btn btn-{{ !$ctrl.stale ? \'success\' : $ctrl.preview ? \'warning\' : \'primary\' }}" ng-click="$ctrl.previewDisplay()" ng-disabled="!$ctrl.stale">\n' +
+          '  <i class="crm-i ' + type.icon + '"></i>' +
+          '  {{ $ctrl.preview && $ctrl.stale ? ts("Refresh") : ts("Preview") }}\n' +
+          '  </button>\n' +
+          '  <hr>\n' +
+          '  <div ng-if="$ctrl.preview">\n' +
+          '    <crm-search-display-' + type.name + ' api-entity="$ctrl.savedSearch.api_entity" api-params="$ctrl.savedSearch.api_params" settings="$ctrl.display.settings"></crm-search-display-' + type.name + '>\n' +
+          '  </div>\n' +
+          '</div>\n';
+      });
+      html += '</div>';
+      return html;
+    },
+    controller: function($scope, $timeout) {
+      var ts = $scope.ts = CRM.ts(),
+        ctrl = this;
+
+      this.preview = this.stale = false;
+
+      this.previewDisplay = function() {
+        ctrl.preview = !ctrl.preview;
+        ctrl.stale = false;
+        if (!ctrl.preview) {
+          $timeout(function() {
+            ctrl.preview = true;
+          }, 100);
+        }
+      };
+
+      $scope.$watch('$ctrl.display.settings', function() {
+        ctrl.stale = true;
+      }, true);
+    }
+  });
+
+})(angular, CRM.$, CRM._);
diff --git a/ext/search/ang/searchAdmin/crmSearchAdminDisplay.html b/ext/search/ang/searchAdmin/crmSearchAdminDisplay.html
new file mode 100644 (file)
index 0000000..812b0bb
--- /dev/null
@@ -0,0 +1,7 @@
+<fieldset>
+  <div class="form-inline">
+    <label for="search_display_label">{{:: ts('Name:') }} <span class="crm-marker">*</span></label>
+    <input id="search_display_label" type="text" class="form-control" ng-model="$ctrl.display.label" required />
+    <label class="pull-right">{{:: $ctrl.displayTypes[$ctrl.display.type].label }}</label>
+  </div>
+</fieldset>
diff --git a/ext/search/ang/searchAdmin/display.html b/ext/search/ang/searchAdmin/display.html
deleted file mode 100644 (file)
index 7e954ed..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<fieldset>
-  <div class="form-inline">
-    <label for="search_display_label">{{:: ts('Name:') }} <span class="crm-marker">*</span></label>
-    <input id="search_display_label" type="text" class="form-control" ng-model="display.label" required />
-    <label class="pull-right">{{:: $ctrl.displayTypes[display.type].label }}</label>
-  </div>
-</fieldset>
-<!-- Load template with the name of this display type, e.g. 'table.html' -->
-<div ng-if="display.type" ng-include="'~/searchAdmin/displays/' + display.type + '.html'"></div>
index 5d3b6b97b0ba6ee44c805408fd2125fb9141cae0..b2206148cebe36a0d9d4c9de61df45e5116617de 100644 (file)
@@ -40,7 +40,6 @@
       };
 
       this.$onInit = function () {
-        ctrl.display.settings.limit = parseInt(ctrl.display.settings.limit || 0, 10);
         ctrl.getFieldLabel = ctrl.crmSearchAdmin.getFieldLabel;
         if (!ctrl.display.settings.columns) {
           ctrl.display.settings.columns = _.transform(ctrl.apiParams.select, function(columns, fieldExpr) {
diff --git a/ext/search/ang/searchAdmin/displays/table.html b/ext/search/ang/searchAdmin/displays/table.html
deleted file mode 100644 (file)
index fb5bf38..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<search-admin-display-table api-entity="$ctrl.savedSearch.api_entity" api-params="$ctrl.savedSearch.api_params" display="display"></search-admin-display-table>
-<hr>
-<!--<crm-search-display-table api-entity="$ctrl.apiEntity" api-params="$ctrl.apiParams" settings="display.settings"></crm-search-display-table>-->
index 6f581bc714e53a8249c7cad5966ad052d1d852ca..1880310b7f5563b9c4b607cda652eadb5753194b 100644 (file)
@@ -33,6 +33,7 @@
         {{:: ts('Smart Group') }}
       </a>
     </li>
+    <li class="dropdown-header">{{ ts('Display:') }}</li>
     <li ng-repeat="type in ::$ctrl.displayTypes">
       <a href ng-click="$ctrl.addDisplay(type.name)">
         <i class="crm-i {{:: type.icon }}"></i>
index 88448c8c2da001696c76060909e4a227b6c74299..ce37a888686bc3e0e4020414f31aabbd56399bd5 100644 (file)
@@ -151,7 +151,7 @@ function search_civicrm_pre($op, $entity, $id, &$params) {
 function search_civicrm_alterAngular($angular) {
   $changeSet = \Civi\Angular\ChangeSet::create('searchSettings')
     ->alterHtml(';\\.aff\\.html$;', function($doc, $path) {
-      $displayTypes = array_column(\Civi\Search\Admin::getDisplayTypes(['name']), 'name');
+      $displayTypes = array_column(\Civi\Search\Display::getDisplayTypes(['name']), 'name');
 
       if ($displayTypes) {
         $componentNames = 'crm-search-display-' . implode(', crm-search-display-', $displayTypes);