Merge changes from topic 'cm4'
* changes:
SideBySide2: Highlight search results on scrollbar
SideBySide2: Fix wrong mode selection after JS loading
Dynamically load CodeMirror themes
Simplify CodeMirror build by splitting out addons
Fallback language detection with meta.js extensions
Use CodeMirror meta.js to describe modes
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index f5c113f..11e4831 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -7,6 +7,44 @@
[[account-endpoints]]
== Account Endpoints
+[[suggest-account]]
+=== Suggest Account
+--
+'GET /accounts/'
+--
+
+Suggest users for a given query `q` and result limit `n`. If result
+limit is not passed, then the default 10 is used. Returns a list of
+matching link:#account-info[AccountInfo] entities.
+
+.Request
+----
+ GET /accounts/?q=John HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ [
+ {
+ "_account_id": 1000096,
+ "name": "John Doe",
+ "email": "john.doe@example.com",
+ "username": "john"
+ },
+ {
+ "_account_id": 1001439,
+ "name": "John Smith",
+ "email": "john.smith@example.com",
+ "username": "jsmith"
+ },
+ ]
+----
+
[[get-account]]
=== Get Account
--
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 47d074f..4afe4f7 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -293,7 +293,9 @@
[[web-links]]
--
-* `WEB_LINKS`: include the `web_links` field.
+* `WEB_LINKS`: include the `web_links` field in link:#commit-info[CommitInfo],
+ therefore only valid in combination with `CURRENT_COMMIT` or
+ `ALL_COMMITS`.
--
[[check]]
@@ -1807,6 +1809,8 @@
}
----
+Adding query parameter `links` (for example `/changes/.../commit?links`)
+returns a link:#commit-info[CommitInfo] with the additional field `web_links`.
[[get-review]]
=== Get Review
@@ -3387,6 +3391,7 @@
|===========================
|Field Name ||Description
|`change_id` |optional|The Change-Id of the change.
+|`status` |optional|The status of the change.
|`commit` ||The commit as a
link:#commit-info[CommitInfo] entity.
|`_change_number` |optional|The change number.
@@ -3529,6 +3534,9 @@
|`subject` |
The subject of the commit (header line of the commit message).
|`message` |The commit message.
+|`web_links` |optional|
+Links to the commit in external sites as a list of
+link:#web-link-info[WebLinkInfo] entities.
|==========================
[[diff-content]]
@@ -3914,10 +3922,6 @@
|`reviewed` |optional|
Indicates whether the caller is authenticated and has commented on the
current revision. Only set if link:#reviewed[REVIEWED] option is requested.
-|`web_links` |optional|
-Links to the patch set in external sites as a list of
-link:#web-link-info[WebLinkInfo] entities. Only set if
-link:#web-links[WEB_LINKS] option is requested.
|===========================
[[rule-input]]
diff --git a/Documentation/user-review-ui.txt b/Documentation/user-review-ui.txt
index 0cea546..d303703 100644
--- a/Documentation/user-review-ui.txt
+++ b/Documentation/user-review-ui.txt
@@ -538,7 +538,7 @@
note that following the link to an indirect descendant change may
result in a completely different related changes listing.
-** [[closed-ancestor]]Black Dot:
+** [[merged-ancestor]]Black Dot:
+
Indicates a merged ancestor, e.g. the commit was directly pushed into
the repository bypassing code review, or the ancestor change was
@@ -547,6 +547,10 @@
the commit was done on `branch-a`, but was then pushed to
`refs/for/branch-b`.
+** [[abandoned-change]]Dark Red Dot:
++
+Indicates an abandoned change.
+
+
image::images/user-review-ui-change-screen-related-changes-indicators.png[width=800, link="images/user-review-ui-change-screen-related-changes-indicators.png"]
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java
index d05dfc2..7b25a23 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java
@@ -14,7 +14,6 @@
package com.google.gerrit.common.data;
-import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -25,34 +24,6 @@
@RpcImpl(version = Version.V2_0)
public interface SuggestService extends RemoteJsonService {
- void suggestAccount(String query, Boolean enabled, int limit,
- AsyncCallback<List<AccountInfo>> callback);
-
- /**
- * @see #suggestAccountGroupForProject(com.google.gerrit.reviewdb.client.Project.NameKey, String, int, AsyncCallback)
- */
- @Deprecated
- void suggestAccountGroup(String query, int limit,
- AsyncCallback<List<GroupReference>> callback);
-
void suggestAccountGroupForProject(Project.NameKey project, String query,
int limit, AsyncCallback<List<GroupReference>> callback);
-
- /**
- * @see #suggestChangeReviewer(com.google.gerrit.reviewdb.client.Change.Id, String, int, AsyncCallback)
- */
- @Deprecated
- void suggestReviewer(Project.NameKey project, String query, int limit,
- AsyncCallback<List<ReviewerInfo>> callback);
-
- /**
- * Suggests reviewers. A reviewer can be a user or a group. Inactive users,
- * the system groups {@code SystemGroupBackend#ANONYMOUS_USERS} and
- * {@code SystemGroupBackend#REGISTERED_USERS} and groups that have more than
- * the configured {@code addReviewer.maxAllowed} members are not suggested as
- * reviewers.
- * @param changeId the change for which reviewers should be suggested
- */
- void suggestChangeReviewer(Change.Id changeId, String query, int limit,
- AsyncCallback<List<ReviewerInfo>> callback);
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommitInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommitInfo.java
index 7313ab3..a4e4071 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommitInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommitInfo.java
@@ -23,4 +23,5 @@
public GitPerson committer;
public String subject;
public String message;
+ public List<WebLinkInfo> webLinks;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
index 471d519..cbb967c 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
@@ -14,7 +14,6 @@
package com.google.gerrit.extensions.common;
-import java.util.List;
import java.util.Map;
public class RevisionInfo {
@@ -27,5 +26,4 @@
public CommitInfo commit;
public Map<String, FileInfo> files;
public Map<String, ActionInfo> actions;
- public List<WebLinkInfo> webLinks;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
index f86e1fe..d5805ef 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
@@ -16,6 +16,7 @@
import com.google.gerrit.client.changes.QueryScreen;
import com.google.gerrit.client.ui.HintTextBox;
+import com.google.gerrit.client.ui.RemoteSuggestOracle;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -54,8 +55,9 @@
}
});
- final SuggestBox suggestBox =
- new SuggestBox(new SearchSuggestOracle(), searchBox, suggestionDisplay);
+ final SuggestBox suggestBox = new SuggestBox(
+ new RemoteSuggestOracle(new SearchSuggestOracle()),
+ searchBox, suggestionDisplay);
searchBox.setStyleName("gwt-TextBox");
searchBox.setVisibleLength(70);
searchBox.setHintText(Gerrit.C.searchHint());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
index 8906da4..59d65f6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
@@ -33,6 +33,15 @@
return new RestApi("/accounts/").view("self");
}
+ public static void suggest(String query, int limit,
+ AsyncCallback<JsArray<AccountInfo>> cb) {
+ new RestApi("/accounts/")
+ .addParameter("q", query)
+ .addParameter("n", limit)
+ .background()
+ .get(cb);
+ }
+
public static void putDiffPreferences(DiffPreferences in,
AsyncCallback<DiffPreferences> cb) {
self().view("preferences.diff").put(in, cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
index 20c0c38..a8bf3e5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
@@ -20,6 +20,7 @@
import com.google.gerrit.client.ui.HintTextBox;
import com.google.gerrit.client.ui.ProjectListPopup;
import com.google.gerrit.client.ui.ProjectNameSuggestOracle;
+import com.google.gerrit.client.ui.RemoteSuggestBox;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.AccountProjectWatchInfo;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -34,21 +35,16 @@
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.SuggestBox;
-import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
-import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import java.util.List;
public class MyWatchedProjectsScreen extends SettingsScreen {
private Button addNew;
- private HintTextBox nameBox;
- private SuggestBox nameTxt;
+ private RemoteSuggestBox nameBox;
private HintTextBox filterTxt;
private MyWatchesTable watchesTab;
private Button browse;
private Button delSel;
- private boolean submitOnSelection;
private Grid grid;
private ProjectListPopup projectsPopup;
@@ -62,7 +58,7 @@
grid.setStyleName(Gerrit.RESOURCES.css().infoBlock());
grid.setText(0, 0, Util.C.watchedProjectName());
final HorizontalPanel hp = new HorizontalPanel();
- hp.add(nameTxt);
+ hp.add(nameBox);
hp.add(browse);
grid.setWidget(0, 1, hp);
@@ -108,32 +104,13 @@
}
protected void createWidgets() {
- nameBox = new HintTextBox();
- nameTxt = new SuggestBox(new ProjectNameSuggestOracle(), nameBox);
+ nameBox = new RemoteSuggestBox(new ProjectNameSuggestOracle());
nameBox.setVisibleLength(50);
nameBox.setHintText(Util.C.defaultProjectName());
- nameBox.addKeyPressHandler(new KeyPressHandler() {
+ nameBox.addSelectionHandler(new SelectionHandler<String>() {
@Override
- public void onKeyPress(KeyPressEvent event) {
- submitOnSelection = false;
-
- if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
- if (((DefaultSuggestionDisplay) nameTxt.getSuggestionDisplay())
- .isSuggestionListShowing()) {
- submitOnSelection = true;
- } else {
- doAddNew();
- }
- }
- }
- });
- nameTxt.addSelectionHandler(new SelectionHandler<Suggestion>() {
- @Override
- public void onSelection(SelectionEvent<Suggestion> event) {
- if (submitOnSelection) {
- submitOnSelection = false;
- doAddNew();
- }
+ public void onSelection(SelectionEvent<String> event) {
+ doAddNew();
}
});
@@ -196,7 +173,7 @@
}
protected void doAddNew() {
- final String projectName = nameTxt.getText().trim();
+ final String projectName = nameBox.getText().trim();
if ("".equals(projectName)) {
return;
}
@@ -219,7 +196,7 @@
nameBox.setEnabled(true);
filterTxt.setEnabled(true);
- nameTxt.setText("");
+ nameBox.setText("");
watchesTab.insertWatch(result);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
index f6c0002..cd72686 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
@@ -21,14 +21,13 @@
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.AccountGroupSuggestOracle;
import com.google.gerrit.client.ui.OnEditEnabler;
-import com.google.gerrit.client.ui.RPCSuggestOracle;
+import com.google.gerrit.client.ui.RemoteSuggestBox;
import com.google.gerrit.client.ui.SmallHeading;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.clippy.client.CopyableLabel;
import com.google.gwtexpui.globalkey.client.NpTextArea;
@@ -40,8 +39,7 @@
private NpTextBox groupNameTxt;
private Button saveName;
- private NpTextBox ownerTxtBox;
- private SuggestBox ownerTxt;
+ private RemoteSuggestBox ownerTxt;
private Button saveOwner;
private NpTextArea descTxt;
@@ -66,7 +64,7 @@
private void enableForm(final boolean canModify) {
groupNameTxt.setEnabled(canModify);
- ownerTxtBox.setEnabled(canModify);
+ ownerTxt.setEnabled(canModify);
descTxt.setEnabled(canModify);
visibleToAllCheckBox.setEnabled(canModify);
}
@@ -117,12 +115,10 @@
ownerPanel.setStyleName(Gerrit.RESOURCES.css().groupOwnerPanel());
ownerPanel.add(new SmallHeading(Util.C.headingOwner()));
- ownerTxtBox = new NpTextBox();
- ownerTxtBox.setVisibleLength(60);
final AccountGroupSuggestOracle accountGroupOracle = new AccountGroupSuggestOracle();
- ownerTxt = new SuggestBox(new RPCSuggestOracle(
- accountGroupOracle), ownerTxtBox);
+ ownerTxt = new RemoteSuggestBox(accountGroupOracle);
ownerTxt.setStyleName(Gerrit.RESOURCES.css().groupOwnerTextBox());
+ ownerTxt.setVisibleLength(60);
ownerPanel.add(ownerTxt);
saveOwner = new Button(Util.C.buttonChangeGroupOwner());
@@ -227,6 +223,6 @@
saveGroupOptions.setVisible(canModify);
new OnEditEnabler(saveDesc, descTxt);
new OnEditEnabler(saveName, groupNameTxt);
- new OnEditEnabler(saveOwner, ownerTxtBox);
+ new OnEditEnabler(saveOwner, ownerTxt.getTextBox());
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
index 0562689..cf3e940 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
@@ -24,6 +24,7 @@
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.AccountGroupSuggestOracle;
import com.google.gerrit.client.ui.AccountLinkPanel;
+import com.google.gerrit.client.ui.AccountSuggestOracle;
import com.google.gerrit.client.ui.AddMemberBox;
import com.google.gerrit.client.ui.FancyFlexTable;
import com.google.gerrit.client.ui.Hyperlink;
@@ -80,7 +81,10 @@
private void initMemberList() {
- addMemberBox = new AddMemberBox();
+ addMemberBox = new AddMemberBox(
+ Util.C.buttonAddGroupMember(),
+ Util.C.defaultAccountName(),
+ new AccountSuggestOracle());
addMemberBox.addClickHandler(new ClickHandler() {
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
index 0379cc0..3132531 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
@@ -26,11 +26,11 @@
import com.google.gerrit.client.projects.ProjectInfo;
import com.google.gerrit.client.projects.ProjectMap;
import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.HintTextBox;
import com.google.gerrit.client.ui.OnEditEnabler;
import com.google.gerrit.client.ui.ProjectListPopup;
import com.google.gerrit.client.ui.ProjectNameSuggestOracle;
import com.google.gerrit.client.ui.ProjectsTable;
+import com.google.gerrit.client.ui.RemoteSuggestBox;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.ProjectUtil;
@@ -49,7 +49,6 @@
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Grid;
-import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.globalkey.client.NpTextBox;
@@ -58,8 +57,7 @@
private NpTextBox project;
private Button create;
private Button browse;
- private HintTextBox parent;
- private SuggestBox suggestParent;
+ private RemoteSuggestBox parent;
private CheckBox emptyCommit;
private CheckBox permissionsOnly;
private ProjectsTable suggestedParentsTab;
@@ -102,8 +100,8 @@
@Override
protected void onMovePointerTo(String projectName) {
// prevent user input from being overwritten by simply poping up
- if (!projectsPopup.isPoppingUp() || "".equals(suggestParent.getText())) {
- suggestParent.setText(projectName);
+ if (!projectsPopup.isPoppingUp() || "".equals(parent.getText())) {
+ parent.setText(projectName);
}
}
};
@@ -191,9 +189,7 @@
}
private void initParentBox() {
- parent = new HintTextBox();
- suggestParent =
- new SuggestBox(new ProjectNameSuggestOracle(), parent);
+ parent = new RemoteSuggestBox(new ProjectNameSuggestOracle());
parent.setVisibleLength(50);
}
@@ -210,7 +206,7 @@
@Override
public void onClick(ClickEvent event) {
- suggestParent.setText(getRowItem(row).name());
+ parent.setText(getRowItem(row).name());
}
});
@@ -240,14 +236,14 @@
grid.setText(0, 0, Util.C.columnProjectName() + ":");
grid.setWidget(0, 1, project);
grid.setText(1, 0, Util.C.headingParentProjectName() + ":");
- grid.setWidget(1, 1, suggestParent);
+ grid.setWidget(1, 1, parent);
grid.setWidget(1, 2, browse);
fp.add(grid);
}
private void doCreateProject() {
final String projectName = project.getText().trim();
- final String parentName = suggestParent.getText().trim();
+ final String parentName = parent.getText().trim();
if ("".equals(projectName)) {
project.setFocus(true);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
index 5bf2649..c5f757d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
@@ -19,10 +19,8 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.groups.GroupMap;
import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.AccountScreen;
-import com.google.gerrit.client.ui.FilteredUserInterface;
import com.google.gerrit.client.ui.Hyperlink;
-import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
+import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gwt.event.dom.client.KeyCodes;
@@ -33,20 +31,24 @@
import com.google.gwt.user.client.ui.Label;
import com.google.gwtexpui.globalkey.client.NpTextBox;
-public class GroupListScreen extends AccountScreen implements FilteredUserInterface {
+public class GroupListScreen extends Screen {
private Hyperlink prev;
private Hyperlink next;
private GroupTable groups;
private NpTextBox filterTxt;
- private String subname = "";
- private int startPosition;
private int pageSize;
+ private String match = "";
+ private int start;
+ private Query query;
+
public GroupListScreen() {
+ setRequiresSignIn(true);
configurePageSize();
}
public GroupListScreen(String params) {
+ this();
for (String kvPair : params.split("[,;&]")) {
String[] kv = kvPair.split("=", 2);
if (kv.length != 2 || kv[0].isEmpty()) {
@@ -54,14 +56,13 @@
}
if ("filter".equals(kv[0])) {
- subname = URL.decodeQueryString(kv[1]);
+ match = URL.decodeQueryString(kv[1]);
}
if ("skip".equals(kv[0]) && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) {
- startPosition = Integer.parseInt(URL.decodeQueryString(kv[1]));
+ start = Integer.parseInt(URL.decodeQueryString(kv[1]));
}
}
- configurePageSize();
}
private void configurePageSize() {
@@ -78,42 +79,7 @@
@Override
protected void onLoad() {
super.onLoad();
- display();
- refresh(false, false);
- }
-
- private void refresh(final boolean open, final boolean filterModified) {
- if (filterModified){
- startPosition = 0;
- }
- setToken(getTokenForScreen(subname, startPosition));
- // Retrieve one more group than page size to determine if there are more
- // groups to display
- GroupMap.match(subname, pageSize + 1, startPosition,
- new IgnoreOutdatedFilterResultsCallbackWrapper<>(this,
- new GerritCallback<GroupMap>() {
- @Override
- public void onSuccess(GroupMap result) {
- if (open && result.values().length() > 0) {
- Gerrit.display(PageLinks.toGroup(
- result.values().get(0).getGroupUUID()));
- } else {
- if (result.size() <= pageSize) {
- groups.display(result, subname);
- next.setVisible(false);
- } else {
- groups.displaySubset(result, 0, result.size() - 1, subname);
- setupNavigationLink(next, subname, startPosition + pageSize);
- }
- if (startPosition > 0) {
- setupNavigationLink(prev, subname, startPosition - pageSize);
- } else {
- prev.setVisible(false);
- }
- groups.finishDisplay();
- }
- }
- }));
+ query = new Query(match).start(start).run();
}
private void setupNavigationLink(Hyperlink link, String filter, int skip) {
@@ -138,11 +104,6 @@
}
@Override
- public String getCurrentFilter() {
- return subname;
- }
-
- @Override
protected void onInitUI() {
super.onInitUI();
setPageTitle(Util.C.groupListTitle());
@@ -171,16 +132,20 @@
filterLabel.setStyleName(Gerrit.RESOURCES.css().projectFilterLabel());
hp.add(filterLabel);
filterTxt = new NpTextBox();
- filterTxt.setValue(subname);
+ filterTxt.setValue(match);
filterTxt.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
- boolean enterPressed =
- event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER;
- boolean filterModified = !filterTxt.getValue().equals(subname);
- if (enterPressed || filterModified) {
- subname = filterTxt.getValue();
- refresh(enterPressed, filterModified);
+ Query q = new Query(filterTxt.getValue())
+ .open(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER);
+ if (match.equals(q.qMatch)) {
+ q.start(start);
+ }
+ if (q.open || !match.equals(q.qMatch)) {
+ if (query == null) {
+ q.run();
+ }
+ query = q;
}
}
});
@@ -191,8 +156,8 @@
@Override
public void onShowView() {
super.onShowView();
- if (subname != null) {
- filterTxt.setCursorPos(subname.length());
+ if (match != null) {
+ filterTxt.setCursorPos(match.length());
}
filterTxt.setFocus(true);
}
@@ -202,4 +167,73 @@
super.registerKeys();
groups.setRegisterKeys(true);
}
+
+ private class Query {
+ private final String qMatch;
+ private int qStart;
+ private boolean open;
+
+ Query(String match) {
+ this.qMatch = match;
+ }
+
+ Query start(int start) {
+ this.qStart = start;
+ return this;
+ }
+
+ Query open(boolean open) {
+ this.open = open;
+ return this;
+ }
+
+ Query run() {
+ int limit = open ? 1 : pageSize + 1;
+ GroupMap.match(qMatch, limit, qStart,
+ new GerritCallback<GroupMap>() {
+ @Override
+ public void onSuccess(GroupMap result) {
+ if (!isAttached()) {
+ // View has been disposed.
+ } else if (query == Query.this) {
+ query = null;
+ showMap(result);
+ } else {
+ query.run();
+ }
+ }
+ });
+ return this;
+ }
+
+ private void showMap(GroupMap result) {
+ if (open && !result.isEmpty()) {
+ Gerrit.display(PageLinks.toGroup(
+ result.values().get(0).getGroupUUID()));
+ return;
+ }
+
+ setToken(getTokenForScreen(qMatch, qStart));
+ GroupListScreen.this.match = qMatch;
+ GroupListScreen.this.start = qStart;
+
+ if (result.size() <= pageSize) {
+ groups.display(result, qMatch);
+ next.setVisible(false);
+ } else {
+ groups.displaySubset(result, 0, result.size() - 1, qMatch);
+ setupNavigationLink(next, qMatch, qStart + pageSize);
+ }
+
+ if (qStart > 0) {
+ setupNavigationLink(prev, qMatch, qStart - pageSize);
+ } else {
+ prev.setVisible(false);
+ }
+
+ if (!isCurrentView()) {
+ display();
+ }
+ }
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java
index a76638e..c1082bc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java
@@ -15,15 +15,10 @@
package com.google.gerrit.client.admin;
import com.google.gerrit.client.ui.AccountGroupSuggestOracle;
-import com.google.gerrit.client.ui.RPCSuggestOracle;
+import com.google.gerrit.client.ui.RemoteSuggestBox;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.editor.client.LeafValueEditor;
-import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.dom.client.KeyPressHandler;
-import com.google.gwt.event.dom.client.KeyUpEvent;
-import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
@@ -33,67 +28,36 @@
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Focusable;
-import com.google.gwt.user.client.ui.SuggestBox;
-import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
-import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
-import com.google.gwtexpui.globalkey.client.NpTextBox;
public class GroupReferenceBox extends Composite implements
LeafValueEditor<GroupReference>, HasSelectionHandlers<GroupReference>,
HasCloseHandlers<GroupReferenceBox>, Focusable {
- private final DefaultSuggestionDisplay suggestions;
- private final NpTextBox textBox;
private final AccountGroupSuggestOracle oracle;
- private final SuggestBox suggestBox;
-
- private boolean submitOnSelection;
+ private final RemoteSuggestBox suggestBox;
public GroupReferenceBox() {
- suggestions = new DefaultSuggestionDisplay();
- textBox = new NpTextBox();
oracle = new AccountGroupSuggestOracle();
- suggestBox = new SuggestBox( //
- new RPCSuggestOracle(oracle), //
- textBox, //
- suggestions);
+ suggestBox = new RemoteSuggestBox(oracle);
initWidget(suggestBox);
- textBox.addKeyPressHandler(new KeyPressHandler() {
+ suggestBox.addSelectionHandler(new SelectionHandler<String>() {
@Override
- public void onKeyPress(KeyPressEvent event) {
- submitOnSelection = false;
-
- if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
- if (suggestions.isSuggestionListShowing()) {
- submitOnSelection = true;
- } else {
- SelectionEvent.fire(GroupReferenceBox.this, getValue());
- }
- }
+ public void onSelection(SelectionEvent<String> event) {
+ SelectionEvent.fire(GroupReferenceBox.this,
+ toValue(event.getSelectedItem()));
}
});
- suggestBox.addKeyUpHandler(new KeyUpHandler() {
+ suggestBox.addCloseHandler(new CloseHandler<RemoteSuggestBox>(){
@Override
- public void onKeyUp(KeyUpEvent event) {
- if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
- suggestBox.setText("");
- CloseEvent.fire(GroupReferenceBox.this, GroupReferenceBox.this);
- }
- }
- });
- suggestBox.addSelectionHandler(new SelectionHandler<Suggestion>() {
- @Override
- public void onSelection(SelectionEvent<Suggestion> event) {
- if (submitOnSelection) {
- submitOnSelection = false;
- SelectionEvent.fire(GroupReferenceBox.this, getValue());
- }
+ public void onClose(CloseEvent<RemoteSuggestBox> event) {
+ suggestBox.setText("");
+ CloseEvent.fire(GroupReferenceBox.this, GroupReferenceBox.this);
}
});
}
public void setVisibleLength(int len) {
- textBox.setVisibleLength(len);
+ suggestBox.setVisibleLength(len);
}
@Override
@@ -110,12 +74,14 @@
@Override
public GroupReference getValue() {
- String name = suggestBox.getText();
+ return toValue(suggestBox.getText());
+ }
+
+ private GroupReference toValue(String name) {
if (name != null && !name.isEmpty()) {
return new GroupReference(oracle.getUUID(name), name);
- } else {
- return null;
}
+ return null;
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
index e28e465..828352c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
@@ -24,10 +24,8 @@
import com.google.gerrit.client.projects.ProjectMap;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
-import com.google.gerrit.client.ui.FilteredUserInterface;
import com.google.gerrit.client.ui.HighlightingInlineHyperlink;
import com.google.gerrit.client.ui.Hyperlink;
-import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
import com.google.gerrit.client.ui.ProjectSearchLink;
import com.google.gerrit.client.ui.ProjectsTable;
import com.google.gerrit.client.ui.Screen;
@@ -47,15 +45,17 @@
import java.util.List;
-public class ProjectListScreen extends Screen implements FilteredUserInterface {
+public class ProjectListScreen extends Screen {
private Hyperlink prev;
private Hyperlink next;
private ProjectsTable projects;
private NpTextBox filterTxt;
- private String subname = "";
- private int startPosition;
private int pageSize;
+ private String match = "";
+ private int start;
+ private Query query;
+
public ProjectListScreen() {
configurePageSize();
}
@@ -68,11 +68,11 @@
}
if ("filter".equals(kv[0])) {
- subname = URL.decodeQueryString(kv[1]);
+ match = URL.decodeQueryString(kv[1]);
}
if ("skip".equals(kv[0]) && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) {
- startPosition = Integer.parseInt(URL.decodeQueryString(kv[1]));
+ start = Integer.parseInt(URL.decodeQueryString(kv[1]));
}
}
configurePageSize();
@@ -92,41 +92,7 @@
@Override
protected void onLoad() {
super.onLoad();
- display();
- refresh(false, false);
- }
-
- private void refresh(final boolean open, final boolean filterModified) {
- if (filterModified){
- startPosition = 0;
- }
- setToken(getTokenForScreen(subname, startPosition));
- // Retrieve one more project than page size to determine if there are more
- // projects to display
- ProjectMap.match(subname, pageSize + 1, startPosition,
- new IgnoreOutdatedFilterResultsCallbackWrapper<>(this,
- new GerritCallback<ProjectMap>() {
- @Override
- public void onSuccess(ProjectMap result) {
- if (open && result.values().length() > 0) {
- Gerrit.display(PageLinks.toProject(
- result.values().get(0).name_key()));
- } else {
- if (result.size() <= pageSize) {
- projects.display(result);
- next.setVisible(false);
- } else {
- projects.displaySubset(result, 0, result.size() - 1);
- setupNavigationLink(next, subname, startPosition + pageSize);
- }
- if (startPosition > 0) {
- setupNavigationLink(prev, subname, startPosition - pageSize);
- } else {
- prev.setVisible(false);
- }
- }
- }
- }));
+ query = new Query(match).start(start).run();
}
private void setupNavigationLink(Hyperlink link, String filter, int skip) {
@@ -151,11 +117,6 @@
}
@Override
- public String getCurrentFilter() {
- return subname;
- }
-
- @Override
protected void onInitUI() {
super.onInitUI();
setPageTitle(Util.C.projectListTitle());
@@ -215,7 +176,7 @@
FlowPanel fp = new FlowPanel();
fp.add(new ProjectSearchLink(k.name_key()));
- fp.add(new HighlightingInlineHyperlink(k.name(), link(k), subname));
+ fp.add(new HighlightingInlineHyperlink(k.name(), link(k), match));
table.setWidget(row, ProjectsTable.C_NAME, fp);
table.setText(row, ProjectsTable.C_DESCRIPTION, k.description());
addWebLinks(row, k);
@@ -261,16 +222,20 @@
filterLabel.setStyleName(Gerrit.RESOURCES.css().projectFilterLabel());
hp.add(filterLabel);
filterTxt = new NpTextBox();
- filterTxt.setValue(subname);
+ filterTxt.setValue(match);
filterTxt.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
- boolean enterPressed =
- event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER;
- boolean filterModified = !filterTxt.getValue().equals(subname);
- if (enterPressed || filterModified) {
- subname = filterTxt.getValue();
- refresh(enterPressed, filterModified);
+ Query q = new Query(filterTxt.getValue())
+ .open(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER);
+ if (match.equals(q.qMatch)) {
+ q.start(start);
+ }
+ if (q.open || !match.equals(q.qMatch)) {
+ if (query == null) {
+ q.run();
+ }
+ query = q;
}
}
});
@@ -281,8 +246,8 @@
@Override
public void onShowView() {
super.onShowView();
- if (subname != null) {
- filterTxt.setCursorPos(subname.length());
+ if (match != null) {
+ filterTxt.setCursorPos(match.length());
}
filterTxt.setFocus(true);
}
@@ -292,4 +257,72 @@
super.registerKeys();
projects.setRegisterKeys(true);
}
+
+ private class Query {
+ private final String qMatch;
+ private int qStart;
+ private boolean open;
+
+ Query(String match) {
+ this.qMatch = match;
+ }
+
+ Query start(int start) {
+ this.qStart = start;
+ return this;
+ }
+
+ Query open(boolean open) {
+ this.open = open;
+ return this;
+ }
+
+ Query run() {
+ int limit = open ? 1 : pageSize + 1;
+ ProjectMap.match(qMatch, limit, qStart,
+ new GerritCallback<ProjectMap>() {
+ @Override
+ public void onSuccess(ProjectMap result) {
+ if (!isAttached()) {
+ // View has been disposed.
+ } else if (query == Query.this) {
+ query = null;
+ showMap(result);
+ } else {
+ query.run();
+ }
+ }
+ });
+ return this;
+ }
+
+ private void showMap(ProjectMap result) {
+ if (open && !result.isEmpty()) {
+ Gerrit.display(PageLinks.toProject(result.values().get(0).name_key()));
+ return;
+ }
+
+ setToken(getTokenForScreen(qMatch, qStart));
+ ProjectListScreen.this.match = qMatch;
+ ProjectListScreen.this.start = qStart;
+
+ if (result.size() <= pageSize) {
+ projects.display(result);
+ next.setVisible(false);
+ } else {
+ projects.displaySubset(result, 0, result.size() - 1);
+ setupNavigationLink(next, qMatch, qStart + pageSize);
+ }
+
+ if (qStart > 0) {
+ setupNavigationLink(prev, qMatch, qStart - pageSize);
+ } else {
+ prev.setVisible(false);
+ }
+
+ if (!isCurrentView()) {
+ display();
+ }
+ }
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
index ada960c..a7d4945 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
@@ -47,4 +47,6 @@
String sameTopicTooltip();
String noChanges();
String indirectAncestor();
+ String merged();
+ String abandoned();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
index 172c1de..8852d4e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
@@ -28,3 +28,5 @@
sameTopicTooltip = Changes with the same topic
noChanges = No Changes
indirectAncestor = Indirect ancestor
+merged = Merged
+abandoned = Abandoned
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
index 866a43c..45194e2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
@@ -234,8 +234,7 @@
RestApi call = ChangeApi.detail(changeId.get());
ChangeList.addOptions(call, EnumSet.of(
ListChangesOption.CURRENT_ACTIONS,
- ListChangesOption.ALL_REVISIONS,
- ListChangesOption.WEB_LINKS));
+ ListChangesOption.ALL_REVISIONS));
if (!fg) {
call.background();
}
@@ -829,18 +828,18 @@
if (rev.is_edit()) {
return;
}
- ChangeApi.revision(changeId.get(), rev.name())
- .view("commit")
- .get(group.add(new AsyncCallback<CommitInfo>() {
- @Override
- public void onSuccess(CommitInfo info) {
- rev.set_commit(info);
- }
- @Override
- public void onFailure(Throwable caught) {
- }
- }));
+ ChangeApi.commitWithLinks(changeId.get(), rev.name(),
+ group.add(new AsyncCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(CommitInfo info) {
+ rev.set_commit(info);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ }));
}
private void loadSubmitType(final Change.Status status, final boolean canSubmit) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
index 5bb4639..c412587d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
@@ -130,7 +130,7 @@
gw.getLinkName());
}
- JsArray<WebLinkInfo> links = revInfo.web_links();
+ JsArray<WebLinkInfo> links = revInfo.commit().web_links();
if (links != null) {
for (WebLinkInfo link : Natives.asList(links)) {
webLinkPanel.add(link.toAnchor());
@@ -160,6 +160,12 @@
a.setStyleName(style.parentWebLink());
parentWebLinks.add(a);
}
+ JsArray<WebLinkInfo> links = c.web_links();
+ if (links != null) {
+ for (WebLinkInfo link : Natives.asList(links)) {
+ parentWebLinks.add(link.toAnchor());
+ }
+ }
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
index c51587a..90632c8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
@@ -87,9 +87,12 @@
.webLinkPanel>a {
margin-left:2px;
}
- .parentWebLink {
+
+ .parentWebLink a:first-child {
margin-left:16px;
- display: block;
+ }
+ .parentWebLink>a {
+ margin-left:2px;
}
.commit {
@@ -165,7 +168,7 @@
<g:FlowPanel ui:field='parentCommits'/>
</td>
<td>
- <g:FlowPanel ui:field='parentWebLinks'/>
+ <g:FlowPanel ui:field='parentWebLinks' styleName='{style.parentWebLink}'/>
</td>
</tr>
<tr>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
index 7fbbfc7..5f6c6de 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
@@ -55,6 +55,8 @@
String current();
String gitweb();
String indirect();
+ String abandoned();
+ String merged();
String notCurrent();
String pointer();
String row();
@@ -342,6 +344,13 @@
}
public final native String id() /*-{ return this.change_id }-*/;
+
+ public final Change.Status status() {
+ String s = statusRaw();
+ return s != null ? Change.Status.valueOf(s) : null;
+ }
+ private final native String statusRaw() /*-{ return this.status; }-*/;
+
public final native CommitInfo commit() /*-{ return this.commit }-*/;
final native String branch() /*-{ return this.branch }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
index 0f2ee81..2dfd53e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
@@ -20,6 +20,7 @@
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
@@ -301,6 +302,14 @@
sb.setStyleName(RelatedChanges.R.css().notCurrent());
sb.setAttribute("title", Util.C.notCurrent());
sb.append('\u25CF');
+ } else if (Change.Status.MERGED == info.status()) {
+ sb.setStyleName(RelatedChanges.R.css().merged());
+ sb.setAttribute("title", Resources.C.merged());
+ sb.append('\u25CF');
+ } else if (Change.Status.ABANDONED == info.status()) {
+ sb.setStyleName(RelatedChanges.R.css().abandoned());
+ sb.setAttribute("title", Resources.C.abandoned());
+ sb.append('\u25CF');
} else {
sb.setStyleName(RelatedChanges.R.css().current());
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RestReviewerSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReviewerSuggestOracle.java
similarity index 79%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RestReviewerSuggestOracle.java
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReviewerSuggestOracle.java
index 3c544cf..7af247a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RestReviewerSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReviewerSuggestOracle.java
@@ -25,28 +25,32 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
-import com.google.gwt.user.client.ui.SuggestOracle;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/** REST API based suggestion Oracle for reviewers. */
-public class RestReviewerSuggestOracle extends SuggestAfterTypingNCharsOracle {
-
+public class ReviewerSuggestOracle extends SuggestAfterTypingNCharsOracle {
private Change.Id changeId;
@Override
- protected void _onRequestSuggestions(final Request req, final Callback callback) {
- ChangeApi.suggestReviewers(changeId.get(), req.getQuery(),
- req.getLimit()).get(new GerritCallback<JsArray<SuggestReviewerInfo>>() {
+ protected void _onRequestSuggestions(final Request req, final Callback cb) {
+ ChangeApi.suggestReviewers(changeId.get(), req.getQuery(), req.getLimit())
+ .get(new GerritCallback<JsArray<SuggestReviewerInfo>>() {
@Override
public void onSuccess(JsArray<SuggestReviewerInfo> result) {
- final List<RestReviewerSuggestion> r =
- new ArrayList<>(result.length());
- for (final SuggestReviewerInfo reviewer : Natives.asList(result)) {
+ List<RestReviewerSuggestion> r = new ArrayList<>(result.length());
+ for (SuggestReviewerInfo reviewer : Natives.asList(result)) {
r.add(new RestReviewerSuggestion(reviewer));
}
- callback.onSuggestionsReady(req, new Response(r));
+ cb.onSuggestionsReady(req, new Response(r));
+ }
+
+ @Override
+ public void onFailure(Throwable err) {
+ List<Suggestion> r = Collections.emptyList();
+ cb.onSuggestionsReady(req, new Response(r));
}
});
}
@@ -55,7 +59,7 @@
this.changeId = changeId;
}
- private static class RestReviewerSuggestion implements SuggestOracle.Suggestion {
+ private static class RestReviewerSuggestion implements Suggestion {
private final SuggestReviewerInfo reviewer;
RestReviewerSuggestion(final SuggestReviewerInfo reviewer) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
index da0d052..e66ab4e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
@@ -27,16 +27,15 @@
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.NativeString;
import com.google.gerrit.client.rpc.Natives;
-import com.google.gerrit.client.ui.HintTextBox;
+import com.google.gerrit.client.ui.RemoteSuggestBox;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
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.KeyDownEvent;
-import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.uibinder.client.UiBinder;
@@ -46,9 +45,6 @@
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.user.client.ui.SuggestBox;
-import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
-import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
@@ -69,50 +65,33 @@
@UiField Element form;
@UiField Element error;
@UiField(provided = true)
- SuggestBox suggestBox;
+ RemoteSuggestBox suggestBox;
private ChangeScreen2.Style style;
private Element ccText;
- private RestReviewerSuggestOracle reviewerSuggestOracle;
- private HintTextBox nameTxtBox;
+ private ReviewerSuggestOracle reviewerSuggestOracle;
private Change.Id changeId;
- private boolean submitOnSelection;
Reviewers() {
- reviewerSuggestOracle = new RestReviewerSuggestOracle();
- nameTxtBox = new HintTextBox();
- suggestBox = new SuggestBox(reviewerSuggestOracle, nameTxtBox);
+ reviewerSuggestOracle = new ReviewerSuggestOracle();
+ suggestBox = new RemoteSuggestBox(reviewerSuggestOracle);
+ suggestBox.setVisibleLength(55);
+ suggestBox.setHintText(Util.C.approvalTableAddReviewerHint());
+ suggestBox.addCloseHandler(new CloseHandler<RemoteSuggestBox>() {
+ @Override
+ public void onClose(CloseEvent<RemoteSuggestBox> event) {
+ Reviewers.this.onCancel(null);
+ }
+ });
+ suggestBox.addSelectionHandler(new SelectionHandler<String>() {
+ @Override
+ public void onSelection(SelectionEvent<String> event) {
+ addReviewer(event.getSelectedItem(), false);
+ }
+ });
+
initWidget(uiBinder.createAndBindUi(this));
-
- nameTxtBox.setVisibleLength(55);
- nameTxtBox.setHintText(Util.C.approvalTableAddReviewerHint());
- nameTxtBox.addKeyDownHandler(new KeyDownHandler() {
- @Override
- public void onKeyDown(KeyDownEvent e) {
- submitOnSelection = false;
-
- if (e.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
- onCancel(null);
- } else if (e.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
- if (((DefaultSuggestionDisplay) suggestBox.getSuggestionDisplay())
- .isSuggestionListShowing()) {
- submitOnSelection = true;
- } else {
- onAdd(null);
- }
- }
- }
- });
- suggestBox.addSelectionHandler(new SelectionHandler<Suggestion>() {
- @Override
- public void onSelection(SelectionEvent<Suggestion> event) {
- nameTxtBox.setFocus(true);
- if (submitOnSelection) {
- onAdd(null);
- }
- }
- });
}
void init(ChangeScreen2.Style style, Element ccText) {
@@ -141,10 +120,7 @@
@UiHandler("add")
void onAdd(@SuppressWarnings("unused") ClickEvent e) {
- String reviewer = suggestBox.getText();
- if (!reviewer.isEmpty()) {
- addReviewer(reviewer, false);
- }
+ addReviewer(suggestBox.getText(), false);
}
@UiHandler("addMe")
@@ -161,13 +137,15 @@
}
private void addReviewer(final String reviewer, boolean confirmed) {
+ if (reviewer.isEmpty()) {
+ return;
+ }
+
ChangeApi.reviewers(changeId.get()).post(
PostInput.create(reviewer, confirmed),
new GerritCallback<PostResult>() {
@Override
public void onSuccess(PostResult result) {
- nameTxtBox.setEnabled(true);
-
if (result.confirm()) {
askForConfirmation(result.error());
} else if (result.error() != null) {
@@ -176,7 +154,7 @@
} else {
UIObject.setVisible(error, false);
error.setInnerText("");
- nameTxtBox.setText("");
+ suggestBox.setText("");
if (result.reviewers() != null
&& result.reviewers().length() > 0) {
@@ -203,7 +181,6 @@
error.setInnerText(err instanceof StatusCodeException
? ((StatusCodeException) err).getEncodedResponse()
: err.getMessage());
- nameTxtBox.setEnabled(true);
}
});
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml
index 2d17a53..9924c1d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml
@@ -17,7 +17,8 @@
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
- xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:u='urn:import:com.google.gerrit.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
<ui:style>
button.openAdd {
@@ -64,7 +65,7 @@
</g:Button>
</div>
<div ui:field='form' style='display: none' aria-hidden='true'>
- <g:SuggestBox ui:field='suggestBox' styleName='{style.suggestBox}'/>
+ <u:RemoteSuggestBox ui:field='suggestBox' styleName='{style.suggestBox}'/>
<div ui:field='error'
class='{style.error}'
style='display: none' aria-hidden='true'/>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
index 450da16..9f45678 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
@@ -27,6 +27,7 @@
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
@@ -118,6 +119,7 @@
onCancel(null);
} else if (e.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
e.stopPropagation();
+ e.preventDefault();
onSave(null);
}
}
@@ -137,4 +139,11 @@
});
onCancel(null);
}
+
+ @UiHandler("save")
+ void onSaveKeyPress(KeyPressEvent e) {
+ if (e.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
+ e.stopPropagation();
+ }
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css
index 2e62b98..4d103ae 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css
@@ -68,6 +68,8 @@
.current,
.gitweb,
.indirect,
+.abandoned,
+.merged,
.notCurrent {
display: inline-block;
text-align: center;
@@ -75,6 +77,7 @@
width: 12px;
}
+.merged,
.gitweb {
color: #000;
}
@@ -84,6 +87,10 @@
font-weight: bold;
}
+.abandoned {
+ color: #900; /* dark red */
+}
+
.notCurrent {
color: #FFA62F; /* orange */
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java
index bdc3142..fc2af89 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java
@@ -21,6 +21,7 @@
import com.google.gerrit.client.ErrorDialog;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.account.AccountInfo;
+import com.google.gerrit.client.change.ReviewerSuggestOracle;
import com.google.gerrit.client.change.Reviewers.PostInput;
import com.google.gerrit.client.change.Reviewers.PostResult;
import com.google.gerrit.client.changes.ChangeInfo.ApprovalInfo;
@@ -29,7 +30,6 @@
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.AccountLinkPanel;
import com.google.gerrit.client.ui.AddMemberBox;
-import com.google.gerrit.client.ui.ReviewerSuggestOracle;
import com.google.gerrit.common.data.ApprovalDetail;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
index 44debe5..c3bbe18 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
@@ -14,8 +14,10 @@
package com.google.gerrit.client.changes;
+import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
import com.google.gerrit.client.changes.ChangeInfo.EditInfo;
import com.google.gerrit.client.changes.ChangeInfo.IncludedInInfo;
+import com.google.gerrit.client.rpc.CallbackGroup.Callback;
import com.google.gerrit.client.rpc.NativeString;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.reviewdb.client.PatchSet;
@@ -265,4 +267,12 @@
public static String emptyToNull(String str) {
return str == null || str.isEmpty() ? null : str;
}
+
+ public static void commitWithLinks(int changeId, String revision,
+ Callback<CommitInfo> callback) {
+ revision(changeId, revision)
+ .view("commit")
+ .addParameterTrue("links")
+ .get(callback);
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index 4a77c9e..a9dec39 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -257,7 +257,6 @@
public final native boolean has_fetch() /*-{ return this.hasOwnProperty('fetch') }-*/;
public final native NativeMap<FetchInfo> fetch() /*-{ return this.fetch; }-*/;
- public final native JsArray<WebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
public static void sortRevisionInfoByNumber(JsArray<RevisionInfo> list) {
final int editParent = findEditParent(list);
@@ -318,6 +317,7 @@
public final native GitPerson committer() /*-{ return this.committer; }-*/;
public final native String subject() /*-{ return this.subject; }-*/;
public final native String message() /*-{ return this.message; }-*/;
+ public final native JsArray<WebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
protected CommitInfo() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
index e91a28c..7753cb3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
@@ -59,7 +59,7 @@
import java.util.List;
-class Header extends Composite {
+public class Header extends Composite {
interface Binder extends UiBinder<HTMLPanel, Header> {}
private static final Binder uiBinder = GWT.create(Binder.class);
static {
@@ -109,7 +109,7 @@
base != null ? base.getId() : null, patchSetId.getId()));
}
- private static SafeHtml formatPath(String path, String project, String commit) {
+ public static SafeHtml formatPath(String path, String project, String commit) {
SafeHtmlBuilder b = new SafeHtmlBuilder();
if (Patch.COMMIT_MSG.equals(path)) {
return b.append(Util.C.commitMessage());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
index 394f61b..1c9f177 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -16,7 +16,12 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
+import com.google.gerrit.client.account.DiffPreferences;
+import com.google.gerrit.client.changes.ChangeApi;
import com.google.gerrit.client.changes.ChangeFileApi;
+import com.google.gerrit.client.changes.ChangeInfo;
+import com.google.gerrit.client.diff.FileInfo;
+import com.google.gerrit.client.diff.Header;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
@@ -36,6 +41,7 @@
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.safehtml.client.SafeHtml;
import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.Configuration;
@@ -43,15 +49,16 @@
import net.codemirror.mode.ModeInjector;
public class EditScreen extends Screen {
-
interface Binder extends UiBinder<HTMLPanel, EditScreen> {}
private static final Binder uiBinder = GWT.create(Binder.class);
private final PatchSet.Id revision;
private final String path;
+ private DiffPreferences prefs;
private CodeMirror cm;
private String type;
+ @UiField Element project;
@UiField Element filePath;
@UiField Button cancel;
@UiField Button save;
@@ -60,6 +67,7 @@
public EditScreen(Patch.Key patch) {
this.revision = patch.getParentKey();
this.path = patch.get();
+ prefs = DiffPreferences.create(Gerrit.getAccountDiffPreference());
add(uiBinder.createAndBindUi(this));
addDomHandler(GlobalKey.STOP_PROPAGATION, KeyPressEvent.getType());
}
@@ -67,24 +75,22 @@
@Override
protected void onInitUI() {
super.onInitUI();
- initPath();
setHeaderVisible(false);
+ setWindowTitle(FileInfo.getFileName(path));
}
@Override
protected void onLoad() {
super.onLoad();
+
CallbackGroup cmGroup = new CallbackGroup();
CodeMirror.initLibrary(cmGroup.add(CallbackGroup.<Void> emptyCallback()));
CallbackGroup group = new CallbackGroup();
- final AsyncCallback<Void> modeInjectorCb =
- group.add(CallbackGroup.<Void> emptyCallback());
- if (Patch.COMMIT_MSG.equals(path)) {
- // No need to inject "text/plain", just fire the callback
- modeInjectorCb.onSuccess(null);
- } else {
+ if (!Patch.COMMIT_MSG.equals(path)) {
+ final AsyncCallback<Void> modeInjectorCb =
+ group.add(CallbackGroup.<Void> emptyCallback());
ChangeFileApi.getContentType(revision, path,
- cmGroup.addFinal(new GerritCallback<String>() {
+ cmGroup.add(new GerritCallback<String>() {
@Override
public void onSuccess(String result) {
ModeInfo mode = ModeInfo.findMode(result, path);
@@ -93,6 +99,17 @@
}
}));
}
+ cmGroup.done();
+
+ ChangeApi.detail(revision.getParentKey().get(),
+ group.add(new GerritCallback<ChangeInfo>() {
+ @Override
+ public void onSuccess(ChangeInfo c) {
+ project.setInnerText(c.project());
+ SafeHtml.setInnerHTML(filePath, Header.formatPath(path, null, null));
+ }
+ }));
+
ChangeFileApi.getContentOrMessage(revision, path,
group.addFinal(new ScreenLoadCallback<String>(this) {
@Override
@@ -105,6 +122,9 @@
@Override
public void onShowView() {
super.onShowView();
+ if (prefs.hideTopMenu()) {
+ Gerrit.setHeaderVisible(false);
+ }
int rest = Gerrit.getHeaderFooterHeight()
+ 30; // Estimate
cm.setHeight(Window.getClientHeight() - rest);
@@ -112,6 +132,12 @@
cm.focus();
}
+ @Override
+ protected void onUnload() {
+ super.onUnload();
+ Gerrit.setHeaderVisible(true);
+ }
+
@UiHandler("save")
void onSave(@SuppressWarnings("unused") ClickEvent e) {
ChangeFileApi.putContentOrMessage(revision, path, cm.getValue(),
@@ -152,8 +178,4 @@
.set("keyMap", "default")
.set("mode", type);
}
-
- private void initPath() {
- filePath.setInnerText(path);
- }
-}
\ No newline at end of file
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
index f39a124..8033bbf 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
@@ -15,46 +15,34 @@
limitations under the License.
-->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:g='urn:import:com.google.gwt.user.client.ui'
- xmlns:e='urn:import:com.google.gerrit.client.editor'>
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
- @eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
-
- @def HEADER_HEIGHT 30px;
- @def BUTTON_HEIGHT 14px;
-
- .infoLine {
- position: absolute;
- top: 0;
- left: 10px;
- height: HEADER_HEIGHT;
- padding-left: 25px;
- }
-
.headerLine {
- position: relative;
- background-color: trimColor;
- height: HEADER_HEIGHT;
- margin: 0 -5px;
- padding: 0 5px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ddd;
+ padding-left: 30px;
}
- .headerButtons button:disabled,
- #change_infoTable button:disabled,
- .popdown button:disabled {
+ .headerButtons {
+ display: inline-block;
+ padding-right: 5px;
+ border-right: 1px inset #ddd;
+ margin-right: 5px;
+ }
+
+ .headerButtons button:disabled {
background-color: #999;
}
.headerButtons button {
- margin: 6px 3px 0 0;
+ margin: 2px 0 2px 0;
text-align: center;
font-size: 8pt;
- font-weight: bold;
cursor: pointer;
- border: 2px solid;
+ border: 1px solid;
color: rgba(0, 0, 0, 0.15);
background-color: #f5f5f5;
- -webkit-border-radius: 2px;
+ -webkit-border-radius: 1px;
-webkit-box-sizing: content-box;
}
@@ -62,15 +50,11 @@
color: #444;
min-width: 54px;
white-space: nowrap;
- height: BUTTON_HEIGHT;
- line-height: BUTTON_HEIGHT;
+ line-height: 8pt;
}
- .infoLineHeaderButtons {
- display: inline-block;
- height: HEADER_HEIGHT;
- line-height: HEADER_HEIGHT;
- vertical-align: top;
+ .save {
+ font-weight: bold;
}
.path {
@@ -78,26 +62,23 @@
}
</ui:style>
<g:HTMLPanel>
- <g:HTMLPanel styleName='{style.headerLine}'>
- <div class='{style.infoLine}'>
- <div class='{style.headerButtons} {style.infoLineHeaderButtons}'>
- <g:Button ui:field='cancel'
- styleName=''
- title='Cancel'>
- <ui:attribute name='title'/>
- <div><ui:msg>Cancel</ui:msg></div>
- </g:Button>
- <g:Button ui:field='save'
- styleName=''
- title='Save'>
- <ui:attribute name='title'/>
- <div><ui:msg>Save</ui:msg></div>
- </g:Button>
- |
- <span class='{style.path}' ui:field='filePath'/>
- </div>
- </div>
- </g:HTMLPanel>
+ <div class='{style.headerLine}'>
+ <div class='{style.headerButtons}'>
+ <g:Button ui:field='cancel'
+ styleName=''
+ title='Cancel'>
+ <ui:attribute name='title'/>
+ <div><ui:msg>Cancel</ui:msg></div>
+ </g:Button>
+ <g:Button ui:field='save'
+ styleName='{style.save}'
+ title='Save'>
+ <ui:attribute name='title'/>
+ <div><ui:msg>Save</ui:msg></div>
+ </g:Button>
+ </div>
+ <span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
+ </div>
<div ui:field='editor' />
</g:HTMLPanel>
</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
index 29a8a01..0f121c8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
@@ -50,6 +50,7 @@
.addParameter("n", limit)
.addParameterRaw("type", "ALL")
.addParameterTrue("d") // description
+ .background()
.get(NativeMap.copyKeysIntoChildren(cb));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountSuggestOracle.java
index ac73dd2..78350db 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountSuggestOracle.java
@@ -15,9 +15,11 @@
package com.google.gerrit.client.ui;
import com.google.gerrit.client.FormatUtil;
-import com.google.gerrit.client.RpcStatus;
+import com.google.gerrit.client.account.AccountApi;
+import com.google.gerrit.client.account.AccountInfo;
import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.common.data.AccountInfo;
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.ui.SuggestOracle;
import java.util.ArrayList;
@@ -26,25 +28,18 @@
/** Suggestion Oracle for Account entities. */
public class AccountSuggestOracle extends SuggestAfterTypingNCharsOracle {
@Override
- public void _onRequestSuggestions(final Request req, final Callback callback) {
- RpcStatus.hide(new Runnable() {
- @Override
- public void run() {
- SuggestUtil.SVC.suggestAccount(req.getQuery(), Boolean.TRUE,
- req.getLimit(),
- new GerritCallback<List<AccountInfo>>() {
- @Override
- public void onSuccess(final List<AccountInfo> result) {
- final ArrayList<AccountSuggestion> r =
- new ArrayList<>(result.size());
- for (final AccountInfo p : result) {
- r.add(new AccountSuggestion(p));
- }
- callback.onSuggestionsReady(req, new Response(r));
- }
- });
- }
- });
+ public void _onRequestSuggestions(final Request req, final Callback cb) {
+ AccountApi.suggest(req.getQuery(), req.getLimit(),
+ new GerritCallback<JsArray<AccountInfo>>() {
+ @Override
+ public void onSuccess(JsArray<AccountInfo> in) {
+ List<AccountSuggestion> r = new ArrayList<>(in.length());
+ for (AccountInfo p : Natives.asList(in)) {
+ r.add(new AccountSuggestion(p));
+ }
+ cb.onSuggestionsReady(req, new Response(r));
+ }
+ });
}
private static class AccountSuggestion implements SuggestOracle.Suggestion {
@@ -56,12 +51,12 @@
@Override
public String getDisplayString() {
- return FormatUtil.nameEmail(FormatUtil.asInfo(info));
+ return FormatUtil.nameEmail(info);
}
@Override
public String getReplacementString() {
- return FormatUtil.nameEmail(FormatUtil.asInfo(info));
+ return FormatUtil.nameEmail(info);
}
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AddMemberBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AddMemberBox.java
index d4aaa4c..72233f5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AddMemberBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AddMemberBox.java
@@ -15,96 +15,56 @@
package com.google.gerrit.client.ui;
import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.admin.Util;
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.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
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.SuggestBox;
-import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
import com.google.gwt.user.client.ui.SuggestOracle;
-import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
public class AddMemberBox extends Composite {
private final FlowPanel addPanel;
private final Button addMember;
- private final HintTextBox nameTxtBox;
- private final SuggestBox nameTxt;
- private boolean submitOnSelection;
-
- public AddMemberBox() {
- this(Util.C.buttonAddGroupMember(), Util.C.defaultAccountName(),
- new AccountSuggestOracle());
- }
+ private final RemoteSuggestBox suggestBox;
public AddMemberBox(final String buttonLabel, final String hint,
final SuggestOracle suggestOracle) {
addPanel = new FlowPanel();
addMember = new Button(buttonLabel);
- nameTxtBox = new HintTextBox();
- nameTxt = new SuggestBox(new RPCSuggestOracle(
- suggestOracle), nameTxtBox);
- nameTxt.setStyleName(Gerrit.RESOURCES.css().addMemberTextBox());
- nameTxtBox.setVisibleLength(50);
- nameTxtBox.setHintText(hint);
- nameTxtBox.addKeyPressHandler(new KeyPressHandler() {
+ suggestBox = new RemoteSuggestBox(suggestOracle);
+ suggestBox.setStyleName(Gerrit.RESOURCES.css().addMemberTextBox());
+ suggestBox.setVisibleLength(50);
+ suggestBox.setHintText(hint);
+ suggestBox.addSelectionHandler(new SelectionHandler<String>() {
@Override
- public void onKeyPress(KeyPressEvent event) {
- submitOnSelection = false;
-
- if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
- if (((DefaultSuggestionDisplay) nameTxt.getSuggestionDisplay())
- .isSuggestionListShowing()) {
- submitOnSelection = true;
- } else {
- doAdd();
- }
- }
- }
- });
- nameTxt.addSelectionHandler(new SelectionHandler<Suggestion>() {
- @Override
- public void onSelection(SelectionEvent<Suggestion> event) {
- nameTxtBox.setFocus(true);
- if (submitOnSelection) {
- submitOnSelection = false;
- doAdd();
- }
+ public void onSelection(SelectionEvent<String> event) {
+ addMember.fireEvent(new ClickEvent() {});
}
});
- addPanel.add(nameTxt);
+ addPanel.add(suggestBox);
addPanel.add(addMember);
initWidget(addPanel);
}
- public void addClickHandler(final ClickHandler handler) {
+ public void addClickHandler(ClickHandler handler) {
addMember.addClickHandler(handler);
}
public String getText() {
- String s = nameTxtBox.getText();
- return s == null ? "" : s;
+ return suggestBox.getText();
}
public void setEnabled(boolean enabled) {
addMember.setEnabled(enabled);
- nameTxtBox.setEnabled(enabled);
+ suggestBox.setEnabled(enabled);
}
public void setText(String text) {
- nameTxtBox.setText(text);
- }
-
- private void doAdd() {
- addMember.fireEvent(new ClickEvent() {});
+ suggestBox.setText(text);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FilteredUserInterface.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FilteredUserInterface.java
deleted file mode 100644
index 3ea7acc..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FilteredUserInterface.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.ui;
-
-public interface FilteredUserInterface {
- /**
- * Return the value by which the user interface is currently filtered.
- *
- * @return value by which the user interface is currently filtered,
- * {@code null} or empty String if currently no filter is applied
- */
- public String getCurrentFilter();
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/IgnoreOutdatedFilterResultsCallbackWrapper.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/IgnoreOutdatedFilterResultsCallbackWrapper.java
deleted file mode 100644
index c9cadcc..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/IgnoreOutdatedFilterResultsCallbackWrapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.ui;
-
-import com.google.gerrit.client.rpc.GerritCallback;
-
-/**
- * GerritCallback to be used on user interfaces that allow filtering to handle
- * RPC's that request filtering. The user may change the filter quickly so that
- * a response may be outdated when the client receives it. In this case the
- * response must be ignored because the responses to RCP's may come out-of-order
- * and an outdated response would overwrite the correct result which was
- * received before.
- */
-public class IgnoreOutdatedFilterResultsCallbackWrapper<T> extends GerritCallback<T> {
- private final FilteredUserInterface filteredUI;
- private final String myFilter;
- private final GerritCallback<T> cb;
-
- public IgnoreOutdatedFilterResultsCallbackWrapper(
- final FilteredUserInterface filteredUI, final GerritCallback<T> cb) {
- this.filteredUI = filteredUI;
- this.myFilter = filteredUI.getCurrentFilter();
- this.cb = cb;
- }
-
- @Override
- public void onSuccess(final T result) {
- if ((myFilter == null && filteredUI.getCurrentFilter() == null)
- || (myFilter != null && myFilter.equals(filteredUI.getCurrentFilter()))) {
- cb.onSuccess(result);
- }
- // Else ignore the result, the user has already changed the filter
- // and the result is not relevant anymore. If multiple RPC's are
- // fired the results may come back out-of-order and a non-relevant
- // result could overwrite the correct result if not ignored.
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
index e11d11c..e254f6e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
@@ -21,26 +21,22 @@
import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.SuggestBox;
-import com.google.gwtexpui.globalkey.client.NpTextBox;
import java.util.HashSet;
import java.util.Set;
public class ParentProjectBox extends Composite {
- private final NpTextBox textBox;
- private final SuggestBox suggestBox;
+ private final RemoteSuggestBox suggestBox;
private final ParentProjectNameSuggestOracle suggestOracle;
public ParentProjectBox() {
- textBox = new NpTextBox();
suggestOracle = new ParentProjectNameSuggestOracle();
- suggestBox = new SuggestBox(suggestOracle, textBox);
+ suggestBox = new RemoteSuggestBox(suggestOracle);
initWidget(suggestBox);
}
public void setVisibleLength(int len) {
- textBox.setVisibleLength(len);
+ suggestBox.setVisibleLength(len);
}
public void setProject(final Project.NameKey project) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
index a7928d7..dc27790 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
@@ -35,13 +35,14 @@
import com.google.gwtexpui.globalkey.client.NpTextBox;
import com.google.gwtexpui.user.client.PluginSafeDialogBox;
-/** It creates a popup containing all the projects. */
-public class ProjectListPopup implements FilteredUserInterface {
+/** A popup containing all projects. */
+public class ProjectListPopup {
private HighlightingProjectsTable projectsTab;
private PluginSafeDialogBox popup;
private NpTextBox filterTxt;
private HorizontalPanel filterPanel;
- private String subname;
+ private String match;
+ private Query query;
private Button close;
private ScrollPanel sp;
private PopupPanel.PositionCallback popupPosition;
@@ -117,12 +118,16 @@
filterLabel.setStyleName(Gerrit.RESOURCES.css().projectFilterLabel());
filterPanel.add(filterLabel);
filterTxt = new NpTextBox();
- filterTxt.setValue(subname);
filterTxt.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
- subname = filterTxt.getValue();
- populateProjects();
+ Query q = new Query(filterTxt.getValue());
+ if (!match.equals(q.qMatch)) {
+ if (query == null) {
+ q.run();
+ }
+ query = q;
+ }
}
});
filterPanel.add(filterTxt);
@@ -158,7 +163,8 @@
public void displayPopup() {
poppingUp = true;
if (firstPopupLoad) { // For sizing/positioning, delay display until loaded
- populateProjects();
+ match = "";
+ query = new Query(match).run();
} else {
popup.setPopupPositionAndShow(popupPosition);
GlobalKey.dialog(popup);
@@ -183,23 +189,39 @@
this.preferredLeft = left;
}
- protected void populateProjects() {
- ProjectMap.match(subname,
- new IgnoreOutdatedFilterResultsCallbackWrapper<>(this,
- new GerritCallback<ProjectMap>() {
- @Override
- public void onSuccess(final ProjectMap result) {
- projectsTab.display(result, subname);
- if (firstPopupLoad) { // Display was delayed until table was loaded
- firstPopupLoad = false;
- displayPopup();
- }
- }
- }));
- }
+ private class Query {
+ private final String qMatch;
- @Override
- public String getCurrentFilter() {
- return subname;
+ Query(String match) {
+ this.qMatch = match;
+ }
+
+ Query run() {
+ ProjectMap.match(qMatch, new GerritCallback<ProjectMap>() {
+ @Override
+ public void onSuccess(ProjectMap result) {
+ if (!firstPopupLoad && !popup.isShowing()) {
+ query = null;
+ } else if (query == Query.this) {
+ query = null;
+ showMap(result);
+ } else {
+ query.run();
+ }
+ }
+ });
+ return this;
+ }
+
+ private void showMap(ProjectMap result) {
+ ProjectListPopup.this.match = qMatch;
+ projectsTab.display(result, qMatch);
+
+ if (firstPopupLoad) {
+ // Display was delayed until table was loaded
+ firstPopupLoad = false;
+ displayPopup();
+ }
+ }
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java
index 80364cf..49120f6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java
@@ -14,7 +14,6 @@
package com.google.gerrit.client.ui;
-import com.google.gerrit.client.RpcStatus;
import com.google.gerrit.client.projects.ProjectMap;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
@@ -23,17 +22,12 @@
public class ProjectNameSuggestOracle extends SuggestAfterTypingNCharsOracle {
@Override
public void _onRequestSuggestions(final Request req, final Callback callback) {
- RpcStatus.hide(new Runnable() {
- @Override
- public void run() {
- ProjectMap.suggest(req.getQuery(), req.getLimit(),
- new GerritCallback<ProjectMap>() {
- @Override
- public void onSuccess(ProjectMap map) {
- callback.onSuggestionsReady(req, new Response(Natives.asList(map.values())));
- }
- });
- }
- });
+ ProjectMap.suggest(req.getQuery(), req.getLimit(),
+ new GerritCallback<ProjectMap>() {
+ @Override
+ public void onSuccess(ProjectMap map) {
+ callback.onSuggestionsReady(req, new Response(Natives.asList(map.values())));
+ }
+ });
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RPCSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RPCSuggestOracle.java
deleted file mode 100644
index be58080..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RPCSuggestOracle.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2010 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.ui;
-
-import com.google.gwt.user.client.ui.SuggestOracle;
-
-/** This class will proxy SuggestOracle requests to another SuggestOracle
- * while keeping track of the latest request. Any repsonse that belongs
- * to a request which is not the latest request will be dropped to prevent
- * invalid deliveries.
- */
-
-public class RPCSuggestOracle extends SuggestOracle {
-
- private SuggestOracle oracle;
- private SuggestOracle.Request request;
- private SuggestOracle.Callback callback;
- private SuggestOracle.Callback myCallback = new SuggestOracle.Callback() {
- @Override
- public void onSuggestionsReady(SuggestOracle.Request req,
- SuggestOracle.Response response) {
- if (request == req) {
- callback.onSuggestionsReady(req, response);
- request = null;
- callback = null;
- }
- }
- };
-
-
- public RPCSuggestOracle(SuggestOracle ora) {
- oracle = ora;
- }
-
- @Override
- public void requestSuggestions(SuggestOracle.Request req,
- SuggestOracle.Callback cb) {
- request = req;
- callback = cb;
- oracle.requestSuggestions(req, myCallback);
- }
-
- @Override
- public boolean isDisplayStringHTML() {
- return oracle.isDisplayStringHTML();
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestBox.java
new file mode 100644
index 0000000..50f991c
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestBox.java
@@ -0,0 +1,137 @@
+// Copyright (C) 2014 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.ui;
+
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.event.logical.shared.HasCloseHandlers;
+import com.google.gwt.event.logical.shared.HasSelectionHandlers;
+import com.google.gwt.event.logical.shared.SelectionEvent;
+import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Focusable;
+import com.google.gwt.user.client.ui.HasText;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
+import com.google.gwt.user.client.ui.SuggestOracle;
+import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
+import com.google.gwt.user.client.ui.TextBoxBase;
+
+public class RemoteSuggestBox extends Composite implements Focusable, HasText,
+ HasSelectionHandlers<String>, HasCloseHandlers<RemoteSuggestBox> {
+ private final RemoteSuggestOracle remoteSuggestOracle;
+ private final DefaultSuggestionDisplay display;
+ private final HintTextBox textBox;
+ private final SuggestBox suggestBox;
+ private boolean submitOnSelection;
+
+ public RemoteSuggestBox(SuggestOracle oracle) {
+ remoteSuggestOracle = new RemoteSuggestOracle(oracle);
+ display = new DefaultSuggestionDisplay();
+
+ textBox = new HintTextBox();
+ textBox.addKeyDownHandler(new KeyDownHandler() {
+ @Override
+ public void onKeyDown(KeyDownEvent e) {
+ submitOnSelection = false;
+
+ if (e.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
+ CloseEvent.fire(RemoteSuggestBox.this, RemoteSuggestBox.this);
+ } else if (e.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
+ if (display.isSuggestionListShowing()) {
+ if (textBox.getValue().equals(remoteSuggestOracle.getLast())) {
+ submitOnSelection = true;
+ } else {
+ display.hideSuggestions();
+ }
+ } else {
+ SelectionEvent.fire(RemoteSuggestBox.this, getText());
+ }
+ }
+ }
+ });
+
+ suggestBox = new SuggestBox(remoteSuggestOracle, textBox, display);
+ suggestBox.addSelectionHandler(new SelectionHandler<Suggestion>() {
+ @Override
+ public void onSelection(SelectionEvent<Suggestion> event) {
+ textBox.setFocus(true);
+ if (submitOnSelection) {
+ SelectionEvent.fire(RemoteSuggestBox.this, getText());
+ }
+ }
+ });
+ initWidget(suggestBox);
+ }
+
+ public void setHintText(String hint) {
+ textBox.setHintText(hint);
+ }
+
+ public void setVisibleLength(int len) {
+ textBox.setVisibleLength(len);
+ }
+
+ public void setEnabled(boolean enabled) {
+ suggestBox.setEnabled(enabled);
+ }
+
+ public TextBoxBase getTextBox() {
+ return textBox;
+ }
+
+ @Override
+ public String getText() {
+ return suggestBox.getText();
+ }
+
+ @Override
+ public void setText(String value) {
+ suggestBox.setText(value);
+ }
+
+ @Override
+ public void setFocus(boolean focus) {
+ suggestBox.setFocus(focus);
+ }
+
+ @Override
+ public int getTabIndex() {
+ return suggestBox.getTabIndex();
+ }
+
+ @Override
+ public void setAccessKey(char key) {
+ suggestBox.setAccessKey(key);
+ }
+
+ @Override
+ public void setTabIndex(int index) {
+ suggestBox.setTabIndex(index);
+ }
+
+ @Override
+ public HandlerRegistration addSelectionHandler(SelectionHandler<String> h) {
+ return addHandler(h, SelectionEvent.getType());
+ }
+
+ @Override
+ public HandlerRegistration addCloseHandler(CloseHandler<RemoteSuggestBox> h) {
+ return addHandler(h, CloseEvent.getType());
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java
new file mode 100644
index 0000000..9554ac5
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java
@@ -0,0 +1,85 @@
+// Copyright (C) 2010 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.ui;
+
+import com.google.gwt.user.client.ui.SuggestOracle;
+
+/**
+ * Delegates to a slow SuggestOracle, such as a remote server API.
+ * <p>
+ * A response is only supplied to the UI if no requests were made after the
+ * oracle begin that request.
+ * <p>
+ * When a request is made while the delegate is still processing a prior request
+ * all intermediate requests are discarded and the most recent request is
+ * queued. The pending request's response is discarded and the most recent
+ * request is started.
+ */
+public class RemoteSuggestOracle extends SuggestOracle {
+ private final SuggestOracle oracle;
+ private Query query;
+ private String last;
+
+ public RemoteSuggestOracle(SuggestOracle src) {
+ oracle = src;
+ }
+
+ public String getLast() {
+ return last;
+ }
+
+ @Override
+ public void requestSuggestions(Request req, Callback cb) {
+ Query q = new Query(req, cb);
+ if (query == null) {
+ q.start();
+ }
+ query = q;
+ }
+
+ @Override
+ public boolean isDisplayStringHTML() {
+ return oracle.isDisplayStringHTML();
+ }
+
+ private class Query implements Callback {
+ final Request request;
+ final Callback callback;
+
+ Query(Request req, Callback cb) {
+ request = req;
+ callback = cb;
+ }
+
+ void start() {
+ oracle.requestSuggestions(request, this);
+ }
+
+ @Override
+ public void onSuggestionsReady(Request req, Response res) {
+ if (query == this) {
+ // No new request was started while this query was running.
+ // Propose this request's response as the suggestions.
+ query = null;
+ last = request.getQuery();
+ callback.onSuggestionsReady(req, res);
+ } else {
+ // Another query came in while this one was running. Skip
+ // this response and start the most recent query.
+ query.start();
+ }
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java
deleted file mode 100644
index 23c8b8f..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (C) 2011 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.ui;
-
-import com.google.gerrit.client.FormatUtil;
-import com.google.gerrit.client.RpcStatus;
-import com.google.gerrit.client.admin.Util;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.common.data.AccountInfo;
-import com.google.gerrit.common.data.ReviewerInfo;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gwt.user.client.ui.SuggestOracle;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Suggestion Oracle for reviewers. */
-public class ReviewerSuggestOracle extends SuggestAfterTypingNCharsOracle {
-
- private Change.Id changeId;
-
- @Override
- protected void _onRequestSuggestions(final Request req, final Callback callback) {
- RpcStatus.hide(new Runnable() {
- @Override
- public void run() {
- SuggestUtil.SVC.suggestChangeReviewer(changeId, req.getQuery(),
- req.getLimit(), new GerritCallback<List<ReviewerInfo>>() {
- @Override
- public void onSuccess(final List<ReviewerInfo> result) {
- final List<ReviewerSuggestion> r =
- new ArrayList<>(result.size());
- for (final ReviewerInfo reviewer : result) {
- r.add(new ReviewerSuggestion(reviewer));
- }
- callback.onSuggestionsReady(req, new Response(r));
- }
- });
- }
- });
- }
-
- public void setChange(Change.Id changeId) {
- this.changeId = changeId;
- }
-
- private static class ReviewerSuggestion implements SuggestOracle.Suggestion {
- private final ReviewerInfo reviewerInfo;
-
- ReviewerSuggestion(final ReviewerInfo reviewerInfo) {
- this.reviewerInfo = reviewerInfo;
- }
-
- @Override
- public String getDisplayString() {
- final AccountInfo accountInfo = reviewerInfo.getAccountInfo();
- if (accountInfo != null) {
- return FormatUtil.nameEmail(FormatUtil.asInfo(accountInfo));
- }
- return reviewerInfo.getGroup().getName() + " ("
- + Util.C.suggestedGroupLabel() + ")";
- }
-
- @Override
- public String getReplacementString() {
- final AccountInfo accountInfo = reviewerInfo.getAccountInfo();
- if (accountInfo != null) {
- return FormatUtil.nameEmail(FormatUtil.asInfo(accountInfo));
- }
- return reviewerInfo.getGroup().getName();
- }
- }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
index ff64c3c..69db233 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
@@ -17,170 +17,34 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.common.Nullable;
-import com.google.gerrit.common.data.AccountInfo;
import com.google.gerrit.common.data.GroupReference;
-import com.google.gerrit.common.data.ReviewerInfo;
import com.google.gerrit.common.data.SuggestService;
-import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountExternalId;
-import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.AccountControl;
-import com.google.gerrit.server.account.AccountVisibility;
import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.account.GroupMembers;
-import com.google.gerrit.server.change.PostReviewers;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import org.eclipse.jgit.lib.Config;
-
-import java.io.IOException;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
class SuggestServiceImpl extends BaseServiceImplementation implements
SuggestService {
- private static final String MAX_SUFFIX = "\u9fa5";
-
- private final Provider<ReviewDb> reviewDbProvider;
- private final AccountCache accountCache;
- private final GroupMembers.Factory groupMembersFactory;
- private final IdentifiedUser.GenericFactory identifiedUserFactory;
- private final AccountControl.Factory accountControlFactory;
- private final ChangeControl.Factory changeControlFactory;
private final ProjectControl.Factory projectControlFactory;
- private final Config cfg;
private final GroupBackend groupBackend;
- private final boolean suggestAccounts;
@Inject
SuggestServiceImpl(final Provider<ReviewDb> schema,
- final AccountCache accountCache,
- final GroupMembers.Factory groupMembersFactory,
final Provider<CurrentUser> currentUser,
- final IdentifiedUser.GenericFactory identifiedUserFactory,
- final AccountControl.Factory accountControlFactory,
- final ChangeControl.Factory changeControlFactory,
final ProjectControl.Factory projectControlFactory,
- @GerritServerConfig final Config cfg, final GroupBackend groupBackend) {
+ final GroupBackend groupBackend) {
super(schema, currentUser);
- this.reviewDbProvider = schema;
- this.accountCache = accountCache;
- this.groupMembersFactory = groupMembersFactory;
- this.identifiedUserFactory = identifiedUserFactory;
- this.accountControlFactory = accountControlFactory;
- this.changeControlFactory = changeControlFactory;
this.projectControlFactory = projectControlFactory;
- this.cfg = cfg;
this.groupBackend = groupBackend;
-
- if ("OFF".equals(cfg.getString("suggest", null, "accounts"))) {
- this.suggestAccounts = false;
- } else {
- boolean suggestAccounts;
- try {
- AccountVisibility av =
- cfg.getEnum("suggest", null, "accounts", AccountVisibility.ALL);
- suggestAccounts = (av != AccountVisibility.NONE);
- } catch (IllegalArgumentException err) {
- suggestAccounts = cfg.getBoolean("suggest", null, "accounts", true);
- }
- this.suggestAccounts = suggestAccounts;
- }
- }
-
- private interface VisibilityControl {
- boolean isVisible(Account account) throws OrmException;
- }
-
- @Override
- public void suggestAccount(final String query, final Boolean active,
- final int limit, final AsyncCallback<List<AccountInfo>> callback) {
- run(callback, new Action<List<AccountInfo>>() {
- @Override
- public List<AccountInfo> run(final ReviewDb db) throws OrmException {
- return suggestAccount(db, query, active, limit, new VisibilityControl() {
- @Override
- public boolean isVisible(Account account) throws OrmException {
- return accountControlFactory.get().canSee(account);
- }
- });
- }
- });
- }
-
- private List<AccountInfo> suggestAccount(final ReviewDb db,
- final String query, final Boolean active, final int limit,
- VisibilityControl visibilityControl)
- throws OrmException {
- if (!suggestAccounts) {
- return Collections.emptyList();
- }
-
- final String a = query;
- final String b = a + MAX_SUFFIX;
- final int max = 10;
- final int n = limit <= 0 ? max : Math.min(limit, max);
-
- LinkedHashMap<Account.Id, AccountInfo> r = new LinkedHashMap<>();
- for (final Account p : db.accounts().suggestByFullName(a, b, n)) {
- addSuggestion(r, p, new AccountInfo(p), active, visibilityControl);
- }
- if (r.size() < n) {
- for (final Account p : db.accounts().suggestByPreferredEmail(a, b,
- n - r.size())) {
- addSuggestion(r, p, new AccountInfo(p), active, visibilityControl);
- }
- }
- if (r.size() < n) {
- for (final AccountExternalId e : db.accountExternalIds()
- .suggestByEmailAddress(a, b, n - r.size())) {
- if (!r.containsKey(e.getAccountId())) {
- final Account p = accountCache.get(e.getAccountId()).getAccount();
- final AccountInfo info = new AccountInfo(p);
- info.setPreferredEmail(e.getEmailAddress());
- addSuggestion(r, p, info, active, visibilityControl);
- }
- }
- }
- return new ArrayList<>(r.values());
- }
-
- private void addSuggestion(Map<Account.Id, AccountInfo> map, Account account,
- AccountInfo info, Boolean active, VisibilityControl visibilityControl)
- throws OrmException {
- if (map.containsKey(account.getId())) {
- return;
- }
- if (active != null && active != account.isActive()) {
- return;
- }
- if (visibilityControl.isVisible(account)) {
- map.put(account.getId(), info);
- }
- }
-
- @Override
- public void suggestAccountGroup(final String query, final int limit,
- final AsyncCallback<List<GroupReference>> callback) {
- suggestAccountGroupForProject(null, query, limit, callback);
}
@Override
@@ -209,103 +73,4 @@
groupBackend.suggest(query, projectControl),
limit <= 0 ? 10 : Math.min(limit, 10)));
}
-
- @Override
- public void suggestReviewer(Project.NameKey project, String query, int limit,
- AsyncCallback<List<ReviewerInfo>> callback) {
- // The RPC is deprecated, but return an empty list for RPC API compatibility.
- callback.onSuccess(Collections.<ReviewerInfo>emptyList());
- }
-
- @Override
- public void suggestChangeReviewer(final Change.Id change,
- final String query, final int limit,
- final AsyncCallback<List<ReviewerInfo>> callback) {
- run(callback, new Action<List<ReviewerInfo>>() {
- @Override
- public List<ReviewerInfo> run(final ReviewDb db)
- throws OrmException, Failure {
- final ChangeControl changeControl;
- try {
- changeControl = changeControlFactory.controlFor(change);
- } catch (NoSuchChangeException e) {
- return Collections.emptyList();
- }
-
- VisibilityControl visibilityControl;
- if (changeControl.getRefControl().isVisibleByRegisteredUsers()) {
- visibilityControl = new VisibilityControl() {
- @Override
- public boolean isVisible(Account account) throws OrmException {
- return true;
- }
- };
- } else {
- visibilityControl = new VisibilityControl() {
- @Override
- public boolean isVisible(Account account) throws OrmException {
- IdentifiedUser who =
- identifiedUserFactory.create(reviewDbProvider, account.getId());
- // we can't use changeControl directly as it won't suggest reviewers
- // to drafts
- return changeControl.forUser(who).isRefVisible();
- }
- };
- }
-
- final List<AccountInfo> suggestedAccounts =
- suggestAccount(db, query, Boolean.TRUE, limit, visibilityControl);
- final List<ReviewerInfo> reviewer =
- new ArrayList<>(suggestedAccounts.size());
- for (final AccountInfo a : suggestedAccounts) {
- reviewer.add(new ReviewerInfo(a));
- }
- final List<GroupReference> suggestedAccountGroups =
- suggestAccountGroup(changeControl.getProjectControl(), query, limit);
- for (final GroupReference g : suggestedAccountGroups) {
- if (suggestGroupAsReviewer(changeControl.getProject().getNameKey(), g)) {
- reviewer.add(new ReviewerInfo(g));
- }
- }
-
- Collections.sort(reviewer);
- if (reviewer.size() <= limit) {
- return reviewer;
- } else {
- return reviewer.subList(0, limit);
- }
- }
- });
- }
-
- private boolean suggestGroupAsReviewer(final Project.NameKey project,
- final GroupReference group) throws OrmException, Failure {
- if (!PostReviewers.isLegalReviewerGroup(group.getUUID())) {
- return false;
- }
-
- try {
- final Set<Account> members = groupMembersFactory.create(getCurrentUser())
- .listAccounts(group.getUUID(), project);
-
- if (members.isEmpty()) {
- return false;
- }
-
- final int maxAllowed =
- cfg.getInt("addreviewer", "maxAllowed",
- PostReviewers.DEFAULT_MAX_REVIEWERS);
- if (maxAllowed > 0 && members.size() > maxAllowed) {
- return false;
- }
- } catch (NoSuchGroupException e) {
- return false;
- } catch (NoSuchProjectException e) {
- return false;
- } catch (IOException e) {
- throw new Failure(e);
- }
-
- return true;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java b/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java
index 588d4d0..173c4bd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java
@@ -27,6 +27,7 @@
import com.google.gerrit.extensions.webui.PatchSetWebLink;
import com.google.gerrit.extensions.webui.ProjectWebLink;
import com.google.gerrit.extensions.webui.WebLink;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -78,13 +79,13 @@
* @param commit SHA1 of commit.
* @return Links for patch sets.
*/
- public FluentIterable<WebLinkInfo> getPatchSetLinks(final String project,
+ public FluentIterable<WebLinkInfo> getPatchSetLinks(final Project.NameKey project,
final String commit) {
return filterLinks(patchSetLinks, new Function<WebLink, WebLinkInfo>() {
@Override
public WebLinkInfo apply(WebLink webLink) {
- return ((PatchSetWebLink)webLink).getPathSetWebLink(project, commit);
+ return ((PatchSetWebLink)webLink).getPathSetWebLink(project.get(), commit);
}
});
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
index 6394a5b..cc62b2b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -121,6 +121,7 @@
private static AccountState missing(Account.Id accountId) {
Account account = new Account(accountId, TimeUtil.nowTs());
+ account.setActive(false);
Collection<AccountExternalId> ids = Collections.emptySet();
Set<AccountGroup.UUID> anon = ImmutableSet.of();
return new AccountState(account, anon, ids);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
index 5ef745b..efe7322 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
@@ -40,6 +40,7 @@
private final AccountResolver resolver;
private final AccountControl.Factory accountControlFactory;
private final IdentifiedUser.GenericFactory userFactory;
+ private final Provider<SuggestAccounts> list;
private final DynamicMap<RestView<AccountResource>> views;
private final CreateAccount.Factory createAccountFactory;
@@ -48,12 +49,14 @@
AccountResolver resolver,
AccountControl.Factory accountControlFactory,
IdentifiedUser.GenericFactory userFactory,
+ Provider<SuggestAccounts> list,
DynamicMap<RestView<AccountResource>> views,
CreateAccount.Factory createAccountFactory) {
this.self = self;
this.resolver = resolver;
this.accountControlFactory = accountControlFactory;
this.userFactory = userFactory;
+ this.list = list;
this.views = views;
this.createAccountFactory = createAccountFactory;
}
@@ -128,7 +131,7 @@
@Override
public RestView<TopLevelResource> list() throws ResourceNotFoundException {
- throw new ResourceNotFoundException();
+ return list.get();
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java
new file mode 100644
index 0000000..07936d9
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java
@@ -0,0 +1,156 @@
+// Copyright (C) 2014 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.server.account;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.lib.Config;
+import org.kohsuke.args4j.Option;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+class SuggestAccounts implements RestReadView<TopLevelResource> {
+ private static final int MAX_RESULTS = 100;
+ private static final String MAX_SUFFIX = "\u9fa5";
+
+ private final AccountControl accountControl;
+ private final AccountLoader accountLoader;
+ private final ReviewDb db;
+ private final boolean suggest;
+ private final int suggestFrom;
+
+ private int limit = 10;
+
+ @Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of users to return")
+ void setLimit(int n) {
+ if (n < 0) {
+ limit = 10;
+ } else if (n == 0) {
+ limit = MAX_RESULTS;
+ } else {
+ limit = Math.min(n, MAX_RESULTS);
+ }
+ }
+
+ @Option(name = "--query", aliases = {"-q"}, metaVar = "QUERY", usage = "match users")
+ private String query;
+
+ @Inject
+ SuggestAccounts(AccountControl.Factory accountControlFactory,
+ AccountLoader.Factory accountLoaderFactory,
+ ReviewDb db,
+ @GerritServerConfig Config cfg) {
+ accountControl = accountControlFactory.get();
+ accountLoader = accountLoaderFactory.create(true);
+ this.db = db;
+ this.suggestFrom = cfg.getInt("suggest", null, "from", 0);
+
+ if ("off".equalsIgnoreCase(cfg.getString("suggest", null, "accounts"))) {
+ suggest = false;
+ } else {
+ boolean suggest;
+ try {
+ AccountVisibility av =
+ cfg.getEnum("suggest", null, "accounts", AccountVisibility.ALL);
+ suggest = (av != AccountVisibility.NONE);
+ } catch (IllegalArgumentException err) {
+ suggest = cfg.getBoolean("suggest", null, "accounts", true);
+ }
+ this.suggest = suggest;
+ }
+ }
+
+ @Override
+ public List<AccountInfo> apply(TopLevelResource rsrc)
+ throws OrmException, BadRequestException {
+ if (Strings.isNullOrEmpty(query)) {
+ throw new BadRequestException("missing query field");
+ }
+
+ if (!suggest || query.length() < suggestFrom) {
+ return Collections.emptyList();
+ }
+
+ String a = query;
+ String b = a + MAX_SUFFIX;
+
+ Map<Account.Id, AccountInfo> matches = new LinkedHashMap<>();
+ Map<Account.Id, String> queryEmail = new HashMap<>();
+
+ for (Account p : db.accounts().suggestByFullName(a, b, limit)) {
+ addSuggestion(matches, p.getId());
+ }
+ if (matches.size() < limit) {
+ for (Account p : db.accounts()
+ .suggestByPreferredEmail(a, b, limit - matches.size())) {
+ addSuggestion(matches, p.getId());
+ }
+ }
+ if (matches.size() < limit) {
+ for (AccountExternalId e : db.accountExternalIds()
+ .suggestByEmailAddress(a, b, limit - matches.size())) {
+ if (addSuggestion(matches, e.getAccountId())) {
+ queryEmail.put(e.getAccountId(), e.getEmailAddress());
+ }
+ }
+ }
+
+ accountLoader.fill();
+ for (Map.Entry<Account.Id, String> p : queryEmail.entrySet()) {
+ AccountInfo info = matches.get(p.getKey());
+ if (info != null) {
+ info.email = p.getValue();
+ }
+ }
+
+ List<AccountInfo> m = new ArrayList<>(matches.values());
+ Collections.sort(m, new Comparator<AccountInfo>() {
+ @Override
+ public int compare(AccountInfo a, AccountInfo b) {
+ return ComparisonChain.start()
+ .compare(a.name, b.name, Ordering.natural().nullsLast())
+ .compare(a.email, b.email, Ordering.natural().nullsLast())
+ .result();
+ }
+ });
+ return m;
+ }
+
+ private boolean addSuggestion(Map<Account.Id, AccountInfo> map, Account.Id id) {
+ if (!map.containsKey(id) && accountControl.canSee(id)) {
+ map.put(id, accountLoader.get(id));
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 0a7005c..e69f90c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -84,6 +84,7 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.PatchSetInfo.ParentInfo;
import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -407,7 +408,7 @@
if (has(ALL_REVISIONS)
|| has(CURRENT_REVISION)
|| limitToPsId.isPresent()) {
- out.revisions = revisions(ctl, cd, out.project, src);
+ out.revisions = revisions(ctl, cd, src);
if (out.revisions != null) {
for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) {
if (entry.getValue().isCurrent) {
@@ -837,13 +838,13 @@
}
private Map<String, RevisionInfo> revisions(ChangeControl ctl, ChangeData cd,
- String project, Map<PatchSet.Id, PatchSet> map) throws OrmException {
+ Map<PatchSet.Id, PatchSet> map) throws OrmException {
Map<String, RevisionInfo> res = Maps.newLinkedHashMap();
for (PatchSet in : map.values()) {
if ((has(ALL_REVISIONS)
|| in.getId().equals(cd.change().currentPatchSetId()))
&& ctl.isPatchVisible(in, db.get())) {
- res.put(in.getRevision().get(), toRevisionInfo(ctl, cd, in, project));
+ res.put(in.getRevision().get(), toRevisionInfo(ctl, cd, in));
}
}
return res;
@@ -878,7 +879,7 @@
}
private RevisionInfo toRevisionInfo(ChangeControl ctl, ChangeData cd,
- PatchSet in, String project) throws OrmException {
+ PatchSet in) throws OrmException {
RevisionInfo out = new RevisionInfo();
out.isCurrent = in.getId().equals(cd.change().currentPatchSetId());
out._number = in.getId().get();
@@ -888,7 +889,7 @@
if (has(ALL_COMMITS) || (out.isCurrent && has(CURRENT_COMMIT))) {
try {
- out.commit = toCommit(in);
+ out.commit = toCommit(in, cd.change().getProject(), has(WEB_LINKS));
} catch (PatchSetInfoNotAvailableException e) {
log.warn("Cannot load PatchSetInfo " + in.getId(), e);
}
@@ -924,16 +925,10 @@
? true
: null;
}
-
- if (has(WEB_LINKS)) {
- FluentIterable<WebLinkInfo> links =
- webLinks.getPatchSetLinks(project, in.getRevision().get());
- out.webLinks = links.isEmpty() ? null : links.toList();
- }
return out;
}
- CommitInfo toCommit(PatchSet in)
+ CommitInfo toCommit(PatchSet in, Project.NameKey project, boolean addLinks)
throws PatchSetInfoNotAvailableException {
PatchSetInfo info = patchSetInfoFactory.get(db.get(), in.getId());
CommitInfo commit = new CommitInfo();
@@ -942,10 +937,22 @@
commit.committer = toGitPerson(info.getCommitter());
commit.subject = info.getSubject();
commit.message = info.getMessage();
+
+ if (addLinks) {
+ FluentIterable<WebLinkInfo> links =
+ webLinks.getPatchSetLinks(project, in.getRevision().get());
+ commit.webLinks = links.isEmpty() ? null : links.toList();
+ }
+
for (ParentInfo parent : info.getParents()) {
CommitInfo i = new CommitInfo();
i.commit = parent.id.get();
i.subject = parent.shortMessage;
+ if (addLinks) {
+ FluentIterable<WebLinkInfo> parentLinks =
+ webLinks.getPatchSetLinks(project, parent.id.get());
+ i.webLinks = parentLinks.isEmpty() ? null : parentLinks.toList();
+ }
commit.parents.add(i);
}
return commit;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
index 2cd948e..6f41a86 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
@@ -22,14 +22,17 @@
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
-import com.google.inject.Singleton;
+
+import org.kohsuke.args4j.Option;
import java.util.concurrent.TimeUnit;
-@Singleton
public class GetCommit implements RestReadView<RevisionResource> {
private final ChangeJson json;
+ @Option(name = "--links", usage = "Add weblinks")
+ private boolean addLinks;
+
@Inject
GetCommit(ChangeJson json) {
this.json = json;
@@ -40,7 +43,8 @@
throws ResourceNotFoundException, OrmException {
try {
Response<CommitInfo> r =
- Response.ok(json.toCommit(resource.getPatchSet()));
+ Response.ok(json.toCommit(resource.getPatchSet(), resource
+ .getChange().getProject(), addLinks));
if (resource.isCacheable()) {
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
index 077ec6f1..6056e5f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
@@ -20,11 +20,13 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.common.ChangeStatus;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CommonConverters;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -119,6 +121,18 @@
if (p != null) {
g = changes.get(p.getId().getParentKey());
added.add(p.getId().getParentKey());
+ } else {
+ // check if there is a merged or abandoned change for this commit
+ ReviewDb db = dbProvider.get();
+ for (PatchSet ps : db.patchSets().byRevision(new RevId(c.name())).toList()) {
+ Change change = db.changes().get(ps.getId().getParentKey());
+ if (change != null && change.getDest().equals(rsrc.getChange().getDest())) {
+ p = ps;
+ g = change;
+ added.add(g.getId());
+ break;
+ }
+ }
}
parents.add(new ChangeAndCommit(g, p, c));
}
@@ -278,6 +292,7 @@
public static class ChangeAndCommit {
public String changeId;
+ public ChangeStatus status;
public CommitInfo commit;
public Integer _changeNumber;
public Integer _revisionNumber;
@@ -286,6 +301,7 @@
ChangeAndCommit(@Nullable Change change, @Nullable PatchSet ps, RevCommit c) {
if (change != null) {
changeId = change.getKey().get();
+ status = change.getStatus().asChangeStatus();
_changeNumber = change.getChangeId();
_revisionNumber = ps != null ? ps.getPatchSetId() : null;
PatchSet.Id curr = change.currentPatchSetId();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java
index e458145..83fa938 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java
@@ -14,10 +14,12 @@
package com.google.gerrit.server.change;
+import com.google.common.base.Predicate;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.inject.Inject;
@@ -50,7 +52,14 @@
.build(new CacheLoader<Boolean, List<Account>>() {
@Override
public List<Account> load(Boolean key) throws Exception {
- return ImmutableList.copyOf(dbProvider.get().accounts().all());
+ return ImmutableList.copyOf(Iterables.filter(
+ dbProvider.get().accounts().all(),
+ new Predicate<Account>() {
+ @Override
+ public boolean apply(Account in) {
+ return in.isActive();
+ }
+ }));
}
});
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/SuggestReviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/SuggestReviewers.java
index a6b3945..ce22034 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/SuggestReviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/SuggestReviewers.java
@@ -18,7 +18,6 @@
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.extensions.common.AccountInfo;
@@ -49,20 +48,21 @@
import org.kohsuke.args4j.Option;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SuggestReviewers implements RestReadView<ChangeResource> {
-
private static final String MAX_SUFFIX = "\u9fa5";
private static final int DEFAULT_MAX_SUGGESTED = 10;
private static final int DEFAULT_MAX_MATCHES = 100;
- private final AccountLoader.Factory accountLoaderFactory;
- private final AccountControl.Factory accountControlFactory;
+ private final AccountLoader accountLoader;
+ private final AccountControl accountControl;
private final GroupMembers.Factory groupMembersFactory;
private final AccountCache accountCache;
private final Provider<ReviewDb> dbProvider;
@@ -105,8 +105,8 @@
@GerritServerConfig Config cfg,
GroupBackend groupBackend,
ReviewerSuggestionCache reviewerSuggestionCache) {
- this.accountLoaderFactory = accountLoaderFactory;
- this.accountControlFactory = accountControlFactory;
+ this.accountLoader = accountLoaderFactory.create(true);
+ this.accountControl = accountControlFactory.get();
this.accountCache = accountCache;
this.groupMembersFactory = groupMembersFactory;
this.dbProvider = dbProvider;
@@ -135,7 +135,7 @@
}
private interface VisibilityControl {
- boolean isVisibleTo(Account account) throws OrmException;
+ boolean isVisibleTo(Account.Id account) throws OrmException;
}
@Override
@@ -156,7 +156,6 @@
} else {
suggestedAccounts = suggestAccount(visibilityControl);
}
- accountLoaderFactory.create(true).fill(suggestedAccounts);
List<SuggestedReviewerInfo> reviewer = Lists.newArrayList();
for (AccountInfo a : suggestedAccounts) {
@@ -186,16 +185,16 @@
if (rsrc.getControl().getRefControl().isVisibleByRegisteredUsers()) {
return new VisibilityControl() {
@Override
- public boolean isVisibleTo(Account account) throws OrmException {
+ public boolean isVisibleTo(Account.Id account) throws OrmException {
return true;
}
};
} else {
return new VisibilityControl() {
@Override
- public boolean isVisibleTo(Account account) throws OrmException {
+ public boolean isVisibleTo(Account.Id account) throws OrmException {
IdentifiedUser who =
- identifiedUserFactory.create(dbProvider, account.getId());
+ identifiedUserFactory.create(dbProvider, account);
// we can't use changeControl directly as it won't suggest reviewers
// to drafts
return rsrc.getControl().forUser(who).isRefVisible();
@@ -214,16 +213,22 @@
String a = query;
String b = a + MAX_SUFFIX;
- LinkedHashMap<Account.Id, AccountInfo> r = Maps.newLinkedHashMap();
+ Map<Account.Id, AccountInfo> r = new LinkedHashMap<>();
+ Map<Account.Id, String> queryEmail = new HashMap<>();
+
for (Account p : dbProvider.get().accounts()
.suggestByFullName(a, b, limit)) {
- addSuggestion(r, p, new AccountInfo(p.getId().get()), visibilityControl);
+ if (p.isActive()) {
+ addSuggestion(r, p.getId(), visibilityControl);
+ }
}
if (r.size() < limit) {
for (Account p : dbProvider.get().accounts()
.suggestByPreferredEmail(a, b, limit - r.size())) {
- addSuggestion(r, p, new AccountInfo(p.getId().get()), visibilityControl);
+ if (p.isActive()) {
+ addSuggestion(r, p.getId(), visibilityControl);
+ }
}
}
@@ -232,21 +237,32 @@
.suggestByEmailAddress(a, b, limit - r.size())) {
if (!r.containsKey(e.getAccountId())) {
Account p = accountCache.get(e.getAccountId()).getAccount();
- AccountInfo info = new AccountInfo(p.getId().get());
- addSuggestion(r, p, info, visibilityControl);
+ if (p.isActive()) {
+ if (addSuggestion(r, p.getId(), visibilityControl)) {
+ queryEmail.put(e.getAccountId(), e.getEmailAddress());
+ }
+ }
}
}
}
- return Lists.newArrayList(r.values());
+ accountLoader.fill();
+ for (Map.Entry<Account.Id, String> p : queryEmail.entrySet()) {
+ AccountInfo info = r.get(p.getKey());
+ if (info != null) {
+ info.email = p.getValue();
+ }
+ }
+ return new ArrayList<>(r.values());
}
private List<AccountInfo> suggestAccountFullTextSearch(
VisibilityControl visibilityControl) throws OrmException {
String str = query.toLowerCase();
- LinkedHashMap<Account.Id, AccountInfo> accountMap = Maps.newLinkedHashMap();
- List<Account> fullNameMatches = Lists.newArrayListWithCapacity(fullTextMaxMatches);
- List<Account> emailMatches = Lists.newArrayListWithCapacity(fullTextMaxMatches);
+ Map<Account.Id, AccountInfo> accountMap = new LinkedHashMap<>();
+ List<Account> fullNameMatches = new ArrayList<>(fullTextMaxMatches);
+ List<Account> emailMatches = new ArrayList<>(fullTextMaxMatches);
+
for (Account a : reviewerSuggestionCache.get()) {
if (a.getFullName() != null
&& a.getFullName().toLowerCase().contains(str)) {
@@ -261,33 +277,35 @@
}
}
for (Account a : fullNameMatches) {
- addSuggestion(accountMap, a, new AccountInfo(a.getId().get()), visibilityControl);
+ addSuggestion(accountMap, a.getId(), visibilityControl);
if (accountMap.size() >= limit) {
break;
}
}
if (accountMap.size() < limit) {
for (Account a : emailMatches) {
- addSuggestion(accountMap, a, new AccountInfo(a.getId().get()), visibilityControl);
+ addSuggestion(accountMap, a.getId(), visibilityControl);
if (accountMap.size() >= limit) {
break;
}
}
}
+ accountLoader.fill();
return Lists.newArrayList(accountMap.values());
}
- private void addSuggestion(Map<Account.Id, AccountInfo> map, Account account,
- AccountInfo info, VisibilityControl visibilityControl)
+ private boolean addSuggestion(Map<Account.Id, AccountInfo> map,
+ Account.Id account, VisibilityControl visibilityControl)
throws OrmException {
- if (!map.containsKey(account.getId())
- && account.isActive()
+ if (!map.containsKey(account)
// Can the suggestion see the change?
&& visibilityControl.isVisibleTo(account)
// Can the account see the current user?
- && accountControlFactory.get().canSee(account)) {
- map.put(account.getId(), info);
+ && accountControl.canSee(account)) {
+ map.put(account, accountLoader.get(account));
+ return true;
}
+ return false;
}
private boolean suggestGroupAsReviewer(Project project,
@@ -312,7 +330,7 @@
// require that at least one member in the group can see the change
for (Account account : members) {
- if (visibilityControl.isVisibleTo(account)) {
+ if (visibilityControl.isVisibleTo(account.getId())) {
return true;
}
}
diff --git a/lib/jgit/BUCK b/lib/jgit/BUCK
index f0ab629..1f9be46 100644
--- a/lib/jgit/BUCK
+++ b/lib/jgit/BUCK
@@ -1,12 +1,12 @@
include_defs('//lib/maven.defs')
-VERS = '3.5.1.201410131835-r'
+VERS = '3.6.0.201412230720-r'
maven_jar(
name = 'jgit',
id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
- bin_sha1 = '23b8793639407fcbe2fee8557fb8238d18b2e409',
- src_sha1 = '48ae55f9fed45e188177bcf3bf4638eed6bf3aae',
+ bin_sha1 = 'b005b69d9f5b4dba636a95403d5cb62bad5c486d',
+ src_sha1 = '9f8ced1e1f5c9ba6a3084e35004a19a24776478a',
license = 'jgit',
unsign = True,
deps = [':ewah'],
@@ -20,7 +20,7 @@
maven_jar(
name = 'jgit-servlet',
id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
- sha1 = 'ee4f9852eb62d9b0785705e4eb40e40035119da7',
+ sha1 = '92cdf015b62c8a4f8fc1f6fd8b1835931bd4b4d6',
license = 'jgit',
deps = [':jgit'],
unsign = True,
@@ -33,7 +33,7 @@
maven_jar(
name = 'jgit-archive',
id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
- sha1 = '48ddea0e3f6e78f9696e30dfc257118a446b453c',
+ sha1 = '359c1f666e4bdc2db795b6c60a7635f6be929a66',
license = 'jgit',
deps = [':jgit',
'//lib/commons:compress',
@@ -49,7 +49,7 @@
maven_jar(
name = 'junit',
id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
- sha1 = '1e8a9e7fa493e96ec6c07b9f6f51ed2d2db60b9f',
+ sha1 = 'cb029dba3fafb329078904028db171d9c460ada8',
license = 'DO_NOT_DISTRIBUTE',
unsign = True,
deps = [':jgit'],