Merge "Revert "Add config option to prevent group updates while migrating groups""
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 06ceb49..7f4522f 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
@@ -27,6 +27,7 @@
 import com.google.gwt.core.client.JsArray;
 import com.google.gwt.core.client.JsArrayString;
 import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtorm.client.KeyUtil;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -49,7 +50,7 @@
   public static void suggest(String query, int limit, AsyncCallback<JsArray<AccountInfo>> cb) {
     new RestApi("/accounts/")
         .addParameterTrue("suggest")
-        .addParameter("q", query)
+        .addParameterRaw("q", KeyUtil.encode(query))
         .addParameter("n", limit)
         .background()
         .get(cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
index 0fd85f1..a376782 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
@@ -102,6 +102,7 @@
     this.changeId = info.legacyId();
     this.project = info.projectNameKey();
     this.canEdit = info.hasActions() && info.actions().containsKey("assignee");
+    assigneeSuggestOracle.setChange(info);
     setAssignee(info.assignee());
     editAssigneeIcon.setVisible(canEdit);
     if (!canEdit) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
index 964f7ad..c8bbfc3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.client.account.AccountApi;
 import com.google.gerrit.client.info.AccountInfo;
+import com.google.gerrit.client.info.ChangeInfo;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gerrit.client.ui.AccountSuggestOracle.AccountSuggestion;
@@ -27,10 +28,17 @@
 
 /** REST API based suggestion Oracle for assignee */
 public class AssigneeSuggestOracle extends SuggestAfterTypingNCharsOracle {
+
+  private ChangeInfo change;
+
+  public void setChange(ChangeInfo change) {
+    this.change = change;
+  }
+
   @Override
   protected void _onRequestSuggestions(Request req, Callback cb) {
     AccountApi.suggest(
-        req.getQuery(),
+        getQuery(req),
         req.getLimit(),
         new GerritCallback<JsArray<AccountInfo>>() {
           @Override
@@ -49,4 +57,13 @@
           }
         });
   }
+
+  private String getQuery(Request req) {
+    StringBuilder query = new StringBuilder();
+    query.append(req.getQuery());
+    if (change != null) {
+      query.append(" cansee:").append(change._number());
+    }
+    return query.toString();
+  }
 }
diff --git a/java/com/google/gerrit/server/config/PluginConfigFactory.java b/java/com/google/gerrit/server/config/PluginConfigFactory.java
index 41230b2..a46efb8 100644
--- a/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.server.config;
 
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.gerrit.server.plugins.Plugin;
 import com.google.gerrit.server.plugins.ReloadPluginListener;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.securestore.SecureStore;
 import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/server/git/SubmoduleOp.java b/java/com/google/gerrit/server/git/SubmoduleOp.java
index 0e3e146..d7af141 100644
--- a/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -31,7 +31,6 @@
 import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateListener;
 import com.google.gerrit.server.update.RepoContext;
@@ -98,7 +97,6 @@
     private final PersonIdent myIdent;
     private final Config cfg;
     private final ProjectCache projectCache;
-    private final ProjectState.Factory projectStateFactory;
     private final BatchUpdate.Factory batchUpdateFactory;
 
     @Inject
@@ -107,27 +105,18 @@
         @GerritPersonIdent PersonIdent myIdent,
         @GerritServerConfig Config cfg,
         ProjectCache projectCache,
-        ProjectState.Factory projectStateFactory,
         BatchUpdate.Factory batchUpdateFactory) {
       this.gitmodulesFactory = gitmodulesFactory;
       this.myIdent = myIdent;
       this.cfg = cfg;
       this.projectCache = projectCache;
-      this.projectStateFactory = projectStateFactory;
       this.batchUpdateFactory = batchUpdateFactory;
     }
 
     public SubmoduleOp create(Set<Branch.NameKey> updatedBranches, MergeOpRepoManager orm)
         throws SubmoduleException {
       return new SubmoduleOp(
-          gitmodulesFactory,
-          myIdent,
-          cfg,
-          projectCache,
-          projectStateFactory,
-          batchUpdateFactory,
-          updatedBranches,
-          orm);
+          gitmodulesFactory, myIdent, cfg, projectCache, batchUpdateFactory, updatedBranches, orm);
     }
   }
 
@@ -136,7 +125,6 @@
   private final GitModules.Factory gitmodulesFactory;
   private final PersonIdent myIdent;
   private final ProjectCache projectCache;
-  private final ProjectState.Factory projectStateFactory;
   private final BatchUpdate.Factory batchUpdateFactory;
   private final VerboseSuperprojectUpdate verboseSuperProject;
   private final boolean enableSuperProjectSubscriptions;
@@ -163,7 +151,6 @@
       PersonIdent myIdent,
       Config cfg,
       ProjectCache projectCache,
-      ProjectState.Factory projectStateFactory,
       BatchUpdate.Factory batchUpdateFactory,
       Set<Branch.NameKey> updatedBranches,
       MergeOpRepoManager orm)
@@ -171,7 +158,6 @@
     this.gitmodulesFactory = gitmodulesFactory;
     this.myIdent = myIdent;
     this.projectCache = projectCache;
-    this.projectStateFactory = projectStateFactory;
     this.batchUpdateFactory = batchUpdateFactory;
     this.verboseSuperProject =
         cfg.getEnum("submodule", null, "verboseSuperprojectUpdate", VerboseSuperprojectUpdate.TRUE);
@@ -335,8 +321,7 @@
     logDebug("Calculating possible superprojects for " + srcBranch);
     Collection<SubmoduleSubscription> ret = new ArrayList<>();
     Project.NameKey srcProject = srcBranch.getParentKey();
-    ProjectConfig cfg = projectCache.get(srcProject).getConfig();
-    for (SubscribeSection s : projectStateFactory.create(cfg).getSubscribeSections(srcBranch)) {
+    for (SubscribeSection s : projectCache.get(srcProject).getSubscribeSections(srcBranch)) {
       logDebug("Checking subscribe section " + s);
       Collection<Branch.NameKey> branches = getDestinationBranches(srcBranch, s);
       for (Branch.NameKey targetBranch : branches) {
diff --git a/java/com/google/gerrit/server/git/ProjectLevelConfig.java b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
similarity index 97%
rename from java/com/google/gerrit/server/git/ProjectLevelConfig.java
rename to java/com/google/gerrit/server/project/ProjectLevelConfig.java
index 2044db0..ee1bbef 100644
--- a/java/com/google/gerrit/server/git/ProjectLevelConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.git;
+package com.google.gerrit.server.project;
 
 import static java.util.stream.Collectors.toList;
 
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Streams;
 import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.git.VersionedMetaData;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Set;
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index 48a8b9a..2ef7891 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -47,7 +47,6 @@
 import com.google.gerrit.server.git.BranchOrderSection;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.rules.PrologEnvironment;
 import com.google.gerrit.server.rules.RulesCache;
diff --git a/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java b/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
index 1fbf877..8b6e1e4 100644
--- a/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
@@ -198,6 +198,14 @@
   protected Predicate<AccountState> defaultField(String query) {
     Predicate<AccountState> defaultPredicate =
         AccountPredicates.defaultPredicate(args.schema(), checkedCanSeeSecondaryEmails(), query);
+    if (query.startsWith("cansee:")) {
+      try {
+        return cansee(query.substring(7));
+      } catch (OrmException | QueryParseException | PermissionBackendException e) {
+        // Ignore, fall back to default query
+      }
+    }
+
     if ("self".equalsIgnoreCase(query) || "me".equalsIgnoreCase(query)) {
       try {
         return Predicate.or(defaultPredicate, AccountPredicates.id(self()));
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html
index 0fa2eb5..dacedd3 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html
@@ -54,10 +54,13 @@
           padding: 0 .15em;
         }
       }
+      .hideBranch {
+        display: none;
+      }
     </style>
     <div class="gr-form-styles">
       <div id="form">
-        <section>
+        <section class$="[[_computeBranchClass(baseChange)]]">
           <span class="title">Select branch for new change</span>
           <span class="value">
             <gr-autocomplete
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
index 367d324..8004faa 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
@@ -33,6 +33,7 @@
           return this._getRepoBranchesSuggestions.bind(this);
         },
       },
+      baseChange: String,
       canCreate: {
         type: Boolean,
         notify: true,
@@ -55,6 +56,10 @@
       '_allowCreate(branch, subject)',
     ],
 
+    _computeBranchClass(baseChange) {
+      return baseChange ? 'hideBranch' : '';
+    },
+
     _allowCreate(branch, subject) {
       this.canCreate = !!branch && !!subject;
     },
@@ -63,7 +68,7 @@
       const isPrivate = this.$.privateChangeCheckBox.checked;
       const isWip = true;
       return this.$.restAPI.createChange(this.repoName, this.branch,
-          this.subject, this.topic, isPrivate, isWip)
+          this.subject, this.topic, isPrivate, isWip, this.baseChange)
           .then(changeCreated => {
             if (!changeCreated) { return; }
             Gerrit.Nav.navigateToChange(changeCreated);
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
index 3489db0..53f9ef5 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
@@ -285,10 +285,13 @@
     },
 
     _handleRKey(e) {
-      if (this.shouldSuppressKeyboardShortcut(e) ||
-          this.modifierPressed(e)) { return; }
+      if (this.shouldSuppressKeyboardShortcut(e)) { return; }
 
       e.preventDefault();
+      this._reloadWindow();
+    },
+
+    _reloadWindow() {
       window.location.reload();
     },
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
index aed48e3..265e34e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
@@ -190,6 +190,10 @@
         MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
         assert.equal(element.selectedIndex, 0);
 
+        const reloadStub = sandbox.stub(element, '_reloadWindow');
+        MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
+        assert.isTrue(reloadStub.called);
+
         done();
       });
     });
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
index 322de71..5b14fd4 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
@@ -19,6 +19,7 @@
 <link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
 <link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/iron-input/iron-input.html">
+<link rel="import" href="../../admin/gr-create-change-dialog/gr-create-change-dialog.html">
 <link rel="import" href="../../core/gr-navigation/gr-navigation.html">
 <link rel="import" href="../../core/gr-reporting/gr-reporting.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
@@ -160,6 +161,22 @@
           on-confirm="_handleAbandonDialogConfirm"
           on-cancel="_handleConfirmDialogCancel"
           hidden></gr-confirm-abandon-dialog>
+      <gr-confirm-dialog id="createFollowUpDialog"
+          class="confirmDialog"
+          confirm-label="Create"
+          on-confirm="_handleCreateFollowUpChange"
+          on-cancel="_handleCloseCreateFollowUpChange">
+        <div class="header" slot="header">
+          Create Follow-Up Change
+        </div>
+        <div class="main" slot="main">
+          <gr-create-change-dialog
+              id="createFollowUpChange"
+              branch="[[change.branch]]"
+              base-change="[[change.id]]"
+              repo-name="[[change.project]]"></gr-create-change-dialog>
+        </div>
+      </gr-confirm-dialog>
       <gr-confirm-dialog
           id="confirmDeleteDialog"
           class="confirmDialog"
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index adab1c8..4a742c2 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -53,6 +53,7 @@
     DELETE: '/',
     DELETE_EDIT: 'deleteEdit',
     EDIT: 'edit',
+    FOLLOW_UP: 'followup',
     IGNORE: 'ignore',
     MOVE: 'move',
     PRIVATE: 'private',
@@ -308,6 +309,10 @@
               type: ActionType.CHANGE,
               key: ChangeActions.PRIVATE_DELETE,
             },
+            {
+              type: ActionType.CHANGE,
+              key: ChangeActions.FOLLOW_UP,
+            },
           ];
           return value;
         },
@@ -860,6 +865,9 @@
         case ChangeActions.DELETE_EDIT:
           this._handleDeleteEditTap();
           break;
+        case ChangeActions.FOLLOW_UP:
+          this._handleFollowUpTap();
+          break;
         case ChangeActions.WIP:
           this._handleWipTap();
           break;
@@ -997,6 +1005,15 @@
           {message: el.message});
     },
 
+    _handleCreateFollowUpChange() {
+      this.$.createFollowUpChange.handleCreateChange();
+      this._handleCloseCreateFollowUpChange();
+    },
+
+    _handleCloseCreateFollowUpChange() {
+      this.$.overlay.close();
+    },
+
     _handleDeleteConfirm() {
       this._fireAction('/', this.actions[ChangeActions.DELETE], false);
     },
@@ -1185,6 +1202,10 @@
       this._showActionDialog(this.$.confirmDeleteEditDialog);
     },
 
+    _handleFollowUpTap() {
+      this._showActionDialog(this.$.createFollowUpDialog);
+    },
+
     _handleWipTap() {
       this._fireAction('/wip', this.actions.wip, false);
     },
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 640c273..bb84fde 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -478,16 +478,18 @@
     },
 
     _handleShiftLeftKey(e) {
-      if (this.shouldSuppressKeyboardShortcut(e)) { return; }
-      if (!this._showInlineDiffs) { return; }
+      if (this.shouldSuppressKeyboardShortcut(e) || this._noDiffsExpanded()) {
+        return;
+      }
 
       e.preventDefault();
       this.$.diffCursor.moveLeft();
     },
 
     _handleShiftRightKey(e) {
-      if (this.shouldSuppressKeyboardShortcut(e)) { return; }
-      if (!this._showInlineDiffs) { return; }
+      if (this.shouldSuppressKeyboardShortcut(e) || this._noDiffsExpanded()) {
+        return;
+      }
 
       e.preventDefault();
       this.$.diffCursor.moveRight();
@@ -591,10 +593,10 @@
 
     _handleNKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
-          this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) {
+          (this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) ||
+          this._noDiffsExpanded()) {
         return;
       }
-      if (!this._showInlineDiffs) { return; }
 
       e.preventDefault();
       if (this.isModifierPressed(e, 'shiftKey')) {
@@ -606,10 +608,10 @@
 
     _handlePKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
-          this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) {
+          (this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) ||
+          this._noDiffsExpanded()) {
         return;
       }
-      if (!this._showInlineDiffs) { return; }
 
       e.preventDefault();
       if (this.isModifierPressed(e, 'shiftKey')) {
@@ -1129,5 +1131,13 @@
       }
       return `sizeBars desktop ${hideClass}`;
     },
+
+    /**
+     * Returns true if none of the inline diffs have been expanded.
+     * @return {boolean}
+     */
+    _noDiffsExpanded() {
+      return this.filesExpanded === GrFileListConstants.FilesExpandedState.NONE;
+    },
   });
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 36b5a41..0eecf30 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -597,6 +597,26 @@
           assert.deepEqual(interact(), {opened_selected: true});
         });
       });
+
+      test('shift+left/shift+right', () => {
+        const moveLeftStub = sandbox.stub(element.$.diffCursor, 'moveLeft');
+        const moveRightStub = sandbox.stub(element.$.diffCursor, 'moveRight');
+
+        let noDiffsExpanded = true;
+        sandbox.stub(element, '_noDiffsExpanded', () => noDiffsExpanded);
+
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+        assert.isFalse(moveLeftStub.called);
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+        assert.isFalse(moveRightStub.called);
+
+        noDiffsExpanded = false;
+
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+        assert.isTrue(moveLeftStub.called);
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+        assert.isTrue(moveRightStub.called);
+      });
     });
 
     test('computed properties', () => {
@@ -1367,6 +1387,7 @@
       let nextCommentStub;
       let nextChunkStub;
       let fileRows;
+
       setup(() => {
         sandbox.stub(element, '_renderInOrder').returns(Promise.resolve());
         nKeySpy = sandbox.spy(element, '_handleNKey');
@@ -1377,9 +1398,11 @@
         fileRows =
             Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
       });
-      test('n key with all files expanded and no shift key', () => {
+
+      test('n key with some files expanded and no shift key', () => {
         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
         flushAsynchronousOperations();
+        assert.equal(nextChunkStub.callCount, 1);
 
         // Handle N key should return before calling diff cursor functions.
         MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
@@ -1387,21 +1410,22 @@
         assert.isFalse(nextCommentStub.called);
 
         // This is also called in diffCursor.moveToFirstChunk.
-        assert.equal(nextChunkStub.callCount, 1);
-        assert.isFalse(!!element._showInlineDiffs);
+        assert.equal(nextChunkStub.callCount, 2);
+        assert.equal(element.filesExpanded, 'some');
       });
 
-      test('n key with all files expanded and shift key', () => {
+      test('n key with some files expanded and shift key', () => {
         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
         flushAsynchronousOperations();
+        assert.equal(nextChunkStub.callCount, 1);
 
         MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
         assert.isTrue(nKeySpy.called);
-        assert.isFalse(nextCommentStub.called);
+        assert.isTrue(nextCommentStub.called);
 
         // This is also called in diffCursor.moveToFirstChunk.
         assert.equal(nextChunkStub.callCount, 1);
-        assert.isFalse(!!element._showInlineDiffs);
+        assert.equal(element.filesExpanded, 'some');
       });
 
       test('n key without all files expanded and shift key', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.html b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
index 0898a60..7c6032d 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
@@ -123,6 +123,7 @@
       }
       .expanded .author {
         cursor: pointer;
+        margin-bottom: .4em;
       }
       .date {
         color: #666;
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index 4647e52..4037f38 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -417,6 +417,14 @@
       },
 
       /**
+       * Navigate to a repo settings page.
+       * @param {string} repoName
+       */
+      navigateToRepo(repoName) {
+        this._navigate(this.getUrlForRepo(repoName));
+      },
+
+      /**
        * @param {string} repoName
        * @return {string}
        */
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 0255361..c166695 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -247,9 +247,8 @@
       /** Support the line length indicator **/
       .full-width td.content,
       .full-width td.blank {
-        /* Base 64 encoded 1x30px of #ddd */
-        background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeAgMAAACQ+5xUAAAACVBMVEXd3d0AAAClpaWbWM6mAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAEElEQVQImWNgwAsakEgMAAAaPAEBM3eopQAAAABJRU5ErkJggg==')
-;
+        /* Base 64 encoded 1x1px of #ddd */
+        background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO8+x8AAr8B3gzOjaQAAAAASUVORK5CYII=');
         background-position: var(--line-limit) 0;
         background-repeat: repeat-y;
       }
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 88faaba..f552c50 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -1421,9 +1421,10 @@
      * @param {string=} opt_topic
      * @param {boolean=} opt_isPrivate
      * @param {boolean=} opt_workInProgress
+     * @param {string=} opt_baseChange
      */
     createChange(project, branch, subject, opt_topic, opt_isPrivate,
-        opt_workInProgress) {
+        opt_workInProgress, opt_baseChange) {
       return this.send('POST', '/changes/', {
         project,
         branch,
@@ -1431,6 +1432,7 @@
         topic: opt_topic,
         is_private: opt_isPrivate,
         work_in_progress: opt_workInProgress,
+        base_change: opt_baseChange,
       }).then(response => this.getResponseObject(response));
     },