Merge "Related changes sections use all space if needed"
diff --git a/java/com/google/gerrit/acceptance/PushOneCommit.java b/java/com/google/gerrit/acceptance/PushOneCommit.java
index 4215255..0db2408 100644
--- a/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -47,6 +47,7 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -294,6 +295,18 @@
     return this;
   }
 
+  public PushOneCommit addGitSubmodule(String modulePath, ObjectId commitId) {
+    commitBuilder.edit(
+        new PathEdit(modulePath) {
+          @Override
+          public void apply(DirCacheEntry ent) {
+            ent.setFileMode(FileMode.GITLINK);
+            ent.setObjectId(commitId);
+          }
+        });
+    return this;
+  }
+
   public Result to(String ref) throws Exception {
     for (Map.Entry<String, String> e : files.entrySet()) {
       commitBuilder.add(e.getKey(), e.getValue());
diff --git a/java/com/google/gerrit/entities/SubmitRecord.java b/java/com/google/gerrit/entities/SubmitRecord.java
index 67c6007..1fd0864 100644
--- a/java/com/google/gerrit/entities/SubmitRecord.java
+++ b/java/com/google/gerrit/entities/SubmitRecord.java
@@ -14,6 +14,9 @@
 
 package com.google.gerrit.entities;
 
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
+import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
@@ -107,6 +110,17 @@
     public Status status;
     public Account.Id appliedBy;
 
+    /**
+     * Returns a new instance of {@link Label} that contains a new instance for each mutable field.
+     */
+    public Label deepCopy() {
+      Label copy = new Label();
+      copy.label = label;
+      copy.status = status;
+      copy.appliedBy = appliedBy;
+      return copy;
+    }
+
     @Override
     public String toString() {
       StringBuilder sb = new StringBuilder();
@@ -134,6 +148,23 @@
     }
   }
 
+  /**
+   * Returns a new instance of {@link SubmitRecord} that contains a new instance for each mutable
+   * field.
+   */
+  public SubmitRecord deepCopy() {
+    SubmitRecord copy = new SubmitRecord();
+    copy.status = status;
+    copy.errorMessage = errorMessage;
+    if (labels != null) {
+      copy.labels = labels.stream().map(Label::deepCopy).collect(toImmutableList());
+    }
+    if (requirements != null) {
+      copy.requirements = ImmutableList.copyOf(requirements);
+    }
+    return copy;
+  }
+
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder();
diff --git a/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java b/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java
index f44b075..0e34e36 100644
--- a/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java
+++ b/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java
@@ -68,7 +68,7 @@
       @Override
       protected void configure() {
         persist(CACHE_NAME, CommentContextKey.class, CommentContext.class)
-            .version(3)
+            .version(4)
             .diskLimit(1 << 30) // limit the total cache size to 1 GB
             .maximumWeight(1 << 23) // Limit the size of the in-memory cache to 8 MB
             .weigher(CommentContextWeigher.class)
diff --git a/java/com/google/gerrit/server/comment/CommentContextLoader.java b/java/com/google/gerrit/server/comment/CommentContextLoader.java
index 4a6c956..a5aca48 100644
--- a/java/com/google/gerrit/server/comment/CommentContextLoader.java
+++ b/java/com/google/gerrit/server/comment/CommentContextLoader.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.mime.FileTypeRegistry;
 import com.google.gerrit.server.patch.ComparisonType;
+import com.google.gerrit.server.patch.SrcContentResolver;
 import com.google.gerrit.server.patch.Text;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
@@ -45,7 +46,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
@@ -168,9 +168,10 @@
         return CommentContext.empty();
       }
       ObjectId id = tw.getObjectId(0);
-      Text src = new Text(repo.open(id, Constants.OBJ_BLOB));
-      String contentType = getContentType(tw, filePath, src);
-      return createContext(src, commentRange, contextPadding, contentType);
+      byte[] sourceContent = SrcContentResolver.getSourceContent(repo, id, tw.getFileMode(0));
+      Text textSrc = new Text(sourceContent);
+      String contentType = getContentType(tw, filePath, textSrc);
+      return createContext(textSrc, commentRange, contextPadding, contentType);
     }
   }
 
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index 59600e0..346d2a6 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -815,7 +815,7 @@
               });
 
   public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_LENIENT =
-      SubmitRuleOptions.builder().allowClosed(true).build();
+      SubmitRuleOptions.builder().recomputeOnClosedChanges(true).build();
 
   public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_STRICT =
       SubmitRuleOptions.builder().build();
diff --git a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index ca573d1..ccc8565 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -16,7 +16,6 @@
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
-import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -102,12 +101,8 @@
                 .map(TaggedEdit::jgitEdit)
                 .collect(toImmutableSet()),
             content.headerLines(),
-            content.oldPath().orElse(null),
-            // TODO(ghareeb): logic for new path is confusing. This is needed because
-            // PatchFileChange does some tricks with paths so that they're compatible with the old
-            // diff cache. Adding this todo to cleanup this stuff when the new diff cache becomes
-            // the default.
-            content.newPath().isPresent() ? content.newPath().get() : content.oldPath().get(),
+            getOldName(content.oldPath(), content.changeType()),
+            getNewName(content.oldPath(), content.newPath(), content.changeType()),
             content.changeType(),
             content.patchType().orElse(null));
     SidesResolver sidesResolver = new SidesResolver(git, content.comparisonType());
@@ -122,6 +117,42 @@
     return build(sides.a, sides.b, change);
   }
 
+  private String getOldName(Optional<String> oldName, ChangeType changeType) {
+    // TODO(ghareeb): We adapt the new diff cache output so that it's compatible with the old diff
+    // cache behaviour. Later on we can cleanup this logic a bit.
+    switch (changeType) {
+      case DELETED:
+      case ADDED:
+      case MODIFIED:
+      case REWRITE:
+        return null;
+      case COPIED:
+      case RENAMED:
+        return oldName.get();
+      default:
+        throw new IllegalArgumentException("Unsupported type " + changeType);
+    }
+  }
+
+  private String getNewName(
+      Optional<String> oldName, Optional<String> newName, ChangeType changeType) {
+    // TODO(ghareeb): logic for new path is confusing. We adapt the new diff cache output so that
+    // it's compatible with the existing behaviour of Get Diff. Later on we can cleanup this logic a
+    // bit.
+    switch (changeType) {
+      case DELETED:
+        return oldName.get();
+      case ADDED:
+      case MODIFIED:
+      case REWRITE:
+      case COPIED:
+      case RENAMED:
+        return newName.get();
+      default:
+        throw new IllegalArgumentException("Unsupported type " + changeType);
+    }
+  }
+
   private ResolvedSides resolveSides(
       Repository git,
       SidesResolver sidesResolver,
@@ -387,16 +418,8 @@
         byte[] srcContent;
         if (reuse) {
           srcContent = other.srcContent;
-
-        } else if (mode.getObjectType() == Constants.OBJ_BLOB) {
-          srcContent = Text.asByteArray(db.open(id, Constants.OBJ_BLOB));
-
-        } else if (mode.getObjectType() == Constants.OBJ_COMMIT) {
-          String strContent = "Subproject commit " + ObjectId.toString(id);
-          srcContent = strContent.getBytes(UTF_8);
-
         } else {
-          srcContent = Text.NO_BYTES;
+          srcContent = SrcContentResolver.getSourceContent(db, id, mode);
         }
         String mimeType = MimeUtil2.UNKNOWN_MIME_TYPE.toString();
         DisplayMethod displayMethod = DisplayMethod.DIFF;
diff --git a/java/com/google/gerrit/server/patch/SrcContentResolver.java b/java/com/google/gerrit/server/patch/SrcContentResolver.java
new file mode 100644
index 0000000..9cd11d2
--- /dev/null
+++ b/java/com/google/gerrit/server/patch/SrcContentResolver.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2021 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.patch;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.IOException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+
+/** Resolver of the source content of a specific file */
+public class SrcContentResolver {
+
+  private SrcContentResolver() {}
+
+  /**
+   * Return the source content of a specific file.
+   *
+   * @param repo Git repository.
+   * @param id Git Object ID of the file blob.
+   * @param fileMode File mode of the underlying file as recognized by Git.
+   * @return byte[] source content of the underlying file if the {@code id} is of type blob, or a
+   *     textual representation of the file if it is a git submodule.
+   * @throws IOException the object ID does not exist in the repository or cannot be accessed.
+   */
+  public static byte[] getSourceContent(Repository repo, ObjectId id, FileMode fileMode)
+      throws IOException {
+    if (fileMode.getObjectType() == Constants.OBJ_BLOB) {
+      return Text.asByteArray(repo.open(id, Constants.OBJ_BLOB));
+    }
+    if (fileMode.getObjectType() == Constants.OBJ_COMMIT) {
+      String strContent = "Subproject commit " + ObjectId.toString(id);
+      return strContent.getBytes(UTF_8);
+    }
+    return Text.NO_BYTES;
+  }
+}
diff --git a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 0e50bb0..c3bcd25 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.project;
 
+import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.gerrit.server.project.ProjectCache.noSuchProject;
 
 import com.google.common.collect.Streams;
@@ -36,7 +37,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 /**
  * Evaluates a submit-like Prolog rule found in the rules.pl file of the current project and filters
@@ -121,10 +121,18 @@
         return Collections.singletonList(ruleError("Error looking up change " + cd.getId(), e));
       }
 
-      if ((!opts.allowClosed() || OnlineReindexMode.isActive()) && change.isClosed()) {
-        SubmitRecord rec = new SubmitRecord();
-        rec.status = SubmitRecord.Status.CLOSED;
-        return Collections.singletonList(rec);
+      if (change.isClosed() && (!opts.recomputeOnClosedChanges() || OnlineReindexMode.isActive())) {
+        return cd.notes().getSubmitRecords().stream()
+            .map(
+                r -> {
+                  SubmitRecord record = r.deepCopy();
+                  if (record.status == SubmitRecord.Status.OK) {
+                    // Submit records that were OK when they got merged are CLOSED now.
+                    record.status = SubmitRecord.Status.CLOSED;
+                  }
+                  return record;
+                })
+            .collect(toImmutableList());
       }
 
       // We evaluate all the plugin-defined evaluators,
@@ -133,7 +141,7 @@
           .map(c -> c.call(s -> s.evaluate(cd)))
           .filter(Optional::isPresent)
           .map(Optional::get)
-          .collect(Collectors.toList());
+          .collect(toImmutableList());
     }
   }
 
diff --git a/java/com/google/gerrit/server/project/SubmitRuleOptions.java b/java/com/google/gerrit/server/project/SubmitRuleOptions.java
index ad077c0..3b511e1 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleOptions.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleOptions.java
@@ -25,7 +25,7 @@
 @AutoValue
 public abstract class SubmitRuleOptions {
   private static final SubmitRuleOptions defaults =
-      new AutoValue_SubmitRuleOptions.Builder().allowClosed(false).build();
+      new AutoValue_SubmitRuleOptions.Builder().recomputeOnClosedChanges(false).build();
 
   public static SubmitRuleOptions defaults() {
     return defaults;
@@ -35,13 +35,16 @@
     return defaults.toBuilder();
   }
 
-  public abstract boolean allowClosed();
+  /**
+   * True if the submit rules should be recomputed even when the change is already closed (merged).
+   */
+  public abstract boolean recomputeOnClosedChanges();
 
   public abstract Builder toBuilder();
 
   @AutoValue.Builder
   public abstract static class Builder {
-    public abstract SubmitRuleOptions.Builder allowClosed(boolean allowClosed);
+    public abstract SubmitRuleOptions.Builder recomputeOnClosedChanges(boolean allowClosed);
 
     public abstract SubmitRuleOptions build();
   }
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index bf56000..8886cca 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -885,7 +885,12 @@
       submitRecords.put(options, records);
       if (!change().isClosed() && submitRecords.size() == 1) {
         // Cache the SubmitRecord with allowClosed = !allowClosed as the SubmitRecord are the same.
-        submitRecords.put(options.toBuilder().allowClosed(!options.allowClosed()).build(), records);
+        submitRecords.put(
+            options
+                .toBuilder()
+                .recomputeOnClosedChanges(!options.recomputeOnClosedChanges())
+                .build(),
+            records);
       }
     }
     return records;
diff --git a/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
index 4922b57..1b6dc62 100644
--- a/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
+++ b/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
@@ -262,7 +262,8 @@
     }
 
     if (includeSubmitRecords) {
-      SubmitRuleOptions options = SubmitRuleOptions.builder().allowClosed(true).build();
+      SubmitRuleOptions options =
+          SubmitRuleOptions.builder().recomputeOnClosedChanges(true).build();
       eventFactory.addSubmitRecords(c, submitRuleEvaluatorFactory.create(options).evaluate(d));
     }
 
diff --git a/java/com/google/gerrit/server/submit/MergeOp.java b/java/com/google/gerrit/server/submit/MergeOp.java
index f486650..ccea90c 100644
--- a/java/com/google/gerrit/server/submit/MergeOp.java
+++ b/java/com/google/gerrit/server/submit/MergeOp.java
@@ -120,7 +120,7 @@
 
   private static final SubmitRuleOptions SUBMIT_RULE_OPTIONS = SubmitRuleOptions.builder().build();
   private static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_ALLOW_CLOSED =
-      SUBMIT_RULE_OPTIONS.toBuilder().allowClosed(true).build();
+      SUBMIT_RULE_OPTIONS.toBuilder().recomputeOnClosedChanges(true).build();
 
   public static class CommitStatus {
     private final ImmutableMap<Change.Id, ChangeData> changes;
diff --git a/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java b/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
new file mode 100644
index 0000000..bc9f50a5
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
@@ -0,0 +1,103 @@
+// Copyright (C) 2021 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.acceptance.api.change;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.entities.LabelFunction;
+import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.LabelValue;
+import com.google.gerrit.entities.SubmitRecord;
+import com.google.gerrit.server.project.SubmitRuleEvaluator;
+import com.google.gerrit.server.project.SubmitRuleOptions;
+import com.google.inject.Inject;
+import java.util.List;
+import org.junit.Test;
+
+public class SubmitRuleIT extends AbstractDaemonTest {
+  @Inject private SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
+
+  @Test
+  public void submitRecordsForClosedChanges_parsedBackByDefault() throws Exception {
+    SubmitRuleEvaluator submitRuleEvaluator =
+        submitRuleEvaluatorFactory.create(SubmitRuleOptions.defaults());
+    PushOneCommit.Result r = createChange();
+    approve(r.getChangeId());
+    List<SubmitRecord> recordsBeforeSubmission = submitRuleEvaluator.evaluate(r.getChange());
+    gApi.changes().id(r.getChangeId()).current().submit();
+    // Add a new label that blocks submission if not granted. In case we reevaluate the rules,
+    // this would show up as blocking submission.
+    setupCustomBlockingLabel();
+    List<SubmitRecord> recordsAfterSubmission = submitRuleEvaluator.evaluate(r.getChange());
+    recordsBeforeSubmission.forEach(
+        sr -> sr.status = SubmitRecord.Status.CLOSED); // Set status to closed
+    assertThat(recordsBeforeSubmission).isEqualTo(recordsAfterSubmission);
+  }
+
+  @Test
+  public void submitRecordsForClosedChanges_recomputedIfRequested() throws Exception {
+    SubmitRuleEvaluator submitRuleEvaluator =
+        submitRuleEvaluatorFactory.create(
+            SubmitRuleOptions.builder().recomputeOnClosedChanges(true).build());
+    PushOneCommit.Result r = createChange();
+    approve(r.getChangeId());
+    List<SubmitRecord> recordsBeforeSubmission = submitRuleEvaluator.evaluate(r.getChange());
+    gApi.changes().id(r.getChangeId()).current().submit();
+    // Add a new label that blocks submission if not granted. In case we reevaluate the rules,
+    // this would show up as blocking submission.
+    setupCustomBlockingLabel();
+    List<SubmitRecord> recordsAfterSubmission = submitRuleEvaluator.evaluate(r.getChange());
+    assertThat(recordsBeforeSubmission).isNotEqualTo(recordsAfterSubmission);
+    assertThat(recordsAfterSubmission).hasSize(1);
+    List<SubmitRecord.Label> recordLabels = recordsAfterSubmission.get(0).labels;
+
+    assertThat(recordLabels).hasSize(2);
+    assertCodeReviewApproved(recordLabels);
+    assertMyLabelNeed(recordLabels);
+  }
+
+  private void assertCodeReviewApproved(List<SubmitRecord.Label> recordLabels) {
+    SubmitRecord.Label haveCodeReview = new SubmitRecord.Label();
+    haveCodeReview.label = "Code-Review";
+    haveCodeReview.status = SubmitRecord.Label.Status.OK;
+    haveCodeReview.appliedBy = admin.id();
+    assertThat(recordLabels).contains(haveCodeReview);
+  }
+
+  private void assertMyLabelNeed(List<SubmitRecord.Label> recordLabels) {
+    SubmitRecord.Label needCustomLabel = new SubmitRecord.Label();
+    needCustomLabel.label = "My-Label";
+    needCustomLabel.status = SubmitRecord.Label.Status.NEED;
+    assertThat(recordLabels).contains(needCustomLabel);
+  }
+
+  private void setupCustomBlockingLabel() throws Exception {
+    try (ProjectConfigUpdate u = updateProject(project)) {
+      u.getConfig()
+          .upsertLabelType(
+              LabelType.builder(
+                      "My-Label",
+                      ImmutableList.of(
+                          LabelValue.create((short) 0, "Not approved"),
+                          LabelValue.create((short) 1, "Approved")))
+                  .setFunction(LabelFunction.MAX_WITH_BLOCK)
+                  .build());
+      u.save();
+    }
+  }
+}
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
index 20b9882..8a0ddd3 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
@@ -37,6 +37,7 @@
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
+import org.eclipse.jgit.lib.ObjectId;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -54,15 +55,37 @@
 
   private static final String FILE_CONTENT =
       String.join("\n", "Line 1 of file", "", "Line 3 of file", "", "", "Line 6 of file");
+  private static final ObjectId dummyCommit =
+      ObjectId.fromString("93e2901bc0b4719ef6081ee6353b49c9cdd97614");
 
   @Inject private RequestScopeOperations requestScopeOperations;
 
   @Before
-  public void setUp() {
+  public void setup() throws Exception {
     requestScopeOperations.setApiUser(user.id());
   }
 
   @Test
+  public void commentContextForGitSubmoduleFiles() throws Exception {
+    String submodulePath = "submodule_path";
+
+    PushOneCommit push =
+        pushFactory.create(admin.newIdent(), testRepo).addGitSubmodule(submodulePath, dummyCommit);
+    PushOneCommit.Result pushResult = push.to("refs/for/master");
+    String changeId = pushResult.getChangeId();
+    CommentInput comment =
+        CommentsUtil.newComment(submodulePath, Side.REVISION, 1, "comment", false);
+    CommentsUtil.addComments(gApi, changeId, pushResult.getCommit().name(), comment);
+
+    List<CommentInfo> comments =
+        gApi.changes().id(changeId).commentsRequest().withContext(true).getAsList();
+    assertThat(comments).hasSize(1);
+    assertThat(comments.get(0).path).isEqualTo(submodulePath);
+    assertThat(comments.get(0).contextLines)
+        .isEqualTo(createContextLines("1", "Subproject commit " + dummyCommit.getName()));
+  }
+
+  @Test
   public void commentContextForCommitMessageForLineComment() throws Exception {
     PushOneCommit.Result result =
         createChange(testRepo, "master", SUBJECT, FILE_NAME, FILE_CONTENT, "topic");
diff --git a/javatests/com/google/gerrit/entities/SubmitRecordTest.java b/javatests/com/google/gerrit/entities/SubmitRecordTest.java
index 0e832f4..e2a5787 100644
--- a/javatests/com/google/gerrit/entities/SubmitRecordTest.java
+++ b/javatests/com/google/gerrit/entities/SubmitRecordTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Collection;
 import org.junit.Test;
@@ -67,4 +68,19 @@
 
     assertThat(SubmitRecord.allRecordsOK(submitRecords)).isFalse();
   }
+
+  @Test
+  public void deepCopy() {
+    SubmitRecord record = new SubmitRecord();
+    record.status = SubmitRecord.Status.CLOSED;
+    record.errorMessage = "ouch";
+    record.requirements =
+        ImmutableList.of(SubmitRequirement.builder().setFallbackText("foo").setType("baz").build());
+    SubmitRecord.Label label = new SubmitRecord.Label();
+    label.label = "Code-Review";
+    record.labels = ImmutableList.of(label);
+
+    assertThat(record).isNotSameInstanceAs(record.deepCopy());
+    assertThat(record).isEqualTo(record.deepCopy());
+  }
 }
diff --git a/plugins/codemirror-editor b/plugins/codemirror-editor
index 740c35a..abe8a75 160000
--- a/plugins/codemirror-editor
+++ b/plugins/codemirror-editor
@@ -1 +1 @@
-Subproject commit 740c35ae36f44748b3c91e60ee7dcb2fb6e99549
+Subproject commit abe8a75f7bedc75a73bd52d3acbc11bc754706f0
diff --git a/polygerrit-ui/app/.eslintrc.js b/polygerrit-ui/app/.eslintrc.js
index c2ae411..faf126c 100644
--- a/polygerrit-ui/app/.eslintrc.js
+++ b/polygerrit-ui/app/.eslintrc.js
@@ -82,7 +82,7 @@
     ],
     // https://eslint.org/docs/rules/new-cap
     'new-cap': ['error', {
-      capIsNewExceptions: ['Polymer', 'GestureEventListeners'],
+      capIsNewExceptions: ['Polymer'],
       capIsNewExceptionPattern: '^.*Mixin$',
     }],
     // https://eslint.org/docs/rules/no-console
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
index cbb3d95..8c756cd 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
@@ -21,7 +21,6 @@
 import '../../shared/gr-icons/gr-icons';
 import '../gr-permission/gr-permission';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {htmlTemplate} from './gr-access-section_html';
 import {
@@ -71,9 +70,7 @@
 }
 
 @customElement('gr-access-section')
-export class GrAccessSection extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccessSection extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
index 4fa84eb..221ab54 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
@@ -21,7 +21,6 @@
 import '../../shared/gr-list-view/gr-list-view';
 import '../../shared/gr-overlay/gr-overlay';
 import '../gr-create-group-dialog/gr-create-group-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-admin-group-list_html';
@@ -50,7 +49,7 @@
 
 @customElement('gr-admin-group-list')
 export class GrAdminGroupList extends ListViewMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
index f2b4c89..31f87ce 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
@@ -31,7 +31,6 @@
 import '../gr-repo-dashboards/gr-repo-dashboards';
 import '../gr-repo-detail-list/gr-repo-detail-list';
 import '../gr-repo-list/gr-repo-list';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-admin-view_html';
@@ -92,9 +91,7 @@
 }
 
 @customElement('gr-admin-view')
-export class GrAdminView extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAdminView extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
index 79a3e95..1e38aa9 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-delete-item-dialog_html';
@@ -36,8 +35,8 @@
 }
 
 @customElement('gr-confirm-delete-item-dialog')
-export class GrConfirmDeleteItemDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrConfirmDeleteItemDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
index 2124949..a2b17ead5 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
@@ -20,7 +20,6 @@
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-create-change-dialog_html';
@@ -50,9 +49,7 @@
   };
 }
 @customElement('gr-create-change-dialog')
-export class GrCreateChangeDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateChangeDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
index e68f6c9..39dbca8 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
@@ -17,7 +17,6 @@
 import '@polymer/iron-input/iron-input';
 import '../../../styles/gr-form-styles';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-create-group-dialog_html';
@@ -28,9 +27,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-create-group-dialog')
-export class GrCreateGroupDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateGroupDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
index 6334670..afcb026 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-create-pointer-dialog_html';
@@ -35,9 +34,7 @@
 }
 
 @customElement('gr-create-pointer-dialog')
-export class GrCreatePointerDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCreatePointerDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
index f320fb1..ec768ff 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
@@ -20,7 +20,6 @@
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-create-repo-dialog_html';
@@ -43,9 +42,7 @@
 }
 
 @customElement('gr-create-repo-dialog')
-export class GrCreateRepoDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateRepoDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
index 201b340..6338988 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-date-formatter/gr-date-formatter';
 import '../../shared/gr-account-link/gr-account-link';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-group-audit-log_html';
@@ -40,7 +39,7 @@
 
 @customElement('gr-group-audit-log')
 export class GrGroupAuditLog extends ListViewMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
index 54f58c2..79eee7d 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
@@ -24,7 +24,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-overlay/gr-overlay';
 import '../gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-group-members_html';
@@ -63,9 +62,7 @@
   };
 }
 @customElement('gr-group-members')
-export class GrGroupMembers extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrGroupMembers extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 84daef8..8e49479 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -22,7 +22,6 @@
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
 import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-group_html';
@@ -71,9 +70,7 @@
 }
 
 @customElement('gr-group')
-export class GrGroup extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrGroup extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
index 85ba052..6528d35 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
@@ -23,7 +23,6 @@
 import '../../shared/gr-button/gr-button';
 import '../gr-rule-editor/gr-rule-editor';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-permission_html';
@@ -94,9 +93,7 @@
  * @event added-permission-removed
  */
 @customElement('gr-permission')
-export class GrPermission extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrPermission extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
index 1ab32ea..7c7c948 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
@@ -20,7 +20,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-plugin-config-array-editor_html';
@@ -38,9 +37,7 @@
 }
 
 @customElement('gr-plugin-config-array-editor')
-class GrPluginConfigArrayEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrPluginConfigArrayEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
index f5e9a92..a6a1a42 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
@@ -17,7 +17,6 @@
 import '../../../styles/gr-table-styles';
 import '../../../styles/shared-styles';
 import '../../shared/gr-list-view/gr-list-view';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-plugin-list_html';
@@ -37,7 +36,7 @@
 }
 @customElement('gr-plugin-list')
 export class GrPluginList extends ListViewMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 56c5733..17a9ee6 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../gr-access-section/gr-access-section';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-access_html';
@@ -63,9 +62,7 @@
  * @event show-alert
  */
 @customElement('gr-repo-access')
-export class GrRepoAccess extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoAccess extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
index f209729..5a6f0c5 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
@@ -23,7 +23,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../shared/gr-overlay/gr-overlay';
 import '../gr-create-change-dialog/gr-create-change-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-commands_html';
@@ -61,9 +60,7 @@
 }
 
 @customElement('gr-repo-commands')
-export class GrRepoCommands extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoCommands extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
index 7b3c7fb..a132f64 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
@@ -17,7 +17,6 @@
 
 import '../../../styles/shared-styles';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-dashboards_html';
@@ -34,9 +33,7 @@
 }
 
 @customElement('gr-repo-dashboards')
-export class GrRepoDashboards extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoDashboards extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
index a486e27..4cb325c 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
@@ -28,7 +28,6 @@
 import '../gr-create-pointer-dialog/gr-create-pointer-dialog';
 import '../gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-detail-list_html';
@@ -63,7 +62,7 @@
 }
 @customElement('gr-repo-detail-list')
 export class GrRepoDetailList extends ListViewMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
index d6aa0e6..e5225f0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
@@ -20,7 +20,6 @@
 import '../../shared/gr-list-view/gr-list-view';
 import '../../shared/gr-overlay/gr-overlay';
 import '../gr-create-repo-dialog/gr-create-repo-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-list_html';
@@ -50,7 +49,7 @@
 
 @customElement('gr-repo-list')
 export class GrRepoList extends ListViewMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
index e9a6158..347a56b 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
@@ -24,7 +24,6 @@
 import '../../shared/gr-tooltip-content/gr-tooltip-content';
 import '../gr-plugin-config-array-editor/gr-plugin-config-array-editor';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-plugin-config_html';
@@ -62,9 +61,7 @@
 }
 
 @customElement('gr-repo-plugin-config')
-class GrRepoPluginConfig extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrRepoPluginConfig extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
index b6881ff..572612f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -24,7 +24,6 @@
 import '../../../styles/gr-subpage-styles';
 import '../../../styles/shared-styles';
 import '../gr-repo-plugin-config/gr-repo-plugin-config';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo_html';
@@ -83,9 +82,7 @@
 };
 
 @customElement('gr-repo')
-export class GrRepo extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRepo extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
index 13d0e50..c3b35a9 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-rule-editor_html';
@@ -102,9 +101,7 @@
 }
 
 @customElement('gr-rule-editor')
-export class GrRuleEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRuleEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
index 558037d..64e2810 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
@@ -26,7 +26,6 @@
 import '../../../styles/shared-styles';
 import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
 import '../../plugins/gr-endpoint-param/gr-endpoint-param';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-list-item_html';
@@ -79,7 +78,7 @@
 
 @customElement('gr-change-list-item')
 export class GrChangeListItem extends ChangeTableMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
index 42741fa..60fcd1f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
@@ -20,7 +20,6 @@
 import '../gr-repo-header/gr-repo-header';
 import '../gr-user-header/gr-user-header';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-list-view_html';
@@ -62,9 +61,7 @@
 }
 
 @customElement('gr-change-list-view')
-export class GrChangeListView extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrChangeListView extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index f26cd46..c9b095c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -21,7 +21,6 @@
 import '../../../styles/shared-styles';
 import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
 import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-list_html';
@@ -74,9 +73,7 @@
 }
 @customElement('gr-change-list')
 export class GrChangeList extends ChangeTableMixin(
-  KeyboardShortcutMixin(
-    GestureEventListeners(LegacyElementMixin(PolymerElement))
-  )
+  KeyboardShortcutMixin(LegacyElementMixin(PolymerElement))
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
index f320296..a6f3d85 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
@@ -18,7 +18,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-icons/gr-icons';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement} from '@polymer/decorators';
@@ -32,9 +31,7 @@
 }
 
 @customElement('gr-create-change-help')
-class GrCreateChangeHelp extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrCreateChangeHelp extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
index 1ee8cb5..ed4c968 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-overlay/gr-overlay';
 import '../../shared/gr-shell-command/gr-shell-command';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement, property} from '@polymer/decorators';
@@ -44,9 +43,7 @@
 }
 
 @customElement('gr-create-commands-dialog')
-export class GrCreateCommandsDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateCommandsDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
index e53f68b..5c263bb 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../shared/gr-overlay/gr-overlay';
 import '../../shared/gr-repo-branch-picker/gr-repo-branch-picker';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-create-destination-dialog_html';
@@ -44,8 +43,8 @@
 }
 
 @customElement('gr-create-destination-dialog')
-export class GrCreateDestinationDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrCreateDestinationDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
index a34bd63..d834b16 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
@@ -23,7 +23,6 @@
 import '../gr-create-change-help/gr-create-change-help';
 import '../gr-create-destination-dialog/gr-create-destination-dialog';
 import '../gr-user-header/gr-user-header';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-dashboard-view_html';
@@ -79,9 +78,7 @@
 }
 
 @customElement('gr-dashboard-view')
-export class GrDashboardView extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDashboardView extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
index 35a2a7f..ec24800 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
@@ -18,7 +18,6 @@
 import '../../../styles/dashboard-header-styles';
 import '../../../styles/shared-styles';
 import '../../shared/gr-date-formatter/gr-date-formatter';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-header_html';
@@ -28,9 +27,7 @@
 
 /** @extends PolymerElement */
 @customElement('gr-repo-header')
-class GrRepoHeader extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrRepoHeader extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
index cfee0cd..c4406cd 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
@@ -21,7 +21,6 @@
 import '../../shared/gr-avatar/gr-avatar';
 import '../../shared/gr-date-formatter/gr-date-formatter';
 import '../../../styles/dashboard-header-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-user-header_html';
@@ -32,9 +31,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-user-header')
-export class GrUserHeader extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrUserHeader extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 87b09c7..147ebc3 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -30,7 +30,6 @@
 import '../gr-confirm-submit-dialog/gr-confirm-submit-dialog';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-actions_html';
@@ -338,8 +337,7 @@
 }
 
 @customElement('gr-change-actions')
-export class GrChangeActions
-  extends GestureEventListeners(LegacyElementMixin(PolymerElement))
+export class GrChangeActions extends LegacyElementMixin(PolymerElement)
   implements GrChangeActionsElement {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
index 68e2368..44974ce 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
@@ -33,7 +33,6 @@
 import '../gr-reviewer-list/gr-reviewer-list';
 import '../../shared/gr-account-list/gr-account-list';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-metadata_html';
@@ -67,7 +66,7 @@
   ServerInfo,
   TopicName,
 } from '../../../types/common';
-import {assertNever} from '../../../utils/common-util';
+import {assertNever, unique} from '../../../utils/common-util';
 import {GrEditableLabel} from '../../shared/gr-editable-label/gr-editable-label';
 import {GrLinkedChip} from '../../shared/gr-linked-chip/gr-linked-chip';
 import {appContext} from '../../../services/app-context';
@@ -78,7 +77,15 @@
   DisplayRules,
 } from '../../../utils/change-metadata-util';
 import {fireEvent} from '../../../utils/event-util';
-import {EditRevisionInfo, ParsedChangeInfo} from '../../../types/types';
+import {
+  EditRevisionInfo,
+  notUndefined,
+  ParsedChangeInfo,
+} from '../../../types/types';
+import {
+  AutocompleteQuery,
+  AutocompleteSuggestion,
+} from '../../shared/gr-autocomplete/gr-autocomplete';
 
 const HASHTAG_ADD_MESSAGE = 'Add Hashtag';
 
@@ -118,9 +125,7 @@
 }
 
 @customElement('gr-change-metadata')
-export class GrChangeMetadata extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrChangeMetadata extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
@@ -206,6 +211,9 @@
   @property({type: Boolean})
   _isNewChangeSummaryUiEnabled = false;
 
+  @property({type: Object})
+  queryTopic?: AutocompleteQuery;
+
   flagsService = appContext.flagsService;
 
   restApiService = appContext.restApiService;
@@ -218,6 +226,7 @@
     this._isNewChangeSummaryUiEnabled = this.flagsService.isEnabled(
       KnownExperimentId.NEW_CHANGE_SUMMARY_UI
     );
+    this.queryTopic = (input: string) => this._getTopicSuggestions(input);
   }
 
   @observe('change.labels')
@@ -678,6 +687,18 @@
     provider.init();
     return provider;
   }
+
+  _getTopicSuggestions(input: string): Promise<AutocompleteSuggestion[]> {
+    return this.restApiService
+      .getChangesWithSimilarTopic(input)
+      .then(response =>
+        (response ?? [])
+          .map(change => change.topic)
+          .filter(notUndefined)
+          .filter(unique)
+          .map(topic => ({name: topic, value: topic}))
+      );
+  }
 }
 
 declare global {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
index 59bf8ad..4f5e6a6 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
@@ -363,6 +363,8 @@
             read-only="[[_topicReadOnly]]"
             on-changed="_handleTopicChanged"
             show-as-edit-pencil="[[_isNewChangeSummaryUiEnabled]]"
+            autocomplete="true"
+            query="[[queryTopic]]"
           ></gr-editable-label>
         </template>
       </span>
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
index e3fdf7a..0b65f53 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
@@ -20,7 +20,6 @@
 import '../../shared/gr-label/gr-label';
 import '../../shared/gr-label-info/gr-label-info';
 import '../../shared/gr-limited-text/gr-limited-text';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-requirements_html';
@@ -58,9 +57,7 @@
 }
 
 @customElement('gr-change-requirements')
-class GrChangeRequirements extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrChangeRequirements extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index abf113c..f555b01 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -45,7 +45,6 @@
 import '../gr-upload-help-dialog/gr-upload-help-dialog';
 import '../../checks/gr-checks-tab';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-view_html';
@@ -250,7 +249,7 @@
 
 @customElement('gr-change-view')
 export class GrChangeView extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
index 18bd3a0..0b148b7 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
@@ -16,7 +16,6 @@
  */
 import '../../../styles/shared-styles';
 import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-commit-info_html';
@@ -31,9 +30,7 @@
 }
 
 @customElement('gr-commit-info')
-export class GrCommitInfo extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCommitInfo extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
index 10563ee..df99471 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
@@ -17,7 +17,6 @@
 import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-abandon-dialog_html';
@@ -42,7 +41,7 @@
  */
 @customElement('gr-confirm-abandon-dialog')
 export class GrConfirmAbandonDialog extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
index 2f33858..5aa5e8b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../../../styles/shared-styles';
 import '../../shared/gr-dialog/gr-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-cherrypick-conflict-dialog_html';
@@ -29,8 +28,8 @@
 }
 
 @customElement('gr-confirm-cherrypick-conflict-dialog')
-export class GrConfirmCherrypickConflictDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrConfirmCherrypickConflictDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index ebcabbf..3475e45 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../shared/gr-dialog/gr-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-cherrypick-dialog_html';
@@ -75,8 +74,8 @@
 }
 
 @customElement('gr-confirm-cherrypick-dialog')
-export class GrConfirmCherrypickDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrConfirmCherrypickDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
index 5e95e66..9da7ea2 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
@@ -17,7 +17,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../shared/gr-dialog/gr-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-move-dialog_html';
@@ -31,7 +30,7 @@
 
 @customElement('gr-confirm-move-dialog')
 export class GrConfirmMoveDialog extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
index b2b6e61..aa8745a 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
@@ -17,7 +17,6 @@
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-rebase-dialog_html';
@@ -49,9 +48,7 @@
 }
 
 @customElement('gr-confirm-rebase-dialog')
-export class GrConfirmRebaseDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmRebaseDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
index e10b12b..a785afd 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
@@ -17,7 +17,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
 import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-revert-dialog_html';
@@ -41,9 +40,7 @@
 }
 
 @customElement('gr-confirm-revert-dialog')
-export class GrConfirmRevertDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmRevertDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
index 9e1256f..609947d 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-revert-submission-dialog_html';
@@ -29,8 +28,8 @@
 const CHANGE_SUBJECT_LIMIT = 50;
 
 @customElement('gr-confirm-revert-submission-dialog')
-export class GrConfirmRevertSubmissionDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrConfirmRevertSubmissionDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
index df0678ee..7130907 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
@@ -21,7 +21,6 @@
 import '../../plugins/gr-endpoint-param/gr-endpoint-param';
 import '../../../styles/shared-styles';
 import '../gr-thread-list/gr-thread-list';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-submit-dialog_html';
@@ -37,9 +36,7 @@
   };
 }
 @customElement('gr-confirm-submit-dialog')
-export class GrConfirmSubmitDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmSubmitDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
index ab1e4e6..0aae46c 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../../../styles/shared-styles';
 import '../../shared/gr-download-commands/gr-download-commands';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-download-dialog_html';
@@ -38,9 +37,7 @@
 }
 
 @customElement('gr-download-dialog')
-export class GrDownloadDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDownloadDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index 146b3e2..851dc63 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -25,7 +25,6 @@
 import '../../shared/gr-icons/gr-icons';
 import '../gr-commit-info/gr-commit-info';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-file-list-header_html';
@@ -75,7 +74,7 @@
 
 @customElement('gr-file-list-header')
 export class GrFileListHeader extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index c2947a6..076fc7f 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -28,7 +28,6 @@
 import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
 import '../../shared/gr-file-status-chip/gr-file-status-chip';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-file-list_html';
@@ -171,7 +170,7 @@
 
 @customElement('gr-file-list')
 export class GrFileList extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
index c57a2d5..9b6decd 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
@@ -375,6 +375,8 @@
                 </gr-endpoint-param>
                 <gr-endpoint-param name="path" value="[[file.__path]]">
                 </gr-endpoint-param>
+                <gr-endpoint-param name="oldPath" value="[[file.old_path]]">
+                </gr-endpoint-param>
               </gr-endpoint-decorator>
             </template>
           </template>
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
index b50bff4..55c505a 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
@@ -17,7 +17,6 @@
 import '@polymer/iron-input/iron-input';
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-included-in-dialog_html';
@@ -31,9 +30,7 @@
 }
 
 @customElement('gr-included-in-dialog')
-export class GrIncludedInDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrIncludedInDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
index 60a6058..7ea2075 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../../styles/gr-voting-styles';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-label-score-row_html';
@@ -56,9 +55,7 @@
 }
 
 @customElement('gr-label-score-row')
-export class GrLabelScoreRow extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrLabelScoreRow extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
index 661cd1a..526d01e 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-label-score-row/gr-label-score-row';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-label-scores_html';
@@ -40,9 +39,7 @@
 import {labelCompare} from '../../../utils/label-util';
 
 @customElement('gr-label-scores')
-export class GrLabelScores extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrLabelScores extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
index f913459..d0e9e23 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
@@ -23,7 +23,6 @@
 import '../../shared/gr-formatted-text/gr-formatted-text';
 import '../../../styles/shared-styles';
 import '../../../styles/gr-voting-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-message_html';
@@ -84,9 +83,7 @@
 }
 
 @customElement('gr-message')
-export class GrMessage extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrMessage extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
index bc3f167..16d9d39 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-icons/gr-icons';
 import '../gr-message/gr-message';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-messages-list_html';
@@ -214,7 +213,7 @@
 
 @customElement('gr-messages-list')
 export class GrMessagesList extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
index 5705c4f..788a42d 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
@@ -19,7 +19,6 @@
 import '../../plugins/gr-endpoint-param/gr-endpoint-param';
 import '../../plugins/gr-endpoint-slot/gr-endpoint-slot';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-related-changes-list_html';
@@ -53,9 +52,7 @@
 }
 
 @customElement('gr-related-changes-list')
-export class GrRelatedChangesList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRelatedChangesList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index a8e89b6..1175b1d 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -26,7 +26,6 @@
 import '../gr-label-scores/gr-label-scores';
 import '../gr-thread-list/gr-thread-list';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-reply-dialog_html';
@@ -173,7 +172,7 @@
 
 @customElement('gr-reply-dialog')
 export class GrReplyDialog extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
index 30931c3..ec895d9 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-reviewer-list_html';
@@ -45,9 +44,7 @@
 import {KnownExperimentId} from '../../../services/flags/flags';
 
 @customElement('gr-reviewer-list')
-export class GrReviewerList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrReviewerList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
index f0ec7cd..b7592b0 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
@@ -18,7 +18,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-comment-thread/gr-comment-thread';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-thread-list_html';
@@ -57,9 +56,7 @@
 }
 
 @customElement('gr-thread-list')
-export class GrThreadList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrThreadList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
index d52da80..d26ae53 100644
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
@@ -17,7 +17,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../shared/gr-shell-command/gr-shell-command';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-upload-help-dialog_html';
@@ -32,9 +31,7 @@
 const PREFERRED_FETCH_COMMAND_ORDER = ['checkout', 'cherry pick', 'pull'];
 
 @customElement('gr-upload-help-dialog')
-export class GrUploadHelpDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrUploadHelpDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
index 0361b9a..33c95db 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-dropdown/gr-dropdown';
 import '../../../styles/shared-styles';
 import '../../shared/gr-avatar/gr-avatar';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-dropdown_html';
@@ -37,9 +36,7 @@
 }
 
 @customElement('gr-account-dropdown')
-export class GrAccountDropdown extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountDropdown extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
index b28b13e..181e132 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../../shared/gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-error-dialog_html';
@@ -29,9 +28,7 @@
 }
 
 @customElement('gr-error-dialog')
-export class GrErrorDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrErrorDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
index 4a86005..4aad50d 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
@@ -19,7 +19,6 @@
 import '../gr-error-dialog/gr-error-dialog';
 import '../../shared/gr-alert/gr-alert';
 import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-error-manager_html';
@@ -77,9 +76,7 @@
 const DEBOUNCER_CHECK_LOGGED_IN = 'checkLoggedIn';
 
 @customElement('gr-error-manager')
-export class GrErrorManager extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrErrorManager extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
index 4bd90ea..b76f0d3 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -17,7 +17,6 @@
 import '../../shared/gr-button/gr-button';
 import '../gr-key-binding-display/gr-key-binding-display';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-keyboard-shortcuts-dialog_html';
@@ -42,7 +41,7 @@
 
 @customElement('gr-keyboard-shortcuts-dialog')
 export class GrKeyboardShortcutsDialog extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index bed07a6..847e49f 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-icons/gr-icons';
 import '../gr-account-dropdown/gr-account-dropdown';
 import '../gr-smart-search/gr-smart-search';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-main-header_html';
@@ -101,9 +100,7 @@
 ]);
 
 @customElement('gr-main-header')
-export class GrMainHeader extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrMainHeader extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index e0bd0b9..c5e4c7a 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {
@@ -287,9 +286,7 @@
 }
 
 @customElement('gr-router')
-export class GrRouter extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRouter extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index ae1985c..942effe 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -17,7 +17,6 @@
 import '../../shared/gr-autocomplete/gr-autocomplete';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-search-bar_html';
@@ -148,7 +147,7 @@
 
 @customElement('gr-search-bar')
 export class GrSearchBar extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
index b698732..c5d6df9 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../gr-search-bar/gr-search-bar';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-smart-search_html';
@@ -35,9 +34,7 @@
 const ME_EXPRESSION = 'me';
 
 @customElement('gr-smart-search')
-export class GrSmartSearch extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrSmartSearch extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index e381213..24f34a6 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../shared/gr-overlay/gr-overlay';
 import '../gr-diff/gr-diff';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-apply-fix-dialog_html';
@@ -53,9 +52,7 @@
 }
 
 @customElement('gr-apply-fix-dialog')
-export class GrApplyFixDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrApplyFixDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
index 55deb46..0ca6ea3 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-comment-api_html';
@@ -596,9 +595,7 @@
 export const _testOnly_getCommentsForPath =
   ChangeComments.prototype.getCommentsForPath;
 @customElement('gr-comment-api')
-export class GrCommentApi extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCommentApi extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts
index 6f9705f..388cc73 100644
--- a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-coverage-layer_html';
@@ -35,8 +34,7 @@
 ]);
 
 @customElement('gr-coverage-layer')
-export class GrCoverageLayer
-  extends GestureEventListeners(LegacyElementMixin(PolymerElement))
+export class GrCoverageLayer extends LegacyElementMixin(PolymerElement)
   implements DiffLayer {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
index a506462..25aac8d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-hovercard/gr-hovercard';
 import '../gr-ranged-comment-layer/gr-ranged-comment-layer';
 import './gr-diff-builder-side-by-side';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-builder-element_html';
@@ -67,9 +66,7 @@
 }
 
 @customElement('gr-diff-builder')
-export class GrDiffBuilderElement extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffBuilderElement extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
index cc3be07..a19968c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
@@ -25,7 +25,6 @@
 } from '../../shared/gr-cursor-manager/gr-cursor-manager';
 import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
 import {dom} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-cursor_html';
@@ -54,9 +53,7 @@
 }
 
 @customElement('gr-diff-cursor')
-export class GrDiffCursor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffCursor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
index 094f2d7..0f53a26 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
@@ -17,7 +17,6 @@
 import '../../../styles/shared-styles';
 import '../gr-selection-action-box/gr-selection-action-box';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-highlight_html';
@@ -57,9 +56,7 @@
 const DEBOUNCER_SELECTION_CHANGE = 'selectionChange';
 
 @customElement('gr-diff-highlight')
-export class GrDiffHighlight extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffHighlight extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
@@ -171,11 +168,11 @@
         rangeNodes.forEach(rangeNode => {
           rangeNode.classList.add('rangeHoverHighlight');
         });
-        const chipNode = threadEl.parentElement?.querySelector(
-          `gr-ranged-comment-chip[threadElRootId="${threadEl.rootId}"]`
+        const hintNode = threadEl.parentElement?.querySelector(
+          `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
         );
-        if (chipNode) {
-          chipNode.shadowRoot
+        if (hintNode) {
+          hintNode.shadowRoot
             ?.querySelectorAll('.rangeHighlight')
             .forEach(highlightNode =>
               highlightNode.classList.add('rangeHoverHighlight')
@@ -188,11 +185,11 @@
         rangeNodes.forEach(rangeNode => {
           rangeNode.classList.remove('rangeHoverHighlight');
         });
-        const chipNode = threadEl.parentElement?.querySelector(
-          `gr-ranged-comment-chip[threadElRootId="${threadEl.rootId}"]`
+        const hintNode = threadEl.parentElement?.querySelector(
+          `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
         );
-        if (chipNode) {
-          chipNode.shadowRoot
+        if (hintNode) {
+          hintNode.shadowRoot
             ?.querySelectorAll('.rangeHoverHighlight')
             .forEach(highlightNode =>
               highlightNode.classList.remove('rangeHoverHighlight')
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index a64f535..e6f08b01 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -16,7 +16,6 @@
  */
 import '../../shared/gr-comment-thread/gr-comment-thread';
 import '../gr-diff/gr-diff';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-host_html';
@@ -131,9 +130,7 @@
  * specific component, while <gr-diff> is a re-usable component.
  */
 @customElement('gr-diff-host')
-export class GrDiffHost extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffHost extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
index 60f2853..0a22556 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
 import {DiffViewMode} from '../../../constants/constants';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-mode-selector_html';
@@ -29,9 +28,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-diff-mode-selector')
-export class GrDiffModeSelector extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffModeSelector extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
index 8829afc..96c2c03 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-diff-preferences/gr-diff-preferences';
 import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-preferences-dialog_html';
@@ -37,8 +36,8 @@
   };
 }
 @customElement('gr-diff-preferences-dialog')
-export class GrDiffPreferencesDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrDiffPreferencesDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
index 9fafcfa..f4772e3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {
@@ -92,9 +91,7 @@
  *    the rest is not.
  */
 @customElement('gr-diff-processor')
-export class GrDiffProcessor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffProcessor extends LegacyElementMixin(PolymerElement) {
   @property({type: Number})
   context = 3;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
index 9493478..39acb86 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
@@ -17,7 +17,6 @@
 import '../../../styles/shared-styles';
 import {addListener} from '@polymer/polymer/lib/utils/gestures';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-selection_html';
@@ -53,9 +52,7 @@
 }
 
 @customElement('gr-diff-selection')
-export class GrDiffSelection extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffSelection extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index aaf555b..d8dbb49 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -31,7 +31,6 @@
 import '../gr-diff-preferences-dialog/gr-diff-preferences-dialog';
 import '../gr-patch-range-select/gr-patch-range-select';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-view_html';
@@ -127,7 +126,7 @@
 
 @customElement('gr-diff-view')
 export class GrDiffView extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
index df47694..802397b 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
@@ -22,10 +22,9 @@
 import '../gr-diff-selection/gr-diff-selection';
 import '../gr-syntax-themes/gr-syntax-theme';
 import '../gr-ranged-comment-themes/gr-ranged-comment-theme';
-import '../gr-ranged-comment-chip/gr-ranged-comment-chip';
+import '../gr-ranged-comment-hint/gr-ranged-comment-hint';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {htmlTemplate} from './gr-diff_html';
 import {LineNumber} from './gr-diff-line';
@@ -113,9 +112,7 @@
 }
 
 @customElement('gr-diff')
-export class GrDiff extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiff extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
@@ -818,7 +815,7 @@
   }
 
   _handleRenderContent() {
-    this.querySelectorAll('gr-ranged-comment-chip').forEach(element =>
+    this.querySelectorAll('gr-ranged-comment-hint').forEach(element =>
       element.remove()
     );
     this._setLoading(false);
@@ -866,14 +863,14 @@
 
         const slotAtt = threadEl.getAttribute('slot');
         if (range && isLongCommentRange(range) && slotAtt) {
-          const longRangeCommentChip = document.createElement(
-            'gr-ranged-comment-chip'
+          const longRangeCommentHint = document.createElement(
+            'gr-ranged-comment-hint'
           );
-          longRangeCommentChip.range = range;
-          longRangeCommentChip.setAttribute('threadElRootId', threadEl.rootId);
-          longRangeCommentChip.setAttribute('slot', slotAtt);
-          this.insertBefore(longRangeCommentChip, threadEl);
-          this._redispatchHoverEvents(longRangeCommentChip, threadEl);
+          longRangeCommentHint.range = range;
+          longRangeCommentHint.setAttribute('threadElRootId', threadEl.rootId);
+          longRangeCommentHint.setAttribute('slot', slotAtt);
+          this.insertBefore(longRangeCommentHint, threadEl);
+          this._redispatchHoverEvents(longRangeCommentHint, threadEl);
         }
 
         // Create a slot for the thread and attach it to the thread group.
@@ -898,7 +895,7 @@
       const removedThreadEls = info.removedNodes.filter(isThreadEl);
       for (const threadEl of removedThreadEls) {
         this.querySelector(
-          `gr-ranged-comment-chip[threadElRootId="${threadEl.rootId}"]`
+          `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
         )?.remove();
       }
     });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
index f68d742..12803b3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
@@ -229,25 +229,22 @@
     }
 
     .delta.dueToMove .movedIn .moveDescription {
-      color: var(--diff-moved-in-background);
-      background-color: var(--diff-moved-in-label-background);
+      color: var(--diff-moved-in-label-color);
     }
     .delta.dueToMove .movedOut .moveDescription {
-      color: var(--diff-moved-out-background);
-      background-color: var(--diff-moved-out-label-background);
+      color: var(--diff-moved-out-label-color);
     }
     .moveLabel {
-      display: flex;
-      justify-content: flex-end;
       font-family: var(--font-family, ''), 'Roboto Mono';
       font-size: var(--font-size-small, 12px);
-    }
-    .delta.dueToMove .moveDescription {
-      border-radius: var(--fully-rounded-radius, 1000px);
+      font-weight: var(--code-hint-font-weight, 500);
+      line-height: var(--line-height-small, 16px);
       padding: var(--spacing-s) var(--spacing-m);
       margin: var(--spacing-s);
-      line-height: var(--line-height-small, 16px);
+    }
+    .delta.dueToMove .moveDescription {
       display: flex;
+      justify-content: flex-end;
     }
 
     .moveDescription iron-icon {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
index 4035f76..c6bd8d6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
@@ -555,7 +555,7 @@
           .calledWithExactly(fakeLineEl, 42));
     });
 
-    test('adds long range comment chip', async () => {
+    test('adds long range comment hint', async () => {
       const range = {
         start_line: 1,
         end_line: 12,
@@ -580,10 +580,10 @@
       await flush();
 
       assert.deepEqual(
-          element.querySelector('gr-ranged-comment-chip').range, range);
+          element.querySelector('gr-ranged-comment-hint').range, range);
     });
 
-    test('no duplicate range chip for same thread', async () => {
+    test('no duplicate range hint for same thread', async () => {
       const range = {
         start_line: 1,
         end_line: 12,
@@ -596,10 +596,10 @@
       threadEl.setAttribute('line-num', 1);
       threadEl.setAttribute('range', JSON.stringify(range));
       threadEl.setAttribute('slot', 'right-1');
-      const firstChip = document.createElement('gr-ranged-comment-chip');
-      firstChip.range = range;
-      firstChip.setAttribute('threadElRootId', threadEl.rootId);
-      firstChip.setAttribute('slot', 'right-1');
+      const firstHint = document.createElement('gr-ranged-comment-hint');
+      firstHint.range = range;
+      firstHint.setAttribute('threadElRootId', threadEl.rootId);
+      firstHint.setAttribute('slot', 'right-1');
       const content = [{
         a: [],
         b: [],
@@ -608,7 +608,7 @@
       }];
       setupSampleDiff({content});
 
-      element.appendChild(firstChip);
+      element.appendChild(firstHint);
       await flush();
       element._handleRenderContent();
       await flush();
@@ -616,10 +616,10 @@
       await flush();
 
       assert.equal(
-          element.querySelectorAll('gr-ranged-comment-chip').length, 1);
+          element.querySelectorAll('gr-ranged-comment-hint').length, 1);
     });
 
-    test('removes long range comment chip when comment is discarded',
+    test('removes long range comment hint when comment is discarded',
         async () => {
           const range = {
             start_line: 1,
@@ -646,7 +646,7 @@
           threadEl.remove();
           await flush();
 
-          assert.isEmpty(element.querySelectorAll('gr-ranged-comment-chip'));
+          assert.isEmpty(element.querySelectorAll('gr-ranged-comment-hint'));
         });
 
     suite('change in preferences', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
index 1ce2506..820971b 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-dropdown-list/gr-dropdown-list';
 import '../../shared/gr-select/gr-select';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-patch-range-select_html';
@@ -84,9 +83,7 @@
  * @extends PolymerElement
  */
 @customElement('gr-patch-range-select')
-export class GrPatchRangeSelect extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrPatchRangeSelect extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
similarity index 83%
rename from polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip.ts
rename to polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
index 6948283..3d35c26 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
@@ -17,11 +17,11 @@
 
 import {customElement, property} from '@polymer/decorators';
 import {CommentRange} from '../../../types/common';
-import {htmlTemplate} from './gr-ranged-comment-chip_html';
+import {htmlTemplate} from './gr-ranged-comment-hint_html';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 
-@customElement('gr-ranged-comment-chip')
-export class GrRangedCommentChip extends PolymerElement {
+@customElement('gr-ranged-comment-hint')
+export class GrRangedCommentHint extends PolymerElement {
   static get template() {
     return htmlTemplate;
   }
@@ -37,6 +37,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    'gr-ranged-comment-chip': GrRangedCommentChip;
+    'gr-ranged-comment-hint': GrRangedCommentHint;
   }
 }
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_html.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_html.ts
similarity index 74%
rename from polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_html.ts
rename to polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_html.ts
index c2861fa..670bfd2 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_html.ts
@@ -22,31 +22,25 @@
   </style>
   <style include="shared-styles">
     .row {
-      color: var(--ranged-comment-chip-text-color);
+      color: var(--ranged-comment-hint-text-color);
       display: flex;
       font-family: var(--font-family, ''), 'Roboto Mono';
       font-size: var(--font-size-small, 12px);
+      font-weight: var(--code-hint-font-weight, 500);
       line-height: var(--line-height-small, 16px);
       justify-content: flex-end;
       margin: var(--spacing-xs) 0;
+      padding: var(--spacing-s) var(--spacing-l);
     }
     .icon {
-      color: var(--ranged-comment-chip-text-color);
+      color: var(--ranged-comment-hint-text-color);
       height: var(--line-height-small, 16px);
       width: var(--line-height-small, 16px);
       margin-right: var(--spacing-s);
     }
-    .chip {
-      background-color: var(--ranged-comment-chip-background);
-      border-radius: var(--fully-rounded-radius, 1000px);
-      margin: var(--spacing-s);
-      padding: var(--spacing-s) var(--spacing-m);
-    }
   </style>
   <div class="row rangeHighlight">
-    <div class="chip">
-      <iron-icon class="icon" icon="gr-icons:comment-outline"></iron-icon>
-      [[_computeRangeLabel(range)]]
-    </div>
+    <iron-icon class="icon" icon="gr-icons:comment"></iron-icon>
+    [[_computeRangeLabel(range)]]
   </div>
 `;
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_test.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_test.ts
similarity index 83%
rename from polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_test.ts
rename to polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_test.ts
index 8bce99d..932c367 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_test.ts
@@ -17,13 +17,13 @@
 
 import '../../../test/common-test-setup-karma';
 import {CommentRange} from '../../../types/common';
-import {GrRangedCommentChip} from './gr-ranged-comment-chip';
+import {GrRangedCommentHint} from './gr-ranged-comment-hint';
 
-suite('gr-ranged-comment-chip tests', () => {
-  let element: GrRangedCommentChip;
+suite('gr-ranged-comment-hint tests', () => {
+  let element: GrRangedCommentHint;
 
   setup(() => {
-    element = fixtureFromElement('gr-ranged-comment-chip').instantiate();
+    element = fixtureFromElement('gr-ranged-comment-hint').instantiate();
   });
 
   test('shows line range', async () => {
@@ -34,7 +34,7 @@
       end_character: 3,
     } as CommentRange;
     await flush();
-    const textDiv = element.root!.querySelector<HTMLDivElement>('.chip');
+    const textDiv = element.root!.querySelector<HTMLDivElement>('.row');
     assert.equal(textDiv!.innerText.trim(), 'Long comment range 2 - 5');
   });
 });
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
index f33c2ce..45a7de6 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-ranged-comment-layer_html';
@@ -72,8 +71,7 @@
 const HOVER_HIGHLIGHT = 'style-scope gr-diff range rangeHoverHighlight';
 
 @customElement('gr-ranged-comment-layer')
-export class GrRangedCommentLayer
-  extends GestureEventListeners(LegacyElementMixin(PolymerElement))
+export class GrRangedCommentLayer extends LegacyElementMixin(PolymerElement)
   implements DiffLayer {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts
index ee52ab6..3e67c49 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts
@@ -18,7 +18,6 @@
 import {GrTooltip} from '../../shared/gr-tooltip/gr-tooltip';
 import {customElement, property} from '@polymer/decorators';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-selection-action-box_html';
@@ -37,9 +36,7 @@
 }
 
 @customElement('gr-selection-action-box')
-export class GrSelectionActionBox extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrSelectionActionBox extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
index 7df3d75..aff9c3d 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
@@ -17,7 +17,6 @@
 import '../../../styles/gr-table-styles';
 import '../../../styles/shared-styles';
 import '../../shared/gr-list-view/gr-list-view';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-documentation-search_html';
@@ -33,7 +32,7 @@
 
 @customElement('gr-documentation-search')
 export class GrDocumentationSearch extends ListViewMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
index 4c63303..eff2d94 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-default-editor_html';
@@ -33,9 +32,7 @@
 
 @customElement('gr-default-editor')
 /** @extends PolymerElement */
-export class GrDefaultEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDefaultEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
index bc153ee..e9dc40c 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
@@ -22,7 +22,6 @@
 import '../../shared/gr-overlay/gr-overlay';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-edit-controls_html';
@@ -49,9 +48,7 @@
 }
 
 @customElement('gr-edit-controls')
-export class GrEditControls extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrEditControls extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
index 9f3d1bc..609cda2 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
@@ -17,7 +17,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-dropdown/gr-dropdown';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-edit-file-controls_html';
@@ -31,9 +30,7 @@
 
 /** @extends PolymerElement */
 @customElement('gr-edit-file-controls')
-class GrEditFileControls extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrEditFileControls extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index 1e08a5c..dd9592d 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -21,7 +21,6 @@
 import '../../shared/gr-storage/gr-storage';
 import '../gr-default-editor/gr-default-editor';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-editor-view_html';
@@ -60,7 +59,7 @@
 
 @customElement('gr-editor-view')
 export class GrEditorView extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index ec3bd0f..153ec31 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -37,7 +37,6 @@
 import './settings/gr-cla-view/gr-cla-view';
 import './settings/gr-registration-dialog/gr-registration-dialog';
 import './settings/gr-settings-view/gr-settings-view';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-app-element_html';
@@ -99,7 +98,7 @@
 // TODO(TS): implement AppElement interface from gr-app-types.ts
 @customElement('gr-app-element')
 export class GrAppElement extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/gr-app.ts b/polygerrit-ui/app/elements/gr-app.ts
index f19931f..2e7618a 100644
--- a/polygerrit-ui/app/elements/gr-app.ts
+++ b/polygerrit-ui/app/elements/gr-app.ts
@@ -36,7 +36,6 @@
 
 import {initGlobalVariables} from './gr-app-global-var-init';
 import './gr-app-element';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-app_html';
@@ -47,7 +46,7 @@
 installPolymerResin(safeTypesBridge);
 
 @customElement('gr-app')
-class GrApp extends GestureEventListeners(LegacyElementMixin(PolymerElement)) {
+class GrApp extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
index 423cff9..998e84e 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-endpoint-decorator_html';
@@ -30,9 +29,7 @@
 const INIT_PROPERTIES_TIMEOUT_MS = 10000;
 
 @customElement('gr-endpoint-decorator')
-export class GrEndpointDecorator extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrEndpointDecorator extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
index 9e9f348..f48bb0f 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement, property} from '@polymer/decorators';
@@ -26,9 +25,7 @@
 }
 
 @customElement('gr-endpoint-param')
-export class GrEndpointParam extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrEndpointParam extends LegacyElementMixin(PolymerElement) {
   @property({type: String, reflectToAttribute: true})
   name = '';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
index dc3ebcf..b4fd804 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import {updateStyles} from '@polymer/polymer/lib/mixins/element-mixin';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-external-style_html';
@@ -24,9 +23,7 @@
 import {customElement, property} from '@polymer/decorators';
 
 @customElement('gr-external-style')
-class GrExternalStyle extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrExternalStyle extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
index 81b3a16..70087a5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
@@ -22,9 +21,7 @@
 import {ServerInfo} from '../../../types/common';
 
 @customElement('gr-plugin-host')
-class GrPluginHost extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrPluginHost extends LegacyElementMixin(PolymerElement) {
   @property({type: Object, observer: '_configChanged'})
   config?: ServerInfo;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts
index 7c6587a..227fab1 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-plugin-popup_html';
@@ -34,9 +33,7 @@
   };
 }
 @customElement('gr-plugin-popup')
-export class GrPluginPopup extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrPluginPopup extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
index 5786576..1bb32a1 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-date-formatter/gr-date-formatter';
 import '../../../styles/gr-form-styles';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-info_html';
@@ -30,9 +29,7 @@
 import {fireEvent} from '../../../utils/event-util';
 
 @customElement('gr-account-info')
-export class GrAccountInfo extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountInfo extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
index da180c3..8fa2c94 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
@@ -17,7 +17,6 @@
 
 import '../../../styles/gr-form-styles';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-agreements-list_html';
@@ -27,9 +26,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-agreements-list')
-export class GrAgreementsList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAgreementsList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
index c6e346b..970fb5f 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
@@ -19,7 +19,6 @@
 import '../../../styles/shared-styles';
 import '../../../styles/gr-form-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-table-editor_html';
@@ -30,7 +29,7 @@
 
 @customElement('gr-change-table-editor')
 export class GrChangeTableEditor extends ChangeTableMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
index b77f5c6..bbfcd7c 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
@@ -19,7 +19,6 @@
 import '../../../styles/gr-form-styles';
 import '../../../styles/shared-styles';
 import '../../shared/gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-cla-view_html';
@@ -40,9 +39,7 @@
 }
 
 @customElement('gr-cla-view')
-export class GrClaView extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrClaView extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
index 411d3aa..5d8cc51 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
@@ -18,7 +18,6 @@
 import '../../../styles/gr-form-styles';
 import '../../../styles/shared-styles';
 import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-edit-preferences_html';
@@ -37,9 +36,7 @@
   };
 }
 @customElement('gr-edit-preferences')
-export class GrEditPreferences extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrEditPreferences extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
deleted file mode 100644
index cffd1ae..0000000
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-edit-preferences.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-edit-preferences');
-
-suite('gr-edit-preferences tests', () => {
-  let element;
-
-  let editPreferences;
-
-  function valueOf(title, fieldsetid) {
-    const sections = element.$[fieldsetid].querySelectorAll('section');
-    let titleEl;
-    for (let i = 0; i < sections.length; i++) {
-      titleEl = sections[i].querySelector('.title');
-      if (titleEl.textContent.trim() === title) {
-        return sections[i].querySelector('.value');
-      }
-    }
-  }
-
-  setup(() => {
-    editPreferences = {
-      auto_close_brackets: false,
-      cursor_blink_rate: 0,
-      hide_line_numbers: false,
-      hide_top_menu: false,
-      indent_unit: 2,
-      indent_with_tabs: false,
-      key_map_type: 'DEFAULT',
-      line_length: 100,
-      line_wrapping: false,
-      match_brackets: true,
-      show_base: false,
-      show_tabs: true,
-      show_whitespace_errors: true,
-      syntax_highlighting: true,
-      tab_size: 8,
-      theme: 'DEFAULT',
-    };
-
-    stubRestApi('getEditPreferences').returns(Promise.resolve(editPreferences));
-
-    element = basicFixture.instantiate();
-
-    return element.loadData();
-  });
-
-  test('renders', () => {
-    // Rendered with the expected preferences selected.
-    assert.equal(valueOf('Tab width', 'editPreferences')
-        .firstElementChild.bindValue, editPreferences.tab_size);
-    assert.equal(valueOf('Columns', 'editPreferences')
-        .firstElementChild.bindValue, editPreferences.line_length);
-    assert.equal(valueOf('Indent unit', 'editPreferences')
-        .firstElementChild.bindValue, editPreferences.indent_unit);
-    assert.equal(valueOf('Syntax highlighting', 'editPreferences')
-        .firstElementChild.checked, editPreferences.syntax_highlighting);
-    assert.equal(valueOf('Show tabs', 'editPreferences')
-        .firstElementChild.checked, editPreferences.show_tabs);
-    assert.equal(valueOf('Match brackets', 'editPreferences')
-        .firstElementChild.checked, editPreferences.match_brackets);
-    assert.equal(valueOf('Line wrapping', 'editPreferences')
-        .firstElementChild.checked, editPreferences.line_wrapping);
-    assert.equal(valueOf('Indent with tabs', 'editPreferences')
-        .firstElementChild.checked, editPreferences.indent_with_tabs);
-    assert.equal(valueOf('Auto close brackets', 'editPreferences')
-        .firstElementChild.checked, editPreferences.auto_close_brackets);
-
-    assert.isFalse(element.hasUnsavedChanges);
-  });
-
-  test('save changes', () => {
-    stubRestApi('saveEditPreferences')
-        .returns(Promise.resolve());
-    const showTabsCheckbox = valueOf('Show tabs', 'editPreferences')
-        .firstElementChild;
-    showTabsCheckbox.checked = false;
-    element._handleEditShowTabsChanged();
-
-    assert.isTrue(element.hasUnsavedChanges);
-
-    // Save the change.
-    return element.save().then(() => {
-      assert.isFalse(element.hasUnsavedChanges);
-    });
-  });
-});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.ts b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.ts
new file mode 100644
index 0000000..bfdcaa0
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.ts
@@ -0,0 +1,125 @@
+/**
+ * @license
+ * Copyright (C) 2018 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.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-edit-preferences';
+import {stubRestApi} from '../../../test/test-utils';
+import {GrEditPreferences} from './gr-edit-preferences';
+import {EditPreferencesInfo} from '../../../types/common';
+import {IronInputElement} from '@polymer/iron-input';
+
+const basicFixture = fixtureFromElement('gr-edit-preferences');
+
+suite('gr-edit-preferences tests', () => {
+  let element: GrEditPreferences;
+
+  let editPreferences: EditPreferencesInfo;
+
+  function valueOf(title: string, id: string): Element {
+    const sections = element.root?.querySelectorAll(`#${id} section`) ?? [];
+    let titleEl;
+    for (let i = 0; i < sections.length; i++) {
+      titleEl = sections[i].querySelector('.title');
+      if (titleEl?.textContent?.trim() === title) {
+        const el = sections[i].querySelector('.value');
+        if (el) return el;
+      }
+    }
+    assert.fail(`element with title ${title} not found`);
+  }
+
+  setup(async () => {
+    editPreferences = {
+      auto_close_brackets: false,
+      cursor_blink_rate: 0,
+      hide_line_numbers: false,
+      hide_top_menu: false,
+      indent_unit: 2,
+      indent_with_tabs: false,
+      key_map_type: 'DEFAULT',
+      line_length: 100,
+      line_wrapping: false,
+      match_brackets: true,
+      show_base: false,
+      show_tabs: true,
+      show_whitespace_errors: true,
+      syntax_highlighting: true,
+      tab_size: 8,
+      theme: 'DEFAULT',
+    };
+
+    stubRestApi('getEditPreferences').returns(Promise.resolve(editPreferences));
+
+    element = basicFixture.instantiate();
+
+    await element.loadData();
+    await flush();
+  });
+
+  test('renders', () => {
+    // Rendered with the expected preferences selected.
+    const tabWidthInput = valueOf('Tab width', 'editPreferences')
+      .firstElementChild as IronInputElement;
+    assert.equal(tabWidthInput.bindValue, `${editPreferences.tab_size}`);
+
+    const columnsInput = valueOf('Columns', 'editPreferences')
+      .firstElementChild as IronInputElement;
+    assert.equal(columnsInput.bindValue, `${editPreferences.line_length}`);
+
+    const indentInput = valueOf('Indent unit', 'editPreferences')
+      .firstElementChild as IronInputElement;
+    assert.equal(indentInput.bindValue, `${editPreferences.indent_unit}`);
+
+    const syntaxInput = valueOf('Syntax highlighting', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    assert.equal(syntaxInput.checked, editPreferences.syntax_highlighting);
+
+    const tabsInput = valueOf('Show tabs', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    assert.equal(tabsInput.checked, editPreferences.show_tabs);
+
+    const bracketsInput = valueOf('Match brackets', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    assert.equal(bracketsInput.checked, editPreferences.match_brackets);
+
+    const wrappingInput = valueOf('Line wrapping', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    assert.equal(wrappingInput.checked, editPreferences.line_wrapping);
+
+    const indentTabsInput = valueOf('Indent with tabs', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    assert.equal(indentTabsInput.checked, editPreferences.indent_with_tabs);
+
+    const autoCloseInput = valueOf('Auto close brackets', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    assert.equal(autoCloseInput.checked, editPreferences.auto_close_brackets);
+
+    assert.isFalse(element.hasUnsavedChanges);
+  });
+
+  test('save changes', async () => {
+    const showTabsCheckbox = valueOf('Show tabs', 'editPreferences')
+      .firstElementChild as HTMLInputElement;
+    showTabsCheckbox.checked = false;
+    element._handleEditShowTabsChanged();
+
+    assert.isTrue(element.hasUnsavedChanges);
+
+    await element.save();
+    assert.isFalse(element.hasUnsavedChanges);
+  });
+});
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
index 9960d83..925d9fb 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
@@ -18,7 +18,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-email-editor_html';
@@ -27,9 +26,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-email-editor')
-export class GrEmailEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrEmailEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
index 0fd0ad9..9cce48e 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
@@ -21,7 +21,6 @@
 import '../../shared/gr-overlay/gr-overlay';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-gpg-editor_html';
@@ -46,9 +45,7 @@
   }
 }
 @customElement('gr-gpg-editor')
-export class GrGpgEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrGpgEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
index c69bebd..c24eaef 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
@@ -16,7 +16,6 @@
  */
 import '../../../styles/shared-styles';
 import '../../../styles/gr-form-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-group-list_html';
@@ -31,9 +30,7 @@
   }
 }
 @customElement('gr-group-list')
-export class GrGroupList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrGroupList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
index 9bb4b00..701c098 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
@@ -19,7 +19,6 @@
 import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
 import '../../shared/gr-overlay/gr-overlay';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-http-password_html';
@@ -40,9 +39,7 @@
 }
 
 @customElement('gr-http-password')
-export class GrHttpPassword extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrHttpPassword extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
index 837332a..221df1f 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
@@ -19,7 +19,6 @@
 import '../../admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog';
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-identities_html';
@@ -39,9 +38,7 @@
 }
 
 @customElement('gr-identities')
-export class GrIdentities extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrIdentities extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
index 805c9ca..34acaf9 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
@@ -20,7 +20,6 @@
 import '../../../styles/shared-styles';
 import '../../../styles/gr-form-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-menu-editor_html';
@@ -28,9 +27,7 @@
 import {TopMenuItemInfo} from '../../../types/common';
 
 @customElement('gr-menu-editor')
-export class GrMenuEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrMenuEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
index 85e692d..02ba85d 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
@@ -18,7 +18,6 @@
 import '../../../styles/gr-form-styles';
 import '../../shared/gr-button/gr-button';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-registration-dialog_html';
@@ -43,9 +42,7 @@
 }
 
 @customElement('gr-registration-dialog')
-export class GrRegistrationDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRegistrationDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
index 5d80a84d..887c441 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-settings-item_html';
@@ -27,9 +26,7 @@
 }
 
 @customElement('gr-settings-item')
-class GrSettingsItem extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrSettingsItem extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
index e288d20..2f89b52 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/gr-page-nav-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-settings-menu-item_html';
@@ -28,9 +27,7 @@
 }
 
 @customElement('gr-settings-menu-item')
-class GrSettingsMenuItem extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrSettingsMenuItem extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 809139d..e6858b4 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -42,7 +42,6 @@
 import '../gr-menu-editor/gr-menu-editor';
 import '../gr-ssh-editor/gr-ssh-editor';
 import '../gr-watched-projects-editor/gr-watched-projects-editor';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-settings-view_html';
@@ -120,7 +119,7 @@
 
 @customElement('gr-settings-view')
 export class GrSettingsView extends ChangeTableMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
index b30b2cb..b2373ec 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
@@ -21,7 +21,6 @@
 import '../../shared/gr-overlay/gr-overlay';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-ssh-editor_html';
@@ -46,9 +45,7 @@
   }
 }
 @customElement('gr-ssh-editor')
-export class GrSshEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrSshEditor extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
index a45e160..fe37795 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
@@ -20,7 +20,6 @@
 import '../../../styles/gr-form-styles';
 import '../../../styles/shared-styles';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-watched-projects-editor_html';
@@ -49,8 +48,8 @@
   };
 }
 @customElement('gr-watched-projects-editor')
-export class GrWatchedProjectsEditor extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrWatchedProjectsEditor extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
index 8ff7a3a..e344a1b 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
@@ -18,7 +18,6 @@
 import '../gr-button/gr-button';
 import '../gr-icons/gr-icons';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-chip_html';
@@ -27,9 +26,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-account-chip')
-export class GrAccountChip extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountChip extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
index 2562a1a..7c8c479 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
@@ -16,7 +16,6 @@
  */
 import '../../../styles/shared-styles';
 import '../gr-autocomplete/gr-autocomplete';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-entry_html';
@@ -33,9 +32,7 @@
  * and/or group with autocomplete support.
  */
 @customElement('gr-account-entry')
-export class GrAccountEntry extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountEntry extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index 3f8fe6b..4702958 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -18,7 +18,6 @@
 import '../../../styles/shared-styles';
 import '../gr-avatar/gr-avatar';
 import '../gr-hovercard-account/gr-hovercard-account';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-label_html';
@@ -34,9 +33,7 @@
 import {ShowAlertEventDetail} from '../../../types/events';
 
 @customElement('gr-account-label')
-export class GrAccountLabel extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountLabel extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
index be54f4e..5d72ca5 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
@@ -17,7 +17,6 @@
 
 import '../gr-account-label/gr-account-label';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-link_html';
@@ -26,9 +25,7 @@
 import {AccountInfo, ChangeInfo} from '../../../types/common';
 
 @customElement('gr-account-link')
-class GrAccountLink extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrAccountLink extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
index 5cc1240..3b15233 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
@@ -17,7 +17,6 @@
 import '../gr-account-chip/gr-account-chip';
 import '../gr-account-entry/gr-account-entry';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-account-list_html';
@@ -115,9 +114,7 @@
 }
 
 @customElement('gr-account-list')
-export class GrAccountList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
index a0fddcd..3b584c7 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-button/gr-button';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-alert_html';
@@ -31,9 +30,7 @@
 }
 
 @customElement('gr-alert')
-export class GrAlert extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAlert extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
index aff6d50..3550b02 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
@@ -18,7 +18,6 @@
 import '../gr-cursor-manager/gr-cursor-manager';
 import '../../../styles/shared-styles';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-autocomplete-dropdown_html';
@@ -55,9 +54,7 @@
  */
 @customElement('gr-autocomplete-dropdown')
 export class GrAutocompleteDropdown extends IronFitMixin(
-  KeyboardShortcutMixin(
-    GestureEventListeners(LegacyElementMixin(PolymerElement))
-  ),
+  KeyboardShortcutMixin(LegacyElementMixin(PolymerElement)),
   IronFitBehavior as IronFitBehavior
 ) {
   static get template() {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index f4eb053..6390237 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -20,7 +20,6 @@
 import '../gr-icons/gr-icons';
 import '../../../styles/shared-styles';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-autocomplete_html';
@@ -72,7 +71,7 @@
 
 @customElement('gr-autocomplete')
 export class GrAutocomplete extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
index 9d7e19b..72b47e0 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-avatar_html';
@@ -26,9 +25,7 @@
 import {appContext} from '../../../services/app-context';
 
 @customElement('gr-avatar')
-export class GrAvatar extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrAvatar extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
index 60b891e..72b2744 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
@@ -16,7 +16,6 @@
  */
 import '@polymer/paper-button/paper-button';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement, property, computed, observe} from '@polymer/decorators';
@@ -36,7 +35,7 @@
 
 @customElement('gr-button')
 export class GrButton extends LegacyElementMixin(
-  KeyboardShortcutMixin(TooltipMixin(GestureEventListeners(PolymerElement)))
+  KeyboardShortcutMixin(TooltipMixin(PolymerElement))
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
index 75ac465..bafc00f 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-icons/gr-icons';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-star_html';
@@ -38,7 +37,7 @@
 
 @customElement('gr-change-star')
 export class GrChangeStar extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
index 7cf9bb1..c84344e 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-tooltip-content/gr-tooltip-content';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-status_html';
@@ -46,9 +45,7 @@
 
 /** @extends PolymerElement */
 @customElement('gr-change-status')
-class GrChangeStatus extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrChangeStatus extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index e138b4d..a2c2eaa 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -19,7 +19,6 @@
 import '../gr-comment/gr-comment';
 import '../../diff/gr-diff/gr-diff';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-comment-thread_html';
@@ -76,7 +75,7 @@
 
 @customElement('gr-comment-thread')
 export class GrCommentThread extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   // KeyboardShortcutMixin Not used in this element rather other elements tests
 
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index bf376f6..c839118 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -30,7 +30,6 @@
 import '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
 import '../gr-account-label/gr-account-label';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-comment_html';
@@ -109,7 +108,7 @@
 
 @customElement('gr-comment')
 export class GrComment extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
index a636a07..6a350b0 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-dialog/gr-dialog';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-confirm-delete-comment-dialog_html';
@@ -35,8 +34,8 @@
 }
 
 @customElement('gr-confirm-delete-comment-dialog')
-export class GrConfirmDeleteCommentDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
+export class GrConfirmDeleteCommentDialog extends LegacyElementMixin(
+  PolymerElement
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
index 47dacc3..979ed02 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
@@ -19,7 +19,6 @@
 import '../gr-button/gr-button';
 import '../gr-icons/gr-icons';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-copy-clipboard_html';
@@ -41,9 +40,7 @@
 
 /** @extends PolymerElement */
 @customElement('gr-copy-clipboard')
-export class GrCopyClipboard extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCopyClipboard extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts
index 119ed20..0d60784 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-cursor-manager_html';
@@ -62,9 +61,7 @@
 }
 
 @customElement('gr-cursor-manager')
-export class GrCursorManager extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrCursorManager extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
index 5bb4f4c..e1134f9 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-date-formatter_html';
@@ -79,7 +78,7 @@
 
 @customElement('gr-date-formatter')
 export class GrDateFormatter extends TooltipMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index fa6403a..62a2b82 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-button/gr-button';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-dialog_html';
@@ -36,9 +35,7 @@
 }
 
 @customElement('gr-dialog')
-export class GrDialog extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDialog extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
index 5810222..5664e22 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
@@ -18,7 +18,6 @@
 import '../../../styles/shared-styles';
 import '../gr-button/gr-button';
 import '../gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-preferences_html';
@@ -40,9 +39,7 @@
 }
 
 @customElement('gr-diff-preferences')
-export class GrDiffPreferences extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffPreferences extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
index 4c2a417..db343c6 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
@@ -17,7 +17,6 @@
 import '@polymer/paper-tabs/paper-tabs';
 import '../gr-shell-command/gr-shell-command';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-download-commands_html';
@@ -43,9 +42,7 @@
 }
 
 @customElement('gr-download-commands')
-export class GrDownloadCommands extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDownloadCommands extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
index 888f34f..006a8de 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
@@ -22,7 +22,6 @@
 import '../gr-date-formatter/gr-date-formatter';
 import '../gr-select/gr-select';
 import '../gr-file-status-chip/gr-file-status-chip';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-dropdown-list_html';
@@ -64,9 +63,7 @@
 export type DropDownValueChangeEvent = CustomEvent<ValueChangeDetail>;
 
 @customElement('gr-dropdown-list')
-export class GrDropdownList extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrDropdownList extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
index ae9bfd7..9918456 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
@@ -20,7 +20,6 @@
 import '../gr-tooltip-content/gr-tooltip-content';
 import '../../../styles/shared-styles';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-dropdown_html';
@@ -67,7 +66,7 @@
 
 @customElement('gr-dropdown')
 export class GrDropdown extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
index 2780fbe..1ecf3d5 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
@@ -19,7 +19,6 @@
 import '../gr-storage/gr-storage';
 import '../gr-button/gr-button';
 import {GrStorage} from '../gr-storage/gr-storage';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement, property} from '@polymer/decorators';
@@ -40,9 +39,7 @@
 const DEBOUNCER_STORE = 'store';
 
 @customElement('gr-editable-content')
-export class GrEditableContent extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrEditableContent extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
index 6f0e84a..c84828c 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
@@ -18,7 +18,7 @@
 import '@polymer/paper-input/paper-input';
 import '../../../styles/shared-styles';
 import '../gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
+import '../../shared/gr-autocomplete/gr-autocomplete';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -28,6 +28,10 @@
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {PaperInputElementExt} from '../../../types/types';
 import {CustomKeyboardEvent} from '../../../types/events';
+import {
+  AutocompleteQuery,
+  GrAutocomplete,
+} from '../gr-autocomplete/gr-autocomplete';
 
 const AWAIT_MAX_ITERS = 10;
 const AWAIT_STEP = 5;
@@ -40,14 +44,13 @@
 
 export interface GrEditableLabel {
   $: {
-    input: PaperInputElementExt;
     dropdown: IronDropdownElement;
   };
 }
 
 @customElement('gr-editable-label')
 export class GrEditableLabel extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
@@ -92,6 +95,12 @@
   @property({type: Boolean})
   showAsEditPencil = false;
 
+  @property({type: Boolean})
+  autocomplete = false;
+
+  @property({type: Object})
+  query?: AutocompleteQuery;
+
   /** @override */
   ready() {
     super.ready();
@@ -120,8 +129,9 @@
     if (this.readOnly || this.editing) return;
     return this._open().then(() => {
       this._nativeInput.focus();
-      if (!this.$.input.value) return;
-      this._nativeInput.setSelectionRange(0, this.$.input.value.length);
+      const input = this.getInput();
+      if (!input?.value) return;
+      this._nativeInput.setSelectionRange(0, input.value.length);
     });
   }
 
@@ -133,7 +143,7 @@
 
   _open() {
     this.$.dropdown.open();
-    this._inputText = this.value;
+    this._inputText = this.value || '';
     this.editing = true;
 
     return new Promise<void>(resolve => {
@@ -190,8 +200,9 @@
 
   get _nativeInput(): HTMLInputElement {
     // In Polymer 2 inputElement isn't nativeInput anymore
-    return (this.$.input.$.nativeInput ||
-      this.$.input.inputElement) as HTMLInputElement;
+    return (this.getInput()?.$.nativeInput ||
+      this.getInput()?.inputElement ||
+      this.getGrAutocomplete()) as HTMLInputElement;
   }
 
   _handleEnter(e: CustomKeyboardEvent) {
@@ -212,6 +223,10 @@
     }
   }
 
+  _handleCommit() {
+    this._save();
+  }
+
   _computeLabelClass(readOnly?: boolean, value?: string, placeholder?: string) {
     const classes = [];
     if (!readOnly) {
@@ -226,4 +241,12 @@
   _updateTitle(value?: string) {
     this.setAttribute('title', this._computeLabel(value, this.placeholder));
   }
+
+  getInput(): PaperInputElementExt | null {
+    return this.shadowRoot!.querySelector<PaperInputElementExt>('#input');
+  }
+
+  getGrAutocomplete(): GrAutocomplete | null {
+    return this.shadowRoot!.querySelector<GrAutocomplete>('#autocomplete');
+  }
 }
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts
index ad4fead..d7b6df8 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts
@@ -105,12 +105,24 @@
   >
     <div class="dropdown-content" slot="dropdown-content">
       <div class="inputContainer">
-        <paper-input
-          id="input"
-          label="[[labelText]]"
-          maxlength="[[maxLength]]"
-          value="{{_inputText}}"
-        ></paper-input>
+        <template is="dom-if" if="[[!autocomplete]]">
+          <paper-input
+            id="input"
+            label="[[labelText]]"
+            maxlength="[[maxLength]]"
+            value="{{_inputText}}"
+          ></paper-input>
+        </template>
+        <template is="dom-if" if="[[autocomplete]]">
+          <gr-autocomplete
+            label="[[labelText]]"
+            id="autocomplete"
+            text="{{_inputText}}"
+            query="[[query]]"
+            on-commit="_handleCommit"
+          >
+          </gr-autocomplete>
+        </template>
         <div class="buttons">
           <gr-button link="" id="cancelBtn" on-click="_cancel"
             >cancel</gr-button
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js
index 2bdc570..3e217f0 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js
@@ -50,7 +50,8 @@
 
     await flush();
     // In Polymer 2 inputElement isn't nativeInput anymore
-    input = element.$.input.$.nativeInput || element.$.input.inputElement;
+    const paperInput = element.shadowRoot.querySelector('#input');
+    input = paperInput.$.nativeInput || paperInput.inputElement;
   });
 
   test('element render', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
index 9298fa3..0e9c0fa 100644
--- a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {htmlTemplate} from './gr-file-status-chip_html';
 import {customElement, property} from '@polymer/decorators';
@@ -35,9 +34,7 @@
 };
 
 @customElement('gr-file-status-chip')
-export class GrFileStatusChip extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrFileStatusChip extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index a6c7b92..82ed264 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-linked-text/gr-linked-text';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement, property} from '@polymer/decorators';
@@ -45,9 +44,7 @@
 }
 
 @customElement('gr-formatted-text')
-export class GrFormattedText extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrFormattedText extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
index ddae8ea..9a2f966 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
@@ -20,7 +20,6 @@
 import '../gr-avatar/gr-avatar';
 import '../gr-button/gr-button';
 import {hovercardBehaviorMixin} from '../gr-hovercard/gr-hovercard-behavior';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-hovercard-account_html';
@@ -48,8 +47,8 @@
 import {assertIsDefined} from '../../../utils/common-util';
 
 @customElement('gr-hovercard-account')
-export class GrHovercardAccount extends GestureEventListeners(
-  hovercardBehaviorMixin(LegacyElementMixin(PolymerElement))
+export class GrHovercardAccount extends hovercardBehaviorMixin(
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
index c56bc8f..a5f23ba 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
@@ -16,7 +16,6 @@
  */
 
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-hovercard_html';
 import {hovercardBehaviorMixin} from './gr-hovercard-behavior';
@@ -25,8 +24,8 @@
 import {customElement} from '@polymer/decorators';
 
 @customElement('gr-hovercard')
-export class GrHovercard extends GestureEventListeners(
-  hovercardBehaviorMixin(LegacyElementMixin(PolymerElement))
+export class GrHovercard extends hovercardBehaviorMixin(
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
index 6c88bd2..8803557 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
@@ -63,8 +63,6 @@
       <g id="hourglass"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"></path><path d="M0 0h24v24H0V0z" fill="none"></path></g>
       <!-- This SVG is a copy from material.io https://material.io/icons/#mode_comment-->
       <g id="comment"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></g>
-      <!-- This SVG is a copy from material.io https://material.io/resources/icons/?icon=mode_comment&style=outline-->
-      <g id="comment-outline"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M20 17.17L18.83 16H4V4h16v13.17zM20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2z"></path></g>
       <!-- This SVG is a copy from material.io https://material.io/icons/#calendar_today-->
       <g id="calendar"><path d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V8h16v13z"></path><path d="M0 0h24v24H0z" fill="none"></path></g>
       <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
index 60a07a4..8dc42fc 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
@@ -22,7 +22,6 @@
 import '../gr-icons/gr-icons';
 import '../gr-label/gr-label';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-label-info_html';
@@ -61,9 +60,7 @@
 }
 
 @customElement('gr-label-info')
-export class GrLabelInfo extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrLabelInfo extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts b/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
index 46b10cc..d3c08f4 100644
--- a/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
@@ -21,7 +21,6 @@
  * used in gr-label-info.
  */
 
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement} from '@polymer/decorators';
@@ -35,9 +34,7 @@
 }
 
 @customElement('gr-label')
-export class GrLabel extends TooltipMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrLabel extends TooltipMixin(LegacyElementMixin(PolymerElement)) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts
index 4240c77..84467ee 100644
--- a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts
@@ -16,7 +16,6 @@
  */
 import '../gr-autocomplete/gr-autocomplete';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-labeled-autocomplete_html';
@@ -32,9 +31,7 @@
   };
 }
 @customElement('gr-labeled-autocomplete')
-export class GrLabeledAutocomplete extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrLabeledAutocomplete extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
index 4d65874..607f75d 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-limited-text_html';
@@ -35,7 +34,7 @@
  */
 @customElement('gr-limited-text')
 export class GrLimitedText extends TooltipMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
index fa244f6..36a360b 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
@@ -19,7 +19,6 @@
 import '../gr-icons/gr-icons';
 import '../gr-limited-text/gr-limited-text';
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {customElement, property} from '@polymer/decorators';
@@ -33,9 +32,7 @@
 }
 
 @customElement('gr-linked-chip')
-export class GrLinkedChip extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrLinkedChip extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
index e2c2d7f..44e740d 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-linked-text_html';
@@ -36,9 +35,7 @@
 }
 
 @customElement('gr-linked-text')
-export class GrLinkedText extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrLinkedText extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts
index bf532ef..f364c01 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts
@@ -18,7 +18,6 @@
 import '@polymer/iron-icon/iron-icon';
 import '../../../styles/shared-styles';
 import '../gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-list-view_html';
@@ -38,9 +37,7 @@
 const DEBOUNCER_RELOAD = 'reload';
 
 @customElement('gr-list-view')
-class GrListView extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrListView extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
index 20e5296..402263d9 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-overlay_html';
@@ -37,7 +36,7 @@
 
 @customElement('gr-overlay')
 export class GrOverlay extends IronOverlayMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement)),
+  LegacyElementMixin(PolymerElement),
   IronOverlayBehavior as IronOverlayBehavior
 ) {
   static get template() {
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
index e009499..57f38df 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-page-nav_html';
@@ -34,9 +33,7 @@
 }
 
 @customElement('gr-page-nav')
-export class GrPageNav extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrPageNav extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
index 6db1925..c49427a 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
@@ -18,7 +18,6 @@
 import '../../../styles/shared-styles';
 import '../gr-icons/gr-icons';
 import '../gr-labeled-autocomplete/gr-labeled-autocomplete';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-repo-branch-picker_html';
@@ -44,9 +43,7 @@
   };
 }
 @customElement('gr-repo-branch-picker')
-export class GrRepoBranchPicker extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoBranchPicker extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index ec59ddc..42ee25c 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -1774,6 +1774,15 @@
     }) as Promise<ChangeInfo[] | undefined>;
   }
 
+  getChangesWithSimilarTopic(topic: string): Promise<ChangeInfo[] | undefined> {
+    const query = [`intopic:"${topic}"`].join(' ');
+    return this._restApiHelper.fetchJSON({
+      url: '/changes/',
+      params: {q: query},
+      anonymizedUrl: '/changes/intopic:*',
+    }) as Promise<ChangeInfo[] | undefined>;
+  }
+
   getReviewedFiles(
     changeNum: NumericChangeId,
     patchNum: PatchSetNum
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts b/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts
index a2c1253..e08dab2 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {html} from '@polymer/polymer/lib/utils/html-tag';
@@ -30,9 +29,7 @@
  * GrSelect `gr-select` component.
  */
 @customElement('gr-select')
-export class GrSelect extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrSelect extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return html` <slot></slot> `;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
index 27f4069..133c6d5 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
@@ -16,7 +16,6 @@
  */
 import '../../../styles/shared-styles';
 import '../gr-copy-clipboard/gr-copy-clipboard';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-shell-command_html';
@@ -29,9 +28,7 @@
 }
 
 @customElement('gr-shell-command')
-class GrShellCommand extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+class GrShellCommand extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index 885db2a..45e0b9a 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -21,7 +21,6 @@
 import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
 import '../../../styles/shared-styles';
 import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-textarea_html';
@@ -82,7 +81,7 @@
  */
 @customElement('gr-textarea')
 export class GrTextarea extends KeyboardShortcutMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
index cfd9e81..ab3b5c5 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../gr-icons/gr-icons';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-tooltip-content_html';
@@ -33,7 +32,7 @@
  */
 @customElement('gr-tooltip-content')
 export class GrTooltipContent extends TooltipMixin(
-  GestureEventListeners(LegacyElementMixin(PolymerElement))
+  LegacyElementMixin(PolymerElement)
 ) {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
index c1a8eb2..8652df0 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-tooltip_html';
@@ -32,9 +31,7 @@
 }
 
 @customElement('gr-tooltip')
-export class GrTooltip extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
+export class GrTooltip extends LegacyElementMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
index 4742e65..a3997af 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
@@ -659,6 +659,7 @@
     topic: string,
     changeNum: NumericChangeId
   ): Promise<ChangeInfo[] | undefined>;
+  getChangesWithSimilarTopic(topic: string): Promise<ChangeInfo[] | undefined>;
 
   hasPendingDiffDrafts(): number;
   awaitPendingDiffDrafts(): Promise<void>;
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 2beb667..c9602a7 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -67,6 +67,8 @@
     --gray-300: #dadce0;
     --gray-100: #f1f3f4;
     --gray-50: #f8f9fa;
+    --purple-900: #681da8;
+    --purple-50: #f3e8fd;
 
     --chip-color: var(--gray-900);
     --error-color: var(--red-900);
@@ -181,6 +183,7 @@
     --font-weight-h2: 400;
     --font-weight-h3: 400;
     --context-control-button-font: var(--font-weight-normal) var(--font-size-normal) var(--font-family);
+    --code-hint-font-weight: 500;
 
     /* spacing */
     --spacing-xxs: 1px;
@@ -221,16 +224,15 @@
     --diff-trailing-whitespace-indicator: #ff9ad2;
     --light-add-highlight-color: #d8fed8;
     --light-rebased-add-highlight-color: #eef;
-    --diff-moved-in-background: #e4f7fb;
-    --diff-moved-out-background: #f3e8fd;
-    --diff-moved-in-label-background: #007b83;
-    --diff-moved-out-label-background: #681da8;
+    --diff-moved-in-background: var(--cyan-50);
+    --diff-moved-out-background: var(--purple-50);
+    --diff-moved-in-label-color: var(--cyan-900);
+    --diff-moved-out-label-color: var(--purple-900);
     --light-remove-add-highlight-color: #fff8dc;
     --light-remove-highlight-color: #ffebee;
     --coverage-covered: #e0f2f1;
     --coverage-not-covered: #ffd1a4;
-    --ranged-comment-chip-background: #b06000;
-    --ranged-comment-chip-text-color: #feefe3;
+    --ranged-comment-hint-text-color: var(--orange-900);
 
     /* syntax colors */
     --syntax-attr-color: #219;
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.ts b/polygerrit-ui/app/styles/themes/dark-theme.ts
index 15ff62d..5c97597 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.ts
+++ b/polygerrit-ui/app/styles/themes/dark-theme.ts
@@ -142,16 +142,15 @@
       --diff-trailing-whitespace-indicator: #ff9ad2;
       --light-add-highlight-color: #0f401f;
       --light-rebased-add-highlight-color: #487165;
-      --diff-moved-in-background: #006066;
-      --diff-moved-out-background: #681da8;
-      --diff-moved-in-label-background: #cbf0f8;
-      --diff-moved-out-label-background: #e9d2fd;
+      --diff-moved-in-background: #1d4042;
+      --diff-moved-out-background: #230e34;
+      --diff-moved-in-label-color: var(--cyan-50);
+      --diff-moved-out-label-color: var(--purple-50);
       --light-remove-add-highlight-color: #2f3f2f;
       --light-remove-highlight-color: #320404;
       --coverage-covered: #112826;
       --coverage-not-covered: #6b3600;
-      --ranged-comment-chip-background: #e8f0fe;
-      --ranged-comment-chip-text-color: #174ea6;
+      --ranged-comment-hint-text-color: var(--blue-50);
 
       /* syntax colors */
       --syntax-attr-color: #80cbbf;
diff --git a/polygerrit-ui/app/test/mocks/comment-api.js b/polygerrit-ui/app/test/mocks/comment-api.js
index f2ca48c..526aabe 100644
--- a/polygerrit-ui/app/test/mocks/comment-api.js
+++ b/polygerrit-ui/app/test/mocks/comment-api.js
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
 import {PolymerElement} from '@polymer/polymer/polymer-element.js';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
 
@@ -23,9 +22,7 @@
  * This is an "abstract" class for tests. The descendant must define a template
  * for this element and a tagName - see createCommentApiMockWithTemplateElement below
  */
-class CommentApiMock extends GestureEventListeners(
-    LegacyElementMixin(
-        PolymerElement)) {
+class CommentApiMock extends LegacyElementMixin(PolymerElement) {
   static get properties() {
     return {
       _changeComments: Object,
diff --git a/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts b/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
index 5efc562..ea960f0 100644
--- a/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
+++ b/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
@@ -258,6 +258,9 @@
   getChangesWithSameTopic(): Promise<ChangeInfo[] | undefined> {
     return Promise.resolve([]);
   },
+  getChangesWithSimilarTopic(): Promise<ChangeInfo[] | undefined> {
+    return Promise.resolve([]);
+  },
   getConfig(): Promise<ServerInfo | undefined> {
     return Promise.resolve(createServerInfo());
   },
diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts
index d2c1cd2..21bf351 100644
--- a/polygerrit-ui/app/test/test-data-generators.ts
+++ b/polygerrit-ui/app/test/test-data-generators.ts
@@ -453,6 +453,7 @@
     message: 'hello world',
     updated: '2018-02-13 22:48:48.018000000' as Timestamp,
     unresolved: false,
+    path: 'abc.txt',
   };
 }
 
@@ -569,9 +570,12 @@
 }
 
 export function createCommentThread(comments: UIComment[]) {
+  if (!comments.length) {
+    throw new Error('comment is required to create a thread');
+  }
   comments = comments.map(comment => {
     return {...createComment(), ...comment};
   });
   const threads = createCommentThreads(comments);
-  return threads.length > 0 ? threads[0] : {};
+  return threads[0];
 }
diff --git a/polygerrit-ui/app/utils/comment-util_test.js b/polygerrit-ui/app/utils/comment-util_test.js
deleted file mode 100644
index 4ce95ef..0000000
--- a/polygerrit-ui/app/utils/comment-util_test.js
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 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.
- */
-
-import '../test/common-test-setup-karma.js';
-import {
-  isUnresolved, getPatchRangeForCommentUrl, createCommentThreads, sortComments,
-} from './comment-util.js';
-import {createComment} from '../test/test-data-generators.js';
-import {CommentSide, Side} from '../constants/constants.js';
-import {ParentPatchSetNum} from '../types/common.js';
-
-suite('comment-util', () => {
-  test('isUnresolved', () => {
-    assert.isFalse(isUnresolved(undefined));
-    assert.isFalse(isUnresolved({comments: []}));
-    assert.isTrue(isUnresolved({comments: [{unresolved: true}]}));
-    assert.isFalse(isUnresolved({comments: [{unresolved: false}]}));
-    assert.isTrue(isUnresolved(
-        {comments: [{unresolved: false}, {unresolved: true}]}));
-    assert.isFalse(isUnresolved(
-        {comments: [{unresolved: true}, {unresolved: false}]}));
-  });
-
-  test('getPatchRangeForCommentUrl', () => {
-    test('comment created with side=PARENT does not navigate to latest ps',
-        () => {
-          const comment = {
-            ...createComment(),
-            id: 'c4',
-            line: 10,
-            patch_set: 4,
-            side: CommentSide.PARENT,
-            path: '/COMMIT_MSG',
-          };
-          assert.deepEqual(getPatchRangeForCommentUrl(comment, 11), {
-            basePatchNum: ParentPatchSetNum,
-            patchNum: 4,
-          });
-        });
-  });
-
-  test('comments sorting', () => {
-    const comments = [
-      {
-        id: 'new_draft',
-        message: 'i do not like either of you',
-        diffSide: Side.LEFT,
-        __draft: true,
-        updated: '2015-12-20 15:01:20.396000000',
-      },
-      {
-        id: 'sallys_confession',
-        message: 'i like you, jack',
-        updated: '2015-12-23 15:00:20.396000000',
-        line: 1,
-        diffSide: Side.LEFT,
-      }, {
-        id: 'jacks_reply',
-        message: 'i like you, too',
-        updated: '2015-12-24 15:01:20.396000000',
-        diffSide: Side.LEFT,
-        line: 1,
-        in_reply_to: 'sallys_confession',
-      },
-    ];
-    const sortedComments = sortComments(comments);
-    assert.equal(sortedComments[0], comments[1]);
-    assert.equal(sortedComments[1], comments[2]);
-    assert.equal(sortedComments[2], comments[0]);
-  });
-
-  suite('createCommentThreads', () => {
-    test('creates threads from individual comments', () => {
-      const comments = [
-        {
-          id: 'sallys_confession',
-          message: 'i like you, jack',
-          updated: '2015-12-23 15:00:20.396000000',
-          line: 1,
-          patch_set: 1,
-          path: 'some/path',
-        }, {
-          id: 'jacks_reply',
-          message: 'i like you, too',
-          updated: '2015-12-24 15:01:20.396000000',
-          line: 1,
-          in_reply_to: 'sallys_confession',
-          patch_set: 1,
-          path: 'some/path',
-        },
-        {
-          id: 'new_draft',
-          message: 'i do not like either of you',
-          __draft: true,
-          updated: '2015-12-20 15:01:20.396000000',
-          patch_set: 1,
-          path: 'some/path',
-        },
-      ];
-
-      const actualThreads = createCommentThreads(comments,
-          {basePatchNum: 1, patchNum: 4});
-
-      assert.equal(actualThreads.length, 2);
-
-      assert.equal(actualThreads[0].diffSide, Side.LEFT);
-      assert.equal(actualThreads[0].comments.length, 2);
-      assert.deepEqual(actualThreads[0].comments[0], comments[0]);
-      assert.deepEqual(actualThreads[0].comments[1], comments[1]);
-      assert.equal(actualThreads[0].patchNum, 1);
-      assert.equal(actualThreads[0].line, 1);
-
-      assert.equal(actualThreads[1].diffSide, Side.LEFT);
-      assert.equal(actualThreads[1].comments.length, 1);
-      assert.deepEqual(actualThreads[1].comments[0], comments[2]);
-      assert.equal(actualThreads[1].patchNum, 1);
-      assert.equal(actualThreads[1].line, 'FILE');
-    });
-
-    test('derives patchNum and range', () => {
-      const comments = [{
-        id: 'betsys_confession',
-        message: 'i like you, jack',
-        updated: '2015-12-24 15:00:10.396000000',
-        range: {
-          start_line: 1,
-          start_character: 1,
-          end_line: 1,
-          end_character: 2,
-        },
-        patch_set: 5,
-        path: '/p',
-        line: 1,
-      }];
-
-      const expectedThreads = [
-        {
-          diffSide: Side.LEFT,
-          commentSide: CommentSide.REVISION,
-          path: '/p',
-          rootId: 'betsys_confession',
-          mergeParentNum: undefined,
-          comments: [{
-            id: 'betsys_confession',
-            path: '/p',
-            message: 'i like you, jack',
-            updated: '2015-12-24 15:00:10.396000000',
-            range: {
-              start_line: 1,
-              start_character: 1,
-              end_line: 1,
-              end_character: 2,
-            },
-            patch_set: 5,
-            line: 1,
-          }],
-          patchNum: 5,
-          range: {
-            start_line: 1,
-            start_character: 1,
-            end_line: 1,
-            end_character: 2,
-          },
-          line: 1,
-        },
-      ];
-
-      assert.deepEqual(
-          createCommentThreads(comments, {basePatchNum: 5, patchNum: 10}),
-          expectedThreads);
-    });
-
-    test('does not thread unrelated comments at same location', () => {
-      const comments = [
-        {
-          id: 'sallys_confession',
-          message: 'i like you, jack',
-          updated: '2015-12-23 15:00:20.396000000',
-          diffSide: Side.LEFT,
-          path: '/p',
-        }, {
-          id: 'jacks_reply',
-          message: 'i like you, too',
-          updated: '2015-12-24 15:01:20.396000000',
-          diffSide: Side.LEFT,
-          path: '/p',
-        },
-      ];
-      assert.equal(createCommentThreads(comments).length, 2);
-    });
-  });
-});
diff --git a/polygerrit-ui/app/utils/comment-util_test.ts b/polygerrit-ui/app/utils/comment-util_test.ts
new file mode 100644
index 0000000..8707b68
--- /dev/null
+++ b/polygerrit-ui/app/utils/comment-util_test.ts
@@ -0,0 +1,256 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+import '../test/common-test-setup-karma.js';
+import {
+  isUnresolved,
+  getPatchRangeForCommentUrl,
+  createCommentThreads,
+  sortComments,
+} from './comment-util.js';
+import {
+  createComment,
+  createCommentThread,
+} from '../test/test-data-generators.js';
+import {CommentSide, Side} from '../constants/constants.js';
+import {
+  ParentPatchSetNum,
+  PatchSetNum,
+  Timestamp,
+  UrlEncodedCommentId,
+} from '../types/common.js';
+
+suite('comment-util', () => {
+  test('isUnresolved', () => {
+    const thread = createCommentThread([createComment()]);
+
+    assert.isFalse(isUnresolved(undefined));
+    assert.isFalse(isUnresolved(thread));
+
+    assert.isTrue(
+      isUnresolved({
+        ...thread,
+        comments: [{...createComment(), unresolved: true}],
+      })
+    );
+    assert.isFalse(
+      isUnresolved({
+        ...thread,
+        comments: [{...createComment(), unresolved: false}],
+      })
+    );
+    assert.isTrue(
+      isUnresolved({
+        ...thread,
+        comments: [
+          {...createComment(), unresolved: false},
+          {...createComment(), unresolved: true},
+        ],
+      })
+    );
+    assert.isFalse(
+      isUnresolved({
+        ...thread,
+        comments: [
+          {...createComment(), unresolved: true},
+          {...createComment(), unresolved: false},
+        ],
+      })
+    );
+  });
+
+  test('getPatchRangeForCommentUrl', () => {
+    test('comment created with side=PARENT does not navigate to latest ps', () => {
+      const comment = {
+        ...createComment(),
+        id: 'c4' as UrlEncodedCommentId,
+        line: 10,
+        patch_set: 4 as PatchSetNum,
+        side: CommentSide.PARENT,
+        path: '/COMMIT_MSG',
+      };
+      assert.deepEqual(getPatchRangeForCommentUrl(comment, 11 as PatchSetNum), {
+        basePatchNum: ParentPatchSetNum,
+        patchNum: 4 as PatchSetNum,
+      });
+    });
+  });
+
+  test('comments sorting', () => {
+    const comments = [
+      {
+        id: 'new_draft' as UrlEncodedCommentId,
+        message: 'i do not like either of you',
+        diffSide: Side.LEFT,
+        __draft: true,
+        updated: '2015-12-20 15:01:20.396000000' as Timestamp,
+      },
+      {
+        id: 'sallys_confession' as UrlEncodedCommentId,
+        message: 'i like you, jack',
+        updated: '2015-12-23 15:00:20.396000000' as Timestamp,
+        line: 1,
+        diffSide: Side.LEFT,
+      },
+      {
+        id: 'jacks_reply' as UrlEncodedCommentId,
+        message: 'i like you, too',
+        updated: '2015-12-24 15:01:20.396000000' as Timestamp,
+        diffSide: Side.LEFT,
+        line: 1,
+        in_reply_to: 'sallys_confession',
+      },
+    ];
+    const sortedComments = sortComments(comments);
+    assert.equal(sortedComments[0], comments[1]);
+    assert.equal(sortedComments[1], comments[2]);
+    assert.equal(sortedComments[2], comments[0]);
+  });
+
+  suite('createCommentThreads', () => {
+    test('creates threads from individual comments', () => {
+      const comments = [
+        {
+          id: 'sallys_confession' as UrlEncodedCommentId,
+          message: 'i like you, jack',
+          updated: '2015-12-23 15:00:20.396000000' as Timestamp,
+          line: 1,
+          patch_set: 1 as PatchSetNum,
+          path: 'some/path',
+        },
+        {
+          id: 'jacks_reply' as UrlEncodedCommentId,
+          message: 'i like you, too',
+          updated: '2015-12-24 15:01:20.396000000' as Timestamp,
+          line: 1,
+          in_reply_to: 'sallys_confession' as UrlEncodedCommentId,
+          patch_set: 1 as PatchSetNum,
+          path: 'some/path',
+        },
+        {
+          id: 'new_draft' as UrlEncodedCommentId,
+          message: 'i do not like either of you' as UrlEncodedCommentId,
+          __draft: true,
+          updated: '2015-12-20 15:01:20.396000000' as Timestamp,
+          patch_set: 1 as PatchSetNum,
+          path: 'some/path',
+        },
+      ];
+
+      const actualThreads = createCommentThreads(comments, {
+        basePatchNum: 1 as PatchSetNum,
+        patchNum: 4 as PatchSetNum,
+      });
+
+      assert.equal(actualThreads.length, 2);
+
+      assert.equal(actualThreads[0].diffSide, Side.LEFT);
+      assert.equal(actualThreads[0].comments.length, 2);
+      assert.deepEqual(actualThreads[0].comments[0], comments[0]);
+      assert.deepEqual(actualThreads[0].comments[1], comments[1]);
+      assert.equal(actualThreads[0].patchNum, 1 as PatchSetNum);
+      assert.equal(actualThreads[0].line, 1);
+
+      assert.equal(actualThreads[1].diffSide, Side.LEFT);
+      assert.equal(actualThreads[1].comments.length, 1);
+      assert.deepEqual(actualThreads[1].comments[0], comments[2]);
+      assert.equal(actualThreads[1].patchNum, 1 as PatchSetNum);
+      assert.equal(actualThreads[1].line, 'FILE');
+    });
+
+    test('derives patchNum and range', () => {
+      const comments = [
+        {
+          id: 'betsys_confession' as UrlEncodedCommentId,
+          message: 'i like you, jack',
+          updated: '2015-12-24 15:00:10.396000000' as Timestamp,
+          range: {
+            start_line: 1,
+            start_character: 1,
+            end_line: 1,
+            end_character: 2,
+          },
+          patch_set: 5 as PatchSetNum,
+          path: '/p',
+          line: 1,
+        },
+      ];
+
+      const expectedThreads = [
+        {
+          diffSide: Side.LEFT,
+          commentSide: CommentSide.REVISION,
+          path: '/p',
+          rootId: 'betsys_confession' as UrlEncodedCommentId,
+          mergeParentNum: undefined,
+          comments: [
+            {
+              id: 'betsys_confession' as UrlEncodedCommentId,
+              path: '/p',
+              message: 'i like you, jack',
+              updated: '2015-12-24 15:00:10.396000000' as Timestamp,
+              range: {
+                start_line: 1,
+                start_character: 1,
+                end_line: 1,
+                end_character: 2,
+              },
+              patch_set: 5 as PatchSetNum,
+              line: 1,
+            },
+          ],
+          patchNum: 5 as PatchSetNum,
+          range: {
+            start_line: 1,
+            start_character: 1,
+            end_line: 1,
+            end_character: 2,
+          },
+          line: 1,
+        },
+      ];
+
+      assert.deepEqual(
+        createCommentThreads(comments, {
+          basePatchNum: 5 as PatchSetNum,
+          patchNum: 10 as PatchSetNum,
+        }),
+        expectedThreads
+      );
+    });
+
+    test('does not thread unrelated comments at same location', () => {
+      const comments = [
+        {
+          id: 'sallys_confession' as UrlEncodedCommentId,
+          message: 'i like you, jack',
+          updated: '2015-12-23 15:00:20.396000000' as Timestamp,
+          diffSide: Side.LEFT,
+          path: '/p',
+        },
+        {
+          id: 'jacks_reply' as UrlEncodedCommentId,
+          message: 'i like you, too',
+          updated: '2015-12-24 15:01:20.396000000' as Timestamp,
+          diffSide: Side.LEFT,
+          path: '/p',
+        },
+      ];
+      assert.equal(createCommentThreads(comments).length, 2);
+    });
+  });
+});
diff --git a/polygerrit-ui/app/utils/common-util.ts b/polygerrit-ui/app/utils/common-util.ts
index f4d6d51..08b5e49 100644
--- a/polygerrit-ui/app/utils/common-util.ts
+++ b/polygerrit-ui/app/utils/common-util.ts
@@ -122,3 +122,7 @@
     set.add(value);
   }
 }
+
+export function unique<T>(item: T, index: number, array: T[]) {
+  return array.indexOf(item) === index;
+}