From 142479d861de3a2e8487daa68acbbef001900747 Mon Sep 17 00:00:00 2001 From: Rich Lott / Artful Robot Date: Mon, 3 Mar 2025 11:55:12 +0000 Subject: [PATCH] Add Category history saved search and searchkit display and afform for contact sum --- ang/afsearchCategory.aff.html | 3 + ang/afsearchCategory.aff.json | 31 +++++ ang/crmSearchDisplayContactCat.ang.php | 9 +- ang/crmSearchDisplayContactCat.css | 3 + ang/crmSearchDisplayContactCat.js | 47 +++++++- .../crmSearchDisplayContactCat.html | 45 ++++--- managed/SavedSearch_Category_history.mgd.php | 110 ++++++++++++++++++ 7 files changed, 228 insertions(+), 20 deletions(-) create mode 100644 ang/afsearchCategory.aff.html create mode 100644 ang/afsearchCategory.aff.json create mode 100644 managed/SavedSearch_Category_history.mgd.php diff --git a/ang/afsearchCategory.aff.html b/ang/afsearchCategory.aff.html new file mode 100644 index 0000000..165d885 --- /dev/null +++ b/ang/afsearchCategory.aff.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/ang/afsearchCategory.aff.json b/ang/afsearchCategory.aff.json new file mode 100644 index 0000000..cf40055 --- /dev/null +++ b/ang/afsearchCategory.aff.json @@ -0,0 +1,31 @@ +{ + "type": "search", + "requires": null, + "entity_type": null, + "join_entity": null, + "title": "Category", + "description": null, + "placement": [ + "contact_summary_block" + ], + "summary_contact_type": [ + "Individual" + ], + "summary_weight": 1, + "icon": "fa-user-tag", + "server_route": "", + "is_public": false, + "permission": [ + "access CiviCRM" + ], + "permission_operator": "AND", + "redirect": null, + "submit_enabled": true, + "submit_limit": null, + "create_submission": false, + "manual_processing": false, + "allow_verification_by_email": false, + "email_confirmation_template_id": null, + "navigation": null, + "modified_date": "2025-03-03 11:26:32" +} diff --git a/ang/crmSearchDisplayContactCat.ang.php b/ang/crmSearchDisplayContactCat.ang.php index 8abd092..6658377 100644 --- a/ang/crmSearchDisplayContactCat.ang.php +++ b/ang/crmSearchDisplayContactCat.ang.php @@ -15,8 +15,11 @@ return [ 'partials' => [ 'ang/crmSearchDisplayContactCat', ], - 'requires' => ['crmUi', 'crmUtil', 'ngRoute'], + 'requires' => ['crmSearchDisplay', 'crmSearchTasks', 'crmUi', 'crmUtil', 'ngRoute'], 'settings' => [], - 'basePages' => ['civicrm/search', 'civicrm/admin/search'], - 'exports' => ['crmSearchAdminDisplayContactCat', 'crmSearchDisplayContactCat'], + 'basePages' => ['civicrm/search', 'civicrm/admin/search', 'civicrm/contact/view'], + 'exports' => [ + 'crm-search-admin-display-contact-cat' => 'E', + 'crm-search-display-contact-cat' => 'E', + ], ]; diff --git a/ang/crmSearchDisplayContactCat.css b/ang/crmSearchDisplayContactCat.css index 3e97d42..4426f0f 100644 --- a/ang/crmSearchDisplayContactCat.css +++ b/ang/crmSearchDisplayContactCat.css @@ -1 +1,4 @@ /* Add any CSS rules for Angular module "crmContactcats" */ +.crm-contact-page .crm-search-display-contact-cat { + padding: var(--crm-dash-block-padding); +} diff --git a/ang/crmSearchDisplayContactCat.js b/ang/crmSearchDisplayContactCat.js index 3986962..34c9e6c 100644 --- a/ang/crmSearchDisplayContactCat.js +++ b/ang/crmSearchDisplayContactCat.js @@ -1,10 +1,11 @@ -console.log(123); +console.log('crmSearchDisplayContactCat.js loaded'); // see https://docs.civicrm.org/dev/en/latest/searchkit/displays/ (function(angular, $, _) { // Declare a list of dependencies. angular.module('crmSearchDisplayContactCat', CRM.angRequires('crmSearchDisplayContactCat')); // angular.module('crmContactcats').component(); + console.log('crmSearchDisplayContactCat module registered'); // This is to be the display // NOTE: the component name is {CamelCaseNameFromOptionValue} // Standard seems to be to name crmSearchDisplay{YourName} @@ -20,21 +21,60 @@ console.log(123); totalCount: '=?' }, // controller: function($scope, $timeout, crmApi4, crmStatus, $document) { - controller: function($scope, $element, searchDisplayBaseTrait, searchDisplayTasksTrait) { + controller: function($scope, $element, crmApi4, searchDisplayBaseTrait, searchDisplayTasksTrait) { + console.log('crmSearchDisplayContactCat controller called'); // Mix in required traits ctrl = angular.extend(this, _.cloneDeep(searchDisplayBaseTrait), _.cloneDeep(searchDisplayTasksTrait)); console.log("hello display"); var ts = ($scope.ts = CRM.ts(null)), ctrl = this; + ctrl.catDefs = null; + ctrl.resultsVM = {}; + ctrl.n = 1; // this.$onInit gets run after the this controller is called, and after the bindings have been applied. this.$onInit = function() { console.log("calling initializeDisplay"); + // Grab all the category definitions + crmApi4('ContactCategoryDefinition', 'get', { + orderBy: {presentation_order: 'ASC'} + }, 'id').then(r => { ctrl.catDefs = r; console.log('catDefs', ctrl.catDefs); ctrl.n++; }); this.initializeDisplay($scope, $element); }; + + $scope.$watch('$ctrl.results', () => { ctrl.n++; }, true); + $scope.$watch('$ctrl.n', () => { + console.log("watch n running"); + if (!ctrl.catDefs || !ctrl.results?.count) { + console.log("...waiting for all the data we need"); + ctrl.ourData = { + rows: [], + count: 0, + }; + return ctrl.n; + } + + const rows = ctrl.results.map((row) => { + const d = (new Date(row.data.activity_date_time.replace(' ', 'T'))).toLocaleString('UTC', { + weekday: 'short', + day: 'numeric', + month: 'short', + year: 'numeric', + }); + return { + contact_id: row.data['Activity_ActivityContact_Contact_01.id'], + new: ctrl.catDefs[row.data['Category_changes.new_category_id']], + when: d, + }; + }); + ctrl.ourData = {rows, count:rows.length}; + console.log("new ourData", ctrl.ourData); + return ctrl.n; + }); } }); + console.log('crmSearchDisplayContactCat registering admin bit'); // This is to be the admin settings for the display // NOTE: the component name is 'searchAdminDisplay'{CamelCaseValueFromOptionValue} angular.module("crmSearchDisplayContactCat").component("searchAdminDisplayContactCat", { @@ -48,7 +88,7 @@ console.log(123); parent: '^crmSearchAdminDisplay' }, controller: function($scope, searchMeta, crmUiHelp) { - console.log("hello admin"); + console.log("hello admin controller"); let ctrl = this; // var ts = ($scope.ts = CRM.ts(null)), // ctrl = this; @@ -69,5 +109,6 @@ console.log(123); ctrl.parent.initColumns({}); }; }}); + console.log('crmSearchDisplayContactCat ends'); })(angular, CRM.$, CRM._); diff --git a/ang/crmSearchDisplayContactCat/crmSearchDisplayContactCat.html b/ang/crmSearchDisplayContactCat/crmSearchDisplayContactCat.html index 49fd2a9..58bd3bb 100644 --- a/ang/crmSearchDisplayContactCat/crmSearchDisplayContactCat.html +++ b/ang/crmSearchDisplayContactCat/crmSearchDisplayContactCat.html @@ -1,18 +1,35 @@
-

This is the crmSearchDisplayContactCat thing

-
-
-
-
-
    -
  1. - - - {{row.data['category_definition_id:label']}} - -
  2. + + + + -
-
+
+ +
+ + {{ts('Category')}}: + {{ts('Loading')}} + + + {{$ctrl.ourData.rows[0].new.label}} + + +
+ {{ts('Category History')}} + +
    +
  1. + {{row.when}} → + + {{row.new.label}} + +
  2. +
+ +
+
+
+
diff --git a/managed/SavedSearch_Category_history.mgd.php b/managed/SavedSearch_Category_history.mgd.php new file mode 100644 index 0000000..ccaa062 --- /dev/null +++ b/managed/SavedSearch_Category_history.mgd.php @@ -0,0 +1,110 @@ + 'SavedSearch_Category_history', + 'entity' => 'SavedSearch', + 'cleanup' => 'unused', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'Category_history', + 'label' => E::ts('Category history'), + 'api_entity' => 'Activity', + 'api_params' => [ + 'version' => 4, + 'select' => [ + 'Activity_ActivityContact_Contact_01.id', + 'id', + 'Activity_ActivityContact_Contact_01.sort_name', + 'Category_changes.previous_category_id', + 'Category_changes.new_category_id', + 'activity_date_time', + ], + 'orderBy' => [], + 'where' => [ + [ + 'activity_type_id:name', + '=', + 'changed_contact_category', + ], + ], + 'groupBy' => [], + 'join' => [ + [ + 'Contact AS Activity_ActivityContact_Contact_01', + 'INNER', + 'ActivityContact', + [ + 'id', + '=', + 'Activity_ActivityContact_Contact_01.activity_id', + ], + [ + 'Activity_ActivityContact_Contact_01.record_type_id:name', + '=', + '"Activity Targets"', + ], + ], + ], + 'having' => [], + ], + ], + 'match' => ['name'], + ], + ], + [ + 'name' => 'SavedSearch_Category_history_SearchDisplay_Category_history_Category_1', + 'entity' => 'SearchDisplay', + 'cleanup' => 'unused', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'Category_history_Category_1', + 'label' => E::ts('Category history Category 1'), + 'saved_search_id.name' => 'Category_history', + 'type' => 'contact-cat', + 'settings' => [ + 'something' => 'nothing', + 'limit' => 50, + 'sort' => [], + 'pager' => [], + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'Activity_ActivityContact_Contact_01.id', + 'dataType' => 'Integer', + ], + [ + 'type' => 'field', + 'key' => 'id', + 'dataType' => 'Integer', + ], + [ + 'type' => 'field', + 'key' => 'Activity_ActivityContact_Contact_01.sort_name', + 'dataType' => 'String', + ], + [ + 'type' => 'field', + 'key' => 'Category_changes.previous_category_id', + 'dataType' => 'Integer', + ], + [ + 'type' => 'field', + 'key' => 'Category_changes.new_category_id', + 'dataType' => 'Integer', + ], + ], + ], + ], + 'match' => [ + 'saved_search_id', + 'name', + ], + ], + ], +];