/changes/: Use in UI for search

Replace the old JSON-RPC interface with the new long term supported
REST API. Since this is a major change to the types being transported
over the network, make a copy of the UI code until we can replace all
existing uses of the old types in the UI code.

Unlike the old interface, the web UI client now obtains the label
information during the query and avoids a second round trip to lookup
the current approvals for each displayed change. For most users this
should improve the way the page renders. The verified and code review
columns will be populated before the table is made visible, preventing
the layout from "jumping" the way the old UI did when the 2nd RPC
finally finished and supplied the label data.

The columns in the table are drawn to match the requirements of the
submit rules that apply to each change, which makes the UI more
dynamic and does not require knowing in advance all of the valid
labels by way of the ApprovalTypes global state object. This is a nice
step towards getting rid of the hard coded approval_categories table
in the database and making the system reflect per-project rules.

Change-Id: I8d83b83e8b95bf2e6fcdfe04f5835cf97bd843b7
This commit is contained in:
Shawn O. Pearce
2012-04-16 19:08:30 -07:00
parent 090c44c6c3
commit 77199942c5
5 changed files with 595 additions and 36 deletions

View File

@@ -0,0 +1,106 @@
// Copyright (C) 2012 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.changes;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwtjsonrpc.client.impl.ser.JavaSqlTimestamp_JsonSerializer;
import java.sql.Timestamp;
import java.util.Set;
public class ChangeInfo extends JavaScriptObject {
public final Project.NameKey project_name_key() {
return new Project.NameKey(project());
}
public final Change.Id legacy_id() {
return new Change.Id(_number());
}
public final Timestamp updated() {
return JavaSqlTimestamp_JsonSerializer.parseTimestamp(updatedRaw());
}
public final String id_abbreviated() {
return new Change.Key(id()).abbreviate();
}
public final Change.Status status() {
return Change.Status.valueOf(statusRaw());
}
public final Set<String> labels() {
return Natives.keys(labels0());
}
public final native String project() /*-{ return this.project; }-*/;
public final native String branch() /*-{ return this.branch; }-*/;
public final native String topic() /*-{ return this.topic; }-*/;
public final native String id() /*-{ return this.id; }-*/;
private final native String statusRaw() /*-{ return this.status; }-*/;
public final native String subject() /*-{ return this.subject; }-*/;
public final native AccountInfo owner() /*-{ return this.owner; }-*/;
private final native String updatedRaw() /*-{ return this.updated; }-*/;
public final native boolean starred() /*-{ return this.starred ? true : false; }-*/;
public final native String _sortkey() /*-{ return this._sortkey; }-*/;
private final native JavaScriptObject labels0() /*-{ return this.labels; }-*/;
public final native LabelInfo label(String n) /*-{ return this.labels[n]; }-*/;
final native int _number() /*-{ return this._number; }-*/;
final native boolean _more_changes()
/*-{ return this._more_changes ? true : false; }-*/;
protected ChangeInfo() {
}
public static class AccountInfo extends JavaScriptObject {
public final native String name() /*-{ return this.name; }-*/;
protected AccountInfo() {
}
}
public static class LabelInfo extends JavaScriptObject {
public final SubmitRecord.Label.Status status() {
if (approved() != null) {
return SubmitRecord.Label.Status.OK;
} else if (rejected() != null) {
return SubmitRecord.Label.Status.REJECT;
} else {
return SubmitRecord.Label.Status.NEED;
}
}
public final native String name() /*-{ return this._name; }-*/;
public final native AccountInfo approved() /*-{ return this.approved; }-*/;
public final native AccountInfo rejected() /*-{ return this.rejected; }-*/;
public final native AccountInfo recommended() /*-{ return this.recommended; }-*/;
public final native AccountInfo disliked() /*-{ return this.disliked; }-*/;
final native short _value()
/*-{
if (this.value) return this.value;
if (this.recommended) return 1;
if (this.disliked) return -1;
return 0;
}-*/;
protected LabelInfo() {
}
}
}

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2012 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.changes;
import com.google.gerrit.client.rpc.NativeList;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtorm.client.KeyUtil;
/** List of changes available from {@code /changes/}. */
public class ChangeList extends NativeList<ChangeInfo> {
private static final String URI = "/changes/";
public static void prev(String query,
int limit, String sortkey,
AsyncCallback<ChangeList> callback) {
RestApi call = newQuery(query);
if (limit > 0) {
call.addParameter("n", limit);
}
if (!PagedSingleListScreen.MIN_SORTKEY.equals(sortkey)) {
call.addParameter("P", sortkey);
}
call.send(callback);
}
public static void next(String query,
int limit, String sortkey,
AsyncCallback<ChangeList> callback) {
RestApi call = newQuery(query);
if (limit > 0) {
call.addParameter("n", limit);
}
if (!PagedSingleListScreen.MAX_SORTKEY.equals(sortkey)) {
call.addParameter("N", sortkey);
}
call.send(callback);
}
private static RestApi newQuery(String query) {
RestApi call = new RestApi(URI);
// The server default is ?q=status:open so don't repeat it.
if (!"status:open".equals(query) && !"is:open".equals(query)) {
call.addParameterRaw("q", KeyUtil.encode(query));
}
return call;
}
protected ChangeList() {
}
}

View File

@@ -0,0 +1,400 @@
// Copyright (C) 2008 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.changes;
import static com.google.gerrit.client.FormatUtil.shortFormat;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
import com.google.gerrit.client.ui.BranchLink;
import com.google.gerrit.client.ui.ChangeLink;
import com.google.gerrit.client.ui.NavigationTable;
import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
import com.google.gerrit.client.ui.ProjectLink;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineLabel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ChangeTable2 extends NavigationTable<ChangeInfo> {
private static final int C_STAR = 1;
private static final int C_ID = 2;
private static final int C_SUBJECT = 3;
private static final int C_OWNER = 4;
private static final int C_PROJECT = 5;
private static final int C_BRANCH = 6;
private static final int C_LAST_UPDATE = 7;
private static final int BASE_COLUMNS = 8;
private final List<Section> sections;
private int columns;
private List<String> labelNames;
public ChangeTable2() {
columns = BASE_COLUMNS;
labelNames = Collections.emptyList();
keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.changeTablePrev()));
keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.changeTableNext()));
keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.changeTableOpen()));
keysNavigation.add(
new OpenKeyCommand(0, KeyCodes.KEY_ENTER, Util.C.changeTableOpen()));
if (Gerrit.isSignedIn()) {
keysAction.add(new StarKeyCommand(0, 's', Util.C.changeTableStar()));
}
sections = new ArrayList<Section>();
table.setText(0, C_STAR, "");
table.setText(0, C_ID, Util.C.changeTableColumnID());
table.setText(0, C_SUBJECT, Util.C.changeTableColumnSubject());
table.setText(0, C_OWNER, Util.C.changeTableColumnOwner());
table.setText(0, C_PROJECT, Util.C.changeTableColumnProject());
table.setText(0, C_BRANCH, Util.C.changeTableColumnBranch());
table.setText(0, C_LAST_UPDATE, Util.C.changeTableColumnLastUpdate());
final FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.addStyleName(0, C_STAR, Gerrit.RESOURCES.css().iconHeader());
fmt.addStyleName(0, C_ID, Gerrit.RESOURCES.css().cID());
for (int i = C_ID; i < columns; i++) {
fmt.addStyleName(0, i, Gerrit.RESOURCES.css().dataHeader());
}
table.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
final Cell cell = table.getCellForEvent(event);
if (cell == null) {
return;
}
if (cell.getCellIndex() == C_STAR) {
// Don't do anything (handled by star itself).
} else if (cell.getCellIndex() == C_OWNER) {
// Don't do anything.
} else if (getRowItem(cell.getRowIndex()) != null) {
movePointerTo(cell.getRowIndex());
}
}
});
}
@Override
protected Object getRowItemKey(final ChangeInfo item) {
return item.legacy_id();
}
@Override
protected void onOpenRow(final int row) {
final ChangeInfo c = getRowItem(row);
final Change.Id id = c.legacy_id();
Gerrit.display(PageLinks.toChange(id), new ChangeScreen(id));
}
private void insertNoneRow(final int row) {
insertRow(row);
table.setText(row, 0, Util.C.changeTableNone());
final FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.setColSpan(row, 0, columns);
fmt.setStyleName(row, 0, Gerrit.RESOURCES.css().emptySection());
}
private void insertChangeRow(final int row) {
insertRow(row);
applyDataRowStyle(row);
}
@Override
protected void applyDataRowStyle(final int row) {
super.applyDataRowStyle(row);
final CellFormatter fmt = table.getCellFormatter();
fmt.addStyleName(row, C_STAR, Gerrit.RESOURCES.css().iconCell());
for (int i = C_ID; i < columns; i++) {
fmt.addStyleName(row, i, Gerrit.RESOURCES.css().dataCell());
}
fmt.addStyleName(row, C_ID, Gerrit.RESOURCES.css().cID());
fmt.addStyleName(row, C_SUBJECT, Gerrit.RESOURCES.css().cSUBJECT());
fmt.addStyleName(row, C_PROJECT, Gerrit.RESOURCES.css().cPROJECT());
fmt.addStyleName(row, C_BRANCH, Gerrit.RESOURCES.css().cPROJECT());
fmt.addStyleName(row, C_LAST_UPDATE, Gerrit.RESOURCES.css().cLastUpdate());
for (int i = BASE_COLUMNS; i < columns; i++) {
fmt.addStyleName(row, i, Gerrit.RESOURCES.css().cAPPROVAL());
}
}
private void updateTableLayoutForLabels(ChangeList list) {
labelNames = new ArrayList<String>();
for (int i = 0; i < list.size(); i++) {
for (String name : list.get(i).labels()) {
if (!labelNames.contains(name)) {
labelNames.add(name);
}
}
}
Collections.sort(labelNames);
if (BASE_COLUMNS + labelNames.size() < columns) {
int n = columns - (BASE_COLUMNS + labelNames.size());
for (int row = 0; row < table.getRowCount(); row++) {
table.removeCells(row, columns, n);
}
}
columns = BASE_COLUMNS + labelNames.size();
FlexCellFormatter fmt = table.getFlexCellFormatter();
for (int i = 0; i < labelNames.size(); i++) {
String name = labelNames.get(i);
int col = BASE_COLUMNS + i;
StringBuilder abbrev = new StringBuilder();
for (String t : name.split("-")) {
abbrev.append(t.substring(0, 1).toUpperCase());
}
table.setText(0, col, abbrev.toString());
table.getCellFormatter().getElement(0, col).setTitle(name);
fmt.addStyleName(0, col, Gerrit.RESOURCES.css().dataHeader());
}
}
private void populateChangeRow(final int row, final ChangeInfo c) {
if (Gerrit.isSignedIn()) {
table.setWidget(row, C_STAR, StarredChanges.createIcon(
c.legacy_id(),
c.starred()));
}
table.setWidget(row, C_ID, new TableChangeLink(c.id_abbreviated(), c));
String subject = c.subject();
if (subject.length() > 80) {
subject = subject.substring(0, 80);
}
Change.Status status = c.status();
if (status != Change.Status.NEW) {
subject += " (" + Util.toLongString(status) + ")";
}
table.setWidget(row, C_SUBJECT, new TableChangeLink(subject, c));
String owner = "";
if (c.owner() != null && c.owner().name() != null) {
owner = c.owner().name();
}
table.setText(row, C_OWNER, owner);
table.setWidget(
row, C_PROJECT, new ProjectLink(c.project_name_key(), c.status()));
table.setWidget(row, C_BRANCH, new BranchLink(c.project_name_key(), c
.status(), c.branch(), c.topic()));
table.setText(row, C_LAST_UPDATE, shortFormat(c.updated()));
boolean displayName = Gerrit.isSignedIn() && Gerrit.getUserAccount()
.getGeneralPreferences().isShowUsernameInReviewCategory();
CellFormatter fmt = table.getCellFormatter();
for (int idx = 0; idx < labelNames.size(); idx++) {
String name = labelNames.get(idx);
int col = BASE_COLUMNS + idx;
LabelInfo label = c.label(name);
if (label == null) {
table.clearCell(row, col);
continue;
}
String user;
if (label.rejected() != null) {
user = label.rejected().name();
if (displayName && user != null) {
FlowPanel panel = new FlowPanel();
panel.add(new Image(Gerrit.RESOURCES.redNot()));
panel.add(new InlineLabel(user));
table.setWidget(row, col, panel);
} else {
table.setWidget(row, col, new Image(Gerrit.RESOURCES.redNot()));
}
} else if (label.approved() != null) {
user = label.approved().name();
if (displayName && user != null) {
FlowPanel panel = new FlowPanel();
panel.add(new Image(Gerrit.RESOURCES.greenCheck()));
panel.add(new InlineLabel(user));
table.setWidget(row, col, panel);
} else {
table.setWidget(row, col, new Image(Gerrit.RESOURCES.greenCheck()));
}
} else if (label.disliked() != null) {
user = label.disliked().name();
String vstr = String.valueOf(label._value());
if (displayName && user != null) {
vstr = vstr + " " + user;
}
fmt.addStyleName(row, col, Gerrit.RESOURCES.css().negscore());
table.setText(row, col, vstr);
} else if (label.recommended() != null) {
user = label.recommended().name();
String vstr = "+" + label._value();
if (displayName && user != null) {
vstr = vstr + " " + user;
}
fmt.addStyleName(row, col, Gerrit.RESOURCES.css().posscore());
table.setText(row, col, vstr);
} else {
table.clearCell(row, col);
continue;
}
fmt.addStyleName(row, col, Gerrit.RESOURCES.css().singleLine());
if (!displayName && user != null) {
// Some web browsers ignore the embedded newline; some like it;
// so we include a space before the newline to accommodate both.
fmt.getElement(row, col).setTitle(name + " \nby " + user);
}
}
// TODO(sop): Highlight changes I haven't reviewed on my dashboard.
// final Element tr = DOM.getParent(fmt.getElement(row, 0));
// UIObject.setStyleName(tr, Gerrit.RESOURCES.css().needsReview(),
// !haveReview && highlightUnreviewed);
setRowItem(row, c);
}
public void addSection(final Section s) {
assert s.parent == null;
if (s.titleText != null) {
s.titleRow = table.getRowCount();
table.setText(s.titleRow, 0, s.titleText);
final FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.setColSpan(s.titleRow, 0, columns);
fmt.addStyleName(s.titleRow, 0, Gerrit.RESOURCES.css().sectionHeader());
} else {
s.titleRow = -1;
}
s.parent = this;
s.dataBegin = table.getRowCount();
insertNoneRow(s.dataBegin);
sections.add(s);
}
private int insertRow(final int beforeRow) {
for (final Section s : sections) {
if (beforeRow <= s.titleRow) {
s.titleRow++;
}
if (beforeRow < s.dataBegin) {
s.dataBegin++;
}
}
return table.insertRow(beforeRow);
}
private void removeRow(final int row) {
for (final Section s : sections) {
if (row < s.titleRow) {
s.titleRow--;
}
if (row < s.dataBegin) {
s.dataBegin--;
}
}
table.removeRow(row);
}
public class StarKeyCommand extends NeedsSignInKeyCommand {
public StarKeyCommand(int mask, char key, String help) {
super(mask, key, help);
}
@Override
public void onKeyPress(final KeyPressEvent event) {
int row = getCurrentRow();
ChangeInfo c = getRowItem(row);
if (c != null && Gerrit.isSignedIn()) {
((StarredChanges.Icon) table.getWidget(row, C_STAR)).toggleStar();
}
}
}
private final class TableChangeLink extends ChangeLink {
private TableChangeLink(final String text, final ChangeInfo c) {
super(text, c.legacy_id());
}
@Override
public void go() {
movePointerTo(cid);
super.go();
}
}
public static class Section {
ChangeTable2 parent;
String titleText;
int titleRow = -1;
int dataBegin;
int rows;
public void setTitleText(final String text) {
titleText = text;
if (titleRow >= 0) {
parent.table.setText(titleRow, 0, titleText);
}
}
public void display(ChangeList changeList) {
final int sz = changeList != null ? changeList.size() : 0;
final boolean hadData = rows > 0;
if (hadData) {
while (sz < rows) {
parent.removeRow(dataBegin);
rows--;
}
}
if (sz == 0) {
if (hadData) {
parent.insertNoneRow(dataBegin);
}
return;
}
if (!hadData) {
parent.removeRow(dataBegin);
}
parent.updateTableLayoutForLabels(changeList);
while (rows < sz) {
parent.insertChangeRow(dataBegin + rows);
rows++;
}
for (int i = 0; i < sz; i++) {
parent.populateChangeRow(dataBegin + i, changeList.get(i));
}
}
}
}

View File

@@ -15,12 +15,9 @@
package com.google.gerrit.client.changes;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.ChangeTable.ApprovalViewType;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.Hyperlink;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.data.ChangeInfo;
import com.google.gerrit.common.data.SingleListChangeInfo;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.user.client.History;
@@ -28,19 +25,16 @@ import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import java.util.List;
public abstract class PagedSingleListScreen extends Screen {
protected static final String MIN_SORTKEY = "";
protected static final String MAX_SORTKEY = "z";
protected final int pageSize;
private ChangeTable table;
private ChangeTable.Section section;
private ChangeTable2 table;
private ChangeTable2.Section section;
protected Hyperlink prev;
protected Hyperlink next;
protected List<ChangeInfo> changes;
protected ChangeList changes;
protected final String anchorPrefix;
protected boolean useLoadPrev;
@@ -71,7 +65,7 @@ public abstract class PagedSingleListScreen extends Screen {
next = new Hyperlink(Util.C.pagedChangeListNext(), true, "");
next.setVisible(false);
table = new ChangeTable(true) {
table = new ChangeTable2() {
{
keysNavigation.add(new DoLinkCommand(0, 'p', Util.C
.changeTablePagePrev(), prev));
@@ -79,8 +73,7 @@ public abstract class PagedSingleListScreen extends Screen {
.changeTablePageNext(), next));
}
};
section = new ChangeTable.Section(null, ApprovalViewType.STRONGEST, null);
section = new ChangeTable2.Section();
table.addSection(section);
table.setSavePointerId(anchorPrefix);
add(table);
@@ -112,36 +105,33 @@ public abstract class PagedSingleListScreen extends Screen {
protected abstract void loadNext();
protected AsyncCallback<SingleListChangeInfo> loadCallback() {
return new ScreenLoadCallback<SingleListChangeInfo>(this) {
protected AsyncCallback<ChangeList> loadCallback() {
return new ScreenLoadCallback<ChangeList>(this) {
@Override
protected void preDisplay(final SingleListChangeInfo result) {
protected void preDisplay(ChangeList result) {
display(result);
}
};
}
protected void display(final SingleListChangeInfo result) {
changes = result.getChanges();
protected void display(final ChangeList result) {
changes = result;
if (!changes.isEmpty()) {
final ChangeInfo f = changes.get(0);
final ChangeInfo l = changes.get(changes.size() - 1);
prev.setTargetHistoryToken(anchorPrefix + ",p," + f.getSortKey());
next.setTargetHistoryToken(anchorPrefix + ",n," + l.getSortKey());
prev.setTargetHistoryToken(anchorPrefix + ",p," + f._sortkey());
next.setTargetHistoryToken(anchorPrefix + ",n," + l._sortkey());
if (useLoadPrev) {
prev.setVisible(!result.isAtEnd());
prev.setVisible(f._more_changes());
next.setVisible(!MIN_SORTKEY.equals(pos));
} else {
prev.setVisible(!MAX_SORTKEY.equals(pos));
next.setVisible(!result.isAtEnd());
next.setVisible(l._more_changes());
}
}
table.setAccountInfoCache(result.getAccounts());
section.display(result.getChanges());
section.display(result);
table.finishDisplay();
}

View File

@@ -17,13 +17,11 @@ package com.google.gerrit.client.changes;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.ChangeInfo;
import com.google.gerrit.common.data.SingleListChangeInfo;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtorm.client.KeyUtil;
public class QueryScreen extends PagedSingleListScreen implements
ChangeListScreen {
public static QueryScreen forQuery(String query) {
@@ -49,13 +47,15 @@ public class QueryScreen extends PagedSingleListScreen implements
}
@Override
protected AsyncCallback<SingleListChangeInfo> loadCallback() {
return new GerritCallback<SingleListChangeInfo>() {
public final void onSuccess(final SingleListChangeInfo result) {
protected AsyncCallback<ChangeList> loadCallback() {
return new GerritCallback<ChangeList>() {
@Override
public final void onSuccess(ChangeList result) {
if (isAttached()) {
if (result.getChanges().size() == 1 && isSingleQuery(query)) {
final ChangeInfo c = result.getChanges().get(0);
Gerrit.display(PageLinks.toChange(c), new ChangeScreen(c));
if (result.size() == 1 && isSingleQuery(query)) {
ChangeInfo c = result.get(0);
Change.Id id = c.legacy_id();
Gerrit.display(PageLinks.toChange(id), new ChangeScreen(id));
} else {
Gerrit.setQueryString(query);
display(result);
@@ -68,12 +68,12 @@ public class QueryScreen extends PagedSingleListScreen implements
@Override
protected void loadPrev() {
Util.LIST_SVC.allQueryPrev(query, pos, pageSize, loadCallback());
ChangeList.prev(query, pageSize, pos, loadCallback());
}
@Override
protected void loadNext() {
Util.LIST_SVC.allQueryNext(query, pos, pageSize, loadCallback());
ChangeList.next(query, pageSize, pos, loadCallback());
}
private static boolean isSingleQuery(String query) {