|
|
|
|
@@ -1,789 +0,0 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @group maniphest
|
|
|
|
|
*/
|
|
|
|
|
final class ManiphestTransactionDetailView extends ManiphestView {
|
|
|
|
|
|
|
|
|
|
private $transactions;
|
|
|
|
|
private $handles;
|
|
|
|
|
private $markupEngine;
|
|
|
|
|
private $forEmail;
|
|
|
|
|
private $preview;
|
|
|
|
|
private $commentNumber;
|
|
|
|
|
|
|
|
|
|
private $auxiliaryFields;
|
|
|
|
|
|
|
|
|
|
public function setAuxiliaryFields(array $fields) {
|
|
|
|
|
assert_instances_of($fields, 'ManiphestCustomField');
|
|
|
|
|
$this->auxiliaryFields = mpull($fields, null, 'getFieldKey');
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getAuxiliaryField($key) {
|
|
|
|
|
return idx($this->auxiliaryFields, $key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setTransactionGroup(array $transactions) {
|
|
|
|
|
assert_instances_of($transactions, 'ManiphestTransaction');
|
|
|
|
|
$this->transactions = $transactions;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setHandles(array $handles) {
|
|
|
|
|
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
|
|
|
|
$this->handles = $handles;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setMarkupEngine(PhabricatorMarkupEngine $engine) {
|
|
|
|
|
$this->markupEngine = $engine;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setPreview($preview) {
|
|
|
|
|
$this->preview = $preview;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setCommentNumber($comment_number) {
|
|
|
|
|
$this->commentNumber = $comment_number;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function renderForEmail($with_date) {
|
|
|
|
|
$this->forEmail = true;
|
|
|
|
|
|
|
|
|
|
$transaction = reset($this->transactions);
|
|
|
|
|
$author = $this->renderHandles(array($transaction->getAuthorPHID()));
|
|
|
|
|
|
|
|
|
|
$action = null;
|
|
|
|
|
$descs = array();
|
|
|
|
|
$comments = null;
|
|
|
|
|
foreach ($this->transactions as $transaction) {
|
|
|
|
|
list($verb, $desc, $classes, $full) = $this->describeAction($transaction);
|
|
|
|
|
|
|
|
|
|
if ($full) {
|
|
|
|
|
$desc = $full;
|
|
|
|
|
} else {
|
|
|
|
|
if ($desc === null) {
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
$desc = $author.' '.$desc.'.';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($action === null) {
|
|
|
|
|
$action = $verb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($with_date) {
|
|
|
|
|
// NOTE: This is going into a (potentially multi-recipient) email so
|
|
|
|
|
// we can't use a single user's timezone preferences. Use the server's
|
|
|
|
|
// instead, but make the timezone explicit.
|
|
|
|
|
$datetime = date('M jS \a\t g:i A T', $transaction->getDateCreated());
|
|
|
|
|
$desc = "On {$datetime}, {$desc}";
|
|
|
|
|
}
|
|
|
|
|
$descs[] = $desc;
|
|
|
|
|
if ($transaction->hasComments()) {
|
|
|
|
|
$comments = $transaction->getComments();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$descs = implode("\n", $descs);
|
|
|
|
|
|
|
|
|
|
if ($comments) {
|
|
|
|
|
$descs .= "\n".$comments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($this->transactions as $transaction) {
|
|
|
|
|
$supplemental = $this->renderSupplementalInfoForEmail($transaction);
|
|
|
|
|
if ($supplemental) {
|
|
|
|
|
$descs .= "\n\n".$supplemental;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->forEmail = false;
|
|
|
|
|
return array($action, $descs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function render() {
|
|
|
|
|
|
|
|
|
|
if (!$this->user) {
|
|
|
|
|
throw new Exception("Call setUser() before render()!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$handles = $this->handles;
|
|
|
|
|
$transactions = $this->transactions;
|
|
|
|
|
|
|
|
|
|
require_celerity_resource('maniphest-transaction-detail-css');
|
|
|
|
|
|
|
|
|
|
$comment_transaction = null;
|
|
|
|
|
foreach ($this->transactions as $transaction) {
|
|
|
|
|
if ($transaction->hasComments()) {
|
|
|
|
|
$comment_transaction = $transaction;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$any_transaction = reset($transactions);
|
|
|
|
|
|
|
|
|
|
$author = $this->handles[$any_transaction->getAuthorPHID()];
|
|
|
|
|
|
|
|
|
|
$more_classes = array();
|
|
|
|
|
$descs = array();
|
|
|
|
|
foreach ($transactions as $transaction) {
|
|
|
|
|
list($verb, $desc, $classes, $full) = $this->describeAction($transaction);
|
|
|
|
|
if ($full) {
|
|
|
|
|
$descs[] = javelin_tag(
|
|
|
|
|
'div',
|
|
|
|
|
array(
|
|
|
|
|
'sigil' => 'maniphest-transaction-description',
|
|
|
|
|
),
|
|
|
|
|
$full);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($desc === null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$more_classes = array_merge($more_classes, $classes);
|
|
|
|
|
$full_summary = null;
|
|
|
|
|
$descs[] = javelin_tag(
|
|
|
|
|
'div',
|
|
|
|
|
array(
|
|
|
|
|
'sigil' => 'maniphest-transaction-description',
|
|
|
|
|
),
|
|
|
|
|
array(
|
|
|
|
|
$author->renderLink(),
|
|
|
|
|
' ',
|
|
|
|
|
$desc,
|
|
|
|
|
'.',
|
|
|
|
|
$full_summary,
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($comment_transaction && $comment_transaction->hasComments()) {
|
|
|
|
|
$comment_block = $this->markupEngine->getOutput(
|
|
|
|
|
$comment_transaction,
|
|
|
|
|
ManiphestTransaction::MARKUP_FIELD_BODY);
|
|
|
|
|
$comment_block = phutil_tag(
|
|
|
|
|
'div',
|
|
|
|
|
array('class' => 'maniphest-transaction-comments phabricator-remarkup'),
|
|
|
|
|
$comment_block);
|
|
|
|
|
} else {
|
|
|
|
|
$comment_block = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$source_transaction = nonempty($comment_transaction, $any_transaction);
|
|
|
|
|
|
|
|
|
|
$xaction_view = id(new PhabricatorTransactionView())
|
|
|
|
|
->setUser($this->user)
|
|
|
|
|
->setImageURI($author->getImageURI())
|
|
|
|
|
->setContentSource($source_transaction->getContentSource())
|
|
|
|
|
->setActions($descs);
|
|
|
|
|
|
|
|
|
|
foreach ($more_classes as $class) {
|
|
|
|
|
$xaction_view->addClass($class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->preview) {
|
|
|
|
|
$xaction_view->setIsPreview($this->preview);
|
|
|
|
|
} else {
|
|
|
|
|
$xaction_view->setEpoch($any_transaction->getDateCreated());
|
|
|
|
|
if ($this->commentNumber) {
|
|
|
|
|
$anchor_name = 'comment-'.$this->commentNumber;
|
|
|
|
|
$anchor_text =
|
|
|
|
|
'#'.$this->commentNumber;
|
|
|
|
|
|
|
|
|
|
$xaction_view->setAnchor($anchor_name, $anchor_text);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$xaction_view->appendChild($comment_block);
|
|
|
|
|
|
|
|
|
|
return $xaction_view->render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function renderSupplementalInfoForEmail($transaction) {
|
|
|
|
|
$handles = $this->handles;
|
|
|
|
|
|
|
|
|
|
$type = $transaction->getTransactionType();
|
|
|
|
|
$new = $transaction->getNewValue();
|
|
|
|
|
$old = $transaction->getOldValue();
|
|
|
|
|
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case ManiphestTransactionType::TYPE_DESCRIPTION:
|
|
|
|
|
return "NEW DESCRIPTION\n ".trim($new)."\n\n".
|
|
|
|
|
"PREVIOUS DESCRIPTION\n ".trim($old);
|
|
|
|
|
case ManiphestTransactionType::TYPE_ATTACH:
|
|
|
|
|
$old_raw = nonempty($old, array());
|
|
|
|
|
$new_raw = nonempty($new, array());
|
|
|
|
|
|
|
|
|
|
$attach_types = array(
|
|
|
|
|
DifferentialPHIDTypeRevision::TYPECONST,
|
|
|
|
|
PhabricatorFilePHIDTypeFile::TYPECONST,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
foreach ($attach_types as $attach_type) {
|
|
|
|
|
$old = array_keys(idx($old_raw, $attach_type, array()));
|
|
|
|
|
$new = array_keys(idx($new_raw, $attach_type, array()));
|
|
|
|
|
if ($old != $new) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$added = array_diff($new, $old);
|
|
|
|
|
if (!$added) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$links = array();
|
|
|
|
|
foreach (array_select_keys($handles, $added) as $handle) {
|
|
|
|
|
$links[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI());
|
|
|
|
|
}
|
|
|
|
|
$links = implode("\n", $links);
|
|
|
|
|
|
|
|
|
|
switch ($attach_type) {
|
|
|
|
|
case DifferentialPHIDTypeRevision::TYPECONST:
|
|
|
|
|
$title = 'ATTACHED REVISIONS';
|
|
|
|
|
break;
|
|
|
|
|
case PhabricatorFilePHIDTypeFile::TYPECONST:
|
|
|
|
|
$title = 'ATTACHED FILES';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $title."\n".$links;
|
|
|
|
|
case ManiphestTransactionType::TYPE_EDGE:
|
|
|
|
|
$add = array_diff_key($new, $old);
|
|
|
|
|
if (!$add) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$links = array();
|
|
|
|
|
foreach ($add as $phid => $ignored) {
|
|
|
|
|
$handle = $handles[$phid];
|
|
|
|
|
$links[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI());
|
|
|
|
|
}
|
|
|
|
|
$links = implode("\n", $links);
|
|
|
|
|
|
|
|
|
|
$edge_type = $transaction->getMetadataValue('edge:type');
|
|
|
|
|
$title = $this->getEdgeEmailTitle($edge_type, $add);
|
|
|
|
|
|
|
|
|
|
return $title."\n".$links;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function describeAction($transaction) {
|
|
|
|
|
$verb = null;
|
|
|
|
|
$desc = null;
|
|
|
|
|
$full = null;
|
|
|
|
|
$classes = array();
|
|
|
|
|
|
|
|
|
|
$handles = $this->handles;
|
|
|
|
|
|
|
|
|
|
$type = $transaction->getTransactionType();
|
|
|
|
|
$author_phid = $transaction->getAuthorPHID();
|
|
|
|
|
$new = $transaction->getNewValue();
|
|
|
|
|
$old = $transaction->getOldValue();
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case ManiphestTransactionType::TYPE_TITLE:
|
|
|
|
|
$verb = 'Retitled';
|
|
|
|
|
$desc = 'changed the title from '.$this->renderString($old).
|
|
|
|
|
' to '.$this->renderString($new);
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_DESCRIPTION:
|
|
|
|
|
$verb = 'Edited';
|
|
|
|
|
$desc = 'updated the task description';
|
|
|
|
|
break;
|
|
|
|
|
case PhabricatorTransactions::TYPE_COMMENT:
|
|
|
|
|
$verb = 'Commented On';
|
|
|
|
|
$desc = 'added a comment';
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_OWNER:
|
|
|
|
|
if ($transaction->getAuthorPHID() == $new) {
|
|
|
|
|
$verb = 'Claimed';
|
|
|
|
|
$desc = 'claimed this task';
|
|
|
|
|
$classes[] = 'claimed';
|
|
|
|
|
} else if (!$new) {
|
|
|
|
|
$verb = 'Up For Grabs';
|
|
|
|
|
$desc = 'placed this task up for grabs';
|
|
|
|
|
$classes[] = 'upforgrab';
|
|
|
|
|
} else if (!$old) {
|
|
|
|
|
$verb = 'Assigned';
|
|
|
|
|
$desc = 'assigned this task to '.$this->renderHandles(array($new));
|
|
|
|
|
$classes[] = 'assigned';
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Reassigned';
|
|
|
|
|
$desc = 'reassigned this task from '.
|
|
|
|
|
$this->renderHandles(array($old)).
|
|
|
|
|
' to '.
|
|
|
|
|
$this->renderHandles(array($new));
|
|
|
|
|
$classes[] = 'reassigned';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_CCS:
|
|
|
|
|
$added = array_diff($new, $old);
|
|
|
|
|
$removed = array_diff($old, $new);
|
|
|
|
|
// can only add in preview so just show placeholder if nothing to add
|
|
|
|
|
if ($this->preview && empty($added)) {
|
|
|
|
|
$verb = 'Changed CC';
|
|
|
|
|
$desc = 'changed CCs..';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ($added && !$removed) {
|
|
|
|
|
$verb = 'Added CC';
|
|
|
|
|
if (count($added) == 1) {
|
|
|
|
|
$desc = 'added '.$this->renderHandles($added).' to CC';
|
|
|
|
|
} else {
|
|
|
|
|
$desc = 'added CCs: '.$this->renderHandles($added);
|
|
|
|
|
}
|
|
|
|
|
} else if ($removed && !$added) {
|
|
|
|
|
$verb = 'Removed CC';
|
|
|
|
|
if (count($removed) == 1) {
|
|
|
|
|
$desc = 'removed '.$this->renderHandles($removed).' from CC';
|
|
|
|
|
} else {
|
|
|
|
|
$desc = 'removed CCs: '.$this->renderHandles($removed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Changed CC';
|
|
|
|
|
$desc = 'changed CCs, added: '.$this->renderHandles($added).'; '.
|
|
|
|
|
'removed: '.$this->renderHandles($removed);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_EDGE:
|
|
|
|
|
$edge_type = $transaction->getMetadataValue('edge:type');
|
|
|
|
|
|
|
|
|
|
$add = array_diff_key($new, $old);
|
|
|
|
|
$rem = array_diff_key($old, $new);
|
|
|
|
|
|
|
|
|
|
if ($add && !$rem) {
|
|
|
|
|
$verb = $this->getEdgeAddVerb($edge_type);
|
|
|
|
|
$desc = $this->getEdgeAddList($edge_type, $add);
|
|
|
|
|
} else if ($rem && !$add) {
|
|
|
|
|
$verb = $this->getEdgeRemVerb($edge_type);
|
|
|
|
|
$desc = $this->getEdgeRemList($edge_type, $rem);
|
|
|
|
|
} else {
|
|
|
|
|
$verb = $this->getEdgeEditVerb($edge_type);
|
|
|
|
|
$desc = $this->getEdgeEditList($edge_type, $add, $rem);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_PROJECTS:
|
|
|
|
|
$added = array_diff($new, $old);
|
|
|
|
|
$removed = array_diff($old, $new);
|
|
|
|
|
// can only add in preview so just show placeholder if nothing to add
|
|
|
|
|
if ($this->preview && empty($added)) {
|
|
|
|
|
$verb = 'Changed Projects';
|
|
|
|
|
$desc = 'changed projects..';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ($added && !$removed) {
|
|
|
|
|
$verb = 'Added Project';
|
|
|
|
|
if (count($added) == 1) {
|
|
|
|
|
$desc = 'added project '.$this->renderHandles($added);
|
|
|
|
|
} else {
|
|
|
|
|
$desc = 'added projects: '.$this->renderHandles($added);
|
|
|
|
|
}
|
|
|
|
|
} else if ($removed && !$added) {
|
|
|
|
|
$verb = 'Removed Project';
|
|
|
|
|
if (count($removed) == 1) {
|
|
|
|
|
$desc = 'removed project '.$this->renderHandles($removed);
|
|
|
|
|
} else {
|
|
|
|
|
$desc = 'removed projects: '.$this->renderHandles($removed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Changed Projects';
|
|
|
|
|
$desc = 'changed projects, added: '.$this->renderHandles($added).'; '.
|
|
|
|
|
'removed: '.$this->renderHandles($removed);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_STATUS:
|
|
|
|
|
if ($new == ManiphestTaskStatus::STATUS_OPEN) {
|
|
|
|
|
if ($old) {
|
|
|
|
|
$verb = 'Reopened';
|
|
|
|
|
$desc = 'reopened this task';
|
|
|
|
|
$classes[] = 'reopened';
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Created';
|
|
|
|
|
$desc = 'created this task';
|
|
|
|
|
$classes[] = 'created';
|
|
|
|
|
}
|
|
|
|
|
} else if ($new == ManiphestTaskStatus::STATUS_CLOSED_SPITE) {
|
|
|
|
|
$verb = 'Spited';
|
|
|
|
|
$desc = 'closed this task out of spite';
|
|
|
|
|
$classes[] = 'spited';
|
|
|
|
|
} else if ($new == ManiphestTaskStatus::STATUS_CLOSED_DUPLICATE) {
|
|
|
|
|
$verb = 'Merged';
|
|
|
|
|
$desc = 'closed this task as a duplicate';
|
|
|
|
|
$classes[] = 'duplicate';
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Closed';
|
|
|
|
|
$full = idx(ManiphestTaskStatus::getTaskStatusMap(), $new, '???');
|
|
|
|
|
$desc = 'closed this task as "'.$full.'"';
|
|
|
|
|
$classes[] = 'closed';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_PRIORITY:
|
|
|
|
|
$old_name = ManiphestTaskPriority::getTaskPriorityName($old);
|
|
|
|
|
$new_name = ManiphestTaskPriority::getTaskPriorityName($new);
|
|
|
|
|
|
|
|
|
|
if ($old == ManiphestTaskPriority::getDefaultPriority()) {
|
|
|
|
|
$verb = 'Triaged';
|
|
|
|
|
$desc = 'triaged this task as "'.$new_name.'" priority';
|
|
|
|
|
} else if ($old > $new) {
|
|
|
|
|
$verb = 'Lowered Priority';
|
|
|
|
|
$desc = 'lowered the priority of this task from "'.$old_name.'" to '.
|
|
|
|
|
'"'.$new_name.'"';
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Raised Priority';
|
|
|
|
|
$desc = 'raised the priority of this task from "'.$old_name.'" to '.
|
|
|
|
|
'"'.$new_name.'"';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ManiphestTransactionType::TYPE_ATTACH:
|
|
|
|
|
if ($this->preview) {
|
|
|
|
|
$verb = 'Changed Attached';
|
|
|
|
|
$desc = 'changed attachments..';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$old_raw = nonempty($old, array());
|
|
|
|
|
$new_raw = nonempty($new, array());
|
|
|
|
|
|
|
|
|
|
foreach (array(
|
|
|
|
|
DifferentialPHIDTypeRevision::TYPECONST,
|
|
|
|
|
ManiphestPHIDTypeTask::TYPECONST,
|
|
|
|
|
PhabricatorFilePHIDTypeFile::TYPECONST) as $attach_type) {
|
|
|
|
|
$old = array_keys(idx($old_raw, $attach_type, array()));
|
|
|
|
|
$new = array_keys(idx($new_raw, $attach_type, array()));
|
|
|
|
|
if ($old != $new) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$added = array_diff($new, $old);
|
|
|
|
|
$removed = array_diff($old, $new);
|
|
|
|
|
|
|
|
|
|
$add_desc = $this->renderHandles($added);
|
|
|
|
|
$rem_desc = $this->renderHandles($removed);
|
|
|
|
|
|
|
|
|
|
if ($added && !$removed) {
|
|
|
|
|
$verb = 'Attached';
|
|
|
|
|
$desc =
|
|
|
|
|
'attached '.
|
|
|
|
|
$this->getAttachName($attach_type, count($added)).': '.
|
|
|
|
|
$add_desc;
|
|
|
|
|
} else if ($removed && !$added) {
|
|
|
|
|
$verb = 'Detached';
|
|
|
|
|
$desc =
|
|
|
|
|
'detached '.
|
|
|
|
|
$this->getAttachName($attach_type, count($removed)).': '.
|
|
|
|
|
$rem_desc;
|
|
|
|
|
} else {
|
|
|
|
|
$verb = 'Changed Attached';
|
|
|
|
|
$desc =
|
|
|
|
|
'changed attached '.
|
|
|
|
|
$this->getAttachName($attach_type, count($added) + count($removed)).
|
|
|
|
|
', added: '.$add_desc.'; '.
|
|
|
|
|
'removed: '.$rem_desc;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
|
|
|
|
$aux_key = $transaction->getMetadataValue('customfield:key');
|
|
|
|
|
$aux_field = idx($this->auxiliaryFields, $aux_key);
|
|
|
|
|
|
|
|
|
|
if ($old === null) {
|
|
|
|
|
$verb = "Set Field";
|
|
|
|
|
} else if ($new === null) {
|
|
|
|
|
$verb = "Removed Field";
|
|
|
|
|
} else {
|
|
|
|
|
$verb = "Updated Field";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$desc = null;
|
|
|
|
|
if ($aux_field) {
|
|
|
|
|
$proxy_transaction = new ManiphestTransactionPro();
|
|
|
|
|
$proxy_transaction->setOldValue($transaction->getOldValue());
|
|
|
|
|
$proxy_transaction->setNewValue($transaction->getNewValue());
|
|
|
|
|
$proxy_transaction->setAuthorPHID($transaction->getAuthorPHID());
|
|
|
|
|
$proxy_transaction->setHandles($this->handles);
|
|
|
|
|
|
|
|
|
|
$full = $aux_field->getApplicationTransactionTitle(
|
|
|
|
|
$proxy_transaction);
|
|
|
|
|
} else {
|
|
|
|
|
$desc = 'updated a field';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return array($type, ' brazenly '.$type."'d", $classes, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: [HTML] This code will all be rewritten when we switch to using
|
|
|
|
|
// ApplicationTransactions. It does not handle HTML or translations
|
|
|
|
|
// correctly right now.
|
|
|
|
|
$desc = phutil_safe_html($desc);
|
|
|
|
|
|
|
|
|
|
return array($verb, $desc, $classes, $full);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function renderExpandLink($transaction) {
|
|
|
|
|
$id = $transaction->getID();
|
|
|
|
|
|
|
|
|
|
Javelin::initBehavior('maniphest-transaction-expand');
|
|
|
|
|
|
|
|
|
|
return javelin_tag(
|
|
|
|
|
'a',
|
|
|
|
|
array(
|
|
|
|
|
'href' => '/maniphest/task/descriptionchange/'.$id.'/',
|
|
|
|
|
'sigil' => 'maniphest-expand-transaction',
|
|
|
|
|
'mustcapture' => true,
|
|
|
|
|
),
|
|
|
|
|
'show details');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function renderHandles($phids, $full = false) {
|
|
|
|
|
$links = array();
|
|
|
|
|
foreach ($phids as $phid) {
|
|
|
|
|
if ($this->forEmail) {
|
|
|
|
|
if ($full) {
|
|
|
|
|
$links[] = $this->handles[$phid]->getFullName();
|
|
|
|
|
} else {
|
|
|
|
|
$links[] = $this->handles[$phid]->getName();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$links[] = $this->handles[$phid]->renderLink();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($this->forEmail) {
|
|
|
|
|
return implode(', ', $links);
|
|
|
|
|
} else {
|
|
|
|
|
return phutil_implode_html(', ', $links);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function renderString($string) {
|
|
|
|
|
if ($this->forEmail) {
|
|
|
|
|
return '"'.$string.'"';
|
|
|
|
|
} else {
|
|
|
|
|
return '"'.phutil_escape_html($string).'"';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -( Strings )------------------------------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getAttachName($attach_type, $count) {
|
|
|
|
|
switch ($attach_type) {
|
|
|
|
|
case DifferentialPHIDTypeRevision::TYPECONST:
|
|
|
|
|
return pht('Differential Revision(s)', $count);
|
|
|
|
|
case PhabricatorFilePHIDTypeFile::TYPECONST:
|
|
|
|
|
return pht('file(s)', $count);
|
|
|
|
|
case ManiphestPHIDTypeTask::TYPECONST:
|
|
|
|
|
return pht('Maniphest Task(s)', $count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeEmailTitle($type, array $list) {
|
|
|
|
|
$count = count($list);
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht('DIFFERENTIAL %d REVISION(S)', $count);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht('DEPENDS ON %d TASK(S)', $count);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht('DEPENDENT %d TASK(s)', $count);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht('ATTACHED %d COMMIT(S)', $count);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht('ATTACHED %d MOCK(S)', $count);
|
|
|
|
|
default:
|
|
|
|
|
return pht('ATTACHED %d OBJECT(S)', $count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeAddVerb($type) {
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht('Added Revision');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht('Added Dependency');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht('Added Dependent Task');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht('Added Commit');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht('Added Mock');
|
|
|
|
|
default:
|
|
|
|
|
return pht('Added Object');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeRemVerb($type) {
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht('Removed Revision');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht('Removed Dependency');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht('Removed Dependent Task');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht('Removed Commit');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht('Removed Mock');
|
|
|
|
|
default:
|
|
|
|
|
return pht('Removed Object');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeEditVerb($type) {
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht('Changed Revisions');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht('Changed Dependencies');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht('Changed Dependent Tasks');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht('Changed Commits');
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht('Changed Mocks');
|
|
|
|
|
default:
|
|
|
|
|
return pht('Changed Objects');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeAddList($type, array $add) {
|
|
|
|
|
$list = $this->renderHandles(array_keys($add), $full = true);
|
|
|
|
|
$count = count($add);
|
|
|
|
|
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht('added %d revision(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht('added %d dependencie(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht('added %d dependent task(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht('added %d commit(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht('added %d mock(s): %s', $count, $list);
|
|
|
|
|
default:
|
|
|
|
|
return pht('added %d object(s): %s', $count, $list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeRemList($type, array $rem) {
|
|
|
|
|
$list = $this->renderHandles(array_keys($rem), $full = true);
|
|
|
|
|
$count = count($rem);
|
|
|
|
|
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht('removed %d revision(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht('removed %d dependencie(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht('removed %d dependent task(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht('removed %d commit(s): %s', $count, $list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht('removed %d mock(s): %s', $count, $list);
|
|
|
|
|
default:
|
|
|
|
|
return pht('removed %d object(s): %s', $count, $list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @task strings
|
|
|
|
|
*/
|
|
|
|
|
private function getEdgeEditList($type, array $add, array $rem) {
|
|
|
|
|
$add_list = $this->renderHandles(array_keys($add), $full = true);
|
|
|
|
|
$rem_list = $this->renderHandles(array_keys($rem), $full = true);
|
|
|
|
|
$add_count = count($add_list);
|
|
|
|
|
$rem_count = count($rem_list);
|
|
|
|
|
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV:
|
|
|
|
|
return pht(
|
|
|
|
|
'changed %d revision(s), added %d: %s; removed %d: %s',
|
|
|
|
|
$add_count + $rem_count,
|
|
|
|
|
$add_count,
|
|
|
|
|
$add_list,
|
|
|
|
|
$rem_count,
|
|
|
|
|
$rem_list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK:
|
|
|
|
|
return pht(
|
|
|
|
|
'changed %d dependencie(s), added %d: %s; removed %d: %s',
|
|
|
|
|
$add_count + $rem_count,
|
|
|
|
|
$add_count,
|
|
|
|
|
$add_list,
|
|
|
|
|
$rem_count,
|
|
|
|
|
$rem_list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK:
|
|
|
|
|
return pht(
|
|
|
|
|
'changed %d dependent task(s), added %d: %s; removed %d: %s',
|
|
|
|
|
$add_count + $rem_count,
|
|
|
|
|
$add_count,
|
|
|
|
|
$add_list,
|
|
|
|
|
$rem_count,
|
|
|
|
|
$rem_list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT:
|
|
|
|
|
return pht(
|
|
|
|
|
'changed %d commit(s), added %d: %s; removed %d: %s',
|
|
|
|
|
$add_count + $rem_count,
|
|
|
|
|
$add_count,
|
|
|
|
|
$add_list,
|
|
|
|
|
$rem_count,
|
|
|
|
|
$rem_list);
|
|
|
|
|
case PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK:
|
|
|
|
|
return pht(
|
|
|
|
|
'changed %d mock(s), added %d: %s; removed %d: %s',
|
|
|
|
|
$add_count + $rem_count,
|
|
|
|
|
$add_count,
|
|
|
|
|
$add_list,
|
|
|
|
|
$rem_count,
|
|
|
|
|
$rem_list);
|
|
|
|
|
default:
|
|
|
|
|
return pht(
|
|
|
|
|
'changed %d object(s), added %d: %s; removed %d: %s',
|
|
|
|
|
$add_count + $rem_count,
|
|
|
|
|
$add_count,
|
|
|
|
|
$add_list,
|
|
|
|
|
$rem_count,
|
|
|
|
|
$rem_list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|