Merge "Bazel: Add support for Java 11 and newer Java versions"
diff --git a/.gitignore b/.gitignore
index e544356..319b3cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,4 @@
/test_site
/tools/format
/.vscode
+/.ijwb
diff --git a/Documentation/dev-contributing.txt b/Documentation/dev-contributing.txt
index bc9f782..8710a2b 100644
--- a/Documentation/dev-contributing.txt
+++ b/Documentation/dev-contributing.txt
@@ -166,7 +166,7 @@
link:https://github.com/google/google-java-format[`google-java-format`]
tool (version 1.6), and to format Bazel BUILD, WORKSPACE and .bzl files the
link:https://github.com/bazelbuild/buildtools/tree/master/buildifier[`buildifier`]
-tool (version 0.15.0).
+tool (version 0.17.2).
These tools automatically apply format according to the style guides; this
streamlines code review by reducing the need for time-consuming, tedious,
and contentious discussions about trivial issues like whitespace.
diff --git a/Documentation/replace_macros.py b/Documentation/replace_macros.py
index 6f90697..309a135 100755
--- a/Documentation/replace_macros.py
+++ b/Documentation/replace_macros.py
@@ -89,7 +89,7 @@
</button>
<script type="text/javascript">
var f = function() {
- window.location = '../#/Documentation/' +
+ window.location = '../#/Documentation/q/' +
encodeURIComponent(document.getElementById("docSearch").value);
}
document.getElementById("searchBox").onclick = f;
diff --git a/WORKSPACE b/WORKSPACE
index 6884db6..a98c42e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -30,9 +30,9 @@
urls = ["https://raw.githubusercontent.com/google/closure-compiler/35d2b3340ff23a69441f10fa3bc820691c2942f2/contrib/externs/polymer-1.0.js"],
)
-load("@bazel_skylib//:lib.bzl", "versions")
+load("@bazel_skylib//lib:versions.bzl", "versions")
-versions.check(minimum_bazel_version = "0.17.1")
+versions.check(minimum_bazel_version = "0.19.0")
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
@@ -759,7 +759,7 @@
sha1 = "bb562ee73f740bb6b2bf7955f97be6b870d9e9f0",
)
-# When updading Bouncy Castle, also update it in bazlets.
+# When updating Bouncy Castle, also update it in bazlets.
BC_VERS = "1.60"
maven_jar(
@@ -833,10 +833,18 @@
sha1 = "f5aa318bda4c6c8d688c9d00b90681dcd82ce636",
)
+# elasticsearch-rest-client explicitly depends on this version
maven_jar(
- name = "httpmime",
- artifact = "org.apache.httpcomponents:httpmime:" + HTTPCOMP_VERS,
- sha1 = "2f8757f5ac5e38f46c794e5229d1f3c522e9b1df",
+ name = "httpasyncclient",
+ artifact = "org.apache.httpcomponents:httpasyncclient:4.1.2",
+ sha1 = "95aa3e6fb520191a0970a73cf09f62948ee614be",
+)
+
+# elasticsearch-rest-client explicitly depends on this version
+maven_jar(
+ name = "httpcore-nio",
+ artifact = "org.apache.httpcomponents:httpcore-nio:4.4.5",
+ sha1 = "f4be009e7505f6ceddf21e7960c759f413f15056",
)
# Test-only dependencies below.
@@ -956,9 +964,9 @@
maven_jar(
name = "derby",
- artifact = "org.apache.derby:derby:10.11.1.1",
+ artifact = "org.apache.derby:derby:10.12.1.1",
attach_source = False,
- sha1 = "df4b50061e8e4c348ce243b921f53ee63ba9bbe1",
+ sha1 = "75070c744a8e52a7d17b8b476468580309d5cd09",
)
JETTY_VERS = "9.4.12.v20180830"
@@ -1038,8 +1046,8 @@
maven_jar(
name = "postgresql",
- artifact = "org.postgresql:postgresql:42.2.4",
- sha1 = "dff98730c28a4b3a3263f0cf4abb9a3392f815a7",
+ artifact = "org.postgresql:postgresql:42.2.5",
+ sha1 = "951b7eda125f3137538a94e2cbdcf744088ad4c2",
)
maven_jar(
@@ -1079,10 +1087,12 @@
sha1 = "76716d529710fc03d1d429b43e3cedd4419f78d4",
)
+# When upgrading elasticsearch-rest-client, also upgrade http-niocore
+# and httpasyncclient as necessary.
maven_jar(
name = "elasticsearch-rest-client",
- artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.4.2",
- sha1 = "a2baf2d4fdf03f31fbd39351a32bee25fcdfa1cf",
+ artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.4.3",
+ sha1 = "5c24325430971ba2fa4769eb446f026b7680d5e7",
)
JACKSON_VERSION = "2.9.7"
@@ -1094,18 +1104,6 @@
)
maven_jar(
- name = "httpasyncclient",
- artifact = "org.apache.httpcomponents:httpasyncclient:4.1.2",
- sha1 = "95aa3e6fb520191a0970a73cf09f62948ee614be",
-)
-
-maven_jar(
- name = "httpcore-nio",
- artifact = "org.apache.httpcomponents:httpcore-nio:" + HTTPCOMP_VERS,
- sha1 = "a8c5e3c3bfea5ce23fb647c335897e415eb442e3",
-)
-
-maven_jar(
name = "testcontainers",
artifact = "org.testcontainers:testcontainers:1.8.0",
sha1 = "bc413912f7044f9f12aa0782853aef0a067ee52a",
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index c9346f4..4b84864 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -236,7 +236,7 @@
if (matchPrefix(QUERY, token)) {
query(token);
- } else if (matchPrefix("/Documentation/", token)) {
+ } else if (matchPrefix("/Documentation/q/", token)) {
docSearch(token);
} else if (matchPrefix("/c/", token)) {
diff --git a/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index 0150e1e..dfa2128 100644
--- a/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -49,17 +49,21 @@
* @return API for accessing the revision.
* @throws RestApiException if an error occurred.
*/
- RevisionApi current() throws RestApiException;
+ default RevisionApi current() throws RestApiException {
+ return revision("current");
+ }
/**
* Look up a revision of a change by number.
*
* @see #current()
*/
- RevisionApi revision(int id) throws RestApiException;
+ default RevisionApi revision(int id) throws RestApiException {
+ return revision(Integer.toString(id));
+ }
/**
- * Look up a revision of a change by commit SHA-1.
+ * Look up a revision of a change by commit SHA-1 or other supported revision string.
*
* @see #current()
*/
@@ -79,15 +83,23 @@
*/
ReviewerApi reviewer(String id) throws RestApiException;
- void abandon() throws RestApiException;
+ default void abandon() throws RestApiException {
+ abandon(new AbandonInput());
+ }
void abandon(AbandonInput in) throws RestApiException;
- void restore() throws RestApiException;
+ default void restore() throws RestApiException {
+ restore(new RestoreInput());
+ }
void restore(RestoreInput in) throws RestApiException;
- void move(String destination) throws RestApiException;
+ default void move(String destination) throws RestApiException {
+ MoveInput in = new MoveInput();
+ in.destinationBranch = destination;
+ move(in);
+ }
void move(MoveInput in) throws RestApiException;
@@ -132,7 +144,9 @@
*
* @see Changes#id(int)
*/
- ChangeApi revert() throws RestApiException;
+ default ChangeApi revert() throws RestApiException {
+ return revert(new RevertInput());
+ }
/**
* Create a new change that reverts this change.
@@ -144,10 +158,17 @@
/** Create a merge patch set for the change. */
ChangeInfo createMergePatchSet(MergePatchSetInput in) throws RestApiException;
- List<ChangeInfo> submittedTogether() throws RestApiException;
+ default List<ChangeInfo> submittedTogether() throws RestApiException {
+ SubmittedTogetherInfo info =
+ submittedTogether(
+ EnumSet.noneOf(ListChangesOption.class), EnumSet.noneOf(SubmittedTogetherOption.class));
+ return info.changes;
+ }
- SubmittedTogetherInfo submittedTogether(EnumSet<SubmittedTogetherOption> options)
- throws RestApiException;
+ default SubmittedTogetherInfo submittedTogether(EnumSet<SubmittedTogetherOption> options)
+ throws RestApiException {
+ return submittedTogether(EnumSet.noneOf(ListChangesOption.class), options);
+ }
SubmittedTogetherInfo submittedTogether(
EnumSet<ListChangesOption> listOptions, EnumSet<SubmittedTogetherOption> submitOptions)
@@ -155,10 +176,14 @@
/** Publishes a draft change. */
@Deprecated
- void publish() throws RestApiException;
+ default void publish() throws RestApiException {
+ throw new UnsupportedOperationException("draft workflow is discontinued");
+ }
/** Rebase the current revision of a change using default options. */
- void rebase() throws RestApiException;
+ default void rebase() throws RestApiException {
+ rebase(new RebaseInput());
+ }
/** Rebase the current revision of a change. */
void rebase(RebaseInput in) throws RestApiException;
@@ -172,13 +197,19 @@
IncludedInInfo includedIn() throws RestApiException;
- AddReviewerResult addReviewer(AddReviewerInput in) throws RestApiException;
+ default AddReviewerResult addReviewer(String reviewer) throws RestApiException {
+ AddReviewerInput in = new AddReviewerInput();
+ in.reviewer = reviewer;
+ return addReviewer(in);
+ }
- AddReviewerResult addReviewer(String in) throws RestApiException;
+ AddReviewerResult addReviewer(AddReviewerInput in) throws RestApiException;
SuggestedReviewersRequest suggestReviewers() throws RestApiException;
- SuggestedReviewersRequest suggestReviewers(String query) throws RestApiException;
+ default SuggestedReviewersRequest suggestReviewers(String query) throws RestApiException {
+ return suggestReviewers().withQuery(query);
+ }
ChangeInfo get(EnumSet<ListChangesOption> options) throws RestApiException;
@@ -198,10 +229,16 @@
* <li>{@code SKIP_MERGEABLE} is omitted, so the {@code mergeable} bit <em>is</em> set.
* </ul>
*/
- ChangeInfo get() throws RestApiException;
+ default ChangeInfo get() throws RestApiException {
+ return get(
+ EnumSet.complementOf(
+ EnumSet.of(ListChangesOption.CHECK, ListChangesOption.SKIP_MERGEABLE)));
+ }
/** {@link #get(ListChangesOption...)} with no options included. */
- ChangeInfo info() throws RestApiException;
+ default ChangeInfo info() throws RestApiException {
+ return get(EnumSet.noneOf(ListChangesOption.class));
+ }
/**
* Retrieve change edit when exists.
@@ -210,7 +247,9 @@
* ChangeEditApi#get()}.
*/
@Deprecated
- EditInfo getEdit() throws RestApiException;
+ default EditInfo getEdit() throws RestApiException {
+ return edit().get().orElse(null);
+ }
/**
* Provides access to an API regarding the change edit of this change.
@@ -221,7 +260,11 @@
ChangeEditApi edit() throws RestApiException;
/** Create a new patch set with a new commit message. */
- void setMessage(String message) throws RestApiException;
+ default void setMessage(String message) throws RestApiException {
+ CommitMessageInput in = new CommitMessageInput();
+ in.message = message;
+ setMessage(in);
+ }
/** Create a new patch set with a new commit message. */
void setMessage(CommitMessageInput in) throws RestApiException;
@@ -347,16 +390,6 @@
}
@Override
- public RevisionApi current() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
- public RevisionApi revision(int id) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public ReviewerApi reviewer(String id) throws RestApiException {
throw new NotImplementedException();
}
@@ -367,31 +400,16 @@
}
@Override
- public void abandon() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public void abandon(AbandonInput in) throws RestApiException {
throw new NotImplementedException();
}
@Override
- public void restore() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public void restore(RestoreInput in) throws RestApiException {
throw new NotImplementedException();
}
@Override
- public void move(String destination) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public void move(MoveInput in) throws RestApiException {
throw new NotImplementedException();
}
@@ -412,27 +430,11 @@
}
@Override
- public ChangeApi revert() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public ChangeApi revert(RevertInput in) throws RestApiException {
throw new NotImplementedException();
}
@Override
- public void publish() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Deprecated
- @Override
- public void rebase() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public void rebase(RebaseInput in) throws RestApiException {
throw new NotImplementedException();
}
@@ -463,51 +465,21 @@
}
@Override
- public AddReviewerResult addReviewer(String in) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public SuggestedReviewersRequest suggestReviewers() throws RestApiException {
throw new NotImplementedException();
}
@Override
- public SuggestedReviewersRequest suggestReviewers(String query) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public ChangeInfo get(EnumSet<ListChangesOption> options) throws RestApiException {
throw new NotImplementedException();
}
@Override
- public ChangeInfo get() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
- public ChangeInfo info() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
- public void setMessage(String message) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public void setMessage(CommitMessageInput in) throws RestApiException {
throw new NotImplementedException();
}
@Override
- public EditInfo getEdit() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public ChangeEditApi edit() throws RestApiException {
throw new NotImplementedException();
}
diff --git a/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index 75cf3a6..14dc589 100644
--- a/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.api.changes;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.CherryPickChangeInfo;
@@ -34,7 +35,9 @@
public interface RevisionApi {
@Deprecated
- void delete() throws RestApiException;
+ default void delete() throws RestApiException {
+ throw new UnsupportedOperationException("draft workflow is discontinued");
+ }
String description() throws RestApiException;
@@ -42,22 +45,32 @@
ReviewResult review(ReviewInput in) throws RestApiException;
- void submit() throws RestApiException;
+ default void submit() throws RestApiException {
+ SubmitInput in = new SubmitInput();
+ submit(in);
+ }
void submit(SubmitInput in) throws RestApiException;
- BinaryResult submitPreview() throws RestApiException;
+ default BinaryResult submitPreview() throws RestApiException {
+ return submitPreview("zip");
+ }
BinaryResult submitPreview(String format) throws RestApiException;
@Deprecated
- void publish() throws RestApiException;
+ default void publish() throws RestApiException {
+ throw new UnsupportedOperationException("draft workflow is discontinued");
+ }
ChangeApi cherryPick(CherryPickInput in) throws RestApiException;
CherryPickChangeInfo cherryPickAsInfo(CherryPickInput in) throws RestApiException;
- ChangeApi rebase() throws RestApiException;
+ default ChangeApi rebase() throws RestApiException {
+ RebaseInput in = new RebaseInput();
+ return rebase(in);
+ }
ChangeApi rebase(RebaseInput in) throws RestApiException;
@@ -69,9 +82,11 @@
Set<String> reviewed() throws RestApiException;
- Map<String, FileInfo> files() throws RestApiException;
+ default Map<String, FileInfo> files() throws RestApiException {
+ return files(null);
+ }
- Map<String, FileInfo> files(String base) throws RestApiException;
+ Map<String, FileInfo> files(@Nullable String base) throws RestApiException;
Map<String, FileInfo> files(int parentNum) throws RestApiException;
@@ -165,33 +180,16 @@
* interface.
*/
class NotImplemented implements RevisionApi {
- @Deprecated
- @Override
- public void delete() throws RestApiException {
- throw new NotImplementedException();
- }
-
@Override
public ReviewResult review(ReviewInput in) throws RestApiException {
throw new NotImplementedException();
}
@Override
- public void submit() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public void submit(SubmitInput in) throws RestApiException {
throw new NotImplementedException();
}
- @Deprecated
- @Override
- public void publish() throws RestApiException {
- throw new NotImplementedException();
- }
-
@Override
public ChangeApi cherryPick(CherryPickInput in) throws RestApiException {
throw new NotImplementedException();
@@ -203,11 +201,6 @@
}
@Override
- public ChangeApi rebase() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public ChangeApi rebase(RebaseInput in) throws RestApiException {
throw new NotImplementedException();
}
@@ -253,11 +246,6 @@
}
@Override
- public Map<String, FileInfo> files() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public List<String> queryFiles(String query) throws RestApiException {
throw new NotImplementedException();
}
@@ -348,11 +336,6 @@
}
@Override
- public BinaryResult submitPreview() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public BinaryResult submitPreview(String format) throws RestApiException {
throw new NotImplementedException();
}
diff --git a/java/com/google/gerrit/extensions/api/projects/RefInfo.java b/java/com/google/gerrit/extensions/api/projects/RefInfo.java
index c573600..d5695fd 100644
--- a/java/com/google/gerrit/extensions/api/projects/RefInfo.java
+++ b/java/com/google/gerrit/extensions/api/projects/RefInfo.java
@@ -14,8 +14,15 @@
package com.google.gerrit.extensions.api.projects;
+import com.google.common.base.MoreObjects;
+
public class RefInfo {
public String ref;
public String revision;
public Boolean canDelete;
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("ref", ref).add("revision", revision).toString();
+ }
}
diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java
index 124ad1c..062d776 100644
--- a/java/com/google/gerrit/httpd/raw/StaticModule.java
+++ b/java/com/google/gerrit/httpd/raw/StaticModule.java
@@ -71,7 +71,15 @@
*/
public static final ImmutableList<String> POLYGERRIT_INDEX_PATHS =
ImmutableList.of(
- "/", "/c/*", "/p/*", "/q/*", "/x/*", "/admin/*", "/dashboard/*", "/settings/*");
+ "/",
+ "/c/*",
+ "/p/*",
+ "/q/*",
+ "/x/*",
+ "/admin/*",
+ "/dashboard/*",
+ "/settings/*",
+ "/Documentation/q/*");
// TODO(dborowitz): These fragments conflict with the REST API
// namespace, so they will need to use a different path.
// "/groups/*",
diff --git a/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 358a3a8..0f731ed 100644
--- a/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -43,7 +43,6 @@
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.CommitMessageInput;
-import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.Input;
import com.google.gerrit.extensions.common.MergePatchSetInput;
import com.google.gerrit.extensions.common.PureRevertInfo;
@@ -256,16 +255,6 @@
}
@Override
- public RevisionApi current() throws RestApiException {
- return revision("current");
- }
-
- @Override
- public RevisionApi revision(int id) throws RestApiException {
- return revision(String.valueOf(id));
- }
-
- @Override
public RevisionApi revision(String id) throws RestApiException {
try {
return revisionApi.create(revisions.parse(change, IdString.fromDecoded(id)));
@@ -284,11 +273,6 @@
}
@Override
- public void abandon() throws RestApiException {
- abandon(new AbandonInput());
- }
-
- @Override
public void abandon(AbandonInput in) throws RestApiException {
try {
abandon.apply(change, in);
@@ -298,11 +282,6 @@
}
@Override
- public void restore() throws RestApiException {
- restore(new RestoreInput());
- }
-
- @Override
public void restore(RestoreInput in) throws RestApiException {
try {
restore.apply(change, in);
@@ -312,13 +291,6 @@
}
@Override
- public void move(String destination) throws RestApiException {
- MoveInput in = new MoveInput();
- in.destinationBranch = destination;
- move(in);
- }
-
- @Override
public void move(MoveInput in) throws RestApiException {
try {
move.apply(change, in);
@@ -360,11 +332,6 @@
}
@Override
- public ChangeApi revert() throws RestApiException {
- return revert(new RevertInput());
- }
-
- @Override
public ChangeApi revert(RevertInput in) throws RestApiException {
try {
return changeApi.id(revert.apply(change, in)._number);
@@ -383,20 +350,6 @@
}
@Override
- public List<ChangeInfo> submittedTogether() throws RestApiException {
- SubmittedTogetherInfo info =
- submittedTogether(
- EnumSet.noneOf(ListChangesOption.class), EnumSet.noneOf(SubmittedTogetherOption.class));
- return info.changes;
- }
-
- @Override
- public SubmittedTogetherInfo submittedTogether(EnumSet<SubmittedTogetherOption> options)
- throws RestApiException {
- return submittedTogether(EnumSet.noneOf(ListChangesOption.class), options);
- }
-
- @Override
public SubmittedTogetherInfo submittedTogether(
EnumSet<ListChangesOption> listOptions, EnumSet<SubmittedTogetherOption> submitOptions)
throws RestApiException {
@@ -411,17 +364,6 @@
}
}
- @Deprecated
- @Override
- public void publish() throws RestApiException {
- throw new UnsupportedOperationException("draft workflow is discontinued");
- }
-
- @Override
- public void rebase() throws RestApiException {
- rebase(new RebaseInput());
- }
-
@Override
public void rebase(RebaseInput in) throws RestApiException {
try {
@@ -466,13 +408,6 @@
}
@Override
- public AddReviewerResult addReviewer(String reviewer) throws RestApiException {
- AddReviewerInput in = new AddReviewerInput();
- in.reviewer = reviewer;
- return addReviewer(in);
- }
-
- @Override
public AddReviewerResult addReviewer(AddReviewerInput in) throws RestApiException {
try {
return postReviewers.apply(change, in);
@@ -491,11 +426,6 @@
};
}
- @Override
- public SuggestedReviewersRequest suggestReviewers(String query) throws RestApiException {
- return suggestReviewers().withQuery(query);
- }
-
private List<SuggestedReviewerInfo> suggestReviewers(SuggestedReviewersRequest r)
throws RestApiException {
try {
@@ -517,30 +447,11 @@
}
@Override
- public ChangeInfo get() throws RestApiException {
- return get(
- EnumSet.complementOf(
- EnumSet.of(ListChangesOption.CHECK, ListChangesOption.SKIP_MERGEABLE)));
- }
-
- @Override
- public EditInfo getEdit() throws RestApiException {
- return edit().get().orElse(null);
- }
-
- @Override
public ChangeEditApi edit() throws RestApiException {
return changeEditApi.create(change);
}
@Override
- public void setMessage(String msg) throws RestApiException {
- CommitMessageInput in = new CommitMessageInput();
- in.message = msg;
- setMessage(in);
- }
-
- @Override
public void setMessage(CommitMessageInput in) throws RestApiException {
try {
putMessage.apply(change, in);
@@ -550,11 +461,6 @@
}
@Override
- public ChangeInfo info() throws RestApiException {
- return get(EnumSet.noneOf(ListChangesOption.class));
- }
-
- @Override
public void setHashtags(HashtagsInput input) throws RestApiException {
try {
postHashtags.apply(change, input);
diff --git a/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index 3f03b57..f8a2ecb 100644
--- a/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -18,6 +18,7 @@
import static com.google.gerrit.server.api.ApiUtil.asRestApiException;
import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.Changes;
import com.google.gerrit.extensions.api.changes.CherryPickInput;
@@ -227,12 +228,6 @@
}
@Override
- public void submit() throws RestApiException {
- SubmitInput in = new SubmitInput();
- submit(in);
- }
-
- @Override
public void submit(SubmitInput in) throws RestApiException {
try {
submit.apply(revision, in);
@@ -242,11 +237,6 @@
}
@Override
- public BinaryResult submitPreview() throws RestApiException {
- return submitPreview("zip");
- }
-
- @Override
public BinaryResult submitPreview(String format) throws RestApiException {
try {
submitPreview.setFormat(format);
@@ -257,22 +247,6 @@
}
@Override
- public void publish() throws RestApiException {
- throw new UnsupportedOperationException("draft workflow is discontinued");
- }
-
- @Override
- public void delete() throws RestApiException {
- throw new UnsupportedOperationException("draft workflow is discontinued");
- }
-
- @Override
- public ChangeApi rebase() throws RestApiException {
- RebaseInput in = new RebaseInput();
- return rebase(in);
- }
-
- @Override
public ChangeApi rebase(RebaseInput in) throws RestApiException {
try {
return changes.id(rebase.apply(revision, in)._number);
@@ -366,17 +340,7 @@
@SuppressWarnings("unchecked")
@Override
- public Map<String, FileInfo> files() throws RestApiException {
- try {
- return (Map<String, FileInfo>) listFiles.apply(revision).value();
- } catch (Exception e) {
- throw asRestApiException("Cannot retrieve files", e);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map<String, FileInfo> files(String base) throws RestApiException {
+ public Map<String, FileInfo> files(@Nullable String base) throws RestApiException {
try {
return (Map<String, FileInfo>) listFiles.setBase(base).apply(revision).value();
} catch (Exception e) {
diff --git a/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java b/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
index afffbef..2268c07 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
@@ -103,8 +103,9 @@
*
* <p>Should only be used in exceptional cases to get direct access to the extension
* implementation. If possible the extension should be invoked through {@link
- * #run(ExtensionImplConsumer)}, {@link #run(ExtensionImplConsumer, Class)}, {@link
- * #call(ExtensionImplFunction)} and {@link #call(CheckedExtensionImplFunction, Class)}.
+ * #run(PluginContext.ExtensionImplConsumer)}, {@link #run(PluginContext.ExtensionImplConsumer,
+ * java.lang.Class)}, {@link #call(PluginContext.ExtensionImplFunction)} and {@link
+ * #call(PluginContext.CheckedExtensionImplFunction, java.lang.Class)}.
*
* @return the implementation of this extension
*/
diff --git a/java/com/google/gerrit/server/project/CreateProjectArgs.java b/java/com/google/gerrit/server/project/CreateProjectArgs.java
index a68bd84..df31c19 100644
--- a/java/com/google/gerrit/server/project/CreateProjectArgs.java
+++ b/java/com/google/gerrit/server/project/CreateProjectArgs.java
@@ -49,6 +49,7 @@
enableSignedPush = InheritableBoolean.INHERIT;
requireSignedPush = InheritableBoolean.INHERIT;
submitType = SubmitType.MERGE_IF_NECESSARY;
+ rejectEmptyCommit = InheritableBoolean.INHERIT;
}
public Project.NameKey getProject() {
diff --git a/java/com/google/gerrit/server/restapi/change/Files.java b/java/com/google/gerrit/server/restapi/change/Files.java
index 1bb6bf2..b374fdc 100644
--- a/java/com/google/gerrit/server/restapi/change/Files.java
+++ b/java/com/google/gerrit/server/restapi/change/Files.java
@@ -18,6 +18,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -332,7 +333,7 @@
return this;
}
- public ListFiles setBase(String base) {
+ public ListFiles setBase(@Nullable String base) {
this.base = base;
return this;
}
diff --git a/java/com/google/gerrit/server/restapi/change/QueryChanges.java b/java/com/google/gerrit/server/restapi/change/QueryChanges.java
index 4a145bc..d1eea44 100644
--- a/java/com/google/gerrit/server/restapi/change/QueryChanges.java
+++ b/java/com/google/gerrit/server/restapi/change/QueryChanges.java
@@ -82,6 +82,7 @@
imp.setStart(start);
}
+ @Override
public void setDynamicBean(String plugin, DynamicOptions.DynamicBean dynamicBean) {
imp.setDynamicBean(plugin, dynamicBean);
}
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index 7773914..60a24d8 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -109,7 +109,7 @@
private final MetaDataUpdate.User metaDataUpdateFactory;
private final GitReferenceUpdated referenceUpdated;
private final RepositoryConfig repositoryCfg;
- private final PersonIdent serverIdent;
+ private final Provider<PersonIdent> serverIdent;
private final Provider<IdentifiedUser> identifiedUser;
private final Provider<PutConfig> putConfig;
private final AllProjectsName allProjects;
@@ -131,7 +131,7 @@
MetaDataUpdate.User metaDataUpdateFactory,
GitReferenceUpdated referenceUpdated,
RepositoryConfig repositoryCfg,
- @GerritPersonIdent PersonIdent serverIdent,
+ @GerritPersonIdent Provider<PersonIdent> serverIdent,
Provider<IdentifiedUser> identifiedUser,
Provider<PutConfig> putConfig,
AllProjectsName allProjects,
@@ -357,7 +357,7 @@
CommitBuilder cb = new CommitBuilder();
cb.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[] {}));
cb.setAuthor(metaDataUpdateFactory.getUserPersonIdent());
- cb.setCommitter(serverIdent);
+ cb.setCommitter(serverIdent.get());
cb.setMessage("Initial empty repository\n");
ObjectId id = oi.insert(cb);
diff --git a/java/com/google/gerrit/sshd/commands/Query.java b/java/com/google/gerrit/sshd/commands/Query.java
index c4a21d1..4d8351e 100644
--- a/java/com/google/gerrit/sshd/commands/Query.java
+++ b/java/com/google/gerrit/sshd/commands/Query.java
@@ -104,6 +104,7 @@
processor.query(join(query, " "));
}
+ @Override
public void setDynamicBean(String plugin, DynamicOptions.DynamicBean dynamicBean) {
processor.setDynamicBean(plugin, dynamicBean);
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index ed4137d..30aef73 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -1692,7 +1692,7 @@
PushOneCommit.Result result = createChange();
String username = name("new-user");
- gApi.accounts().create(username).setActive(false);
+ accountOperations.newAccount().username(username).inactive().create();
AddReviewerInput in = new AddReviewerInput();
in.reviewer = username;
@@ -1714,7 +1714,7 @@
PushOneCommit.Result result = createChange();
String username = "user@domain.com";
- gApi.accounts().create(username).setActive(false);
+ accountOperations.newAccount().username(username).inactive().create();
AddReviewerInput in = new AddReviewerInput();
in.reviewer = username;
@@ -2096,7 +2096,7 @@
ChangeResource rsrc = parseResource(r);
String oldETag = rsrc.getETag();
- gApi.accounts().id(admin.id.get()).setStatus("new status");
+ accountOperations.account(admin.id).forUpdate().status("new status").update();
rsrc = parseResource(r);
assertThat(rsrc.getETag()).isNotEqualTo(oldETag);
}
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
index 9ff2c05..b8380f5 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommentInfo;
@@ -33,6 +34,7 @@
public class MailProcessorIT extends AbstractMailIT {
@Inject private MailProcessor mailProcessor;
+ @Inject private AccountOperations accountOperations;
@Test
public void parseAndPersistChangeMessage() throws Exception {
@@ -163,16 +165,13 @@
b.textContent(txt + textFooterForChange(changeInfo._number, ts));
// Set account state to inactive
- gApi.accounts().id("user").setActive(false);
+ accountOperations.account(user.id).forUpdate().inactive().update();
mailProcessor.process(b.build());
comments = gApi.changes().id(changeId).current().commentsAsList();
// Check that comment size has not changed
assertThat(comments).hasSize(2);
-
- // Reset
- gApi.accounts().id("user").setActive(true);
}
@Test
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
index bb545c9..93e97c4 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -45,13 +45,13 @@
case V2_4:
return "elasticsearch:2.4.6-alpine";
case V5_6:
- return "docker.elastic.co/elasticsearch/elasticsearch:5.6.12";
+ return "docker.elastic.co/elasticsearch/elasticsearch:5.6.13";
case V6_2:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4";
case V6_3:
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.2";
case V6_4:
- return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.2";
+ return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.3";
}
throw new IllegalStateException("No tests for version: " + version.name());
}
diff --git a/lib/httpcomponents/BUILD b/lib/httpcomponents/BUILD
index 8e9fbc5..a875eaf 100644
--- a/lib/httpcomponents/BUILD
+++ b/lib/httpcomponents/BUILD
@@ -28,20 +28,15 @@
)
java_library(
- name = "httpmime",
- data = ["//lib:LICENSE-Apache2.0"],
- visibility = ["//visibility:public"],
- exports = ["@httpmime//jar"],
-)
-
-java_library(
name = "httpasyncclient",
data = ["//lib:LICENSE-Apache2.0"],
+ visibility = ["//java/com/google/gerrit/elasticsearch:__pkg__"],
exports = ["@httpasyncclient//jar"],
)
java_library(
name = "httpcore-nio",
data = ["//lib:LICENSE-Apache2.0"],
+ visibility = ["//java/com/google/gerrit/elasticsearch:__pkg__"],
exports = ["@httpcore-nio//jar"],
)
diff --git a/plugins/replication b/plugins/replication
index a7b900b..bc5efb5 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit a7b900bd524c333c8ca2825e37fa781ac055ac36
+Subproject commit bc5efb5b60a5a93c25c075f3667841e02532a99c
diff --git a/plugins/singleusergroup b/plugins/singleusergroup
index cc636d7..0f798f6 160000
--- a/plugins/singleusergroup
+++ b/plugins/singleusergroup
@@ -1 +1 @@
-Subproject commit cc636d7e36afb62455a9f045b125d246fd84afd0
+Subproject commit 0f798f61c0c598c1499cbaacc1c609078c8bf0d5
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html
index d55d7e9..f43a3e2 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html
@@ -71,6 +71,17 @@
</span>
</section>
<section>
+ <span class="title">Owner</span>
+ <span class="value">
+ <gr-autocomplete
+ id="ownerInput"
+ text="{{_repoOwner}}"
+ value="{{_repoOwnerId}}"
+ query="[[_queryGroups]]">
+ </gr-autocomplete>
+ </span>
+ </section>
+ <section>
<span class="title">Create initial empty commit</span>
<span class="value">
<gr-select
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js
index 9dde290..bb2b5f2 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js
@@ -43,6 +43,11 @@
type: Boolean,
value: false,
},
+ _repoOwner: String,
+ _repoOwnerId: {
+ type: String,
+ observer: '_repoOwnerIdUpdate',
+ },
_query: {
type: Function,
@@ -50,6 +55,12 @@
return this._getRepoSuggestions.bind(this);
},
},
+ _queryGroups: {
+ type: Function,
+ value() {
+ return this._getGroupSuggestions.bind(this);
+ },
+ },
},
observers: [
@@ -70,6 +81,14 @@
this.hasNewRepoName = !!name;
},
+ _repoOwnerIdUpdate(id) {
+ if (id) {
+ this.set('_repoConfig.owners', [id]);
+ } else {
+ this.set('_repoConfig.owners', undefined);
+ }
+ },
+
handleCreateRepo() {
return this.$.restAPI.createRepo(this._repoConfig)
.then(repoRegistered => {
@@ -94,5 +113,20 @@
return repos;
});
},
+
+ _getGroupSuggestions(input) {
+ return this.$.restAPI.getSuggestedGroups(input)
+ .then(response => {
+ const groups = [];
+ for (const key in response) {
+ if (!response.hasOwnProperty(key)) { continue; }
+ groups.push({
+ name: key,
+ value: decodeURIComponent(response[key].id),
+ });
+ }
+ return groups;
+ });
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
index e70c11a..6bc3522 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
@@ -60,6 +60,7 @@
create_empty_commit: true,
parent: 'All-Project',
permissions_only: false,
+ owners: ['testId'],
};
const saveStub = sandbox.stub(element.$.restAPI,
@@ -76,8 +77,12 @@
permissions_only: false,
};
+ element._repoOwner = 'test';
+ element._repoOwnerId = 'testId';
+
element.$.repoNameInput.bindValue = configInputObj.name;
element.$.rightsInheritFromInput.bindValue = configInputObj.parent;
+ element.$.ownerInput.text = configInputObj.owners[0];
element.$.initalCommit.bindValue =
configInputObj.create_empty_commit;
element.$.parentRepo.bindValue =
@@ -92,5 +97,10 @@
done();
});
});
+
+ test('testing observer of _repoOwner', () => {
+ element._repoOwnerId = 'test-5';
+ assert.deepEqual(element._repoConfig.owners, ['test-5']);
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 148cd34..38f5f2f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -531,6 +531,7 @@
patch-num="{{_patchRange.patchNum}}"
base-patch-num="{{_patchRange.basePatchNum}}"
files-expanded="[[_filesExpanded]]"
+ diff-prefs-disabled="[[_diffPrefsDisabled]]"
on-open-diff-prefs="_handleOpenDiffPrefs"
on-open-download-dialog="_handleOpenDownloadDialog"
on-open-upload-help-dialog="_handleOpenUploadHelpDialog"
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index a905c9f..24453be 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -108,6 +108,14 @@
type: Boolean,
value: false,
},
+ disableDiffPrefs: {
+ type: Boolean,
+ value: false,
+ },
+ _diffPrefsDisabled: {
+ type: Boolean,
+ computed: '_computeDiffPrefsDisabled(disableDiffPrefs, _loggedIn)',
+ },
_commentThreads: Array,
/** @type {?} */
_serverConfig: {
@@ -978,6 +986,8 @@
if (this.shouldSuppressKeyboardShortcut(e) ||
this.modifierPressed(e)) { return; }
+ if (this._diffPrefsDisabled) { return; }
+
e.preventDefault();
this.$.fileList.openDiffPrefs();
},
@@ -1664,5 +1674,9 @@
_computeCurrentRevision(currentRevision, revisions) {
return revisions && revisions[currentRevision];
},
+
+ _computeDiffPrefsDisabled(disableDiffPrefs, loggedIn) {
+ return disableDiffPrefs || !loggedIn;
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index 4b6cc6c..df06e55 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -291,6 +291,16 @@
test(', should open diff preferences', () => {
const stub = sandbox.stub(element.$.fileList.$.diffPreferences, 'open');
+ element._loggedIn = false;
+ element.disableDiffPrefs = true;
+ MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+ assert.isFalse(stub.called);
+
+ element._loggedIn = true;
+ MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+ assert.isFalse(stub.called);
+
+ element.disableDiffPrefs = false;
MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
assert.isTrue(stub.called);
});
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
index 142e706..924ddab 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
@@ -249,10 +249,10 @@
<gr-diff-mode-selector
id="modeSelect"
mode="{{diffViewMode}}"
- save-on-change="[[loggedIn]]"></gr-diff-mode-selector>
+ save-on-change="[[!diffPrefsDisabled]]"></gr-diff-mode-selector>
<span id="diffPrefsContainer"
class="hideOnEdit"
- hidden$="[[_computePrefsButtonHidden(diffPrefs, loggedIn)]]"
+ hidden$="[[_computePrefsButtonHidden(diffPrefs, diffPrefsDisabled)]]"
hidden>
<gr-button
link
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
index 665472b..b9e6288 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
@@ -62,6 +62,7 @@
serverConfig: Object,
shownFileCount: Number,
diffPrefs: Object,
+ diffPrefsDisabled: Boolean,
diffViewMode: {
type: String,
notify: true,
@@ -186,11 +187,10 @@
});
},
- _computePrefsButtonHidden(prefs, loggedIn) {
- return !loggedIn || !prefs;
+ _computePrefsButtonHidden(prefs, diffPrefsDisabled) {
+ return diffPrefsDisabled || !prefs;
},
-
_fileListActionsVisible(shownFileCount, maxFilesForBulkActions) {
return shownFileCount <= maxFilesForBulkActions;
},
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
index e2685e1..adfeeb4 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
@@ -62,21 +62,21 @@
});
});
- test('Diff preferences hidden when no prefs or logged out', () => {
- element.loggedIn = false;
+ test('Diff preferences hidden when no prefs or diffPrefsDisabled', () => {
+ element.diffPrefsDisabled = true;
flushAsynchronousOperations();
assert.isTrue(element.$.diffPrefsContainer.hidden);
- element.loggedIn = true;
+ element.diffPrefsDisabled = false;
flushAsynchronousOperations();
assert.isTrue(element.$.diffPrefsContainer.hidden);
- element.loggedIn = false;
+ element.diffPrefsDisabled = true;
element.diffPrefs = {font_size: '12'};
flushAsynchronousOperations();
assert.isTrue(element.$.diffPrefsContainer.hidden);
- element.loggedIn = true;
+ element.diffPrefsDisabled = false;
flushAsynchronousOperations();
assert.isFalse(element.$.diffPrefsContainer.hidden);
});
@@ -265,7 +265,7 @@
suite('editMode behavior', () => {
setup(() => {
- element.loggedIn = true;
+ element.diffPrefsDisabled = false;
element.diffPrefs = {};
});
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
index ff5b290..f2cfe87 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
@@ -290,14 +290,14 @@
_resultsChanged(related, submittedTogether, conflicts,
cherryPicks, sameTopic) {
const results = [
- related,
- submittedTogether,
+ related && related.changes,
+ submittedTogether && submittedTogether.changes,
conflicts,
cherryPicks,
sameTopic,
];
for (let i = 0; i < results.length; i++) {
- if (results[i].length > 0) {
+ if (results[i] && results[i].length > 0) {
this.hidden = false;
this.fire('update', null, {bubbles: false});
return;
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
index bfeb694..48cc565 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
@@ -382,7 +382,7 @@
true);
});
- test('clear and empties', () => {
+ suite('hidden attribute and update event', () => {
const changes = [{
project: 'foo/bar',
change_id: 'Ideadbeef',
@@ -397,33 +397,68 @@
_current_revision_number: 1,
status: 'NEW',
}];
- element._relatedResponse = {changes};
- element._submittedTogether = {changes};
- element._conflicts = changes;
- element._cherryPicks = changes;
- element._sameTopic = changes;
- element.hidden = false;
- element.clear();
- assert.isTrue(element.hidden);
- assert.equal(element._relatedResponse.changes.length, 0);
- assert.equal(element._submittedTogether.changes.length, 0);
- assert.equal(element._conflicts.length, 0);
- assert.equal(element._cherryPicks.length, 0);
- assert.equal(element._sameTopic.length, 0);
- });
+ test('clear and empties', () => {
+ element._relatedResponse = {changes};
+ element._submittedTogether = {changes};
+ element._conflicts = changes;
+ element._cherryPicks = changes;
+ element._sameTopic = changes;
- test('update fires', () => {
- const updateHandler = sandbox.stub();
- element.addEventListener('update', updateHandler);
+ element.hidden = false;
+ element.clear();
+ assert.isTrue(element.hidden);
+ assert.equal(element._relatedResponse.changes.length, 0);
+ assert.equal(element._submittedTogether.changes.length, 0);
+ assert.equal(element._conflicts.length, 0);
+ assert.equal(element._cherryPicks.length, 0);
+ assert.equal(element._sameTopic.length, 0);
+ });
- element._resultsChanged([], [], [], [], []);
- assert.isTrue(element.hidden);
- assert.isFalse(updateHandler.called);
+ test('update fires', () => {
+ const updateHandler = sandbox.stub();
+ element.addEventListener('update', updateHandler);
- element._resultsChanged([], [], [], [], ['test']);
- assert.isFalse(element.hidden);
- assert.isTrue(updateHandler.called);
+ element._resultsChanged({}, {}, [], [], []);
+ assert.isTrue(element.hidden);
+ assert.isFalse(updateHandler.called);
+
+ element._resultsChanged({}, {}, [], [], ['test']);
+ assert.isFalse(element.hidden);
+ assert.isTrue(updateHandler.called);
+ });
+
+ suite('hiding and unhiding', () => {
+ test('related response', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged({changes}, {}, [], [], []);
+ assert.isFalse(element.hidden);
+ });
+
+ test('submitted together', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged({}, {changes}, [], [], []);
+ assert.isFalse(element.hidden);
+ });
+
+ test('conflicts', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged({}, {}, changes, [], []);
+ assert.isFalse(element.hidden);
+ });
+
+ test('cherrypicks', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged({}, {}, [], changes, []);
+ assert.isFalse(element.hidden);
+ });
+
+ test('same topic', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged({}, {}, [], [], changes);
+ assert.isFalse(element.hidden);
+ });
+ });
});
test('_computeChangeURL uses Gerrit.Nav', () => {
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index 5be259c..7278c5a 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -166,6 +166,7 @@
CHANGE: 'change',
DASHBOARD: 'dashboard',
DIFF: 'diff',
+ DOCUMENTATION_SEARCH: 'documentation-search',
EDIT: 'edit',
GROUP: 'group',
PLUGIN_SCREEN: 'plugin-screen',
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index 2ea7e37..0f2bbff 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -148,6 +148,10 @@
IMPROPERLY_ENCODED_PLUS: /^\/c\/(.+)\/\ \/(.+)$/,
PLUGIN_SCREEN: /^\/x\/([\w-]+)\/([\w-]+)\/?/,
+
+ DOCUMENTATION_SEARCH_FILTER: '/Documentation/q/filter::filter',
+ DOCUMENTATION_SEARCH: /^\/Documentation\/q\/(.*)$/,
+ DOCUMENTATION: /^\/Documentation(\/)?(.+)?/,
};
/**
@@ -848,6 +852,17 @@
this._mapRoute(RoutePattern.PLUGIN_SCREEN, '_handlePluginScreen');
+ this._mapRoute(RoutePattern.DOCUMENTATION_SEARCH_FILTER,
+ '_handleDocumentationSearchRoute');
+
+ // redirects /Documentation/q/* to /Documentation/q/filter:*
+ this._mapRoute(RoutePattern.DOCUMENTATION_SEARCH,
+ '_handleDocumentationSearchRedirectRoute');
+
+ // Makes sure /Documentation/* links work (doin't return 404)
+ this._mapRoute(RoutePattern.DOCUMENTATION,
+ '_handleDocumentationRedirectRoute');
+
// Note: this route should appear last so it only catches URLs unmatched
// by other patterns.
this._mapRoute(RoutePattern.DEFAULT, '_handleDefaultRoute');
@@ -1425,6 +1440,27 @@
this._setParams({view, plugin, screen});
},
+ _handleDocumentationSearchRoute(data) {
+ this._setParams({
+ view: Gerrit.Nav.View.DOCUMENTATION_SEARCH,
+ filter: data.params.filter || null,
+ });
+ },
+
+ _handleDocumentationSearchRedirectRoute(data) {
+ this._redirect('/Documentation/q/filter:' +
+ encodeURIComponent(data.params[0]));
+ },
+
+ _handleDocumentationRedirectRoute(data) {
+ if (data.params[1]) {
+ location.reload();
+ } else {
+ // Redirect /Documentation to /Documentation/index.html
+ this._redirect('/Documentation/index.html');
+ }
+ },
+
/**
* Catchall route for when no other route is matched.
*/
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
index 7d4f9ba..b9eaa18 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
@@ -157,6 +157,9 @@
'_handleDefaultRoute',
'_handleChangeLegacyRoute',
'_handleDiffLegacyRoute',
+ '_handleDocumentationRedirectRoute',
+ '_handleDocumentationSearchRoute',
+ '_handleDocumentationSearchRedirectRoute',
'_handleLegacyLinenum',
'_handleImproperlyEncodedPlusRoute',
'_handlePassThroughRoute',
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
index b2fc64c..a9242be 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
@@ -14,14 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-(function(window, GrDiffBuilderSideBySide) {
+(function(window, GrDiffBuilder) {
'use strict';
// Prevent redefinition.
if (window.GrDiffBuilderBinary) { return; }
- function GrDiffBuilderBinary(diff, comments, prefs, outputEl) {
- GrDiffBuilder.call(this, diff, comments, null, prefs, outputEl);
+ function GrDiffBuilderBinary(diff, patchRange, commentThreadEls, prefs,
+ outputEl) {
+ GrDiffBuilder.call(this, diff, patchRange, commentThreadEls, prefs,
+ outputEl);
}
GrDiffBuilderBinary.prototype = Object.create(GrDiffBuilder.prototype);
@@ -43,4 +45,4 @@
};
window.GrDiffBuilderBinary = GrDiffBuilderBinary;
-})(window, GrDiffBuilderSideBySide);
+})(window, GrDiffBuilder);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
index 88ff79b..c52a504 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
@@ -22,9 +22,9 @@
const IMAGE_MIME_PATTERN = /^image\/(bmp|gif|jpeg|jpg|png|tiff|webp)$/;
- function GrDiffBuilderImage(diff, comments, createThreadGroupFn, prefs,
+ function GrDiffBuilderImage(diff, patchRange, commentThreadEls, prefs,
outputEl, baseImage, revisionImage) {
- GrDiffBuilderSideBySide.call(this, diff, comments, createThreadGroupFn,
+ GrDiffBuilderSideBySide.call(this, diff, patchRange, commentThreadEls,
prefs, outputEl, []);
this._baseImage = baseImage;
this._revisionImage = revisionImage;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
index fafae63..da085c2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
@@ -20,9 +20,9 @@
// Prevent redefinition.
if (window.GrDiffBuilderSideBySide) { return; }
- function GrDiffBuilderSideBySide(diff, comments, createThreadGroupFn, prefs,
- outputEl, layers) {
- GrDiffBuilder.call(this, diff, comments, createThreadGroupFn, prefs,
+ function GrDiffBuilderSideBySide(diff, patchRange, commentThreadEls,
+ prefs, outputEl, layers) {
+ GrDiffBuilder.call(this, diff, patchRange, commentThreadEls, prefs,
outputEl, layers);
}
GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
index 9a04b1f..0657ee4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
@@ -20,9 +20,9 @@
// Prevent redefinition.
if (window.GrDiffBuilderUnified) { return; }
- function GrDiffBuilderUnified(diff, comments, createThreadGroupFn, prefs,
+ function GrDiffBuilderUnified(diff, patchRange, commentThreadEls, prefs,
outputEl, layers) {
- GrDiffBuilder.call(this, diff, comments, createThreadGroupFn, prefs,
+ GrDiffBuilder.call(this, diff, patchRange, commentThreadEls, prefs,
outputEl, layers);
}
GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index 0997fee..e26201a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -16,9 +16,9 @@
-->
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../core/gr-reporting/gr-reporting.html">
-<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
-<link rel="import" href="../gr-diff-comment-thread-group/gr-diff-comment-thread-group.html">
+<link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
<link rel="import" href="../gr-diff-processor/gr-diff-processor.html">
+<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
<link rel="import" href="../gr-ranged-comment-layer/gr-ranged-comment-layer.html">
<link rel="import" href="../gr-syntax-layer/gr-syntax-layer.html">
@@ -113,17 +113,14 @@
isImageDiff: Boolean,
baseImage: Object,
revisionImage: Object,
+ parentIndex: Number,
+ path: String,
projectName: String,
/**
* @type {Defs.LineOfInterest|null}
*/
lineOfInterest: Object,
- /**
- * @type {function(number, booleam, !string)}
- */
- createCommentFn: Function,
-
_builder: Object,
_groups: Array,
_layers: Array,
@@ -134,6 +131,10 @@
return this.queryEffectiveChildren('#diffTable');
},
+ get _commentThreadElements() {
+ return this.queryAllEffectiveChildren('.comment-thread');
+ },
+
observers: [
'_groupsChanged(_groups.splices)',
],
@@ -155,10 +156,6 @@
}
this._layers = layers;
-
- this.async(() => {
- this._preRenderThread();
- });
},
render(comments, prefs) {
@@ -169,7 +166,8 @@
// Stop the processor and syntax layer (if they're running).
this.cancel();
- this._builder = this._getDiffBuilder(this.diff, comments, prefs);
+ this._builder = this._getDiffBuilder(
+ this.diff, comments.meta.patchRange, prefs);
this.$.processor.context = prefs.context;
this.$.processor.keyLocations = this._getKeyLocations(comments,
@@ -293,7 +291,7 @@
throw Error(`Invalid preference value: ${pref}`);
},
- _getDiffBuilder(diff, comments, prefs) {
+ _getDiffBuilder(diff, patchRange, prefs) {
if (isNaN(prefs.tab_size) || prefs.tab_size <= 0) {
this._handlePreferenceError('tab size');
return;
@@ -305,20 +303,22 @@
}
let builder = null;
- const createFn = this.createCommentFn;
if (this.isImageDiff) {
- builder = new GrDiffBuilderImage(diff, comments, createFn, prefs,
- this.diffElement, this.baseImage, this.revisionImage);
+ builder = new GrDiffBuilderImage(diff, patchRange,
+ this._commentThreadElements, prefs, this.diffElement,
+ this.baseImage, this.revisionImage);
} else if (diff.binary) {
// If the diff is binary, but not an image.
- return new GrDiffBuilderBinary(diff, comments, prefs,
- this.diffElement);
+ return new GrDiffBuilderBinary(diff, patchRange,
+ this._commentThreadElements, prefs, this.diffElement);
} else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
- builder = new GrDiffBuilderSideBySide(diff, comments, createFn,
- prefs, this.diffElement, this._layers);
+ builder = new GrDiffBuilderSideBySide(diff, patchRange,
+ this._commentThreadElements, prefs, this.diffElement,
+ this._layers);
} else if (this.viewMode === DiffViewMode.UNIFIED) {
- builder = new GrDiffBuilderUnified(diff, comments, createFn, prefs,
- this.diffElement, this._layers);
+ builder = new GrDiffBuilderUnified(diff, patchRange,
+ this._commentThreadElements, prefs, this.diffElement,
+ this._layers);
}
if (!builder) {
throw Error('Unsupported diff view mode: ' + this.viewMode);
@@ -445,25 +445,6 @@
},
/**
- * In pages with large diffs, creating the first comment thread can be
- * slow because nested Polymer elements (particularly
- * iron-autogrow-textarea) add style elements to the document head,
- * which, in turn, triggers a reflow on the page. Create a hidden
- * thread, attach it to the page, and remove it so the stylesheet will
- * already exist and the user's comment will be quick to load.
- * @see https://gerrit-review.googlesource.com/c/82213/
- */
- _preRenderThread() {
- const thread = document.createElement('gr-diff-comment-thread');
- thread.setAttribute('hidden', true);
- thread.addDraft();
- const parent = Polymer.dom(this.root);
- parent.appendChild(thread);
- Polymer.dom.flush();
- parent.removeChild(thread);
- },
-
- /**
* @return {boolean} whether any of the lines in _groups are longer
* than SYNTAX_MAX_LINE_LENGTH.
*/
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
index be53fda..6ea48ac 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
@@ -20,6 +20,60 @@
// Prevent redefinition.
if (window.GrDiffBuilder) { return; }
+ /** @enum {string} */
+ Gerrit.DiffSide = {
+ LEFT: 'left',
+ RIGHT: 'right',
+ BOTH: 'both',
+ };
+
+ /**
+ * @param {!Array<!HTMLElement>} threadEls
+ * @param {!{beforeNumber: (number|string|undefined),
+ * afterNumber: (number|string|undefined)}}
+ * lineInfo
+ * @param {!Gerrit.DiffSide=} side The side (LEFT, RIGHT, BOTH) for
+ * which to return the threads (default: BOTH).
+ * @return {!Array<!HTMLElement>} The thread elements matching the given
+ * location.
+ */
+ Gerrit.filterThreadElsForLocation = function(
+ threadEls, lineInfo, side = Gerrit.DiffSide.BOTH) {
+ function matchesLeftLine(threadEl) {
+ return threadEl.getAttribute('comment-side') ==
+ Gerrit.DiffSide.LEFT &&
+ threadEl.getAttribute('line-num') == lineInfo.beforeNumber;
+ }
+ function matchesRightLine(threadEl) {
+ return threadEl.getAttribute('comment-side') ==
+ Gerrit.DiffSide.RIGHT &&
+ threadEl.getAttribute('line-num') == lineInfo.afterNumber;
+ }
+ function matchesFileComment(threadEl) {
+ return (side === Gerrit.DiffSide.BOTH ||
+ threadEl.getAttribute('comment-side') == side) &&
+ // line/range comments have 1-based line set, if line is falsy it's
+ // a file comment
+ !threadEl.getAttribute('line-num');
+ }
+
+ // Select the appropriate matchers for the desired side and line
+ // If side is BOTH, we want both the left and right matcher.
+ const matchers = [];
+ if (side !== Gerrit.DiffSide.RIGHT) {
+ matchers.push(matchesLeftLine);
+ }
+ if (side !== Gerrit.DiffSide.LEFT) {
+ matchers.push(matchesRightLine);
+ }
+ if (lineInfo.afterNumber === 'FILE' ||
+ lineInfo.beforeNumber === 'FILE') {
+ matchers.push(matchesFileComment);
+ }
+ return threadEls.filter(threadEl =>
+ matchers.some(matcher => matcher(threadEl)));
+ };
+
/**
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
* For example '𐀏'.length is 2. An occurence of such a code point is called a
@@ -42,11 +96,10 @@
*/
const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
- function GrDiffBuilder(diff, comments, createThreadGroupFn, prefs, outputEl,
- layers) {
+ function GrDiffBuilder(diff, patchRange, commentThreadEls, prefs,
+ outputEl, layers) {
this._diff = diff;
- this._comments = comments;
- this._createThreadGroupFn = createThreadGroupFn;
+ this._patchRange = patchRange;
this._prefs = prefs;
this._outputEl = outputEl;
this.groups = [];
@@ -68,15 +121,7 @@
}
}
- const allComments = [];
- for (const side of [GrDiffBuilder.Side.LEFT, GrDiffBuilder.Side.RIGHT]) {
- // This is needed by the threading.
- for (const comment of this._comments[side]) {
- comment.__commentSide = side;
- }
- allComments.push(...this._comments[side]);
- }
- this._threads = this._createThreads(allComments);
+ this._threadEls = commentThreadEls;
}
GrDiffBuilder.GroupType = {
@@ -330,150 +375,26 @@
};
/**
- * @param {!Array<Object>} threads
* @param {!GrDiffLine} line
* @param {!GrDiffBuilder.Side=} side The side (LEFT, RIGHT, BOTH) for which
- * to return the threads (default: BOTH).
- */
- GrDiffBuilder.prototype._filterThreadsForLine = function(
- threads, line, side = GrDiffBuilder.Side.BOTH) {
- function matchesLeftLine(thread) {
- return thread.commentSide == GrDiffBuilder.Side.LEFT &&
- thread.comments[0].line == line.beforeNumber;
- }
- function matchesRightLine(thread) {
- return thread.commentSide == GrDiffBuilder.Side.RIGHT &&
- thread.comments[0].line == line.afterNumber;
- }
- function matchesFileComment(thread) {
- return (side === GrDiffBuilder.Side.BOTH ||
- thread.commentSide == side) &&
- // line/range comments have 1-based line set, if line is falsy it's
- // a file comment
- !thread.comments[0].line;
- }
-
- // Select the appropriate matchers for the desired side and line
- // If side is BOTH, we want both the left and right matcher.
- const matchers = [];
- if (side !== GrDiffBuilder.Side.RIGHT) {
- matchers.push(matchesLeftLine);
- }
- if (side !== GrDiffBuilder.Side.LEFT) {
- matchers.push(matchesRightLine);
- }
- if (line.afterNumber === GrDiffLine.FILE ||
- line.beforeNumber === GrDiffLine.FILE) {
- matchers.push(matchesFileComment);
- }
-
- return threads.filter(thread => matchers.find(matcher => matcher(thread)));
- };
-
- /**
- * @param {Array<Object>} comments
- */
- GrDiffBuilder.prototype._createThreads = function(comments) {
- const sortedComments = comments.slice(0).sort((a, b) => {
- if (b.__draft && !a.__draft ) { return 0; }
- if (a.__draft && !b.__draft ) { return 1; }
- return util.parseDate(a.updated) - util.parseDate(b.updated);
- });
-
- const threads = [];
- for (const comment of sortedComments) {
- // If the comment is in reply to another comment, find that comment's
- // thread and append to it.
- if (comment.in_reply_to) {
- const thread = threads.find(thread =>
- thread.comments.some(c => c.id === comment.in_reply_to));
- if (thread) {
- thread.comments.push(comment);
- continue;
- }
- }
-
- // Otherwise, this comment starts its own thread.
- const newThread = {
- start_datetime: comment.updated,
- comments: [comment],
- commentSide: comment.__commentSide,
- patchNum: comment.patch_set,
- rootId: comment.id || comment.__draftID,
- };
- if (comment.range) {
- newThread.range = Object.assign({}, comment.range);
- }
- threads.push(newThread);
- }
- return threads;
- };
-
- /**
- * Returns the patch number that new comment threads should be attached to.
- *
- * @param {GrDiffLine} line The line new thread will be attached to.
- * @param {string=} opt_side Set to LEFT to force adding it to the LEFT side -
- * will be ignored if the left is a parent or a merge parent
- * @return {number} Patch set to attach the new thread to
- */
- GrDiffBuilder.prototype._determinePatchNumForNewThreads = function(
- patchRange, line, opt_side) {
- if ((line.type === GrDiffLine.Type.REMOVE ||
- opt_side === GrDiffBuilder.Side.LEFT) &&
- patchRange.basePatchNum !== 'PARENT' &&
- !Gerrit.PatchSetBehavior.isMergeParent(patchRange.basePatchNum)) {
- return patchRange.basePatchNum;
- } else {
- return patchRange.patchNum;
- }
- };
-
- /**
- * Returns whether the comments on the given line are on a (merge) parent.
- *
- * @param {string} firstCommentSide
- * @param {{basePatchNum: number, patchNum: number}} patchRange
- * @param {GrDiffLine} line The line the comments are on.
- * @param {string=} opt_side
- * @return {boolean} True iff the comments on the given line are on a (merge)
- * parent.
- */
- GrDiffBuilder.prototype._determineIsOnParent = function(
- firstCommentSide, patchRange, line, opt_side) {
- return ((line.type === GrDiffLine.Type.REMOVE ||
- opt_side === GrDiffBuilder.Side.LEFT) &&
- (patchRange.basePatchNum === 'PARENT' ||
- Gerrit.PatchSetBehavior.isMergeParent(
- patchRange.basePatchNum))) ||
- firstCommentSide === 'PARENT';
- };
-
- /**
- * @param {!GrDiffLine} line
- * @param {!GrDiffBuilder.Side=} side The side (LEFT, RIGHT, BOTH) for which to return
- * the thread group (default: BOTH).
+ * to return the thread group (default: BOTH).
* @return {!Object}
*/
GrDiffBuilder.prototype._commentThreadGroupForLine = function(
- line, side = GrDiffBuilder.Side.BOTH) {
- const threads =
- this._filterThreadsForLine(this._threads, line, side);
- if (!threads || threads.length === 0) {
+ line, commentSide = GrDiffBuilder.Side.BOTH) {
+ const threadElsForGroup =
+ Gerrit.filterThreadElsForLocation(this._threadEls, line, commentSide);
+ if (!threadElsForGroup || threadElsForGroup.length === 0) {
return null;
}
- const patchRange = this._comments.meta.patchRange;
- const patchNumForNewThread = this._determinePatchNumForNewThreads(
- patchRange, line, side);
- const isOnParent = this._determineIsOnParent(
- threads[0].side, patchRange, line, side);
-
- const threadGroupEl = this._createThreadGroupFn(
- patchNumForNewThread, isOnParent, side);
- threadGroupEl.threads = threads;
- if (side) {
- threadGroupEl.setAttribute('data-side', side);
+ const threadGroupEl = document.createElement('div');
+ threadGroupEl.className = 'thread-group';
+ for (const threadEl of threadElsForGroup) {
+ Polymer.dom(threadGroupEl).appendChild(threadEl);
+ }
+ if (commentSide) {
+ threadGroupEl.setAttribute('data-side', commentSide);
}
return threadGroupEl;
};
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index 80b45a4..a855833 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -60,7 +60,6 @@
let prefs;
let element;
let builder;
- let createThreadGroupFn;
let sandbox;
const LINE_FEED_HTML = '<span class="style-scope gr-diff br"></span>';
@@ -76,142 +75,69 @@
show_tabs: true,
tab_size: 4,
};
- createThreadGroupFn = sinon.spy(() => ({
- setAttribute: sinon.spy(),
- }));
builder = new GrDiffBuilder(
- {content: []}, {left: [], right: []}, createThreadGroupFn, prefs);
+ {content: []}, {left: [], right: []}, [], prefs);
});
teardown(() => { sandbox.restore(); });
- test('_createThreads', () => {
- const comments = [
- {
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- __commentSide: 'left',
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- __commentSide: 'left',
- in_reply_to: 'sallys_confession',
- },
- {
- id: 'new_draft',
- message: 'i do not like either of you',
- __commentSide: 'left',
- __draft: true,
- updated: '2015-12-20 15:01:20.396000000',
- },
- ];
+ test('filterThreadElsForLocation with no threads', () => {
+ const line = {beforeNumber: 3, afterNumber: 5};
- const expectedThreadGroups = [
- {
- start_datetime: '2015-12-23 15:00:20.396000000',
- commentSide: 'left',
- comments: [{
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- __commentSide: 'left',
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- __commentSide: 'left',
- in_reply_to: 'sallys_confession',
- }],
- patchNum: undefined,
- rootId: 'sallys_confession',
- },
- {
- start_datetime: '2015-12-20 15:01:20.396000000',
- commentSide: 'left',
- comments: [
- {
- id: 'new_draft',
- message: 'i do not like either of you',
- __commentSide: 'left',
- __draft: true,
- updated: '2015-12-20 15:01:20.396000000',
- },
- ],
- patchNum: undefined,
- rootId: 'new_draft',
- },
- ];
-
- assert.deepEqual(
- builder._createThreads(comments),
- expectedThreadGroups);
+ const threads = [];
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threads, line), []);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threads, line,
+ Gerrit.DiffSide.LEFT), []);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threads, line,
+ Gerrit.DiffSide.RIGHT), []);
});
- test('_createThreads inherits patchNum amd 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,
- __commentSide: 'left',
- }];
+ test('filterThreadElsForLocation for line comments', () => {
+ const line = {beforeNumber: 3, afterNumber: 5};
- expectedThreadGroups = [
- {
- start_datetime: '2015-12-24 15:00:10.396000000',
- commentSide: 'left',
- 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,
- __commentSide: 'left',
- }],
- patchNum: 5,
- rootId: 'betsys_confession',
- range: {
- start_line: 1,
- start_character: 1,
- end_line: 1,
- end_character: 2,
- },
- },
- ];
+ const l3 = document.createElement('div');
+ l3.setAttribute('line-num', 3);
+ l3.setAttribute('comment-side', 'left');
- assert.deepEqual(
- builder._createThreads(comments),
- expectedThreadGroups);
+ const l5 = document.createElement('div');
+ l5.setAttribute('line-num', 5);
+ l5.setAttribute('comment-side', 'left');
+
+ const r3 = document.createElement('div');
+ r3.setAttribute('line-num', 3);
+ r3.setAttribute('comment-side', 'right');
+
+ const r5 = document.createElement('div');
+ r5.setAttribute('line-num', 5);
+ r5.setAttribute('comment-side', 'right');
+
+ const threadEls = [l3, l5, r3, r5];
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line),
+ [l3, r5]);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
+ Gerrit.DiffSide.LEFT), [l3]);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
+ Gerrit.DiffSide.RIGHT), [r5]);
});
- test('multiple comments at same location but not threaded', () => {
- const comments = [
- {
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- __commentSide: 'left',
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- __commentSide: 'left',
- },
- ];
- assert.equal(builder._createThreads(comments).length, 2);
+ test('filterThreadElsForLocation for file comments', () => {
+ const line = {beforeNumber: 'FILE', afterNumber: 'FILE'};
+
+ const l = document.createElement('div');
+ l.setAttribute('comment-side', 'left');
+
+ const r = document.createElement('div');
+ r.setAttribute('comment-side', 'right');
+
+ const threadEls = [l, r];
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line),
+ [l, r]);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
+ Gerrit.DiffSide.BOTH), [l, r]);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
+ Gerrit.DiffSide.LEFT), [l]);
+ assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
+ Gerrit.DiffSide.RIGHT), [r]);
});
test('_createElement classStr applies all classes', () => {
@@ -387,170 +313,76 @@
}
});
- test('_filterThreadsForLine with no threads', () => {
- const line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = 3;
- line.afterNumber = 5;
-
- const threads = [];
- assert.deepEqual(
- builder._filterThreadsForLine(threads, line), []);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.LEFT), []);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.RIGHT), []);
- });
-
- test('_filterThreadsForLine for line comments', () => {
- const line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = 3;
- line.afterNumber = 5;
-
- const l3 = {
- comments: [{id: 'l3', line: 3}],
- range: {end_line: 3},
- commentSide: 'left',
- };
- const l5 = {
- comments: [{id: 'l5', line: 5}],
- range: {end_line: 5},
- commentSide: 'left',
- };
- const r3 = {
- comments: [{id: 'r3', line: 3}],
- range: {end_line: 3},
- commentSide: 'right',
- };
- const r5 = {
- comments: [{id: 'r5', line: 5}],
- range: {end_line: 5},
- commentSide: 'right',
- };
-
- const threads = [l3, l5, r3, r5];
- assert.deepEqual(builder._filterThreadsForLine(threads, line),
- [l3, r5]);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.LEFT), [l3]);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.RIGHT), [r5]);
- });
-
- test('_filterThreadsForLine for file comments', () => {
- const line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = GrDiffLine.FILE;
- line.afterNumber = GrDiffLine.FILE;
-
- const l = {
- comments: [{id: 'l', line: undefined}],
- commentSide: 'left',
- };
- const r = {
- comments: [{id: 'r', line: undefined}],
- commentSide: 'right',
- };
-
- const threads = [l, r];
- assert.deepEqual(builder._filterThreadsForLine(threads, line),
- [l, r]);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.BOTH), [l, r]);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.LEFT), [l]);
- assert.deepEqual(builder._filterThreadsForLine(threads, line,
- GrDiffBuilder.Side.RIGHT), [r]);
- });
-
test('comment thread group creation', () => {
- const l3 = {id: 'l3', line: 3, updated: '2016-08-09 00:42:32.000000000',
- __commentSide: 'left'};
- const l5 = {id: 'l5', line: 5, updated: '2016-08-09 00:42:32.000000000',
- __commentSide: 'left'};
- const r5 = {id: 'r5', line: 5, updated: '2016-08-09 00:42:32.000000000',
- __commentSide: 'right'};
+ const l3 = document.createElement('div');
+ l3.className = 'comment-thread';
+ l3.setAttribute('comment-side', 'left');
+ l3.setAttribute('line-num', 3);
+
+ const l5 = document.createElement('div');
+ l5.className = 'comment-thread';
+ l5.setAttribute('comment-side', 'left');
+ l5.setAttribute('line-num', 5);
+
+ const r5 = document.createElement('div');
+ r5.className = 'comment-thread';
+ r5.setAttribute('comment-side', 'right');
+ r5.setAttribute('line-num', 5);
builder = new GrDiffBuilder(
- {content: []}, {
- meta: {
- changeNum: '42',
- patchRange: {
- basePatchNum: 'PARENT',
- patchNum: '3',
- },
- path: '/path/to/foo',
- projectConfig: {foo: 'bar'},
- },
- left: [l3, l5],
- right: [r5],
- }, createThreadGroupFn, prefs);
+ {content: []}, {basePatchNum: 'PARENT', patchNum: '3'}, [l3, l5, r5],
+ prefs);
- function threadForComment(c, patchNum) {
- return {
- commentSide: c.__commentSide,
- comments: [c],
- patchNum,
- rootId: c.id,
- start_datetime: c.updated,
- };
- }
-
- function checkThreadGroupProps(threadGroupEl, patchNum, isOnParent,
- comments) {
- assert.equal(createThreadGroupFn.lastCall.args[0], patchNum);
- assert.equal(createThreadGroupFn.lastCall.args[1], isOnParent);
- assert.deepEqual(
- threadGroupEl.threads,
- comments.map(c => threadForComment(c, undefined)));
+ function checkThreadGroupProps(threadGroupEl,
+ expectedThreadEls) {
+ const threadEls = Polymer.dom(threadGroupEl).queryDistributedElements(
+ '.comment-thread');
+ assert.equal(threadEls.length, expectedThreadEls.length);
+ for (let i=0; i<expectedThreadEls.length; i++) {
+ assert.equal(threadEls[i], expectedThreadEls[i]);
+ }
}
let line = new GrDiffLine(GrDiffLine.Type.BOTH);
line.beforeNumber = 5;
line.afterNumber = 5;
let threadGroupEl = builder._commentThreadGroupForLine(line);
- assert.isTrue(createThreadGroupFn.calledOnce);
- checkThreadGroupProps(threadGroupEl, '3', false, [l5, r5]);
+ checkThreadGroupProps(threadGroupEl, [l5, r5]);
threadGroupEl =
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
- assert.isTrue(createThreadGroupFn.calledTwice);
- checkThreadGroupProps(threadGroupEl, '3', false, [r5]);
+ checkThreadGroupProps(threadGroupEl, [r5]);
threadGroupEl =
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
- assert.isTrue(createThreadGroupFn.calledThrice);
- checkThreadGroupProps(threadGroupEl, '3', true, [l5]);
+ checkThreadGroupProps(threadGroupEl, [l5]);
- builder._comments.meta.patchRange.basePatchNum = '1';
+ builder._patchRange.basePatchNum = '1';
threadGroupEl = builder._commentThreadGroupForLine(line);
- assert.equal(createThreadGroupFn.callCount, 4);
- checkThreadGroupProps(threadGroupEl, '3', false, [l5, r5]);
+ checkThreadGroupProps(threadGroupEl, [l5, r5]);
threadEl =
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
- assert.equal(createThreadGroupFn.callCount, 5);
- checkThreadGroupProps(threadEl, '1', false, [l5]);
+ checkThreadGroupProps(threadEl, [l5]);
threadGroupEl =
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
- assert.equal(createThreadGroupFn.callCount, 6);
- checkThreadGroupProps(threadGroupEl, '3', false, [r5]);
+ checkThreadGroupProps(threadGroupEl, [r5]);
- builder._comments.meta.patchRange.basePatchNum = 'PARENT';
+ builder._patchRange.basePatchNum = 'PARENT';
line = new GrDiffLine(GrDiffLine.Type.REMOVE);
line.beforeNumber = 5;
line.afterNumber = 5;
threadGroupEl = builder._commentThreadGroupForLine(line);
- assert.equal(createThreadGroupFn.callCount, 7);
- checkThreadGroupProps(threadGroupEl, '3', true, [l5, r5]);
+ checkThreadGroupProps(threadGroupEl, [l5, r5]);
line = new GrDiffLine(GrDiffLine.Type.ADD);
line.beforeNumber = 3;
line.afterNumber = 5;
threadGroupEl = builder._commentThreadGroupForLine(line);
- assert.equal(createThreadGroupFn.callCount, 8);
- checkThreadGroupProps(threadGroupEl, '3', false, [l3, r5]);
+ checkThreadGroupProps(threadGroupEl, [l3, r5]);
});
@@ -584,16 +416,18 @@
});
const lineOfInterest = {number: 789, leftSide: true};
- assert.deepEqual(element._getKeyLocations(comments, lineOfInterest), {
- left: {FILE: true, 123: true, 789: true},
- right: {456: true},
- });
+ assert.deepEqual(
+ element._getKeyLocations(comments, lineOfInterest), {
+ left: {FILE: true, 123: true, 789: true},
+ right: {456: true},
+ });
delete lineOfInterest.leftSide;
- assert.deepEqual(element._getKeyLocations(comments, lineOfInterest), {
- left: {FILE: true, 123: true},
- right: {456: true, 789: true},
- });
+ assert.deepEqual(
+ element._getKeyLocations(comments, lineOfInterest), {
+ left: {FILE: true, 123: true},
+ right: {456: true, 789: true},
+ });
});
suite('_isTotal', () => {
@@ -1035,7 +869,7 @@
processStub = sandbox.stub(element.$.processor, 'process')
.returns(Promise.resolve());
sandbox.stub(element, '_anyLineTooLong').returns(true);
- comments = {left: [], right: []};
+ comments = {left: [], right: [], meta: {patchRange: undefined}};
prefs = {
line_length: 10,
show_tabs: true,
@@ -1083,6 +917,7 @@
suite('rendering', () => {
let content;
let outputEl;
+ let comments;
setup(done => {
const prefs = {
@@ -1110,9 +945,10 @@
});
element = fixture('basic');
outputEl = element.queryEffectiveChildren('#diffTable');
+ comments = {left: [], right: [], meta: {patchRange: undefined}};
sandbox.stub(element, '_getDiffBuilder', () => {
const builder = new GrDiffBuilder(
- {content}, {left: [], right: []}, null, prefs, outputEl);
+ {content}, undefined, [], prefs, outputEl);
sandbox.stub(builder, 'addColumns');
builder.buildSectionElement = function(group) {
const section = document.createElement('stub');
@@ -1124,7 +960,7 @@
return builder;
});
element.diff = {content};
- element.render({left: [], right: []}, prefs).then(done);
+ element.render(comments, prefs).then(done);
});
test('reporting', done => {
@@ -1149,7 +985,7 @@
});
test('addColumns is called', done => {
- element.render({left: [], right: []}, {}).then(done);
+ element.render(comments, {}).then(done);
assert.isTrue(element._builder.addColumns.called);
});
@@ -1173,7 +1009,7 @@
test('render-start and render are fired', done => {
const dispatchEventStub = sandbox.stub(element, 'dispatchEvent');
- element.render({left: [], right: []}, {}).then(() => {
+ element.render(comments, {}).then(() => {
const firedEventTypes = dispatchEventStub.getCalls()
.map(c => { return c.args[0].type; });
assert.include(firedEventTypes, 'render-start');
@@ -1201,7 +1037,7 @@
context: -1,
syntax_highlighting: true,
};
- element.render({left: [], right: []}, prefs);
+ element.render(comments, prefs);
});
test('cancel', () => {
@@ -1218,6 +1054,7 @@
let builder;
let diff;
let prefs;
+ let comments;
setup(done => {
element = fixture('mock-diff');
@@ -1229,8 +1066,9 @@
show_tabs: true,
tab_size: 4,
};
+ comments = {left: [], right: [], meta: {patchRange: undefined}};
- element.render({left: [], right: []}, prefs).then(() => {
+ element.render(comments, prefs).then(() => {
builder = element._builder;
done();
});
@@ -1340,7 +1178,7 @@
test('_getNextContentOnSide unified left', done => {
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
- element.render({left: [], right: []}, prefs).then(() => {
+ element.render(comments, prefs).then(() => {
builder = element._builder;
const startElem = builder.getContentByLine(5, 'left',
@@ -1360,7 +1198,7 @@
test('_getNextContentOnSide unified right', done => {
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
- element.render({left: [], right: []}, prefs).then(() => {
+ element.render(comments, prefs).then(() => {
builder = element._builder;
const startElem = builder.getContentByLine(5, 'right',
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
deleted file mode 100644
index 58b7c32..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!--
-@license
-Copyright (C) 2017 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.
--->
-
-<link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
-<link rel="import" href="../../../styles/shared-styles.html">
-
-<dom-module id="gr-diff-comment-thread-group">
- <template>
- <style include="shared-styles">
- :host {
- display: block;
- max-width: var(--content-width, 80ch);
- white-space: normal;
- }
- gr-diff-comment-thread + gr-diff-comment-thread {
- margin-top: .2em;
- }
- </style>
- <template is="dom-repeat" items="[[threads]]" as="thread">
- <gr-diff-comment-thread
- comments="[[thread.comments]]"
- comment-side="[[thread.commentSide]]"
- is-on-parent="[[isOnParent]]"
- parent-index="[[parentIndex]]"
- change-num="[[changeNum]]"
- patch-num="[[thread.patchNum]]"
- root-id="{{thread.rootId}}"
- path="[[path]]"
- project-name="[[projectName]]"
- range="[[thread.range]]"
- on-thread-discard="_handleThreadDiscard"></gr-diff-comment-thread>
- </template>
- </template>
- <script src="gr-diff-comment-thread-group.js"></script>
-</dom-module>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
deleted file mode 100644
index 23d0a58..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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.
- */
-(function() {
- 'use strict';
-
- Polymer({
- is: 'gr-diff-comment-thread-group',
-
- properties: {
- changeNum: String,
- projectName: String,
- patchForNewThreads: String,
- isOnParent: {
- type: Boolean,
- value: false,
- },
- parentIndex: {
- type: Number,
- value: null,
- },
- threads: {
- type: Array,
- value() { return []; },
- },
- },
-
- get threadEls() {
- return Polymer.dom(this.root).querySelectorAll('gr-diff-comment-thread');
- },
-
- /**
- * Adds a new thread. Range is optional because a comment can be
- * added to a line without a range selected.
- *
- * @param {!Object} opt_range
- */
- addNewThread(commentSide, opt_range) {
- this.push('threads', {
- comments: [],
- commentSide,
- patchNum: this.patchForNewThreads,
- range: opt_range,
- });
- },
-
- removeThread(rootId) {
- for (let i = 0; i < this.threads.length; i++) {
- if (this.threads[i].rootId === rootId) {
- this.splice('threads', i, 1);
- return;
- }
- }
- },
-
- /**
- * Fetch the thread group at the given range, or the range-less thread
- * on the line if no range is provided, lineNum, and side.
- *
- * @param {string} side
- * @param {!Object=} opt_range
- * @return {!Object|undefined}
- */
- getThread(side, opt_range) {
- const threads = [].filter.call(this.threadEls,
- thread => this._rangesEqual(thread.range, opt_range))
- .filter(thread => thread.commentSide === side);
- if (threads.length === 1) {
- return threads[0];
- }
- },
-
- _handleThreadDiscard(e) {
- this.removeThread(e.detail.rootId);
- },
-
- /**
- * Compare two ranges. Either argument may be falsy, but will only return
- * true if both are falsy or if neither are falsy and have the same position
- * values.
- *
- * @param {Object=} a range 1
- * @param {Object=} b range 2
- * @return {boolean}
- */
- _rangesEqual(a, b) {
- if (!a && !b) { return true; }
- if (!a || !b) { return false; }
- return a.startLine === b.startLine &&
- a.startChar === b.startChar &&
- a.endLine === b.endLine &&
- a.endChar === b.endChar;
- },
- });
-})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
deleted file mode 100644
index 81181b1..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
+++ /dev/null
@@ -1,168 +0,0 @@
-<!DOCTYPE html>
-<!--
-@license
-Copyright (C) 2017 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.
--->
-
-<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<title>gr-diff-comment-thread-group</title>
-
-<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
-<script src="../../../bower_components/web-component-tester/browser.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<script src="../../../scripts/util.js"></script>
-
-<link rel="import" href="gr-diff-comment-thread-group.html">
-
-<script>void(0);</script>
-
-<test-fixture id="basic">
- <template>
- <gr-diff-comment-thread-group></gr-diff-comment-thread-group>
- </template>
-</test-fixture>
-
-<script>
- suite('gr-diff-comment-thread-group tests', () => {
- let element;
- let sandbox;
-
- setup(() => {
- sandbox = sinon.sandbox.create();
- stub('gr-rest-api-interface', {
- getLoggedIn() { return Promise.resolve(false); },
- });
- element = fixture('basic');
- });
-
- teardown(() => {
- sandbox.restore();
- });
-
- test('getThread', () => {
- const range = {
- start_line: 1,
- start_character: 1,
- end_line: 1,
- end_character: 2,
- };
- element.threads = [
- {
- rootId: 'sallys_confession',
- commentSide: 'left',
- comments: [
- {
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- __commentSide: 'left',
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- __commentSide: 'left',
- in_reply_to: 'sallys_confession',
- }, {
- id: 'new_draft',
- message: 'i do not like either of you',
- __commentSide: 'left',
- __draft: true,
- in_reply_to: 'sallys_confession',
- updated: '2015-12-20 15:01:20.396000000',
- },
- ],
- },
- {
- rootId: 'right_side_comment',
- commentSide: 'right',
- comments: [
- {
- id: 'right_side_comment',
- message: 'right side comment',
- __commentSide: 'right',
- __draft: true,
- updated: '2015-12-20 15:01:20.396000000',
- },
- ],
- }, {
- rootId: 'betsys_confession',
- commentSide: 'left',
- range,
- comments: [
- {
- id: 'betsys_confession',
- message: 'i like you more, jack',
- updated: '2015-12-24 15:00:10.396000000',
- range,
- __commentSide: 'left',
- },
- ],
- },
- ];
-
- flushAsynchronousOperations();
- assert.deepEqual(element.getThread('right').rootId, 'right_side_comment');
- assert.deepEqual(element.getThread('right').comments.length, 1);
- assert.deepEqual(element.getThread('left').rootId, 'sallys_confession');
- assert.deepEqual(element.getThread('left').comments.length, 3);
- assert.deepEqual(element.getThread('left', range).rootId,
- 'betsys_confession');
- assert.deepEqual(element.getThread('left', range).comments.length, 1);
- });
-
- test('addNewThread', () => {
- const commentSide = 'left';
- const range = {startLine: 1, endLine: 2, startChar: 3, endChar: 4};
- element.patchForNewThreads = 5;
- element.addNewThread(commentSide, range);
- assert.equal(element.threads.length, 1);
- assert.equal(element.threads[0].comments.length, 0);
- assert.equal(element.threads[0].commentSide, commentSide);
- assert.equal(element.threads[0].patchNum, 5);
- assert.equal(element.threads[0].range.startLine, range.startLine);
- assert.equal(element.threads[0].range.endLine, range.endLine);
- assert.equal(element.threads[0].range.startChar, range.startChar);
- assert.equal(element.threads[0].range.endChar, range.endChar);
- });
-
- test('removeThread', () => {
- element.threads = [
- {rootId: 4711},
- {rootId: 42},
- ];
- element.removeThread(4711);
- assert.equal(element.threads.length, 1);
- assert.equal(element.threads[0].rootId, 42);
- });
-
- test('_rangesEqual', () => {
- const range1 =
- {startLine: 123, startChar: 345, endLine: 234, endChar: 456};
- const range2 =
- {startLine: 1, startChar: 2, endLine: 3, endChar: 4};
-
- assert.isTrue(element._rangesEqual(null, null));
- assert.isTrue(element._rangesEqual(null, undefined));
- assert.isTrue(element._rangesEqual(undefined, null));
- assert.isTrue(element._rangesEqual(undefined, undefined));
-
- assert.isFalse(element._rangesEqual(range1, null));
- assert.isFalse(element._rangesEqual(null, range1));
- assert.isFalse(element._rangesEqual(range1, range2));
-
- assert.isTrue(element._rangesEqual(range1, Object.assign({}, range1)));
- });
- });
-</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
index 9668a54..f111378 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
@@ -60,7 +60,11 @@
diffElement.loggedIn = false;
diffElement.patchRange = {basePatchNum: 1, patchNum: 2};
- diffElement.comments = {left: [], right: []};
+ diffElement.comments = {
+ left: [],
+ right: [],
+ meta: {patchRange: undefined},
+ };
const setupDone = () => {
cursorElement._updateStops();
cursorElement.moveToFirstChunk();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html
index a5f5fd9..d335e7a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html
@@ -19,6 +19,7 @@
<link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
<link rel="import" href="../../core/gr-reporting/gr-reporting.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
+<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
<link rel="import" href="../gr-diff/gr-diff.html">
<dom-module id="gr-diff-host">
@@ -46,8 +47,7 @@
base-image="[[_baseImage]]"
revision-image=[[_revisionImage]]
blame="[[_blame]]"
- diff="[[_diff]]"
- parent-index="[[_parentIndex]]"></gr-diff>
+ diff="[[_diff]]"></gr-diff>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-reporting id="reporting" category="diff"></gr-reporting>
</template>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
index 056ab60..5e4a3fd 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
@@ -45,13 +45,35 @@
return !!(diff.binary && (isA || isB));
}
+ /** @typedef {{startLine: number, startChar: number,
+ * endLine: number, endChar: number}} */
+ Gerrit.Range;
+
+
+ /**
+ * Compare two ranges. Either argument may be falsy, but will only return
+ * true if both are falsy or if neither are falsy and have the same position
+ * values.
+ *
+ * @param {Gerrit.Range=} a range 1
+ * @param {Gerrit.Range=} b range 2
+ * @return {boolean}
+ */
+ function rangesEqual(a, b) {
+ if (!a && !b) { return true; }
+ if (!a || !b) { return false; }
+ return a.startLine === b.startLine &&
+ a.startChar === b.startChar &&
+ a.endLine === b.endLine &&
+ a.endChar === b.endChar;
+ }
+
/**
* Wrapper around gr-diff.
*
* Webcomponent fetching diffs and related data from restAPI and passing them
* to the presentational gr-diff for rendering.
*/
- // TODO(oler): Move all calls to restAPI from gr-diff here.
Polymer({
is: 'gr-diff-host',
@@ -108,7 +130,10 @@
type: Boolean,
value: false,
},
- comments: Object,
+ comments: {
+ type: Object,
+ observer: '_commentsChanged',
+ },
lineWrapping: {
type: Boolean,
value: false,
@@ -176,6 +201,11 @@
type: Number,
computed: '_computeParentIndex(patchRange.*)',
},
+
+ _threadEls: {
+ type: Array,
+ value: [],
+ },
},
behaviors: [
@@ -310,7 +340,7 @@
* @return {!Array<!HTMLElement>}
*/
getThreadEls() {
- return this.$.diff.getThreadEls();
+ return this._threadEls;
},
/** @param {HTMLElement} el */
@@ -437,6 +467,70 @@
return isImageDiff(diff);
},
+
+ _commentsChanged(newComments) {
+ const allComments = [];
+ for (const side of [GrDiffBuilder.Side.LEFT, GrDiffBuilder.Side.RIGHT]) {
+ // This is needed by the threading.
+ for (const comment of newComments[side]) {
+ comment.__commentSide = side;
+ }
+ allComments.push(...newComments[side]);
+ }
+ // Currently, the only way this is ever changed here is when the initial
+ // comments are loaded, so it's okay performance wise to clear the threads
+ // and recreate them. If this changes in future, we might want to reuse
+ // some DOM nodes here.
+ this._clearThreads();
+ const threads = this._createThreads(allComments);
+ for (const thread of threads) {
+ const threadEl = this._createThreadElement(thread);
+ this._attachThreadElement(threadEl);
+ }
+ },
+
+ /**
+ * @param {!Array<!Object>} comments
+ * @return {!Array<!Object>} Threads for the given comments.
+ */
+ _createThreads(comments) {
+ const sortedComments = comments.slice(0).sort((a, b) => {
+ if (b.__draft && !a.__draft ) { return 0; }
+ if (a.__draft && !b.__draft ) { return 1; }
+ return util.parseDate(a.updated) - util.parseDate(b.updated);
+ });
+
+ const threads = [];
+ for (const comment of sortedComments) {
+ // If the comment is in reply to another comment, find that comment's
+ // thread and append to it.
+ if (comment.in_reply_to) {
+ const thread = threads.find(thread =>
+ thread.comments.some(c => c.id === comment.in_reply_to));
+ if (thread) {
+ thread.comments.push(comment);
+ continue;
+ }
+ }
+
+ // Otherwise, this comment starts its own thread.
+ const newThread = {
+ start_datetime: comment.updated,
+ comments: [comment],
+ commentSide: comment.__commentSide,
+ patchNum: comment.patch_set,
+ rootId: comment.id || comment.__draftID,
+ lineNum: comment.line,
+ isOnParent: comment.side === 'PARENT',
+ };
+ if (comment.range) {
+ newThread.range = Object.assign({}, comment.range);
+ }
+ threads.push(newThread);
+ }
+ return threads;
+ },
+
/**
* @param {Object} blame
* @return {boolean}
@@ -456,32 +550,117 @@
/** @param {CustomEvent} e */
_handleCreateComment(e) {
- const {threadGroupEl, lineNum, side, range} = e.detail;
- const threadEl = this._getOrCreateThread(threadGroupEl, side, range);
+ const {lineNum, side, patchNum, isOnParent, range} = e.detail;
+ const threadEl = this._getOrCreateThread(patchNum, lineNum, side, range,
+ isOnParent);
threadEl.addOrEditDraft(lineNum, range);
+
this.$.reporting.recordDraftInteraction();
},
/**
- * Gets or creates a comment thread from a specific thread group.
- * May include a range, if the comment is a range comment.
+ * Gets or creates a comment thread at a given location.
+ * May provide a range, to get/create a range comment.
*
- * @param {!Object} threadGroupEl
+ * @param {string} patchNum
+ * @param {?number} lineNum
* @param {string} commentSide
- * @param {!Object=} range
+ * @param {Gerrit.Range|undefined} range
+ * @param {boolean} isOnParent
* @return {!Object}
*/
- _getOrCreateThread(threadGroupEl, commentSide, range=undefined) {
- let threadEl = threadGroupEl.getThread(commentSide, range);
-
+ _getOrCreateThread(patchNum, lineNum, commentSide, range, isOnParent) {
+ let threadEl = this._getThreadEl(lineNum, commentSide, range);
if (!threadEl) {
- threadGroupEl.addNewThread(commentSide, range);
- Polymer.dom.flush();
- threadEl = threadGroupEl.getThread(commentSide, range);
+ threadEl = this._createThreadElement({
+ comments: [],
+ commentSide,
+ patchNum,
+ lineNum,
+ range,
+ isOnParent,
+ });
+ this._attachThreadElement(threadEl);
}
return threadEl;
},
+ _attachThreadElement(threadEl) {
+ this._threadEls.push(threadEl);
+ Polymer.dom(this.$.diff).appendChild(threadEl);
+ },
+
+ _clearThreads() {
+ for (const threadEl of this._threadEls) {
+ const parent = Polymer.dom(threadEl).parentNode;
+ Polymer.dom(parent).removeChild(threadEl);
+ }
+ this._threadEls = [];
+ },
+
+ _createThreadElement(thread) {
+ const threadEl = document.createElement('gr-diff-comment-thread');
+ threadEl.className = 'comment-thread';
+ threadEl.comments = thread.comments;
+ threadEl.commentSide = thread.commentSide;
+ threadEl.isOnParent = !!thread.isOnParent;
+ threadEl.parentIndex = this._parentIndex;
+ threadEl.changeNum = this.changeNum;
+ threadEl.patchNum = thread.patchNum;
+ threadEl.lineNum = thread.lineNum;
+ const rootIdChangedListener = changeEvent => {
+ thread.rootId = changeEvent.detail.value;
+ };
+ threadEl.addEventListener('root-id-changed', rootIdChangedListener);
+ threadEl.path = this.path;
+ threadEl.projectName = this.projectName;
+ threadEl.range = thread.range;
+ const threadDiscardListener = e => {
+ const threadEl = /** @type {!Node} */ (e.currentTarget);
+
+ const parent = Polymer.dom(threadEl).parentNode;
+ Polymer.dom(parent).removeChild(threadEl);
+
+ const i = this._threadEls.findIndex(
+ threadEl => threadEl.rootId == e.detail.rootId);
+ this._threadEls.splice(i, 1);
+
+ threadEl.removeEventListener('root-id-changed', rootIdChangedListener);
+ threadEl.removeEventListener('thread-discard', threadDiscardListener);
+ };
+ threadEl.addEventListener('thread-discard', threadDiscardListener);
+ return threadEl;
+ },
+
+ /**
+ * Gets a comment thread element at a given location.
+ * May provide a range, to get a range comment.
+ *
+ * @param {?number} lineNum
+ * @param {string} commentSide
+ * @param {!Gerrit.Range=} range
+ * @return {?Node}
+ */
+ _getThreadEl(lineNum, commentSide, range=undefined) {
+ let line;
+ if (commentSide === GrDiffBuilder.Side.LEFT) {
+ line = {beforeNumber: lineNum};
+ } else if (commentSide === GrDiffBuilder.Side.RIGHT) {
+ line = {afterNumber: lineNum};
+ } else {
+ throw new Error(`Unknown side: ${commentSide}`);
+ }
+ function matchesRange(threadEl) {
+ const threadRange = /** @type {!Gerrit.Range} */(
+ JSON.parse(threadEl.getAttribute('range')));
+ return rangesEqual(threadRange, range);
+ }
+
+ const filteredThreadEls = Gerrit.filterThreadElsForLocation(
+ this._threadEls, line, commentSide).filter(matchesRange);
+ return filteredThreadEls.length ? filteredThreadEls[0] : null;
+ },
+
/**
* Take a diff that was loaded with a ignore-whitespace other than
* IGNORE_NONE, and convert delta chunks labeled as common into shared
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
index 24afe87..c7ee1c2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
@@ -46,12 +46,41 @@
async getLoggedIn() { return getLoggedIn; },
});
element = fixture('basic');
+ // For reasons beyond me, fixture reuses elements, cleans out some
+ // stuff but not that list.
+ element._threadEls = [];
});
teardown(() => {
sandbox.restore();
});
+ test('thread-discard handling', () => {
+ const threads = [
+ {comments: [{id: 4711}]},
+ {comments: [{id: 42}]},
+ ];
+ element._parentIndex = 1;
+ element.changeNum = '2';
+ element.path = 'some/path';
+ element.projectName = 'Some project';
+ const threadEls = threads.map(
+ thread => element._createThreadElement(thread));
+ assert.equal(threadEls.length, 2);
+ assert.equal(threadEls[0].rootId, 4711);
+ assert.equal(threadEls[1].rootId, 42);
+ for (const threadEl of threadEls) {
+ Polymer.dom(element).appendChild(threadEl);
+ }
+
+ threadEls[0].dispatchEvent(
+ new CustomEvent('thread-discard', {detail: {rootId: 4711}}));
+ const attachedThreads = element.queryAllEffectiveChildren(
+ 'gr-diff-comment-thread');
+ assert.equal(attachedThreads.length, 1);
+ assert.equal(attachedThreads[0].rootId, 42);
+ });
+
test('reload() cancels before network resolves', () => {
const cancelStub = sandbox.stub(element.$.diff, 'cancel');
@@ -182,7 +211,11 @@
});
element.patchRange = {basePatchNum: 'PARENT', patchNum: 1};
- element.comments = {left: [], right: []};
+ element.comments = {
+ left: [],
+ right: [],
+ meta: {patchRange: element.patchRange},
+ };
});
test('renders image diffs with same file name', done => {
@@ -556,13 +589,10 @@
});
});
- test('delegates getThreadEls()', () => {
+ test('getThreadEls() returns _threadEls', () => {
const returnValue = [document.createElement('b')];
- const stub = sandbox.stub(element.$.diff, 'getThreadEls')
- .returns(returnValue);
+ element._threadEls = returnValue;
assert.equal(element.getThreadEls(), returnValue);
- assert.isTrue(stub.calledOnce);
- assert.equal(stub.lastCall.args.length, 0);
});
test('delegates addDraftAtLine(el)', () => {
@@ -771,13 +801,168 @@
});
});
+ test('_createThreads', () => {
+ const comments = [
+ {
+ id: 'sallys_confession',
+ message: 'i like you, jack',
+ updated: '2015-12-23 15:00:20.396000000',
+ line: 1,
+ __commentSide: 'left',
+ }, {
+ id: 'jacks_reply',
+ message: 'i like you, too',
+ updated: '2015-12-24 15:01:20.396000000',
+ __commentSide: 'left',
+ line: 1,
+ in_reply_to: 'sallys_confession',
+ },
+ {
+ id: 'new_draft',
+ message: 'i do not like either of you',
+ __commentSide: 'left',
+ __draft: true,
+ updated: '2015-12-20 15:01:20.396000000',
+ },
+ ];
+
+ const actualThreads = element._createThreads(comments);
+
+ assert.equal(actualThreads.length, 2);
+
+ assert.equal(
+ actualThreads[0].start_datetime, '2015-12-23 15:00:20.396000000');
+ assert.equal(actualThreads[0].commentSide, '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, undefined);
+ assert.equal(actualThreads[0].rootId, 'sallys_confession');
+ assert.equal(actualThreads[0].lineNum, 1);
+
+ assert.equal(
+ actualThreads[1].start_datetime, '2015-12-20 15:01:20.396000000');
+ assert.equal(actualThreads[1].commentSide, 'left');
+ assert.equal(actualThreads[1].comments.length, 1);
+ assert.deepEqual(actualThreads[1].comments[0], comments[2]);
+ assert.equal(actualThreads[1].patchNum, undefined);
+ assert.equal(actualThreads[1].rootId, 'new_draft');
+ assert.equal(actualThreads[1].lineNum, undefined);
+ });
+
+ test('_createThreads inherits 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,
+ __commentSide: 'left',
+ line: 1,
+ }];
+
+ expectedThreads = [
+ {
+ start_datetime: '2015-12-24 15:00:10.396000000',
+ commentSide: 'left',
+ 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,
+ __commentSide: 'left',
+ line: 1,
+ }],
+ patchNum: 5,
+ rootId: 'betsys_confession',
+ range: {
+ start_line: 1,
+ start_character: 1,
+ end_line: 1,
+ end_character: 2,
+ },
+ lineNum: 1,
+ isOnParent: false,
+ },
+ ];
+
+ assert.deepEqual(
+ element._createThreads(comments),
+ expectedThreads);
+ });
+
+ test('_createThreads 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',
+ __commentSide: 'left',
+ }, {
+ id: 'jacks_reply',
+ message: 'i like you, too',
+ updated: '2015-12-24 15:01:20.396000000',
+ __commentSide: 'left',
+ },
+ ];
+ assert.equal(element._createThreads(comments).length, 2);
+ });
+
+ test('_createThreads derives isOnParent using side from first comment',
+ () => {
+ const comments = [
+ {
+ id: 'sallys_confession',
+ message: 'i like you, jack',
+ updated: '2015-12-23 15:00:20.396000000',
+ // line: 1,
+ // __commentSide: 'left',
+ }, {
+ id: 'jacks_reply',
+ message: 'i like you, too',
+ updated: '2015-12-24 15:01:20.396000000',
+ // __commentSide: 'left',
+ // line: 1,
+ in_reply_to: 'sallys_confession',
+ },
+ ];
+
+ assert.equal(element._createThreads(comments)[0].isOnParent, false);
+
+ comments[0].side = 'REVISION';
+ assert.equal(element._createThreads(comments)[0].isOnParent, false);
+
+ comments[0].side = 'PARENT';
+ assert.equal(element._createThreads(comments)[0].isOnParent, true);
+ });
+
test('_getOrCreateThread', () => {
- const threadGroupEl =
- document.createElement('gr-diff-comment-thread-group');
const commentSide = 'left';
- assert.isOk(element._getOrCreateThread(threadGroupEl,
- commentSide));
+ assert.isOk(element._getOrCreateThread('2', 3,
+ commentSide, undefined, false));
+
+ let threads = Polymer.dom(element.$.diff)
+ .queryDistributedElements('gr-diff-comment-thread');
+
+ assert.equal(threads.length, 1);
+ assert.equal(threads[0].commentSide, commentSide);
+ assert.equal(threads[0].range, undefined);
+ assert.equal(threads[0].isOnParent, false);
+ assert.equal(threads[0].patchNum, 2);
+
// Try to fetch a thread with a different range.
range = {
@@ -788,10 +973,16 @@
};
assert.isOk(element._getOrCreateThread(
- threadGroupEl, commentSide, range));
- const threadCount = Polymer.dom(threadGroupEl.root).
- querySelectorAll('gr-diff-comment-thread').length;
- assert.equal(threadCount, 2);
+ '3', 1, commentSide, range, true));
+
+ threads = Polymer.dom(element.$.diff)
+ .queryDistributedElements('gr-diff-comment-thread');
+
+ assert.equal(threads.length, 2);
+ assert.equal(threads[1].commentSide, commentSide);
+ assert.equal(threads[1].range, range);
+ assert.equal(threads[1].isOnParent, true);
+ assert.equal(threads[1].patchNum, 3);
});
suite('_translateChunksToIgnore', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index bb3eff9..b3210cc 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -286,11 +286,11 @@
<span>Diff view:</span>
<gr-diff-mode-selector
id="modeSelect"
- save-on-change="[[_loggedIn]]"
+ save-on-change="[[!_diffPrefsDisabled]]"
mode="{{changeViewState.diffMode}}"></gr-diff-mode-selector>
</div>
<span id="diffPrefsContainer"
- hidden$="[[_computePrefsButtonHidden(_prefs, _loggedIn)]]" hidden>
+ hidden$="[[_computePrefsButtonHidden(_prefs, _diffPrefsDisabled)]]" hidden>
<span class="preferences desktop">
<gr-button
link
@@ -332,7 +332,6 @@
patch-range="[[_patchRange]]"
path="[[_path]]"
prefs="[[_prefs]]"
- project-config="[[_projectConfig]]"
project-name="[[_change.project]]"
view-mode="[[_diffMode]]"
is-blame-loaded="{{_isBlameLoaded}}"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 6f361d8..59c5b1f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -69,6 +69,14 @@
value() { return {}; },
observer: '_changeViewStateChanged',
},
+ disableDiffPrefs: {
+ type: Boolean,
+ value: false,
+ },
+ _diffPrefsDisabled: {
+ type: Boolean,
+ computed: '_computeDiffPrefsDisabled(disableDiffPrefs, _loggedIn)',
+ },
/** @type {?} */
_patchRange: Object,
/** @type {?} */
@@ -450,6 +458,7 @@
_handleCommaKey(e) {
if (this.shouldSuppressKeyboardShortcut(e) ||
this.modifierPressed(e)) { return; }
+ if (this._diffPrefsDisabled) { return; }
e.preventDefault();
this.$.diffPreferences.open();
@@ -791,8 +800,8 @@
(unresolvedString ? `${unresolvedString}` : '');
},
- _computePrefsButtonHidden(prefs, loggedIn) {
- return !loggedIn || !prefs;
+ _computePrefsButtonHidden(prefs, prefsDisabled) {
+ return prefsDisabled || !prefs;
},
_handleFileChange(e) {
@@ -1012,5 +1021,9 @@
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
this.$.diffHost.expandAllContext();
},
+
+ _computeDiffPrefsDisabled(disableDiffPrefs, loggedIn) {
+ return disableDiffPrefs || !loggedIn;
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index 431578b..3a5ca51 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -135,6 +135,7 @@
element._fileList = ['chell.go', 'glados.txt', 'wheatley.md'];
element._path = 'glados.txt';
element.changeViewState.selectedFileIndex = 1;
+ element._loggedIn = true;
const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
@@ -177,6 +178,10 @@
MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
assert(showPrefsStub.calledOnce);
+ element.disableDiffPrefs = true;
+ MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+ assert(showPrefsStub.calledOnce);
+
let scrollStub = sandbox.stub(element.$.cursor, 'moveToNextChunk');
MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
assert(scrollStub.calledOnce);
@@ -343,23 +348,39 @@
PARENT), 'Should navigate to /c/42/1');
});
- test('Diff preferences hidden when no prefs or logged out', () => {
- element._loggedIn = false;
- flushAsynchronousOperations();
- assert.isTrue(element.$.diffPrefsContainer.hidden);
+ suite('diff prefs hidden', () => {
+ test('when no prefs or logged out', () => {
+ element.disableDiffPrefs = false;
+ element._loggedIn = false;
+ flushAsynchronousOperations();
+ assert.isTrue(element.$.diffPrefsContainer.hidden);
- element._loggedIn = true;
- flushAsynchronousOperations();
- assert.isTrue(element.$.diffPrefsContainer.hidden);
+ element._loggedIn = true;
+ flushAsynchronousOperations();
+ assert.isTrue(element.$.diffPrefsContainer.hidden);
- element._loggedIn = false;
- element._prefs = {font_size: '12'};
- flushAsynchronousOperations();
- assert.isTrue(element.$.diffPrefsContainer.hidden);
+ element._loggedIn = false;
+ element._prefs = {font_size: '12'};
+ flushAsynchronousOperations();
+ assert.isTrue(element.$.diffPrefsContainer.hidden);
- element._loggedIn = true;
- flushAsynchronousOperations();
- assert.isFalse(element.$.diffPrefsContainer.hidden);
+ element._loggedIn = true;
+ flushAsynchronousOperations();
+ assert.isFalse(element.$.diffPrefsContainer.hidden);
+ });
+
+ test('when disableDiffPrefs is set', () => {
+ element._loggedIn = true;
+ element._prefs = {font_size: '12'};
+ element.disableDiffPrefs = false;
+ flushAsynchronousOperations();
+
+ assert.isFalse(element.$.diffPrefsContainer.hidden);
+ element.disableDiffPrefs = true;
+ flushAsynchronousOperations();
+
+ assert.isTrue(element.$.diffPrefsContainer.hidden);
+ });
});
test('prefsButton opens gr-diff-preferences', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index adb4dd6..7f7ec72 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -20,7 +20,6 @@
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../gr-diff-builder/gr-diff-builder.html">
-<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
<link rel="import" href="../gr-diff-highlight/gr-diff-highlight.html">
<link rel="import" href="../gr-diff-selection/gr-diff-selection.html">
<link rel="import" href="../gr-syntax-themes/gr-syntax-theme.html">
@@ -36,6 +35,11 @@
:host(.no-left) .sideBySide ::content .right:not([data-value]) + td {
display: none;
}
+ .thread-group, ::slotted(*) .thread-group {
+ display: block;
+ max-width: var(--content-width, 80ch);
+ white-space: normal;
+ }
.diffContainer {
display: flex;
font-family: var(--monospace-font-family);
@@ -290,8 +294,8 @@
is-image-diff="[[isImageDiff]]"
base-image="[[baseImage]]"
revision-image="[[revisionImage]]"
- create-comment-fn="[[_createThreadGroupFn]]"
line-of-interest="[[lineOfInterest]]">
+ <slot></slot>
<table
id="diffTable"
class$="[[_diffTableClass]]"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 6016a5a..76a62b8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -179,17 +179,10 @@
computed: '_computeNewlineWarning(diff)',
},
- /**
- * @type {function(number, boolean, !string)}
- */
- _createThreadGroupFn: {
- type: Function,
- value() {
- return this._createCommentThreadGroup.bind(this);
- },
- },
-
_diffLength: Number,
+
+ /** @type {?PolymerDomApi.ObserveHandle} */
+ _nodeObserver: Object,
},
behaviors: [
@@ -201,6 +194,11 @@
'comment-update': '_handleCommentUpdate',
'comment-save': '_handleCommentSave',
'create-range-comment': '_handleCreateRangeComment',
+ 'render-content': '_handleRenderContent',
+ },
+
+ detached() {
+ this._unobserveNodes();
},
/** Cancel any remaining diff builder rendering work. */
@@ -240,17 +238,6 @@
{bubbles: true}));
},
- /** @return {!Array<!HTMLElement>} */
- getThreadEls() {
- let threads = [];
- const threadGroupEls = Polymer.dom(this.root)
- .querySelectorAll('gr-diff-comment-thread-group');
- for (const threadGroupEl of threadGroupEls) {
- threads = threads.concat(threadGroupEl.threadEls);
- }
- return threads;
- },
-
/** @return {string} */
_computeContainerClass(loggedIn, viewMode, displayLine) {
const classes = ['diffContainer'];
@@ -361,66 +348,44 @@
const contentEl = contentText.parentElement;
side = side ||
this._getCommentSideByLineAndContent(lineEl, contentEl);
- const patchNum = this._getPatchNumByLineAndContent(lineEl, contentEl);
+ const patchForNewThreads = this._getPatchNumByLineAndContent(
+ lineEl, contentEl);
const isOnParent =
- this._getIsParentCommentByLineAndContent(lineEl, contentEl);
- const threadGroupEl = this._getOrCreateThreadGroup(contentEl, patchNum,
- side, isOnParent);
+ this._getIsParentCommentByLineAndContent(lineEl, contentEl);
this.dispatchEvent(new CustomEvent('create-comment', {
bubbles: true,
detail: {
- threadGroupEl,
lineNum,
side,
+ patchNum: patchForNewThreads,
+ isOnParent,
range,
},
}));
},
_getThreadGroupForLine(contentEl) {
- return contentEl.querySelector('gr-diff-comment-thread-group');
+ return contentEl.querySelector('.thread-group');
},
/**
* Gets or creates a comment thread group for a specific line and side on a
* diff.
* @param {!Object} contentEl
- * @param {number} patchNum
- * @param {string} commentSide
- * @param {boolean} isOnParent
- * @return {!Object}
+ * @return {!Node}
*/
- _getOrCreateThreadGroup(contentEl, patchNum, commentSide, isOnParent) {
+ _getOrCreateThreadGroup(contentEl) {
// Check if thread group exists.
let threadGroupEl = this._getThreadGroupForLine(contentEl);
if (!threadGroupEl) {
- threadGroupEl = this._createCommentThreadGroup(patchNum, isOnParent,
- commentSide);
+ threadGroupEl = document.createElement('div');
+ threadGroupEl.className = 'thread-group';
contentEl.appendChild(threadGroupEl);
}
return threadGroupEl;
},
/**
- * @param {number} patchNum
- * @param {boolean} isOnParent
- * @param {!string} commentSide
- * @return {!Object}
- */
- _createCommentThreadGroup(patchNum, isOnParent, commentSide) {
- const threadGroupEl =
- document.createElement('gr-diff-comment-thread-group');
- threadGroupEl.changeNum = this.changeNum;
- threadGroupEl.commentSide = commentSide;
- threadGroupEl.patchForNewThreads = patchNum;
- threadGroupEl.path = this.path;
- threadGroupEl.isOnParent = isOnParent;
- threadGroupEl.projectName = this.projectName;
- threadGroupEl.parentIndex = this._parentIndex;
- return threadGroupEl;
- },
-
- /**
* The value to be used for the patch number of new comments created at the
* given line and content elements.
*
@@ -608,6 +573,7 @@
},
_renderDiffTable() {
+ this._unobserveNodes();
if (!this.prefs) {
this.dispatchEvent(new CustomEvent('render', {bubbles: true}));
return;
@@ -624,6 +590,34 @@
this.$.diffBuilder.render(this.comments, this._getBypassPrefs());
},
+ _handleRenderContent() {
+ this._nodeObserver = Polymer.dom(this).observeNodes(info => {
+ const addedThreadEls = info.addedNodes.filter(
+ node => node.nodeType === Node.ELEMENT_NODE);
+ // In principal we should also handle removed nodes, but I have not
+ // figured out how to do that yet without also catching all the removals
+ // caused by further redistribution. Right now, comments are never
+ // removed by no longer slotting them in, so I decided to not handle
+ // this situation until it occurs.
+ for (const threadEl of addedThreadEls) {
+ const lineNum = Number(threadEl.getAttribute('line-num'));
+ const commentSide = threadEl.getAttribute('comment-side');
+ const lineEl = this.$.diffBuilder.getLineElByNumber(
+ lineNum, commentSide);
+ const contentText = this.$.diffBuilder.getContentByLineEl(lineEl);
+ const contentEl = contentText.parentElement;
+ const threadGroupEl = this._getOrCreateThreadGroup(contentEl);
+ Polymer.dom(threadGroupEl).appendChild(threadEl);
+ }
+ });
+ },
+
+ _unobserveNodes() {
+ if (this._nodeObserver) {
+ Polymer.dom(this).unobserveNodes(this._nodeObserver);
+ }
+ },
+
/**
* Get the preferences object including the safety bypass context (if any).
*/
@@ -635,6 +629,7 @@
},
clearDiffContent() {
+ this._unobserveNodes();
this.$.diffTable.innerHTML = null;
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 07584c7..4befd2f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -295,9 +295,6 @@
test('thread groups', () => {
const contentEl = document.createElement('div');
- const commentSide = 'left';
- const patchNum = 1;
- const side = 'PARENT';
element.changeNum = 123;
element.patchRange = {basePatchNum: 1, patchNum: 2};
@@ -312,15 +309,13 @@
assert.isNotOk(element._getThreadGroupForLine(contentEl));
// A thread group gets created.
- const threadGroupEl = element._getOrCreateThreadGroup(contentEl,
- patchNum, commentSide, side);
+ const threadGroupEl = element._getOrCreateThreadGroup(contentEl);
assert.isOk(threadGroupEl);
// The new thread group can be fetched.
assert.isOk(element._getThreadGroupForLine(contentEl));
- assert.equal(contentEl.querySelectorAll(
- 'gr-diff-comment-thread-group').length, 1);
+ assert.equal(contentEl.querySelectorAll('.thread-group').length, 1);
});
suite('image diffs', () => {
@@ -339,7 +334,11 @@
};
element.patchRange = {basePatchNum: 'PARENT', patchNum: 1};
- element.comments = {left: [], right: []};
+ element.comments = {
+ left: [],
+ right: [],
+ meta: {patchRange: undefined},
+ };
element.isImageDiff = true;
element.prefs = {
auto_hide_diff_table_header: true,
@@ -668,6 +667,7 @@
element.comments = {
left: [],
right: [],
+ meta: {patchRange: undefined},
};
element.prefs = {
context: 10,
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.html b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.html
new file mode 100644
index 0000000..720f353
--- /dev/null
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.html
@@ -0,0 +1,62 @@
+<!--
+@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.
+-->
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
+<link rel="import" href="../../../behaviors/gr-list-view-behavior/gr-list-view-behavior.html">
+<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
+<link rel="import" href="../../../styles/gr-table-styles.html">
+<link rel="import" href="../../../styles/shared-styles.html">
+<link rel="import" href="../../shared/gr-list-view/gr-list-view.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
+
+<dom-module id="gr-documentation-search">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-table-styles"></style>
+ <gr-list-view
+ filter="[[_filter]]"
+ items=false
+ offset=0
+ loading="[[_loading]]"
+ path="[[_path]]">
+ <table id="list" class="genericList">
+ <tr class="headerRow">
+ <th class="name topHeader">Name</th>
+ <th class="name topHeader"></th>
+ <th class="name topHeader"></th>
+ </tr>
+ <tr id="loading" class$="loadingMsg [[computeLoadingClass(_loading)]]">
+ <td>Loading...</td>
+ </tr>
+ <tbody class$="[[computeLoadingClass(_loading)]]">
+ <template is="dom-repeat" items="[[_documentationSearches]]">
+ <tr class="table">
+ <td class="name">
+ <a href$="[[_computeSearchUrl(item.url)]]">[[item.title]]</a>
+ </td>
+ <td></td>
+ <td></td>
+ </tr>
+ </template>
+ </tbody>
+ </table>
+ </gr-list-view>
+ <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
+ </template>
+ <script src="gr-documentation-search.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.js b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.js
new file mode 100644
index 0000000..f850b9d
--- /dev/null
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.js
@@ -0,0 +1,81 @@
+/**
+ * @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.
+ */
+(function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-documentation-search',
+
+ properties: {
+ /**
+ * URL params passed from the router.
+ */
+ params: {
+ type: Object,
+ observer: '_paramsChanged',
+ },
+
+ _path: {
+ type: String,
+ readOnly: true,
+ value: '/Documentation',
+ },
+ _documentationSearches: Array,
+
+ _loading: {
+ type: Boolean,
+ value: true,
+ },
+ _filter: {
+ type: String,
+ value: '',
+ },
+ },
+
+ behaviors: [
+ Gerrit.ListViewBehavior,
+ ],
+
+ attached() {
+ this.dispatchEvent(
+ new CustomEvent('title-change', {title: 'Documentation Search'}));
+ },
+
+ _paramsChanged(params) {
+ this._loading = true;
+ this._filter = this.getFilterValue(params);
+
+ return this._getDocumentationSearches(this._filter);
+ },
+
+ _getDocumentationSearches(filter) {
+ this._documentationSearches = [];
+ return this.$.restAPI.getDocumentationSearches(filter)
+ .then(searches => {
+ // Late response.
+ if (filter !== this._filter || !searches) { return; }
+ this._documentationSearches = searches;
+ this._loading = false;
+ });
+ },
+
+ _computeSearchUrl(url) {
+ if (!url) { return ''; }
+ return this.getBaseUrl() + '/' + url;
+ },
+ });
+})();
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html
new file mode 100644
index 0000000..84addb0
--- /dev/null
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<!--
+@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.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-documentation-search</title>
+
+<script src="../../../bower_components/page/page.js"></script>
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+<link rel="import" href="../../../test/common-test-setup.html"/>
+<link rel="import" href="gr-documentation-search.html">
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+ <template>
+ <gr-documentation-search></gr-documentation-search>
+ </template>
+</test-fixture>
+
+<script>
+ let counter;
+ const documentationGenerator = () => {
+ return {
+ title: `Gerrit Code Review - REST API Developers Notes${++counter}`,
+ url: 'Documentation/dev-rest-api.html',
+ };
+ };
+
+ suite('gr-documentation-search tests', () => {
+ let element;
+ let documentationSearches;
+ let sandbox;
+ let value;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(page, 'show');
+ element = fixture('basic');
+ counter = 0;
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
+
+ suite('list with searches for documentation', () => {
+ setup(done => {
+ documentationSearches = _.times(26, documentationGenerator);
+ stub('gr-rest-api-interface', {
+ getDocumentationSearches() {
+ return Promise.resolve(documentationSearches);
+ },
+ });
+ element._paramsChanged(value).then(() => { flush(done); });
+ });
+
+ test('test for test repo in the list', done => {
+ flush(() => {
+ assert.equal(element._documentationSearches[0].title,
+ 'Gerrit Code Review - REST API Developers Notes1');
+ assert.equal(element._documentationSearches[0].url,
+ 'Documentation/dev-rest-api.html');
+ done();
+ });
+ });
+ });
+
+ suite('filter', () => {
+ setup(() => {
+ documentationSearches = _.times(25, documentationGenerator);
+ documentationSearchesFiltered = _.times(1, documentationSearches);
+ });
+
+ test('_paramsChanged', done => {
+ sandbox.stub(element.$.restAPI, 'getDocumentationSearches', () => {
+ return Promise.resolve(documentationSearches);
+ });
+ const value = {
+ filter: 'test',
+ };
+ element._paramsChanged(value).then(() => {
+ assert.isTrue(element.$.restAPI.getDocumentationSearches.lastCall
+ .calledWithExactly('test'));
+ done();
+ });
+ });
+ });
+
+ suite('loading', () => {
+ test('correct contents are displayed', () => {
+ assert.isTrue(element._loading);
+ assert.equal(element.computeLoadingClass(element._loading), 'loading');
+ assert.equal(getComputedStyle(element.$.loading).display, 'block');
+
+ element._loading = false;
+ element._repos = _.times(25, documentationGenerator);
+
+ flushAsynchronousOperations();
+ assert.equal(element.computeLoadingClass(element._loading), '');
+ assert.equal(getComputedStyle(element.$.loading).display, 'none');
+ });
+ });
+ });
+</script>
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 787a1c6..b34cd0a 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -48,6 +48,7 @@
<link rel="import" href="../styles/shared-styles.html">
<link rel="import" href="../styles/themes/app-theme.html">
<link rel="import" href="./admin/gr-admin-view/gr-admin-view.html">
+<link rel="import" href="./documentation/gr-documentation-search/gr-documentation-search.html">
<link rel="import" href="./change-list/gr-change-list-view/gr-change-list-view.html">
<link rel="import" href="./change-list/gr-dashboard-view/gr-dashboard-view.html">
<link rel="import" href="./change/gr-change-view/gr-change-view.html">
@@ -198,6 +199,11 @@
<template is="dom-if" if="[[_showCLAView]]" restamp="true">
<gr-cla-view></gr-cla-view>
</template>
+ <template is="dom-if" if="[[_showDocumentationSearch]]" restamp="true">
+ <gr-documentation-search
+ params="[[params]]">
+ </gr-documentation-search>
+ </template>
<div id="errorView" class="errorView">
<div class="errorEmoji">[[_lastError.emoji]]</div>
<div class="errorText">[[_lastError.text]]</div>
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index b0cc514..9c465f0 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -72,6 +72,7 @@
_showCLAView: Boolean,
_showEditorView: Boolean,
_showPluginScreen: Boolean,
+ _showDocumentationSearch: Boolean,
/** @type {?} */
_viewState: Object,
/** @type {?} */
@@ -315,6 +316,8 @@
if (isPluginScreen) {
this.async(() => this.set('_showPluginScreen', true), 1);
}
+ this.set('_showDocumentationSearch',
+ view === Gerrit.Nav.View.DOCUMENTATION_SEARCH);
if (this.params.justRegistered) {
this.$.registrationOverlay.open();
this.$.registrationDialog.loadData().then(() => {
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html
index 782100e..b3e6990 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html
@@ -35,6 +35,7 @@
prevent-invalid-input
allowed-pattern="[0-9]"
bind-value="{{editPrefs.tab_size}}"
+ on-keypress="_handleEditPrefsChanged"
on-change="_handleEditPrefsChanged">
</span>
</section>
@@ -47,6 +48,7 @@
prevent-invalid-input
allowed-pattern="[0-9]"
bind-value="{{editPrefs.line_length}}"
+ on-keypress="_handleEditPrefsChanged"
on-change="_handleEditPrefsChanged">
</span>
</section>
@@ -59,6 +61,7 @@
prevent-invalid-input
allowed-pattern="[0-9]"
bind-value="{{editPrefs.indent_unit}}"
+ on-keypress="_handleEditPrefsChanged"
on-change="_handleEditPrefsChanged">
</span>
</section>
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
index dcb428f..3d9d36b 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
@@ -229,7 +229,7 @@
if (typeof link.url === 'undefined') {
return '';
}
- if (link.target) {
+ if (link.target || !link.url.startsWith('/')) {
return link.url;
}
return this._computeRelativeURL(link.url);
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
index 456f235..7bb4dce 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
@@ -73,6 +73,12 @@
test('link URLs', () => {
assert.equal(
+ element._computeLinkURL({url: 'http://example.com/test'}),
+ 'http://example.com/test');
+ assert.equal(
+ element._computeLinkURL({url: 'https://example.com/test'}),
+ 'https://example.com/test');
+ assert.equal(
element._computeLinkURL({url: '/test'}),
'//' + window.location.host + '/test');
assert.equal(
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index c0078e9..2a1ad9e 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -2981,6 +2981,22 @@
});
},
+ /**
+ * @param {string} filter
+ * @return {!Promise<?Object>}
+ */
+ getDocumentationSearches(filter) {
+ filter = filter.trim();
+ const encodedFilter = encodeURIComponent(filter);
+
+ // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
+ // supports it.
+ return this._fetchSharedCacheURL({
+ url: `/Documentation/?q=${encodedFilter}`,
+ anonymizedUrl: '/Documentation/?*',
+ });
+ },
+
getMergeable(changeNum) {
return this._getChangeURLAndFetch({
changeNum,
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 5b9ae15..20a4a1e 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -103,7 +103,6 @@
'core/gr-smart-search/gr-smart-search_test.html',
'diff/gr-comment-api/gr-comment-api_test.html',
'diff/gr-diff-builder/gr-diff-builder_test.html',
- 'diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html',
'diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html',
'diff/gr-diff-comment/gr-diff-comment_test.html',
'diff/gr-diff-cursor/gr-diff-cursor_test.html',
@@ -120,6 +119,7 @@
'diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html',
'diff/gr-selection-action-box/gr-selection-action-box_test.html',
'diff/gr-syntax-layer/gr-syntax-layer_test.html',
+ 'documentation/gr-documentation-search/gr-documentation-search_test.html',
'edit/gr-default-editor/gr-default-editor_test.html',
'edit/gr-edit-controls/gr-edit-controls_test.html',
'edit/gr-edit-file-controls/gr-edit-file-controls_test.html',
diff --git a/tools/BUILD b/tools/BUILD
index c368eed..aefb867 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -13,7 +13,7 @@
default_java_toolchain(
name = "error_prone_warnings_toolchain",
- bootclasspath = ["@bazel_tools//tools/jdk:platformclasspath9.jar"],
+ bootclasspath = ["@bazel_tools//tools/jdk:platformclasspath.jar"],
jvm_opts = JDK9_JVM_OPTS,
package_configuration = [
":error_prone",