From 007167dfb90eaaeb0c76f2c9e5b0327f0b3e22e9 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Sun, 26 Dec 2021 14:01:20 -0500 Subject: [PATCH] SearchKit/Afform - Provide contextual titles to search Afforms in standalone mode When displaying a full-page search with contextual filters, e.g. submissions for a particular form, provides a contextual title based on the url filter arg, e.g. "My Great Form Submissions" --- ang/crmUi.js | 9 ++- .../ang/afAdminFormSubmissionList.aff.html | 6 -- .../ang/afAdminFormSubmissionList.aff.json | 2 +- .../core/CRM/Afform/Page/AfformBase.php | 1 - ext/afform/core/afform.php | 3 +- ext/afform/core/ang/afCore.js | 8 +++ ext/afform/core/ang/afformStandalone.js | 6 +- .../templates/CRM/Afform/Page/AfformBase.tpl | 5 +- .../SearchDisplay/AbstractRunAction.php | 65 ++++++++++++++++++- .../Api4/Action/SearchDisplay/Download.php | 4 +- .../Civi/Api4/Action/SearchDisplay/Run.php | 5 +- .../Api4/Result/SearchDisplayRunResult.php | 26 ++++++++ .../traits/searchDisplayBaseTrait.service.js | 6 ++ .../traits/searchDisplayTasksTrait.service.js | 4 +- 14 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 ext/search_kit/Civi/Api4/Result/SearchDisplayRunResult.php diff --git a/ang/crmUi.js b/ang/crmUi.js index 944630d4db..3f091914b2 100644 --- a/ang/crmUi.js +++ b/ang/crmUi.js @@ -1083,15 +1083,20 @@ function update() { $timeout(function() { var newPageTitle = _.trim($el.html()), - newDocumentTitle = scope.crmDocumentTitle || $el.text(); + newDocumentTitle = scope.crmDocumentTitle || $el.text(), + h1Count = 0; document.title = $('title').text().replace(documentTitle, newDocumentTitle); // If the CMS has already added title markup to the page, use it $('h1').not('.crm-container h1').each(function() { - if (_.trim($(this).html()) === pageTitle) { + if ($(this).hasClass('crm-page-title') || _.trim($(this).html()) === pageTitle) { $(this).addClass('crm-page-title').html(newPageTitle); $el.hide(); + ++h1Count; } }); + if (!h1Count) { + $el.show(); + } pageTitle = newPageTitle; documentTitle = newDocumentTitle; }); diff --git a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.html b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.html index f26eb38f85..ff558c0097 100644 --- a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.html +++ b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.html @@ -1,9 +1,3 @@ -
-

{{ ts('%1 Submissions', {1: api4.result.title || ts('Loading')}) }}

-
diff --git a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json index 3e4fa2160d..abec61a2d0 100644 --- a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json +++ b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json @@ -1,6 +1,6 @@ { "type": "search", - "title": "Form Submissions", + "title": "Submissions", "server_route": "civicrm/admin/afform/submissions", "permission": "administer CiviCRM" } diff --git a/ext/afform/core/CRM/Afform/Page/AfformBase.php b/ext/afform/core/CRM/Afform/Page/AfformBase.php index aceb38f6e8..715913f5d8 100644 --- a/ext/afform/core/CRM/Afform/Page/AfformBase.php +++ b/ext/afform/core/CRM/Afform/Page/AfformBase.php @@ -40,7 +40,6 @@ class CRM_Afform_Page_AfformBase extends CRM_Core_Page { if (!empty($afform['title'])) { $title = strip_tags($afform['title']); - CRM_Utils_System::setTitle($title); if (!$isFrontEndPage) { CRM_Utils_System::appendBreadCrumb([ [ diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index 4832b26355..c0c8f0fc23 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -337,7 +337,7 @@ function afform_civicrm_buildAsset($asset, $params, &$mimeType, &$content) { $moduleName = _afform_angular_module_name($params['name'], 'camel'); $formMetaData = (array) civicrm_api4('Afform', 'get', [ 'checkPermissions' => FALSE, - 'select' => ['redirect', 'name'], + 'select' => ['redirect', 'name', 'title'], 'where' => [['name', '=', $params['name']]], ], 0); $smarty = CRM_Core_Smarty::singleton(); @@ -366,7 +366,6 @@ function afform_civicrm_alterMenu(&$items) { $items[$meta['server_route']] = [ 'page_callback' => 'CRM_Afform_Page_AfformBase', 'page_arguments' => 'afform=' . urlencode($name), - 'title' => $meta['title'] ?? '', 'access_arguments' => [["@afform:$name"], 'and'], 'is_public' => $meta['is_public'], ]; diff --git a/ext/afform/core/ang/afCore.js b/ext/afform/core/ang/afCore.js index cef661948e..ef64b2ee9d 100644 --- a/ext/afform/core/ang/afCore.js +++ b/ext/afform/core/ang/afCore.js @@ -21,6 +21,14 @@ $scope.$watch(function() {return $location.search();}, function(params) { $scope.routeParams = params; }); + + $scope.$parent.afformTitle = meta.title; + + // Prepends a string to the afform title + // Provides contextual titles to search Afforms in standalone mode + $scope.addTitle = function(addition) { + $scope.$parent.afformTitle = addition + ' ' + meta.title; + }; } }; return d; diff --git a/ext/afform/core/ang/afformStandalone.js b/ext/afform/core/ang/afformStandalone.js index 626551e40c..6d595fd426 100644 --- a/ext/afform/core/ang/afformStandalone.js +++ b/ext/afform/core/ang/afformStandalone.js @@ -1,5 +1,9 @@ (function(angular, $, _) { // Empty module just loads all available modules. - angular.module('afformStandalone', CRM.angular.modules); + angular.module('afformStandalone', CRM.angular.modules) + + .controller('AfformStandalonePageCtrl', function($scope) { + $scope.afformTitle = ''; + }); })(angular, CRM.$, CRM._); diff --git a/ext/afform/core/templates/CRM/Afform/Page/AfformBase.tpl b/ext/afform/core/templates/CRM/Afform/Page/AfformBase.tpl index ead23c7a08..273f6ff566 100644 --- a/ext/afform/core/templates/CRM/Afform/Page/AfformBase.tpl +++ b/ext/afform/core/templates/CRM/Afform/Page/AfformBase.tpl @@ -1,5 +1,8 @@ -
+ + {literal} +

{{ afformTitle }}

+ {/literal} <{$directive}>
diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php index 0ed8a5642c..0a693e5cc0 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php @@ -48,6 +48,14 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { */ protected $filters = []; + /** + * Filters passed directly into this display via Afform markup + * will have their labels appended to the Afform title. + * + * @var array + */ + protected $filterLabels = []; + /** * Integer used as a seed when ordering by RAND(). * This keeps the order stable enough to use a pager with random sorting. @@ -67,6 +75,14 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { */ private $_afform; + /** + * Override execute method to change the result object type + * @return \Civi\Api4\Result\SearchDisplayRunResult + */ + public function execute() { + return parent::execute(); + } + /** * @param \Civi\Api4\Generic\Result $result * @throws UnauthorizedException @@ -105,7 +121,7 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { $this->processResult($result); } - abstract protected function processResult(\Civi\Api4\Generic\Result $result); + abstract protected function processResult(\Civi\Api4\Result\SearchDisplayRunResult $result); /** * Transforms each row into an array of raw data and an array of formatted columns @@ -587,7 +603,8 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { */ protected function applyFilters() { // Allow all filters that are included in SELECT clause or are fields on the Afform. - $allowedFilters = array_merge($this->getSelectAliases(), $this->getAfformFilters()); + $afformFilters = $this->getAfformFilters(); + $allowedFilters = array_merge($this->getSelectAliases(), $afformFilters); // Ignore empty strings $filters = array_filter($this->filters, [$this, 'hasValue']); @@ -600,6 +617,9 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { if (in_array($key, $allowedFilters, TRUE) || !array_diff($fieldNames, $allowedFilters)) { $this->applyFilter($fieldNames, $value); } + if (in_array($key, $afformFilters, TRUE)) { + $this->addFilterLabel($key, $value); + } } } @@ -941,4 +961,45 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { ]; } + /** + * Sets $this->filterLabels to provide contextual titles to search Afforms + * + * @param $fieldName + * @param $value + * @throws \API_Exception + * @throws \Civi\API\Exception\NotImplementedException + */ + private function addFilterLabel($fieldName, $value) { + $field = $this->getField($fieldName); + if (!$field || !$value) { + return; + } + $idField = CoreUtil::getIdFieldName($field['entity']); + if ($field['name'] === $idField) { + $field['fk_entity'] = $field['entity']; + } + if (!empty($field['options'])) { + $options = civicrm_api4($field['entity'], 'getFields', [ + 'loadOptions' => TRUE, + 'where' => [['name', '=', $field['name']]], + ])->first()['options'] ?? []; + if (!empty($options[$value])) { + $this->filterLabels[] = $options[$value]; + } + } + elseif (!empty($field['fk_entity'])) { + $idField = CoreUtil::getIdFieldName($field['fk_entity']); + $labelField = CoreUtil::getInfoItem($field['fk_entity'], 'label_field'); + if ($labelField) { + $record = civicrm_api4($field['fk_entity'], 'get', [ + 'where' => [[$idField, '=', $value]], + 'select' => [$labelField], + ])->first() ?? NULL; + if (isset($record[$labelField])) { + $this->filterLabels[] = $record[$labelField]; + } + } + } + } + } diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/Download.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/Download.php index 7f8bd75a18..c2cf45f192 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/Download.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/Download.php @@ -46,10 +46,10 @@ class Download extends AbstractRunAction { ]; /** - * @param \Civi\Api4\Generic\Result $result + * @param \Civi\Api4\Result\SearchDisplayRunResult $result * @throws \API_Exception */ - protected function processResult(\Civi\Api4\Generic\Result $result) { + protected function processResult(\Civi\Api4\Result\SearchDisplayRunResult $result) { $entityName = $this->savedSearch['api_entity']; $apiParams =& $this->_apiParams; $settings = $this->display['settings']; diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php index 5a42ddb614..fad6bc95a5 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php @@ -29,10 +29,10 @@ class Run extends AbstractRunAction { protected $limit; /** - * @param \Civi\Api4\Generic\Result $result + * @param \Civi\Api4\Result\SearchDisplayRunResult $result * @throws \API_Exception */ - protected function processResult(\Civi\Api4\Generic\Result $result) { + protected function processResult(\Civi\Api4\Result\SearchDisplayRunResult $result) { $entityName = $this->savedSearch['api_entity']; $apiParams =& $this->_apiParams; $settings = $this->display['settings']; @@ -77,6 +77,7 @@ class Run extends AbstractRunAction { } else { $result->exchangeArray($this->formatResult($apiResult)); + $result->labels = $this->filterLabels; } } diff --git a/ext/search_kit/Civi/Api4/Result/SearchDisplayRunResult.php b/ext/search_kit/Civi/Api4/Result/SearchDisplayRunResult.php new file mode 100644 index 0000000000..d1c5fa37b4 --- /dev/null +++ b/ext/search_kit/Civi/Api4/Result/SearchDisplayRunResult.php @@ -0,0 +1,26 @@ +