Search ext: Add vertical tabs
authorColeman Watts <coleman@civicrm.org>
Sun, 18 Oct 2020 04:03:39 +0000 (00:03 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 29 Oct 2020 23:48:28 +0000 (19:48 -0400)
ext/search/Civi/Search/Admin.php
ext/search/ang/searchActions/saveSmartGroup.directive.js
ext/search/ang/searchAdmin/compose/controls.html [moved from ext/search/ang/searchAdmin/crmSearch/controls.html with 56% similarity]
ext/search/ang/searchAdmin/compose/criteria.html [moved from ext/search/ang/searchAdmin/crmSearch/criteria.html with 86% similarity]
ext/search/ang/searchAdmin/compose/debug.html [moved from ext/search/ang/searchAdmin/crmSearch/debug.html with 100% similarity]
ext/search/ang/searchAdmin/compose/pager.html [moved from ext/search/ang/searchAdmin/crmSearch/pager.html with 100% similarity]
ext/search/ang/searchAdmin/compose/results.html [moved from ext/search/ang/searchAdmin/crmSearch/results.html with 100% similarity]
ext/search/ang/searchAdmin/crmSearch.component.js
ext/search/ang/searchAdmin/crmSearch.html
ext/search/ang/searchAdmin/tabs.html [new file with mode: 0644]

index a0de3e6059a827fdd1dc68a227007e0b3a5d4a83..1867ac5b49ff3ebfa255ae88177350e372d660e6 100644 (file)
@@ -24,6 +24,11 @@ class Admin {
     return [
       'operators' => \CRM_Utils_Array::makeNonAssociative(self::getOperators()),
       'functions' => \CRM_Api4_Page_Api4Explorer::getSqlFunctions(),
+      'displayTypes' => \Civi\Api4\SearchDisplay::getFields(FALSE)
+        ->setLoadOptions(['name', 'label', 'description', 'icon'])
+        ->addWhere('name', '=', 'type')
+        ->execute()
+        ->first()['options'],
     ];
   }
 
index c53a387cdcc7cb7179064525edd8eeffcc2858b4..9f59a7d668b55d497a2dc0cf209de05076bf02d0 100644 (file)
             autoOpen: false,
             title: ts('Save smart group')
           });
-          dialogService.open('saveSearchDialog', '~/searchActions/saveSmartGroup.html', model, options)
-            .then(function () {
-              if (ctrl.load) {
-                ctrl.load.saved = true;
-              }
-            });
+          dialogService.open('saveSearchDialog', '~/searchActions/saveSmartGroup.html', model, options);
         };
       }
     };
similarity index 56%
rename from ext/search/ang/searchAdmin/crmSearch/controls.html
rename to ext/search/ang/searchAdmin/compose/controls.html
index 873d4f097f07664675fcfaebb96700f9619f6b87..77a8b7774029a06ce72171ec258d0c134e6ee12f 100644 (file)
     </button>
   </div>
   <crm-search-actions entity="$ctrl.savedSearch.api_entity" ids="$ctrl.selectedRows" refresh="$ctrl.refreshPage()"></crm-search-actions>
-  <div class="btn-group pull-right">
-    <button type="button" class="btn btn-default form-control dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-      <i class="crm-i fa-save"></i> {{:: ts('Create')}}
-      <span class="caret"></span>
-    </button>
-    <ul class="dropdown-menu">
-      <li ng-if=":: $ctrl.perm.editGroups">
-        <a href save-smart-group load="$ctrl.load" entity="$ctrl.savedSearch.api_entity" params="$ctrl.savedSearch.api_params" ng-click="saveGroup()">{{:: ts('Smart Group') }}</a>
-      </li>
-    </ul>
-  </div>
 </div>
similarity index 86%
rename from ext/search/ang/searchAdmin/crmSearch/criteria.html
rename to ext/search/ang/searchAdmin/compose/criteria.html
index adbeb7343ef8aad407db35d8523c24b6c7696853..1cfa81ba708d05c38823a1b7a8d9847f10b44697 100644 (file)
     </fieldset>
   </div>
   <div>
-    <div class="navbar-form clearfix" ng-if="$ctrl.load">
-      <div class="form-group pull-right">
-        <label>{{ $ctrl.load.title }}</label>
-        <button ng-if=":: $ctrl.perm.editGroups" save-smart-group load="$ctrl.load" entity="$ctrl.savedSearch.api_entity" params="$ctrl.savedSearch.api_params" class="btn btn-default" ng-disabled="$ctrl.load.saved" ng-click="saveGroup()">
-          {{ $ctrl.load.saved ? ts('Saved') : ts('Save') }}
-        </button>
-      </div>
-    </div>
     <fieldset class="api4-clause-fieldset">
       <crm-search-clause clauses="$ctrl.savedSearch.api_params.where" format="string" op="AND" label="{{ ts('Where') }}" fields="fieldsForWhere" ></crm-search-clause>
     </fieldset>
index b4a2b1548b9971a62671fcb6f9793c8e4959b9b8..7ee57f62b839da95dbdb4ddc43aaf62236135275 100644 (file)
@@ -15,6 +15,7 @@
       this.selectedRows = [];
       this.limit = CRM.cache.get('searchPageSize', 30);
       this.page = 1;
+      this.displayTypes = _.indexBy(CRM.searchAdmin.displayTypes, 'name');
       // After a search this.results is an object of result arrays keyed by page,
       // Initially this.results is an empty string because 1: it's falsey (unlike an empty object) and 2: it doesn't throw an error if you try to access undefined properties (unlike null)
       this.results = '';
@@ -23,7 +24,7 @@
       // Have the filters (WHERE, HAVING, GROUP BY, JOIN) changed?
       this.stale = true;
 
-      $scope.controls = {};
+      $scope.controls = {tab: 'compose'};
       $scope.joinTypes = [{k: false, v: ts('Optional')}, {k: true, v: ts('Required')}];
       $scope.entities = formatForSelect2(CRM.vars.search.schema, 'name', 'title_plural', ['description', 'icon']);
       this.perm = {
@@ -33,6 +34,8 @@
       this.$onInit = function() {
         this.entityTitle = searchMeta.getEntity(this.savedSearch.api_entity).title_plural;
 
+        this.savedSearch.displays = this.savedSearch.displays || [];
+
         if (!this.savedSearch.api_params) {
           this.savedSearch.api_params = {
             select: getDefaultSelect(),
         return _.includes(searchMeta.getEntity(ctrl.savedSearch.api_entity).params, param);
       };
 
+      this.addDisplay = function(type) {
+        $scope.controls.tab = 'display_' + ctrl.savedSearch.displays.length;
+        ctrl.savedSearch.displays.push({
+          type: type
+        });
+      };
+
       $scope.getJoinEntities = function() {
         var joinEntities = _.transform(CRM.vars.search.links[ctrl.savedSearch.api_entity], function(joinEntities, link) {
           var entity = searchMeta.getEntity(link.entity);
           }
         }
         if (ctrl.load) {
-          ctrl.load.saved = false;
+          ctrl.saved = false;
         }
       }
 
         ctrl.stale = true;
         ctrl.selectedRows.length = 0;
         if (ctrl.load) {
-          ctrl.load.saved = false;
+          ctrl.saved = false;
         }
         if (ctrl.autoSearch) {
           ctrl.refreshAll();
index de97c672a6a607ad34908e509c83a6cc318d87a0..a6b8dff76d4940e4a8e0a415d686bc51a4c3d700 100644 (file)
   </div>
 
   <form>
-    <div ng-include="'~/searchAdmin/crmSearch/criteria.html'"></div>
-    <div ng-include="'~/searchAdmin/crmSearch/controls.html'"></div>
-    <div ng-include="'~/searchAdmin/crmSearch/debug.html'" ng-if="$ctrl.debug"></div>
-    <div ng-include="'~/searchAdmin/crmSearch/results.html'" class="crm-search-results"></div>
-    <div ng-include="'~/searchAdmin/crmSearch/pager.html'"></div>
+    <div class="navbar-form clearfix">
+      <div class="form-group pull-right">
+        <button class="btn btn-default" ng-disabled="$ctrl.saved" ng-click="$ctrl.save()">
+          {{ $ctrl.saved ? ts('Saved') : ts('Save') }}
+        </button>
+      </div>
+    </div>
+    <div class="crm-flex-box">
+      <ul class="nav nav-pills nav-stacked" ng-include="'~/searchAdmin/tabs.html'"></ul>
+      <div class="crm-flex-4" ng-switch="controls.tab">
+        <div ng-switch-when="compose">
+          <div ng-include="'~/searchAdmin/compose/criteria.html'"></div>
+          <div ng-include="'~/searchAdmin/compose/controls.html'"></div>
+          <div ng-include="'~/searchAdmin/compose/debug.html'" ng-if="$ctrl.debug"></div>
+          <div ng-include="'~/searchAdmin/compose/results.html'" class="crm-search-results"></div>
+          <div ng-include="'~/searchAdmin/compose/pager.html'"></div>
+        </div>
+        <div ng-switch-when="group">
+        </div>
+        <div ng-switch-default>
+        </div>
+      </div>
+    </div>
   </form>
 </div>
diff --git a/ext/search/ang/searchAdmin/tabs.html b/ext/search/ang/searchAdmin/tabs.html
new file mode 100644 (file)
index 0000000..e70810e
--- /dev/null
@@ -0,0 +1,28 @@
+<li role="presentation" ng-class="{active: controls.tab === 'compose'}">
+  <a href ng-click="controls.tab = 'compose'">
+    <i class="crm-i fa-gears"></i>
+    {{ ts('Compose Search') }}
+  </a>
+</li>
+<li role="presentation" ng-class="{active: controls.tab === 'group'}">
+  <a href ng-click="controls.tab = 'group'">
+    <i class="crm-i fa-users"></i>
+    {{ ts('Smart Group: %1') }}
+  </a>
+</li>
+<li role="presentation" ng-repeat="display in $ctrl.savedSearch.displays" ng-class="{active: controls.tab === ('display_' + $index)}">
+  <a href ng-click="controls.tab = ('display_' + $index)">
+    <i class="crm-i {{ $ctrl.displayTypes[display.type].icon }}"></i>
+    {{ $ctrl.displayTypes[display.type].label }}
+  </a>
+</li>
+<li role="presentation">
+  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+    <i class="crm-i fa-plus"></i> {{ ts('Add Display') }} <span class="caret"></span>
+  </button>
+  <ul class="dropdown-menu">
+    <li ng-repeat="type in $ctrl.displayTypes" >
+      <a href ng-click="$ctrl.addDisplay(type.name)">{{ type.label }}</a>
+    </li>
+  </ul>
+</li>