Commit b5722a99 authored by epriestley's avatar epriestley
Browse files

Use EditEngine stacked comments in Diffusion

Summary: Ref T10978. Ref T8739. Fixes T10446. Converts Diffusion to modern comment/preview code, like Differential.

Test Plan: {F2342933}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10978, T10446, T8739

Differential Revision: https://secure.phabricator.com/D17183
parent 82c891f5
......@@ -13,7 +13,7 @@ return array(
'core.pkg.js' => 'a2ead3fe',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '9535a7e6',
'differential.pkg.js' => '40b18f35',
'differential.pkg.js' => 'ddfeb49b',
'diffusion.pkg.css' => '91c5d3a6',
'diffusion.pkg.js' => '84c8f8fd',
'favicon.ico' => '30672e08',
......@@ -399,13 +399,12 @@ return array(
'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832',
'rsrc/js/application/differential/ChangesetViewManager.js' => 'a2828756',
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '2e3f9738',
'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18',
'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d',
'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76',
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '9a6b9324',
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '4fbbc3e9',
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '92904457',
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb',
'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d',
......@@ -627,13 +626,12 @@ return array(
'javelin-behavior-detect-timezone' => '4c193c96',
'javelin-behavior-device' => 'bb1dd507',
'javelin-behavior-diff-preview-link' => '051c7832',
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
'javelin-behavior-differential-comment-jump' => '4fdb476d',
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
'javelin-behavior-differential-dropdown-menus' => '9a6b9324',
'javelin-behavior-differential-edit-inline-comments' => '4fbbc3e9',
'javelin-behavior-differential-feedback-preview' => 'b064af76',
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
'javelin-behavior-differential-keyboard-navigation' => '92904457',
'javelin-behavior-differential-populate' => '8694b1df',
'javelin-behavior-differential-toggle-files' => 'ca3f91eb',
'javelin-behavior-differential-user-select' => 'a8d8459d',
......@@ -1144,12 +1142,6 @@ return array(
'javelin-install',
'javelin-util',
),
'2c426492' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-keyboard-shortcut',
),
'2caa8fb8' => array(
'javelin-install',
'javelin-event',
......@@ -1651,6 +1643,12 @@ return array(
'javelin-dom',
'javelin-request',
),
92904457 => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-keyboard-shortcut',
),
'92b9ec77' => array(
'javelin-behavior',
'javelin-stratcom',
......@@ -2086,11 +2084,6 @@ return array(
'javelin-request',
'javelin-util',
),
'e10f8e18' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-prefab',
),
'e1621fd5' => array(
'phui-inline-comment-view-css',
),
......@@ -2463,7 +2456,6 @@ return array(
'javelin-behavior-differential-populate',
'javelin-behavior-differential-diff-radios',
'javelin-behavior-differential-comment-jump',
'javelin-behavior-differential-add-reviewers-and-ccs',
'javelin-behavior-differential-keyboard-navigation',
'javelin-behavior-aphront-drag-and-drop-textarea',
'javelin-behavior-phabricator-object-selector',
......
......@@ -195,7 +195,6 @@ return array(
'javelin-behavior-differential-populate',
'javelin-behavior-differential-diff-radios',
'javelin-behavior-differential-comment-jump',
'javelin-behavior-differential-add-reviewers-and-ccs',
'javelin-behavior-differential-keyboard-navigation',
'javelin-behavior-aphront-drag-and-drop-textarea',
'javelin-behavior-phabricator-object-selector',
......
......@@ -1867,7 +1867,6 @@ phutil_register_library_map(array(
'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorAsanaSubtaskHasObjectEdgeType.php',
'PhabricatorAsanaTaskHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorAsanaTaskHasObjectEdgeType.php',
'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php',
'PhabricatorAuditAddCommentController' => 'applications/audit/controller/PhabricatorAuditAddCommentController.php',
'PhabricatorAuditApplication' => 'applications/audit/application/PhabricatorAuditApplication.php',
'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php',
'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/PhabricatorAuditCommitStatusConstants.php',
......@@ -1879,7 +1878,6 @@ phutil_register_library_map(array(
'PhabricatorAuditMailReceiver' => 'applications/audit/mail/PhabricatorAuditMailReceiver.php',
'PhabricatorAuditManagementDeleteWorkflow' => 'applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php',
'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php',
'PhabricatorAuditPreviewController' => 'applications/audit/controller/PhabricatorAuditPreviewController.php',
'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php',
'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php',
'PhabricatorAuditTransaction' => 'applications/audit/storage/PhabricatorAuditTransaction.php',
......@@ -6757,7 +6755,6 @@ phutil_register_library_map(array(
'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorAsanaTaskHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorAuditActionConstants' => 'Phobject',
'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController',
'PhabricatorAuditApplication' => 'PhabricatorApplication',
'PhabricatorAuditCommentEditor' => 'PhabricatorEditor',
'PhabricatorAuditCommitStatusConstants' => 'Phobject',
......@@ -6772,7 +6769,6 @@ phutil_register_library_map(array(
'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver',
'PhabricatorAuditManagementDeleteWorkflow' => 'PhabricatorAuditManagementWorkflow',
'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorAuditPreviewController' => 'PhabricatorAuditController',
'PhabricatorAuditReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'PhabricatorAuditStatusConstants' => 'Phobject',
'PhabricatorAuditTransaction' => 'PhabricatorModularTransaction',
......
......@@ -35,8 +35,6 @@ final class PhabricatorAuditApplication extends PhabricatorApplication {
return array(
'/audit/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorAuditListController',
'addcomment/' => 'PhabricatorAuditAddCommentController',
'preview/(?P<id>[1-9]\d*)/' => 'PhabricatorAuditPreviewController',
),
);
}
......
<?php
final class PhabricatorAuditAddCommentController
extends PhabricatorAuditController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
if (!$request->isFormPost()) {
return new Aphront403Response();
}
$commit_phid = $request->getStr('commit');
$commit = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withPHIDs(array($commit_phid))
->needAuditRequests(true)
->executeOne();
if (!$commit) {
return new Aphront404Response();
}
$xactions = array();
// make sure we only add auditors or ccs if the action matches
$action = $request->getStr('action');
switch ($action) {
case PhabricatorAuditActionConstants::ADD_AUDITORS:
$auditors = $request->getArr('auditors');
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorAuditActionConstants::ADD_AUDITORS)
->setNewValue(array_fuse($auditors));
break;
case PhabricatorAuditActionConstants::ADD_CCS:
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
->setNewValue(
array(
'+' => $request->getArr('ccs'),
));
break;
case PhabricatorAuditActionConstants::COMMENT:
// We'll deal with this below.
break;
default:
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorAuditActionConstants::ACTION)
->setNewValue($action);
break;
}
$content = $request->getStr('content');
if (strlen($content)) {
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new PhabricatorAuditTransactionComment())
->setCommitPHID($commit->getPHID())
->setContent($content));
}
$inlines = PhabricatorAuditInlineComment::loadDraftComments(
$viewer,
$commit->getPHID());
foreach ($inlines as $inline) {
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorAuditActionConstants::INLINE)
->attachComment($inline->getTransactionComment());
}
id(new PhabricatorAuditEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnMissingFields(true)
->applyTransactions($commit, $xactions);
$draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s',
$viewer->getPHID(),
'diffusion-audit-'.$commit->getID());
if ($draft) {
$draft->delete();
}
$uri = $commit->getURI();
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
<?php
final class PhabricatorAuditPreviewController
extends PhabricatorAuditController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$commit = id(new PhabricatorRepositoryCommit())->load($id);
if (!$commit) {
return new Aphront404Response();
}
$xactions = array();
$action = $request->getStr('action');
if ($action != PhabricatorAuditActionConstants::COMMENT) {
$action_xaction = id(new PhabricatorAuditTransaction())
->setAuthorPHID($viewer->getPHID())
->setObjectPHID($commit->getPHID())
->setTransactionType(PhabricatorAuditActionConstants::ACTION)
->setNewValue($action);
$auditors = $request->getStrList('auditors');
if ($action == PhabricatorAuditActionConstants::ADD_AUDITORS &&
$auditors) {
$action_xaction->setTransactionType($action);
$action_xaction->setNewValue(array_fuse($auditors));
}
$ccs = $request->getStrList('ccs');
if ($action == PhabricatorAuditActionConstants::ADD_CCS && $ccs) {
$action_xaction->setTransactionType(
PhabricatorTransactions::TYPE_SUBSCRIBERS);
// NOTE: This doesn't get processed before use, so just provide fake
// values.
$action_xaction->setOldValue(array());
$action_xaction->setNewValue($ccs);
}
$xactions[] = $action_xaction;
}
$content = $request->getStr('content');
if (strlen($content)) {
$xactions[] = id(new PhabricatorAuditTransaction())
->setAuthorPHID($viewer->getPHID())
->setObjectPHID($commit->getPHID())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new PhabricatorAuditTransactionComment())
->setContent($content));
}
$phids = array();
foreach ($xactions as $xaction) {
$phids[] = $xaction->getRequiredHandlePHIDs();
}
$phids = array_mergev($phids);
$handles = $this->loadViewerHandles($phids);
foreach ($xactions as $xaction) {
$xaction->setHandles($handles);
}
$view = id(new PhabricatorAuditTransactionView())
->setIsPreview(true)
->setUser($viewer)
->setObjectPHID($commit->getPHID())
->setTransactions($xactions);
id(new PhabricatorDraft())
->setAuthorPHID($viewer->getPHID())
->setDraftKey('diffusion-audit-'.$id)
->setDraft($content)
->replaceOrDelete();
return id(new AphrontAjaxResponse())->setContent(hsprintf('%s', $view));
}
}
......@@ -10,7 +10,7 @@ final class PhabricatorAuditEditor
private $rawPatch;
private $auditorPHIDs = array();
private $didExpandInlineState;
private $didExpandInlineState = false;
public function addAuditReason($phid, $reason) {
if (!isset($this->auditReasonMap[$phid])) {
......@@ -67,6 +67,21 @@ final class PhabricatorAuditEditor
return $types;
}
protected function expandTransactions(
PhabricatorLiskDAO $object,
array $xactions) {
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorTransactions::TYPE_INLINESTATE:
$this->didExpandInlineState = true;
break;
}
}
return parent::expandTransactions($object, $xactions);
}
protected function transactionHasEffect(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
......
......@@ -68,7 +68,8 @@ final class PhabricatorAuditInlineComment
public static function loadDraftComments(
PhabricatorUser $viewer,
$commit_phid) {
$commit_phid,
$raw = false) {
$inlines = id(new DiffusionDiffInlineCommentQuery())
->setViewer($viewer)
......@@ -80,6 +81,10 @@ final class PhabricatorAuditInlineComment
->needReplyToComments(true)
->execute();
if ($raw) {
return $inlines;
}
return self::buildProxies($inlines);
}
......
......@@ -3,7 +3,7 @@
final class PhabricatorAuditTransactionView
extends PhabricatorApplicationTransactionView {
private $pathMap;
private $pathMap = array();
public function setPathMap(array $path_map) {
$this->pathMap = $path_map;
......@@ -55,12 +55,17 @@ final class PhabricatorAuditTransactionView
$type_inline = PhabricatorAuditActionConstants::INLINE;
$group = $xaction->getTransactionGroup();
if ($xaction->getTransactionType() == $type_inline) {
array_unshift($group, $xaction);
} else {
$out[] = parent::renderTransactionContent($xaction);
}
if ($this->getIsPreview()) {
return $out;
}
if (!$group) {
return $out;
}
......
......@@ -463,12 +463,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
Javelin::initBehavior('differential-user-select');
Javelin::initBehavior(
'differential-keyboard-navigation',
array(
'haunt' => null,
));
Javelin::initBehavior('differential-keyboard-navigation');
$view = id(new PHUITwoColumnView())
->setHeader($header)
......
......@@ -369,7 +369,9 @@ final class DiffusionCommitController extends DiffusionController {
}
$add_comment = $this->renderAddCommentPanel($commit, $audit_requests);
$add_comment = $this->renderAddCommentPanel(
$commit,
$timeline);
$filetree_on = $viewer->compareUserSetting(
PhabricatorShowFiletreeSetting::SETTINGKEY,
......@@ -717,150 +719,24 @@ final class DiffusionCommitController extends DiffusionController {
private function renderAddCommentPanel(
PhabricatorRepositoryCommit $commit,
array $audit_requests) {
assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
$timeline) {
$request = $this->getRequest();
$viewer = $request->getUser();
if (!$viewer->isLoggedIn()) {
return id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setRequestURI($request->getRequestURI());
}
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$pane_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'differential-keyboard-navigation',
array(
'haunt' => $pane_id,
));
$draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s',
$viewer->getPHID(),
'diffusion-audit-'.$commit->getID());
if ($draft) {
$draft = $draft->getDraft();
} else {
$draft = null;
}
$actions = $this->getAuditActions($commit, $audit_requests);
$mailable_source = new PhabricatorMetaMTAMailableDatasource();
$auditor_source = new DiffusionAuditorDatasource();
$form = id(new AphrontFormView())
->setUser($viewer)
->setAction('/audit/addcomment/')
->addHiddenInput('commit', $commit->getPHID())
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Action'))
->setName('action')
->setID('audit-action')
->setOptions($actions))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Add Auditors'))
->setName('auditors')
->setControlID('add-auditors')
->setControlStyle('display: none')
->setID('add-auditors-tokenizer')
->setDisableBehavior(true)
->setDatasource($auditor_source))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Add CCs'))
->setName('ccs')
->setControlID('add-ccs')
->setControlStyle('display: none')
->setID('add-ccs-tokenizer')
->setDisableBehavior(true)
->setDatasource($mailable_source))
->appendChild(
id(new PhabricatorRemarkupControl())
->setLabel(pht('Comments'))
->setName('content')
->setValue($draft)
->setID('audit-content')
->setUser($viewer))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Submit')));
$header = new PHUIHeaderView();
$header->setHeader(
$is_serious ? pht('Audit Commit') : pht('Creative Accounting'));
Javelin::initBehavior(
'differential-add-reviewers-and-ccs',
array(
'dynamic' => array(
'add-auditors-tokenizer' => array(
'actions' => array('add_auditors' => 1),
'src' => $auditor_source->getDatasourceURI(),
'row' => 'add-auditors',
'placeholder' => $auditor_source->getPlaceholderText(),
),
'add-ccs-tokenizer' => array(
'actions' => array('add_ccs' => 1),
'src' => $mailable_source->getDatasourceURI(),
'row' => 'add-ccs',
'placeholder' => $mailable_source->getPlaceholderText(),
),
),
'select' => 'audit-action',
));
Javelin::initBehavior('differential-feedback-preview', array(
'uri' => '/audit/preview/'.$commit->getID().'/',
'preview' => 'audit-preview',
'content' => 'audit-content',
'action' => 'audit-action',
'previewTokenizers' => array(
'auditors' => 'add-auditors-tokenizer',
'ccs' => 'add-ccs-tokenizer',
),
'inline' => 'inline-comment-preview',
'inlineuri' => '/diffusion/inline/preview/'.$commit->getPHID().'/',
));
$loading = phutil_tag_div(
'aphront-panel-preview-loading-text',
pht('Loading preview...'));
$preview_panel = phutil_tag_div(
'aphront-panel-preview aphront-panel-flush',
array(
phutil_tag('div', array('id' => 'audit-preview'), $loading),
phutil_tag('div', array('id' => 'inline-comment-preview')),
));
Javelin::initBehavior('differential-keyboard-navigation');
// TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better.
require_celerity_resource('differential-core-view-css');
$anchor = id(new PhabricatorAnchorView())
->setAnchorName('comment')
->setNavigationMarker(true)
->render();
$comment_view = id(new DiffusionCommitEditEngine())
->setViewer($viewer)
->buildEditEngineCommentView($commit);
$comment_box = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($form);
$comment_view->setTransactionTimeline($timeline);
return phutil_tag(
'div',
array(
'id' => $pane_id,
),
phutil_tag_div(
'differential-add-comment-panel',
array($anchor, $comment_box, $preview_panel)));
return $comment_view;
}
/**
......
......@@ -48,6 +48,21 @@ final class DiffusionCommitEditEngine
->needAuditRequests(true);
}
protected function getEditorURI() {
return $this->getApplication()->getApplicationURI('commit/edit/');
}
protected function newCommentActionGroups() {
return array(
id(new PhabricatorEditEngineCommentActionGroup())
->setKey(self::ACTIONGROUP_AUDIT)
->setLabel(pht('Audit Actions')),
id(new PhabricatorEditEngineCommentActionGroup())
->setKey(self::ACTIONGROUP_COMMIT)
->setLabel(pht('Commit Actions')),
);
}
protected function getObjectCreateTitleText($object) {
return pht('Create Commit');
}
......@@ -143,4 +158,76 @@ final class DiffusionCommitEditEngine
return $fields;
}
protected function newAutomaticCommentTransactions($object) {
$viewer = $this->getViewer();