This allows extensions to define batch actions without the need for any javascript code
if (array_key_exists('delete', $entity['actions'])) {
$tasks[$entity['name']]['delete'] = [
- 'module' => 'crmSearchTasks',
'title' => E::ts('Delete %1', [1 => $entity['title_plural']]),
'icon' => 'fa-trash',
- 'uiDialog' => ['templateUrl' => '~/crmSearchTasks/crmSearchTaskDelete.html'],
+ 'apiBatch' => [
+ 'action' => 'delete',
+ 'params' => NULL,
+ 'confirmMsg' => E::ts('Are you sure you want to delete %1 %2?'),
+ 'runMsg' => E::ts('Deleting %1 %2...'),
+ 'successMsg' => E::ts('Successfully deleted %1 %2.'),
+ 'errorMsg' => E::ts('An error occurred while attempting to delete %1 %2.'),
+ ],
];
}
$null, $null, $null, 'civicrm_searchKitTasks'
);
- usort($tasks[$entity['name']], function($a, $b) {
- return strnatcasecmp($a['title'], $b['title']);
- });
-
foreach ($tasks[$entity['name']] as $name => &$task) {
$task['name'] = $name;
// Add default for number of rows action requires
$task += ['number' => '> 0'];
}
- $result->exchangeArray(array_values($tasks[$entity['name']]));
+ usort($tasks[$entity['name']], function($a, $b) {
+ return strnatcasecmp($a['title'], $b['title']);
+ });
+
+ $result->exchangeArray($tasks[$entity['name']]);
+ }
+
+ public static function fields() {
+ return [
+ [
+ 'name' => 'name',
+ ],
+ [
+ 'name' => 'module',
+ ],
+ [
+ 'name' => 'title',
+ ],
+ [
+ 'name' => 'icon',
+ ],
+ [
+ 'number' => 'icon',
+ ],
+ [
+ 'name' => 'apiBatch',
+ 'data_type' => 'Array',
+ ],
+ [
+ 'name' => 'uiDialog',
+ 'data_type' => 'Array',
+ ],
+ [
+ 'name' => 'crmPopup',
+ 'data_type' => 'Array',
+ ],
+ ];
}
}
--- /dev/null
+(function(angular, $, _) {
+ "use strict";
+
+ // Generic controller for running an ApiBatch task
+ angular.module('crmSearchTasks').controller('crmSearchTaskApiBatch', function($scope, searchTaskBaseTrait) {
+ var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
+ // Combine this controller with model properties (ids, entity, entityInfo) and searchTaskBaseTrait
+ ctrl = angular.extend(this, $scope.model, searchTaskBaseTrait);
+
+ this.entityTitle = this.getEntityTitle();
+
+ // If no confirmation message, skip straight to processing
+ if (!ctrl.apiBatch.confirmMsg) {
+ ctrl.start(ctrl.apiBatch.params);
+ }
+
+ this.onSuccess = function() {
+ CRM.alert(ts(ctrl.apiBatch.successMsg, {1: ctrl.ids.length, 2: ctrl.entityTitle}), ts('%1 Complete', {1: ctrl.taskTitle}), 'success');
+ this.close();
+ };
+
+ this.onError = function() {
+ CRM.alert(ts(ctrl.apiBatch.errorMsg, {1: ctrl.ids.length, 2: ctrl.entityTitle}), ts('Error'), 'error');
+ this.cancel();
+ };
+
+ });
+})(angular, CRM.$, CRM._);
--- /dev/null
+<div id="bootstrap-theme" crm-dialog="crmSearchTask">
+ <form ng-controller="crmSearchTaskApiBatch as $ctrl">
+ <p><strong ng-if="model.apiBatch.confirmMsg">{{:: ts(model.apiBatch.confirmMsg, {1: model.ids.length, 2: $ctrl.entityTitle}) }}</strong></p>
+ <hr />
+ <div ng-if="$ctrl.run" class="crm-search-task-progress">
+ <h5>{{:: ts(model.apiBatch.runMsg, {1: model.ids.length, 2: $ctrl.entityTitle}) }}</h5>
+ <crm-search-batch-runner entity="model.entity" action="{{:: model.apiBatch.action }}" params="$ctrl.run" ids="model.ids" success="$ctrl.onSuccess()" error="$ctrl.onError()" id-field="{{:: $ctrl.entityInfo.primary_key[0] }}"></crm-search-batch-runner>
+ </div>
+
+ <crm-dialog-button text="ts('Cancel')" icons="{primary: 'fa-times'}" on-click="$ctrl.cancel()" disabled="$ctrl.run" ></crm-dialog-button>
+ <crm-dialog-button ng-if="model.apiBatch.confirmMsg" text="model.taskTitle" icons="{primary: $ctrl.run ? 'fa-spin fa-spinner' : 'fa-check'}" on-click="$ctrl.start(model.apiBatch.params)" disabled="$ctrl.run" ></crm-dialog-button>
+ </form>
+</div>
+++ /dev/null
-(function(angular, $, _) {
- "use strict";
-
- angular.module('crmSearchTasks').controller('crmSearchTaskDelete', function($scope, searchTaskBaseTrait) {
- var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
- // Combine this controller with model properties (ids, entity, entityInfo) and searchTaskBaseTrait
- ctrl = angular.extend(this, $scope.model, searchTaskBaseTrait);
-
- this.entityTitle = this.getEntityTitle();
-
- this.onSuccess = function() {
- CRM.alert(ts('Successfully deleted %1 %2.', {1: ctrl.ids.length, 2: ctrl.entityTitle}), ts('Deleted'), 'success');
- this.close();
- };
-
- this.onError = function() {
- CRM.alert(ts('An error occurred while attempting to delete %1 %2.', {1: ctrl.ids.length, 2: ctrl.entityTitle}), ts('Error'), 'error');
- this.cancel();
- };
-
- });
-})(angular, CRM.$, CRM._);
+++ /dev/null
-<div id="bootstrap-theme" crm-dialog="crmSearchTask">
- <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-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>
-
- <crm-dialog-button text="ts('Cancel')" icons="{primary: 'fa-times'}" on-click="$ctrl.cancel()" disabled="$ctrl.run" ></crm-dialog-button>
- <crm-dialog-button text="ts('Delete %1', {1: $ctrl.entityTitle})" icons="{primary: $ctrl.run ? 'fa-spin fa-spinner' : 'fa-trash'}" on-click="$ctrl.start()" disabled="$ctrl.run" ></crm-dialog-button>
- </form>
-</div>
}
initialized = true;
crmApi4({
- entityInfo: ['Entity', 'get', {select: ['name', 'title', 'title_plural'], where: [['name', '=', ctrl.entity]]}, 0],
+ entityInfo: ['Entity', 'get', {select: ['name', 'title', 'title_plural', 'primary_key'], where: [['name', '=', ctrl.entity]]}, 0],
tasks: ['SearchDisplay', 'getSearchTasks', {entity: ctrl.entity}]
}).then(function(result) {
ctrl.entityInfo = result.entityInfo;
search: ctrl.search,
display: ctrl.display,
displayController: ctrl.displayController,
- entityInfo: ctrl.entityInfo
+ entityInfo: ctrl.entityInfo,
+ taskTitle: action.title,
+ apiBatch: _.cloneDeep(action.apiBatch)
};
// If action uses a crmPopup form
if (action.crmPopup) {
.on('crmFormSuccess', ctrl.refresh);
}
// If action uses dialogService
- else if (action.uiDialog) {
+ else {
var options = CRM.utils.adjustDialogDefaults({
autoOpen: false,
dialogClass: 'crm-search-task-dialog',
title: action.title
});
- dialogService.open('crmSearchTask', action.uiDialog.templateUrl, data, options)
+ dialogService.open('crmSearchTask', (action.uiDialog && action.uiDialog.templateUrl) || '~/crmSearchTasks/crmSearchTaskApiBatch.html', data, options)
// Reload results on success, do nothing on cancel
.then(ctrl.refresh, _.noop);
}