Add canned per-line comment reply of 'Done'
The inline comment panels now have a canned reply button labeled "Reply 'Done'" to automatically write the comment and save it as a draft message. This change covers only the original feature request in issue 405, for just this button, to save a lot of keystrokes when typing out a very common reply for some Google engineers. An additional comment requested configurable per-user and per-project canned replies, in a lot more contexts than just the per-line case. This is a bit more to implement because we need to have a way to store the canned reply list, and to edit it. Bug: issue 405 Change-Id: If67ab6f71eaf30cd23a9cd67b5914ec63dbecdfc Signed-off-by: Shawn O. Pearce <sop@google.com> Reviewed-by: Nico Sallembien <nsallembien@google.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import com.google.gerrit.client.Gerrit;
|
|||||||
import com.google.gerrit.client.changes.PatchTable;
|
import com.google.gerrit.client.changes.PatchTable;
|
||||||
import com.google.gerrit.client.changes.PublishCommentScreen;
|
import com.google.gerrit.client.changes.PublishCommentScreen;
|
||||||
import com.google.gerrit.client.changes.Util;
|
import com.google.gerrit.client.changes.Util;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
import com.google.gerrit.client.ui.CommentPanel;
|
import com.google.gerrit.client.ui.CommentPanel;
|
||||||
import com.google.gerrit.client.ui.NavigationTable;
|
import com.google.gerrit.client.ui.NavigationTable;
|
||||||
import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
|
import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
|
||||||
@@ -319,76 +320,8 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
|
|||||||
*/
|
*/
|
||||||
protected void createCommentEditor(final int suggestRow, final int column,
|
protected void createCommentEditor(final int suggestRow, final int column,
|
||||||
final int line, final short file) {
|
final int line, final short file) {
|
||||||
createCommentEditor(suggestRow, column, line, file, null /* no parent */);
|
if (Gerrit.isSignedIn()) {
|
||||||
}
|
if (1 <= line) {
|
||||||
|
|
||||||
protected void createReplyEditor(final PublishedCommentPanel currentPanel) {
|
|
||||||
final int row = rowOf(currentPanel.getElement());
|
|
||||||
if (row >= 0) {
|
|
||||||
final int column = columnOf(currentPanel.getElement());
|
|
||||||
final PatchLineComment c = currentPanel.comment;
|
|
||||||
final String uuid = c.getKey().get();
|
|
||||||
final PatchSet.Id psId = c.getKey().getParentKey().getParentKey();
|
|
||||||
final short file;
|
|
||||||
if (idSideA == null) {
|
|
||||||
file = c.getSide();
|
|
||||||
} else if (idSideB.equals(psId)) {
|
|
||||||
file = 1;
|
|
||||||
} else {
|
|
||||||
file = 0;
|
|
||||||
}
|
|
||||||
createCommentEditor(row, column, c.getLine(), file, uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createCommentEditor(final int suggestRow, final int column,
|
|
||||||
final int line, final short file, final String parentUuid) {
|
|
||||||
if (line < 1) {
|
|
||||||
// Refuse to create an editor before the start of the file.
|
|
||||||
//
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int row = suggestRow;
|
|
||||||
if (parentUuid != null) {
|
|
||||||
row++;
|
|
||||||
} else {
|
|
||||||
int spans[] = new int[column + 1];
|
|
||||||
OUTER: while (row < table.getRowCount()) {
|
|
||||||
int col = 0;
|
|
||||||
for (int cell = 0; row < table.getRowCount()
|
|
||||||
&& cell < table.getCellCount(row); cell++) {
|
|
||||||
while (col < column && 0 < spans[col]) {
|
|
||||||
spans[col++]--;
|
|
||||||
}
|
|
||||||
spans[col] = table.getFlexCellFormatter().getRowSpan(row, cell);
|
|
||||||
if (col == column) {
|
|
||||||
final Widget w = table.getWidget(row, cell);
|
|
||||||
if (w instanceof CommentEditorPanel) {
|
|
||||||
break OUTER;
|
|
||||||
} else if (w instanceof CommentPanel) {
|
|
||||||
row++;
|
|
||||||
} else {
|
|
||||||
break OUTER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (row < table.getRowCount() && column < table.getCellCount(row)
|
|
||||||
&& table.getWidget(row, column) instanceof CommentEditorPanel) {
|
|
||||||
// Don't insert two editors on the same position, it doesn't make
|
|
||||||
// any sense to the user.
|
|
||||||
//
|
|
||||||
((CommentEditorPanel) table.getWidget(row, column)).setFocus(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Gerrit.isSignedIn()) {
|
|
||||||
Gerrit.doSignIn(History.getToken());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Patch.Key parentKey;
|
final Patch.Key parentKey;
|
||||||
final short side;
|
final short side;
|
||||||
switch (file) {
|
switch (file) {
|
||||||
@@ -410,11 +343,57 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
|
|||||||
}
|
}
|
||||||
|
|
||||||
final PatchLineComment newComment =
|
final PatchLineComment newComment =
|
||||||
new PatchLineComment(new PatchLineComment.Key(parentKey, null), line,
|
new PatchLineComment(new PatchLineComment.Key(parentKey, null),
|
||||||
Gerrit.getUserAccount().getId(), parentUuid);
|
line, Gerrit.getUserAccount().getId(), null);
|
||||||
newComment.setSide(side);
|
newComment.setSide(side);
|
||||||
newComment.setMessage("");
|
newComment.setMessage("");
|
||||||
|
|
||||||
|
createCommentEditor(suggestRow, column, newComment).setFocus(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Gerrit.doSignIn(History.getToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommentEditorPanel createCommentEditor(final int suggestRow,
|
||||||
|
final int column, final PatchLineComment newComment) {
|
||||||
|
int row = suggestRow;
|
||||||
|
int spans[] = new int[column + 1];
|
||||||
|
FIND_ROW: while (row < table.getRowCount()) {
|
||||||
|
int col = 0;
|
||||||
|
for (int cell = 0; row < table.getRowCount()
|
||||||
|
&& cell < table.getCellCount(row); cell++) {
|
||||||
|
while (col < column && 0 < spans[col]) {
|
||||||
|
spans[col++]--;
|
||||||
|
}
|
||||||
|
spans[col] = table.getFlexCellFormatter().getRowSpan(row, cell);
|
||||||
|
if (col == column) {
|
||||||
|
final Widget w = table.getWidget(row, cell);
|
||||||
|
if (w instanceof CommentEditorPanel) {
|
||||||
|
// Don't insert two editors on the same position, it doesn't make
|
||||||
|
// any sense to the user.
|
||||||
|
//
|
||||||
|
return ((CommentEditorPanel) w);
|
||||||
|
|
||||||
|
} else if (w instanceof CommentPanel) {
|
||||||
|
if (newComment != null && newComment.getParentUuid() != null) {
|
||||||
|
// If we are a reply, we were given the exact row to insert
|
||||||
|
// ourselves at. We should be before this panel so break.
|
||||||
|
//
|
||||||
|
break FIND_ROW;
|
||||||
|
}
|
||||||
|
row++;
|
||||||
|
} else {
|
||||||
|
break FIND_ROW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newComment == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final CommentEditorPanel ed = new CommentEditorPanel(newComment);
|
final CommentEditorPanel ed = new CommentEditorPanel(newComment);
|
||||||
boolean isCommentRow = false;
|
boolean isCommentRow = false;
|
||||||
boolean needInsert = false;
|
boolean needInsert = false;
|
||||||
@@ -467,7 +446,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ed.setFocus(true);
|
return ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void insertRow(final int row) {
|
protected void insertRow(final int row) {
|
||||||
@@ -691,19 +670,92 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
|
|||||||
private class PublishedCommentPanel extends CommentPanel implements
|
private class PublishedCommentPanel extends CommentPanel implements
|
||||||
ClickHandler {
|
ClickHandler {
|
||||||
final PatchLineComment comment;
|
final PatchLineComment comment;
|
||||||
|
final Button reply;
|
||||||
|
final Button replyDone;
|
||||||
|
|
||||||
PublishedCommentPanel(final AccountInfo author, final PatchLineComment c) {
|
PublishedCommentPanel(final AccountInfo author, final PatchLineComment c) {
|
||||||
super(author, c.getWrittenOn(), c.getMessage());
|
super(author, c.getWrittenOn(), c.getMessage());
|
||||||
this.comment = c;
|
this.comment = c;
|
||||||
|
|
||||||
final Button reply = new Button(PatchUtil.C.buttonReply());
|
reply = new Button(PatchUtil.C.buttonReply());
|
||||||
reply.addClickHandler(this);
|
reply.addClickHandler(this);
|
||||||
getButtonPanel().add(reply);
|
getButtonPanel().add(reply);
|
||||||
|
|
||||||
|
replyDone = new Button(PatchUtil.C.buttonReplyDone());
|
||||||
|
replyDone.addClickHandler(this);
|
||||||
|
getButtonPanel().add(replyDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final ClickEvent event) {
|
public void onClick(final ClickEvent event) {
|
||||||
createReplyEditor(this);
|
if (Gerrit.isSignedIn()) {
|
||||||
|
if (reply == event.getSource()) {
|
||||||
|
createReplyEditor();
|
||||||
|
} else if (replyDone == event.getSource()) {
|
||||||
|
cannedReply(PatchUtil.C.cannedReplyDone());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Gerrit.doSignIn(History.getToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createReplyEditor() {
|
||||||
|
final PatchLineComment newComment = newComment();
|
||||||
|
newComment.setMessage("");
|
||||||
|
createEditor(newComment).setFocus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cannedReply(String message) {
|
||||||
|
CommentEditorPanel p = createEditor(null);
|
||||||
|
if (p == null) {
|
||||||
|
final PatchLineComment newComment = newComment();
|
||||||
|
newComment.setMessage(message);
|
||||||
|
|
||||||
|
enable(false);
|
||||||
|
PatchUtil.DETAIL_SVC.saveDraft(newComment,
|
||||||
|
new GerritCallback<PatchLineComment>() {
|
||||||
|
public void onSuccess(final PatchLineComment result) {
|
||||||
|
enable(true);
|
||||||
|
notifyDraftDelta(1);
|
||||||
|
createEditor(result).setOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
enable(true);
|
||||||
|
super.onFailure(caught);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!p.isOpen()) {
|
||||||
|
p.setOpen(true);
|
||||||
|
}
|
||||||
|
p.setFocus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommentEditorPanel createEditor(final PatchLineComment newComment) {
|
||||||
|
int row = rowOf(getElement());
|
||||||
|
int column = columnOf(getElement());
|
||||||
|
return createCommentEditor(row + 1, column, newComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PatchLineComment newComment() {
|
||||||
|
PatchLineComment newComment =
|
||||||
|
new PatchLineComment(new PatchLineComment.Key(comment.getKey()
|
||||||
|
.getParentKey(), null), comment.getLine(), Gerrit
|
||||||
|
.getUserAccount().getId(), comment.getKey().get());
|
||||||
|
newComment.setSide(comment.getSide());
|
||||||
|
return newComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enable(boolean on) {
|
||||||
|
for (Widget w : getButtonPanel()) {
|
||||||
|
if (w instanceof Button) {
|
||||||
|
((Button) w).setEnabled(on);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,4 +61,7 @@ public interface PatchConstants extends Constants {
|
|||||||
|
|
||||||
String reviewed();
|
String reviewed();
|
||||||
String download();
|
String download();
|
||||||
|
|
||||||
|
String buttonReplyDone();
|
||||||
|
String cannedReplyDone();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
draft = (Draft)
|
draft = (Draft)
|
||||||
|
|
||||||
buttonReply = Reply
|
buttonReply = Reply ...
|
||||||
|
buttonReplyDone = Reply 'Done'
|
||||||
|
cannedReplyDone = Done
|
||||||
buttonEdit = Edit
|
buttonEdit = Edit
|
||||||
buttonSave = Save
|
buttonSave = Save
|
||||||
buttonCancel = Cancel
|
buttonCancel = Cancel
|
||||||
|
|||||||
Reference in New Issue
Block a user