From 493f83d421b6b3a4f8ea9d0d7438b1084e471625 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 29 Oct 2020 13:18:48 -0400 Subject: [PATCH] Search ext: decouple actions, add searchKit base module, rename searchAdmin module to crmSearchAdmin --- ext/search/ang/crmSearchActions.ang.php | 4 +- .../crmSearchActionDelete.ctrl.js | 5 +- .../crmSearchActionUpdate.ctrl.js | 23 ++++++--- .../crmSearchActionUpdate.html | 4 +- .../crmSearchActions.component.js | 18 ++++--- ext/search/ang/crmSearchAdmin.ang.php | 18 +++++++ ...min.module.js => crmSearchAdmin.module.js} | 22 ++------ .../compose/controls.html | 0 .../compose/criteria.html | 0 .../compose/debug.html | 0 .../compose/pager.html | 0 .../compose/results.html | 0 .../crmSearchAdmin.component.js | 6 +-- .../crmSearchAdmin.html | 14 +++--- .../crmSearchAdminDisplay.component.js | 6 +-- .../crmSearchAdminDisplay.html | 0 .../crmSearchClause.component.js | 25 ++++++++-- .../crmSearchClause.html | 2 +- .../crmSearchFunction.component.js | 8 +-- .../crmSearchFunction.html | 0 .../searchAdminDisplayTable.component.js | 4 +- .../displays/searchAdminDisplayTable.html | 1 + .../group.html | 0 .../searchList.controller.js | 4 +- .../searchList.html | 0 .../{searchAdmin => crmSearchAdmin}/tabs.html | 0 ext/search/ang/crmSearchDisplay.ang.php | 2 +- .../crmSearchDisplayTable.component.js | 50 ++++++++++++++++--- .../crmSearchDisplayTable.html | 7 ++- ext/search/ang/crmSearchKit.ang.php | 14 ++++++ ext/search/ang/crmSearchKit.module.js | 21 ++++++++ .../crmSearchValue.directive.js | 8 ++- ext/search/ang/searchAdmin.ang.php | 18 ------- 33 files changed, 184 insertions(+), 100 deletions(-) create mode 100644 ext/search/ang/crmSearchAdmin.ang.php rename ext/search/ang/{searchAdmin.module.js => crmSearchAdmin.module.js} (87%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/compose/controls.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/compose/criteria.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/compose/debug.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/compose/pager.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/compose/results.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchAdmin.component.js (99%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchAdmin.html (80%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchAdminDisplay.component.js (89%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchAdminDisplay.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchClause.component.js (75%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchClause.html (95%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchFunction.component.js (77%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/crmSearchFunction.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/displays/searchAdminDisplayTable.component.js (93%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/displays/searchAdminDisplayTable.html (94%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/group.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/searchList.controller.js (83%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/searchList.html (100%) rename ext/search/ang/{searchAdmin => crmSearchAdmin}/tabs.html (100%) create mode 100644 ext/search/ang/crmSearchKit.ang.php create mode 100644 ext/search/ang/crmSearchKit.module.js rename ext/search/ang/{searchAdmin => crmSearchKit}/crmSearchValue.directive.js (93%) delete mode 100644 ext/search/ang/searchAdmin.ang.php diff --git a/ext/search/ang/crmSearchActions.ang.php b/ext/search/ang/crmSearchActions.ang.php index 4b0841c470..478cd09609 100644 --- a/ext/search/ang/crmSearchActions.ang.php +++ b/ext/search/ang/crmSearchActions.ang.php @@ -1,5 +1,5 @@ [ 'ang/crmSearchActions.module.js', @@ -10,7 +10,7 @@ return [ 'ang/crmSearchActions', ], 'basePages' => [], - 'requires' => ['crmUi', 'crmUtil', 'dialogService', 'api4'], + 'requires' => ['crmUi', 'crmUtil', 'dialogService', 'api4', 'crmSearchKit'], 'settingsFactory' => ['\Civi\Search\Actions', 'getActionSettings'], 'permissions' => ['edit groups', 'administer reserved groups'], ]; diff --git a/ext/search/ang/crmSearchActions/crmSearchActionDelete.ctrl.js b/ext/search/ang/crmSearchActions/crmSearchActionDelete.ctrl.js index b842e96a39..d7c3f48282 100644 --- a/ext/search/ang/crmSearchActions/crmSearchActionDelete.ctrl.js +++ b/ext/search/ang/crmSearchActions/crmSearchActionDelete.ctrl.js @@ -1,13 +1,12 @@ (function(angular, $, _) { "use strict"; - angular.module('crmSearchActions').controller('crmSearchActionDelete', function($scope, crmApi4, dialogService, searchMeta) { + angular.module('crmSearchActions').controller('crmSearchActionDelete', function($scope, crmApi4, dialogService) { var ts = $scope.ts = CRM.ts(), model = $scope.model, ctrl = $scope.$ctrl = this; - this.entity = searchMeta.getEntity(model.entity); - this.entityTitle = model.ids.length === 1 ? this.entity.title : this.entity.titlePlural; + this.entityTitle = model.ids.length === 1 ? model.entityInfo.title : model.entityInfo.title_plural; this.cancel = function() { dialogService.cancel('crmSearchAction'); diff --git a/ext/search/ang/crmSearchActions/crmSearchActionUpdate.ctrl.js b/ext/search/ang/crmSearchActions/crmSearchActionUpdate.ctrl.js index 229d75c735..01bd9e67ee 100644 --- a/ext/search/ang/crmSearchActions/crmSearchActionUpdate.ctrl.js +++ b/ext/search/ang/crmSearchActions/crmSearchActionUpdate.ctrl.js @@ -1,19 +1,20 @@ (function(angular, $, _) { "use strict"; - angular.module('crmSearchActions').controller('crmSearchActionUpdate', function ($scope, $timeout, crmApi4, dialogService, searchMeta) { + angular.module('crmSearchActions').controller('crmSearchActionUpdate', function ($scope, $timeout, crmApi4, dialogService) { var ts = $scope.ts = CRM.ts(), model = $scope.model, ctrl = $scope.$ctrl = this; - this.entity = searchMeta.getEntity(model.entity); - this.entityTitle = model.ids.length === 1 ? this.entity.title : this.entity.titlePlural; + this.entityTitle = model.ids.length === 1 ? model.entityInfo.title : model.entityInfo.title_plural; this.values = []; this.add = null; + this.fields = null; - function fieldInUse(fieldName) { - return _.includes(_.collect(ctrl.values, 0), fieldName); - } + crmApi4(model.entity, 'getFields', {action: 'update', loadOptions: ['id', 'name', 'label', 'description', 'color', 'icon']}) + .then(function(fields) { + ctrl.fields = fields; + }); this.updateField = function(index) { // Debounce the onchange event using timeout @@ -34,8 +35,16 @@ }); }; + this.getField = function(fieldName) { + return _.where(ctrl.fields, {name: fieldName})[0]; + }; + + function fieldInUse(fieldName) { + return _.includes(_.collect(ctrl.values, 0), fieldName); + } + this.availableFields = function() { - var results = _.transform(ctrl.entity.fields, function(result, item) { + var results = _.transform(ctrl.fields, function(result, item) { var formatted = {id: item.name, text: item.label, description: item.description}; if (fieldInUse(item.name)) { formatted.disabled = true; diff --git a/ext/search/ang/crmSearchActions/crmSearchActionUpdate.html b/ext/search/ang/crmSearchActions/crmSearchActionUpdate.html index a1af56da3c..bb1a380337 100644 --- a/ext/search/ang/crmSearchActions/crmSearchActionUpdate.html +++ b/ext/search/ang/crmSearchActions/crmSearchActionUpdate.html @@ -3,10 +3,10 @@

{{:: ts('Update the %1 selected %2 with the following values:', {1: model.ids.length, 2: $ctrl.entityTitle}) }}

- +
- +

diff --git a/ext/search/ang/crmSearchActions/crmSearchActions.component.js b/ext/search/ang/crmSearchActions/crmSearchActions.component.js index 1958e5da63..1c300db7b5 100644 --- a/ext/search/ang/crmSearchActions/crmSearchActions.component.js +++ b/ext/search/ang/crmSearchActions/crmSearchActions.component.js @@ -8,7 +8,7 @@ ids: '<' }, templateUrl: '~/crmSearchActions/crmSearchActions.html', - controller: function($scope, crmApi4, dialogService, searchMeta) { + controller: function($scope, crmApi4, dialogService) { var ts = $scope.ts = CRM.ts(), ctrl = this, initialized = false, @@ -23,16 +23,17 @@ } function initialize() { - var entityTitle = searchMeta.getEntity(ctrl.entity).title_plural; - crmApi4(ctrl.entity, 'getActions', { - where: [['name', 'IN', ['update', 'delete']]], - }, ['name']).then(function(allowed) { - _.each(allowed, function(action) { + crmApi4({ + entityInfo: ['Entity', 'get', {select: ['name', 'title', 'title_plural'], where: [['name', '=', ctrl.entity]]}, 0], + allowed: [ctrl.entity, 'getActions', {where: [['name', 'IN', ['update', 'delete']]]}, ['name']] + }).then(function(result) { + ctrl.entityInfo = result.entityInfo; + _.each(result.allowed, function(action) { CRM.crmSearchActions.tasks[action].entities.push(ctrl.entity); }); var actions = _.transform(_.cloneDeep(CRM.crmSearchActions.tasks), function(actions, action) { if (_.includes(action.entities, ctrl.entity)) { - action.title = action.title.replace('%1', entityTitle); + action.title = action.title.replace('%1', ctrl.entityInfo.title_plural); actions.push(action); } }, []); @@ -50,7 +51,8 @@ } var data = { ids: ctrl.ids, - entity: ctrl.entity + entity: ctrl.entity, + entityInfo: ctrl.entityInfo }; // If action uses a crmPopup form if (action.crmPopup) { diff --git a/ext/search/ang/crmSearchAdmin.ang.php b/ext/search/ang/crmSearchAdmin.ang.php new file mode 100644 index 0000000000..d582bd0708 --- /dev/null +++ b/ext/search/ang/crmSearchAdmin.ang.php @@ -0,0 +1,18 @@ + [ + 'ang/crmSearchAdmin.module.js', + 'ang/crmSearchAdmin/*.js', + 'ang/crmSearchAdmin/*/*.js', + ], + 'css' => [ + 'css/*.css', + ], + 'partials' => [ + 'ang/crmSearchAdmin', + ], + 'basePages' => ['civicrm/admin/search'], + 'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'ui.sortable', 'ui.bootstrap', 'api4', 'crmSearchDisplay', 'crmSearchActions', 'crmSearchKit'], + 'settingsFactory' => ['\Civi\Search\Admin', 'getAdminSettings'], +]; diff --git a/ext/search/ang/searchAdmin.module.js b/ext/search/ang/crmSearchAdmin.module.js similarity index 87% rename from ext/search/ang/searchAdmin.module.js rename to ext/search/ang/crmSearchAdmin.module.js index bb3fbf2d5e..af31489c9a 100644 --- a/ext/search/ang/searchAdmin.module.js +++ b/ext/search/ang/crmSearchAdmin.module.js @@ -6,12 +6,12 @@ undefined; // Declare module and route/controller/services - angular.module('searchAdmin', CRM.angRequires('searchAdmin')) + angular.module('crmSearchAdmin', CRM.angRequires('crmSearchAdmin')) .config(function($routeProvider) { $routeProvider.when('/list', { controller: 'searchList', - templateUrl: '~/searchAdmin/searchList.html', + templateUrl: '~/crmSearchAdmin/searchList.html', resolve: { // Load data for lists savedSearches: function(crmApi4) { @@ -116,7 +116,7 @@ if (bracketPos >= 0) { var parsed = expr.substr(bracketPos).match(/[ ]?([A-Z]+[ ]+)?([\w.:]+)/); fieldName = parsed[2]; - result.fn = _.find(CRM.searchAdmin.functions, {name: expr.substring(0, bracketPos)}); + result.fn = _.find(CRM.crmSearchAdmin.functions, {name: expr.substring(0, bracketPos)}); result.modifier = _.trim(parsed[1]); } result.field = expr ? getField(fieldName, searchEntity) : undefined; @@ -142,7 +142,7 @@ if ((entityName === 'Contact' && field.name === 'id') || field.fk_entity === 'Contact') { columns.push({ id: prefix + field.name, - text: entity.titlePlural + (entityCount[entityName] ? ' ' + entityCount[entityName] : '') + ': ' + field.label, + text: entity.title_plural + (entityCount[entityName] ? ' ' + entityCount[entityName] : '') + ': ' + field.label, icon: entity.icon }); } @@ -151,20 +151,6 @@ }); } }; - }) - - // Reformat an array of objects for compatibility with select2 - // Todo this probably belongs in core - .factory('formatForSelect2', function() { - return function(input, key, label, extra) { - return _.transform(input, function(result, item) { - var formatted = {id: item[key], text: item[label]}; - if (extra) { - _.merge(formatted, _.pick(item, extra)); - } - result.push(formatted); - }, []); - }; }); })(angular, CRM.$, CRM._); diff --git a/ext/search/ang/searchAdmin/compose/controls.html b/ext/search/ang/crmSearchAdmin/compose/controls.html similarity index 100% rename from ext/search/ang/searchAdmin/compose/controls.html rename to ext/search/ang/crmSearchAdmin/compose/controls.html diff --git a/ext/search/ang/searchAdmin/compose/criteria.html b/ext/search/ang/crmSearchAdmin/compose/criteria.html similarity index 100% rename from ext/search/ang/searchAdmin/compose/criteria.html rename to ext/search/ang/crmSearchAdmin/compose/criteria.html diff --git a/ext/search/ang/searchAdmin/compose/debug.html b/ext/search/ang/crmSearchAdmin/compose/debug.html similarity index 100% rename from ext/search/ang/searchAdmin/compose/debug.html rename to ext/search/ang/crmSearchAdmin/compose/debug.html diff --git a/ext/search/ang/searchAdmin/compose/pager.html b/ext/search/ang/crmSearchAdmin/compose/pager.html similarity index 100% rename from ext/search/ang/searchAdmin/compose/pager.html rename to ext/search/ang/crmSearchAdmin/compose/pager.html diff --git a/ext/search/ang/searchAdmin/compose/results.html b/ext/search/ang/crmSearchAdmin/compose/results.html similarity index 100% rename from ext/search/ang/searchAdmin/compose/results.html rename to ext/search/ang/crmSearchAdmin/compose/results.html diff --git a/ext/search/ang/searchAdmin/crmSearchAdmin.component.js b/ext/search/ang/crmSearchAdmin/crmSearchAdmin.component.js similarity index 99% rename from ext/search/ang/searchAdmin/crmSearchAdmin.component.js rename to ext/search/ang/crmSearchAdmin/crmSearchAdmin.component.js index 0e98c31d9d..b5a34a34e3 100644 --- a/ext/search/ang/searchAdmin/crmSearchAdmin.component.js +++ b/ext/search/ang/crmSearchAdmin/crmSearchAdmin.component.js @@ -1,11 +1,11 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').component('crmSearchAdmin', { + angular.module('crmSearchAdmin').component('crmSearchAdmin', { bindings: { savedSearch: '<' }, - templateUrl: '~/searchAdmin/crmSearchAdmin.html', + templateUrl: '~/crmSearchAdmin/crmSearchAdmin.html', controller: function($scope, $element, $timeout, crmApi4, dialogService, searchMeta, formatForSelect2) { var ts = $scope.ts = CRM.ts(), ctrl = this; @@ -15,7 +15,7 @@ this.selectedRows = []; this.limit = CRM.cache.get('searchPageSize', 30); this.page = 1; - this.displayTypes = _.indexBy(CRM.searchAdmin.displayTypes, 'name'); + this.displayTypes = _.indexBy(CRM.crmSearchAdmin.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 = ''; diff --git a/ext/search/ang/searchAdmin/crmSearchAdmin.html b/ext/search/ang/crmSearchAdmin/crmSearchAdmin.html similarity index 80% rename from ext/search/ang/searchAdmin/crmSearchAdmin.html rename to ext/search/ang/crmSearchAdmin/crmSearchAdmin.html index a8201e12a7..570df17b20 100644 --- a/ext/search/ang/searchAdmin/crmSearchAdmin.html +++ b/ext/search/ang/crmSearchAdmin/crmSearchAdmin.html @@ -27,17 +27,17 @@
- +
-
-
-
-
-
+
+
+
+
+
-
+
diff --git a/ext/search/ang/searchAdmin/crmSearchAdminDisplay.component.js b/ext/search/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js similarity index 89% rename from ext/search/ang/searchAdmin/crmSearchAdminDisplay.component.js rename to ext/search/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js index cc771b468d..4bdf10f9db 100644 --- a/ext/search/ang/searchAdmin/crmSearchAdminDisplay.component.js +++ b/ext/search/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js @@ -1,7 +1,7 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').component('crmSearchAdminDisplay', { + angular.module('crmSearchAdmin').component('crmSearchAdminDisplay', { bindings: { savedSearch: '<', display: '<' @@ -9,9 +9,9 @@ template: function() { // Dynamic template generates switch condition for each display type var html = - '
\n' + + '
\n' + '
\n'; - _.each(CRM.searchAdmin.displayTypes, function(type) { + _.each(CRM.crmSearchAdmin.displayTypes, function(type) { html += '
\n' + ' \n' + diff --git a/ext/search/ang/searchAdmin/crmSearchAdminDisplay.html b/ext/search/ang/crmSearchAdmin/crmSearchAdminDisplay.html similarity index 100% rename from ext/search/ang/searchAdmin/crmSearchAdminDisplay.html rename to ext/search/ang/crmSearchAdmin/crmSearchAdminDisplay.html diff --git a/ext/search/ang/searchAdmin/crmSearchClause.component.js b/ext/search/ang/crmSearchAdmin/crmSearchClause.component.js similarity index 75% rename from ext/search/ang/searchAdmin/crmSearchClause.component.js rename to ext/search/ang/crmSearchAdmin/crmSearchClause.component.js index 884eae6bf5..3c196a440b 100644 --- a/ext/search/ang/searchAdmin/crmSearchClause.component.js +++ b/ext/search/ang/crmSearchAdmin/crmSearchClause.component.js @@ -1,7 +1,7 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').component('crmSearchClause', { + angular.module('crmSearchAdmin').component('crmSearchClause', { bindings: { fields: '<', clauses: '<', @@ -11,12 +11,13 @@ label: '@', deleteGroup: '&' }, - templateUrl: '~/searchAdmin/crmSearchClause.html', - controller: function ($scope, $element, $timeout) { + templateUrl: '~/crmSearchAdmin/crmSearchClause.html', + controller: function ($scope, $element, $timeout, searchMeta) { var ts = $scope.ts = CRM.ts(), - ctrl = this; + ctrl = this, + meta = {}; this.conjunctions = {AND: ts('And'), OR: ts('Or'), NOT: ts('Not')}; - this.operators = CRM.searchAdmin.operators; + this.operators = CRM.crmSearchAdmin.operators; this.sortOptions = { axis: 'y', connectWith: '.api4-clause-group-sortable', @@ -30,6 +31,20 @@ ctrl.hasParent = !!$element.attr('delete-group'); }; + this.getField = function(expr) { + if (!meta[expr]) { + meta[expr] = searchMeta.parseExpr(expr); + } + return meta[expr].field; + }; + + this.getOptionKey = function(expr) { + if (!meta[expr]) { + meta[expr] = searchMeta.parseExpr(expr); + } + return meta[expr].suffix ? meta[expr].suffix.slice(1) : 'id'; + }; + this.addGroup = function(op) { ctrl.clauses.push([op, []]); }; diff --git a/ext/search/ang/searchAdmin/crmSearchClause.html b/ext/search/ang/crmSearchAdmin/crmSearchClause.html similarity index 95% rename from ext/search/ang/searchAdmin/crmSearchClause.html rename to ext/search/ang/crmSearchAdmin/crmSearchClause.html index a50df23725..bcc23f7038 100644 --- a/ext/search/ang/searchAdmin/crmSearchClause.html +++ b/ext/search/ang/crmSearchAdmin/crmSearchClause.html @@ -17,7 +17,7 @@
- +
diff --git a/ext/search/ang/searchAdmin/crmSearchFunction.component.js b/ext/search/ang/crmSearchAdmin/crmSearchFunction.component.js similarity index 77% rename from ext/search/ang/searchAdmin/crmSearchFunction.component.js rename to ext/search/ang/crmSearchAdmin/crmSearchFunction.component.js index 4ac5870576..ff009085f8 100644 --- a/ext/search/ang/searchAdmin/crmSearchFunction.component.js +++ b/ext/search/ang/crmSearchAdmin/crmSearchFunction.component.js @@ -1,18 +1,18 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').component('crmSearchFunction', { + angular.module('crmSearchAdmin').component('crmSearchFunction', { bindings: { expr: '=', cat: '<' }, - templateUrl: '~/searchAdmin/crmSearchFunction.html', + templateUrl: '~/crmSearchAdmin/crmSearchFunction.html', controller: function($scope, formatForSelect2, searchMeta) { var ts = $scope.ts = CRM.ts(), ctrl = this; this.$onInit = function() { - ctrl.functions = formatForSelect2(_.where(CRM.searchAdmin.functions, {category: ctrl.cat}), 'name', 'title'); + ctrl.functions = formatForSelect2(_.where(CRM.crmSearchAdmin.functions, {category: ctrl.cat}), 'name', 'title'); var fieldInfo = searchMeta.parseExpr(ctrl.expr); ctrl.path = fieldInfo.path + fieldInfo.suffix; ctrl.field = fieldInfo.field; @@ -22,7 +22,7 @@ }; function initFunction() { - ctrl.fnInfo = _.find(CRM.searchAdmin.functions, {name: ctrl.fn}); + ctrl.fnInfo = _.find(CRM.crmSearchAdmin.functions, {name: ctrl.fn}); if (ctrl.fnInfo && _.includes(ctrl.fnInfo.params[0].prefix, 'DISTINCT')) { ctrl.modifierAllowed = true; } diff --git a/ext/search/ang/searchAdmin/crmSearchFunction.html b/ext/search/ang/crmSearchAdmin/crmSearchFunction.html similarity index 100% rename from ext/search/ang/searchAdmin/crmSearchFunction.html rename to ext/search/ang/crmSearchAdmin/crmSearchFunction.html diff --git a/ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.component.js b/ext/search/ang/crmSearchAdmin/displays/searchAdminDisplayTable.component.js similarity index 93% rename from ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.component.js rename to ext/search/ang/crmSearchAdmin/displays/searchAdminDisplayTable.component.js index b2206148ce..871d5f7805 100644 --- a/ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.component.js +++ b/ext/search/ang/crmSearchAdmin/displays/searchAdminDisplayTable.component.js @@ -1,7 +1,7 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').component('searchAdminDisplayTable', { + angular.module('crmSearchAdmin').component('searchAdminDisplayTable', { bindings: { display: '<', apiEntity: '<', @@ -10,7 +10,7 @@ require: { crmSearchAdmin: '^crmSearchAdmin' }, - templateUrl: '~/searchAdmin/displays/searchAdminDisplayTable.html', + templateUrl: '~/crmSearchAdmin/displays/searchAdminDisplayTable.html', controller: function($scope, searchMeta) { var ts = $scope.ts = CRM.ts(), ctrl = this; diff --git a/ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.html b/ext/search/ang/crmSearchAdmin/displays/searchAdminDisplayTable.html similarity index 94% rename from ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.html rename to ext/search/ang/crmSearchAdmin/displays/searchAdminDisplayTable.html index 4367c4c6c7..e65c0b6ba0 100644 --- a/ext/search/ang/searchAdmin/displays/searchAdminDisplayTable.html +++ b/ext/search/ang/crmSearchAdmin/displays/searchAdminDisplayTable.html @@ -3,6 +3,7 @@ +
diff --git a/ext/search/ang/searchAdmin/group.html b/ext/search/ang/crmSearchAdmin/group.html similarity index 100% rename from ext/search/ang/searchAdmin/group.html rename to ext/search/ang/crmSearchAdmin/group.html diff --git a/ext/search/ang/searchAdmin/searchList.controller.js b/ext/search/ang/crmSearchAdmin/searchList.controller.js similarity index 83% rename from ext/search/ang/searchAdmin/searchList.controller.js rename to ext/search/ang/crmSearchAdmin/searchList.controller.js index c6609dbe3c..aebfc761cb 100644 --- a/ext/search/ang/searchAdmin/searchList.controller.js +++ b/ext/search/ang/crmSearchAdmin/searchList.controller.js @@ -1,12 +1,12 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').controller('searchList', function($scope, savedSearches, crmApi4) { + angular.module('crmSearchAdmin').controller('searchList', function($scope, savedSearches, crmApi4) { var ts = $scope.ts = CRM.ts(), ctrl = $scope.$ctrl = this; this.savedSearches = savedSearches; this.entityTitles = _.transform(CRM.vars.search.schema, function(titles, entity) { - titles[entity.name] = entity.titlePlural; + titles[entity.name] = entity.title_plural; }, {}); this.searchPath = window.location.href.split('#')[0].replace('civicrm/admin/search', 'civicrm/search'); diff --git a/ext/search/ang/searchAdmin/searchList.html b/ext/search/ang/crmSearchAdmin/searchList.html similarity index 100% rename from ext/search/ang/searchAdmin/searchList.html rename to ext/search/ang/crmSearchAdmin/searchList.html diff --git a/ext/search/ang/searchAdmin/tabs.html b/ext/search/ang/crmSearchAdmin/tabs.html similarity index 100% rename from ext/search/ang/searchAdmin/tabs.html rename to ext/search/ang/crmSearchAdmin/tabs.html diff --git a/ext/search/ang/crmSearchDisplay.ang.php b/ext/search/ang/crmSearchDisplay.ang.php index a2524b3396..31d98189de 100644 --- a/ext/search/ang/crmSearchDisplay.ang.php +++ b/ext/search/ang/crmSearchDisplay.ang.php @@ -1,5 +1,5 @@ [ 'ang/crmSearchDisplay.module.js', diff --git a/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.component.js b/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.component.js index 6cfef82713..09fa60a56f 100644 --- a/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.component.js +++ b/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.component.js @@ -14,6 +14,8 @@ ctrl = this; this.page = 1; + this.selectedRows = []; + this.allRowsSelected = false; this.$onInit = function() { this.orderBy = _.cloneDeep(this.apiParams.orderBy || {}); @@ -29,7 +31,7 @@ }); }; - function getResults() { + this.getResults = function() { var params = _.merge(_.cloneDeep(ctrl.apiParams), {limit: ctrl.limit, offset: (ctrl.page - 1) * ctrl.limit, orderBy: ctrl.orderBy}); if (_.isEmpty(params.where)) { params.where = []; @@ -46,13 +48,9 @@ ctrl.results = results; ctrl.rowCount = results.count; }); - } - - this.changePage = function() { - getResults(); }; - $scope.$watch('$ctrl.filters', getResults, true); + $scope.$watch('$ctrl.filters', ctrl.getResults, true); /** * Returns crm-i icon class for a sortable column @@ -78,7 +76,7 @@ ctrl.orderBy = {}; } ctrl.orderBy[col.key] = dir; - getResults(); + ctrl.getResults(); }; $scope.formatResult = function(row, col) { @@ -105,6 +103,44 @@ return value; } + $scope.selectAllRows = function() { + // Deselect all + if (ctrl.allRowsSelected) { + ctrl.allRowsSelected = false; + ctrl.selectedRows.length = 0; + return; + } + // Select all + ctrl.allRowsSelected = true; + if (ctrl.page === 1 && ctrl.results[1].length < ctrl.limit) { + ctrl.selectedRows = _.pluck(ctrl.results[1], 'id'); + return; + } + // If more than one page of results, use ajax to fetch all ids + $scope.loadingAllRows = true; + var params = _.cloneDeep(ctrl.apiParams); + params.select = ['id']; + crmApi4(ctrl.apiEntity, 'get', params, ['id']).then(function(ids) { + $scope.loadingAllRows = false; + ctrl.selectedRows = _.toArray(ids); + }); + }; + + $scope.selectRow = function(row) { + var index = ctrl.selectedRows.indexOf(row.id); + if (index < 0) { + ctrl.selectedRows.push(row.id); + ctrl.allRowsSelected = (ctrl.rowCount === ctrl.selectedRows.length); + } else { + ctrl.allRowsSelected = false; + ctrl.selectedRows.splice(index, 1); + } + }; + + $scope.isRowSelected = function(row) { + return ctrl.allRowsSelected || _.includes(ctrl.selectedRows, row.id); + }; + } }); diff --git a/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.html b/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.html index 7583ea3f0a..cf006e89df 100644 --- a/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.html +++ b/ext/search/ang/crmSearchDisplay/crmSearchDisplayTable.html @@ -1,3 +1,6 @@ +
+ +
@@ -13,7 +16,7 @@
- + {{ formatResult(row, col) }} @@ -28,7 +31,7 @@ boundary-links="true" total-items="$ctrl.rowCount" ng-model="$ctrl.page" - ng-change="$ctrl.changePage()" + ng-change="$ctrl.getResults()" items-per-page="$ctrl.limit" max-size="6" force-ellipses="true" diff --git a/ext/search/ang/crmSearchKit.ang.php b/ext/search/ang/crmSearchKit.ang.php new file mode 100644 index 0000000000..e48bd14ce0 --- /dev/null +++ b/ext/search/ang/crmSearchKit.ang.php @@ -0,0 +1,14 @@ + [ + 'ang/crmSearchKit.module.js', + 'ang/crmSearchKit/*.js', + 'ang/crmSearchKit/*/*.js', + ], + 'partials' => [ + 'ang/crmSearchKit', + ], + 'basePages' => [], + 'requires' => ['api4'], +]; diff --git a/ext/search/ang/crmSearchKit.module.js b/ext/search/ang/crmSearchKit.module.js new file mode 100644 index 0000000000..76caa98e61 --- /dev/null +++ b/ext/search/ang/crmSearchKit.module.js @@ -0,0 +1,21 @@ +(function(angular, $, _) { + "use strict"; + + // Declare module + angular.module('crmSearchKit', CRM.angRequires('crmSearchKit')) + + // Reformat an array of objects for compatibility with select2 + // Todo this probably belongs in core + .factory('formatForSelect2', function() { + return function(input, key, label, extra) { + return _.transform(input, function(result, item) { + var formatted = {id: item[key], text: item[label]}; + if (extra) { + _.merge(formatted, _.pick(item, extra)); + } + result.push(formatted); + }, []); + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ext/search/ang/searchAdmin/crmSearchValue.directive.js b/ext/search/ang/crmSearchKit/crmSearchValue.directive.js similarity index 93% rename from ext/search/ang/searchAdmin/crmSearchValue.directive.js rename to ext/search/ang/crmSearchKit/crmSearchValue.directive.js index 2f3b7f5b20..2d1bbd09e5 100644 --- a/ext/search/ang/searchAdmin/crmSearchValue.directive.js +++ b/ext/search/ang/crmSearchKit/crmSearchValue.directive.js @@ -1,7 +1,7 @@ (function(angular, $, _) { "use strict"; - angular.module('searchAdmin').directive('crmSearchValue', function($interval, searchMeta, formatForSelect2) { + angular.module('crmSearchKit').directive('crmSearchValue', function($interval, formatForSelect2) { return { scope: { data: '=crmSearchValue' @@ -102,10 +102,8 @@ scope.$watchCollection('data', function(data) { destroyWidget(); - var field = searchMeta.parseExpr(data.field).field; - if (field) { - var optionKey = data.field.split(':')[1] || 'id'; - makeWidget(field, data.op, optionKey); + if (data.field) { + makeWidget(data.field, data.op, data.optionKey || 'id'); } }); } diff --git a/ext/search/ang/searchAdmin.ang.php b/ext/search/ang/searchAdmin.ang.php deleted file mode 100644 index 4b944adcd6..0000000000 --- a/ext/search/ang/searchAdmin.ang.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'ang/searchAdmin.module.js', - 'ang/searchAdmin/*.js', - 'ang/searchAdmin/*/*.js', - ], - 'css' => [ - 'css/*.css', - ], - 'partials' => [ - 'ang/searchAdmin', - ], - 'basePages' => ['civicrm/admin/search'], - 'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'ui.sortable', 'ui.bootstrap', 'api4', 'crmSearchDisplay', 'crmSearchActions'], - 'settingsFactory' => ['\Civi\Search\Admin', 'getAdminSettings'], -]; -- 2.25.1