APIv4 - Improve saveSearch popup in Explorer
authorColeman Watts <coleman@civicrm.org>
Tue, 17 Mar 2020 20:28:14 +0000 (16:28 -0400)
committerColeman Watts <coleman@civicrm.org>
Fri, 20 Mar 2020 12:51:15 +0000 (08:51 -0400)
CRM/Api4/Page/Api4Explorer.php
ang/api4Explorer.ang.php
ang/api4Explorer/Explorer.html
ang/api4Explorer/Explorer.js
ang/api4Explorer/SaveSearch.html
css/api4-explorer.css

index adc1d74326dd8727a288a7d3ebd8b359045632ff..77eb0d1e5337f3752e4f144d984ca36224faf6c8 100644 (file)
@@ -21,16 +21,18 @@ class CRM_Api4_Page_Api4Explorer extends CRM_Core_Page {
 
   public function run() {
     $apiDoc = new ReflectionFunction('civicrm_api4');
+    $groupOptions = civicrm_api4('Group', 'getFields', ['loadOptions' => TRUE, 'select' => ['options', 'name'], 'where' => [['name', 'IN', ['visibility', 'group_type']]]]);
     $vars = [
       'operators' => \CRM_Core_DAO::acceptedSQLOperators(),
       'basePath' => Civi::resources()->getUrl('civicrm'),
       'schema' => (array) \Civi\Api4\Entity::get()->setChain(['fields' => ['$name', 'getFields']])->execute(),
       'links' => (array) \Civi\Api4\Entity::getLinks()->execute(),
       'docs' => \Civi\Api4\Utils\ReflectionUtils::parseDocBlock($apiDoc->getDocComment()),
+      'groupOptions' => array_column((array) $groupOptions, 'options', 'name'),
     ];
     Civi::resources()
       ->addVars('api4', $vars)
-      ->addPermissions(['access debug output'])
+      ->addPermissions(['access debug output', 'edit groups', 'administer reserved groups'])
       ->addScriptFile('civicrm', 'js/load-bootstrap.js')
       ->addScriptFile('civicrm', 'bower_components/js-yaml/dist/js-yaml.min.js')
       ->addScriptFile('civicrm', 'bower_components/marked/marked.min.js')
index 816856b86df8c00bddae1ac05f08f657617d19b8..2eec108aaf14abe9d0c390e7640a8c7c12c596ef 100644 (file)
@@ -13,5 +13,5 @@ return [
     'ang/api4Explorer',
   ],
   'basePages' => [],
-  'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'crmRouteBinder', 'ui.sortable', 'api4', 'ngSanitize', 'dialogService'],
+  'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'crmRouteBinder', 'ui.sortable', 'api4', 'ngSanitize', 'dialogService', 'checklist-model'],
 ];
index 90d3287deb4b5ac9c37c2554c815c8493f780260..659917ecb2fe8a459cc27c658148f563459784ef 100644 (file)
@@ -26,7 +26,7 @@
             </span>
             <input class="form-control api4-index" type="search" ng-model="index" ng-mouseenter="help('index', paramDoc('$index'))" ng-mouseleave="help()" placeholder="{{ ts('Index') }}" />
             <button class="btn btn-success pull-right" crm-icon="fa-bolt" ng-disabled="!entity || !action || loading" ng-click="execute()" ng-mouseenter="help(ts('Execute'), executeDoc())" ng-mouseleave="help()">{{ ts('Execute') }}</button>
-            <button class="btn btn-primary pull-right" crm-icon="fa-save" ng-show="entity === 'Contact' && action === 'get'" ng-click="save()" ng-mouseenter="help(ts('Save smart group'), saveDoc())" ng-mouseleave="help()">{{ ts('Save...') }}</button>
+            <button class="btn btn-primary pull-right" crm-icon="fa-save" ng-show="perm.editGroups && entity === 'Contact' && action === 'get'" ng-click="save()" ng-mouseenter="help(ts('Save smart group'), saveDoc())" ng-mouseleave="help()">{{ ts('Save...') }}</button>
           </div>
         </div>
         <div class="panel-body">
index b589bdaaf3e420d137891fb8fa411281d5e3d012..09db7d1d02a2023fee9ea88a87af0f7e462f5bf5 100644 (file)
@@ -32,7 +32,8 @@
     $scope.index = '';
     $scope.selectedTab = {result: 'result', code: 'php'};
     $scope.perm = {
-      accessDebugOutput: CRM.checkPerm('access debug output')
+      accessDebugOutput: CRM.checkPerm('access debug output'),
+      editGroups: CRM.checkPerm('edit groups')
     };
     marked.setOptions({highlight: prettyPrintOne});
     var getMetaParams = {},
     $scope.save = function() {
       var model = {
         title: '',
+        description: '',
+        visibility: 'User and User Admin Only',
+        group_type: [],
         id: null,
         entity: $scope.entity,
         params: JSON.parse(angular.toJson($scope.params))
   angular.module('api4Explorer').controller('SaveSearchCtrl', function($scope, crmApi4, dialogService) {
     var ts = $scope.ts = CRM.ts(),
       model = $scope.model;
+    $scope.groupEntityRefParams = {
+      entity: 'Group',
+      api: {
+        params: {is_hidden: 0, is_active: 1, 'saved_search_id.api_entity': model.entity},
+        extra: ['saved_search_id', 'description', 'visibility', 'group_type']
+      },
+      select: {
+        allowClear: true,
+        minimumInputLength: 0,
+        placeholder: ts('Select existing group')
+      }
+    };
+    if (!CRM.checkPerm('administer reserved groups')) {
+      $scope.groupEntityRefParams.api.params.is_reserved = 0;
+    }
+    $scope.perm = {
+      administerReservedGroups: CRM.checkPerm('administer reserved groups')
+    };
+    $scope.options = CRM.vars.api4.groupOptions;
     $scope.$watch('model.id', function(id) {
       if (id) {
-        model.description = $('#api-save-search-select-group').select2('data').extra.description;
+        _.assign(model, $('#api-save-search-select-group').select2('data').extra);
       }
     });
     $scope.cancel = function() {
       $('.ui-dialog:visible').block();
       var group = model.id ? {id: model.id} : {title: model.title};
       group.description = model.description;
+      group.visibility = model.visibility;
+      group.group_type = model.group_type;
       group.saved_search_id = '$id';
       var savedSearch = {
         api_entity: model.entity,
         api_params: model.params
       };
       if (group.id) {
-        savedSearch.id = $('#api-save-search-select-group').select2('data').extra.saved_search_id;
+        savedSearch.id = model.saved_search_id;
       }
       crmApi4('SavedSearch', 'save', {records: [savedSearch], chain: {group: ['Group', 'save', {'records': [group]}]}})
         .then(function(result) {
index 2935d325fec698644d40e3d84754216502597591..72ffecfeaf88ccdb4f52a87196d5750d92c4ed97 100644 (file)
@@ -1,13 +1,25 @@
 <form id="bootstrap-theme">
   <div ng-controller="SaveSearchCtrl">
-    <input class="form-control" id="api-save-search-select-group" ng-model="model.id" crm-entityref="{entity: 'Group', api: {extra: ['saved_search_id', 'description'], params: {is_hidden: 0, is_active: 1, 'saved_search_id.api_entity': model.entity}}, select: {allowClear: true, placeholder: ts('Select existing group')}}" >
+    <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">
+    <hr />
     <label>{{ ts('Description:') }}</label>
-    <textarea ng-model="model.description"></textarea>
+    <textarea class="form-control" ng-model="model.description"></textarea>
+    <label>{{ ts('Group Type:') }}</label>
+    <div class="form-inline">
+      <div class="checkbox" ng-repeat="(key, label) in options.group_type">
+        <label>
+          <input type="checkbox" checklist-model="model.group_type" checklist-value="key">
+          {{ label }}
+        </label>
+      </div>
+    </div>
+    <label>{{ ts('Visibility:') }}</label>
+    <select class="form-control" ng-model="model.visibility" ng-options="name as value for (name, value) in options.visibility"></select>
     <hr />
     <div class="buttons pull-right">
-      <button ng-click="cancel()" class="btn btn-danger">{{ ts('Cancel') }}</button>
+      <button type="button" ng-click="cancel()" class="btn btn-danger">{{ ts('Cancel') }}</button>
       <button ng-click="save()" class="btn btn-primary" ng-disabled="!model.title && !model.id">{{ ts('Save') }}</button>
     </div>
   </div>
index ae419a5086cbb2f60c14bc8a1220366441cca43f..077f95b7bef4a907beaa1eb9d1779de19b56de09 100644 (file)
@@ -199,6 +199,14 @@ div.select2-drop.collapsible-optgroups-enabled .select2-result-with-children.opt
   content: "\f0d7";
 }
 
+/* Another weird shoreditch fix */
+#bootstrap-theme .form-inline div.checkbox {
+  margin-right: 1em;
+}
+#bootstrap-theme .form-inline div.checkbox label input[type=checkbox] {
+  margin: 0;
+}
+
 /**
  * Shims so the UI isn't completely broken when a Bootstrap theme is not installed
  */