Redesign change screen on new REST API
The new screen exists at #/c2/<id> as it is missing a large number of features. The proposal is to include the screen as-is and iterate in tree, similar to the CodeMirror work. This allows power users to start trying the screen out by editing the URL. Missing features: - Add reviewer(s) - Remove reviewer(s) - Edit commit message - Diff files in two patch sets - Dependencies and dependents - Download links by URL and action (cherry-pick, checkout, etc.) Change-Id: Ie957fb85c873d044c947000f0f0207a66f87c784
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.client.change;
|
||||
|
||||
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.ReviewInput;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.common.data.LabelValue;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
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.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.KeyCodes;
|
||||
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||
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.CheckBox;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.RadioButton;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
class ReplyBox extends Composite {
|
||||
interface Binder extends UiBinder<HTMLPanel, ReplyBox> {}
|
||||
private static Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
interface Styles extends CssResource {
|
||||
String label_name();
|
||||
String label_value();
|
||||
}
|
||||
|
||||
private final Change.Id changeId;
|
||||
private final String revision;
|
||||
private ReviewInput in = ReviewInput.create();
|
||||
private List<Runnable> lgtm;
|
||||
|
||||
@UiField Styles style;
|
||||
@UiField NpTextArea message;
|
||||
@UiField Element labelsParent;
|
||||
@UiField Grid labelsTable;
|
||||
@UiField Button send;
|
||||
@UiField CheckBox email;
|
||||
|
||||
ReplyBox(
|
||||
Change.Id changeId,
|
||||
String revision,
|
||||
NativeMap<LabelInfo> all,
|
||||
NativeMap<JsArrayString> permitted) {
|
||||
this.changeId = changeId;
|
||||
this.revision = revision;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
List<String> names = new ArrayList<String>(permitted.keySet());
|
||||
if (names.isEmpty()) {
|
||||
UIObject.setVisible(labelsParent, false);
|
||||
} else {
|
||||
Collections.sort(names);
|
||||
lgtm = new ArrayList<Runnable>(names.size());
|
||||
renderLabels(names, all, permitted);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
message.setFocus(true);
|
||||
}});
|
||||
}
|
||||
|
||||
@UiHandler("message")
|
||||
void onMessageKey(KeyPressEvent event) {
|
||||
if ((event.getCharCode() == '\n' || event.getCharCode() == KeyCodes.KEY_ENTER)
|
||||
&& event.isControlKeyDown()) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onSend(null);
|
||||
} else if (lgtm != null
|
||||
&& event.getCharCode() == 'M'
|
||||
&& message.getValue().equals("LGT")) {
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
if (message.getValue().startsWith("LGTM")) {
|
||||
for (Runnable r : lgtm) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@UiHandler("email")
|
||||
void onEmail(ValueChangeEvent<Boolean> e) {
|
||||
if (e.getValue()) {
|
||||
in.notify(ReviewInput.NotifyHandling.ALL);
|
||||
} else {
|
||||
in.notify(ReviewInput.NotifyHandling.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@UiHandler("send")
|
||||
void onSend(ClickEvent e) {
|
||||
in.message(message.getText().trim());
|
||||
ChangeApi.revision(changeId.get(), revision)
|
||||
.view("review")
|
||||
.post(in, new GerritCallback<ReviewInput>() {
|
||||
@Override
|
||||
public void onSuccess(ReviewInput result) {
|
||||
Gerrit.display(PageLinks.toChange2(changeId));
|
||||
}
|
||||
});
|
||||
hide();
|
||||
}
|
||||
|
||||
private void hide() {
|
||||
for (Widget w = getParent(); w != null; w = w.getParent()) {
|
||||
if (w instanceof PopupPanel) {
|
||||
((PopupPanel) w).hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void renderLabels(
|
||||
List<String> names,
|
||||
NativeMap<LabelInfo> all,
|
||||
NativeMap<JsArrayString> permitted) {
|
||||
TreeSet<Short> values = new TreeSet<Short>();
|
||||
for (String id : names) {
|
||||
JsArrayString p = permitted.get(id);
|
||||
if (p != null) {
|
||||
for (int i = 0; i < p.length(); i++) {
|
||||
values.add(LabelInfo.parseValue(p.get(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Short> columns = new ArrayList<Short>(values);
|
||||
|
||||
labelsTable.resize(1 + permitted.size(), 1 + values.size());
|
||||
for (int c = 0; c < columns.size(); c++) {
|
||||
labelsTable.setText(0, 1 + c, LabelValue.formatValue(columns.get(c)));
|
||||
labelsTable.getCellFormatter().setStyleName(0, 1 + c, style.label_value());
|
||||
}
|
||||
|
||||
List<String> checkboxes = new ArrayList<String>(permitted.size());
|
||||
int row = 1;
|
||||
for (String id : names) {
|
||||
Set<Short> vals = all.get(id).value_set();
|
||||
if (isCheckBox(vals)) {
|
||||
checkboxes.add(id);
|
||||
} else {
|
||||
renderRadio(row++, id, columns, vals, all.get(id));
|
||||
}
|
||||
}
|
||||
for (String id : checkboxes) {
|
||||
renderCheckBox(row++, id, all.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
private void renderRadio(int row, final String id,
|
||||
List<Short> columns,
|
||||
Set<Short> values,
|
||||
LabelInfo info) {
|
||||
labelsTable.setText(row, 0, id);
|
||||
labelsTable.getCellFormatter().setStyleName(row, 0, style.label_name());
|
||||
|
||||
ApprovalInfo self = Gerrit.isSignedIn()
|
||||
? info.for_user(Gerrit.getUserAccount().getId().get())
|
||||
: null;
|
||||
|
||||
final List<RadioButton> group = new ArrayList<RadioButton>(values.size());
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
final Short v = columns.get(i);
|
||||
if (values.contains(v)) {
|
||||
RadioButton b = new RadioButton(id);
|
||||
b.setTitle(info.value_text(LabelValue.formatValue(v)));
|
||||
if ((self != null && v == self.value()) || (self == null && v == 0)) {
|
||||
b.setValue(true);
|
||||
}
|
||||
b.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
if (event.getValue()) {
|
||||
in.label(id, v);
|
||||
}
|
||||
}
|
||||
});
|
||||
group.add(b);
|
||||
labelsTable.setWidget(row, 1 + i, b);
|
||||
}
|
||||
}
|
||||
|
||||
if (!group.isEmpty()) {
|
||||
lgtm.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < group.size() - 1; i++) {
|
||||
group.get(i).setValue(false, false);
|
||||
}
|
||||
group.get(group.size() - 1).setValue(true, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void renderCheckBox(int row, final String id, LabelInfo info) {
|
||||
ApprovalInfo self = Gerrit.isSignedIn()
|
||||
? info.for_user(Gerrit.getUserAccount().getId().get())
|
||||
: null;
|
||||
|
||||
final CheckBox b = new CheckBox();
|
||||
b.setText(id);
|
||||
b.setTitle(info.value_text("+1"));
|
||||
if (self != null && self.value() == 1) {
|
||||
b.setValue(true);
|
||||
}
|
||||
b.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
in.label(id, event.getValue() ? (short) 1 : (short) 0);
|
||||
}
|
||||
});
|
||||
b.setStyleName(style.label_name());
|
||||
labelsTable.setWidget(row, 0, b);
|
||||
|
||||
lgtm.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
b.setValue(true, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isCheckBox(Set<Short> values) {
|
||||
return values.size() == 2
|
||||
&& values.contains((short) 0)
|
||||
&& values.contains((short) 1);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user