Пример #1
0
 protected function newTableRow($phid, $object, $trace)
 {
     $viewer = $this->getViewer();
     if ($object) {
         $status = $object->getStatus();
         $priority = $object->getPriority();
         $status_icon = ManiphestTaskStatus::getStatusIcon($status);
         $status_name = ManiphestTaskStatus::getTaskStatusName($status);
         $priority_color = ManiphestTaskPriority::getTaskPriorityColor($priority);
         if ($object->isClosed()) {
             $priority_color = 'grey';
         }
         $status = array(id(new PHUIIconView())->setIcon($status_icon, $priority_color), ' ', $status_name);
         $owner_phid = $object->getOwnerPHID();
         if ($owner_phid) {
             $assigned = $viewer->renderHandle($owner_phid);
         } else {
             $assigned = phutil_tag('em', array(), pht('None'));
         }
         $link = phutil_tag('a', array('href' => $object->getURI()), $object->getTitle());
         $link = array($object->getMonogram(), ' ', $link);
     } else {
         $status = null;
         $assigned = null;
         $link = $viewer->renderHandle($phid);
     }
     return array($trace, $status, $assigned, $link);
 }
 public function render()
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     $task = $this->task;
     $handles = $this->handles;
     require_celerity_resource('maniphest-task-summary-css');
     $pri_class = self::getPriorityClass($task->getPriority());
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     $batch = null;
     if ($this->showBatchControls) {
         $batch = '<td class="maniphest-task-batch">' . javelin_render_tag('input', array('type' => 'checkbox', 'name' => 'batch[]', 'value' => $task->getID(), 'sigil' => 'maniphest-batch'), null) . '</td>';
     }
     $projects_view = new ManiphestTaskProjectsView();
     $projects_view->setHandles(array_select_keys($this->handles, $task->getProjectPHIDs()));
     $control_class = null;
     $control_sigil = null;
     if ($this->showSubpriorityControls) {
         $control_class = 'maniphest-active-handle';
         $control_sigil = 'maniphest-task-handle';
     }
     $handle = javelin_render_tag('td', array('class' => 'maniphest-task-handle ' . $pri_class . ' ' . $control_class, 'sigil' => $control_sigil), '');
     return javelin_render_tag('table', array('class' => 'maniphest-task-summary', 'sigil' => 'maniphest-task', 'meta' => array('taskID' => $task->getID())), '<tr>' . $handle . $batch . '<td class="maniphest-task-number">' . 'T' . $task->getID() . '</td>' . '<td class="maniphest-task-status">' . idx($status_map, $task->getStatus(), 'Unknown') . '</td>' . '<td class="maniphest-task-owner">' . ($task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : '<em>None</em>') . '</td>' . '<td class="maniphest-task-name">' . phutil_render_tag('a', array('href' => '/T' . $task->getID()), phutil_escape_html($task->getTitle())) . '</td>' . '<td class="maniphest-task-projects">' . $projects_view->render() . '</td>' . '<td class="maniphest-task-updated">' . phabricator_date($task->getDateModified(), $this->user) . '</td>' . '</tr>');
 }
 private function buildActionView(ManiphestTask $task)
 {
     $viewer = $this->getRequest()->getUser();
     $id = $task->getID();
     $phid = $task->getPHID();
     $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $task, PhabricatorPolicyCapability::CAN_EDIT);
     $view = id(new PhabricatorActionListView())->setUser($viewer)->setObject($task);
     $view->addAction(id(new PhabricatorActionView())->setName(pht('Edit Task'))->setIcon('fa-pencil')->setHref($this->getApplicationURI("/task/edit/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(!$can_edit));
     $view->addAction(id(new PhabricatorActionView())->setName(pht('Merge Duplicates In'))->setHref("/search/attach/{$phid}/TASK/merge/")->setWorkflow(true)->setIcon('fa-compress')->setDisabled(!$can_edit)->setWorkflow(true));
     $edit_config = id(new ManiphestEditEngine())->setViewer($viewer)->loadDefaultEditConfiguration();
     $can_create = (bool) $edit_config;
     if ($can_create) {
         $form_key = $edit_config->getIdentifier();
         $edit_uri = id(new PhutilURI("/task/edit/form/{$form_key}/"))->setQueryParam('parent', $id)->setQueryParam('template', $id)->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus());
         $edit_uri = $this->getApplicationURI($edit_uri);
     } else {
         // TODO: This will usually give us a somewhat-reasonable error page, but
         // could be a bit cleaner.
         $edit_uri = "/task/edit/{$id}/";
         $edit_uri = $this->getApplicationURI($edit_uri);
     }
     $view->addAction(id(new PhabricatorActionView())->setName(pht('Create Subtask'))->setHref($edit_uri)->setIcon('fa-level-down')->setDisabled(!$can_create)->setWorkflow(!$can_create));
     $view->addAction(id(new PhabricatorActionView())->setName(pht('Edit Blocking Tasks'))->setHref("/search/attach/{$phid}/TASK/blocks/")->setWorkflow(true)->setIcon('fa-link')->setDisabled(!$can_edit)->setWorkflow(true));
     return $view;
 }
Пример #4
0
 public function getItem()
 {
     $task = $this->getTask();
     $owner = $this->getOwner();
     $can_edit = $this->getCanEdit();
     $viewer = $this->getViewer();
     $color_map = ManiphestTaskPriority::getColorMap();
     $bar_color = idx($color_map, $task->getPriority(), 'grey');
     $card = id(new PHUIObjectItemView())->setObject($task)->setUser($viewer)->setObjectName('T' . $task->getID())->setHeader($task->getTitle())->setGrippable($can_edit)->setHref('/T' . $task->getID())->addSigil('project-card')->setDisabled($task->isClosed())->setMetadata(array('objectPHID' => $task->getPHID()))->addAction(id(new PHUIListItemView())->setName(pht('Edit'))->setIcon('fa-pencil')->addSigil('edit-project-card')->setHref('/maniphest/task/edit/' . $task->getID() . '/'))->setBarColor($bar_color);
     if ($owner) {
         $card->addHandleIcon($owner, $owner->getName());
     }
     $cover_file = $this->getCoverImageFile();
     if ($cover_file) {
         $card->setCoverImage($cover_file->getBestURI());
     }
     if ($task->isClosed()) {
         $icon = ManiphestTaskStatus::getStatusIcon($task->getStatus());
         $icon = id(new PHUIIconView())->setIcon($icon . ' grey');
         $card->addAttribute($icon);
         $card->setBarColor('grey');
     }
     $project_handles = $this->getProjectHandles();
     if ($project_handles) {
         $tag_list = id(new PHUIHandleTagListView())->setSlim(true)->setHandles($project_handles);
         $card->addAttribute($tag_list);
     }
     return $card;
 }
 protected function renderActionEffectDescription($type, $data)
 {
     switch ($type) {
         case self::DO_STATUS:
             return pht('Changed task status to "%s".', ManiphestTaskStatus::getTaskStatusName($data));
     }
 }
 private function buildHeaderView(ManiphestTask $task)
 {
     $view = id(new PHUIHeaderView())->setHeader($task->getTitle())->setUser($this->getRequest()->getUser())->setPolicyObject($task);
     $status = $task->getStatus();
     $status_name = ManiphestTaskStatus::renderFullDescription($status);
     $view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name);
     return $view;
 }
 private function buildResults()
 {
     $results = array();
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     foreach ($status_map as $value => $name) {
         $results[$value] = id(new PhabricatorTypeaheadResult())->setIcon(ManiphestTaskStatus::getStatusIcon($value))->setPHID($value)->setName($name);
     }
     return $results;
 }
 public function loadStatus(PhabricatorUser $user)
 {
     $status = array();
     $query = id(new ManiphestTaskQuery())->setViewer($user)->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())->withOwners(array($user->getPHID()));
     $count = count($query->execute());
     $type = PhabricatorApplicationStatusView::TYPE_WARNING;
     $status[] = id(new PhabricatorApplicationStatusView())->setType($type)->setText(pht('%s Assigned Task(s)', new PhutilNumber($count)))->setCount($count);
     return $status;
 }
 public function getEditorValue(PhabricatorUser $viewer, $value)
 {
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     $value_map = array();
     foreach ($value as $status) {
         $value_map[$status] = idx($status_map, $status, $status);
     }
     return $value_map;
 }
 private function renderUserItems(PhutilEvent $event)
 {
     if (!$this->canUseApplication($event->getUser())) {
         return null;
     }
     $user = $event->getValue('object');
     $phid = $user->getPHID();
     $view_uri = sprintf('/maniphest/?statuses=%s&assigned=%s#R', implode(',', ManiphestTaskStatus::getOpenStatusConstants()), $phid);
     return id(new PhabricatorActionView())->setIcon('fa-anchor')->setName(pht('View Tasks'))->setHref($view_uri);
 }
 private function assertConfigValid($expect, $name, array $config)
 {
     $caught = null;
     try {
         ManiphestTaskStatus::validateConfiguration($config);
     } catch (Exception $ex) {
         $caught = $ex;
     }
     $this->assertEqual($expect, !$caught instanceof Exception, pht('Validation of "%s"', $name));
 }
 public function generateTaskStatus()
 {
     $statuses = array_keys(ManiphestTaskStatus::getTaskStatusMap());
     // Make sure 4/5th of all generated Tasks are open
     $random = rand(0, 4);
     if ($random != 0) {
         return ManiphestTaskStatus::getDefaultStatus();
     } else {
         return array_rand($statuses);
     }
 }
Пример #13
0
 public function render()
 {
     $handles = $this->handles;
     require_celerity_resource('maniphest-task-summary-css');
     $list = new PHUIObjectItemListView();
     if ($this->noDataString) {
         $list->setNoDataString($this->noDataString);
     } else {
         $list->setNoDataString(pht('No tasks.'));
     }
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     $color_map = ManiphestTaskPriority::getColorMap();
     $priority_map = ManiphestTaskPriority::getTaskPriorityMap();
     if ($this->showBatchControls) {
         Javelin::initBehavior('maniphest-list-editor');
     }
     foreach ($this->tasks as $task) {
         $item = id(new PHUIObjectItemView())->setUser($this->getUser())->setObject($task)->setObjectName('T' . $task->getID())->setHeader($task->getTitle())->setHref('/T' . $task->getID());
         if ($task->getOwnerPHID()) {
             $owner = $handles[$task->getOwnerPHID()];
             $item->addByline(pht('Assigned: %s', $owner->renderLink()));
         }
         $status = $task->getStatus();
         $pri = idx($priority_map, $task->getPriority());
         $status_name = idx($status_map, $task->getStatus());
         $tooltip = pht('%s, %s', $status_name, $pri);
         $icon = ManiphestTaskStatus::getStatusIcon($task->getStatus());
         $color = idx($color_map, $task->getPriority(), 'grey');
         if ($task->isClosed()) {
             $item->setDisabled(true);
             $color = 'grey';
         }
         $item->setStatusIcon($icon . ' ' . $color, $tooltip);
         $item->addIcon('none', phabricator_datetime($task->getDateModified(), $this->getUser()));
         if ($this->showSubpriorityControls) {
             $item->setGrippable(true);
         }
         if ($this->showSubpriorityControls || $this->showBatchControls) {
             $item->addSigil('maniphest-task');
         }
         $project_handles = array_select_keys($handles, array_reverse($task->getProjectPHIDs()));
         $item->addAttribute(id(new PHUIHandleTagListView())->setLimit(4)->setNoDataString(pht('No Projects'))->setSlim(true)->setHandles($project_handles));
         $item->setMetadata(array('taskID' => $task->getID()));
         if ($this->showBatchControls) {
             $href = new PhutilURI('/maniphest/task/edit/' . $task->getID() . '/');
             if (!$this->showSubpriorityControls) {
                 $href->setQueryParam('ungrippable', 'true');
             }
             $item->addAction(id(new PHUIListItemView())->setIcon('fa-pencil')->addSigil('maniphest-edit-task')->setHref($href));
         }
         $list->addItem($item);
     }
     return $list;
 }
 private function buildCurtain(ManiphestTask $task, PhabricatorEditEngine $edit_engine)
 {
     $viewer = $this->getViewer();
     $id = $task->getID();
     $phid = $task->getPHID();
     $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $task, PhabricatorPolicyCapability::CAN_EDIT);
     $curtain = $this->newCurtainView($task);
     $curtain->addAction(id(new PhabricatorActionView())->setName(pht('Edit Task'))->setIcon('fa-pencil')->setHref($this->getApplicationURI("/task/edit/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(!$can_edit));
     $edit_config = $edit_engine->loadDefaultEditConfiguration();
     $can_create = (bool) $edit_config;
     $can_reassign = $edit_engine->hasEditAccessToTransaction(ManiphestTransaction::TYPE_OWNER);
     if ($can_create) {
         $form_key = $edit_config->getIdentifier();
         $edit_uri = id(new PhutilURI("/task/edit/form/{$form_key}/"))->setQueryParam('parent', $id)->setQueryParam('template', $id)->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus());
         $edit_uri = $this->getApplicationURI($edit_uri);
     } else {
         // TODO: This will usually give us a somewhat-reasonable error page, but
         // could be a bit cleaner.
         $edit_uri = "/task/edit/{$id}/";
         $edit_uri = $this->getApplicationURI($edit_uri);
     }
     $subtask_item = id(new PhabricatorActionView())->setName(pht('Create Subtask'))->setHref($edit_uri)->setIcon('fa-level-down')->setDisabled(!$can_create)->setWorkflow(!$can_create);
     $relationship_list = PhabricatorObjectRelationshipList::newForObject($viewer, $task);
     $submenu_actions = array($subtask_item, ManiphestTaskHasParentRelationship::RELATIONSHIPKEY, ManiphestTaskHasSubtaskRelationship::RELATIONSHIPKEY, ManiphestTaskMergeInRelationship::RELATIONSHIPKEY, ManiphestTaskCloseAsDuplicateRelationship::RELATIONSHIPKEY);
     $task_submenu = $relationship_list->newActionSubmenu($submenu_actions)->setName(pht('Edit Related Tasks...'))->setIcon('fa-anchor');
     $curtain->addAction($task_submenu);
     $relationship_submenu = $relationship_list->newActionMenu();
     if ($relationship_submenu) {
         $curtain->addAction($relationship_submenu);
     }
     $owner_phid = $task->getOwnerPHID();
     $author_phid = $task->getAuthorPHID();
     $handles = $viewer->loadHandles(array($owner_phid, $author_phid));
     if ($owner_phid) {
         $image_uri = $handles[$owner_phid]->getImageURI();
         $image_href = $handles[$owner_phid]->getURI();
         $owner = $viewer->renderHandle($owner_phid)->render();
         $content = phutil_tag('strong', array(), $owner);
         $assigned_to = id(new PHUIHeadThingView())->setImage($image_uri)->setImageHref($image_href)->setContent($content);
     } else {
         $assigned_to = phutil_tag('em', array(), pht('None'));
     }
     $curtain->newPanel()->setHeaderText(pht('Assigned To'))->appendChild($assigned_to);
     $author_uri = $handles[$author_phid]->getImageURI();
     $author_href = $handles[$author_phid]->getURI();
     $author = $viewer->renderHandle($author_phid)->render();
     $content = phutil_tag('strong', array(), $author);
     $date = phabricator_date($task->getDateCreated(), $viewer);
     $content = pht('%s, %s', $content, $date);
     $authored_by = id(new PHUIHeadThingView())->setImage($author_uri)->setImageHref($author_href)->setContent($content);
     $curtain->newPanel()->setHeaderText(pht('Authored By'))->appendChild($authored_by);
     return $curtain;
 }
 public function processRequest()
 {
     $this->requireApplicationCapability(ManiphestBulkEditCapability::CAPABILITY);
     $request = $this->getRequest();
     $user = $request->getUser();
     $task_ids = $request->getArr('batch');
     $tasks = id(new ManiphestTaskQuery())->setViewer($user)->withIDs($task_ids)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
     $actions = $request->getStr('actions');
     if ($actions) {
         $actions = json_decode($actions, true);
     }
     if ($request->isFormPost() && is_array($actions)) {
         foreach ($tasks as $task) {
             $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT);
             $field_list->readFieldsFromStorage($task);
             $xactions = $this->buildTransactions($actions, $task);
             if ($xactions) {
                 // TODO: Set content source to "batch edit".
                 $editor = id(new ManiphestTransactionEditor())->setActor($user)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->applyTransactions($task, $xactions);
             }
         }
         $task_ids = implode(',', mpull($tasks, 'getID'));
         return id(new AphrontRedirectResponse())->setURI('/maniphest/?ids=' . $task_ids);
     }
     $handles = ManiphestTaskListView::loadTaskHandles($user, $tasks);
     $list = new ManiphestTaskListView();
     $list->setTasks($tasks);
     $list->setUser($user);
     $list->setHandles($handles);
     $template = new AphrontTokenizerTemplateView();
     $template = $template->render();
     $projects_source = new PhabricatorProjectDatasource();
     $mailable_source = new PhabricatorMetaMTAMailableDatasource();
     $owner_source = new PhabricatorTypeaheadOwnerDatasource();
     require_celerity_resource('maniphest-batch-editor');
     Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText()), 'owner' => array('src' => $owner_source->getDatasourceURI(), 'placeholder' => $owner_source->getPlaceholderText(), 'limit' => 1), 'cc' => array('src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText())), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap()));
     $form = new AphrontFormView();
     $form->setUser($user);
     $form->setID('maniphest-batch-edit-form');
     foreach ($tasks as $task) {
         $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID())));
     }
     $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions')));
     $form->appendChild(phutil_tag('p', array(), pht('These tasks will be edited:')));
     $form->appendChild($list);
     $form->appendChild(id(new AphrontFormInsetView())->setTitle('Actions')->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), pht('Add Another Action')))->setContent(javelin_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Update Tasks'))->addCancelButton('/maniphest/'));
     $title = pht('Batch Editor');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb($title);
     $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Batch Edit Tasks'))->setForm($form);
     return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => $title, 'device' => false));
 }
 public function render()
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     $task = $this->task;
     $handles = $this->handles;
     require_celerity_resource('maniphest-task-summary-css');
     $classes = array(ManiphestTaskPriority::PRIORITY_UNBREAK_NOW => 'pri-unbreak', ManiphestTaskPriority::PRIORITY_TRIAGE => 'pri-triage', ManiphestTaskPriority::PRIORITY_HIGH => 'pri-high', ManiphestTaskPriority::PRIORITY_NORMAL => 'pri-normal', ManiphestTaskPriority::PRIORITY_LOW => 'pri-low', ManiphestTaskPriority::PRIORITY_WISH => 'pri-wish');
     $pri_class = idx($classes, $task->getPriority());
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     return '<table class="maniphest-task-summary">' . '<tr>' . '<td class="maniphest-task-number ' . $pri_class . '">' . 'T' . $task->getID() . '</td>' . '<td class="maniphest-task-status">' . idx($status_map, $task->getStatus(), 'Unknown') . '</td>' . '<td class="maniphest-task-owner">' . ($task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : '<em>None</em>') . '</td>' . '<td class="maniphest-task-name">' . phutil_render_tag('a', array('href' => '/T' . $task->getID()), phutil_escape_html($task->getTitle())) . '</td>' . '<td class="maniphest-task-priority">' . ManiphestTaskPriority::getTaskPriorityName($task->getPriority()) . '</td>' . '<td class="maniphest-task-updated">' . phabricator_datetime($task->getDateModified(), $this->user) . '</td>' . '</tr>' . '</table>';
 }
 public function loadStatus(PhabricatorUser $user)
 {
     $status = array();
     if (!$user->isLoggedIn()) {
         return $status;
     }
     $query = id(new ManiphestTaskQuery())->setViewer($user)->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())->withOwners(array($user->getPHID()))->setLimit(self::MAX_STATUS_ITEMS);
     $count = count($query->execute());
     $count_str = self::formatStatusCount($count, '%s Assigned Tasks', '%d Assigned Task(s)');
     $type = PhabricatorApplicationStatusView::TYPE_WARNING;
     $status[] = id(new PhabricatorApplicationStatusView())->setType($type)->setText($count_str)->setCount($count);
     return $status;
 }
 protected function evaluateFunction($function, array $argv_list)
 {
     $results = array();
     $map = ManiphestTaskStatus::getTaskStatusMap();
     foreach ($argv_list as $argv) {
         foreach ($map as $status => $name) {
             if (ManiphestTaskStatus::isOpenStatus($status)) {
                 $results[] = $status;
             }
         }
     }
     return $results;
 }
 private function buildResults()
 {
     $results = array();
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     foreach ($status_map as $value => $name) {
         $result = id(new PhabricatorTypeaheadResult())->setIcon(ManiphestTaskStatus::getStatusIcon($value))->setPHID($value)->setName($name);
         if (ManiphestTaskStatus::isDisabledStatus($value)) {
             $result->setClosed(pht('Disabled'));
         }
         $results[$value] = $result;
     }
     return $results;
 }
 /**
  * @phutil-external-symbol class PHPExcel
  * @phutil-external-symbol class PHPExcel_IOFactory
  * @phutil-external-symbol class PHPExcel_Style_NumberFormat
  * @phutil-external-symbol class PHPExcel_Cell_DataType
  */
 public function buildWorkbook(PHPExcel $workbook, array $tasks, array $handles, PhabricatorUser $user)
 {
     $sheet = $workbook->setActiveSheetIndex(0);
     $sheet->setTitle(pht('Tasks'));
     $widths = array(null, 15, null, 10, 15, 15, 60, 30, 20, 100);
     foreach ($widths as $col => $width) {
         if ($width !== null) {
             $sheet->getColumnDimension($this->col($col))->setWidth($width);
         }
     }
     $status_map = ManiphestTaskStatus::getTaskStatusMap();
     $pri_map = ManiphestTaskPriority::getTaskPriorityMap();
     $date_format = null;
     $rows = array();
     $rows[] = array(pht('ID'), pht('Owner'), pht('Status'), pht('Priority'), pht('Date Created'), pht('Date Updated'), pht('Deadline'), pht('Title'), pht('Projects'), pht('Description'));
     $is_date = array(false, false, false, false, true, true, true, false, false, false);
     $header_format = array('font' => array('bold' => true));
     foreach ($tasks as $task) {
         $task_owner = null;
         if ($task->getOwnerPHID()) {
             $task_owner = $handles[$task->getOwnerPHID()]->getName();
         }
         $projects = array();
         foreach ($task->getProjectPHIDs() as $phid) {
             $projects[] = $handles[$phid]->getName();
         }
         $projects = implode(', ', $projects);
         $custom_fields = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW);
         $custom_fields->setViewer($user)->readFieldsFromStorage($task);
         $fields = $custom_fields->getFields();
         $rows[] = array('T' . $task->getID(), $task_owner, idx($status_map, $task->getStatus(), '?'), idx($pri_map, $task->getPriority(), '?'), $this->computeExcelDate($task->getDateCreated()), $this->computeExcelDate($task->getDateModified()), $this->computeExcelDate($fields['std:maniphest:Deadline']->getValueForStorage()), $task->getTitle(), $projects, id(new PhutilUTF8StringTruncator())->setMaximumBytes(512)->truncateString($task->getDescription()));
     }
     foreach ($rows as $row => $cols) {
         foreach ($cols as $col => $spec) {
             $cell_name = $this->col($col) . ($row + 1);
             $cell = $sheet->setCellValue($cell_name, $spec, $return_cell = true);
             if ($row == 0) {
                 $sheet->getStyle($cell_name)->applyFromArray($header_format);
             }
             if ($is_date[$col]) {
                 $code = PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2;
                 $sheet->getStyle($cell_name)->getNumberFormat()->setFormatCode($code);
             } else {
                 $cell->setDataType(PHPExcel_Cell_DataType::TYPE_STRING);
             }
         }
     }
 }
 private function buildCurtain(ManiphestTask $task, PhabricatorEditEngine $edit_engine)
 {
     $viewer = $this->getViewer();
     $id = $task->getID();
     $phid = $task->getPHID();
     $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $task, PhabricatorPolicyCapability::CAN_EDIT);
     $curtain = $this->newCurtainView($task);
     $curtain->addAction(id(new PhabricatorActionView())->setName(pht('Edit Task'))->setIcon('fa-pencil')->setHref($this->getApplicationURI("/task/edit/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(!$can_edit));
     $curtain->addAction(id(new PhabricatorActionView())->setName(pht('Merge Duplicates In'))->setHref("/search/attach/{$phid}/TASK/merge/")->setWorkflow(true)->setIcon('fa-compress')->setDisabled(!$can_edit)->setWorkflow(true));
     $edit_config = $edit_engine->loadDefaultEditConfiguration();
     $can_create = (bool) $edit_config;
     $can_reassign = $edit_engine->hasEditAccessToTransaction(ManiphestTransaction::TYPE_OWNER);
     if ($can_create) {
         $form_key = $edit_config->getIdentifier();
         $edit_uri = id(new PhutilURI("/task/edit/form/{$form_key}/"))->setQueryParam('parent', $id)->setQueryParam('template', $id)->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus());
         $edit_uri = $this->getApplicationURI($edit_uri);
     } else {
         // TODO: This will usually give us a somewhat-reasonable error page, but
         // could be a bit cleaner.
         $edit_uri = "/task/edit/{$id}/";
         $edit_uri = $this->getApplicationURI($edit_uri);
     }
     $curtain->addAction(id(new PhabricatorActionView())->setName(pht('Create Subtask'))->setHref($edit_uri)->setIcon('fa-level-down')->setDisabled(!$can_create)->setWorkflow(!$can_create));
     $curtain->addAction(id(new PhabricatorActionView())->setName(pht('Edit Blocking Tasks'))->setHref("/search/attach/{$phid}/TASK/blocks/")->setWorkflow(true)->setIcon('fa-link')->setDisabled(!$can_edit)->setWorkflow(true));
     $owner_phid = $task->getOwnerPHID();
     $author_phid = $task->getAuthorPHID();
     $handles = $viewer->loadHandles(array($owner_phid, $author_phid));
     if ($owner_phid) {
         $image_uri = $handles[$owner_phid]->getImageURI();
         $image_href = $handles[$owner_phid]->getURI();
         $owner = $viewer->renderHandle($owner_phid)->render();
         $content = phutil_tag('strong', array(), $owner);
         $assigned_to = id(new PHUIHeadThingView())->setImage($image_uri)->setImageHref($image_href)->setContent($content);
     } else {
         $assigned_to = phutil_tag('em', array(), pht('None'));
     }
     $curtain->newPanel()->setHeaderText(pht('Assigned To'))->appendChild($assigned_to);
     $author_uri = $handles[$author_phid]->getImageURI();
     $author_href = $handles[$author_phid]->getURI();
     $author = $viewer->renderHandle($author_phid)->render();
     $content = phutil_tag('strong', array(), $author);
     $date = phabricator_date($task->getDateCreated(), $viewer);
     $content = pht('%s, %s', $content, $date);
     $authored_by = id(new PHUIHeadThingView())->setImage($author_uri)->setImageHref($author_href)->setContent($content);
     $curtain->newPanel()->setHeaderText(pht('Authored By'))->appendChild($authored_by);
     return $curtain;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $task_ids = $request->getArr('batch');
     $tasks = id(new ManiphestTask())->loadAllWhere('id IN (%Ld)', $task_ids);
     $actions = $request->getStr('actions');
     if ($actions) {
         $actions = json_decode($actions, true);
     }
     if ($request->isFormPost() && is_array($actions)) {
         foreach ($tasks as $task) {
             $xactions = $this->buildTransactions($actions, $task);
             if ($xactions) {
                 $editor = new ManiphestTransactionEditor();
                 $editor->applyTransactions($task, $xactions);
             }
         }
         $task_ids = implode(',', mpull($tasks, 'getID'));
         return id(new AphrontRedirectResponse())->setURI('/maniphest/view/custom/?s=oc&tasks=' . $task_ids);
     }
     $panel = new AphrontPanelView();
     $panel->setHeader('Maniphest Batch Editor');
     $handle_phids = mpull($tasks, 'getOwnerPHID');
     $handles = id(new PhabricatorObjectHandleData($handle_phids))->loadHandles();
     $list = new ManiphestTaskListView();
     $list->setTasks($tasks);
     $list->setUser($user);
     $list->setHandles($handles);
     $template = new AphrontTokenizerTemplateView();
     $template = $template->render();
     require_celerity_resource('maniphest-batch-editor');
     Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => '/typeahead/common/projects/', 'placeholder' => 'Type a project name...'), 'owner' => array('src' => '/typeahead/common/searchowner/', 'placeholder' => 'Type a user name...', 'limit' => 1)), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap()));
     $form = new AphrontFormView();
     $form->setUser($user);
     $form->setID('maniphest-batch-edit-form');
     foreach ($tasks as $task) {
         $form->appendChild(phutil_render_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID()), null));
     }
     $form->appendChild(phutil_render_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions'), null));
     $form->appendChild('<p>These tasks will be edited:</p>');
     $form->appendChild($list);
     $form->appendChild(id(new AphrontFormInsetView())->setTitle('Actions')->setRightButton(javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), 'Add Another Action'))->setContent(javelin_render_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue('Update Tasks')->addCancelButton('/maniphest/', 'Done'));
     $panel->appendChild($form);
     return $this->buildStandardPageResponse($panel, array('title' => 'Batch Editor'));
 }
Пример #23
0
 protected function newTableRow($phid, $object, $trace)
 {
     $viewer = $this->getViewer();
     if ($object) {
         $status = $object->getStatus();
         $priority = $object->getPriority();
         $status_icon = ManiphestTaskStatus::getStatusIcon($status);
         $status_name = ManiphestTaskStatus::getTaskStatusName($status);
         $priority_color = ManiphestTaskPriority::getTaskPriorityColor($priority);
         if ($object->isClosed()) {
             $priority_color = 'grey';
         }
         $status = array(id(new PHUIIconView())->setIcon($status_icon, $priority_color), ' ', $status_name);
         $owner_phid = $object->getOwnerPHID();
         if ($owner_phid) {
             $assigned = $viewer->renderHandle($owner_phid);
         } else {
             $assigned = phutil_tag('em', array(), pht('None'));
         }
         $full_title = $object->getTitle();
         $title = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(80)->truncateString($full_title);
         $link = phutil_tag('a', array('href' => $object->getURI(), 'title' => $full_title), $title);
         $link = array(phutil_tag('span', array('class' => 'object-name'), $object->getMonogram()), ' ', $link);
     } else {
         $status = null;
         $assigned = null;
         $link = $viewer->renderHandle($phid);
     }
     if ($this->isParentTask($phid)) {
         $marker = 'fa-chevron-circle-up bluegrey';
         $marker_tip = pht('Direct Parent');
     } else {
         if ($this->isChildTask($phid)) {
             $marker = 'fa-chevron-circle-down bluegrey';
             $marker_tip = pht('Direct Subtask');
         } else {
             $marker = null;
         }
     }
     if ($marker) {
         $marker = id(new PHUIIconView())->setIcon($marker)->addSigil('has-tooltip')->setMetadata(array('tip' => $marker_tip, 'align' => 'E'));
     }
     return array($marker, $trace, $status, $assigned, $link);
 }
 public function buildTransactions(PhabricatorUser $viewer, PhabricatorApplicationTransactionInterface $object, PhabricatorMetaMTAReceivedMail $mail, $command, array $argv)
 {
     $xactions = array();
     $target = phutil_utf8_strtolower(head($argv));
     $status = null;
     $keywords = ManiphestTaskStatus::getTaskStatusKeywordsMap();
     foreach ($keywords as $key => $words) {
         foreach ($words as $word) {
             if ($word == $target) {
                 $status = $key;
                 break;
             }
         }
     }
     if ($status === null) {
         return array();
     }
     $xactions[] = $object->getApplicationTransactionTemplate()->setTransactionType(ManiphestTransaction::TYPE_STATUS)->setNewValue($status);
     return $xactions;
 }
Пример #25
0
function addTask($kan_task, $project_id)
{
    $user = getAdmin();
    $task = ManiphestTask::initializeNewTask($user);
    $changes = array();
    $transactions = array();
    $changes[ManiphestTransaction::TYPE_TITLE] = $kan_task['title'];
    $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $kan_task['description'];
    $changes[ManiphestTransaction::TYPE_STATUS] = ManiphestTaskStatus::getDefaultStatus();
    $changes[PhabricatorTransactions::TYPE_COMMENT] = null;
    $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
    $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setNewValue(array('=' => array_fuse(array($project_id))));
    $template = new ManiphestTransaction();
    foreach ($changes as $type => $value) {
        $transaction = clone $template;
        $transaction->setTransactionType($type);
        $transaction->setNewValue($value);
        $transactions[] = $transaction;
    }
    $editor = id(new ManiphestTransactionEditor())->setActor($user)->setContentSourceFromConduitRequest(new ConduitAPIRequest(array()))->setContinueOnNoEffect(true);
    $editor->applyTransactions($task, $transactions);
}
 private function addTaskStatustoData($data)
 {
     foreach ($data as $key => $row) {
         // NOTE: Hack to avoid json_decode().
         $oldv = trim($row['oldValue'], '"');
         $newv = trim($row['newValue'], '"');
         if ($oldv == 'null') {
             $old_is_open = false;
         } else {
             $old_is_open = ManiphestTaskStatus::isOpenStatus($oldv);
         }
         $new_is_open = ManiphestTaskStatus::isOpenStatus($newv);
         $is_open = $new_is_open && !$old_is_open;
         $is_close = $old_is_open && !$new_is_open;
         $data[$key]['_is_open'] = $is_open;
         $data[$key]['_is_close'] = $is_close;
         if (!$is_open && !$is_close) {
             // This is either some kind of bogus events, or a resolution change
             // (e.g., resolved -> invalid). Just skip it.
             continue;
         }
     }
     return $data;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $results = array('defaultStatus' => ManiphestTaskStatus::getDefaultStatus(), 'defaultClosedStatus' => ManiphestTaskStatus::getDefaultClosedStatus(), 'duplicateStatus' => ManiphestTaskStatus::getDuplicateStatus(), 'openStatuses' => ManiphestTaskStatus::getOpenStatusConstants(), 'closedStatuses' => ManiphestTaskStatus::getClosedStatusConstants(), 'allStatuses' => array_keys(ManiphestTaskStatus::getTaskStatusMap()), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap());
     return $results;
 }
 private function loadTasks(array $user_phids, array $project_phids, array $task_ids, array $dict)
 {
     $query = new ManiphestTaskQuery();
     $query->withProjects($project_phids);
     $query->withTaskIDs($task_ids);
     $status = $dict['status'];
     if (!empty($status['open']) && !empty($status['closed'])) {
         $query->withStatus(ManiphestTaskQuery::STATUS_ANY);
     } else {
         if (!empty($status['open'])) {
             $query->withStatus(ManiphestTaskQuery::STATUS_OPEN);
         } else {
             $query->withStatus(ManiphestTaskQuery::STATUS_CLOSED);
         }
     }
     switch ($this->view) {
         case 'action':
             $query->withOwners($user_phids);
             break;
         case 'created':
             $query->withAuthors($user_phids);
             break;
         case 'subscribed':
             $query->withSubscribers($user_phids);
             break;
         case 'triage':
             $query->withOwners($user_phids);
             $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
             break;
         case 'alltriage':
             $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
             break;
         case 'all':
             break;
     }
     $order_map = array('priority' => ManiphestTaskQuery::ORDER_PRIORITY, 'created' => ManiphestTaskQuery::ORDER_CREATED);
     $query->setOrderBy(idx($order_map, $dict['order'], ManiphestTaskQuery::ORDER_MODIFIED));
     $group_map = array('priority' => ManiphestTaskQuery::GROUP_PRIORITY, 'owner' => ManiphestTaskQuery::GROUP_OWNER, 'status' => ManiphestTaskQuery::GROUP_STATUS);
     $query->setGroupBy(idx($group_map, $dict['group'], ManiphestTaskQuery::GROUP_NONE));
     $query->setCalculateRows(true);
     $query->setLimit($dict['limit']);
     $query->setOffset($dict['offset']);
     $data = $query->execute();
     $total_row_count = $query->getRowCount();
     $handle_phids = mpull($data, 'getOwnerPHID');
     $handle_phids = array_merge($handle_phids, $project_phids, $user_phids);
     $handles = id(new PhabricatorObjectHandleData($handle_phids))->loadHandles();
     switch ($dict['group']) {
         case 'priority':
             $data = mgroup($data, 'getPriority');
             krsort($data);
             // If we have invalid priorities, they'll all map to "???". Merge
             // arrays to prevent them from overwriting each other.
             $out = array();
             foreach ($data as $pri => $tasks) {
                 $out[ManiphestTaskPriority::getTaskPriorityName($pri)][] = $tasks;
             }
             foreach ($out as $pri => $tasks) {
                 $out[$pri] = array_mergev($tasks);
             }
             $data = $out;
             break;
         case 'status':
             $data = mgroup($data, 'getStatus');
             ksort($data);
             $out = array();
             foreach ($data as $status => $tasks) {
                 $out[ManiphestTaskStatus::getTaskStatusFullName($status)] = $tasks;
             }
             $data = $out;
             break;
         case 'owner':
             $data = mgroup($data, 'getOwnerPHID');
             $out = array();
             foreach ($data as $phid => $tasks) {
                 if ($phid) {
                     $out[$handles[$phid]->getFullName()] = $tasks;
                 } else {
                     $out['Unassigned'] = $tasks;
                 }
             }
             if (isset($out['Unassigned'])) {
                 // If any tasks are unassigned, move them to the front of the list.
                 $data = array('Unassigned' => $out['Unassigned']) + $out;
             } else {
                 $data = $out;
             }
             ksort($data);
             break;
         default:
             $data = array('Tasks' => $data);
             break;
     }
     return array($data, $handles, $total_row_count);
 }
 protected function expandTransactions(PhabricatorLiskDAO $object, array $xactions)
 {
     $results = parent::expandTransactions($object, $xactions);
     $is_unassigned = $object->getOwnerPHID() === null;
     $any_assign = false;
     foreach ($xactions as $xaction) {
         if ($xaction->getTransactionType() == ManiphestTransaction::TYPE_OWNER) {
             $any_assign = true;
             break;
         }
     }
     $is_open = !$object->isClosed();
     $new_status = null;
     foreach ($xactions as $xaction) {
         switch ($xaction->getTransactionType()) {
             case ManiphestTransaction::TYPE_STATUS:
                 $new_status = $xaction->getNewValue();
                 break;
         }
     }
     if ($new_status === null) {
         $is_closing = false;
     } else {
         $is_closing = ManiphestTaskStatus::isClosedStatus($new_status);
     }
     // If the task is not assigned, not being assigned, currently open, and
     // being closed, try to assign the actor as the owner.
     if ($is_unassigned && !$any_assign && $is_open && $is_closing) {
         // Don't assign the actor if they aren't a real user.
         $actor = $this->getActor();
         $actor_phid = $actor->getPHID();
         if ($actor_phid) {
             $results[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_OWNER)->setNewValue($actor_phid);
         }
     }
     return $results;
 }
 public static function loadTasks(PhabricatorSearchQuery $search_query)
 {
     $any_project = false;
     $search_text = $search_query->getParameter('fullTextSearch');
     $user_phids = $search_query->getParameter('userPHIDs', array());
     $project_phids = $search_query->getParameter('projectPHIDs', array());
     $task_ids = $search_query->getParameter('taskIDs', array());
     $xproject_phids = $search_query->getParameter('excludeProjectPHIDs', array());
     $owner_phids = $search_query->getParameter('ownerPHIDs', array());
     $author_phids = $search_query->getParameter('authorPHIDs', array());
     $low_priority = $search_query->getParameter('lowPriority');
     $low_priority = nonempty($low_priority, ManiphestTaskPriority::getLowestPriority());
     $high_priority = $search_query->getParameter('highPriority');
     $high_priority = nonempty($high_priority, ManiphestTaskPriority::getHighestPriority());
     $query = new ManiphestTaskQuery();
     $query->withProjects($project_phids);
     $query->withTaskIDs($task_ids);
     if ($xproject_phids) {
         $query->withoutProjects($xproject_phids);
     }
     if ($owner_phids) {
         $query->withOwners($owner_phids);
     }
     if ($author_phids) {
         $query->withAuthors($author_phids);
     }
     $status = $search_query->getParameter('status', 'all');
     if (!empty($status['open']) && !empty($status['closed'])) {
         $query->withStatus(ManiphestTaskQuery::STATUS_ANY);
     } else {
         if (!empty($status['open'])) {
             $query->withStatus(ManiphestTaskQuery::STATUS_OPEN);
         } else {
             $query->withStatus(ManiphestTaskQuery::STATUS_CLOSED);
         }
     }
     switch ($search_query->getParameter('view')) {
         case 'action':
             $query->withOwners($user_phids);
             break;
         case 'created':
             $query->withAuthors($user_phids);
             break;
         case 'subscribed':
             $query->withSubscribers($user_phids);
             break;
         case 'triage':
             $query->withOwners($user_phids);
             $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
             break;
         case 'alltriage':
             $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
             break;
         case 'all':
             break;
         case 'projecttriage':
             $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
             $any_project = true;
             break;
         case 'projectall':
             $any_project = true;
             break;
         case 'custom':
             $query->withPrioritiesBetween($low_priority, $high_priority);
             break;
     }
     $query->withAnyProject($any_project);
     $query->withFullTextSearch($search_text);
     $order_map = array('priority' => ManiphestTaskQuery::ORDER_PRIORITY, 'created' => ManiphestTaskQuery::ORDER_CREATED, 'title' => ManiphestTaskQuery::ORDER_TITLE);
     $query->setOrderBy(idx($order_map, $search_query->getParameter('order'), ManiphestTaskQuery::ORDER_MODIFIED));
     $group_map = array('priority' => ManiphestTaskQuery::GROUP_PRIORITY, 'owner' => ManiphestTaskQuery::GROUP_OWNER, 'status' => ManiphestTaskQuery::GROUP_STATUS, 'project' => ManiphestTaskQuery::GROUP_PROJECT);
     $query->setGroupBy(idx($group_map, $search_query->getParameter('group'), ManiphestTaskQuery::GROUP_NONE));
     $query->setCalculateRows(true);
     $query->setLimit($search_query->getParameter('limit'));
     $query->setOffset($search_query->getParameter('offset'));
     $data = $query->execute();
     $total_row_count = $query->getRowCount();
     $project_group_phids = array();
     if ($search_query->getParameter('group') == 'project') {
         foreach ($data as $task) {
             foreach ($task->getProjectPHIDs() as $phid) {
                 $project_group_phids[] = $phid;
             }
         }
     }
     $handle_phids = mpull($data, 'getOwnerPHID');
     $handle_phids = array_merge($handle_phids, $project_phids, $user_phids, $xproject_phids, $owner_phids, $author_phids, $project_group_phids, array_mergev(mpull($data, 'getProjectPHIDs')));
     $handles = id(new PhabricatorObjectHandleData($handle_phids))->loadHandles();
     switch ($search_query->getParameter('group')) {
         case 'priority':
             $data = mgroup($data, 'getPriority');
             // If we have invalid priorities, they'll all map to "???". Merge
             // arrays to prevent them from overwriting each other.
             $out = array();
             foreach ($data as $pri => $tasks) {
                 $out[ManiphestTaskPriority::getTaskPriorityName($pri)][] = $tasks;
             }
             foreach ($out as $pri => $tasks) {
                 $out[$pri] = array_mergev($tasks);
             }
             $data = $out;
             break;
         case 'status':
             $data = mgroup($data, 'getStatus');
             $out = array();
             foreach ($data as $status => $tasks) {
                 $out[ManiphestTaskStatus::getTaskStatusFullName($status)] = $tasks;
             }
             $data = $out;
             break;
         case 'owner':
             $data = mgroup($data, 'getOwnerPHID');
             $out = array();
             foreach ($data as $phid => $tasks) {
                 if ($phid) {
                     $out[$handles[$phid]->getFullName()] = $tasks;
                 } else {
                     $out['Unassigned'] = $tasks;
                 }
             }
             $data = $out;
             ksort($data);
             // Move "Unassigned" to the top of the list.
             if (isset($data['Unassigned'])) {
                 $data = array('Unassigned' => $out['Unassigned']) + $out;
             }
             break;
         case 'project':
             $grouped = array();
             foreach ($query->getGroupByProjectResults() as $project => $tasks) {
                 foreach ($tasks as $task) {
                     $group = $project ? $handles[$project]->getName() : 'No Project';
                     $grouped[$group][$task->getID()] = $task;
                 }
             }
             $data = $grouped;
             ksort($data);
             // Move "No Project" to the end of the list.
             if (isset($data['No Project'])) {
                 $noproject = $data['No Project'];
                 unset($data['No Project']);
                 $data += array('No Project' => $noproject);
             }
             break;
         default:
             $data = array('Tasks' => $data);
             break;
     }
     return array($data, $handles, $total_row_count);
 }