Add reply button to each cover message comment
Reply button in cover message comment would allow to reply onto a specific comment. When pressed a new cover message comment would be created with the master cover message copied and '>' prefixes inserted. Feature: issue 592 Change-Id: I7ae221d8de09f2b643e3564ffddb03a9a2ceadf6
This commit is contained in:

committed by
Shawn Pearce

parent
08c3cd446d
commit
57d0f41ef9
@@ -417,7 +417,7 @@ public class ChangeScreen2 extends Screen {
|
||||
|
||||
private void onReply() {
|
||||
if (Gerrit.isSignedIn()) {
|
||||
replyAction.onReply();
|
||||
replyAction.onReply(null);
|
||||
} else {
|
||||
Gerrit.doSignIn(getToken());
|
||||
}
|
||||
@@ -673,7 +673,6 @@ public class ChangeScreen2 extends Screen {
|
||||
related.set(info, revision);
|
||||
reviewers.set(info);
|
||||
quickApprove.set(info, revision);
|
||||
history.set(commentLinkProcessor, changeId, info);
|
||||
|
||||
if (Gerrit.isSignedIn()) {
|
||||
initEditMessageAction(info, revision);
|
||||
@@ -687,6 +686,8 @@ public class ChangeScreen2 extends Screen {
|
||||
});
|
||||
}
|
||||
}
|
||||
history.set(commentLinkProcessor, replyAction, changeId, info);
|
||||
|
||||
if (current) {
|
||||
loadMergeable(info.status(), canSubmit);
|
||||
}
|
||||
|
@@ -40,14 +40,17 @@ import java.util.Set;
|
||||
|
||||
class History extends FlowPanel {
|
||||
private CommentLinkProcessor clp;
|
||||
private ReplyAction replyAction;
|
||||
private Change.Id changeId;
|
||||
|
||||
private final Set<Integer> loaded = new HashSet<Integer>();
|
||||
private final Map<AuthorRevision, List<CommentInfo>> byAuthor =
|
||||
new HashMap<AuthorRevision, List<CommentInfo>>();
|
||||
|
||||
void set(CommentLinkProcessor clp, Change.Id id, ChangeInfo info) {
|
||||
void set(CommentLinkProcessor clp, ReplyAction ra,
|
||||
Change.Id id, ChangeInfo info) {
|
||||
this.clp = clp;
|
||||
this.replyAction = ra;
|
||||
this.changeId = id;
|
||||
|
||||
JsArray<MessageInfo> messages = info.messages();
|
||||
@@ -70,6 +73,10 @@ class History extends FlowPanel {
|
||||
return changeId;
|
||||
}
|
||||
|
||||
void replyTo(MessageInfo info) {
|
||||
replyAction.onReply(info);
|
||||
}
|
||||
|
||||
void addComments(int id, NativeMap<JsArray<CommentInfo>> map) {
|
||||
loaded.add(id);
|
||||
|
||||
|
@@ -25,11 +25,14 @@ import com.google.gerrit.reviewdb.client.Patch;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.Style.Visibility;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
@@ -55,6 +58,7 @@ class Message extends Composite {
|
||||
@UiField Element name;
|
||||
@UiField Element summary;
|
||||
@UiField Element date;
|
||||
@UiField Button reply;
|
||||
@UiField Element message;
|
||||
@UiField FlowPanel comments;
|
||||
|
||||
@@ -91,6 +95,19 @@ class Message extends Composite {
|
||||
summary.setInnerText(msg);
|
||||
message.setInnerSafeHtml(history.getCommentLinkProcessor()
|
||||
.apply(new SafeHtmlBuilder().append(msg).wikify()));
|
||||
} else {
|
||||
reply.getElement().getStyle().setVisibility(Visibility.HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
@UiHandler("reply")
|
||||
void onReply(ClickEvent e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (Gerrit.isSignedIn()) {
|
||||
history.replyTo(info);
|
||||
} else {
|
||||
Gerrit.doSignIn(com.google.gwt.user.client.History.getToken());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -66,7 +66,7 @@ limitations under the License.
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 120px;
|
||||
width: 915px;
|
||||
width: 880px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -76,7 +76,25 @@ limitations under the License.
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 5px;
|
||||
right: 18px;
|
||||
}
|
||||
|
||||
.reply {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 1px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
border: none;
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 15px;
|
||||
font-family: Arial Unicode MS, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
.closed .reply {
|
||||
visibility: HIDDEN;
|
||||
}
|
||||
</ui:style>
|
||||
|
||||
@@ -89,6 +107,12 @@ limitations under the License.
|
||||
<div class='{style.name}' ui:field='name'/>
|
||||
<div ui:field='summary' class='{style.summary}'/>
|
||||
<div class='{style.date}' ui:field='date'/>
|
||||
<g:Button styleName='{style.reply}'
|
||||
ui:field='reply'
|
||||
title='Reply to this message'>
|
||||
<ui:attribute name='title'/>
|
||||
<div>↩</div>
|
||||
</g:Button>
|
||||
</g:HTMLPanel>
|
||||
<div ui:field='message'
|
||||
aria-hidden='true'
|
||||
|
@@ -16,6 +16,7 @@ package com.google.gerrit.client.change;
|
||||
|
||||
import com.google.gerrit.client.changes.ChangeInfo;
|
||||
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.JsArrayString;
|
||||
@@ -57,7 +58,7 @@ class ReplyAction {
|
||||
: NativeMap.<JsArrayString> create();
|
||||
}
|
||||
|
||||
void onReply() {
|
||||
void onReply(MessageInfo msg) {
|
||||
if (popup != null) {
|
||||
popup.hide();
|
||||
return;
|
||||
@@ -72,6 +73,9 @@ class ReplyAction {
|
||||
allLabels = null;
|
||||
permittedLabels = null;
|
||||
}
|
||||
if (msg != null) {
|
||||
replyBox.replyTo(msg);
|
||||
}
|
||||
|
||||
final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
|
||||
p.setStyleName(style.replyBox());
|
||||
|
@@ -18,6 +18,7 @@ import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.changes.ChangeApi;
|
||||
import com.google.gerrit.client.changes.ChangeInfo.ApprovalInfo;
|
||||
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
|
||||
import com.google.gerrit.client.changes.ReviewInput;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
@@ -27,6 +28,7 @@ import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.JsArrayString;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
@@ -38,6 +40,7 @@ import com.google.gwt.resources.client.CssResource;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
@@ -102,8 +105,18 @@ class ReplyBox extends Composite {
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
Window.scrollTo(0, 0);
|
||||
message.setFocus(true);
|
||||
}});
|
||||
Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
|
||||
@Override
|
||||
public boolean execute() {
|
||||
String t = message.getText();
|
||||
if (t != null) {
|
||||
message.setCursorPos(t.length());
|
||||
}
|
||||
return false;
|
||||
}}, 0);
|
||||
}
|
||||
|
||||
@UiHandler("message")
|
||||
@@ -155,6 +168,34 @@ class ReplyBox extends Composite {
|
||||
hide();
|
||||
}
|
||||
|
||||
void replyTo(MessageInfo msg) {
|
||||
if (msg.message() != null) {
|
||||
String t = message.getText();
|
||||
String m = quote(msg);
|
||||
if (t == null || t.isEmpty()) {
|
||||
t = m;
|
||||
} else if (t.endsWith("\n\n")) {
|
||||
t += m;
|
||||
} else if (t.endsWith("\n")) {
|
||||
t += "\n" + m;
|
||||
} else {
|
||||
t += "\n\n" + m;
|
||||
}
|
||||
message.setText(t + "\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static String quote(MessageInfo msg) {
|
||||
String m = msg.message().trim();
|
||||
if (m.startsWith("Patch Set ")) {
|
||||
int i = m.indexOf('\n');
|
||||
if (i > 0) {
|
||||
m = m.substring(i + 1).trim();
|
||||
}
|
||||
}
|
||||
return "> " + m.replaceAll("\\n", "\\\n> ");
|
||||
}
|
||||
|
||||
private void hide() {
|
||||
for (Widget w = getParent(); w != null; w = w.getParent()) {
|
||||
if (w instanceof PopupPanel) {
|
||||
|
Reference in New Issue
Block a user