protected function renderActionEffectDescription($type, $data)
 {
     switch ($type) {
         case self::DO_STATUS:
             return pht('Changed task status to "%s".', ManiphestTaskStatus::getTaskStatusName($data));
     }
 }
 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);
 }
 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);
 }
 protected function buildTaskInfoDictionaries(array $tasks)
 {
     assert_instances_of($tasks, 'ManiphestTask');
     if (!$tasks) {
         return array();
     }
     $task_phids = mpull($tasks, 'getPHID');
     $all_deps = id(new PhabricatorEdgeQuery())->withSourcePHIDs($task_phids)->withEdgeTypes(array(ManiphestTaskDependsOnTaskEdgeType::EDGECONST));
     $all_deps->execute();
     $result = array();
     foreach ($tasks as $task) {
         // TODO: Batch this get as CustomField gets cleaned up.
         $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT);
         $field_list->readFieldsFromStorage($task);
         $auxiliary = mpull($field_list->getFields(), 'getValueForStorage', 'getFieldKey');
         $task_deps = $all_deps->getDestinationPHIDs(array($task->getPHID()), array(ManiphestTaskDependsOnTaskEdgeType::EDGECONST));
         $result[$task->getPHID()] = array('id' => $task->getID(), 'phid' => $task->getPHID(), 'authorPHID' => $task->getAuthorPHID(), 'ownerPHID' => $task->getOwnerPHID(), 'ccPHIDs' => $task->getSubscriberPHIDs(), 'status' => $task->getStatus(), 'statusName' => ManiphestTaskStatus::getTaskStatusName($task->getStatus()), 'isClosed' => $task->isClosed(), 'priority' => ManiphestTaskPriority::getTaskPriorityName($task->getPriority()), 'priorityColor' => ManiphestTaskPriority::getTaskPriorityColor($task->getPriority()), 'title' => $task->getTitle(), 'description' => $task->getDescription(), 'projectPHIDs' => $task->getProjectPHIDs(), 'uri' => PhabricatorEnv::getProductionURI('/T' . $task->getID()), 'auxiliary' => $auxiliary, 'objectName' => 'T' . $task->getID(), 'dateCreated' => $task->getDateCreated(), 'dateModified' => $task->getDateModified(), 'dependsOnTaskPHIDs' => $task_deps);
     }
     return $result;
 }
 public function getTitleForFeed(PhabricatorFeedStory $story)
 {
     $author_phid = $this->getAuthorPHID();
     $object_phid = $this->getObjectPHID();
     $old = $this->getOldValue();
     $new = $this->getNewValue();
     switch ($this->getTransactionType()) {
         case self::TYPE_TITLE:
             if ($old === null) {
                 return pht('%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             }
             return pht('%s renamed %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new);
         case self::TYPE_DESCRIPTION:
             return pht('%s edited the description of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
         case self::TYPE_STATUS:
             $old_closed = ManiphestTaskStatus::isClosedStatus($old);
             $new_closed = ManiphestTaskStatus::isClosedStatus($new);
             $old_name = ManiphestTaskStatus::getTaskStatusName($old);
             $new_name = ManiphestTaskStatus::getTaskStatusName($new);
             if ($new_closed && !$old_closed) {
                 if ($new == ManiphestTaskStatus::getDuplicateStatus()) {
                     return pht('%s closed %s as a duplicate.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
                 } else {
                     return pht('%s closed %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name);
                 }
             } else {
                 if (!$new_closed && $old_closed) {
                     return pht('%s reopened %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name);
                 } else {
                     return pht('%s changed the status of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 }
             }
         case self::TYPE_UNBLOCK:
             $blocker_phid = key($new);
             $old_status = head($old);
             $new_status = head($new);
             $old_closed = ManiphestTaskStatus::isClosedStatus($old_status);
             $new_closed = ManiphestTaskStatus::isClosedStatus($new_status);
             $old_name = ManiphestTaskStatus::getTaskStatusName($old_status);
             $new_name = ManiphestTaskStatus::getTaskStatusName($new_status);
             if ($old_closed && !$new_closed) {
                 return pht('%s reopened %s, a task blocking %s, as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $this->renderHandleLink($object_phid), $new_name);
             } else {
                 if (!$old_closed && $new_closed) {
                     return pht('%s closed %s, a task blocking %s, as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $this->renderHandleLink($object_phid), $new_name);
                 } else {
                     return pht('%s changed the status of %s, a task blocking %s, ' . 'from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 }
             }
         case self::TYPE_OWNER:
             if ($author_phid == $new) {
                 return pht('%s claimed %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             } else {
                 if (!$new) {
                     return pht('%s placed %s up for grabs.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
                 } else {
                     if (!$old) {
                         return pht('%s assigned %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($new));
                     } else {
                         return pht('%s reassigned %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($old), $this->renderHandleLink($new));
                     }
                 }
             }
         case self::TYPE_PROJECTS:
             $added = array_diff($new, $old);
             $removed = array_diff($old, $new);
             if ($added && !$removed) {
                 return pht('%s added %d project(s) to %s: %s', $this->renderHandleLink($author_phid), count($added), $this->renderHandleLink($object_phid), $this->renderHandleList($added));
             } else {
                 if ($removed && !$added) {
                     return pht('%s removed %d project(s) from %s: %s', $this->renderHandleLink($author_phid), count($removed), $this->renderHandleLink($object_phid), $this->renderHandleList($removed));
                 } else {
                     if ($removed && $added) {
                         return pht('%s changed project(s) of %s, added %d: %s; removed %d: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed));
                     }
                 }
             }
         case self::TYPE_PRIORITY:
             $old_name = ManiphestTaskPriority::getTaskPriorityName($old);
             $new_name = ManiphestTaskPriority::getTaskPriorityName($new);
             if ($old == ManiphestTaskPriority::getDefaultPriority()) {
                 return pht('%s triaged %s as "%s" priority.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name);
             } else {
                 if ($old > $new) {
                     return pht('%s lowered the priority of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 } else {
                     return pht('%s raised the priority of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 }
             }
         case self::TYPE_CCS:
             // TODO: Remove this when we switch to subscribers. Just reuse the
             // code in the parent.
             $clone = clone $this;
             $clone->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS);
             return $clone->getTitleForFeed($story);
         case self::TYPE_EDGE:
             // TODO: Remove this when we switch to real edges. Just reuse the
             // code in the parent;
             $clone = clone $this;
             $clone->setTransactionType(PhabricatorTransactions::TYPE_EDGE);
             return $clone->getTitleForFeed($story);
         case self::TYPE_ATTACH:
             $old = nonempty($old, array());
             $new = nonempty($new, array());
             $new = array_keys(idx($new, 'FILE', array()));
             $old = array_keys(idx($old, 'FILE', array()));
             $added = array_diff($new, $old);
             $removed = array_diff($old, $new);
             if ($added && !$removed) {
                 return pht('%s attached %d file(s) of %s: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added));
             } else {
                 if ($removed && !$added) {
                     return pht('%s detached %d file(s) of %s: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($removed), $this->renderHandleList($removed));
                 } else {
                     return pht('%s changed file(s) for %s, attached %d: %s; detached %d: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed));
                 }
             }
         case self::TYPE_PROJECT_COLUMN:
             $project_phid = $new['projectPHID'];
             $column_phid = head($new['columnPHIDs']);
             return pht('%s moved %s to %s on the %s workboard.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($column_phid), $this->renderHandleLink($project_phid));
         case self::TYPE_MERGED_INTO:
             return pht('%s merged task %s into %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($new));
         case self::TYPE_MERGED_FROM:
             return pht('%s merged %d task(s) %s into %s.', $this->renderHandleLink($author_phid), count($new), $this->renderHandleList($new), $this->renderHandleLink($object_phid));
     }
     return parent::getTitleForFeed($story);
 }
 protected function newNavigationMenuItems(PhabricatorProfilePanelConfiguration $config)
 {
     $viewer = $this->getViewer();
     $project = $config->getProfileObject();
     $limit = 250;
     $tasks = id(new ManiphestTaskQuery())->setViewer($viewer)->withEdgeLogicPHIDs(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_AND, array($project->getPHID()))->setLimit($limit + 1)->execute();
     if (count($tasks) > $limit) {
         return $this->renderError(pht('Too many tasks to compute statistics for (more than %s).', new PhutilNumber($limit)));
     }
     if (!$tasks) {
         return $this->renderError(pht('This milestone has no tasks yet.'));
     }
     $statuses = array();
     $points_done = 0;
     $points_total = 0;
     $no_points = 0;
     foreach ($tasks as $task) {
         $points = $task->getPoints();
         if ($points === null) {
             $no_points++;
             continue;
         }
         if (!$points) {
             continue;
         }
         $status = $task->getStatus();
         if (empty($statuses[$status])) {
             $statuses[$status] = 0;
         }
         $statuses[$status] += $points;
         if (ManiphestTaskStatus::isClosedStatus($status)) {
             $points_done += $points;
         }
         $points_total += $points;
     }
     if ($no_points == count($tasks)) {
         return $this->renderError(pht('No tasks have assigned point values.'));
     }
     if (!$points_total) {
         return $this->renderError(pht('All tasks with assigned point values are worth zero points.'));
     }
     $label = pht('%s of %s %s', new PhutilNumber($points_done), new PhutilNumber($points_total), ManiphestTaskPoints::getPointsLabel());
     $bar = id(new PHUISegmentBarView())->setLabel($label);
     $map = ManiphestTaskStatus::getTaskStatusMap();
     $statuses = array_select_keys($statuses, array_keys($map));
     foreach ($statuses as $status => $points) {
         if (!$points) {
             continue;
         }
         if (!ManiphestTaskStatus::isClosedStatus($status)) {
             continue;
         }
         $color = ManiphestTaskStatus::getStatusColor($status);
         if (!$color) {
             $color = 'sky';
         }
         $tooltip = pht('%s %s', new PhutilNumber($points), ManiphestTaskStatus::getTaskStatusName($status));
         $bar->newSegment()->setWidth($points / $points_total)->setColor($color)->setTooltip($tooltip);
     }
     $bar = phutil_tag('div', array('class' => 'phui-profile-segment-bar'), $bar);
     $item = $this->newItem()->appendChild($bar);
     return array($item);
 }
 public function getFieldValuesForConduit()
 {
     $status_value = $this->getStatus();
     $status_info = array('value' => $status_value, 'name' => ManiphestTaskStatus::getTaskStatusName($status_value), 'color' => ManiphestTaskStatus::getStatusColor($status_value));
     $priority_value = (int) $this->getPriority();
     $priority_info = array('value' => $priority_value, 'subpriority' => (double) $this->getSubpriority(), 'name' => ManiphestTaskPriority::getTaskPriorityName($priority_value), 'color' => ManiphestTaskPriority::getTaskPriorityColor($priority_value));
     return array('name' => $this->getTitle(), 'authorPHID' => $this->getAuthorPHID(), 'ownerPHID' => $this->getOwnerPHID(), 'status' => $status_info, 'priority' => $priority_info);
 }
 public function getTitleForFeed()
 {
     $author_phid = $this->getAuthorPHID();
     $object_phid = $this->getObjectPHID();
     $old = $this->getOldValue();
     $new = $this->getNewValue();
     switch ($this->getTransactionType()) {
         case self::TYPE_TITLE:
             if ($old === null) {
                 return pht('%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             }
             return pht('%s renamed %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new);
         case self::TYPE_DESCRIPTION:
             return pht('%s edited the description of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
         case self::TYPE_STATUS:
             $old_closed = ManiphestTaskStatus::isClosedStatus($old);
             $new_closed = ManiphestTaskStatus::isClosedStatus($new);
             $old_name = ManiphestTaskStatus::getTaskStatusName($old);
             $new_name = ManiphestTaskStatus::getTaskStatusName($new);
             $commit_phid = $this->getMetadataValue('commitPHID');
             if ($new_closed && !$old_closed) {
                 if ($new == ManiphestTaskStatus::getDuplicateStatus()) {
                     if ($commit_phid) {
                         return pht('%s closed %s as a duplicate by committing %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($commit_phid));
                     } else {
                         return pht('%s closed %s as a duplicate.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
                     }
                 } else {
                     if ($commit_phid) {
                         return pht('%s closed %s as "%s" by committing %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name, $this->renderHandleLink($commit_phid));
                     } else {
                         return pht('%s closed %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name);
                     }
                 }
             } else {
                 if (!$new_closed && $old_closed) {
                     if ($commit_phid) {
                         return pht('%s reopened %s as "%s" by committing %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name, $this->renderHandleLink($commit_phid));
                     } else {
                         return pht('%s reopened %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name);
                     }
                 } else {
                     if ($commit_phid) {
                         return pht('%s changed the status of %s from "%s" to "%s" by committing %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name, $this->renderHandleLink($commit_phid));
                     } else {
                         return pht('%s changed the status of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                     }
                 }
             }
         case self::TYPE_UNBLOCK:
             $blocker_phid = key($new);
             $old_status = head($old);
             $new_status = head($new);
             $old_closed = ManiphestTaskStatus::isClosedStatus($old_status);
             $new_closed = ManiphestTaskStatus::isClosedStatus($new_status);
             $old_name = ManiphestTaskStatus::getTaskStatusName($old_status);
             $new_name = ManiphestTaskStatus::getTaskStatusName($new_status);
             if ($old_closed && !$new_closed) {
                 return pht('%s reopened %s, a subtask of %s, as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $this->renderHandleLink($object_phid), $new_name);
             } else {
                 if (!$old_closed && $new_closed) {
                     return pht('%s closed %s, a subtask of %s, as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $this->renderHandleLink($object_phid), $new_name);
                 } else {
                     return pht('%s changed the status of %s, a subtasktask of %s, ' . 'from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 }
             }
         case self::TYPE_OWNER:
             if ($author_phid == $new) {
                 return pht('%s claimed %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             } else {
                 if (!$new) {
                     return pht('%s placed %s up for grabs.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
                 } else {
                     if (!$old) {
                         return pht('%s assigned %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($new));
                     } else {
                         return pht('%s reassigned %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($old), $this->renderHandleLink($new));
                     }
                 }
             }
         case self::TYPE_PRIORITY:
             $old_name = ManiphestTaskPriority::getTaskPriorityName($old);
             $new_name = ManiphestTaskPriority::getTaskPriorityName($new);
             if ($old == ManiphestTaskPriority::getDefaultPriority()) {
                 return pht('%s triaged %s as "%s" priority.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name);
             } else {
                 if ($old > $new) {
                     return pht('%s lowered the priority of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 } else {
                     return pht('%s raised the priority of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name);
                 }
             }
         case self::TYPE_ATTACH:
             $old = nonempty($old, array());
             $new = nonempty($new, array());
             $new = array_keys(idx($new, 'FILE', array()));
             $old = array_keys(idx($old, 'FILE', array()));
             $added = array_diff($new, $old);
             $removed = array_diff($old, $new);
             if ($added && !$removed) {
                 return pht('%s attached %d file(s) of %s: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added));
             } else {
                 if ($removed && !$added) {
                     return pht('%s detached %d file(s) of %s: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($removed), $this->renderHandleList($removed));
                 } else {
                     return pht('%s changed file(s) for %s, attached %d: %s; detached %d: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed));
                 }
             }
         case self::TYPE_MERGED_INTO:
             return pht('%s merged task %s into %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($new));
         case self::TYPE_MERGED_FROM:
             return pht('%s merged %s task(s) %s into %s.', $this->renderHandleLink($author_phid), phutil_count($new), $this->renderHandleList($new), $this->renderHandleLink($object_phid));
     }
     return parent::getTitleForFeed();
 }