From 9df0deac96f838106cf12316c5f7db0e742e70c7 Mon Sep 17 00:00:00 2001 From: Coleman Watts <coleman@civicrm.org> Date: Thu, 30 Jun 2022 14:42:35 -0400 Subject: [PATCH] Afform - Allow picking icon for tab, add CrmUiIconPicker widget Since this is needed in several places, this adds a general purpose crmUiIconPicker widget to crmUi. It also switches Afforms's hook_civicrm_tabset to use the API, which ensures virtual forms get picked up. Adds the new icon for CiviGrant as an example. --- ang/crmUi.js | 15 ++++++++ .../ang/afGuiEditor/afGuiEditor.component.js | 1 + .../admin/ang/afGuiEditor/config-form.html | 3 ++ ext/afform/core/Civi/Api4/Afform.php | 4 +++ ext/afform/core/afform.php | 36 +++++++++---------- ext/civigrant/ang/afsearchGrants.aff.json | 1 + .../common/searchAdminIcons.component.js | 9 ----- .../displays/common/searchAdminIcons.html | 2 +- 8 files changed, 43 insertions(+), 28 deletions(-) diff --git a/ang/crmUi.js b/ang/crmUi.js index 11eb5e28ef31..d8b56772bba0 100644 --- a/ang/crmUi.js +++ b/ang/crmUi.js @@ -1170,6 +1170,21 @@ }; }) + // Adds an icon picker widget + // Example: `<input crm-ui-icon-picker ng-model="model.icon">` + .directive('crmUiIconPicker', function($timeout) { + return { + restrict: 'A', + controller: function($element) { + CRM.loadScript(CRM.config.resourceBase + 'js/jquery/jquery.crmIconPicker.js').then(function() { + $timeout(function() { + $element.crmIconPicker(); + }); + }); + } + }; + }) + .run(function($rootScope, $location) { /// Example: <button ng-click="goto('home')">Go home!</button> $rootScope.goto = function(path) { diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js index 18283b58a5d9..e99e02c58ce8 100644 --- a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js +++ b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js @@ -95,6 +95,7 @@ editor.afform.is_dashlet = false; editor.afform.title += ' ' + ts('(copy)'); } + editor.afform.icon = editor.afform.icon || 'fa-list-alt'; $scope.canvasTab = 'layout'; $scope.layoutHtml = ''; $scope.entities = {}; diff --git a/ext/afform/admin/ang/afGuiEditor/config-form.html b/ext/afform/admin/ang/afGuiEditor/config-form.html index cb49a6f4fbf2..ca85a02cb134 100644 --- a/ext/afform/admin/ang/afGuiEditor/config-form.html +++ b/ext/afform/admin/ang/afGuiEditor/config-form.html @@ -71,6 +71,9 @@ <option value="block">{{:: ts('As Block') }}</option> <option value="tab">{{:: ts('As Tab') }}</option> </select> + <div class="form-group" ng-show="editor.afform.contact_summary === 'tab'"> + <input required ng-model="editor.afform.icon" crm-ui-icon-picker class="form-control"> + </div> </div> <p class="help-block">{{:: ts('Placement can be configured using the Contact Layout Editor.') }}</p> </div> diff --git a/ext/afform/core/Civi/Api4/Afform.php b/ext/afform/core/Civi/Api4/Afform.php index 3c48e9ef0545..15d2aea8d8f2 100644 --- a/ext/afform/core/Civi/Api4/Afform.php +++ b/ext/afform/core/Civi/Api4/Afform.php @@ -165,6 +165,10 @@ public static function getFields($checkPermissions = TRUE) { 'tab' => ts('Contact Summary Tab'), ], ], + [ + 'name' => 'icon', + 'description' => 'Icon shown in the contact summary tab', + ], [ 'name' => 'server_route', ], diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index 898dd8c08e49..19f86de1ad57 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -178,25 +178,25 @@ function afform_civicrm_tabset($tabsetName, &$tabs, $context) { if ($tabsetName !== 'civicrm/contact/view') { return; } - $scanner = \Civi::service('afform_scanner'); + $afforms = Civi\Api4\Afform::get(FALSE) + ->addWhere('contact_summary', '=', 'tab') + ->addSelect('name', 'title', 'icon', 'module_name', 'directive_name') + ->execute(); $weight = 111; - foreach ($scanner->getMetas() as $afform) { - if (!empty($afform['contact_summary']) && $afform['contact_summary'] === 'tab') { - $module = _afform_angular_module_name($afform['name']); - $tabs[] = [ - 'id' => $afform['name'], - 'title' => $afform['title'], - 'weight' => $weight++, - 'icon' => 'crm-i fa-list-alt', - 'is_active' => TRUE, - 'template' => 'afform/contactSummary/AfformTab.tpl', - 'module' => $module, - 'directive' => _afform_angular_module_name($afform['name'], 'dash'), - ]; - // If this is the real contact summary page (and not a callback from ContactLayoutEditor), load module. - if (empty($context['caller'])) { - Civi::service('angularjs.loader')->addModules($module); - } + foreach ($afforms as $afform) { + $tabs[] = [ + 'id' => $afform['name'], + 'title' => $afform['title'], + 'weight' => $weight++, + 'icon' => 'crm-i ' . ($afform['icon'] ?: 'fa-list-alt'), + 'is_active' => TRUE, + 'template' => 'afform/contactSummary/AfformTab.tpl', + 'module' => $afform['module_name'], + 'directive' => $afform['directive_name'], + ]; + // If this is the real contact summary page (and not a callback from ContactLayoutEditor), load module. + if (empty($context['caller'])) { + Civi::service('angularjs.loader')->addModules($afform['module_name']); } } } diff --git a/ext/civigrant/ang/afsearchGrants.aff.json b/ext/civigrant/ang/afsearchGrants.aff.json index 093d18d9f91b..44b9ee3dcdd2 100644 --- a/ext/civigrant/ang/afsearchGrants.aff.json +++ b/ext/civigrant/ang/afsearchGrants.aff.json @@ -2,6 +2,7 @@ "type": "search", "title": "Grants", "contact_summary": "tab", + "icon": "fa-money", "server_route": "", "permission": "access CiviGrant" } diff --git a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js index d8a1e5eb69e7..6a7d439f9e90 100644 --- a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js +++ b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js @@ -22,12 +22,6 @@ }; }; - function initWidgets() { - CRM.loadScript(CRM.config.resourceBase + 'js/jquery/jquery.crmIconPicker.js').then(function() { - $('.crm-search-admin-field-icon > input.crm-icon-picker[ng-model]', $element).crmIconPicker(); - }); - } - this.$onInit = function() { $element.on('hidden.bs.dropdown', function() { $timeout(function() { @@ -51,7 +45,6 @@ } ctrl.iconFields = _.transform(allFields, getIconFields, []); ctrl.iconFieldMap = _.indexBy(ctrl.iconFields, 'id'); - $timeout(initWidgets); }; this.onSelectField = function(clause) { @@ -72,7 +65,6 @@ searchMeta.pickIcon().then(function(icon) { if (icon) { ctrl.item.icons.push({icon: icon, side: 'left', if: []}); - $timeout(initWidgets); } }); } @@ -85,7 +77,6 @@ item.icon = icon; delete item.field; item.if = item.if || []; - $timeout(initWidgets); } }); }; diff --git a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.html b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.html index 98d7676884c7..dd698a81fcbc 100644 --- a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.html +++ b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.html @@ -17,7 +17,7 @@ </div> </div> <div class="form-group crm-search-admin-field-icon" ng-if="icon.icon"> - <input required ng-model="icon.icon" class="form-control crm-icon-picker"> + <input required ng-model="icon.icon" crm-ui-icon-picker class="form-control crm-icon-picker"> </div> <select class="form-control" ng-model="icon.side" title="{{:: ts('Show icon on left or right side of the field') }}"> <option value="left">{{:: ts('Align left') }}</option>