public function _run(\Civi\Api4\Generic\Result $result) {
$entity = Entity::get($this->checkPermissions)->addWhere('name', '=', $this->entity)
->addSelect('name', 'title_plural')
- ->setChain(['actions' => [$this->entity, 'getActions', ['where' => [['name', 'IN', ['update', 'delete']]]], 'name']])
+ ->setChain(['actions' => ['$name', 'getActions', ['where' => [['name', 'IN', ['update', 'delete']]]], 'name']])
->execute()->first();
if (!$entity) {
return;
}
- $tasks = [];
+ $tasks = [$entity['name'] => []];
if (array_key_exists($entity['name'], \CRM_Export_BAO_Export::getComponents())) {
- $tasks[] = [
- 'name' => 'export',
+ $tasks[$entity['name']]['export'] = [
'title' => E::ts('Export %1', [1 => $entity['title_plural']]),
'icon' => 'fa-file-excel-o',
'crmPopup' => [
}
if (array_key_exists('update', $entity['actions'])) {
- $tasks[] = [
- 'name' => 'update',
+ $tasks[$entity['name']]['update'] = [
+ 'module' => 'crmSearchTasks',
'title' => E::ts('Update %1', [1 => $entity['title_plural']]),
'icon' => 'fa-save',
- 'uiDialog' => ['templateUrl' => '~/crmSearchActions/crmSearchActionUpdate.html'],
+ 'uiDialog' => ['templateUrl' => '~/crmSearchTasks/crmSearchTaskUpdate.html'],
];
}
if (array_key_exists('delete', $entity['actions'])) {
- $tasks[] = [
- 'name' => 'delete',
+ $tasks[$entity['name']]['delete'] = [
+ 'module' => 'crmSearchTasks',
'title' => E::ts('Delete %1', [1 => $entity['title_plural']]),
'icon' => 'fa-trash',
- 'uiDialog' => ['templateUrl' => '~/crmSearchActions/crmSearchActionDelete.html'],
+ 'uiDialog' => ['templateUrl' => '~/crmSearchTasks/crmSearchTaskDelete.html'],
];
}
if ($task['url'] === 'civicrm/task/pick-profile') {
$task['title'] = E::ts('Profile Update');
}
- $tasks[] = [
- 'name' => 'contact.' . $id,
+ $tasks[$entity['name']]['contact.' . $id] = [
'title' => $task['title'],
'icon' => $task['icon'] ?? 'fa-gear',
'crmPopup' => [
if ($entity['name'] === 'Contribution') {
foreach (\CRM_Contribute_Task::tasks() as $id => $task) {
if (!empty($task['url'])) {
- $tasks[] = [
- 'name' => 'contribution.' . $id,
+ $tasks[$entity['name']]['contribution.' . $id] = [
'title' => $task['title'],
'icon' => $task['icon'] ?? 'fa-gear',
'crmPopup' => [
}
}
- usort($tasks, function($a, $b) {
+ $null = NULL;
+ \CRM_Utils_Hook::singleton()->invoke(['tasks'], $tasks,
+ $null, $null, $null, $null, $null, 'civicrm_searchKitTasks'
+ );
+
+ usort($tasks[$entity['name']], function($a, $b) {
return strnatcasecmp($a['title'], $b['title']);
});
- $result->exchangeArray($tasks);
+ foreach ($tasks[$entity['name']] as $name => &$task) {
+ $task['name'] = $name;
+ }
+
+ $result->exchangeArray(array_values($tasks[$entity['name']]));
}
}
],
'bundles' => ['bootstrap3'],
'basePages' => ['civicrm/admin/search'],
- 'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'ui.sortable', 'ui.bootstrap', 'api4', 'crmSearchActions', 'crmRouteBinder'],
+ 'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'ui.sortable', 'ui.bootstrap', 'api4', 'crmSearchTasks', 'crmRouteBinder'],
'settingsFactory' => ['\Civi\Search\Admin', 'getAdminSettings'],
];
{{:: ts('Auto') }}
</button>
</div>
- <crm-search-actions entity="$ctrl.savedSearch.api_entity" ids="$ctrl.selectedRows" refresh="$ctrl.refreshPage()"></crm-search-actions>
+ <crm-search-tasks entity="$ctrl.savedSearch.api_entity" ids="$ctrl.selectedRows" refresh="$ctrl.refreshPage()"></crm-search-tasks>
</div>
'ang/crmSearchDisplayTable',
],
'basePages' => ['civicrm/search', 'civicrm/admin/search'],
- 'requires' => ['crmSearchDisplay', 'crmUi', 'crmSearchActions', 'ui.bootstrap'],
+ 'requires' => ['crmSearchDisplay', 'crmUi', 'crmSearchTasks', 'ui.bootstrap'],
'bundles' => ['bootstrap3'],
'exports' => [
'crm-search-display-table' => 'E',
<div class="crm-search-display crm-search-display-table">
<div class="form-inline" ng-if="$ctrl.settings.actions">
- <crm-search-actions entity="$ctrl.apiEntity" ids="$ctrl.selectedRows" refresh="$ctrl.getResults()"></crm-search-actions>
+ <crm-search-tasks entity="$ctrl.apiEntity" ids="$ctrl.selectedRows" refresh="$ctrl.getResults()"></crm-search-tasks>
</div>
<table>
<thead>
// Search actions module - provides dropdown menu with bulk actions to take on selected rows.
return [
'js' => [
- 'ang/crmSearchActions.module.js',
- 'ang/crmSearchActions/*.js',
- 'ang/crmSearchActions/*/*.js',
+ 'ang/crmSearchTasks.module.js',
+ 'ang/crmSearchTasks/*.js',
+ 'ang/crmSearchTasks/*/*.js',
],
'partials' => [
- 'ang/crmSearchActions',
+ 'ang/crmSearchTasks',
],
'css' => [
- 'css/crmSearchActions.css',
+ 'css/crmSearchTasks.css',
],
'basePages' => [],
'requires' => ['crmUi', 'crmUtil', 'dialogService', 'api4', 'checklist-model'],
"use strict";
// Declare module
- angular.module('crmSearchActions', CRM.angRequires('crmSearchActions'))
+ angular.module('crmSearchTasks', CRM.angRequires('crmSearchTasks'))
// Reformat an array of objects for compatibility with select2
// Todo this probably belongs in core
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions').component('crmSearchBatchRunner', {
+ angular.module('crmSearchTasks').component('crmSearchBatchRunner', {
bindings: {
entity: '<',
action: '@',
success: '&',
error: '&'
},
- templateUrl: '~/crmSearchActions/crmSearchBatchRunner.html',
+ templateUrl: '~/crmSearchTasks/crmSearchBatchRunner.html',
controller: function($scope, $timeout, $interval, crmApi4) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
ctrl = this,
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions')
+ angular.module('crmSearchTasks')
.directive('crmMultiSelectDate', function () {
return {
restrict: 'A',
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions').component('crmSearchInput', {
+ angular.module('crmSearchTasks').component('crmSearchInput', {
bindings: {
field: '<',
'op': '<',
'optionKey': '<'
},
require: {ngModel: 'ngModel'},
- templateUrl: '~/crmSearchActions/crmSearchInput/crmSearchInput.html',
+ templateUrl: '~/crmSearchTasks/crmSearchInput/crmSearchInput.html',
controller: function($scope) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
ctrl = this;
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions').component('crmSearchInputVal', {
+ angular.module('crmSearchTasks').component('crmSearchInputVal', {
bindings: {
field: '<',
'multi': '<',
this.$onInit = function() {
var rendered = false;
- ctrl.dateRanges = CRM.crmSearchActions.dateRanges;
+ ctrl.dateRanges = CRM.crmSearchTasks.dateRanges;
ctrl.entity = ctrl.field.fk_entity || ctrl.field.entity;
this.ngModel.$render = function() {
this.getTemplate = function() {
if (ctrl.field.input_type === 'Date') {
- return '~/crmSearchActions/crmSearchInput/date.html';
+ return '~/crmSearchTasks/crmSearchInput/date.html';
}
if (ctrl.field.data_type === 'Boolean') {
- return '~/crmSearchActions/crmSearchInput/boolean.html';
+ return '~/crmSearchTasks/crmSearchInput/boolean.html';
}
if (ctrl.field.options) {
- return '~/crmSearchActions/crmSearchInput/select.html';
+ return '~/crmSearchTasks/crmSearchInput/select.html';
}
if (ctrl.field.fk_entity || ctrl.field.name === 'id') {
- return '~/crmSearchActions/crmSearchInput/entityRef.html';
+ return '~/crmSearchTasks/crmSearchInput/entityRef.html';
}
if (ctrl.field.data_type === 'Integer') {
- return '~/crmSearchActions/crmSearchInput/integer.html';
+ return '~/crmSearchTasks/crmSearchInput/integer.html';
}
if (ctrl.field.data_type === 'Float') {
- return '~/crmSearchActions/crmSearchInput/float.html';
+ return '~/crmSearchTasks/crmSearchInput/float.html';
}
- return '~/crmSearchActions/crmSearchInput/text.html';
+ return '~/crmSearchTasks/crmSearchInput/text.html';
};
this.getFieldOptions = function() {
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions').controller('crmSearchActionDelete', function($scope, dialogService) {
+ angular.module('crmSearchTasks').controller('crmSearchTaskDelete', function($scope, dialogService) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
model = $scope.model,
ctrl = this;
this.entityTitle = model.ids.length === 1 ? model.entityInfo.title : model.entityInfo.title_plural;
this.cancel = function() {
- dialogService.cancel('crmSearchAction');
+ dialogService.cancel('crmSearchTask');
};
this.delete = function() {
this.onSuccess = function() {
CRM.alert(ts('Successfully deleted %1 %2.', {1: model.ids.length, 2: ctrl.entityTitle}), ts('Deleted'), 'success');
- dialogService.close('crmSearchAction');
+ dialogService.close('crmSearchTask');
};
this.onError = function() {
CRM.alert(ts('An error occurred while attempting to delete %1 %2.', {1: model.ids.length, 2: ctrl.entityTitle}), ts('Error'), 'error');
- dialogService.close('crmSearchAction');
+ dialogService.close('crmSearchTask');
};
});
<div id="bootstrap-theme">
- <form ng-controller="crmSearchActionDelete as $ctrl">
+ <form ng-controller="crmSearchTaskDelete as $ctrl">
<p><strong>{{:: ts('Are you sure you want to delete %1 %2?', {1: model.ids.length, 2: $ctrl.entityTitle}) }}</strong></p>
<hr />
- <div ng-if="$ctrl.run" class="crm-search-action-progress">
+ <div ng-if="$ctrl.run" class="crm-search-task-progress">
<h5>{{:: ts('Deleting %1 %2...', {1: model.ids.length, 2: $ctrl.entityTitle}) }}</h5>
<crm-search-batch-runner entity="model.entity" action="Delete" params="$ctrl.run" ids="model.ids" success="$ctrl.onSuccess()" error="$ctrl.onError()" ></crm-search-batch-runner>
</div>
{{:: ts('Delete %1', {1: $ctrl.entityTitle}) }}
</button>
</div>
+ </form>
</div>
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions').controller('crmSearchActionUpdate', function ($scope, $timeout, crmApi4, dialogService) {
+ angular.module('crmSearchTasks').controller('crmSearchTaskUpdate', function ($scope, $timeout, crmApi4, dialogService) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
model = $scope.model,
ctrl = this;
};
this.cancel = function() {
- dialogService.cancel('crmSearchAction');
+ dialogService.cancel('crmSearchTask');
};
this.save = function() {
this.onSuccess = function() {
CRM.alert(ts('Successfully updated %1 %2.', {1: model.ids.length, 2: ctrl.entityTitle}), ts('Saved'), 'success');
- dialogService.close('crmSearchAction');
+ dialogService.close('crmSearchTask');
};
this.onError = function() {
CRM.alert(ts('An error occurred while attempting to update %1 %2.', {1: model.ids.length, 2: ctrl.entityTitle}), ts('Error'), 'error');
- dialogService.close('crmSearchAction');
+ dialogService.close('crmSearchTask');
};
});
<div id="bootstrap-theme">
- <form ng-controller="crmSearchActionUpdate as $ctrl">
+ <form ng-controller="crmSearchTaskUpdate as $ctrl">
<p><strong>{{:: ts('Update the %1 selected %2 with the following values:', {1: model.ids.length, 2: $ctrl.entityTitle}) }}</strong></p>
<div class="form-inline" ng-repeat="clause in $ctrl.values" >
<input class="form-control" ng-change="$ctrl.updateField($index)" ng-disabled="$ctrl.run" ng-model="clause[0]" crm-ui-select="{data: $ctrl.availableFields, allowClear: true, placeholder: 'Field'}" />
<div class="form-inline" ng-hide="$ctrl.run">
<input class="form-control twenty" style="width: 15em;" ng-model="$ctrl.add" ng-change="$ctrl.addField()" ng-disabled="!$ctrl.fields" ng-class="{loading: !$ctrl.fields}" crm-ui-select="{data: $ctrl.availableFields, placeholder: ts('Add Value')}"/>
</div>
- <div ng-if="$ctrl.run" class="crm-search-action-progress">
+ <div ng-if="$ctrl.run" class="crm-search-task-progress">
<h5>{{:: ts('Updating %1 %2...', {1: model.ids.length, 2: $ctrl.entityTitle}) }}</h5>
<crm-search-batch-runner entity="model.entity" action="Update" params="$ctrl.run" ids="model.ids" success="$ctrl.onSuccess()" error="$ctrl.onError()" ></crm-search-batch-runner>
</div>
(function(angular, $, _) {
"use strict";
- angular.module('crmSearchActions').component('crmSearchActions', {
+ angular.module('crmSearchTasks').component('crmSearchTasks', {
bindings: {
entity: '<',
refresh: '&',
ids: '<'
},
- templateUrl: '~/crmSearchActions/crmSearchActions.html',
+ templateUrl: '~/crmSearchTasks/crmSearchTasks.html',
controller: function($scope, crmApi4, dialogService) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
ctrl = this,
autoOpen: false,
title: action.title
});
- dialogService.open('crmSearchAction', action.uiDialog.templateUrl, data, options)
+ dialogService.open('crmSearchTask', action.uiDialog.templateUrl, data, options)
.then(ctrl.refresh);
}
};
-.crm-search-action-progress {
+.crm-search-task-progress {
padding: 10px;
margin-top: 10px;
border: 1px solid lightgrey;
*/
function search_kit_civicrm_angularModules(&$angularModules) {
_search_kit_civix_civicrm_angularModules($angularModules);
+ // Fetch all search tasks provided by other modules and add them as crmSearchTasks dependencies
+ $tasks = $dependencies = [];
+ $null = NULL;
+ CRM_Utils_Hook::singleton()->invoke(['tasks'], $tasks,
+ $null, $null, $null, $null, $null, 'civicrm_searchKitTasks'
+ );
+ foreach ($tasks as $entityTasks) {
+ foreach ($entityTasks as $task) {
+ if (isset($task['module']) && $task['module'] !== 'crmSearchTasks' &&
+ !in_array($task['module'], $angularModules['crmSearchTasks']['requires'], TRUE)
+ ) {
+ $angularModules['crmSearchTasks']['requires'][] = $task['module'];
+ }
+ }
+ }
}
/**