From bf317ed561929bef6d766beb25c9444c92e6ef1e Mon Sep 17 00:00:00 2001
From: Jaap Jansma <jaap.jansma@civicoop.org>
Date: Mon, 5 Aug 2024 14:56:37 +0200
Subject: [PATCH] Added configuration for search outputs to limit and sort the
 task list.

---
 CHANGELOG.md                                  |  1 +
 CRM/Contact/DataProcessorContactSearch.php    |  7 +-
 .../Form/DataProcessorContactSearch.php       |  1 +
 CRM/DataprocessorSearch/ActivitySearch.php    |  5 +-
 CRM/DataprocessorSearch/CaseSearch.php        |  5 +-
 .../ContributionSearch.php                    |  6 +-
 .../Form/AbstractSearch.php                   | 18 +++-
 .../Form/ActivitySearch.php                   |  1 +
 CRM/DataprocessorSearch/Form/CaseSearch.php   |  1 +
 .../Form/ContributionSearch.php               |  1 +
 .../Form/MembershipSearch.php                 |  1 +
 .../Form/ParticipantSearch.php                |  3 +-
 CRM/DataprocessorSearch/Form/Search.php       |  1 +
 CRM/DataprocessorSearch/MembershipSearch.php  |  6 +-
 CRM/DataprocessorSearch/ParticipantSearch.php |  8 +-
 CRM/DataprocessorSearch/Search.php            |  5 +-
 CRM/DataprocessorSearch/Utils/Tasks.php       | 89 +++++++++++++++++++
 .../DataProcessorContactSearch.tpl            |  1 +
 .../OutputConfiguration/ActivitySearch.tpl    |  1 +
 .../Form/OutputConfiguration/CaseSearch.tpl   |  1 +
 .../ContributionSearch.tpl                    |  1 +
 .../OutputConfiguration/MembershipSearch.tpl  |  1 +
 .../OutputConfiguration/ParticipantSearch.tpl |  2 +
 .../Form/OutputConfiguration/Search.tpl       |  1 +
 .../Form/OutputConfiguration/Tasks.tpl        | 49 ++++++++++
 25 files changed, 205 insertions(+), 11 deletions(-)
 create mode 100644 CRM/DataprocessorSearch/Utils/Tasks.php
 create mode 100644 templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e580b01..f7e01d6d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 # Version 1.110 (not yet released)
 
+* Added configuration for search outputs to limit and sort the task list.
 * Fixed issue with Edit Participant link in participant searches. See !128 and thanks to @david124136468769
 * Added two new Field output handlers for date ranges. See !127 and thanks to @gngn
 
diff --git a/CRM/Contact/DataProcessorContactSearch.php b/CRM/Contact/DataProcessorContactSearch.php
index 36906804..baddc6be 100644
--- a/CRM/Contact/DataProcessorContactSearch.php
+++ b/CRM/Contact/DataProcessorContactSearch.php
@@ -70,6 +70,11 @@ class CRM_Contact_DataProcessorContactSearch implements UIFormOutputInterface {
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    $taskParams['deletedContacts'] = FALSE;
+    $taskParams['ssID'] = $this->_ssID ?? NULL;
+    $allTasks = CRM_Contact_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+
     $defaults = array();
     if ($output) {
 
@@ -155,7 +160,7 @@ class CRM_Contact_DataProcessorContactSearch implements UIFormOutputInterface {
     $configuration['link_to_view_contact'] = $submittedValues['link_to_view_contact'];
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/Contact/Form/DataProcessorContactSearch.php b/CRM/Contact/Form/DataProcessorContactSearch.php
index 4e5f9046..177c1ee0 100644
--- a/CRM/Contact/Form/DataProcessorContactSearch.php
+++ b/CRM/Contact/Form/DataProcessorContactSearch.php
@@ -152,6 +152,7 @@ class CRM_Contact_Form_DataProcessorContactSearch extends CRM_DataprocessorSearc
       $taskParams['deletedContacts'] = FALSE;
       $taskParams['ssID'] = $this->_ssID ?? NULL;
       $this->_taskList = CRM_Contact_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/ActivitySearch.php b/CRM/DataprocessorSearch/ActivitySearch.php
index 4bee8bd0..3e387713 100644
--- a/CRM/DataprocessorSearch/ActivitySearch.php
+++ b/CRM/DataprocessorSearch/ActivitySearch.php
@@ -67,6 +67,9 @@ class CRM_DataprocessorSearch_ActivitySearch implements UIFormOutputInterface {
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    $allTasks = CRM_Activity_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission());
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+
     $defaults = array();
     if ($output) {
       if (isset($output['permission'])) {
@@ -143,7 +146,7 @@ class CRM_DataprocessorSearch_ActivitySearch implements UIFormOutputInterface {
     $configuration['expanded_search'] = isset($submittedValues['expanded_search']) ? $submittedValues['expanded_search'] : false;
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/DataprocessorSearch/CaseSearch.php b/CRM/DataprocessorSearch/CaseSearch.php
index ecbb892d..cbf65716 100644
--- a/CRM/DataprocessorSearch/CaseSearch.php
+++ b/CRM/DataprocessorSearch/CaseSearch.php
@@ -73,6 +73,9 @@ class CRM_DataprocessorSearch_CaseSearch implements UIFormOutputInterface {
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    $allTasks = CRM_Case_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission());
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+
     $defaults = array();
     if ($output) {
       if (isset($output['permission'])) {
@@ -157,7 +160,7 @@ class CRM_DataprocessorSearch_CaseSearch implements UIFormOutputInterface {
     $configuration['show_manage_case'] = isset($submittedValues['show_manage_case']) ? $submittedValues['show_manage_case'] : false;
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/DataprocessorSearch/ContributionSearch.php b/CRM/DataprocessorSearch/ContributionSearch.php
index aa054ba9..eaa70eb2 100644
--- a/CRM/DataprocessorSearch/ContributionSearch.php
+++ b/CRM/DataprocessorSearch/ContributionSearch.php
@@ -67,6 +67,10 @@ class CRM_DataprocessorSearch_ContributionSearch implements UIFormOutputInterfac
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    $taskParams['softCreditFiltering'] = FALSE;
+    $allTasks = CRM_Contribute_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+
     $defaults = array();
     if ($output) {
       if (isset($output['permission'])) {
@@ -143,7 +147,7 @@ class CRM_DataprocessorSearch_ContributionSearch implements UIFormOutputInterfac
     $configuration['expanded_search'] = isset($submittedValues['expanded_search']) ? $submittedValues['expanded_search'] : false;
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/DataprocessorSearch/Form/AbstractSearch.php b/CRM/DataprocessorSearch/Form/AbstractSearch.php
index 38c1b048..f653e60c 100644
--- a/CRM/DataprocessorSearch/Form/AbstractSearch.php
+++ b/CRM/DataprocessorSearch/Form/AbstractSearch.php
@@ -102,7 +102,8 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
   abstract protected function getEntityTable();
 
   /**
-   * Builds the list of tasks or actions that a searcher can perform on a result set.
+   * Builds the list of tasks or actions that a searcher can perform on a
+   * result set.
    *
    * @return array
    */
@@ -110,6 +111,17 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
     return $this->_taskList;
   }
 
+  protected function filterTaskList() {
+    if (!empty($this->dataProcessorOutput['configuration']['restrict_tasks'])) {
+      $allTasks = $this->_taskList;
+      $this->_taskList = [];
+      foreach($this->dataProcessorOutput['configuration']['tasks'] as $task) {
+        $taskId = substr($task, 5);
+        $this->_taskList[$taskId] = $allTasks[$taskId];
+      }
+    }
+  }
+
   /**
    * Returns whether we want to use the prevnext cache.
    * @return bool
@@ -572,8 +584,8 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
    *
    * Use this function in child classes to add for example additional filters.
    *
-   * E.g. The contact summary tab uses this to add additional filtering on the contact id of
-   * the displayed contact.
+   * E.g. The contact summary tab uses this to add additional filtering on the
+   * contact id of the displayed contact.
    *
    * @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
    */
diff --git a/CRM/DataprocessorSearch/Form/ActivitySearch.php b/CRM/DataprocessorSearch/Form/ActivitySearch.php
index 9c105518..eb8e191a 100644
--- a/CRM/DataprocessorSearch/Form/ActivitySearch.php
+++ b/CRM/DataprocessorSearch/Form/ActivitySearch.php
@@ -133,6 +133,7 @@ class CRM_DataprocessorSearch_Form_ActivitySearch extends CRM_DataprocessorSearc
   public function buildTaskList(): array {
     if (!$this->_taskList) {
       $this->_taskList = CRM_Activity_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission());
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/Form/CaseSearch.php b/CRM/DataprocessorSearch/Form/CaseSearch.php
index 54317dff..56559089 100644
--- a/CRM/DataprocessorSearch/Form/CaseSearch.php
+++ b/CRM/DataprocessorSearch/Form/CaseSearch.php
@@ -114,6 +114,7 @@ class CRM_DataprocessorSearch_Form_CaseSearch extends CRM_DataprocessorSearch_Fo
   public function buildTaskList(): array {
     if (!$this->_taskList) {
       $this->_taskList = CRM_Case_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission());
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/Form/ContributionSearch.php b/CRM/DataprocessorSearch/Form/ContributionSearch.php
index 4cfaadcb..24aced33 100644
--- a/CRM/DataprocessorSearch/Form/ContributionSearch.php
+++ b/CRM/DataprocessorSearch/Form/ContributionSearch.php
@@ -102,6 +102,7 @@ class CRM_DataprocessorSearch_Form_ContributionSearch extends CRM_DataprocessorS
     if (!$this->_taskList) {
       $taskParams['softCreditFiltering'] = FALSE;
       $this->_taskList = CRM_Contribute_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/Form/MembershipSearch.php b/CRM/DataprocessorSearch/Form/MembershipSearch.php
index 7476f02c..0528846a 100644
--- a/CRM/DataprocessorSearch/Form/MembershipSearch.php
+++ b/CRM/DataprocessorSearch/Form/MembershipSearch.php
@@ -111,6 +111,7 @@ class CRM_DataprocessorSearch_Form_MembershipSearch extends CRM_DataprocessorSea
     if (!$this->_taskList) {
       $taskParams = [];
       $this->_taskList = CRM_Member_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/Form/ParticipantSearch.php b/CRM/DataprocessorSearch/Form/ParticipantSearch.php
index b716a41e..9f5def10 100644
--- a/CRM/DataprocessorSearch/Form/ParticipantSearch.php
+++ b/CRM/DataprocessorSearch/Form/ParticipantSearch.php
@@ -34,7 +34,7 @@ class CRM_DataprocessorSearch_Form_ParticipantSearch extends CRM_DataprocessorSe
     } catch (CiviCRM_API3_Exception $ex) {
       // Do nothing.
     }
-  
+
     return CRM_Utils_System::url('civicrm/contact/view/participant', 'reset=1&id='.$row['id'].'&cid='.$contact_id.'&action=view');
   }
 
@@ -112,6 +112,7 @@ class CRM_DataprocessorSearch_Form_ParticipantSearch extends CRM_DataprocessorSe
     if (!$this->_taskList) {
       $taskParams['deletedParticipants'] = FALSE;
       $this->_taskList = CRM_Event_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/Form/Search.php b/CRM/DataprocessorSearch/Form/Search.php
index 1974eddd..431757d8 100644
--- a/CRM/DataprocessorSearch/Form/Search.php
+++ b/CRM/DataprocessorSearch/Form/Search.php
@@ -107,6 +107,7 @@ class CRM_DataprocessorSearch_Form_Search extends CRM_DataprocessorSearch_Form_A
   public function buildTaskList(): array {
     if (!$this->_taskList) {
       $this->_taskList = CRM_DataprocessorSearch_Task::taskTitles();
+      $this->filterTaskList();
     }
     return $this->_taskList;
   }
diff --git a/CRM/DataprocessorSearch/MembershipSearch.php b/CRM/DataprocessorSearch/MembershipSearch.php
index c48766b0..d9d28430 100644
--- a/CRM/DataprocessorSearch/MembershipSearch.php
+++ b/CRM/DataprocessorSearch/MembershipSearch.php
@@ -67,6 +67,10 @@ class CRM_DataprocessorSearch_MembershipSearch implements UIFormOutputInterface
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    $taskParams = [];
+    $allTasks = CRM_Member_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+
     $defaults = array();
     if ($output) {
       if (isset($output['permission'])) {
@@ -143,7 +147,7 @@ class CRM_DataprocessorSearch_MembershipSearch implements UIFormOutputInterface
     $configuration['expanded_search'] = isset($submittedValues['expanded_search']) ? $submittedValues['expanded_search'] : false;
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/DataprocessorSearch/ParticipantSearch.php b/CRM/DataprocessorSearch/ParticipantSearch.php
index 628e29a1..562ec069 100644
--- a/CRM/DataprocessorSearch/ParticipantSearch.php
+++ b/CRM/DataprocessorSearch/ParticipantSearch.php
@@ -67,6 +67,12 @@ class CRM_DataprocessorSearch_ParticipantSearch implements UIFormOutputInterface
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    // Task list and sorting
+    $taskParams['deletedParticipants'] = FALSE;
+    $allTasks = CRM_Event_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams);
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+    $form->add('checkbox', 'restrict_tasks', E::ts('Restrict or reorder tasks?'));
+
     $defaults = array();
     if ($output) {
       if (isset($output['permission'])) {
@@ -143,7 +149,7 @@ class CRM_DataprocessorSearch_ParticipantSearch implements UIFormOutputInterface
     $configuration['expanded_search'] = isset($submittedValues['expanded_search']) ? $submittedValues['expanded_search'] : false;
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/DataprocessorSearch/Search.php b/CRM/DataprocessorSearch/Search.php
index f2e8f267..a07b68a7 100644
--- a/CRM/DataprocessorSearch/Search.php
+++ b/CRM/DataprocessorSearch/Search.php
@@ -70,6 +70,9 @@ class CRM_DataprocessorSearch_Search implements UIFormOutputInterface {
     $form->add('select', 'navigation_parent_path', ts('Parent Menu'), array('' => ts('- select -')) + $navigationOptions, true);
     $form->add('text', 'navigation_weight', E::ts('Weight'), array('class' => 'huge'), false);
 
+    $allTasks = CRM_DataprocessorSearch_Task::taskTitles();
+    CRM_DataprocessorSearch_Utils_Tasks::buildConfigurationForm($allTasks, $form, $output);
+
     $defaults = array();
     if ($output) {
       if (isset($output['permission'])) {
@@ -153,7 +156,7 @@ class CRM_DataprocessorSearch_Search implements UIFormOutputInterface {
     $configuration['expose_hidden_fields'] = isset($submittedValues['expose_hidden_fields']) ? $submittedValues['expose_hidden_fields'] : false;
     $configuration['enable_hard_limit'] = isset($submittedValues['enable_hard_limit']) ? $submittedValues['enable_hard_limit'] : false;
     $configuration['default_hard_limit'] = $submittedValues['default_hard_limit'];
-    return $configuration;
+    return CRM_DataprocessorSearch_Utils_Tasks::processConfiguration($submittedValues, $configuration);
   }
 
   /**
diff --git a/CRM/DataprocessorSearch/Utils/Tasks.php b/CRM/DataprocessorSearch/Utils/Tasks.php
new file mode 100644
index 00000000..297e1d21
--- /dev/null
+++ b/CRM/DataprocessorSearch/Utils/Tasks.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright (C) 2024  Jaap Jansma (jaap.jansma@civicoop.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+class CRM_DataprocessorSearch_Utils_Tasks {
+
+  /**
+   * Build configuration form for adding retricted tasks
+   *
+   * @param $allTasks
+   * @param \CRM_Core_Form $form
+   * @param $output
+   *
+   * @return void
+   */
+  public static function buildConfigurationForm($allTasks, \CRM_Core_Form $form, $output=array()) {
+    $form->add('checkbox', 'restrict_tasks', E::ts('Restrict or reorder tasks?'));
+    $tasks = [];
+    if (isset($output['configuration']['tasks']) && is_array($output['configuration']['tasks'])) {
+      foreach($output['configuration']['tasks'] as $task) {
+        $label = $allTasks[substr($task, 5)];
+        $tasks[$label] = $task;;
+      }
+    }
+    foreach($allTasks as $task => $label) {
+      if (!in_array('task_'.$task, $tasks)) {
+        $tasks[$label] = 'task_' . $task;
+      }
+    }
+    $form->addCheckBox('tasks_checkboxes',  E::ts('Restrict to tasks'), $tasks);
+    $form->assign('tasks', $tasks);
+    if ($form->isSubmitted()) {
+      $form->add('hidden', 'sorted_tasks', NULL, ['id' => 'sorted_tasks']);
+    }
+
+    $defaults = array();
+    if ($output && isset($output['configuration']) && is_array($output['configuration'])) {
+      if (isset($output['configuration']['restrict_tasks'])) {
+        $defaults['restrict_tasks'] = $output['configuration']['restrict_tasks'];
+      }
+      if (isset($output['configuration']['tasks'])) {
+        $defaults['tasks_checkboxes'] = [];
+        foreach($output['configuration']['tasks'] as $task) {
+          $defaults['tasks_checkboxes'][$task] = 1;
+        }
+      }
+    }
+    $form->setDefaults($defaults);
+  }
+
+  /**
+   * Process the submitted values and create a configuration array
+   *
+   * @param $submittedValues
+   * @return array
+   */
+  public static function processConfiguration($submittedValues, $configuration) {
+    $configuration['restrict_tasks'] = isset($submittedValues['restrict_tasks']) ? $submittedValues['restrict_tasks'] : false;
+    $configuration['tasks'] = [];
+    if (!empty($submittedValues['sorted_tasks'])) {
+      $sortedTasks = explode(',', $submittedValues['sorted_tasks']);
+      foreach ($sortedTasks as $val) {
+        if ($val && isset($submittedValues['tasks_checkboxes']['task_' . $val])) {
+          $configuration['tasks'][] = 'task_' . $val;
+        }
+      }
+    } elseif (isset($submittedValues['tasks_checkboxes'])) {
+      $configuration['tasks'] = array_keys($submittedValues['tasks_checkboxes']);
+    }
+    return $configuration;
+  }
+
+}
diff --git a/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl b/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl
index 2d318253..cab0f5c9 100644
--- a/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl
+++ b/templates/CRM/Contact/Form/OutputConfiguration/DataProcessorContactSearch.tpl
@@ -64,6 +64,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
 <script type="text/javascript">
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ActivitySearch.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ActivitySearch.tpl
index 0b57b9ca..0dfbe565 100644
--- a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ActivitySearch.tpl
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ActivitySearch.tpl
@@ -59,6 +59,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
   <script type="text/javascript">
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/CaseSearch.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/CaseSearch.tpl
index 6ab845e2..2c1a895d 100644
--- a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/CaseSearch.tpl
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/CaseSearch.tpl
@@ -69,6 +69,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
   <script type="text/javascript">
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ContributionSearch.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ContributionSearch.tpl
index dde68b1f..cda27071 100644
--- a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ContributionSearch.tpl
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ContributionSearch.tpl
@@ -59,6 +59,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
   <script type="text/javascript">
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/MembershipSearch.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/MembershipSearch.tpl
index f517dc44..3bb61037 100644
--- a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/MembershipSearch.tpl
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/MembershipSearch.tpl
@@ -59,6 +59,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
   <script type="text/javascript">
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ParticipantSearch.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ParticipantSearch.tpl
index 8ead8939..faaec9a0 100644
--- a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ParticipantSearch.tpl
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/ParticipantSearch.tpl
@@ -59,6 +59,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
   <script type="text/javascript">
@@ -73,3 +74,4 @@
     hardLimitChange();
   </script>
 {/literal}
+
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Search.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Search.tpl
index c947cc2c..1576c9d7 100644
--- a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Search.tpl
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Search.tpl
@@ -69,6 +69,7 @@
     <div class="content">{$form.default_hard_limit.html}</div>
     <div class="clear"></div>
   </div>
+  {include file="CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl"}
 {/crmScope}
 {literal}
   <script type="text/javascript">
diff --git a/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl
new file mode 100644
index 00000000..19f71be6
--- /dev/null
+++ b/templates/CRM/DataprocessorSearch/Form/OutputConfiguration/Tasks.tpl
@@ -0,0 +1,49 @@
+<div class="crm-section">
+  <div class="label">{$form.restrict_tasks.label}</div>
+  <div class="content">{$form.restrict_tasks.html}</div>
+  <div class="clear"></div>
+</div>
+<div class="crm-section" id="section-restrict-tasks">
+  <input type="hidden" name="sorted_tasks" id="sorted_tasks" value="" />
+  <div class="label">{$form.tasks_checkboxes.label}</div>
+  <div class="content">
+    <ul id="tasks" class="crm-checkbox-list crm-sortable-list" style="width: 600px;">
+      {foreach from=$tasks item="task"}
+        <li id="{$task}">
+          {$form.tasks_checkboxes.$task.html}
+        </li>
+      {/foreach}
+    </ul>
+  </div>
+  <div class="clear"></div>
+</div>
+{literal}
+  <script type="text/javascript">
+    cj("#restrict_tasks").click(restrictTasksChange);
+    function restrictTasksChange() {
+      if (document.getElementById("restrict_tasks").checked) {
+        cj('#section-restrict-tasks').show();
+      } else {
+        cj('#section-restrict-tasks').hide();
+      }
+    }
+    restrictTasksChange();
+
+    function getTaskSorting(e, ui) {
+      var params = [];
+      var items = cj("#tasks li");
+      if (items.length > 0) {
+        for (var y = 0; y < items.length; y++) {
+          var idState = items[y].id.substring(5);
+          params[y + 1] = idState;
+        }
+      }
+      cj('#sorted_tasks').val(params.toString());
+    }
+
+    cj("#tasks").sortable({
+      placeholder: 'ui-state-highlight',
+      update: getTaskSorting
+    });
+  </script>
+{/literal}
-- 
GitLab