diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt index 957e14d929..883198ad99 100644 --- a/Documentation/js-api.txt +++ b/Documentation/js-api.txt @@ -873,6 +873,10 @@ Gerrit.screen(pattern, callback); === Gerrit.refresh() Redisplays the current web UI view, refreshing all information. +[[Gerrit_refreshMenuBar]] +=== Gerrit.refreshMenuBar() +Refreshes Gerrit's menu bar. + [[Gerrit_url]] === Gerrit.url() Returns the URL of the Gerrit Code Review server. If invoked with diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt index d777db1d60..161aedfc51 100644 --- a/Documentation/rest-api-groups.txt +++ b/Documentation/rest-api-groups.txt @@ -161,6 +161,24 @@ returned. } ---- +[[group-limit]] +==== Group Limit +The `/groups/` URL also accepts a limit integer in the `n` parameter. +This limits the results to show `n` groups. + +Query the first 25 groups in group list. +---- + GET /groups/?n=25 HTTP/1.0 +---- + +The `/groups/` URL also accepts a start integer in the `S` parameter. +The results will skip `S` groups from group list. + +Query 25 groups starting from index 50. +---- + GET /groups/?n=25&S=50 HTTP/1.0 +---- + [[get-group]] === Get Group -- diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java index 9e87b48399..a92b736374 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java @@ -137,4 +137,7 @@ public interface AdminConstants extends Constants { String pagedProjectListPrev(); String pagedProjectListNext(); + + String pagedGroupListPrev(); + String pagedGroupListNext(); } diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties index 04baf49587..ef35e00718 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties @@ -102,6 +102,9 @@ errorNoGitRepository = No Git Repository pagedProjectListPrev = ⇦Prev pagedProjectListNext = Next⇨ +pagedGroupListPrev = ⇦Prev +pagedGroupListNext = Next⇨ + addPermission = Add Permission ... # Permission Names 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 bed6b4a2d0..6579f83e96 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 @@ -21,8 +21,10 @@ 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.common.PageLinks; +import com.google.gerrit.reviewdb.client.AccountGeneralPreferences; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; @@ -32,11 +34,16 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwtexpui.globalkey.client.NpTextBox; public class GroupListScreen extends AccountScreen implements FilteredUserInterface { + private Hyperlink prev; + private Hyperlink next; private GroupTable groups; private NpTextBox filterTxt; - private String subname; + private String subname = ""; + private int startPosition; + private int pageSize; public GroupListScreen() { + configurePageSize(); } public GroupListScreen(String params) { @@ -49,6 +56,22 @@ public class GroupListScreen extends AccountScreen implements FilteredUserInterf if ("filter".equals(kv[0])) { subname = URL.decodeQueryString(kv[1]); } + + if ("skip".equals(kv[0]) && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) { + startPosition = Integer.parseInt(URL.decodeQueryString(kv[1])); + } + } + configurePageSize(); + } + + private void configurePageSize() { + if (Gerrit.isSignedIn()) { + final AccountGeneralPreferences p = + Gerrit.getUserAccount().getGeneralPreferences(); + final short m = p.getMaximumPageSize(); + pageSize = 0 < m ? m : AccountGeneralPreferences.DEFAULT_PAGESIZE; + } else { + pageSize = AccountGeneralPreferences.DEFAULT_PAGESIZE; } } @@ -56,13 +79,17 @@ public class GroupListScreen extends AccountScreen implements FilteredUserInterf protected void onLoad() { super.onLoad(); display(); - refresh(false); + refresh(false, false); } - private void refresh(final boolean open) { - setToken(subname == null || "".equals(subname) ? ADMIN_GROUPS - : ADMIN_GROUPS + "?filter=" + URL.encodeQueryString(subname)); - GroupMap.match(subname, + 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() { @Override @@ -71,13 +98,45 @@ public class GroupListScreen extends AccountScreen implements FilteredUserInterf Gerrit.display(PageLinks.toGroup( result.values().get(0).getGroupUUID())); } else { - groups.display(result, subname); + 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(); } } })); } + private void setupNavigationLink(Hyperlink link, String filter, int skip) { + link.setTargetHistoryToken(getTokenForScreen(filter, skip)); + link.setVisible(true); + } + + private String getTokenForScreen(String filter, int skip) { + String token = ADMIN_GROUPS; + if (filter != null && !filter.isEmpty()) { + token += "?filter=" + URL.encodeQueryString(filter); + } + if (skip > 0) { + if (token.contains("?filter=")) { + token += ","; + } else { + token += "?"; + } + token += "skip=" + skip; + } + return token; + } + @Override public String getCurrentFilter() { return subname; @@ -89,8 +148,20 @@ public class GroupListScreen extends AccountScreen implements FilteredUserInterf setPageTitle(Util.C.groupListTitle()); initPageHeader(); + prev = new Hyperlink(Util.C.pagedGroupListPrev(), true, ""); + prev.setVisible(false); + + next = new Hyperlink(Util.C.pagedGroupListNext(), true, ""); + next.setVisible(false); + groups = new GroupTable(PageLinks.ADMIN_GROUPS); add(groups); + + final HorizontalPanel buttons = new HorizontalPanel(); + buttons.setStyleName(Gerrit.RESOURCES.css().changeTablePrevNextLinks()); + buttons.add(prev); + buttons.add(next); + add(buttons); } private void initPageHeader() { @@ -104,8 +175,13 @@ public class GroupListScreen extends AccountScreen implements FilteredUserInterf filterTxt.addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent event) { - subname = filterTxt.getValue(); - refresh(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER); + boolean enterPressed = + event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER; + boolean filterModified = !filterTxt.getValue().equals(subname); + if (enterPressed || filterModified) { + subname = filterTxt.getValue(); + refresh(enterPressed, filterModified); + } } }); hp.add(filterTxt); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java index de840813b6..1b420b4e51 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java @@ -95,6 +95,14 @@ public class GroupTable extends NavigationTable { } public void display(List list, String toHighlight) { + displaySubset(list, toHighlight, 0, list.size()); + } + + public void displaySubset(GroupMap groups, int fromIndex, int toIndex, String toHighlight) { + displaySubset(Natives.asList(groups.values()), toHighlight, fromIndex, toIndex); + } + + public void displaySubset(List list, String toHighlight, int fromIndex, int toIndex) { while (1 < table.getRowCount()) table.removeRow(table.getRowCount() - 1); @@ -104,7 +112,7 @@ public class GroupTable extends NavigationTable { return a.name().compareTo(b.name()); } }); - for(GroupInfo group : list) { + for(GroupInfo group : list.subList(fromIndex, toIndex)) { final int row = table.getRowCount(); table.insertRow(row); applyDataRowStyle(row); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java index 8f701a3feb..7490d82619 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java @@ -38,6 +38,7 @@ public class ActionContext extends JavaScriptObject { Gerrit.ActionContext.prototype = { go: Gerrit.go, refresh: Gerrit.refresh, + refreshMenuBar: Gerrit.refreshMenuBar, showError: Gerrit.showError, br: function(){return doc.createElement('br')}, diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java index ba7e6e6103..8da896e36b 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java @@ -63,6 +63,7 @@ public class ApiGlue { go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;), refresh: @com.google.gerrit.client.api.ApiGlue::refresh(), + refreshMenuBar: @com.google.gerrit.client.api.ApiGlue::refreshMenuBar(), showError: @com.google.gerrit.client.api.ApiGlue::showError(Ljava/lang/String;), on: function (e,f){(this.events[e] || (this.events[e]=[])).push(f)}, @@ -191,6 +192,10 @@ public class ApiGlue { Gerrit.display(History.getToken()); } + private static final void refreshMenuBar() { + Gerrit.refreshMenuBar(); + } + private static final void showError(String message) { new ErrorDialog(message).center(); } diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java index 00c674f9c8..7ef022a62b 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java @@ -52,6 +52,7 @@ final class Plugin extends JavaScriptObject { getPluginName: function(){return this.name}, go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;), refresh: @com.google.gerrit.client.api.ApiGlue::refresh(), + refreshMenuBar: @com.google.gerrit.client.api.ApiGlue::refreshMenuBar(), showError: @com.google.gerrit.client.api.ApiGlue::showError(Ljava/lang/String;), on: function(e,f){G.on(e,f)}, onAction: function(t,n,c){G._onAction(this.name,t,n,c)}, diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java index 6ba00ae643..f28fb8649a 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java @@ -24,12 +24,18 @@ public class GroupMap extends NativeMap { groups().get(NativeMap.copyKeysIntoChildren(callback)); } - public static void match(String match, AsyncCallback cb) { - if (match == null || "".equals(match)) { - all(cb); - } else { - groups().addParameter("m", match).get(NativeMap.copyKeysIntoChildren(cb)); + public static void match(String match, int limit, int start, AsyncCallback cb) { + RestApi call = groups(); + if (match != null) { + call.addParameter("m", match); } + if (limit > 0) { + call.addParameter("n", limit); + } + if (start > 0) { + call.addParameter("S", start); + } + call.get(NativeMap.copyKeysIntoChildren(cb)); } public static void myOwned(AsyncCallback cb) { diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java index 41c03a25de..046488d969 100644 --- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java +++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java @@ -50,6 +50,10 @@ public final class Plugin extends JavaScriptObject { public final native void refresh() /*-{ return this.refresh() }-*/; + /** Refresh Gerrit's menu bar. */ + public final native void refreshMenuBar() + /*-{ return this.refreshMenuBar() }-*/; + /** Show message in Gerrit's ErrorDialog. */ public final native void showError(String message) /*-{ return this.showError(message) }-*/; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java index d7f12ca0bf..2121e7bedd 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java @@ -188,7 +188,8 @@ public class Submit implements RestModifyView, "Merge patch set %d into %s", resource.getPatchSet().getPatchSetId(), resource.getChange().getDest().getShortName())) - .setVisible(resource.getChange().getStatus().isOpen() + .setVisible(!resource.getPatchSet().isDraft() + && resource.getChange().getStatus().isOpen() && resource.getPatchSet().getId().equals(current) && resource.getControl().canSubmit()); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java index b43967ac4d..457c827ef6 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java @@ -574,7 +574,7 @@ public class ReceiveCommits { if (c.getResult() == OK) { switch (c.getType()) { case CREATE: - if (isHead(c)) { + if (isHead(c) || isConfig(c)) { autoCloseChanges(c); } break; @@ -584,13 +584,13 @@ public class ReceiveCommits { c.getRefName(), c.getOldId(), c.getNewId()); - if (isHead(c)) { + if (isHead(c) || isConfig(c)) { autoCloseChanges(c); } break; case UPDATE_NONFASTFORWARD: - if (isHead(c)) { + if (isHead(c) || isConfig(c)) { autoCloseChanges(c); } break; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java index 170c346f16..f6b71877a1 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java @@ -87,6 +87,12 @@ public class ListGroups implements RestReadView { groupsToInspect.add(id); } + @Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of groups to list") + private int limit; + + @Option(name = "-S", metaVar = "CNT", usage = "number of groups to skip") + private int start; + @Option(name = "-m", metaVar = "MATCH", usage = "match group substring") private String matchSubstring; @@ -168,7 +174,15 @@ public class ListGroups implements RestReadView { groupList = filterGroups(groupCache.all()); } groupInfos = Lists.newArrayListWithCapacity(groupList.size()); + int found = 0; + int foundIndex = 0; for (AccountGroup group : groupList) { + if (foundIndex++ < start) { + continue; + } + if (limit > 0 && ++found > limit) { + break; + } groupInfos.add(json.addOptions(options).format( GroupDescriptions.forAccountGroup(group))); } @@ -180,11 +194,19 @@ public class ListGroups implements RestReadView { private List getGroupsOwnedBy(IdentifiedUser user) throws OrmException { List groups = Lists.newArrayList(); + int found = 0; + int foundIndex = 0; for (AccountGroup g : filterGroups(groupCache.all())) { GroupControl ctl = groupControlFactory.controlFor(g); try { if (genericGroupControlFactory.controlFor(user, g.getGroupUUID()) .isOwner()) { + if (foundIndex++ < start) { + continue; + } + if (limit > 0 && ++found > limit) { + break; + } groups.add(json.addOptions(options).format(ctl.getGroup())); } } catch (NoSuchGroupException e) {