1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-03 18:38:27 +01:00
phorge-phorge/src/infrastructure/diff/PhabricatorInlineCommentController.php

609 lines
18 KiB
PHP
Raw Normal View History

<?php
abstract class PhabricatorInlineCommentController
extends PhabricatorController {
private $containerObject;
abstract protected function createComment();
abstract protected function newInlineCommentQuery();
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
abstract protected function loadCommentForDone($id);
abstract protected function loadObjectOwnerPHID(
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
PhabricatorInlineComment $inline);
abstract protected function newContainerObject();
final protected function getContainerObject() {
if ($this->containerObject === null) {
$object = $this->newContainerObject();
if (!$object) {
throw new Exception(
pht(
'Failed to load container object for inline comment.'));
}
$this->containerObject = $object;
}
return $this->containerObject;
}
protected function hideComments(array $ids) {
throw new PhutilMethodNotImplementedException();
}
protected function showComments(array $ids) {
throw new PhutilMethodNotImplementedException();
}
private $changesetID;
private $isNewFile;
private $isOnRight;
private $lineNumber;
private $lineLength;
private $operation;
private $commentID;
private $renderer;
private $replyToCommentPHID;
public function getCommentID() {
return $this->commentID;
}
public function getOperation() {
return $this->operation;
}
public function getLineLength() {
return $this->lineLength;
}
public function getLineNumber() {
return $this->lineNumber;
}
public function getIsOnRight() {
return $this->isOnRight;
}
public function getChangesetID() {
return $this->changesetID;
}
public function getIsNewFile() {
return $this->isNewFile;
}
public function setRenderer($renderer) {
$this->renderer = $renderer;
return $this;
}
public function getRenderer() {
return $this->renderer;
}
public function setReplyToCommentPHID($phid) {
$this->replyToCommentPHID = $phid;
return $this;
}
public function getReplyToCommentPHID() {
return $this->replyToCommentPHID;
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $this->getViewer();
if (!$request->validateCSRF()) {
return new Aphront404Response();
}
$this->readRequestParameters();
$op = $this->getOperation();
switch ($op) {
case 'hide':
case 'show':
$ids = $request->getStrList('ids');
if ($ids) {
if ($op == 'hide') {
$this->hideComments($ids);
} else {
$this->showComments($ids);
}
}
return id(new AphrontAjaxResponse())->setContent(array());
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
case 'done':
$inline = $this->loadCommentForDone($this->getCommentID());
$is_draft_state = false;
$is_checked = false;
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
switch ($inline->getFixedState()) {
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
case PhabricatorInlineComment::STATE_DRAFT:
$next_state = PhabricatorInlineComment::STATE_UNDONE;
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
break;
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
case PhabricatorInlineComment::STATE_UNDRAFT:
$next_state = PhabricatorInlineComment::STATE_DONE;
$is_checked = true;
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
break;
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
case PhabricatorInlineComment::STATE_DONE:
$next_state = PhabricatorInlineComment::STATE_UNDRAFT;
$is_draft_state = true;
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
break;
default:
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
case PhabricatorInlineComment::STATE_UNDONE:
$next_state = PhabricatorInlineComment::STATE_DRAFT;
$is_draft_state = true;
$is_checked = true;
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
break;
}
$inline->setFixedState($next_state)->save();
return id(new AphrontAjaxResponse())
->setContent(
array(
'isChecked' => $is_checked,
'draftState' => $is_draft_state,
));
case 'delete':
case 'undelete':
case 'refdelete':
// NOTE: For normal deletes, we just process the delete immediately
// and show an "Undo" action. For deletes by reference from the
// preview ("refdelete"), we prompt first (because the "Undo" may
// not draw, or may not be easy to locate).
if ($op == 'refdelete') {
if (!$request->isFormPost()) {
return $this->newDialog()
->setTitle(pht('Really delete comment?'))
->addHiddenInput('id', $this->getCommentID())
->addHiddenInput('op', $op)
->appendParagraph(pht('Delete this inline comment?'))
->addCancelButton('#')
->addSubmitButton(pht('Delete'));
}
}
$is_delete = ($op == 'delete' || $op == 'refdelete');
$inline = $this->loadCommentByIDForEdit($this->getCommentID());
if ($is_delete) {
Update client logic for inline comment "Save" and "Cancel" actions Summary: Ref T13559. Substantially correct the client logic for "Save" and "Cancel" actions to handle unusual cases. Test Plan: Quoting behavior: - Quoted a comment. - Cancelled the quoted comment without modifying anything. - Reloaded page. - Before changes: quoted comment still exists. - After changes: quoted comment is deleted. - Looked at comment count in header, saw consistent behavior (before: weird behavior). Empty suggestion behavior: - Created a new comment on a suggestable file. - Clicked "Suggest Edit" to enable suggestions. - Without making any text or suggestion changes, clicked "Save". - Before changes: comment saves, but is empty. - After changes: comment deletes itself without undo. General behavior: - Created and saved an empty comment (deletes itself). - Created and saved a nonempty comment (saves as draft). - Created and saved an empty comment with an edit suggestion (saves). - Created and saved an empty comment with a suggestion to entirely delete lines -- that is, no suggestion text (saves). - Edited a comment, saved without changes (save). - Edited a comment, save deleting all text (saves -- note that this is intentionally without undo, since this is a lot of steps to do by accident). - Cancel editing an unchanged comment (cancels without undo). - Cancel editing a changed comment (cancels with undo). - Undo'd, got text back. - Cancel new comment with no text (deletes without undo). - Cancel new comment with text (deletes with undo). - Undo'd, got text back. - Saved a quoted comment with no changes (saves -- note that this is intentionally not a "delete", since just quoting someone seems fine if you click "Save" -- maybe you want to come back to it later). Maniphest Tasks: T13559 Differential Revision: https://secure.phabricator.com/D21654
2021-03-25 13:28:04 -07:00
$inline
->setIsEditing(false)
->setIsDeleted(1);
} else {
$inline->setIsDeleted(0);
}
$this->saveComment($inline);
return $this->buildEmptyResponse();
case 'save':
$inline = $this->loadCommentByIDForEdit($this->getCommentID());
$this->updateCommentContentState($inline);
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
$inline
->setIsEditing(false)
->setIsDeleted(0);
// Since we're saving the comment, update the committed state.
$active_state = $inline->getContentState();
$inline->setCommittedContentState($active_state);
$this->saveComment($inline);
return $this->buildRenderedCommentResponse(
$inline,
$this->getIsOnRight());
case 'edit':
$inline = $this->loadCommentByIDForEdit($this->getCommentID());
// NOTE: At time of writing, the "editing" state of inlines is
// preserved by simulating a click on "Edit" when the inline loads.
// In this case, we don't want to "saveComment()", because it
// recalculates object drafts and purges versioned drafts.
// The recalculation is merely unnecessary (state doesn't change)
// but purging drafts means that loading a page and then closing it
// discards your drafts.
// To avoid the purge, only invoke "saveComment()" if we actually
// have changes to apply.
$is_dirty = false;
if (!$inline->getIsEditing()) {
$inline
->setIsDeleted(0)
->setIsEditing(true);
$is_dirty = true;
}
if ($this->hasContentState()) {
$this->updateCommentContentState($inline);
$is_dirty = true;
} else {
PhabricatorInlineComment::loadAndAttachVersionedDrafts(
$viewer,
array($inline));
}
if ($is_dirty) {
$this->saveComment($inline);
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
}
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
$edit_dialog = $this->buildEditDialog($inline)
->setTitle(pht('Edit Inline Comment'));
$view = $this->buildScaffoldForView($edit_dialog);
return $this->newInlineResponse($inline, $view, true);
case 'cancel':
$inline = $this->loadCommentByIDForEdit($this->getCommentID());
$inline->setIsEditing(false);
// If the user uses "Undo" to get into an edited state ("AB"), then
// clicks cancel to return to the previous state ("A"), we also want
// to set the stored state back to "A".
$this->updateCommentContentState($inline);
$this->saveComment($inline);
return $this->buildEmptyResponse();
case 'draft':
$inline = $this->loadCommentByIDForEdit($this->getCommentID());
$versioned_draft = PhabricatorVersionedDraft::loadOrCreateDraft(
$inline->getPHID(),
$viewer->getPHID(),
$inline->getID());
$map = $this->newRequestContentState($inline)->newStorageMap();
$versioned_draft->setProperty('inline.state', $map);
$versioned_draft->save();
// We have to synchronize the draft engine after saving a versioned
// draft, because taking an inline comment from "no text, no draft"
// to "no text, text in a draft" marks the container object as having
// a draft.
$draft_engine = $this->newDraftEngine();
if ($draft_engine) {
$draft_engine->synchronize();
}
return $this->buildEmptyResponse();
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
case 'new':
case 'reply':
default:
// NOTE: We read the values from the client (the display values), not
// the values from the database (the original values) when replying.
// In particular, when replying to a ghost comment which was moved
// across diffs and then moved backward to the most recent visible
// line, we want to reply on the display line (which exists), not on
// the comment's original line (which may not exist in this changeset).
$is_new = $this->getIsNewFile();
$number = $this->getLineNumber();
$length = $this->getLineLength();
$inline = $this->createComment()
->setChangesetID($this->getChangesetID())
->setAuthorPHID($viewer->getPHID())
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
->setIsNewFile($is_new)
->setLineNumber($number)
->setLineLength($length)
->setReplyToCommentPHID($this->getReplyToCommentPHID())
->setIsEditing(true)
->setStartOffset($request->getInt('startOffset'))
->setEndOffset($request->getInt('endOffset'))
->setContent('');
$document_engine_key = $request->getStr('documentEngineKey');
if ($document_engine_key !== null) {
$inline->setDocumentEngineKey($document_engine_key);
}
// If you own this object, mark your own inlines as "Done" by default.
$owner_phid = $this->loadObjectOwnerPHID($inline);
if ($owner_phid) {
if ($viewer->getPHID() == $owner_phid) {
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
$fixed_state = PhabricatorInlineComment::STATE_DRAFT;
$inline->setFixedState($fixed_state);
}
}
if ($this->hasContentState()) {
$this->updateCommentContentState($inline);
}
// NOTE: We're writing the comment as "deleted", then reloading to
// pick up context and undeleting it. This is silly -- we just want
// to load and attach context -- but just loading context is currently
// complicated (for example, context relies on cache keys that expect
// the inline to have an ID).
$inline->setIsDeleted(1);
$this->saveComment($inline);
// Reload the inline to attach context.
$inline = $this->loadCommentByIDForEdit($inline->getID());
// Now, we can read the source file and set the initial state.
$state = $inline->getContentState();
$default_suggestion = $inline->getDefaultSuggestionText();
$state->setContentSuggestionText($default_suggestion);
$inline->setInitialContentState($state);
$inline->setContentState($state);
$inline->setIsDeleted(0);
$this->saveComment($inline);
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
$edit_dialog = $this->buildEditDialog($inline);
if ($this->getOperation() == 'reply') {
$edit_dialog->setTitle(pht('Reply to Inline Comment'));
} else {
$edit_dialog->setTitle(pht('New Inline Comment'));
}
$view = $this->buildScaffoldForView($edit_dialog);
return $this->newInlineResponse($inline, $view, true);
}
}
private function readRequestParameters() {
$request = $this->getRequest();
// NOTE: This isn't necessarily a DifferentialChangeset ID, just an
// application identifier for the changeset. In Diffusion, it's a Path ID.
$this->changesetID = $request->getInt('changesetID');
$this->isNewFile = (int)$request->getBool('is_new');
$this->isOnRight = $request->getBool('on_right');
$this->lineNumber = $request->getInt('number');
$this->lineLength = $request->getInt('length');
$this->commentID = $request->getInt('id');
$this->operation = $request->getStr('op');
$this->renderer = $request->getStr('renderer');
$this->replyToCommentPHID = $request->getStr('replyToCommentPHID');
if ($this->getReplyToCommentPHID()) {
$reply_phid = $this->getReplyToCommentPHID();
$reply_comment = $this->loadCommentByPHID($reply_phid);
if (!$reply_comment) {
throw new Exception(
pht('Failed to load comment "%s".', $reply_phid));
}
// When replying, force the new comment into the same location as the
// old comment. If we don't do this, replying to a ghost comment from
// diff A while viewing diff B can end up placing the two comments in
// different places while viewing diff C, because the porting algorithm
// makes a different decision. Forcing the comments to bind to the same
// place makes sure they stick together no matter which diff is being
// viewed. See T10562 for discussion.
$this->changesetID = $reply_comment->getChangesetID();
$this->isNewFile = $reply_comment->getIsNewFile();
$this->lineNumber = $reply_comment->getLineNumber();
$this->lineLength = $reply_comment->getLineLength();
}
}
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
private function buildEditDialog(PhabricatorInlineComment $inline) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$edit_dialog = id(new PHUIDiffInlineCommentEditView())
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
->setViewer($viewer)
->setInlineComment($inline)
->setIsOnRight($this->getIsOnRight())
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
->setRenderer($this->getRenderer());
return $edit_dialog;
}
private function buildEmptyResponse() {
return id(new AphrontAjaxResponse())
->setContent(
array(
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
'inline' => array(),
'view' => null,
));
}
private function buildRenderedCommentResponse(
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
PhabricatorInlineComment $inline,
$on_right) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$engine = new PhabricatorMarkupEngine();
$engine->setViewer($viewer);
$engine->addObject(
$inline,
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
PhabricatorInlineComment::MARKUP_FIELD_BODY);
$engine->process();
$phids = array($viewer->getPHID());
$handles = $this->loadViewerHandles($phids);
$object_owner_phid = $this->loadObjectOwnerPHID($inline);
$view = id(new PHUIDiffInlineCommentDetailView())
->setUser($viewer)
->setInlineComment($inline)
->setIsOnRight($on_right)
->setMarkupEngine($engine)
->setHandles($handles)
Track a "Done" state on inline comments Summary: Ref T1460. This just barely works, but throwing it up in case any of it sounds mechanically crazy before we build integrations/UI/etc. Specifically, these are the behaviors: - You can mark your own draft comments as "done" before you submit them. The intent is to let reviewers mark their stuff advisory/minor/not-important before they submit it, to hint to authors that they don't expect the feedback to necessarily be addressed (maybe it's a joke, maybe it's just discussion, maybe it's "consider.."). - You can mark others' published comments as "done" if you're the revision/commit author. The intent is to keep this lightweight by not requiring an audit trail of who marked what done when. If anyone could mark anything done, we'd have to have some way to show who marked stuff. - When you mark stuff done (or unmark it), it goes into a "draft" state, where you see the change but others don't see it yet. The intent is twofold: - Be consistent with how inlines work. - Allow us to publish a "epriestley updated this revision + epriestley marked 15 inlines as done" story later if we want. This seems more useful than publishing 15 "epriestley marked one thing as done" stories. - The actual bit where done-ness publishes isn't implemented. - UI is bare bones. - No integration with the rest of the UI yet. Test Plan: Clicked some checkboxes. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: paulshen, chasemp, epriestley Maniphest Tasks: T1460 Differential Revision: https://secure.phabricator.com/D12033
2015-03-09 18:41:47 -07:00
->setEditable(true)
->setCanMarkDone(false)
->setObjectOwnerPHID($object_owner_phid);
$view = $this->buildScaffoldForView($view);
return $this->newInlineResponse($inline, $view, false);
}
private function buildScaffoldForView(PHUIDiffInlineCommentView $view) {
$renderer = DifferentialChangesetHTMLRenderer::getHTMLRendererByKey(
$this->getRenderer());
$view = $renderer->getRowScaffoldForInline($view);
return id(new PHUIDiffInlineCommentTableScaffold())
->addRowScaffold($view);
}
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
private function newInlineResponse(
PhabricatorInlineComment $inline,
$view,
$is_edit) {
$viewer = $this->getViewer();
if ($inline->getReplyToCommentPHID()) {
$can_suggest = false;
} else {
$can_suggest = (bool)$inline->getInlineContext();
}
if ($is_edit) {
$state = $inline->getContentStateMapForEdit($viewer);
} else {
$state = $inline->getContentStateMap();
}
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
$response = array(
'inline' => array(
'id' => $inline->getID(),
'state' => $state,
'canSuggestEdit' => $can_suggest,
Make "editing" state persistent for inline comments Summary: Ref T13513. This is mostly an infrastructure cleanup change. In a perfect world, this would be a series of several changes, but they're tightly interconnected and don't have an obvious clean, nontrivial partition (or, at least, I don't see one). Followup changes will exercise this code repeatedly and all of these individual mutations are "obviously good", so I'm not too worried about the breadth of this change. --- Inline comments are stored as transaction comments in the `PhabricatorAuditTransactionComment` and `DifferentialTransactionComment` classes. On top of these two storage classes sit `PhabricatorAuditInlineComment` and `DifferentialInlineComment`. Historically, these were an indirection layer over significantly different storage classes, but nowadays both storage classes look pretty similar and most of the logic is actually the same. Prior to this change, these two classes were about 80% copy/pastes of one another. Part of the reason they're so copy/pastey is that they implement a parent `Interface`. They are the only classes which implement this interface, and the interface does not provide any correctness guarantees (the storage objects are not actually constrained by it). To simplify this: - Make `PhabricatorInlineCommentInterface` an abstract base class instead. - Lift as much code out of the `Audit` and `Differential` subclasses as possible. - Delete methods which no longer have callers, or have only trivial callers. --- Inline comments have two `View` rendering classes, `DetailView` and `EditView`. They share very little code. Partly, this is because `EditView` does not take an `$inline` object. Historically, it needed to be able to operate on inlines that did not have an ID yet, and even further back in history this was probably just an outgrowth of a simple `<form />`. These classes can be significantly simplified by passing an `$inline` to the `EditView`, instead of individually setting all the properties on the `View` itself. This allows the `DetailView` and `EditView` classes to share a lot of code. The `EditView` can not fully render its content. Move the content rendering code into the view. --- Prior to this change, some operations need to work on inlines that don't have an inline ID yet (we assign an ID the first time you "Save" a comment). Since "editing" comments will now be saved, we can instead create a row immediately. This means that all the inline code can always rely on having a valid ID to work with, even if that ID corresponds to an empty, draft, "isEditing" comment. This simplifies more code in `EditView` and allows the "create" and "reply" code to be merged in `PhabricatorInlineCommentController`. --- Client-side inline events are currently handled through a mixture of `ChangesetList` listeners (good) and ad-hoc row-level listeners (less good). In particular, the "save", "cancel", and "undo" events are row-level. All other events are list-level. Move all events to list-level. This is supported by all inlines now having an ID at all stages of their lifecycle. This allows some of the client behavior to be simplified. It currently depends on binding complex ad-hoc dictionaries into event handlers in `_drawRows()`, but it seems like almost all of this code can be removed. In fact, no more than one row ever seems to be drawn, so this code can probably be simplified further. --- Finally, save an "isEditing" state. When we rebuild a revision on the client, click the "edit" button if it's in this state. This is a little hacky, but simpler to get into a stable state, since the row layout of an inline depends on a "view row" followed by an "edit row". Test Plan: - Created comments on either side of a diff. - Edited a comment, reloaded, saw edit stick. - Saved comments, reloaded, saw save stick. - Edited a comment, typed text, cancelled, "unedited" to get state back. - Created a comment, typed text, cancelled, "unedited" to get state back. - Deleted a comment, "undeleted" to get state back. Weirdness / known issues: - Drafts don't autosave yet. - Fixed in D21187: - When you create an empty comment then reload, you get an empty editor. This is a bit silly. - "Cancel" does not save state, but should, once drafts autosave. - Mostly fixed in D21188: - "Editing" comments aren't handled specially by the overall submission flow. - "Editing" comments submitted in that state try to edit themselves again on load, which doesn't work. Subscribers: jmeador Maniphest Tasks: T13513 Differential Revision: https://secure.phabricator.com/D21186
2020-04-28 14:45:54 -07:00
),
'view' => hsprintf('%s', $view),
);
return id(new AphrontAjaxResponse())
->setContent($response);
}
final protected function loadCommentByID($id) {
$query = $this->newInlineCommentQuery()
->withIDs(array($id));
return $this->loadCommentByQuery($query);
}
final protected function loadCommentByPHID($phid) {
$query = $this->newInlineCommentQuery()
->withPHIDs(array($phid));
return $this->loadCommentByQuery($query);
}
final protected function loadCommentByIDForEdit($id) {
$viewer = $this->getViewer();
$query = $this->newInlineCommentQuery()
->withIDs(array($id))
->needInlineContext(true);
$inline = $this->loadCommentByQuery($query);
if (!$inline) {
throw new Exception(
pht(
'Unable to load inline "%s".',
$id));
}
if (!$this->canEditInlineComment($viewer, $inline)) {
throw new Exception(
pht(
'Inline comment "%s" is not editable.',
$id));
}
return $inline;
}
private function loadCommentByQuery(
PhabricatorDiffInlineCommentQuery $query) {
$viewer = $this->getViewer();
$inline = $query
->setViewer($viewer)
->executeOne();
if ($inline) {
$inline = $inline->newInlineCommentObject();
}
return $inline;
}
private function hasContentState() {
$request = $this->getRequest();
return (bool)$request->getBool('hasContentState');
}
private function newRequestContentState($inline) {
$request = $this->getRequest();
return $inline->newContentStateFromRequest($request);
}
private function updateCommentContentState(PhabricatorInlineComment $inline) {
if (!$this->hasContentState()) {
throw new Exception(
pht(
'Attempting to update comment content state, but request has no '.
'content state.'));
}
$state = $this->newRequestContentState($inline);
$inline->setContentState($state);
}
private function saveComment(PhabricatorInlineComment $inline) {
$viewer = $this->getViewer();
$draft_engine = $this->newDraftEngine();
$inline->openTransaction();
$inline->save();
PhabricatorVersionedDraft::purgeDrafts(
$inline->getPHID(),
$viewer->getPHID());
if ($draft_engine) {
$draft_engine->synchronize();
}
$inline->saveTransaction();
}
private function newDraftEngine() {
$viewer = $this->getViewer();
$object = $this->getContainerObject();
if (!($object instanceof PhabricatorDraftInterface)) {
return null;
}
return $object->newDraftEngine()
->setObject($object)
->setViewer($viewer);
}
}